【问题标题】:Modifying control register in kernel module修改内核模块中的控制寄存器
【发布时间】:2015-01-15 00:23:05
【问题描述】:

以下简单内核模块在加载后设置 cr4 寄存器 (CR4.VMXE) 的第 13 位,并在退出时清除该位。

vmx.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

MODULE_LICENSE("GPL");

static inline uint64_t getcr4(void) {
    register uint64_t ret = 0;

    asm volatile (
        "movq %%cr4, %0\n"
        :"=r"(ret)
    );

    return ret;
}

static inline void setcr4(register uint64_t val) {
    asm volatile (
        "movq %0, %%cr4\n"
        :
        :"r"(val)
    );
}

static int __init init_routine(void) {
    uint64_t cr4 = getcr4();

    printk(KERN_INFO "VTX Test loaded: %llu (%u).\n", cr4, (unsigned char)((cr4 >> 13) & 1));
    cr4 |= (1 << 13);
    setcr4(cr4);
    cr4 = getcr4();
    printk(KERN_INFO "cr4: %llu (%u).\n", cr4, (unsigned char)((cr4 >> 13) & 1));

    return 0;
}

static void __exit exit_routine(void) {
    uint64_t cr4 = getcr4();

    printk(KERN_INFO "cr4: %llu (%u).\n", cr4, (unsigned char)((cr4 >> 13) & 1));
    cr4 &= ~(1 << 13);
    setcr4(cr4);
    cr4 = getcr4();
    printk(KERN_INFO "VTX Test exited: %llu (%u).\n", cr4, (unsigned char)((cr4 >> 13) & 1));
}

module_init(init_routine);
module_exit(exit_routine);

生成文件

obj-m += vmx.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

要运行我使用make clean &amp;&amp; make &amp;&amp; sudo insmod vmx.ko &amp;&amp; sudo rmmod vmx &amp;&amp; sudo dmesg -c 的模块。这有时会给我以下(预期的)输出

[ 2295.121537] VTX Test loaded: 1312736 (0).
[ 2295.121540] cr4: 1320928 (1).
[ 2295.123975] cr4: 1320928 (1).
[ 2295.123977] VTX Test exited: 1312736 (0).

有时还有以下内容:

[ 2296.256982] VTX Test loaded: 1320928 (1).
[ 2296.256984] cr4: 1320928 (1).
[ 2296.259481] cr4: 1312736 (0).
[ 2296.259483] VTX Test exited: 1312736 (0).

第二个输出中的第二行和第三行对我来说似乎很奇怪,因为在离开init_routine 之后,修改后的控制寄存器 cr4 似乎已被重置。另外奇怪的是,在第一行中似乎设置了 VMXE 位,这实际上没有任何意义。这种行为正常吗?怎么解释?是否会运行另一个修改 CR4 的内核模块?这似乎很奇怪,因为我见过几个 VTX 实现,它们都在初始化例程中设置了 VMXE 位,并在退出例程中以与本模块相同的方式清除该位。

【问题讨论】:

    标签: c linux linux-kernel kernel-module


    【解决方案1】:

    您可能已经加载了kvm 模块(以及相关的kvm-intelkvm-amd)内核模块。这些模块已经管理处理器的 VT 状态,如果您开始在其他地方修改它,可能会非常困惑

    查看内核源代码中的arch/x86/kvm 目录,了解已经存在的内容。

    【讨论】:

    • sudo rmmod kvm-intel &amp;&amp; sudo rmmod kvm卸载kvm后问题依旧存在
    • 事实证明,我认为需要确保使用 on_each_cpu 函数在所有 CPU 内核上修改寄存器,这似乎解决了我的问题。如果它确实是我正在寻找的解决方案,我将仔细研究并稍后发布答案。
    【解决方案2】:

    事实证明,问题在于寄存器没有在所有 CPU 内核上修改。为了确保修改发生在所有内核上,调用on_each_cpu 似乎就足够了。修正以下代码,Makefile 不变。

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    
    MODULE_LICENSE("GPL");
    
    static inline uint64_t getcr4(void) {
        register uint64_t ret = 0;
    
        asm volatile (
            "movq %%cr4, %0\n"
            :"=r"(ret)
        );
    
        return ret;
    }
    
    static inline void setcr4(register uint64_t val) {
        asm volatile (
            "movq %0, %%cr4\n"
            :
            :"r"(val)
        );
    }
    
    static void setvmxe(void* info) {
        uint64_t cr4 = getcr4();
    
        cr4 |= (1 << 13);
        setcr4(cr4);
    }
    
    static void clearvmxe(void* info) {
        uint64_t cr4 = getcr4();
    
        cr4 &= ~(1 << 13);
        setcr4(cr4);
    }
    
    static int __init init_routine(void) {
        uint64_t cr4 = getcr4();
    
        printk(KERN_INFO "VTX Test loaded: %llu (%u).\n", cr4, (unsigned char)((cr4 >> 13) & 1));
        on_each_cpu(setvmxe, NULL, 0);
        cr4 = getcr4();
        printk(KERN_INFO "cr4: %llu (%u).\n", cr4, (unsigned char)((cr4 >> 13) & 1));
    
        return 0;
    }
    
    static void __exit exit_routine(void) {
        uint64_t cr4 = getcr4();
    
        printk(KERN_INFO "cr4: %llu (%u).\n", cr4, (unsigned char)((cr4 >> 13) & 1));
        on_each_cpu(clearvmxe, NULL, 0);
        cr4 = getcr4();
        printk(KERN_INFO "VTX Test exited: %llu (%u).\n", cr4, (unsigned char)((cr4 >> 13) & 1));
    }
    
    module_init(init_routine);
    module_exit(exit_routine);
    

    【讨论】:

    • 所以,如果是 kvm 问题,最好向社区报告。 Subscribe
    • @AndyShevchenko 问题与kvm无关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    • 2012-01-21
    相关资源
    最近更新 更多