Linux Kernel Module: CR4.VMXE configuration not saved

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.

?

!

+4

All Articles