From: Jack Lange Date: Wed, 23 Sep 2009 22:27:50 +0000 (-0500) Subject: added symbiotic interface and a number of other small changes X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=ed8feff1d5dd6bf028cd5ba0960ec125505d7597 added symbiotic interface and a number of other small changes --- diff --git a/palacios/include/palacios/vm_guest.h b/palacios/include/palacios/vm_guest.h index 86a1cc4..d8444a6 100644 --- a/palacios/include/palacios/vm_guest.h +++ b/palacios/include/palacios/vm_guest.h @@ -34,7 +34,7 @@ #include #include #include -#include + #ifdef CONFIG_TELEMETRY #include @@ -45,6 +45,9 @@ #endif + + + struct v3_gprs { v3_reg_t rdi; v3_reg_t rsi; @@ -116,6 +119,11 @@ struct v3_segments { struct v3_segment tr; }; + +#ifdef CONFIG_SYMBIOTIC +#include +#endif + struct shadow_page_state; struct v3_intr_state; @@ -127,6 +135,9 @@ struct v3_telemetry; struct v3_sym_swap_state; #endif +#ifdef CONFIG_SYMBIOTIC +struct v3_sym_state; +#endif struct guest_info { uint64_t rip; @@ -157,9 +168,10 @@ struct guest_info { struct v3_cpuid_map cpuid_map; +#ifdef CONFIG_SYMBIOTIC // Symbiotic state struct v3_sym_state sym_state; - +#endif v3_hypercall_map_t hcall_map; @@ -211,6 +223,8 @@ v3_mem_mode_t v3_get_vm_mem_mode(struct guest_info * info); const uchar_t * v3_cpu_mode_to_str(v3_cpu_mode_t mode); const uchar_t * v3_mem_mode_to_str(v3_mem_mode_t mode); +int v3_translate_segment(struct guest_info * info, uint16_t selector, struct v3_segment * seg); + void v3_print_guest_state(struct guest_info * info); diff --git a/palacios/include/palacios/vmm_lowlevel.h b/palacios/include/palacios/vmm_lowlevel.h index f3c8db5..331a307 100644 --- a/palacios/include/palacios/vmm_lowlevel.h +++ b/palacios/include/palacios/vmm_lowlevel.h @@ -23,6 +23,47 @@ #define CPUID_FEATURE_IDS 0x00000001 #define CPUID_EXT_FEATURE_IDS 0x80000001 +struct seg_selector { + union { + uint16_t value; + struct { + uint8_t rpl : 2; + uint8_t ti : 1; + uint16_t si : 13; + } __attribute__((packed)); + } __attribute__((packed)); +} __attribute__((packed)); + +struct gen_segment { + uint16_t limit_lo; + uint32_t base_lo : 24; + uint8_t type : 4; + uint8_t system : 1; + uint8_t dpl : 2; + uint8_t present : 1; + uint8_t limit_hi : 4; + uint8_t avail : 1; + uint8_t long_mode : 1; + uint8_t db : 1; + uint8_t granularity : 1; + uint8_t base_hi : 8; +} __attribute__((packed)); + +struct sys_segment64 { + uint16_t limit_lo; + uint32_t base_lo : 24; + uint8_t type : 4; + uint8_t rsvd0 : 1; + uint8_t dpl : 2; + uint8_t present : 1; + uint8_t limit_hi : 4; + uint8_t avail : 1; + uint8_t rsvd1 : 3; + uint8_t granularity : 1; + uint64_t base_hi : 40; + uint32_t rsvd2; +} __attribute__((packed)); + static void __inline__ v3_cpuid(uint32_t target, diff --git a/palacios/include/palacios/vmm_sym_iface.h b/palacios/include/palacios/vmm_sym_iface.h index 5fcb69a..94b47ec 100644 --- a/palacios/include/palacios/vmm_sym_iface.h +++ b/palacios/include/palacios/vmm_sym_iface.h @@ -23,7 +23,7 @@ #ifdef __V3VEE__ - +#include @@ -34,35 +34,100 @@ struct v3_sym_interface { union { uint32_t feature_flags; struct { - uint_t cur_proc_valid : 1; - uint_t proc_list_valid : 1; + uint_t pci_map_valid : 1; + uint32_t sym_call_enabled : 1; + } __attribute__((packed)); + } __attribute__((packed)); + + union { + uint32_t state_flags; + struct { + uint32_t sym_call_active : 1; } __attribute__((packed)); } __attribute__((packed)); - addr_t current_proc; - addr_t proc_list; + uint64_t current_proc; + uint64_t proc_list; + + uint8_t pci_pt_map[(4 * 256) / 8]; // we're hardcoding this: (4 busses, 256 max devs) + + + uint64_t sym_call_rip; + uint64_t sym_call_cs; + uint64_t sym_call_rsp; + uint64_t sym_call_gs; + uint64_t sym_call_ret_fn; - uint8_t pci_pt_map[256 / 8]; } __attribute__((packed)); + + +struct v3_sym_context { + struct v3_gprs vm_regs; + struct v3_segment cs; + struct v3_segment ss; + uint64_t gs_base; + uint64_t fs_base; + uint64_t rip; + uint8_t cpl; +}; + + + struct v3_sym_state { struct v3_sym_interface * sym_page; addr_t sym_page_pa; - uint_t active; uint64_t guest_pg_addr; + struct { + uint_t active : 1; + uint_t call_pending : 1; + uint_t call_active : 1; + } __attribute__((packed)); + + struct v3_sym_context old_ctx; + uint64_t args[6]; + int (*notifier)(struct guest_info * info, void * private_data); + + void * private_data; + }; int v3_init_sym_iface(struct guest_info * info); + +#define v3_sym_call0(info, call_num, cb, priv) \ + v3_sym_call(info, call_num, 0, 0, 0, 0, 0, cb, priv) +#define v3_sym_call1(info, call_num, arg1, cb, priv) \ + v3_sym_call(info, call_num, arg1, 0, 0, 0, 0, cb, priv) +#define v3_sym_call2(info, call_num, arg1, arg2, cb, priv) \ + v3_sym_call(info, call_num, arg1, arg2, 0, 0, 0, cb, priv) +#define v3_sym_call3(info, call_num, arg1, arg2, arg3, cb, priv) \ + v3_sym_call(info, call_num, arg1, arg2, arg3, 0, 0, cb, priv) +#define v3_sym_call4(info, call_num, arg1, arg2, arg3, arg4, cb, priv) \ + v3_sym_call(info, call_num, arg1, arg2, arg3, arg4, 0, cb, priv) +#define v3_sym_call5(info, call_num, arg1, arg2, arg3, arg4, arg5, cb, priv) \ + v3_sym_call(info, call_num, arg1, arg2, arg3, arg4, arg5, cb, priv) + + + + int v3_sym_map_pci_passthrough(struct guest_info * info, uint_t bus, uint_t dev, uint_t fn); int v3_sym_unmap_pci_passthrough(struct guest_info * info, uint_t bus, uint_t dev, uint_t fn); +int v3_sym_call(struct guest_info * info, + uint64_t arg0, uint64_t arg1, + uint64_t arg2, uint64_t arg3, + uint64_t arg4, uint64_t arg5, + int (*notifier)(struct guest_info * info, void * private_data), + void * private_data); + +int v3_activate_sym_call(struct guest_info * info); #endif diff --git a/palacios/src/devices/keyboard.c b/palacios/src/devices/keyboard.c index e9fff1f..c50374a 100644 --- a/palacios/src/devices/keyboard.c +++ b/palacios/src/devices/keyboard.c @@ -327,6 +327,9 @@ static int key_event_handler(struct guest_info * info, if (evt->scan_code == 0x44) { // F10 debug dump v3_print_guest_state(info); // PrintGuestPageTables(info, info->shdw_pg_state.guest_cr3); + } else if (evt->scan_code == 0x43) { // F9 Sym test + PrintDebug("Testing sym call\n"); + v3_sym_call0(info, 0, NULL, NULL); } addr_t irq_state = v3_lock_irqsave(state->kb_lock); diff --git a/palacios/src/devices/piix3.c b/palacios/src/devices/piix3.c index 9a69ed0..44a00ed 100644 --- a/palacios/src/devices/piix3.c +++ b/palacios/src/devices/piix3.c @@ -367,7 +367,7 @@ static int raise_pci_irq(struct vm_device * dev, struct pci_device * pci_dev) { int intr_pin = pci_dev->config_header.intr_pin - 1; int irq_index = (intr_pin + pci_dev->dev_num - 1) & 0x3; - PrintError("Raising PCI IRQ %d\n", piix3_cfg->pirq_rc[irq_index]); + // PrintError("Raising PCI IRQ %d\n", piix3_cfg->pirq_rc[irq_index]); v3_raise_irq(dev->vm, piix3_cfg->pirq_rc[irq_index]); diff --git a/palacios/src/palacios/svm_handler.c b/palacios/src/palacios/svm_handler.c index 4c4aa2c..1c64657 100644 --- a/palacios/src/palacios/svm_handler.c +++ b/palacios/src/palacios/svm_handler.c @@ -34,6 +34,10 @@ #include #include +#ifdef CONFIG_SYMBIOTIC +#include +#endif + #ifdef CONFIG_TELEMETRY #include #endif @@ -43,7 +47,12 @@ int v3_handle_svm_exit(struct guest_info * info) { vmcb_ctrl_t * guest_ctrl = 0; vmcb_saved_state_t * guest_state = 0; ulong_t exit_code = 0; - + +#ifdef CONFIG_SYMBIOTIC + static int sym_started = 0; +#endif + + guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data)); guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); @@ -70,8 +79,21 @@ int v3_handle_svm_exit(struct guest_info * info) { exit_code = guest_ctrl->exit_code; - // PrintDebug("SVM Exit: %s (rip=%p) (info1=%p)\n", vmexit_code_to_str(exit_code), - // (void *)(addr_t)info->rip, (void *)(addr_t)guest_ctrl->exit_info1); + + +#ifdef CONFIG_SYMBIOTIC + if (0) { + // ignore interrupt injection if we just started a symcall + PrintDebug("SVM Exit: %s (rip=%p) (info1=%p) (info2=%p)\n", vmexit_code_to_str(exit_code), + (void *)(addr_t)info->rip, (void *)(addr_t)guest_ctrl->exit_info1, + (void *)(addr_t)guest_ctrl->exit_info2); + if (exit_code == VMEXIT_EXCP14) { + PrintGuestPageTree(info, guest_ctrl->exit_info2, info->shdw_pg_state.guest_cr3); + } + + } +#endif + if ((info->intr_state.irq_pending == 1) && (guest_ctrl->guest_ctrl.V_IRQ == 0)) { @@ -186,6 +208,7 @@ int v3_handle_svm_exit(struct guest_info * info) { if (v3_handle_cr3_write(info) == -1) { return -1; } + break; case VMEXIT_CR3_READ: #ifdef CONFIG_DEBUG_CTRL_REGS @@ -256,13 +279,15 @@ int v3_handle_svm_exit(struct guest_info * info) { /* * Hypercall */ - + + // VMMCALL is a 3 byte op + // We do this early because some hypercalls can change the rip... + info->rip += 3; + if (v3_handle_hypercall(info) == -1) { return -1; } - - // VMMCALL is a 3 byte op - info->rip += 3; + break; case VMEXIT_INTR: // handled by interrupt dispatch earlier @@ -279,7 +304,7 @@ int v3_handle_svm_exit(struct guest_info * info) { } break; case VMEXIT_PAUSE: - //PrintDebug("Guest paused\n"); + PrintDebug("Guest paused\n"); if (v3_handle_svm_pause(info) == -1) { return -1; } @@ -339,6 +364,32 @@ int v3_handle_svm_exit(struct guest_info * info) { #endif + +#ifdef CONFIG_SYMBIOTIC + v3_activate_sym_call(info); +#endif + + guest_state->cr0 = info->ctrl_regs.cr0; + guest_state->cr2 = info->ctrl_regs.cr2; + guest_state->cr3 = info->ctrl_regs.cr3; + guest_state->cr4 = info->ctrl_regs.cr4; + guest_state->dr6 = info->dbg_regs.dr6; + guest_state->dr7 = info->dbg_regs.dr7; + guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff; + guest_state->rflags = info->ctrl_regs.rflags; + guest_state->efer = info->ctrl_regs.efer; + + guest_state->cpl = info->cpl; + + v3_set_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments)); + + guest_state->rax = info->vm_regs.rax; + guest_state->rip = info->rip; + guest_state->rsp = info->vm_regs.rsp; + + + + if (v3_excp_pending(info)) { uint_t excp = v3_get_excp_number(info); @@ -355,12 +406,27 @@ int v3_handle_svm_exit(struct guest_info * info) { guest_ctrl->EVENTINJ.vector = excp; guest_ctrl->EVENTINJ.valid = 1; + + PrintDebug("Injecting Exception %d (EIP=%p)\n", + guest_ctrl->EVENTINJ.vector, + (void *)(addr_t)info->rip); + + + #ifdef CONFIG_DEBUG_INTERRUPTS PrintDebug("Injecting Exception %d (EIP=%p)\n", guest_ctrl->EVENTINJ.vector, (void *)(addr_t)info->rip); #endif v3_injecting_excp(info, excp); + +#ifdef CONFIG_SYMBIOTIC + } else if (info->sym_state.call_active == 1) { + // ignore interrupt injection if we just started a symcall + PrintDebug("Symcall active\n"); + sym_started = 1; +#endif + } else if (info->intr_state.irq_started == 1) { #ifdef CONFIG_DEBUG_INTERRUPTS PrintDebug("IRQ pending from previous injection\n"); @@ -409,24 +475,6 @@ int v3_handle_svm_exit(struct guest_info * info) { } - guest_state->cr0 = info->ctrl_regs.cr0; - guest_state->cr2 = info->ctrl_regs.cr2; - guest_state->cr3 = info->ctrl_regs.cr3; - guest_state->cr4 = info->ctrl_regs.cr4; - guest_state->dr6 = info->dbg_regs.dr6; - guest_state->dr7 = info->dbg_regs.dr7; - guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff; - guest_state->rflags = info->ctrl_regs.rflags; - guest_state->efer = info->ctrl_regs.efer; - - guest_state->cpl = info->cpl; - - guest_state->rax = info->vm_regs.rax; - guest_state->rip = info->rip; - guest_state->rsp = info->vm_regs.rsp; - - - v3_set_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments)); if (exit_code == VMEXIT_INTR) { //PrintDebug("INTR ret IP = %x\n", guest_state->rip); diff --git a/palacios/src/palacios/svm_msr.c b/palacios/src/palacios/svm_msr.c index 22807a1..82614f1 100644 --- a/palacios/src/palacios/svm_msr.c +++ b/palacios/src/palacios/svm_msr.c @@ -19,7 +19,7 @@ #include #include - +#include #include @@ -30,9 +30,9 @@ #define AMD_7_8_GEN_MSRS_START 0xc0010000 #define AMD_7_8_GEN_MSRS_END 0xc0011fff -#define PENTIUM_MSRS_INDEX (0x0 * 4) -#define AMD_6_GEN_MSRS_INDEX (0x800 * 4) -#define AMD_7_8_GEN_MSRS_INDEX (0x1000 * 4) +#define PENTIUM_MSRS_INDEX (0) +#define AMD_6_GEN_MSRS_INDEX (0x2000) +#define AMD_7_8_GEN_MSRS_INDEX (0x4000) @@ -71,7 +71,7 @@ static int update_map(struct guest_info * info, uint_t msr, int hook_reads, int *(bitmap + major) &= ~(mask << minor); *(bitmap + major) |= (val << minor); - + return 0; } diff --git a/palacios/src/palacios/vm_guest.c b/palacios/src/palacios/vm_guest.c index 8a2e4d4..94bbc7b 100644 --- a/palacios/src/palacios/vm_guest.c +++ b/palacios/src/palacios/vm_guest.c @@ -25,6 +25,10 @@ #include #include #include +#include +#include +#include + v3_cpu_mode_t v3_get_vm_cpu_mode(struct guest_info * info) { @@ -173,10 +177,67 @@ void v3_print_segments(struct guest_info * info) { seg_ptr[i].long_mode, seg_ptr[i].db); } +} + +// +// We don't handle those fancy 64 bit system segments... +// +int v3_translate_segment(struct guest_info * info, uint16_t selector, struct v3_segment * seg) { + struct v3_segment * gdt = &(info->segments.gdtr); + addr_t gdt_addr = 0; + uint16_t seg_offset = (selector & ~0x7); + addr_t seg_addr = 0; + struct gen_segment * gen_seg = NULL; + struct seg_selector sel; + + memset(seg, 0, sizeof(struct v3_segment)); + + sel.value = selector; + + if (sel.ti == 1) { + PrintError("LDT translations not supported\n"); + return -1; + } + if (guest_va_to_host_va(info, gdt->base, &gdt_addr) == -1) { + PrintError("Unable to translate GDT address\n"); + return -1; + } + + seg_addr = gdt_addr + seg_offset; + gen_seg = (struct gen_segment *)seg_addr; + + //translate + seg->selector = selector; + + seg->limit = gen_seg->limit_hi; + seg->limit <<= 16; + seg->limit += gen_seg->limit_lo; + + seg->base = gen_seg->base_hi; + seg->base <<= 24; + seg->base += gen_seg->base_lo; + + if (gen_seg->granularity == 1) { + seg->limit <<= 12; + seg->limit |= 0xfff; + } + + seg->type = gen_seg->type; + seg->system = gen_seg->system; + seg->dpl = gen_seg->dpl; + seg->present = gen_seg->present; + seg->avail = gen_seg->avail; + seg->long_mode = gen_seg->long_mode; + seg->db = gen_seg->db; + seg->granularity = gen_seg->granularity; + + return 0; } + + void v3_print_ctrl_regs(struct guest_info * info) { struct v3_ctrl_regs * regs = &(info->ctrl_regs); int i = 0; diff --git a/palacios/src/palacios/vmm_config.c b/palacios/src/palacios/vmm_config.c index 72887c6..44dbd50 100644 --- a/palacios/src/palacios/vmm_config.c +++ b/palacios/src/palacios/vmm_config.c @@ -258,7 +258,8 @@ static int setup_devices(struct guest_info * info, struct v3_vm_config * config_ if (config_ptr->enable_pci == 1) { struct ide_cfg ide_config = {"PCI", "PIIX3"}; - struct pci_passthrough_cfg pci_pt_cfg = {"PCI", "E1000", 0x8086, 0x100e}; + struct pci_passthrough_cfg pci_qemu_pt_cfg = {"PCI", "E1000", 0x8086, 0x100e}; + struct pci_passthrough_cfg pci_hw_pt_cfg = {"PCI", "E1000", 0x8086, 0x107c}; v3_create_device(info, "PCI", NULL); v3_create_device(info, "i440FX", "PCI"); @@ -272,7 +273,9 @@ static int setup_devices(struct guest_info * info, struct v3_vm_config * config_ v3_create_device(info, "IDE", &ide_config); - v3_create_device(info, "PCI_PASSTHROUGH", &pci_pt_cfg); + v3_create_device(info, "PCI_PASSTHROUGH", &pci_qemu_pt_cfg); + v3_create_device(info, "PCI_PASSTHROUGH", &pci_hw_pt_cfg); + } else { v3_create_device(info, "IDE", NULL); diff --git a/palacios/src/palacios/vmm_cpuid.c b/palacios/src/palacios/vmm_cpuid.c index 6dc29eb..d0c3a32 100644 --- a/palacios/src/palacios/vmm_cpuid.c +++ b/palacios/src/palacios/vmm_cpuid.c @@ -131,7 +131,10 @@ int v3_handle_cpuid(struct guest_info * info) { uint32_t cpuid = info->vm_regs.rax; struct v3_cpuid_hook * hook = get_cpuid_hook(info, cpuid); + //PrintDebug("CPUID called for 0x%x\n", cpuid); + if (hook == NULL) { + //PrintDebug("Calling passthrough handler\n"); // call the passthrough handler v3_cpuid(cpuid, (uint32_t *)&(info->vm_regs.rax), @@ -139,6 +142,8 @@ int v3_handle_cpuid(struct guest_info * info) { (uint32_t *)&(info->vm_regs.rcx), (uint32_t *)&(info->vm_regs.rdx)); } else { + // PrintDebug("Calling hook function\n"); + if (hook->hook_fn(info, cpuid, (uint32_t *)&(info->vm_regs.rax), (uint32_t *)&(info->vm_regs.rbx), @@ -150,6 +155,8 @@ int v3_handle_cpuid(struct guest_info * info) { } } + // PrintDebug("Cleaning up register contents\n"); + info->vm_regs.rax &= 0x00000000ffffffffLL; info->vm_regs.rbx &= 0x00000000ffffffffLL; info->vm_regs.rcx &= 0x00000000ffffffffLL; diff --git a/palacios/src/palacios/vmm_msr.c b/palacios/src/palacios/vmm_msr.c index 8b70dd2..de68a86 100644 --- a/palacios/src/palacios/vmm_msr.c +++ b/palacios/src/palacios/vmm_msr.c @@ -38,6 +38,8 @@ int v3_handle_msr_write(struct guest_info * info) { struct v3_msr msr_val; struct v3_msr_hook * hook = NULL; + PrintDebug("MSR write for msr 0x%x\n", msr_num); + hook = v3_get_msr_hook(info, msr_num); if (!hook) { @@ -151,6 +153,7 @@ void v3_refresh_msr_map(struct guest_info * info) { } list_for_each_entry(hook, &(msr_map->hook_list), link) { + PrintDebug("updating MSR map for msr %d\n", hook->msr); msr_map->update_map(info, hook->msr, (hook->read == NULL) ? 0 : 1, (hook->write == NULL) ? 0 : 1); @@ -162,7 +165,7 @@ void v3_print_msr_map(struct guest_info * info) { struct v3_msr_hook * hook = NULL; list_for_each_entry(hook, &(msr_map->hook_list), link) { - PrintDebug("MSR HOOK (MSR=%d) (read=0x%p) (write=0x%p)\n", + V3_Print("MSR HOOK (MSR=0x%x) (read=0x%p) (write=0x%p)\n", hook->msr, hook->read, hook->write); } } diff --git a/palacios/src/palacios/vmm_shadow_paging_64.h b/palacios/src/palacios/vmm_shadow_paging_64.h index 8ba9841..421707a 100644 --- a/palacios/src/palacios/vmm_shadow_paging_64.h +++ b/palacios/src/palacios/vmm_shadow_paging_64.h @@ -154,7 +154,7 @@ static inline int handle_shadow_pagefault_64(struct guest_info * info, addr_t fa if (guest_pa_to_host_va(info, BASE_TO_PAGE_ADDR(guest_pml4e->pdp_base_addr), (addr_t *)&guest_pdp) == -1) { // Machine check the guest - PrintDebug("Invalid Guest PDP Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pml4e->pdp_base_addr)); + PrintError("Invalid Guest PDP Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pml4e->pdp_base_addr)); v3_raise_exception(info, MC_EXCEPTION); return 0; } @@ -255,7 +255,7 @@ static int handle_pdpe_shadow_pagefault_64(struct guest_info * info, addr_t faul if (guest_pa_to_host_va(info, BASE_TO_PAGE_ADDR(guest_pdpe->pd_base_addr), (addr_t *)&guest_pd) == -1) { // Machine check the guest - PrintDebug("Invalid Guest PTE Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pdpe->pd_base_addr)); + PrintError("Invalid Guest PTE Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pdpe->pd_base_addr)); v3_raise_exception(info, MC_EXCEPTION); return 0; } @@ -377,7 +377,7 @@ static int handle_pde_shadow_pagefault_64(struct guest_info * info, addr_t fault if (guest_pde->large_page == 0) { if (guest_pa_to_host_va(info, BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr), (addr_t *)&guest_pt) == -1) { // Machine check the guest - PrintDebug("Invalid Guest PTE Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr)); + PrintError("Invalid Guest PTE Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr)); v3_raise_exception(info, MC_EXCEPTION); return 0; } @@ -414,7 +414,7 @@ static int handle_pte_shadow_pagefault_64(struct guest_info * info, addr_t fault if (shdw_reg == NULL) { // Inject a machine check in the guest - PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_pa); + PrintError("Invalid Guest Address in page table (0x%p)\n", (void *)guest_pa); v3_raise_exception(info, MC_EXCEPTION); return 0; } @@ -541,7 +541,7 @@ static int handle_2MB_shadow_pagefault_64(struct guest_info * info, if (shdw_reg == NULL) { // Inject a machine check in the guest - PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_fault_pa); + PrintError("Invalid Guest Address in page table (0x%p)\n", (void *)guest_fault_pa); v3_raise_exception(info, MC_EXCEPTION); return 0; } diff --git a/palacios/src/palacios/vmm_sym_iface.c b/palacios/src/palacios/vmm_sym_iface.c index 0c6414d..5cb4e35 100644 --- a/palacios/src/palacios/vmm_sym_iface.c +++ b/palacios/src/palacios/vmm_sym_iface.c @@ -21,10 +21,13 @@ #include #include #include +#include -#define SYM_MSR_NUM 0x535 +#define SYM_PAGE_MSR 0x535 +#define SYM_CPUID_NUM 0x90000000 +#define SYM_CALL_RET_HCALL 0x535 static int msr_read(uint_t msr, struct v3_msr * dst, void * priv_data) { @@ -40,6 +43,9 @@ static int msr_write(uint_t msr, struct v3_msr src, void * priv_data) { struct guest_info * info = (struct guest_info *)priv_data; struct v3_sym_state * state = &(info->sym_state); + + PrintDebug("Symbiotic MSR write for page %p\n", (void *)src.value); + if (state->active == 1) { // unmap page struct v3_shadow_region * old_reg = v3_get_shadow_region(info, (addr_t)state->guest_pg_addr); @@ -65,45 +71,216 @@ static int msr_write(uint_t msr, struct v3_msr src, void * priv_data) { return 0; } +static int cpuid_fn(struct guest_info * info, uint32_t cpuid, + uint32_t * eax, uint32_t * ebx, + uint32_t * ecx, uint32_t * edx, + void * private_data) { + + memset(eax, 0, sizeof(uint32_t)); + memcpy(eax, "V3V", 3); + + return 0; +} + + +static int sym_call_ret(struct guest_info * info, uint_t hcall_id, void * private_data); + int v3_init_sym_iface(struct guest_info * info) { struct v3_sym_state * state = &(info->sym_state); - memset(state, 0, sizeof(struct v3_sym_state)); - PrintDebug("Allocating symbiotic page\n"); state->sym_page_pa = (addr_t)V3_AllocPages(1); state->sym_page = (struct v3_sym_interface *)V3_VAddr((void *)state->sym_page_pa); - - PrintDebug("Clearing symbiotic page\n"); memset(state->sym_page, 0, PAGE_SIZE_4KB); - PrintDebug("hooking MSR\n"); - v3_hook_msr(info, SYM_MSR_NUM, msr_read, msr_write, info); + + memcpy(&(state->sym_page->magic), "V3V", 3); + + v3_hook_msr(info, SYM_PAGE_MSR, msr_read, msr_write, info); + + v3_hook_cpuid(info, SYM_CPUID_NUM, cpuid_fn, info); + + + v3_register_hypercall(info, SYM_CALL_RET_HCALL, sym_call_ret, NULL); - PrintDebug("Done\n"); return 0; } int v3_sym_map_pci_passthrough(struct guest_info * info, uint_t bus, uint_t dev, uint_t fn) { struct v3_sym_state * state = &(info->sym_state); - uint_t dev_index = (bus << 16) + (dev << 8) + fn; + uint_t dev_index = (bus << 8) + (dev << 3) + fn; uint_t major = dev_index / 8; uint_t minor = dev_index % 8; + if (bus > 3) { + PrintError("Invalid PCI bus %d\n", bus); + return -1; + } + + PrintDebug("Setting passthrough pci map for index=%d\n", dev_index); + state->sym_page->pci_pt_map[major] |= 0x1 << minor; + PrintDebug("pt_map entry=%x\n", state->sym_page->pci_pt_map[major]); + + PrintDebug("pt map vmm addr=%p\n", state->sym_page->pci_pt_map); + return 0; } int v3_sym_unmap_pci_passthrough(struct guest_info * info, uint_t bus, uint_t dev, uint_t fn) { struct v3_sym_state * state = &(info->sym_state); - uint_t dev_index = (bus << 16) + (dev << 8) + fn; + uint_t dev_index = (bus << 8) + (dev << 3) + fn; uint_t major = dev_index / 8; uint_t minor = dev_index % 8; + if (bus > 3) { + PrintError("Invalid PCI bus %d\n", bus); + return -1; + } + state->sym_page->pci_pt_map[major] &= ~(0x1 << minor); return 0; } + + + +static int sym_call_ret(struct guest_info * info, uint_t hcall_id, void * private_data) { + struct v3_sym_state * state = (struct v3_sym_state *)&(info->sym_state); + struct v3_sym_context * old_ctx = (struct v3_sym_context *)&(state->old_ctx); + + + PrintError("Return from sym call\n"); + v3_print_guest_state(info); + v3_print_mem_map(info); + + + if (state->notifier != NULL) { + if (state->notifier(info, state->private_data) == -1) { + PrintError("Error in return from symcall.\n"); + return -1; + } + } + + + // restore guest state + memcpy(&(info->vm_regs), &(old_ctx->vm_regs), sizeof(struct v3_gprs)); + memcpy(&(info->segments.cs), &(old_ctx->cs), sizeof(struct v3_segment)); + memcpy(&(info->segments.ss), &(old_ctx->ss), sizeof(struct v3_segment)); + info->segments.gs.base = old_ctx->gs_base; + info->segments.fs.base = old_ctx->fs_base; + info->rip = old_ctx->rip; + info->cpl = old_ctx->cpl; + + + PrintDebug("restoring guest state\n"); + v3_print_guest_state(info); + + // clear sym flags + state->call_active = 0; + + + return 0; +} + + +int v3_sym_call(struct guest_info * info, + uint64_t arg0, uint64_t arg1, + uint64_t arg2, uint64_t arg3, + uint64_t arg4, uint64_t arg5, + int (*notifier)(struct guest_info * info, void * private_data), + void * private_data) { + struct v3_sym_state * state = (struct v3_sym_state *)&(info->sym_state); + + + PrintDebug("Making Sym call\n"); + + if ((state->sym_page->sym_call_enabled == 0) || + (state->call_active == 1) || + (state->call_pending == 1)) { + return -1; + } + + state->args[0] = arg0; + state->args[1] = arg1; + state->args[2] = arg2; + state->args[3] = arg3; + state->args[4] = arg4; + state->args[5] = arg5; + + state->notifier = notifier; + state->private_data = private_data; + + state->call_pending = 1; + + return 0; +} + + + +int v3_activate_sym_call(struct guest_info * info) { + struct v3_sym_state * state = (struct v3_sym_state *)&(info->sym_state); + struct v3_sym_context * old_ctx = (struct v3_sym_context *)&(state->old_ctx); + struct v3_segment sym_cs; + struct v3_segment sym_ss; + + + if ((state->sym_page->sym_call_enabled == 0) || + (state->call_pending == 0)) { + // Unable to make sym call or none pending + if (state->call_active == 1) { + PrintError("handled exit while in symcall\n"); + } + return 0; + } + + + PrintDebug("Activating Symbiotic call\n"); + v3_print_guest_state(info); + + + // Save the old context + memcpy(&(old_ctx->vm_regs), &(info->vm_regs), sizeof(struct v3_gprs)); + memcpy(&(old_ctx->cs), &(info->segments.cs), sizeof(struct v3_segment)); + memcpy(&(old_ctx->ss), &(info->segments.ss), sizeof(struct v3_segment)); + old_ctx->gs_base = info->segments.gs.base; + old_ctx->fs_base = info->segments.fs.base; + old_ctx->rip = info->rip; + old_ctx->cpl = info->cpl; + + + + // Setup the sym call context + info->rip = state->sym_page->sym_call_rip; + info->vm_regs.rsp = state->sym_page->sym_call_rsp; + + v3_translate_segment(info, state->sym_page->sym_call_cs, &sym_cs); + memcpy(&(info->segments.cs), &sym_cs, sizeof(struct v3_segment)); + + v3_translate_segment(info, state->sym_page->sym_call_cs + 8, &sym_ss); + memcpy(&(info->segments.ss), &sym_ss, sizeof(struct v3_segment)); + + info->segments.gs.base = state->sym_page->sym_call_gs; + info->segments.fs.base = 0; + info->cpl = 0; + + info->vm_regs.rax = state->args[0]; + info->vm_regs.rbx = state->args[1]; + info->vm_regs.rcx = state->args[2]; + info->vm_regs.rdx = state->args[3]; + info->vm_regs.rsi = state->args[4]; + info->vm_regs.rdi = state->args[5]; + + // Mark sym call as active + state->call_pending = 0; + state->call_active = 1; + + + PrintDebug("Sym state\n"); + v3_print_guest_state(info); + + return 1; +} diff --git a/palacios/src/palacios/vmx_ctrl_regs.c b/palacios/src/palacios/vmx_ctrl_regs.c index 8fb7a81..00fd7e9 100644 --- a/palacios/src/palacios/vmx_ctrl_regs.c +++ b/palacios/src/palacios/vmx_ctrl_regs.c @@ -83,10 +83,11 @@ static int handle_mov_to_cr3(struct guest_info * info, v3_reg_t * cr3_reg) { if (info->shdw_pg_mode == SHADOW_PAGING) { + /* PrintDebug("Old Guest CR3=%p, Old Shadow CR3=%p\n", (void *)info->ctrl_regs.cr3, (void *)info->shdw_pg_state.guest_cr3); - + */ if (info->cpu_mode == LONG) { info->shdw_pg_state.guest_cr3 = (uint64_t)*cr3_reg; } else { @@ -100,11 +101,11 @@ static int handle_mov_to_cr3(struct guest_info * info, v3_reg_t * cr3_reg) { return -1; } } - + /* PrintDebug("New guest CR3=%p, New shadow CR3=%p\n", (void *)info->ctrl_regs.cr3, (void *)info->shdw_pg_state.guest_cr3); - + */ } else if (info->shdw_pg_mode == NESTED_PAGING) { PrintError("Nested paging not available in VMX right now!\n"); return -1; @@ -150,15 +151,17 @@ static int handle_mov_to_cr0(struct guest_info * info, v3_reg_t * new_cr0) { uint_t paging_transition = 0; int instr_len = 0; + /* PrintDebug("Old shadow CR0: 0x%x, New shadow CR0: 0x%x\n", (uint32_t)info->shdw_pg_state.guest_cr0, (uint32_t)*new_cr0); - + */ if (new_shdw_cr0->pe != shdw_cr0->pe) { + /* PrintDebug("Guest CR0: 0x%x\n", *(uint32_t *)guest_cr0); PrintDebug("Old shadow CR0: 0x%x\n", *(uint32_t *)shdw_cr0); PrintDebug("New shadow CR0: 0x%x\n", *(uint32_t *)new_shdw_cr0); - + */ if (v3_vmxassist_ctx_switch(info) != 0) { PrintError("Unable to execute VMXASSIST context switch!\n"); return -1; @@ -200,7 +203,7 @@ static int handle_mov_to_cr0(struct guest_info * info, v3_reg_t * new_cr0) { struct efer_64 * guest_efer = (struct efer_64 *)&(info->ctrl_regs.efer); if (guest_efer->lme == 1) { - PrintDebug("Enabling long mode\n"); + // PrintDebug("Enabling long mode\n"); guest_efer->lma = 1; guest_efer->lme = 1; @@ -208,7 +211,7 @@ static int handle_mov_to_cr0(struct guest_info * info, v3_reg_t * new_cr0) { vmx_info->entry_ctrls.guest_ia32e = 1; } - PrintDebug("Activating Shadow Page tables\n"); + // PrintDebug("Activating Shadow Page tables\n"); if (v3_activate_shadow_pt(info) == -1) { PrintError("Failed to activate shadow page tables\n"); diff --git a/palacios/src/palacios/vmx_handler.c b/palacios/src/palacios/vmx_handler.c index ee1824f..1da5abd 100644 --- a/palacios/src/palacios/vmx_handler.c +++ b/palacios/src/palacios/vmx_handler.c @@ -67,10 +67,10 @@ static int inline handle_cr_access(struct guest_info * info, ulong_t exit_qual) // PrintDebug("Control register: %d\n", cr_qual->access_type); switch(cr_qual->cr_id) { case 0: - PrintDebug("Handling CR0 Access\n"); + //PrintDebug("Handling CR0 Access\n"); return v3_vmx_handle_cr0_access(info); case 3: - PrintDebug("Handling CR3 Access\n"); + //PrintDebug("Handling CR3 Access\n"); return v3_vmx_handle_cr3_access(info); default: PrintError("Unhandled CR access: %d\n", cr_qual->cr_id); @@ -201,6 +201,19 @@ int v3_handle_vmx_exit(struct v3_gprs * gprs, struct guest_info * info, struct v } break; + case VMEXIT_VMCALL: + /* + * Hypercall + */ + + // VMCALL is a 3 byte op + // We do this early because some hypercalls can change the rip... + info->rip += 3; + + if (v3_handle_hypercall(info) == -1) { + return -1; + } + break; case VMEXIT_IO_INSTR: { struct vmx_exit_io_qual * io_qual = (struct vmx_exit_io_qual *)&exit_qual; @@ -293,12 +306,16 @@ int v3_handle_vmx_exit(struct v3_gprs * gprs, struct guest_info * info, struct v check_vmcs_write(VMCS_ENTRY_EXCP_ERR, info->excp_state.excp_error_code); int_info.error_code = 1; +#ifdef CONFIG_DEBUG_INTERRUPTS PrintDebug("Injecting exception %d with error code %x\n", int_info.vector, info->excp_state.excp_error_code); +#endif } int_info.valid = 1; +#ifdef CONFIG_DEBUG_INTERRUPTS PrintDebug("Injecting exception %d (EIP=%p)\n", int_info.vector, (void *)info->rip); +#endif check_vmcs_write(VMCS_ENTRY_INT_INFO, int_info.value); v3_injecting_excp(info, int_info.vector); diff --git a/test/geekos_test_vm/src/geekos/main.c b/test/geekos_test_vm/src/geekos/main.c index 177771a..cc1f722 100644 --- a/test/geekos_test_vm/src/geekos/main.c +++ b/test/geekos_test_vm/src/geekos/main.c @@ -291,8 +291,39 @@ void Main(struct Boot_Info* bootInfo) PrintBoth("Next: setup GDT\n"); + { + uint_t addr = 0xe0000; + uint_t hi = 0; + + + + // wrmsr(SYMBIOTIC_MSR, hi, addr); + { + uint_t msr_num = 0x0000001B; + __asm__ __volatile__ ("rdmsr" : : "c"(msr_num) : "%eax","%edx","memory"); + } + { + uint_t msr_num = 0x0000001c; + __asm__ __volatile__ ("rdmsr" : : "c"(msr_num) : "%eax","%edx","memory"); + } + + + { + uint_t msr_num = 0x0000001B; + __asm__ __volatile__ ("wrmsr" : : "c"(msr_num), "a"(hi), "d"(addr) : "memory"); + } + + { + uint_t msr_num = 0x535; + __asm__ __volatile__ ("wrmsr" : : "c"(msr_num), "a"(hi), "d"(addr) : "memory"); + } + + + while (1) {} + + } if (TEST_PAGING) { int i = 0; for (i = 0; i < 1024; i++) {