From 6c09fb82edbf8c19be0a3ea3e1e823c8891ee5a1 Mon Sep 17 00:00:00 2001 From: Marios Pomonis Date: Thu, 27 Mar 2025 01:49:18 -0700 Subject: executor/kvm: bug fix and minor refactor in KVM * Fixes a bug when setting up a 64-bit guest by making the bit manipulation macros produce unsigned long long: To create a VCPU that has paging enabled, one needs to set the CR0.PE and CR0.PG bits in CR0. The latter is problematic when setting up a 64-bit guest since if the macro is not using 1ULL, it sign extends the output (in 64-bit mode the control registers are extended to 64-bits with some of the CR0[32:63] bits reserved). This results in either failing the KVM_SET_SREGS ioctl (in newer kernel versions) or just failing the KVM_RUN ioctl with EXIT_REASON_INVALID_STATE. * Moved the bit manipulation definitions from the amd64 specific to the generic kvm header to consolidate them with the already existing ones. Prefixed them with X86_ to avoid confusion. --- executor/common_kvm_amd64.h | 351 +++++++++++++++++++------------------------- executor/common_kvm_arm64.h | 5 - executor/kvm.h | 202 ++++++++++++++++--------- executor/kvm_amd64.S | 96 ++++++------ 4 files changed, 326 insertions(+), 328 deletions(-) diff --git a/executor/common_kvm_amd64.h b/executor/common_kvm_amd64.h index 3683325de..ef0a769b0 100644 --- a/executor/common_kvm_amd64.h +++ b/executor/common_kvm_amd64.h @@ -14,63 +14,6 @@ #define KVM_SMI _IO(KVMIO, 0xb7) #endif -#define CR0_PE 1 -#define CR0_MP (1 << 1) -#define CR0_EM (1 << 2) -#define CR0_TS (1 << 3) -#define CR0_ET (1 << 4) -#define CR0_NE (1 << 5) -#define CR0_WP (1 << 16) -#define CR0_AM (1 << 18) -#define CR0_NW (1 << 29) -#define CR0_CD (1 << 30) -#define CR0_PG (1 << 31) - -#define CR4_VME 1 -#define CR4_PVI (1 << 1) -#define CR4_TSD (1 << 2) -#define CR4_DE (1 << 3) -#define CR4_PSE (1 << 4) -#define CR4_PAE (1 << 5) -#define CR4_MCE (1 << 6) -#define CR4_PGE (1 << 7) -#define CR4_PCE (1 << 8) -#define CR4_OSFXSR (1 << 8) -#define CR4_OSXMMEXCPT (1 << 10) -#define CR4_UMIP (1 << 11) -#define CR4_VMXE (1 << 13) -#define CR4_SMXE (1 << 14) -#define CR4_FSGSBASE (1 << 16) -#define CR4_PCIDE (1 << 17) -#define CR4_OSXSAVE (1 << 18) -#define CR4_SMEP (1 << 20) -#define CR4_SMAP (1 << 21) -#define CR4_PKE (1 << 22) - -#define EFER_SCE 1 -#define EFER_LME (1 << 8) -#define EFER_LMA (1 << 10) -#define EFER_NXE (1 << 11) -#define EFER_SVME (1 << 12) -#define EFER_LMSLE (1 << 13) -#define EFER_FFXSR (1 << 14) -#define EFER_TCE (1 << 15) - -// 32-bit page directory entry bits -#define PDE32_PRESENT 1 -#define PDE32_RW (1 << 1) -#define PDE32_USER (1 << 2) -#define PDE32_PS (1 << 7) - -// 64-bit page * entry bits -#define PDE64_PRESENT 1 -#define PDE64_RW (1 << 1) -#define PDE64_USER (1 << 2) -#define PDE64_ACCESSED (1 << 5) -#define PDE64_DIRTY (1 << 6) -#define PDE64_PS (1 << 7) -#define PDE64_G (1 << 8) - struct tss16 { uint16 prev; uint16 sp0; @@ -160,22 +103,22 @@ static void setup_syscall_msrs(int cpufd, uint16 sel_cs, uint16 sel_cs_cpl3) struct kvm_msrs* msrs = (struct kvm_msrs*)buf; struct kvm_msr_entry* entries = msrs->entries; msrs->nmsrs = 5; - entries[0].index = MSR_IA32_SYSENTER_CS; + entries[0].index = X86_MSR_IA32_SYSENTER_CS; entries[0].data = sel_cs; - entries[1].index = MSR_IA32_SYSENTER_ESP; - entries[1].data = ADDR_STACK0; - entries[2].index = MSR_IA32_SYSENTER_EIP; - entries[2].data = ADDR_VAR_SYSEXIT; - entries[3].index = MSR_IA32_STAR; + entries[1].index = X86_MSR_IA32_SYSENTER_ESP; + entries[1].data = X86_ADDR_STACK0; + entries[2].index = X86_MSR_IA32_SYSENTER_EIP; + entries[2].data = X86_ADDR_VAR_SYSEXIT; + entries[3].index = X86_MSR_IA32_STAR; entries[3].data = ((uint64)sel_cs << 32) | ((uint64)sel_cs_cpl3 << 48); - entries[4].index = MSR_IA32_LSTAR; - entries[4].data = ADDR_VAR_SYSRET; + entries[4].index = X86_MSR_IA32_LSTAR; + entries[4].data = X86_ADDR_VAR_SYSRET; ioctl(cpufd, KVM_SET_MSRS, msrs); } static void setup_32bit_idt(struct kvm_sregs* sregs, char* host_mem, uintptr_t guest_mem) { - sregs->idt.base = guest_mem + ADDR_VAR_IDT; + sregs->idt.base = guest_mem + X86_ADDR_VAR_IDT; sregs->idt.limit = 0x1ff; uint64* idt = (uint64*)(host_mem + sregs->idt.base); for (int i = 0; i < 32; i++) { @@ -185,35 +128,35 @@ static void setup_32bit_idt(struct kvm_sregs* sregs, char* host_mem, uintptr_t g case 0: // 16-bit interrupt gate gate.type = 6; - gate.base = SEL_CS16; + gate.base = X86_SEL_CS16; break; case 1: // 16-bit trap gate gate.type = 7; - gate.base = SEL_CS16; + gate.base = X86_SEL_CS16; break; case 2: // 16-bit task gate gate.type = 3; - gate.base = SEL_TGATE16; + gate.base = X86_SEL_TGATE16; break; case 3: // 32-bit interrupt gate gate.type = 14; - gate.base = SEL_CS32; + gate.base = X86_SEL_CS32; break; case 4: // 32-bit trap gate gate.type = 15; - gate.base = SEL_CS32; + gate.base = X86_SEL_CS32; break; case 5: // 32-bit task gate gate.type = 11; - gate.base = SEL_TGATE32; + gate.base = X86_SEL_TGATE32; break; } - gate.limit = guest_mem + ADDR_VAR_USER_CODE2; // entry offset + gate.limit = guest_mem + X86_ADDR_VAR_USER_CODE2; // entry offset gate.present = 1; gate.dpl = 0; gate.s = 0; @@ -227,15 +170,15 @@ static void setup_32bit_idt(struct kvm_sregs* sregs, char* host_mem, uintptr_t g static void setup_64bit_idt(struct kvm_sregs* sregs, char* host_mem, uintptr_t guest_mem) { - sregs->idt.base = guest_mem + ADDR_VAR_IDT; + sregs->idt.base = guest_mem + X86_ADDR_VAR_IDT; sregs->idt.limit = 0x1ff; uint64* idt = (uint64*)(host_mem + sregs->idt.base); for (int i = 0; i < 32; i++) { struct kvm_segment gate; gate.selector = (i * 2) << 3; gate.type = (i & 1) ? 14 : 15; // interrupt or trap gate - gate.base = SEL_CS64; - gate.limit = guest_mem + ADDR_VAR_USER_CODE2; // entry offset + gate.base = X86_SEL_CS64; + gate.limit = guest_mem + X86_ADDR_VAR_USER_CODE2; // entry offset gate.present = 1; gate.dpl = 0; gate.s = 0; @@ -314,18 +257,18 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat struct kvm_regs regs; memset(®s, 0, sizeof(regs)); - regs.rip = guest_mem + ADDR_TEXT; - regs.rsp = ADDR_STACK0; + regs.rip = guest_mem + X86_ADDR_TEXT; + regs.rsp = X86_ADDR_STACK0; - sregs.gdt.base = guest_mem + ADDR_GDT; + sregs.gdt.base = guest_mem + X86_ADDR_GDT; sregs.gdt.limit = 256 * sizeof(uint64) - 1; uint64* gdt = (uint64*)(host_mem + sregs.gdt.base); struct kvm_segment seg_ldt; memset(&seg_ldt, 0, sizeof(seg_ldt)); - seg_ldt.selector = SEL_LDT; + seg_ldt.selector = X86_SEL_LDT; seg_ldt.type = 2; - seg_ldt.base = guest_mem + ADDR_LDT; + seg_ldt.base = guest_mem + X86_ADDR_LDT; seg_ldt.limit = 256 * sizeof(uint64) - 1; seg_ldt.present = 1; seg_ldt.dpl = 0; @@ -338,7 +281,7 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat struct kvm_segment seg_cs16; memset(&seg_cs16, 0, sizeof(seg_cs16)); - seg_cs16.selector = SEL_CS16; + seg_cs16.selector = X86_SEL_CS16; seg_cs16.type = 11; seg_cs16.base = 0; seg_cs16.limit = 0xfffff; @@ -350,53 +293,53 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat seg_cs16.l = 0; struct kvm_segment seg_ds16 = seg_cs16; - seg_ds16.selector = SEL_DS16; + seg_ds16.selector = X86_SEL_DS16; seg_ds16.type = 3; struct kvm_segment seg_cs16_cpl3 = seg_cs16; - seg_cs16_cpl3.selector = SEL_CS16_CPL3; + seg_cs16_cpl3.selector = X86_SEL_CS16_CPL3; seg_cs16_cpl3.dpl = 3; struct kvm_segment seg_ds16_cpl3 = seg_ds16; - seg_ds16_cpl3.selector = SEL_DS16_CPL3; + seg_ds16_cpl3.selector = X86_SEL_DS16_CPL3; seg_ds16_cpl3.dpl = 3; struct kvm_segment seg_cs32 = seg_cs16; - seg_cs32.selector = SEL_CS32; + seg_cs32.selector = X86_SEL_CS32; seg_cs32.db = 1; struct kvm_segment seg_ds32 = seg_ds16; - seg_ds32.selector = SEL_DS32; + seg_ds32.selector = X86_SEL_DS32; seg_ds32.db = 1; struct kvm_segment seg_cs32_cpl3 = seg_cs32; - seg_cs32_cpl3.selector = SEL_CS32_CPL3; + seg_cs32_cpl3.selector = X86_SEL_CS32_CPL3; seg_cs32_cpl3.dpl = 3; struct kvm_segment seg_ds32_cpl3 = seg_ds32; - seg_ds32_cpl3.selector = SEL_DS32_CPL3; + seg_ds32_cpl3.selector = X86_SEL_DS32_CPL3; seg_ds32_cpl3.dpl = 3; struct kvm_segment seg_cs64 = seg_cs16; - seg_cs64.selector = SEL_CS64; + seg_cs64.selector = X86_SEL_CS64; seg_cs64.l = 1; struct kvm_segment seg_ds64 = seg_ds32; - seg_ds64.selector = SEL_DS64; + seg_ds64.selector = X86_SEL_DS64; struct kvm_segment seg_cs64_cpl3 = seg_cs64; - seg_cs64_cpl3.selector = SEL_CS64_CPL3; + seg_cs64_cpl3.selector = X86_SEL_CS64_CPL3; seg_cs64_cpl3.dpl = 3; struct kvm_segment seg_ds64_cpl3 = seg_ds64; - seg_ds64_cpl3.selector = SEL_DS64_CPL3; + seg_ds64_cpl3.selector = X86_SEL_DS64_CPL3; seg_ds64_cpl3.dpl = 3; struct kvm_segment seg_tss32; memset(&seg_tss32, 0, sizeof(seg_tss32)); - seg_tss32.selector = SEL_TSS32; + seg_tss32.selector = X86_SEL_TSS32; seg_tss32.type = 9; - seg_tss32.base = ADDR_VAR_TSS32; + seg_tss32.base = X86_ADDR_VAR_TSS32; seg_tss32.limit = 0x1ff; seg_tss32.present = 1; seg_tss32.dpl = 0; @@ -406,49 +349,49 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat seg_tss32.l = 0; struct kvm_segment seg_tss32_2 = seg_tss32; - seg_tss32_2.selector = SEL_TSS32_2; - seg_tss32_2.base = ADDR_VAR_TSS32_2; + seg_tss32_2.selector = X86_SEL_TSS32_2; + seg_tss32_2.base = X86_ADDR_VAR_TSS32_2; struct kvm_segment seg_tss32_cpl3 = seg_tss32; - seg_tss32_cpl3.selector = SEL_TSS32_CPL3; - seg_tss32_cpl3.base = ADDR_VAR_TSS32_CPL3; + seg_tss32_cpl3.selector = X86_SEL_TSS32_CPL3; + seg_tss32_cpl3.base = X86_ADDR_VAR_TSS32_CPL3; struct kvm_segment seg_tss32_vm86 = seg_tss32; - seg_tss32_vm86.selector = SEL_TSS32_VM86; - seg_tss32_vm86.base = ADDR_VAR_TSS32_VM86; + seg_tss32_vm86.selector = X86_SEL_TSS32_VM86; + seg_tss32_vm86.base = X86_ADDR_VAR_TSS32_VM86; struct kvm_segment seg_tss16 = seg_tss32; - seg_tss16.selector = SEL_TSS16; - seg_tss16.base = ADDR_VAR_TSS16; + seg_tss16.selector = X86_SEL_TSS16; + seg_tss16.base = X86_ADDR_VAR_TSS16; seg_tss16.limit = 0xff; seg_tss16.type = 1; struct kvm_segment seg_tss16_2 = seg_tss16; - seg_tss16_2.selector = SEL_TSS16_2; - seg_tss16_2.base = ADDR_VAR_TSS16_2; + seg_tss16_2.selector = X86_SEL_TSS16_2; + seg_tss16_2.base = X86_ADDR_VAR_TSS16_2; seg_tss16_2.dpl = 0; struct kvm_segment seg_tss16_cpl3 = seg_tss16; - seg_tss16_cpl3.selector = SEL_TSS16_CPL3; - seg_tss16_cpl3.base = ADDR_VAR_TSS16_CPL3; + seg_tss16_cpl3.selector = X86_SEL_TSS16_CPL3; + seg_tss16_cpl3.base = X86_ADDR_VAR_TSS16_CPL3; seg_tss16_cpl3.dpl = 3; struct kvm_segment seg_tss64 = seg_tss32; - seg_tss64.selector = SEL_TSS64; - seg_tss64.base = ADDR_VAR_TSS64; + seg_tss64.selector = X86_SEL_TSS64; + seg_tss64.base = X86_ADDR_VAR_TSS64; seg_tss64.limit = 0x1ff; struct kvm_segment seg_tss64_cpl3 = seg_tss64; - seg_tss64_cpl3.selector = SEL_TSS64_CPL3; - seg_tss64_cpl3.base = ADDR_VAR_TSS64_CPL3; + seg_tss64_cpl3.selector = X86_SEL_TSS64_CPL3; + seg_tss64_cpl3.base = X86_ADDR_VAR_TSS64_CPL3; seg_tss64_cpl3.dpl = 3; struct kvm_segment seg_cgate16; memset(&seg_cgate16, 0, sizeof(seg_cgate16)); - seg_cgate16.selector = SEL_CGATE16; + seg_cgate16.selector = X86_SEL_CGATE16; seg_cgate16.type = 4; - seg_cgate16.base = SEL_CS16 | (2 << 16); // selector + param count - seg_cgate16.limit = ADDR_VAR_USER_CODE2; // entry offset + seg_cgate16.base = X86_SEL_CS16 | (2 << 16); // selector + param count + seg_cgate16.limit = X86_ADDR_VAR_USER_CODE2; // entry offset seg_cgate16.present = 1; seg_cgate16.dpl = 0; seg_cgate16.s = 0; @@ -458,26 +401,26 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat seg_cgate16.avl = 0; struct kvm_segment seg_tgate16 = seg_cgate16; - seg_tgate16.selector = SEL_TGATE16; + seg_tgate16.selector = X86_SEL_TGATE16; seg_tgate16.type = 3; - seg_cgate16.base = SEL_TSS16_2; + seg_cgate16.base = X86_SEL_TSS16_2; seg_tgate16.limit = 0; struct kvm_segment seg_cgate32 = seg_cgate16; - seg_cgate32.selector = SEL_CGATE32; + seg_cgate32.selector = X86_SEL_CGATE32; seg_cgate32.type = 12; - seg_cgate32.base = SEL_CS32 | (2 << 16); // selector + param count + seg_cgate32.base = X86_SEL_CS32 | (2 << 16); // selector + param count struct kvm_segment seg_tgate32 = seg_cgate32; - seg_tgate32.selector = SEL_TGATE32; + seg_tgate32.selector = X86_SEL_TGATE32; seg_tgate32.type = 11; - seg_tgate32.base = SEL_TSS32_2; + seg_tgate32.base = X86_SEL_TSS32_2; seg_tgate32.limit = 0; struct kvm_segment seg_cgate64 = seg_cgate16; - seg_cgate64.selector = SEL_CGATE64; + seg_cgate64.selector = X86_SEL_CGATE64; seg_cgate64.type = 12; - seg_cgate64.base = SEL_CS64; + seg_cgate64.base = X86_SEL_CS64; int kvmfd = open("/dev/kvm", O_RDWR); char buf[sizeof(struct kvm_cpuid2) + 128 * sizeof(struct kvm_cpuid_entry2)]; @@ -490,39 +433,39 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat const char* text_prefix = 0; int text_prefix_size = 0; - char* host_text = host_mem + ADDR_TEXT; + char* host_text = host_mem + X86_ADDR_TEXT; if (text_type == 8) { if (flags & KVM_SETUP_SMM) { if (flags & KVM_SETUP_PROTECTED) { sregs.cs = seg_cs16; sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16; - sregs.cr0 |= CR0_PE; + sregs.cr0 |= X86_CR0_PE; } else { sregs.cs.selector = 0; sregs.cs.base = 0; } - *(host_mem + ADDR_TEXT) = 0xf4; // hlt for rsm + *(host_mem + X86_ADDR_TEXT) = 0xf4; // hlt for rsm host_text = host_mem + 0x8000; ioctl(cpufd, KVM_SMI, 0); } else if (flags & KVM_SETUP_VIRT86) { sregs.cs = seg_cs32; sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32; - sregs.cr0 |= CR0_PE; - sregs.efer |= EFER_SCE; + sregs.cr0 |= X86_CR0_PE; + sregs.efer |= X86_EFER_SCE; - setup_syscall_msrs(cpufd, SEL_CS32, SEL_CS32_CPL3); + setup_syscall_msrs(cpufd, X86_SEL_CS32, X86_SEL_CS32_CPL3); setup_32bit_idt(&sregs, host_mem, guest_mem); if (flags & KVM_SETUP_PAGING) { - uint64 pd_addr = guest_mem + ADDR_PD; - uint64* pd = (uint64*)(host_mem + ADDR_PD); + uint64 pd_addr = guest_mem + X86_ADDR_PD; + uint64* pd = (uint64*)(host_mem + X86_ADDR_PD); // A single 4MB page to cover the memory region - pd[0] = PDE32_PRESENT | PDE32_RW | PDE32_USER | PDE32_PS; + pd[0] = X86_PDE32_PRESENT | X86_PDE32_RW | X86_PDE32_USER | X86_PDE32_PS; sregs.cr3 = pd_addr; - sregs.cr4 |= CR4_PSE; + sregs.cr4 |= X86_CR4_PSE; text_prefix = kvm_asm32_paged_vm86; text_prefix_size = sizeof(kvm_asm32_paged_vm86) - 1; @@ -542,22 +485,22 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat text_prefix = kvm_asm16_cpl3; text_prefix_size = sizeof(kvm_asm16_cpl3) - 1; } else { - sregs.cr0 |= CR0_PE; + sregs.cr0 |= X86_CR0_PE; sregs.cs = seg_cs16; sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16; } } else if (text_type == 32) { - sregs.cr0 |= CR0_PE; - sregs.efer |= EFER_SCE; + sregs.cr0 |= X86_CR0_PE; + sregs.efer |= X86_EFER_SCE; - setup_syscall_msrs(cpufd, SEL_CS32, SEL_CS32_CPL3); + setup_syscall_msrs(cpufd, X86_SEL_CS32, X86_SEL_CS32_CPL3); setup_32bit_idt(&sregs, host_mem, guest_mem); if (flags & KVM_SETUP_SMM) { sregs.cs = seg_cs32; sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32; - *(host_mem + ADDR_TEXT) = 0xf4; // hlt for rsm + *(host_mem + X86_ADDR_TEXT) = 0xf4; // hlt for rsm host_text = host_mem + 0x8000; ioctl(cpufd, KVM_SMI, 0); @@ -565,12 +508,12 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat sregs.cs = seg_cs32; sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32; - uint64 pd_addr = guest_mem + ADDR_PD; - uint64* pd = (uint64*)(host_mem + ADDR_PD); + uint64 pd_addr = guest_mem + X86_ADDR_PD; + uint64* pd = (uint64*)(host_mem + X86_ADDR_PD); // A single 4MB page to cover the memory region - pd[0] = PDE32_PRESENT | PDE32_RW | PDE32_USER | PDE32_PS; + pd[0] = X86_PDE32_PRESENT | X86_PDE32_RW | X86_PDE32_USER | X86_PDE32_PS; sregs.cr3 = pd_addr; - sregs.cr4 |= CR4_PSE; + sregs.cr4 |= X86_CR4_PSE; text_prefix = kvm_asm32_paged; text_prefix_size = sizeof(kvm_asm32_paged) - 1; @@ -582,34 +525,34 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32; } } else { - sregs.efer |= EFER_LME | EFER_SCE; - sregs.cr0 |= CR0_PE; + sregs.efer |= X86_EFER_LME | X86_EFER_SCE; + sregs.cr0 |= X86_CR0_PE; - setup_syscall_msrs(cpufd, SEL_CS64, SEL_CS64_CPL3); + setup_syscall_msrs(cpufd, X86_SEL_CS64, X86_SEL_CS64_CPL3); setup_64bit_idt(&sregs, host_mem, guest_mem); sregs.cs = seg_cs32; sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32; - uint64 pml4_addr = guest_mem + ADDR_PML4; - uint64* pml4 = (uint64*)(host_mem + ADDR_PML4); - uint64 pdpt_addr = guest_mem + ADDR_PDP; - uint64* pdpt = (uint64*)(host_mem + ADDR_PDP); - uint64 pd_addr = guest_mem + ADDR_PD; - uint64* pd = (uint64*)(host_mem + ADDR_PD); - pml4[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | pdpt_addr; - pdpt[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | pd_addr; - pd[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | PDE64_PS; + uint64 pml4_addr = guest_mem + X86_ADDR_PML4; + uint64* pml4 = (uint64*)(host_mem + X86_ADDR_PML4); + uint64 pdpt_addr = guest_mem + X86_ADDR_PDP; + uint64* pdpt = (uint64*)(host_mem + X86_ADDR_PDP); + uint64 pd_addr = guest_mem + X86_ADDR_PD; + uint64* pd = (uint64*)(host_mem + X86_ADDR_PD); + pml4[0] = X86_PDE64_PRESENT | X86_PDE64_RW | X86_PDE64_USER | pdpt_addr; + pdpt[0] = X86_PDE64_PRESENT | X86_PDE64_RW | X86_PDE64_USER | pd_addr; + pd[0] = X86_PDE64_PRESENT | X86_PDE64_RW | X86_PDE64_USER | X86_PDE64_PS; sregs.cr3 = pml4_addr; - sregs.cr4 |= CR4_PAE; + sregs.cr4 |= X86_CR4_PAE; if (flags & KVM_SETUP_VM) { - sregs.cr0 |= CR0_NE; + sregs.cr0 |= X86_CR0_NE; - *((uint64*)(host_mem + ADDR_VAR_VMXON_PTR)) = ADDR_VAR_VMXON; - *((uint64*)(host_mem + ADDR_VAR_VMCS_PTR)) = ADDR_VAR_VMCS; - memcpy(host_mem + ADDR_VAR_VMEXIT_CODE, kvm_asm64_vm_exit, sizeof(kvm_asm64_vm_exit) - 1); - *((uint64*)(host_mem + ADDR_VAR_VMEXIT_PTR)) = ADDR_VAR_VMEXIT_CODE; + *((uint64*)(host_mem + X86_ADDR_VAR_VMXON_PTR)) = X86_ADDR_VAR_VMXON; + *((uint64*)(host_mem + X86_ADDR_VAR_VMCS_PTR)) = X86_ADDR_VAR_VMCS; + memcpy(host_mem + X86_ADDR_VAR_VMEXIT_CODE, kvm_asm64_vm_exit, sizeof(kvm_asm64_vm_exit) - 1); + *((uint64*)(host_mem + X86_ADDR_VAR_VMEXIT_PTR)) = X86_ADDR_VAR_VMEXIT_CODE; text_prefix = kvm_asm64_init_vm; text_prefix_size = sizeof(kvm_asm64_init_vm) - 1; @@ -624,48 +567,48 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat struct tss16 tss16; memset(&tss16, 0, sizeof(tss16)); - tss16.ss0 = tss16.ss1 = tss16.ss2 = SEL_DS16; - tss16.sp0 = tss16.sp1 = tss16.sp2 = ADDR_STACK0; - tss16.ip = ADDR_VAR_USER_CODE2; + tss16.ss0 = tss16.ss1 = tss16.ss2 = X86_SEL_DS16; + tss16.sp0 = tss16.sp1 = tss16.sp2 = X86_ADDR_STACK0; + tss16.ip = X86_ADDR_VAR_USER_CODE2; tss16.flags = (1 << 1); - tss16.cs = SEL_CS16; - tss16.es = tss16.ds = tss16.ss = SEL_DS16; - tss16.ldt = SEL_LDT; + tss16.cs = X86_SEL_CS16; + tss16.es = tss16.ds = tss16.ss = X86_SEL_DS16; + tss16.ldt = X86_SEL_LDT; struct tss16* tss16_addr = (struct tss16*)(host_mem + seg_tss16_2.base); memcpy(tss16_addr, &tss16, sizeof(tss16)); memset(&tss16, 0, sizeof(tss16)); - tss16.ss0 = tss16.ss1 = tss16.ss2 = SEL_DS16; - tss16.sp0 = tss16.sp1 = tss16.sp2 = ADDR_STACK0; - tss16.ip = ADDR_VAR_USER_CODE2; + tss16.ss0 = tss16.ss1 = tss16.ss2 = X86_SEL_DS16; + tss16.sp0 = tss16.sp1 = tss16.sp2 = X86_ADDR_STACK0; + tss16.ip = X86_ADDR_VAR_USER_CODE2; tss16.flags = (1 << 1); - tss16.cs = SEL_CS16_CPL3; - tss16.es = tss16.ds = tss16.ss = SEL_DS16_CPL3; - tss16.ldt = SEL_LDT; + tss16.cs = X86_SEL_CS16_CPL3; + tss16.es = tss16.ds = tss16.ss = X86_SEL_DS16_CPL3; + tss16.ldt = X86_SEL_LDT; struct tss16* tss16_cpl3_addr = (struct tss16*)(host_mem + seg_tss16_cpl3.base); memcpy(tss16_cpl3_addr, &tss16, sizeof(tss16)); struct tss32 tss32; memset(&tss32, 0, sizeof(tss32)); - tss32.ss0 = tss32.ss1 = tss32.ss2 = SEL_DS32; - tss32.sp0 = tss32.sp1 = tss32.sp2 = ADDR_STACK0; - tss32.ip = ADDR_VAR_USER_CODE; + tss32.ss0 = tss32.ss1 = tss32.ss2 = X86_SEL_DS32; + tss32.sp0 = tss32.sp1 = tss32.sp2 = X86_ADDR_STACK0; + tss32.ip = X86_ADDR_VAR_USER_CODE; tss32.flags = (1 << 1) | (1 << 17); - tss32.ldt = SEL_LDT; + tss32.ldt = X86_SEL_LDT; tss32.cr3 = sregs.cr3; tss32.io_bitmap = offsetof(struct tss32, io_bitmap); struct tss32* tss32_addr = (struct tss32*)(host_mem + seg_tss32_vm86.base); memcpy(tss32_addr, &tss32, sizeof(tss32)); memset(&tss32, 0, sizeof(tss32)); - tss32.ss0 = tss32.ss1 = tss32.ss2 = SEL_DS32; - tss32.sp0 = tss32.sp1 = tss32.sp2 = ADDR_STACK0; - tss32.ip = ADDR_VAR_USER_CODE; + tss32.ss0 = tss32.ss1 = tss32.ss2 = X86_SEL_DS32; + tss32.sp0 = tss32.sp1 = tss32.sp2 = X86_ADDR_STACK0; + tss32.ip = X86_ADDR_VAR_USER_CODE; tss32.flags = (1 << 1); tss32.cr3 = sregs.cr3; - tss32.es = tss32.ds = tss32.ss = tss32.gs = tss32.fs = SEL_DS32; - tss32.cs = SEL_CS32; - tss32.ldt = SEL_LDT; + tss32.es = tss32.ds = tss32.ss = tss32.gs = tss32.fs = X86_SEL_DS32; + tss32.cs = X86_SEL_CS32; + tss32.ldt = X86_SEL_LDT; tss32.cr3 = sregs.cr3; tss32.io_bitmap = offsetof(struct tss32, io_bitmap); struct tss32* tss32_cpl3_addr = (struct tss32*)(host_mem + seg_tss32_2.base); @@ -673,17 +616,17 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat struct tss64 tss64; memset(&tss64, 0, sizeof(tss64)); - tss64.rsp[0] = ADDR_STACK0; - tss64.rsp[1] = ADDR_STACK0; - tss64.rsp[2] = ADDR_STACK0; + tss64.rsp[0] = X86_ADDR_STACK0; + tss64.rsp[1] = X86_ADDR_STACK0; + tss64.rsp[2] = X86_ADDR_STACK0; tss64.io_bitmap = offsetof(struct tss64, io_bitmap); struct tss64* tss64_addr = (struct tss64*)(host_mem + seg_tss64.base); memcpy(tss64_addr, &tss64, sizeof(tss64)); memset(&tss64, 0, sizeof(tss64)); - tss64.rsp[0] = ADDR_STACK0; - tss64.rsp[1] = ADDR_STACK0; - tss64.rsp[2] = ADDR_STACK0; + tss64.rsp[0] = X86_ADDR_STACK0; + tss64.rsp[1] = X86_ADDR_STACK0; + tss64.rsp[2] = X86_ADDR_STACK0; tss64.io_bitmap = offsetof(struct tss64, io_bitmap); struct tss64* tss64_cpl3_addr = (struct tss64*)(host_mem + seg_tss64_cpl3.base); memcpy(tss64_cpl3_addr, &tss64, sizeof(tss64)); @@ -695,24 +638,24 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat // Replace 0xbadc0de in LJMP with offset of a next instruction. void* patch = memmem(host_text, text_prefix_size, "\xde\xc0\xad\x0b", 4); if (patch) - *((uint32*)patch) = guest_mem + ADDR_TEXT + ((char*)patch - host_text) + 6; - uint16 magic = PREFIX_SIZE; + *((uint32*)patch) = guest_mem + X86_ADDR_TEXT + ((char*)patch - host_text) + 6; + uint16 magic = X86_PREFIX_SIZE; patch = memmem(host_text, text_prefix_size, &magic, sizeof(magic)); if (patch) - *((uint16*)patch) = guest_mem + ADDR_TEXT + text_prefix_size; + *((uint16*)patch) = guest_mem + X86_ADDR_TEXT + text_prefix_size; } memcpy((void*)(host_text + text_prefix_size), text, text_size); *(host_text + text_prefix_size + text_size) = 0xf4; // hlt - memcpy(host_mem + ADDR_VAR_USER_CODE, text, text_size); - *(host_mem + ADDR_VAR_USER_CODE + text_size) = 0xf4; // hlt + memcpy(host_mem + X86_ADDR_VAR_USER_CODE, text, text_size); + *(host_mem + X86_ADDR_VAR_USER_CODE + text_size) = 0xf4; // hlt - *(host_mem + ADDR_VAR_HLT) = 0xf4; // hlt - memcpy(host_mem + ADDR_VAR_SYSRET, "\x0f\x07\xf4", 3); - memcpy(host_mem + ADDR_VAR_SYSEXIT, "\x0f\x35\xf4", 3); + *(host_mem + X86_ADDR_VAR_HLT) = 0xf4; // hlt + memcpy(host_mem + X86_ADDR_VAR_SYSRET, "\x0f\x07\xf4", 3); + memcpy(host_mem + X86_ADDR_VAR_SYSEXIT, "\x0f\x35\xf4", 3); - *(uint64*)(host_mem + ADDR_VAR_VMWRITE_FLD) = 0; - *(uint64*)(host_mem + ADDR_VAR_VMWRITE_VAL) = 0; + *(uint64*)(host_mem + X86_ADDR_VAR_VMWRITE_FLD) = 0; + *(uint64*)(host_mem + X86_ADDR_VAR_VMWRITE_VAL) = 0; if (opt_count > 2) opt_count = 2; @@ -721,15 +664,15 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat uint64 val = opt_array_ptr[i].val; switch (typ % 9) { case 0: - sregs.cr0 ^= val & (CR0_MP | CR0_EM | CR0_ET | CR0_NE | CR0_WP | CR0_AM | CR0_NW | CR0_CD); + sregs.cr0 ^= val & (X86_CR0_MP | X86_CR0_EM | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | X86_CR0_NW | X86_CR0_CD); break; case 1: - sregs.cr4 ^= val & (CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_MCE | CR4_PGE | CR4_PCE | - CR4_OSFXSR | CR4_OSXMMEXCPT | CR4_UMIP | CR4_VMXE | CR4_SMXE | CR4_FSGSBASE | CR4_PCIDE | - CR4_OSXSAVE | CR4_SMEP | CR4_SMAP | CR4_PKE); + sregs.cr4 ^= val & (X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE | X86_CR4_MCE | X86_CR4_PGE | X86_CR4_PCE | + X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT | X86_CR4_UMIP | X86_CR4_VMXE | X86_CR4_SMXE | X86_CR4_FSGSBASE | X86_CR4_PCIDE | + X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE); break; case 2: - sregs.efer ^= val & (EFER_SCE | EFER_NXE | EFER_SVME | EFER_LMSLE | EFER_FFXSR | EFER_TCE); + sregs.efer ^= val & (X86_EFER_SCE | X86_EFER_NXE | X86_EFER_SVME | X86_EFER_LMSLE | X86_EFER_FFXSR | X86_EFER_TCE); break; case 3: val &= ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 12) | (1 << 13) | (1 << 14) | @@ -761,8 +704,8 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat seg_ds64_cpl3.type = val & 0xf; break; case 8: - *(uint64*)(host_mem + ADDR_VAR_VMWRITE_FLD) = (val & 0xffff); - *(uint64*)(host_mem + ADDR_VAR_VMWRITE_VAL) = (val >> 16); + *(uint64*)(host_mem + X86_ADDR_VAR_VMWRITE_FLD) = (val & 0xffff); + *(uint64*)(host_mem + X86_ADDR_VAR_VMWRITE_VAL) = (val >> 16); break; default: fail("bad kvm setup opt"); diff --git a/executor/common_kvm_arm64.h b/executor/common_kvm_arm64.h index 6feec78ab..97a6429fe 100644 --- a/executor/common_kvm_arm64.h +++ b/executor/common_kvm_arm64.h @@ -10,11 +10,6 @@ #if SYZ_EXECUTOR || __NR_syz_kvm_setup_cpu || __NR_syz_kvm_add_vcpu || __NR_syz_kvm_setup_syzos_vm #include "common_kvm_arm64_syzos.h" - -#define KVM_MAX_VCPU 4 -#define KVM_PAGE_SIZE (4 << 10) -#define KVM_GUEST_MEM_SIZE (1024 * KVM_PAGE_SIZE) - #endif #if SYZ_EXECUTOR || __NR_syz_kvm_setup_cpu || __NR_syz_kvm_add_vcpu diff --git a/executor/kvm.h b/executor/kvm.h index d72913bc3..df89d9fb6 100644 --- a/executor/kvm.h +++ b/executor/kvm.h @@ -1,81 +1,141 @@ // Copyright 2017 syzkaller project authors. All rights reserved. // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. -#define ADDR_TEXT 0x0000 -#define ADDR_GDT 0x1000 -#define ADDR_LDT 0x1800 -#define ADDR_PML4 0x2000 -#define ADDR_PDP 0x3000 -#define ADDR_PD 0x4000 -#define ADDR_STACK0 0x0f80 -#define ADDR_VAR_HLT 0x2800 -#define ADDR_VAR_SYSRET 0x2808 -#define ADDR_VAR_SYSEXIT 0x2810 -#define ADDR_VAR_IDT 0x3800 -#define ADDR_VAR_TSS64 0x3a00 -#define ADDR_VAR_TSS64_CPL3 0x3c00 -#define ADDR_VAR_TSS16 0x3d00 -#define ADDR_VAR_TSS16_2 0x3e00 -#define ADDR_VAR_TSS16_CPL3 0x3f00 -#define ADDR_VAR_TSS32 0x4800 -#define ADDR_VAR_TSS32_2 0x4a00 -#define ADDR_VAR_TSS32_CPL3 0x4c00 -#define ADDR_VAR_TSS32_VM86 0x4e00 -#define ADDR_VAR_VMXON_PTR 0x5f00 -#define ADDR_VAR_VMCS_PTR 0x5f08 -#define ADDR_VAR_VMEXIT_PTR 0x5f10 -#define ADDR_VAR_VMWRITE_FLD 0x5f18 -#define ADDR_VAR_VMWRITE_VAL 0x5f20 -#define ADDR_VAR_VMXON 0x6000 -#define ADDR_VAR_VMCS 0x7000 -#define ADDR_VAR_VMEXIT_CODE 0x9000 -#define ADDR_VAR_USER_CODE 0x9100 -#define ADDR_VAR_USER_CODE2 0x9120 +#define X86_ADDR_TEXT 0x0000 +#define X86_ADDR_GDT 0x1000 +#define X86_ADDR_LDT 0x1800 +#define X86_ADDR_PML4 0x2000 +#define X86_ADDR_PDP 0x3000 +#define X86_ADDR_PD 0x4000 +#define X86_ADDR_STACK0 0x0f80 +#define X86_ADDR_VAR_HLT 0x2800 +#define X86_ADDR_VAR_SYSRET 0x2808 +#define X86_ADDR_VAR_SYSEXIT 0x2810 +#define X86_ADDR_VAR_IDT 0x3800 +#define X86_ADDR_VAR_TSS64 0x3a00 +#define X86_ADDR_VAR_TSS64_CPL3 0x3c00 +#define X86_ADDR_VAR_TSS16 0x3d00 +#define X86_ADDR_VAR_TSS16_2 0x3e00 +#define X86_ADDR_VAR_TSS16_CPL3 0x3f00 +#define X86_ADDR_VAR_TSS32 0x4800 +#define X86_ADDR_VAR_TSS32_2 0x4a00 +#define X86_ADDR_VAR_TSS32_CPL3 0x4c00 +#define X86_ADDR_VAR_TSS32_VM86 0x4e00 +#define X86_ADDR_VAR_VMXON_PTR 0x5f00 +#define X86_ADDR_VAR_VMCS_PTR 0x5f08 +#define X86_ADDR_VAR_VMEXIT_PTR 0x5f10 +#define X86_ADDR_VAR_VMWRITE_FLD 0x5f18 +#define X86_ADDR_VAR_VMWRITE_VAL 0x5f20 +#define X86_ADDR_VAR_VMXON 0x6000 +#define X86_ADDR_VAR_VMCS 0x7000 +#define X86_ADDR_VAR_VMEXIT_CODE 0x9000 +#define X86_ADDR_VAR_USER_CODE 0x9100 +#define X86_ADDR_VAR_USER_CODE2 0x9120 -#define SEL_LDT (1 << 3) -#define SEL_CS16 (2 << 3) -#define SEL_DS16 (3 << 3) -#define SEL_CS16_CPL3 ((4 << 3) + 3) -#define SEL_DS16_CPL3 ((5 << 3) + 3) -#define SEL_CS32 (6 << 3) -#define SEL_DS32 (7 << 3) -#define SEL_CS32_CPL3 ((8 << 3) + 3) -#define SEL_DS32_CPL3 ((9 << 3) + 3) -#define SEL_CS64 (10 << 3) -#define SEL_DS64 (11 << 3) -#define SEL_CS64_CPL3 ((12 << 3) + 3) -#define SEL_DS64_CPL3 ((13 << 3) + 3) -#define SEL_CGATE16 (14 << 3) -#define SEL_TGATE16 (15 << 3) -#define SEL_CGATE32 (16 << 3) -#define SEL_TGATE32 (17 << 3) -#define SEL_CGATE64 (18 << 3) -#define SEL_CGATE64_HI (19 << 3) -#define SEL_TSS16 (20 << 3) -#define SEL_TSS16_2 (21 << 3) -#define SEL_TSS16_CPL3 ((22 << 3) + 3) -#define SEL_TSS32 (23 << 3) -#define SEL_TSS32_2 (24 << 3) -#define SEL_TSS32_CPL3 ((25 << 3) + 3) -#define SEL_TSS32_VM86 (26 << 3) -#define SEL_TSS64 (27 << 3) -#define SEL_TSS64_HI (28 << 3) -#define SEL_TSS64_CPL3 ((29 << 3) + 3) -#define SEL_TSS64_CPL3_HI (30 << 3) +#define X86_CR0_PE 1ULL +#define X86_CR0_MP (1ULL << 1) +#define X86_CR0_EM (1ULL << 2) +#define X86_CR0_TS (1ULL << 3) +#define X86_CR0_ET (1ULL << 4) +#define X86_CR0_NE (1ULL << 5) +#define X86_CR0_WP (1ULL << 16) +#define X86_CR0_AM (1ULL << 18) +#define X86_CR0_NW (1ULL << 29) +#define X86_CR0_CD (1ULL << 30) +#define X86_CR0_PG (1ULL << 31) -#define MSR_IA32_FEATURE_CONTROL 0x3a -#define MSR_IA32_VMX_BASIC 0x480 -#define MSR_IA32_SMBASE 0x9e -#define MSR_IA32_SYSENTER_CS 0x174 -#define MSR_IA32_SYSENTER_ESP 0x175 -#define MSR_IA32_SYSENTER_EIP 0x176 -#define MSR_IA32_STAR 0xC0000081 -#define MSR_IA32_LSTAR 0xC0000082 -#define MSR_IA32_VMX_PROCBASED_CTLS2 0x48B +#define X86_CR4_VME 1ULL +#define X86_CR4_PVI (1ULL << 1) +#define X86_CR4_TSD (1ULL << 2) +#define X86_CR4_DE (1ULL << 3) +#define X86_CR4_PSE (1ULL << 4) +#define X86_CR4_PAE (1ULL << 5) +#define X86_CR4_MCE (1ULL << 6) +#define X86_CR4_PGE (1ULL << 7) +#define X86_CR4_PCE (1ULL << 8) +#define X86_CR4_OSFXSR (1ULL << 8) +#define X86_CR4_OSXMMEXCPT (1ULL << 10) +#define X86_CR4_UMIP (1ULL << 11) +#define X86_CR4_VMXE (1ULL << 13) +#define X86_CR4_SMXE (1ULL << 14) +#define X86_CR4_FSGSBASE (1ULL << 16) +#define X86_CR4_PCIDE (1ULL << 17) +#define X86_CR4_OSXSAVE (1ULL << 18) +#define X86_CR4_SMEP (1ULL << 20) +#define X86_CR4_SMAP (1ULL << 21) +#define X86_CR4_PKE (1ULL << 22) -#define NEXT_INSN $0xbadc0de -#define PREFIX_SIZE 0xba1d +#define X86_EFER_SCE 1ULL +#define X86_EFER_LME (1ULL << 8) +#define X86_EFER_LMA (1ULL << 10) +#define X86_EFER_NXE (1ULL << 11) +#define X86_EFER_SVME (1ULL << 12) +#define X86_EFER_LMSLE (1ULL << 13) +#define X86_EFER_FFXSR (1ULL << 14) +#define X86_EFER_TCE (1ULL << 15) +// 32-bit page directory entry bits +#define X86_PDE32_PRESENT 1UL +#define X86_PDE32_RW (1UL << 1) +#define X86_PDE32_USER (1UL << 2) +#define X86_PDE32_PS (1UL << 7) + +// 64-bit page * entry bits +#define X86_PDE64_PRESENT 1 +#define X86_PDE64_RW (1ULL << 1) +#define X86_PDE64_USER (1ULL << 2) +#define X86_PDE64_ACCESSED (1ULL << 5) +#define X86_PDE64_DIRTY (1ULL << 6) +#define X86_PDE64_PS (1ULL << 7) +#define X86_PDE64_G (1ULL << 8) + +#define X86_SEL_LDT (1 << 3) +#define X86_SEL_CS16 (2 << 3) +#define X86_SEL_DS16 (3 << 3) +#define X86_SEL_CS16_CPL3 ((4 << 3) + 3) +#define X86_SEL_DS16_CPL3 ((5 << 3) + 3) +#define X86_SEL_CS32 (6 << 3) +#define X86_SEL_DS32 (7 << 3) +#define X86_SEL_CS32_CPL3 ((8 << 3) + 3) +#define X86_SEL_DS32_CPL3 ((9 << 3) + 3) +#define X86_SEL_CS64 (10 << 3) +#define X86_SEL_DS64 (11 << 3) +#define X86_SEL_CS64_CPL3 ((12 << 3) + 3) +#define X86_SEL_DS64_CPL3 ((13 << 3) + 3) +#define X86_SEL_CGATE16 (14 << 3) +#define X86_SEL_TGATE16 (15 << 3) +#define X86_SEL_CGATE32 (16 << 3) +#define X86_SEL_TGATE32 (17 << 3) +#define X86_SEL_CGATE64 (18 << 3) +#define X86_SEL_CGATE64_HI (19 << 3) +#define X86_SEL_TSS16 (20 << 3) +#define X86_SEL_TSS16_2 (21 << 3) +#define X86_SEL_TSS16_CPL3 ((22 << 3) + 3) +#define X86_SEL_TSS32 (23 << 3) +#define X86_SEL_TSS32_2 (24 << 3) +#define X86_SEL_TSS32_CPL3 ((25 << 3) + 3) +#define X86_SEL_TSS32_VM86 (26 << 3) +#define X86_SEL_TSS64 (27 << 3) +#define X86_SEL_TSS64_HI (28 << 3) +#define X86_SEL_TSS64_CPL3 ((29 << 3) + 3) +#define X86_SEL_TSS64_CPL3_HI (30 << 3) + +#define X86_MSR_IA32_FEATURE_CONTROL 0x3a +#define X86_MSR_IA32_VMX_BASIC 0x480 +#define X86_MSR_IA32_SMBASE 0x9e +#define X86_MSR_IA32_SYSENTER_CS 0x174 +#define X86_MSR_IA32_SYSENTER_ESP 0x175 +#define X86_MSR_IA32_SYSENTER_EIP 0x176 +#define X86_MSR_IA32_STAR 0xC0000081 +#define X86_MSR_IA32_LSTAR 0xC0000082 +#define X86_MSR_IA32_VMX_PROCBASED_CTLS2 0x48B + +#define X86_NEXT_INSN $0xbadc0de +#define X86_PREFIX_SIZE 0xba1d + +#define KVM_MAX_VCPU 4 +#define KVM_PAGE_SIZE (1 << 12) +#define KVM_GUEST_MEM_SIZE (1024 * KVM_PAGE_SIZE) #define SZ_4K 0x00001000 #define SZ_64K 0x00010000 diff --git a/executor/kvm_amd64.S b/executor/kvm_amd64.S index 884f8262b..a713a67d2 100644 --- a/executor/kvm_amd64.S +++ b/executor/kvm_amd64.S @@ -13,9 +13,9 @@ kvm_asm64_enable_long: mov %cr0, %eax or $0x80000000, %eax mov %eax, %cr0 - ljmp $SEL_CS64, NEXT_INSN + ljmp $X86_SEL_CS64, X86_NEXT_INSN .code64 - mov $SEL_TSS64, %rax + mov $X86_SEL_TSS64, %rax ltr %ax kvm_asm64_enable_long_end: nop @@ -32,9 +32,9 @@ kvm_asm32_paged_end: .global kvm_asm32_vm86, kvm_asm32_vm86_end kvm_asm32_vm86: .code32 - mov $SEL_TSS32, %ax + mov $X86_SEL_TSS32, %ax ltr %ax - ljmp $SEL_TSS32_VM86, $0 + ljmp $X86_SEL_TSS32_VM86, $0 kvm_asm32_vm86_end: nop @@ -44,9 +44,9 @@ kvm_asm32_paged_vm86: mov %cr0, %eax or $0x80000000, %eax mov %eax, %cr0 - mov $SEL_TSS32, %ax + mov $X86_SEL_TSS32, %ax ltr %ax - ljmp $SEL_TSS32_VM86, $0 + ljmp $X86_SEL_TSS32_VM86, $0 kvm_asm32_paged_vm86_end: nop @@ -56,18 +56,18 @@ kvm_asm16_cpl3: mov %cr0, %eax or $1, %eax mov %eax, %cr0 - mov $SEL_TSS16, %ax + mov $X86_SEL_TSS16, %ax ltr %ax - mov $SEL_DS16_CPL3, %ax + mov $X86_SEL_DS16_CPL3, %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs mov $0x100, %sp - movw $PREFIX_SIZE, 0x100 - movw $SEL_CS16_CPL3, 0x102 + movw $X86_PREFIX_SIZE, 0x100 + movw $X86_SEL_CS16_CPL3, 0x102 movw $0x100, 0x104 - movw $SEL_DS16_CPL3, 0x106 + movw $X86_SEL_DS16_CPL3, 0x106 lret kvm_asm16_cpl3_end: nop @@ -78,20 +78,20 @@ kvm_asm64_cpl3: mov %cr0, %eax or $0x80000000, %eax mov %eax, %cr0 - ljmp $SEL_CS64, NEXT_INSN + ljmp $X86_SEL_CS64, X86_NEXT_INSN .code64 - mov $SEL_TSS64, %rax + mov $X86_SEL_TSS64, %rax ltr %ax - mov $SEL_DS64_CPL3, %rax + mov $X86_SEL_DS64_CPL3, %rax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs - mov $ADDR_STACK0, %rsp - movq $PREFIX_SIZE, 0(%rsp) - movq $SEL_CS64_CPL3, 4(%rsp) - movq $ADDR_STACK0, 8(%rsp) - movq $SEL_DS64_CPL3, 12(%rsp) + mov $X86_ADDR_STACK0, %rsp + movq $X86_PREFIX_SIZE, 0(%rsp) + movq $X86_SEL_CS64_CPL3, 4(%rsp) + movq $X86_ADDR_STACK0, 8(%rsp) + movq $X86_SEL_DS64_CPL3, 12(%rsp) lretl kvm_asm64_cpl3_end: nop @@ -103,13 +103,13 @@ kvm_asm64_init_vm: mov %cr0, %eax or $0x80000000, %eax mov %eax, %cr0 - ljmp $SEL_CS64, NEXT_INSN + ljmp $X86_SEL_CS64, X86_NEXT_INSN .code64 - mov $SEL_TSS64, %rax + mov $X86_SEL_TSS64, %rax ltr %ax // Enable and lock non-SMM VM - mov $MSR_IA32_FEATURE_CONTROL, %rcx + mov $X86_MSR_IA32_FEATURE_CONTROL, %rcx rdmsr or $0x5, %rax wrmsr @@ -120,16 +120,16 @@ kvm_asm64_init_vm: mov %rax, %cr4 // Write VMCS revision into VMXON and VMCS regions - mov $MSR_IA32_VMX_BASIC, %rcx + mov $X86_MSR_IA32_VMX_BASIC, %rcx rdmsr - mov $ADDR_VAR_VMXON, %rdx + mov $X86_ADDR_VAR_VMXON, %rdx mov %eax, (%rdx) - mov $ADDR_VAR_VMCS, %rdx + mov $X86_ADDR_VAR_VMCS, %rdx mov %eax, (%rdx) - mov $ADDR_VAR_VMXON_PTR, %rax + mov $X86_ADDR_VAR_VMXON_PTR, %rax vmxon (%rax) - mov $ADDR_VAR_VMCS_PTR, %rax + mov $X86_ADDR_VAR_VMCS_PTR, %rax vmclear (%rax) vmptrld (%rax) @@ -158,9 +158,9 @@ kvm_asm64_init_vm: VMSET(0x00002C04, $0) // Host IA32_PERF_GLOBAL_CTR VMSET(0x00002800, $0xffffffffffffffff) // VMCS link pointer - VMSET(0x00000C02, $SEL_CS64) // host CS + VMSET(0x00000C02, $X86_SEL_CS64) // host CS - mov $SEL_DS64, %rax + mov $X86_SEL_DS64, %rax mov $0x00000C00, %rdx // host ES vmwrite %rax, %rdx mov $0x00000C04, %rdx // host SS @@ -171,13 +171,13 @@ kvm_asm64_init_vm: vmwrite %rax, %rdx mov $0x00000C0A, %rdx // host GS vmwrite %rax, %rdx - mov $SEL_TSS64, %rax + mov $X86_SEL_TSS64, %rax mov $0x00000C0C, %rdx // host TR vmwrite %rax, %rdx VMSET(0x00002C02, $0x500) // host EFER - VMSET(0x00004C00, $SEL_CS64) // Host IA32_SYSENTER_CS + VMSET(0x00004C00, $X86_SEL_CS64) // Host IA32_SYSENTER_CS VMSET(0x00006C10, $0) // Host IA32_SYSENTER_ESP VMSET(0x00006C12, $0) // Host IA32_SYSENTER_EIP @@ -190,13 +190,13 @@ kvm_asm64_init_vm: VMSET(0x00006C06, $0) // host FS base VMSET(0x00006C08, $0) // host GS base - VMSET(0x00006C0A, $ADDR_VAR_TSS64) // host TR base + VMSET(0x00006C0A, $X86_ADDR_VAR_TSS64) // host TR base - VMSET(0x00006C0C, $ADDR_GDT) // host GDTR base - VMSET(0x00006C0E, $ADDR_VAR_IDT) // host IDTR base + VMSET(0x00006C0C, $X86_ADDR_GDT) // host GDTR base + VMSET(0x00006C0E, $X86_ADDR_VAR_IDT) // host IDTR base VMSET(0x00006C14, $0) // host RSP - VMSET(0x00006C16, ADDR_VAR_VMEXIT_PTR) // host RIP + VMSET(0x00006C16, X86_ADDR_VAR_VMEXIT_PTR) // host RIP VMSET(0x00000000, $1) // VPID VMSET(0x00000002, $0) // Posted-interrupt notification vector @@ -228,19 +228,19 @@ kvm_asm64_init_vm: VMSET(0x00002020, $0) // EOI-exit bitmap 2 VMSET(0x00002022, $0) // EOI-exit bitmap 3 - VMSET(0x00000800, $SEL_DS64) // Guest ES selector - VMSET(0x00000802, $SEL_CS64) // Guest CS selector - VMSET(0x00000804, $SEL_DS64) // Guest SS selector - VMSET(0x00000806, $SEL_DS64) // Guest DS selector - VMSET(0x00000808, $SEL_DS64) // Guest FS selector - VMSET(0x0000080A, $SEL_DS64) // Guest GS selector + VMSET(0x00000800, $X86_SEL_DS64) // Guest ES selector + VMSET(0x00000802, $X86_SEL_CS64) // Guest CS selector + VMSET(0x00000804, $X86_SEL_DS64) // Guest SS selector + VMSET(0x00000806, $X86_SEL_DS64) // Guest DS selector + VMSET(0x00000808, $X86_SEL_DS64) // Guest FS selector + VMSET(0x0000080A, $X86_SEL_DS64) // Guest GS selector VMSET(0x0000080C, $0) // Guest LDTR selector - VMSET(0x0000080E, $SEL_TSS64) // Guest TR selector + VMSET(0x0000080E, $X86_SEL_TSS64) // Guest TR selector VMSET(0x00006812, $0) // Guest LDTR base - VMSET(0x00006814, $ADDR_VAR_TSS64) // Guest TR base - VMSET(0x00006816, $ADDR_GDT) // Guest GDTR base - VMSET(0x00006818, $ADDR_VAR_IDT) // Guest IDTR base + VMSET(0x00006814, $X86_ADDR_VAR_TSS64) // Guest TR base + VMSET(0x00006816, $X86_ADDR_GDT) // Guest GDTR base + VMSET(0x00006818, $X86_ADDR_VAR_IDT) // Guest IDTR base VMSET(0x00004800, $0xfffff) // Guest ES limit VMSET(0x00004802, $0xfffff) // Guest CS limit @@ -263,7 +263,7 @@ kvm_asm64_init_vm: VMSET(0x00004822, $0x8b) // Guest TR access rights VMSET(0x0000681C, $0) // Guest RSP - VMSET(0x0000681E, $ADDR_VAR_USER_CODE) // Guest RIP + VMSET(0x0000681E, $X86_ADDR_VAR_USER_CODE) // Guest RIP VMSET(0x00006820, $((1<<1))) // Guest RFLAGS VMSET(0x00002806, $0x500) // Guest IA32_EFER VMSET(0x0000280A, $0) // Guest PDPTE0 @@ -279,9 +279,9 @@ kvm_asm64_init_vm: VMSET(0x00006804, %rax) // Guest CR4 // Write 1 additional random field. - mov $ADDR_VAR_VMWRITE_FLD, %rax + mov $X86_ADDR_VAR_VMWRITE_FLD, %rax mov (%rax), %rdx - mov $ADDR_VAR_VMWRITE_VAL, %rax + mov $X86_ADDR_VAR_VMWRITE_VAL, %rax mov (%rax), %rcx xor %rax, %rax vmread %rdx, %rax -- cgit mrf-deployment