Я портирую VMLaunch simple на Ubuntu 16.04, код на https://github.com/vishmohan/vmlaunch. И изменил vmlaunch_simple.c, чтобы он почти работал в Ubuntu 16.04.
Когда я загружаюмодуль (KVM и KVM_intel были выгружены), зависание «insmod vmlaunch_simple.ko», где включается kexec / kdump и перезагружается хост.
После перезагрузки журнал сбоя показывал ниже,
[ 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
Исходный код,
#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);
Без вызова vmlaunch, загрузка / выгрузка модуля в порядке.Пожалуйста, помогите проверить, если что-то не так.