vmlaunch simple crash ubuntu 16.04

1

I am porting VMLaunch simple to ubuntu 16.04, the code is at https://github.com/vishmohan/vmlaunch. And modified the vmlaunch_simple.c to make it almost work in ubuntu 16.04.
When I load the module (KVM and KVM_intel have been unloaded), the 'insmod vmlaunch_simple.ko' hang, where kexec/kdump chimed in and the host is rebooted.
After reboot, the crash log showed below,

[  866.579251] vmlaunch_simple: module verification failed: signature `.....`
[  866.581183] BUG: unable to handle kernel NULL pointer dereference at 0000000000000005
[  866.584255] IP: [<0000000000000005>] 0x5
[  866.585750] PGD 0
[  866.586562] Oops: 0010 [#1] SMP
[  866.619897] task: ffff8800b99cee00 ti: ffff880234138000 task.ti: ffff880234138000
[  866.622615] RIP: 0010:[<0000000000000005>]  [<0000000000000005>] 0x5
[  866.625045] RSP: 0018:ffff88023413bc40  EFLAGS: 00010286
[  866.626989] RAX: 0000000000000000 RBX: 0000001200000018 RCX: 0000000000000006
[  866.629643] RDX: 0000000000000000 RSI: 0000000000000246 RDI: ffff88023fc8cbf0
[  866.632236] RBP: fffa322300000001 R08: 656e6f44203e313c R09: 0000000000000801
[  866.634830] R10: ffffea0008d1a600 R11: 0000000000000801 R12: ffff880035cfda40
[  866.637502] R13: 0000000000000000 R14: ffffffffc0421868 R15: ffffffffc0424bc0
[  866.640104] FS:  ffffffffe4901700(0000) GS:ffff88023fc80000(0000) knlGS:0000000000000000
[  866.643040] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  866.645162] CR2: 0000000000000005 CR3: 0000000233356000 CR4: 00000000001406e0
[  866.647807] Stack:
[  866.648576]  0000000000004402 000001e75074c4cf 000001e75076e27f 5076e27f5074c4cf
[  866.651460]  000001e7000001e7 00000000cc0ba018 ffffffff81e0f040 ffff88023413bcf8
[  866.654341]  ffffffff810003e3 ffffea0008ccd300 ffff88023413bcd0 0000000000000282
[  866.657224] Call Trace:
[  866.658152]  [<ffffffff810003e3>] ? do_one_initcall+0xb3/0x1f0
[  866.660315]  [<ffffffff811cfeb3>] ? kmem_cache_alloc_trace+0x183/0x1f0
[  866.663309]  [<ffffffff81171c37>] ? do_init_module+0x5f/0x1cf
[  866.666023]  [<ffffffff810efdba>] ? load_module+0x225a/0x28b0
[  866.668854]  [<ffffffff810ec3c0>] ? __symbol_put+0x60/0x60
[  866.671464]  [<ffffffff811f6120>] ? kernel_read+0x50/0x80
[  866.674031]  [<ffffffff810f0654>] ? SYSC_finit_module+0xb4/0xe0
[  866.676784]  [<ffffffff810f069e>] ? SyS_finit_module+0xe/0x10
[  866.679455]  [<ffffffff818046db>] ? entry_SYSCALL_64_fastpath+0x16/0x6a
[  866.682455] Code:  Bad RIP value.
[  866.684408] RIP  [<0000000000000005>] 0x5
[  866.686492]  RSP <ffff88023413bc40>
[  866.688334] CR2: 0000000000000005

The source code,

#include <linux/init.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <asm/tlbflush.h>
#include <asm/desc.h>
#include "vmxon_simple.h"

MODULE_LICENSE("Dual BSD/GPL");

#define MYPAGE_SIZE 4096
#define VMX_BASIC_MSR 0x480
#define FEATURE_CONTROL_MSR 0x3A
#define CPUID_VMX_BIT 5

bool alloc_failure = false;
int vmx_msr_addr = VMX_BASIC_MSR;
int feature_control_msr_addr = FEATURE_CONTROL_MSR;
u64    vmx_rev_id = 0;
int vmxon_success = 0;
int vmxoff_success = 0;
int vmptrld_success = 0;
int vmclear_success = 0;
int vmwrite_success = 0;
int vmread_success = 0;
int vmlaunch_success = 0;
char *vmxon_region;
char *vmcs_guest_region;
char *io_bitmap_a_region;
char *io_bitmap_b_region;
char *msr_bitmap_region;
char *virtual_apic_page;

long int vmxon_phy_region = 0;
long int vmcs_phy_region = 0;
long int io_bitmap_a_phy_region = 0;
long int io_bitmap_b_phy_region = 0;
long int msr_bitmap_phy_region = 0;
long int virtual_apic_page_phy_region = 0;

unsigned long value;
long int rflags_value = 0;
u16 tr_sel; //selector for task register

static int  do_vmclear(void);
static int  do_vmptrld(void);
static void vmxon_exit(void);
static u64  do_vmread(unsigned long field);

u16         host_gdtr[5], host_idtr[5];

#define MY_VMX_VMXON_RAX         ".byte 0xf3, 0x0f, 0xc7, 0x30"
#define MY_VMX_VMPTRLD_RAX       ".byte 0x0f, 0xc7, 0x30"
#define MY_VMX_VMCLEAR_RAX       ".byte 0x66, 0x0f, 0xc7, 0x30"
#define MY_VMX_VMLAUNCH          ".byte 0x0f, 0x01, 0xc2"
#define MY_VMX_VMRESUME          ".byte 0x0f, 0x01, 0xc3"
#define MY_VMX_VMREAD_RDX_RAX    ".byte 0x0f, 0x78, 0xd0"
#define MY_VMX_VMWRITE_RAX_RDX   ".byte 0x0f, 0x79, 0xd0"
#define MY_VMX_VMXOFF            ".byte 0x0f, 0x01, 0xc4"
#define MY_VMX_VMCALL            ".byte 0x0f, 0x01, 0xc1"
#define MY_HLT                 ".byte 0xf4"

static u64 do_vmread(unsigned long field)
{
    u64 value = 0;

    vmread_success = 1;
    asm volatile("vmread %1, %0\n"
            : "=a"(value) : "d"(field) : "cc");
    asm volatile("jbe vmread_fail\n");
    asm volatile("jmp vmread_finish\n");
    asm volatile("vmread_fail:\n");
    printk("   # vmread(0x%lX) failed\n", field);
    printk("   # RFLAGS: 0x%lX\n", rflags_value);
    vmread_success = 0;
    asm volatile("vmread_finish:\n");
    return value;
}

static int do_vmxon(void)
{
    vmxon_success = 1;
    smp_mb();
    asm volatile( "vmxon %0\n"           \
            "jbe vmxon_fail\n"     \
            "jmp vmxon_finish\n"   \
            "vmxon_fail:     \n"   \
            "   movl  $0, vmxon_success \n"\
            "vmxon_finish: \n"
            :
            : "m"(vmxon_phy_region)
            : "memory", "cc");
    if (vmxon_success == 0) {
        printk("[i] vmxon has failed! VT-X is busy by other VMM.\n");
    }

    return !(vmxon_success);
}

static int do_vmptrld(void)
{
    asm volatile("vmptrld %0\n"
            :
            : "m"(vmcs_phy_region)
            : "cc", "memory");
    asm volatile("jbe vmptrld_fail\n");
    vmptrld_success = 1;
    asm volatile("jmp vmptrld_finish\n"
            "vmptrld_fail:\n");
    vmptrld_success = 0;
    pr_err("[i] vmptrld has failed!\n");
    asm volatile("vmptrld_finish:\n");

    return !vmptrld_success;
}

static int do_vmclear(void)
{
    asm volatile ("vmclear %1 \n"
            : : "a"(&vmcs_phy_region), "m"(vmcs_phy_region)
            : "cc", "memory");
    asm volatile("jbe vmclear_fail");
    vmclear_success = 1;
    asm volatile("jmp vmclear_finish\n"
            "vmclear_fail:\n");
    vmclear_success = 0;
    pr_err("[i] vmclear has failed!\n");
    asm volatile("vmclear_finish:\n");
    printk("<1> vmclear done!\n");

    return !(vmclear_success);
}

/*do vmxoff*/
static int do_vmxoff(void)
{
    asm volatile("vmxoff\n" : : : "cc");
    asm volatile("jbe vmxoff_fail\n");
    vmxoff_success = 1;
    asm volatile("jmp vmxoff_finish\n");
    asm volatile("vmxoff_fail:\n");
    vmxoff_success = 0;
    pr_err("[i] vmxoff has failed!\n");
    asm volatile("vmxoff_finish:\n");

    printk("<1> vmxoff complete\n");
    return !(vmxoff_success);
}

static u8 do_vmwrite(u32 field, u64 val)
{
    u8 error;

    __asm __volatile ( "clc; vmwrite %%rax, %%rdx; setna %0"
            : "=q"( error ) : "a"( val), "d"( field ) : "cc");
    return error;
}

static void do_vmwrite16(unsigned long field, u16 value)
{
    do_vmwrite(field, value);
}

static void do_vmwrite32(unsigned long field, u32 value)
{
    do_vmwrite(field, value);
}

static void do_vmwrite64(unsigned long field, u64 value)
{
    do_vmwrite(field, value);
}

static void initialize_16bit_host_guest_state(void)
{
    unsigned long field,field1;
    u16         value;
    field = VMX_HOST_ES_SEL;
    field1 = VMX_GUEST_ES_SEL;
    asm ("movw %%es, %%ax\n"
            :"=a"(value)
        );
    do_vmwrite16(field,value);
    do_vmwrite16(field1,value);

    field = VMX_HOST_CS_SEL;
    field1 = VMX_GUEST_CS_SEL;
    asm ("movw %%cs, %%ax\n"
            : "=a"(value));
    do_vmwrite16(field,value);
    do_vmwrite16(field1,value);

    field = VMX_HOST_SS_SEL;
    field1 = VMX_GUEST_SS_SEL;
    asm ("movw %%ss, %%ax\n"
            : "=a"(value));
    do_vmwrite16(field,value);
    do_vmwrite16(field1,value);

    field = VMX_HOST_DS_SEL;
    field1 = VMX_GUEST_DS_SEL;
    asm ("movw %%ds, %%ax\n"
            : "=a"(value));
    do_vmwrite16(field,value);
    do_vmwrite16(field1,value);

    field = VMX_HOST_FS_SEL;
    field1 = VMX_GUEST_FS_SEL;
    asm ("movw %%fs, %%ax\n"
            : "=a"(value));
    do_vmwrite16(field,value);
    do_vmwrite16(field1,value);

    field = VMX_HOST_GS_SEL;
    field1 = VMX_GUEST_GS_SEL;
    asm ("movw %%gs, %%ax\n"
            : "=a"(value));
    do_vmwrite16(field,value);
    do_vmwrite16(field1,value);

    field = VMX_HOST_TR_SEL;
    field1 = VMX_GUEST_TR_SEL;
    asm("str %%ax\n" : "=a"(tr_sel));
    do_vmwrite16(field,tr_sel);
    do_vmwrite16(field1,tr_sel);

    field = VMX_GUEST_LDTR_SEL;
    asm("sldt %%ax\n" : "=a"(value));
    do_vmwrite16(field,value);
}

static void initialize_64bit_control(void)
{
    unsigned long field;
    u64         value;

    field = VMX_IO_BITMAP_A_FULL;
    io_bitmap_a_phy_region = __pa(io_bitmap_a_region);
    value = io_bitmap_a_phy_region;
    do_vmwrite64(field,value);

    field = VMX_IO_BITMAP_B_FULL;
    io_bitmap_b_phy_region = __pa(io_bitmap_b_region);
    value = io_bitmap_b_phy_region;
    do_vmwrite64(field,value);

    field = VMX_MSR_BITMAP_FULL;
    msr_bitmap_phy_region = __pa(msr_bitmap_region);
    value = msr_bitmap_phy_region;
    do_vmwrite64(field,value);

    field = VMX_VIRTUAL_APIC_PAGE_ADDR_FULL;
    virtual_apic_page_phy_region = __pa(virtual_apic_page);
    value = virtual_apic_page_phy_region;
    do_vmwrite64(field,value);

    field = VMX_EXECUTIVE_VMCS_PTR_FULL;
    value = 0;
    do_vmwrite64(field,value);

    field = VMX_TSC_OFFSET_FULL;
    value = 0;
    do_vmwrite64(field,value);
}

static void initialize_64bit_host_guest_state(void)
{
    unsigned long field;
    u64         value;
    field = VMX_VMS_LINK_PTR_FULL;
    value = 0xffffffffffffffffull;
    do_vmwrite64(field,value);
    field = VMX_GUEST_IA32_DEBUGCTL_FULL;
    value = 0;
    do_vmwrite64(field,value);
}

static void initialize_32bit_control(void)
{
    unsigned long field;
    u32         value;

    field = VMX_PIN_VM_EXEC_CONTROLS;
    value = 0x1e;
    do_vmwrite32(field,value);

    field = VMX_PROC_VM_EXEC_CONTROLS;
    value = 0x0401e172 ;
    do_vmwrite32(field,value);

    field = VMX_EXCEPTION_BITMAP;
    value = 0xffffffff ;
    do_vmwrite32(field,value);

    field = VMX_PF_EC_MASK;
    value = 0x0 ;
    do_vmwrite32(field,value);

    field = VMX_PF_EC_MATCH;
    value = 0 ;
    do_vmwrite32(field,value);

    field = VMX_CR3_TARGET_COUNT;
    value = 0 ;
    do_vmwrite32(field,value);

    field = VMX_EXIT_CONTROLS;
    value = 0x36fff ;
    do_vmwrite32(field,value);

    field = VMX_EXIT_MSR_STORE_COUNT;
    value = 0 ;
    do_vmwrite32(field,value);

    field = VMX_EXIT_MSR_LOAD_COUNT;
    value = 0 ;
    do_vmwrite32(field,value);

    field = VMX_ENTRY_CONTROLS;
    value = 0x13ff ;
    do_vmwrite32(field,value);

    field = VMX_ENTRY_MSR_LOAD_COUNT;
    value = 0 ;
    do_vmwrite32(field,value);

    field = VMX_ENTRY_INT_INFO_FIELD;
    value = 0 ;
    do_vmwrite32(field,value);

    field = VMX_ENTRY_EXCEPTION_EC;
    value = 0 ;
    do_vmwrite32(field,value);

    field = VMX_ENTRY_INSTR_LENGTH;
    value = 0 ;
    do_vmwrite32(field,value);

    field = VMX_TPR_THRESHOLD;
    value = 0 ;
    do_vmwrite32(field,value);
}

static void initialize_32bit_host_guest_state(void)
{
    unsigned long field;
    struct desc_ptr  xdesc;
    u64      value;
    s64     *host_gdt = NULL;
    s64         desc;
    s64         idtb;
    u64      gdtb;
    s64      realtrbase;
    u32      unusable_ar = 0x10000;
    u32      usable_ar;
    u16      sel_value;

    field = VMX_GUEST_ES_LIMIT;
    value = 0xffffffff ;
    do_vmwrite32(field,value);

    field = VMX_GUEST_ES_ATTR;
    value = unusable_ar;
    do_vmwrite32(field,value);

    field = VMX_GUEST_CS_LIMIT;
    value = 0xffffffff ;
    do_vmwrite32(field,value);

    asm ("movw %%cs, %%ax\n"
            : "=a"(sel_value));
    asm("lar %%eax,%%eax\n" :"=a"(usable_ar) :"a"(sel_value));
    usable_ar = usable_ar >> 8;
    usable_ar &= 0xf0ff; //clear bits 11:8

    field = VMX_GUEST_CS_ATTR;
    do_vmwrite32(field,usable_ar);
    value = do_vmread(field);

    field = VMX_GUEST_SS_LIMIT;
    value = 0xffffffff ;
    do_vmwrite32(field,value);

    asm ("movw %%ss, %%ax\n"
            : "=a"(sel_value));
    asm("lar %%eax,%%eax\n" :"=a"(usable_ar) :"a"(sel_value));
    usable_ar = usable_ar >> 8;
    usable_ar &= 0xf0ff; //clear bits 11:8

    field = VMX_GUEST_SS_ATTR;
    do_vmwrite32(field,usable_ar);

    field = VMX_GUEST_DS_LIMIT;
    value = 0xffffffff ;
    do_vmwrite32(field,value);

    field = VMX_GUEST_DS_ATTR;
    value = unusable_ar;
    do_vmwrite32(field,value);

    field = VMX_GUEST_FS_LIMIT;
    value = 0xffffffff ;
    do_vmwrite32(field,value);

    field = VMX_GUEST_FS_ATTR;
    value = unusable_ar;
    do_vmwrite32(field,value);

    field = VMX_GUEST_GS_LIMIT;
    value = 0xffffffff ;
    do_vmwrite32(field,value);

    field = VMX_GUEST_GS_ATTR;
    value = unusable_ar;
    do_vmwrite32(field,value);

    field = VMX_GUEST_LDTR_LIMIT;
    value = 0x0;
    do_vmwrite32(field,value);

    field = VMX_GUEST_LDTR_ATTR;
    value = unusable_ar;
    do_vmwrite32(field,value);

    field = VMX_GUEST_TR_LIMIT;
    asm volatile("mov %%rax, %%rax"
            :
            :"a"(tr_sel)
            );
    asm("lsl %%eax, %%eax\n" :"=a"(value));
    do_vmwrite32(field,value);

    asm("lar %%eax,%%eax\n" :"=a"(usable_ar) :"a"(tr_sel));
    usable_ar = usable_ar >> 8;

    field = VMX_GUEST_TR_ATTR;
    do_vmwrite32(field,usable_ar);

    asm(" sgdt %0 ": "=m" (xdesc));
    value = xdesc.size & 0x0ffff;
    gdtb = xdesc.address; //base

    field = VMX_GUEST_GDTR_LIMIT;
    do_vmwrite32(field,value);

    field = VMX_GUEST_GDTR_BASE;
    do_vmwrite64(field,gdtb);
    field = VMX_HOST_GDTR_BASE;
    do_vmwrite64(field,gdtb);

    host_gdt = (s64 *)gdtb;
    desc = host_gdt[ (tr_sel >> 3) + 0 ];
    realtrbase = ((desc >> 32)&0xFF000000)|((desc >> 16)&0x00FFFFFF);
    desc = host_gdt[ (tr_sel >> 3) + 1 ];
    desc <<= 48;    // maneuver to insure 'canonical' addressing
    realtrbase |= (desc >> 16)&0xFFFFFFFF00000000;
    field = VMX_HOST_TR_BASE;
    do_vmwrite64(field,realtrbase);

    field = VMX_GUEST_TR_BASE;
    do_vmwrite64(field,realtrbase);

    asm("sidt %0\n" : "=m"(xdesc));
    value = xdesc.size & 0x0ffff;
    idtb = xdesc.address; //base

    field = VMX_GUEST_IDTR_LIMIT;
    do_vmwrite32(field,value);

    field = VMX_GUEST_IDTR_BASE;
    do_vmwrite64(field,idtb);
    field = VMX_HOST_IDTR_BASE;
    do_vmwrite64(field,idtb);

    field = VMX_GUEST_INTERRUPTIBILITY_INFO;
    value = 0;
    do_vmwrite32(field,value);

    field = VMX_GUEST_ACTIVITY_STATE;
    value = 0;
    do_vmwrite32(field,value);

    field = VMX_GUEST_SMBASE;
    value = 0;
    do_vmwrite32(field,value);

    rdmsrl_safe(0x174, &value);
    field  = VMX_HOST_IA32_SYSENTER_CS;
    do_vmwrite32(field,value);
    field = VMX_GUEST_IA32_SYSENTER_CS;
    do_vmwrite32(field,value);
}

static void initialize_naturalwidth_control(void)
{
    unsigned long field;
    u64         value;

    field = VMX_CR0_MASK;
    value = 0;
    do_vmwrite64(field,value);
    field = VMX_CR4_MASK;
    value = 0;
    do_vmwrite64(field,value);

    field = VMX_CR0_READ_SHADOW;
    value = 0;
    do_vmwrite64(field,value);

    field = VMX_CR4_READ_SHADOW;
    value = 0;
    do_vmwrite64(field,value);

    field = VMX_CR3_TARGET_0;
    value = 0;
    do_vmwrite64(field,value);

    field = VMX_CR3_TARGET_1;
    value = 0;
    do_vmwrite64(field,value);

    field = VMX_CR3_TARGET_2;
    value = 0;
    do_vmwrite64(field,value);

    field = VMX_CR3_TARGET_3;
    value = 0;
    do_vmwrite64(field,value);
}

static void initialize_naturalwidth_host_guest_state(void)
{
    unsigned long field,field1;
    u64         value;
    int      fs_low;
    int      gs_low;

    field =  VMX_HOST_CR0;
    field1 = VMX_GUEST_CR0;
    asm ("movq %%cr0, %%rax\n"
            :"=a"(value)
        );
    do_vmwrite64(field,value);
    do_vmwrite64(field1,value);

    field =  VMX_HOST_CR3;
    field1 = VMX_GUEST_CR3;
    asm ("movq %%cr3, %%rax\n"
            :"=a"(value)
        );
    do_vmwrite64(field,value);
    do_vmwrite64(field1,value);

    field =  VMX_HOST_CR4;
    field1 = VMX_GUEST_CR4;
    asm ("movq %%cr4, %%rax\n"
            :"=a"(value)
        );
    do_vmwrite64(field,value);
    do_vmwrite64(field1,value);

    value=0;
    field1 = VMX_GUEST_ES_BASE;
    do_vmwrite64(field1,value);
    field1 = VMX_GUEST_CS_BASE;
    do_vmwrite64(field1,value);
    field1 = VMX_GUEST_SS_BASE;
    do_vmwrite64(field1,value);
    field1 = VMX_GUEST_DS_BASE;
    do_vmwrite64(field1,value);
    field1 = VMX_GUEST_LDTR_BASE;
    do_vmwrite64(field1,value);

    value = 0;
    field =  VMX_HOST_FS_BASE;
    field1 = VMX_GUEST_FS_BASE;

    asm volatile("mov $0xc0000100, %rcx\n");
    asm volatile("rdmsr\n" :"=a"(fs_low) : :"%rdx");
    //asm volatile ("mov %%rax, %0\n" : :"m"(fs_low) :"memory");
    asm volatile ("shl $32, %%rdx\n" :"=d"(value));
    value|=fs_low;
    do_vmwrite64(field1,value);
    do_vmwrite64(field,value);

    value = 0;
    field =  VMX_HOST_GS_BASE;
    field1 = VMX_GUEST_GS_BASE;
    asm volatile("mov $0xc0000101, %rcx\n");
    asm volatile("rdmsr\n" :"=a"(gs_low) : :"%rdx");
    //asm volatile ("mov %%rax, %0\n" : :"m"(gs_low) :"memory");
    asm volatile ("shl $32, %%rdx\n" :"=d"(value));
    value|=gs_low;
    do_vmwrite64(field1,value);
    do_vmwrite64(field,value);

    field1 = VMX_GUEST_DR7;
    value = 0x400;
    do_vmwrite64(field1,value);

    field = VMX_HOST_RSP;
    field1 = VMX_GUEST_RSP;
    asm ("movq %%rsp, %%rax\n"
            :"=a"(value)
        );
    do_vmwrite64(field1,value);
    do_vmwrite64(field,value);

    /*
       field1 = VMX_GUEST_RIP;
       value = (u64) guest_entry_code;
       do_vmwrite64(field1,value);

       field1 = VMX_HOST_RIP;
       value  = (u64) handle_vmexit;
       do_vmwrite64(field1,value); */


    field1 = VMX_GUEST_RFLAGS;
    asm volatile("pushfq\n");
    asm volatile("popq %0\n" :"=m"(value)::"memory");
    do_vmwrite64(field1,value);

    field1 = VMX_GUEST_PENDING_DEBUG_EXCEPT;
    value = 0x0;
    do_vmwrite64(field1,value);

    field1 = VMX_GUEST_IA32_SYSENTER_ESP;
    field  = VMX_HOST_IA32_SYSENTER_ESP;
    rdmsrl_safe(0x176, &value);
    do_vmwrite64(field1,value);
    do_vmwrite64(field,value);

    field1 = VMX_GUEST_IA32_SYSENTER_EIP;
    field =  VMX_HOST_IA32_SYSENTER_EIP;
    rdmsrl_safe(0x175, &value);
    do_vmwrite64(field1,value);
    do_vmwrite64(field,value);
}

static void initialize_guest_vmcs(void)
{
    initialize_16bit_host_guest_state();
    initialize_64bit_control();
    initialize_64bit_host_guest_state();
    initialize_32bit_control();
    initialize_naturalwidth_control();
    initialize_32bit_host_guest_state();
    initialize_naturalwidth_host_guest_state();
}

/* Allocate a 4K region for vmxon */
static void allocate_vmxon_region(void)
{
    vmxon_region = kmalloc(MYPAGE_SIZE,GFP_KERNEL);
}

/* Allocate a 4K vmcs region for the guest */
static void allocate_vmcs_region(void)
{
    vmcs_guest_region  =  kmalloc(MYPAGE_SIZE,GFP_KERNEL);
    io_bitmap_a_region =  kmalloc(MYPAGE_SIZE,GFP_KERNEL);
    io_bitmap_b_region =  kmalloc(MYPAGE_SIZE,GFP_KERNEL);
    msr_bitmap_region  =  kmalloc(MYPAGE_SIZE,GFP_KERNEL);
    virtual_apic_page  =  kmalloc(MYPAGE_SIZE,GFP_KERNEL);
    //Initialize data structures
    memset(vmcs_guest_region, 0, MYPAGE_SIZE);
    memset(io_bitmap_a_region, 0, MYPAGE_SIZE);
    memset(io_bitmap_b_region, 0, MYPAGE_SIZE);
    memset(msr_bitmap_region, 0, MYPAGE_SIZE);
    memset(virtual_apic_page, 0, MYPAGE_SIZE);
}

/* Dealloc vmxon region*/
static void deallocate_vmxon_region(void)
{
    if (vmxon_region) {
        printk("<1> freeing allocated vmxon region!\n");
        kfree(vmxon_region);
        vmxon_region = NULL;
    }
}

/* Dealloc vmcs guest region*/
static void deallocate_vmcs_region(void)
{
    if (vmcs_guest_region) {
        printk("<1> freeing allocated vmcs region!\n");
        kfree(vmcs_guest_region);
        vmcs_guest_region = NULL;
    }
    if (io_bitmap_a_region) {
        printk("<1> freeing allocated io bitmapA region!\n");
        kfree(io_bitmap_a_region);
        io_bitmap_a_region = NULL;
    }
    if (io_bitmap_b_region) {
        printk("<1> freeing allocated io bitmapB region!\n");
        kfree(io_bitmap_b_region);
        io_bitmap_b_region = NULL;
    }
    if (msr_bitmap_region) {
        printk("<1> freeing allocated msr bitmap region!\n");
        kfree(msr_bitmap_region);
        msr_bitmap_region = NULL;
    }
    if (virtual_apic_page) {
        printk("<1> freeing allocated virtual apic page region!\n");
        kfree(virtual_apic_page);
        virtual_apic_page = NULL;
    }
}

/*initialize revision id*/
static void vmxon_setup_revid(void)
{
    rdmsrl_safe(vmx_msr_addr, &vmx_rev_id);
}

void turn_on_vmxe( void *dummy )
{
    u64 crx[16];

    asm ( "mov %%cr4, %%rax \n"\
          "mov %%rax, %0\n" : "=m" (crx[id]) ::"ax");
    if ((crx[id] & (1 << 13)) == 0) {
        asm (   " mov  %%cr4, %%rax     \n"\
                " bts  $13, %%rax       \n"\
                " mov  %%rax, %%cr4     " ::: "ax" );

        asm (   "mov %%cr4, %%rax \n"\
                "mov %%rax, %0\n" : "=m" (crx[id]) ::"ax");
    } else {
        pr_warn("VMXE in CR4 already been set, VT-X may be used by other VMM\n");
    }
}

void turn_off_vmxe( void *dummy )
{
    u64 crx[16];

    asm ( "mov %%cr4, %%rax \n"\
          "mov %%rax, %0\n" : "=m" (crx[id]) ::"ax");
    crx[id] &= ~(1 << 13);
    asm (   " mov  %%cr4, %%rax     \n"\
            " btr  $13, %%rax       \n"\
            " mov  %%rax, %%cr4     " ::: "ax" );
}

static void vmxon_exit(void)
{
    if (vmxon_success == 1) {
        printk("<1> Machine in vmxon: Attempting vmxoff\n");
        do_vmclear();
        do_vmxoff();
        vmxon_success = 0;
    }
    turn_off_vmxe(NULL);
    deallocate_vmcs_region();
    deallocate_vmxon_region();
}

static int vmxon_init(void)
{
    unsigned long   field_1;
    u32  value_1    =0;
    int  cpuid_leaf =1;
    int  cpuid_ecx  =0;
    u64  msr3a_value = 0;
    u32     lo[2], hi[2];
    u64  start, end;

    printk("<1> In vmxon\n");

    asm volatile("cpuid\n\t"
            :"=c"(cpuid_ecx)
            :"a"(cpuid_leaf)
            :"%rbx","%rdx");

    if ((cpuid_ecx >> CPUID_VMX_BIT) & 1) {
        printk("<1> VMX supported CPU.\n");
    } else {
        printk("<1> VMX not supported by CPU. Not doing anything\n");
        goto finish_here;
    }

    rdmsrl_safe(feature_control_msr_addr, &msr3a_value);

    if (msr3a_value & 1) {
        if ((msr3a_value >> 2) & 1) {
            printk("MSR 0x3A:Lock bit is on.VMXON bit is on.OK\n");
        } else {
            printk("MSR 0x3A:Lock bit is on.VMXONbit is off.Cannot do vmxon\n");
            goto finish_here;
        }
    } else {
        printk("MSR 0x3A: Lock bit is not on. Not doing anything\n");
        goto finish_here;
    }

    allocate_vmxon_region();

    if (vmxon_region == NULL) {
        printk("<1> Error allocating vmxon region\n");
        vmxon_exit();
        vmxon_success = -ENOMEM;
        return vmxon_success;
    }

    allocate_vmcs_region();
    alloc_failure = (vmcs_guest_region == NULL)  ||
                    (io_bitmap_a_region == NULL) ||
                    (io_bitmap_b_region == NULL) ||
                    (msr_bitmap_region == NULL)  ||
                    (virtual_apic_page == NULL);

    if (alloc_failure) {
        printk("<1> Error allocating vmcs guest region\n");
        vmxon_exit();
        vmptrld_success = -ENOMEM;
        return vmptrld_success;
    }

    vmxon_setup_revid();
    vmxon_phy_region = virt_to_phys(vmxon_region);
    memset(vmxon_region, 0, MYPAGE_SIZE);
    memcpy(vmxon_region, &vmx_rev_id, 4); //copy revision id to vmxon region

    turn_on_vmxe(NULL);

    do_vmxon();

    vmcs_phy_region = virt_to_phys(vmcs_guest_region);
    memset(vmcs_guest_region, 0, MYPAGE_SIZE);
    memcpy(vmcs_guest_region, &vmx_rev_id, 4); //copy revision id to vmcs region

    do_vmclear();
    do_vmptrld();

    initialize_guest_vmcs();

    //host rip
    asm ("movq $0x6c16, %rdx");
    asm ("movq $vmexit_handler, %rax");
    asm ("vmwrite %rax, %rdx");

    //guest rip
    asm ("movq $0x681e, %rdx");
    asm ("movq $guest_entry_point, %rax");
    asm ("vmwrite %rax, %rdx");

    printk("<1> Doing vmlaunch now..\n");

    asm volatile (
            "vmlaunch                      \n"\
            "jbe vmexit_handler            \n" \
            "nop                           \n" \
            "guest_entry_point:            \n" \
            "   vmcall                     \n" \
            "   ud2                        \n" \
            "vmexit_handler: \n");

    asm volatile("sti");

    printk("<1> After vmexit\n");

    field_1 = VMX_EXIT_REASON;
    value_1 = do_vmread(field_1);
    printk("<1> Guest VMexit reason: 0x%x\n",value_1);

finish_here:
    vmxon_exit(); //do vmxoff
    printk("<1> Done\n");
    return 0;
}

static void vmxon_exit_dummy(void)
{
    printk("In Function %s\n", __func__);
}

module_init(vmxon_init);
module_exit(vmxon_exit_dummy);

Without calling 'vmlaunch', module loading/unloading are OK. Please help check if there is anything wrong.

linux
x86-64
virtualization
asked on Stack Overflow Apr 22, 2019 by wangt13

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0