From: Jack Lange Date: Sat, 1 Mar 2008 23:06:54 +0000 (+0000) Subject: initial SVM guest running X-Git-Tag: working-cdboot-physical-but-not-qemu~63 X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=2e05f3b8f738466246add183c55bcb17abf33ec9 initial SVM guest running --- diff --git a/palacios/build/Makefile b/palacios/build/Makefile index 7587e29..7bf6dc7 100644 --- a/palacios/build/Makefile +++ b/palacios/build/Makefile @@ -1,6 +1,6 @@ # Makefile for GeekOS kernel, userspace, and tools # Copyright (c) 2004,2005 David H. Hovemeyer -# $Revision: 1.12 $ +# $Revision: 1.13 $ # This is free software. You are permitted to use, # redistribute, and modify it as specified in the file "COPYING". @@ -99,6 +99,7 @@ KERNEL_C_SRCS := idt.c int.c trap.c irq.c io.c \ serial.c reboot.c \ paging.c vmx.c vmcs_gen.c vmcs.c \ svm.c vmm.c vmm_util.c vmm_stubs.c \ + vmcb.c vmm_mem.c vm_guest.c \ debug.c\ main.c diff --git a/palacios/include/geekos/svm.h b/palacios/include/geekos/svm.h index bb967f3..32d79c6 100644 --- a/palacios/include/geekos/svm.h +++ b/palacios/include/geekos/svm.h @@ -3,6 +3,7 @@ #include #include +#include #define CPUID_FEATURE_IDS 0x80000001 #define CPUID_FEATURE_IDS_ecx_svm_avail 0x00000004 @@ -214,6 +215,10 @@ void Init_SVM(); int is_svm_capable(); +vmcb_t * Allocate_VMCB(); +void Init_VMCB(vmcb_t * vmcb, guest_info_t vm_info); +int init_svm_guest(struct guest_info *info); +int start_svm_guest(struct guest_info * info); #endif diff --git a/palacios/include/geekos/vm_guest.h b/palacios/include/geekos/vm_guest.h new file mode 100644 index 0000000..15b6cca --- /dev/null +++ b/palacios/include/geekos/vm_guest.h @@ -0,0 +1,26 @@ +#ifndef __VM_GUEST_H +#define __VM_GUEST_H + +#include +#include + + + + + +typedef struct guest_state { + reg_ex_t rip; + reg_ex_t rsp; + + + void * arch_data; +} guest_state_t; + + + + + + + + +#endif diff --git a/palacios/include/geekos/vmcb.h b/palacios/include/geekos/vmcb.h index e6d609f..b17c7d9 100644 --- a/palacios/include/geekos/vmcb.h +++ b/palacios/include/geekos/vmcb.h @@ -1,13 +1,14 @@ #ifndef __VMCB_H #define __VMCB_H +#include #define VMCB_CTRL_AREA_OFFSET 0x0 #define VMCB_STATE_SAVE_AREA_OFFSET 0x400 -#define GET_VMCB_CTRL_AREA(page) (page + VMCB_CONTROL_AREA_OFFSET) +#define GET_VMCB_CTRL_AREA(page) (page + VMCB_CTRL_AREA_OFFSET) #define GET_VMCB_SAVE_STATE_AREA(page) (page + VMCB_STATE_SAVE_AREA_OFFSET) @@ -17,6 +18,10 @@ #define PACKED __attribute__((packed)) #endif + +typedef void vmcb_t; + + union Ctrl_Registers { ushort_t bitmap PACKED; struct { @@ -189,7 +194,7 @@ typedef struct VMCB_Control_Area { union Instr_Intercepts instrs PACKED; union SVM_Instr_Intercepts svm_instrs PACKED; - uchar_t rsvd1[43] PACKED; // Should be 0 + uchar_t rsvd1[44] PACKED; // Should be 0 // offset 0x040 ullong_t IOPM_BASE_PA PACKED; @@ -223,7 +228,7 @@ typedef struct VMCB_Control_Area { uint_t NP_ENABLE : 1 PACKED; ullong_t rsvd6 : 63 PACKED; // Should be 0 - uchar_t rsvd7[15] PACKED; // Should be 0 + uchar_t rsvd7[16] PACKED; // Should be 0 // Offset 0xA8 ullong_t EVENTINJ PACKED; @@ -250,10 +255,27 @@ typedef struct VMCB_Control_Area { struct vmcb_selector { ushort_t selector PACKED; - ushort_t attrib PACKED; + + /* These attributes are basically a direct map of the attribute fields of a segment desc. + * The segment limit in the middle is removed and the fields are pused together + * There IS empty space at the end... See AMD Arch vol3, sect. 4.7.1, pg 78 + */ + union { + ushort_t raw PACKED; + struct { + uint_t type : 4 PACKED; // segment type, [see Intel vol. 3b, sect. 3.4.5.1 (because I have the books)] + uint_t S : 1 PACKED; // System=0, code/data=1 + uint_t dpl : 2 PACKED; // priviledge level, corresonds to protection ring + uint_t P : 1 PACKED; // present flag + uint_t avl : 1 PACKED; // available for use by system software + uint_t L : 1 PACKED; // long mode (64 bit?) + uint_t db : 1 PACKED; // default op size (0=16 bit seg, 1=32 bit seg) + uint_t G : 1 PACKED; // Granularity, (0=bytes, 1=4k) + } fields; + } attrib; uint_t limit PACKED; ullong_t base PACKED; -} +}; typedef struct VMCB_State_Save_Area { @@ -269,7 +291,7 @@ typedef struct VMCB_State_Save_Area { struct vmcb_selector idtr PACKED; // selector+attrib are reserved, only lower 16 bits of limit are implemented struct vmcb_selector tr PACKED; - uchar_t rsvd1[42] PACKED; + uchar_t rsvd1[43] PACKED; //offset 0x0cb uchar_t cpl PACKED; // if the guest is real-mode then the CPL is forced to 0 @@ -280,7 +302,7 @@ typedef struct VMCB_State_Save_Area { // offset 0x0d0 ullong_t efer PACKED; - uchar_t rsvd3[111] PACKED; + uchar_t rsvd3[112] PACKED; //offset 0x148 ullong_t cr4 PACKED; @@ -291,12 +313,12 @@ typedef struct VMCB_State_Save_Area { ullong_t rflags PACKED; ullong_t rip PACKED; - uchar_t rsvd4[87] PACKED; + uchar_t rsvd4[88] PACKED; //offset 0x1d8 ullong_t rsp PACKED; - uchar_t rsvd5[23] PACKED; + uchar_t rsvd5[24] PACKED; //offset 0x1f8 ullong_t rax PACKED; @@ -311,7 +333,7 @@ typedef struct VMCB_State_Save_Area { ullong_t cr2 PACKED; - uchar_t rsvd6[31] PACKED; + uchar_t rsvd6[32] PACKED; //offset 0x268 ullong_t g_pat PACKED; // Guest PAT @@ -330,4 +352,6 @@ typedef struct VMCB_State_Save_Area { } vmcb_saved_state_t; + + #endif diff --git a/palacios/include/geekos/vmm.h b/palacios/include/geekos/vmm.h index 89b56f1..c1c82d9 100644 --- a/palacios/include/geekos/vmm.h +++ b/palacios/include/geekos/vmm.h @@ -5,6 +5,7 @@ #include #include +#include /* utility definitions */ @@ -15,17 +16,17 @@ (os_hooks)->print_debug((fmt), ##args); \ } \ } while (0) \ - -#define PrintInfo(fmt, args...) \ - do { \ - extern struct vmm_os_hooks * os_hooks; \ - if ((os_hooks) && (os_hooks)->print_info) { \ - (os_hooks)->print_info((fmt), ##args); \ - } \ - } while (0) \ - + +#define PrintInfo(fmt, args...) \ + do { \ + extern struct vmm_os_hooks * os_hooks; \ + if ((os_hooks) && (os_hooks)->print_info) { \ + (os_hooks)->print_info((fmt), ##args); \ + } \ + } while (0) \ + #define PrintTrace(fmt, args...) \ do { \ @@ -34,10 +35,9 @@ (os_hooks)->print_trace((fmt), ##args); \ } \ } while (0) \ - -/* ** */ +/* ** */ #define VMM_INVALID_CPU 0 @@ -45,6 +45,22 @@ #define VMM_SVM_CPU 2 + +typedef struct guest_info { + ullong_t rip; + ullong_t rsp; + + vmm_mem_map_t mem_map; + // preallocation map + // device_map + + void * vmm_data; +} guest_info_t; + + + +/* We need a memory map and an IO device map */ + /* This will contain function pointers that provide OS services */ struct vmm_os_hooks { void (*print_info)(const char * format, ...); @@ -52,7 +68,13 @@ struct vmm_os_hooks { void (*print_trace)(const char * format, ...); void *(*Allocate_Pages)(int numPages); - void (*Free_Page)(void * page); + void (*Free_Page)(void * page); + + void *(*malloc)(uint_t size); + void (*free)(void * addr); + + + void (*start_kernel_thread)(); // include pointer to function }; @@ -60,13 +82,19 @@ struct vmm_os_hooks { /* This will contain Function pointers that control the VMs */ struct vmm_ctrl_ops { - - + int (*init_guest)(struct guest_info* info); + int (*start_guest)(struct guest_info * info); + // int (*stop_vm)(uint_t vm_id); }; -void Init_VMM(struct vmm_os_hooks * hooks); + + + + +void Init_VMM(struct vmm_os_hooks * hooks, struct vmm_ctrl_ops * vmm_ops); + diff --git a/palacios/include/geekos/vmm_mem.h b/palacios/include/geekos/vmm_mem.h new file mode 100644 index 0000000..dd6ec34 --- /dev/null +++ b/palacios/include/geekos/vmm_mem.h @@ -0,0 +1,34 @@ +#ifndef __VMM_MEM_H +#define __VMM_MEM_H + + +#include + + +typedef struct mem_region { + ullong_t addr; + uint_t numPages; + + struct mem_region * next; + struct mem_region * prev; +} mem_region_t; + + +typedef struct vmm_mem_map { + uint_t num_pages; + bool long_mode; + + uint_t num_regions; + mem_region_t * head; + mem_region_t * tail; +} vmm_mem_map_t; + + +void init_mem_map(vmm_mem_map_t * map); + +void add_pages(vmm_mem_map_t * map, ullong_t addr, uint_t numPages); +int remove_pages(vmm_mem_map_t * map, ullong_t addr, uint_t numPages); + + + +#endif diff --git a/palacios/include/geekos/vmm_types.h b/palacios/include/geekos/vmm_types.h new file mode 100644 index 0000000..2d0a6fe --- /dev/null +++ b/palacios/include/geekos/vmm_types.h @@ -0,0 +1,21 @@ +#ifndef __VMM_TYPES_H +#define __VMM_TYPES_H + + + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +typedef unsigned long size_t; + + +#endif diff --git a/palacios/src/geekos/TODO b/palacios/src/geekos/TODO new file mode 100644 index 0000000..eb57c3c --- /dev/null +++ b/palacios/src/geekos/TODO @@ -0,0 +1,15 @@ +Get Relocation working + code audit to ensure no compile time addresses are generated (globals) + figure out how to get the .asm files to work + thoughts: add a GOT table somewhere, + setup a special 'ASM' gdt entry for code/data + +64 bit porting work... + change register ops to work with 64 bit values + e.g. Get/Set_MSR + get a 64/32 bit register abstraction that is GOOD + see reg_ex_t in vmm_util.h + +Support allocating multiple contiguous pages in geekos + either rewrite allocator or just step through until you find one + diff --git a/palacios/src/geekos/debug.c b/palacios/src/geekos/debug.c index 0c64a15..986fc5f 100644 --- a/palacios/src/geekos/debug.c +++ b/palacios/src/geekos/debug.c @@ -6,6 +6,6 @@ void PrintBoth(const char * format, ...) { va_start(args, format); PrintList(format, args); - //SerialPrintList(format, args); + SerialPrintList(format, args); va_end(args); } diff --git a/palacios/src/geekos/lowlevel.asm b/palacios/src/geekos/lowlevel.asm index f90212c..c530a5c 100644 --- a/palacios/src/geekos/lowlevel.asm +++ b/palacios/src/geekos/lowlevel.asm @@ -2,7 +2,7 @@ ; Low level interrupt/thread handling code for GeekOS. ; Copyright (c) 2001,2003,2004 David H. Hovemeyer ; Copyright (c) 2003, Jeffrey K. Hollingsworth -; $Revision: 1.2 $ +; $Revision: 1.3 $ ; This is free software. You are permitted to use, ; redistribute, and modify it as specified in the file "COPYING". @@ -279,9 +279,15 @@ cpuid_edx: push ebp mov ebp, esp push edx + push ecx + push ebx + mov eax, [ebp + 8] cpuid mov eax, edx + + pop ebx + pop ecx pop edx pop ebp ret @@ -294,11 +300,17 @@ align 8 cpuid_ecx: push ebp mov ebp, esp + push edx push ecx + push ebx + mov eax, [ebp + 8] cpuid mov eax, ecx + + pop ebx pop ecx + pop edx pop ebp ret @@ -307,8 +319,19 @@ cpuid_ecx: ; align 8 cpuid_eax: + push ebp + mov ebp, esp + push edx + push ecx + push ebx + mov eax, [esp+4] cpuid + + pop ebx + pop ecx + pop edx + pop ebp ret ; diff --git a/palacios/src/geekos/main.c b/palacios/src/geekos/main.c index e09ef5c..4da5461 100644 --- a/palacios/src/geekos/main.c +++ b/palacios/src/geekos/main.c @@ -3,7 +3,7 @@ * Copyright (c) 2001,2003,2004 David H. Hovemeyer * Copyright (c) 2003, Jeffrey K. Hollingsworth * Copyright (c) 2004, Iulian Neamtiu - * $Revision: 1.12 $ + * $Revision: 1.13 $ * * This is free software. You are permitted to use, * redistribute, and modify it as specified in the file "COPYING". @@ -120,7 +120,9 @@ void BuzzVM() int j; unsigned char init; - + + SerialPrint("Starting To Buzz\n"); + init=MyIn_Byte(SPEAKER_PORT); while (1) { @@ -315,24 +317,42 @@ void Main(struct Boot_Info* bootInfo) */ #endif -#if 1 +#if 0 SerialPrint("Dumping GUEST KERNEL CODE (first 512*2 bytes @ 0x100000)\n"); SerialMemDump((unsigned char *)0x100000, 512*2); #endif - + { struct vmm_os_hooks os_hooks; + struct vmm_ctrl_ops vmm_ops; + guest_info_t vm_info; + memset(&os_hooks, 0, sizeof(struct vmm_os_hooks)); + memset(&vmm_ops, 0, sizeof(struct vmm_ctrl_ops)); + memset(&vm_info, 0, sizeof(guest_info_t)); + os_hooks.print_debug = &PrintBoth; os_hooks.print_info = &Print; os_hooks.print_trace = &SerialPrint; os_hooks.Allocate_Pages = &Allocate_VMM_Pages; os_hooks.Free_Page = &Free_VMM_Page; - Init_VMM(&os_hooks); + Init_VMM(&os_hooks, &vmm_ops); + + + + vm_info.rip = (ullong_t)(void*)&BuzzVM; + vm_info.rsp = (ulong_t)Alloc_Page(); + + SerialPrint("Initializing Guest\n"); + (vmm_ops).init_guest(&vm_info); + SerialPrint("Starting Guest\n"); + (vmm_ops).start_guest(&vm_info); + + } + - SerialPrintLevel(1000,"Launching Noisemaker and keyboard listener threads\n"); key_thread = Start_Kernel_Thread(Keyboard_Listener, (ulong_t)&doIBuzz, PRIORITY_NORMAL, false); diff --git a/palacios/src/geekos/svm.c b/palacios/src/geekos/svm.c index 88ab002..5e8eb77 100644 --- a/palacios/src/geekos/svm.c +++ b/palacios/src/geekos/svm.c @@ -1,5 +1,7 @@ #include +#include +#include extern struct vmm_os_hooks * os_hooks; @@ -7,6 +9,8 @@ extern uint_t cpuid_ecx(uint_t op); extern uint_t cpuid_edx(uint_t op); extern void Get_MSR(uint_t MSR, uint_t * high_byte, uint_t * low_byte); extern void Set_MSR(uint_t MSR, uint_t high_byte, uint_t low_byte); +extern uint_t launch_svm(vmcb_t * vmcb_addr); + /* Checks machine SVM capability */ /* Implemented from: AMD Arch Manual 3, sect 15.4 */ @@ -15,6 +19,7 @@ int is_svm_capable() { uint_t vm_cr_low = 0, vm_cr_high = 0; + return 1; if ((ret & CPUID_FEATURE_IDS_ecx_svm_avail) == 0) { PrintDebug("SVM Not Available\n"); return 0; @@ -58,6 +63,8 @@ void Init_SVM() { msr.e_reg.high = 0; msr.e_reg.low = (uint_t)host_state; + + PrintDebug("Host State being saved at %x\n", (uint_t)host_state); Set_MSR(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low); @@ -65,11 +72,97 @@ void Init_SVM() { } +int init_svm_guest(struct guest_info *info) { + PrintDebug("Allocating VMCB\n"); + info->vmm_data = (void*)Allocate_VMCB(); + + PrintDebug("Initializing VMCB (addr=%x)\n", info->vmm_data); + Init_VMCB((vmcb_t*)(info->vmm_data), *info); + + return 0; +} + + +// can we start a kernel thread here... +int start_svm_guest(struct guest_info *info) { + vmcb_ctrl_t * guest_ctrl = 0; + + ulong_t exit_code = 0; + + PrintDebug("Launching SVM VM (vmcb=%x)\n", info->vmm_data); + + launch_svm((vmcb_t*)(info->vmm_data)); + + guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data)); + + + PrintDebug("SVM Returned: (Exit Code=%x) (VMCB=%x)\n",&(guest_ctrl->exit_code), info->vmm_data); + + + exit_code = guest_ctrl->exit_code; + + PrintDebug("SVM Returned: Exit Code: %x\n",exit_code); + + return 0; +} -void Allocate_VMCB() { - void * vmcb_page = os_hooks->Allocate_Pages(1); + +vmcb_t * Allocate_VMCB() { + vmcb_t * vmcb_page = (vmcb_t*)os_hooks->Allocate_Pages(1); memset(vmcb_page, 0, 4096); + + return vmcb_page; +} + + + +void Init_VMCB(vmcb_t *vmcb, guest_info_t vm_info) { + vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb); + vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(vmcb); + uint_t i = 0; + + + guest_state->rsp = vm_info.rsp; + guest_state->rip = vm_info.rip; + + + /* I pretty much just gutted this from TVMM */ + /* Note: That means its probably wrong */ + + // set the segment registers to mirror ours + guest_state->cs.selector = 0; + guest_state->cs.attrib.fields.type = 0xa; // Code segment+read + guest_state->cs.attrib.fields.S = 1; + guest_state->cs.attrib.fields.P = 1; + guest_state->cs.attrib.fields.db = 1; + guest_state->cs.limit = 0xffffffff; + guest_state->cs.base = 0; + + struct vmcb_selector *segregs [] = {&(guest_state->ss), &(guest_state->ds), &(guest_state->es), &(guest_state->fs), &(guest_state->gs), NULL}; + for ( i = 0; segregs[i] != NULL; i++) { + struct vmcb_selector * seg = segregs[i]; + + seg->selector = 0; + seg->attrib.fields.type = 0x2; // Data Segment+read/write + seg->attrib.fields.S = 1; + seg->attrib.fields.P = 1; + seg->attrib.fields.db = 1; + seg->limit = 0xffffffff; + seg->base = 0; + } + + + guest_state->efer |= EFER_MSR_svm_enable; + guest_state->cr0 = 0x00000001; // PE + guest_state->rflags = 0x00000002; // The reserved bit is always 1 + ctrl_area->svm_instrs.instrs.VMRUN = 1; + ctrl_area->guest_ASID = 1; + + + + /* ** */ + } diff --git a/palacios/src/geekos/svm_lowlevel.asm b/palacios/src/geekos/svm_lowlevel.asm index badc8f1..40bb8ea 100644 --- a/palacios/src/geekos/svm_lowlevel.asm +++ b/palacios/src/geekos/svm_lowlevel.asm @@ -8,12 +8,35 @@ %include "symbol.asm" + +EXPORT launch_svm + + [BITS 32] +%macro vmrun 0 + db 00fh, 001h, 0d8h +%endmacro +;VMRUN equ db 0Fh, 01h, D8h +;VMLOAD equ db 0x0F,0x01,0xDA +;VMSAVE equ db 0x0F,0x01,0xDB +;STGI equ db 0x0F,0x01,0xDC +;CLGI equ db 0x0F,0x01,0xDD +launch_svm: + push ebp + mov ebp, esp + pusha + + mov eax, [ebp + 8] +; vmrun + db 00fh, 001h, 0d8h + popa + pop ebp + ret %endif diff --git a/palacios/src/geekos/vm_guest.c b/palacios/src/geekos/vm_guest.c new file mode 100644 index 0000000..1900834 --- /dev/null +++ b/palacios/src/geekos/vm_guest.c @@ -0,0 +1 @@ +#include diff --git a/palacios/src/geekos/vmcb.c b/palacios/src/geekos/vmcb.c new file mode 100644 index 0000000..66a7c9c --- /dev/null +++ b/palacios/src/geekos/vmcb.c @@ -0,0 +1,4 @@ +#include + + + diff --git a/palacios/src/geekos/vmm.c b/palacios/src/geekos/vmm.c index a162af9..e081816 100644 --- a/palacios/src/geekos/vmm.c +++ b/palacios/src/geekos/vmm.c @@ -11,7 +11,10 @@ uint_t vmm_cpu_type; struct vmm_os_hooks * os_hooks = NULL; -void Init_VMM(struct vmm_os_hooks * hooks) { + + + +void Init_VMM(struct vmm_os_hooks * hooks, struct vmm_ctrl_ops * vmm_ops) { vmm_cpu_type = VMM_INVALID_CPU; os_hooks = hooks; @@ -21,7 +24,12 @@ void Init_VMM(struct vmm_os_hooks * hooks) { if (is_svm_capable()) { vmm_cpu_type = VMM_SVM_CPU; PrintDebug("Machine is SVM Capable\n"); + Init_SVM(); + + vmm_ops->init_guest = &init_svm_guest; + vmm_ops->start_guest = &start_svm_guest; + } else if (is_vmx_capable()) { vmm_cpu_type = VMM_VMX_CPU; PrintDebug("Machine is VMX Capable\n"); @@ -30,3 +38,6 @@ void Init_VMM(struct vmm_os_hooks * hooks) { PrintDebug("CPU has no virtualization Extensions\n"); } } + + + diff --git a/palacios/src/geekos/vmm_mem.c b/palacios/src/geekos/vmm_mem.c new file mode 100644 index 0000000..128df3d --- /dev/null +++ b/palacios/src/geekos/vmm_mem.c @@ -0,0 +1,5 @@ +#include + + + +