I am playing with VMX on XUbuntu 16.04, but I am having problems setting the VMXE CR4 bits. The problem is that by the time my output function exits, the bit is no longer set.
vmmod.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
Makefile
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
Testing
$> sudo insmod testmod.ko && sudo rmmod testmod
Output
[ 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]
The output clearly shows that bit 13 (VMXE) CR4 is turned on after the module load function, but during the module unload function it is no longer set.
Is there a kernel module that will periodically reset VMXE? I have kvm.ko and kvm_intel.ko that are unloaded when this code is run, and Intel emulation BIOS settings were enabled, and the processor supports VMX.
According to ( Changing the control register in the kernel module ), I tried to add on_each_cpuVMXE on each core of the CPU to install, but this did not help.
?
!