2015-01-15 63 views
0

下面的簡單內核模塊在加載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); 

的Makefile

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 && make && sudo insmod vmx.ko && sudo rmmod vmx && 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). 

在謝勝利,輸出的二,三線看起來很奇怪我,因爲它看起來像修改控制寄存器cr4在離開init_routine後已被重置。另外奇怪的是,在第一行中,VMXE位似乎被設置,這並沒有任何意義。這種行爲是否正常?如何解釋?有沒有其他的內核模塊可以修改CR4?這似乎相當奇怪,因爲我已經看到了幾個VTX實現,它們都在它們的初始化例程中設置了VMXE位,並以與本模塊相同的方式清除它們的退出例程中的位。

回答

0

事實證明,問題在於,寄存器未在所有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); 
+0

因此,如果這是一個kvm問題,那麼最好向社區報告。 [訂閱](http://vger.kernel.org/vger-lists.html#kvm) – 0andriy

+0

@AndyShevchenko問題與kvm無關。 – user1658887

0

您可能已經加載了kvm模塊(以及相關的kvm-intelkvm-amd)內核模塊。這些模塊已經可以管理處理器的VT狀態,並且如果您在其他地方開始修改它,很可能會很困惑。

查看內核源代碼中的arch/x86/kvm目錄,以瞭解已存在的內容。

+0

問題仍與'須藤rmmod的KVM-英特爾&&須藤rmmod的kvm' – user1658887

+0

卸載KVM後存在事實證明,我認爲一個人需要確保該寄存器被使用的所有CPU內核修改' on_each_cpu'函數,這似乎解決了我的問題。如果它真的是我正在尋找的解決方案,我將仔細研究它,並在稍後發佈答案。 – user1658887