我在XUbuntu 16.04上使用VMX,但是我在设置CR 4的VMXE位时遇到了一些问题。问题是当我调用退出函数时,该位不再被设置。
虚拟机修改. c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#define AUTHOR "me"
#define DESC "Test"
extern u64 read_cr4(void);
extern void write_cr4(u64 val);
static bool IsVMXEEnabled(void)
{
return (read_cr4() >> 13) & 1;
}
static void SetVMXEEnabled(void* _val)
{
bool val = *(bool*)_val;
u64 mask = (1 << 13);
u64 cr4 = read_cr4();
if (val)
cr4 |= mask;
else
cr4 &= (~mask);
write_cr4(cr4);
}
static void LogVMXEState(void* info)
{
(void) info;
printk(KERN_INFO "CR4: %08LX\n", read_cr4());
}
static int __init init_(void)
{
printk(KERN_INFO "===================================\n");
if (IsVMXEEnabled())
printk(KERN_INFO "VMXE Is Enabled\n");
else
{
bool new_vmxe_state = true;
printk(KERN_INFO "Enabling VMXE\n");
on_each_cpu(SetVMXEEnabled, &new_vmxe_state, 1);
if (IsVMXEEnabled())
{
printk(KERN_INFO "VMXE Has Been Enabled\n");
on_each_cpu(LogVMXEState, NULL, 1);
}
else
{
printk(KERN_INFO "VMXE Could Not Be Enabled\n");
return -1;
}
}
return 0;
}
static void __exit exit_(void)
{
printk(KERN_INFO "----------------------------------------\n");
on_each_cpu(LogVMXEState, NULL, 1);
if (IsVMXEEnabled())
{
bool new_val = false;
printk(KERN_INFO "Disabling VMXE\n");
on_each_cpu(SetVMXEEnabled, &new_val, 1);
if (!IsVMXEEnabled())
printk(KERN_INFO "VMXE Has Been Disabled\n");
else
printk(KERN_INFO "Couldn't disabled VMXE...\n");
}
else
printk(KERN_INFO "VMXE Wasn't enabled?\n");
printk(KERN_INFO "===================================\n");
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR(AUTHOR);
MODULE_DESCRIPTION(DESC);
module_init(init_);
module_exit(exit_);
vmasm.S中指定的值
.intel_syntax noprefix
.text
.global read_cr4
read_cr4:
mov rax, cr4
ret
.global write_cr4
write_cr4:
mov cr4, rdi
ret
生成文件
obj-m += testmod.o
testmod-objs := vmmod.o vmasm.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
测试
$> sudo insmod testmod.ko && sudo rmmod testmod
输出
[ 607.459248] ===================================
[ 607.459256] Enabling VMXE
[ 607.459302] VMXE Has Been Enabled
[ 607.459311] CR4: 000426E0
[ 607.459315] CR4: 000426E0
[ 607.459318] CR4: 000426E0
[ 607.459321] CR4: 000426F0
[ 607.459334] CR4: 000426E0
[ 607.459336] CR4: 000426E0
[ 607.459338] CR4: 000426E0
[ 607.459373] CR4: 000426E0
[ 607.473007] ----------------------------------------
[ 607.473025] CR4: 000406E0
[ 607.473065] CR4: 000406E0
[ 607.473068] CR4: 000406F0
[ 607.473072] CR4: 000406E0
[ 607.473074] CR4: 000406E0
[ 607.473078] CR4: 000406E0
[ 607.473080] CR4: 000406E0
[ 607.473103] CR4: 000406E0
[ 607.473121] VMXE Wasn't enabled?
[ 607.473129] ===================================
输出清楚地显示,CR 4的位13(VMXE)在模块加载功能之后使能,但在模块卸载功能期间不再置位。
是否有会定期重置VMXE的内核模块?我在运行此代码时卸载了kvm.ko和kvm_intel.ko,并且启用了英特尔仿真BIOS设置,CPU支持VMX。
根据(Modifying control register in kernel module),我尝试添加on_each_cpu
以在每个CPU内核上设置VMXE,但没有帮助。
有什么想法吗?
谢谢你!
1条答案
按热度按时间hkmswyz61#
Linux内核并没有刻意地将CR4.VMXE设置为CR4.VMXE。相反,Linux会缓存CR 4的值,并使用该高速缓存而不是阅读寄存器,这可能是出于性能原因。由于您没有更改缓存,因此下次内核试图清除CR 4中的位时,它将从缓存中恢复VMXE位,将其清除为零。如果您的驱动程序已经建立了VMXON区域,而是在内核无意中清除了具有活动VMXON区域的CR4.VMXE时看到内核崩溃。
据我所知,没有任何东西会定期重置CR 4位。然而,TLB命中是很常见的,如果任何被无效的页面是全局的,* 唯一 * 的方法就是清除CR4.PGE。我不知道为什么全局页面会频繁地被无效,但我知道我的一个同事不得不调试一个问题,这个问题开始于4. 4. 0系列内核,是由CR 4. PGE被清除引起的,所以它肯定会以一定的频率发生。
启用CR 4功能位的正确方式与内核本身的方式相同,例如在/arch/x86/kernel/cpu/common.c中:
最后调用此函数:
请注意,它没有调用
__read_cr4()
,而是调用this_cpu_read(cpu_tlbstate.cr4)
。如果您希望内核停止禁用CR4.VMXE,则必须更新该高速缓存。