问题描述
下面这个简单的内核模块设置CR4寄存器的第13位( CR4.VMXE
),一旦它被加载并清除在退出该位。
The following simple kernel module sets the 13th bit of the cr4 register (CR4.VMXE
) once it is loaded and clears the bit on exit.
#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
要运行我用使清洁和功放模块;&安培;让&功放;&安培;须藤用insmod vmx.ko&放大器;&安培;须藤rmmod的VMX和放大器;&安培;须藤的dmesg -c
。这有时给我下(预期)输出
To run the module I use make clean && make && sudo insmod vmx.ko && sudo rmmod vmx && sudo dmesg -c
. This sometimes gives me the following (expected) output
[ 2295.121537] VTX Test loaded: 1312736 (0).
[ 2295.121540] cr4: 1320928 (1).
[ 2295.123975] cr4: 1320928 (1).
[ 2295.123977] VTX Test exited: 1312736 (0).
有时也以下内容:
And sometimes also the following:
[ 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位和清除位在他们的出口例程以同样的方式在本模块中,这似乎很奇怪。
The second and third line in the secound output seem strange to me, because it seems like the modified control register cr4 has been reset after leaving init_routine
. Additionally it is strange that in the first line the VMXE bit seems to be set, which doesn't really make any sense. Is this behavior normal? How can it be explained? Could there be another kernel module running which modifies CR4? This seems rather strange because I've seen several VTX implementations and they all set the VMXE bit in their initialization routine and clear the bit in their exit routine in the same fashion as in this module.
推荐答案
事实证明,问题是该寄存器不被修改所有的CPU核心。为确保修改发生在所有的内核似乎足以调用 on_each_cpu
。下面固定code,Makefile文件不变。
As it turns out, the problem is that the register is not modified on all CPU cores. To ensure that the modifications happen on all cores it seems to be enough to invoke on_each_cpu
. Fixed code below, Makefile unchanged.
#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);
这篇关于修改控制寄存器内核模块中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!