From: Jack Lange Date: Fri, 4 Apr 2008 00:28:23 +0000 (+0000) Subject: added support for in/out instructions X-Git-Tag: working-cdboot-physical-but-not-qemu~44 X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=29dcf8d7134d5c8fe56ec1f3ffaaa37192ce6fb8 added support for in/out instructions --- diff --git a/palacios/build/Makefile b/palacios/build/Makefile index 7a42b22..fad3695 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.20 $ +# $Revision: 1.21 $ # This is free software. You are permitted to use, # redistribute, and modify it as specified in the file "COPYING". @@ -86,7 +86,7 @@ KERNEL_C_SRCS := idt.c int.c trap.c irq.c io.c \ serial.c reboot.c \ paging.c vm_guest.c \ svm.c svm_handler.c vmm.c vmm_util.c vmm_stubs.c svm_ctrl_regs.c \ - vmcb.c vmm_mem.c vmm_paging.c vmm_io.c vmm_debug.c \ + vmcb.c vmm_mem.c vmm_paging.c vmm_io.c vmm_debug.c svm_io.c \ vmm_shadow_paging.c vm_guest_mem.c \ debug.c vmx.c vmcs_gen.c vmcs.c\ main.c diff --git a/palacios/include/geekos/svm_handler.h b/palacios/include/geekos/svm_handler.h index b09ac60..21f030f 100644 --- a/palacios/include/geekos/svm_handler.h +++ b/palacios/include/geekos/svm_handler.h @@ -170,23 +170,8 @@ /******************************************/ -struct svm_io_info { - uint_t type : 1 PACKED; // (0=out, 1=in) - uint_t rsvd : 1 PACKED; // Must be Zero - uint_t str : 1 PACKED; // string based io - uint_t rep : 1 PACKED; // repeated io - uint_t sz8 : 1 PACKED; // 8 bit op size - uint_t sz16 : 1 PACKED; // 16 bit op size - uint_t sz32 : 1 PACKED; // 32 bit op size - uint_t A16 : 1 PACKED; // 16 bit addr - uint_t A32 : 1 PACKED; // 32 bit addr - uint_t A64 : 1 PACKED; // 64 bit addr - uint_t rsvd2 : 6 PACKED; // Should be Zero - ushort_t port PACKED; // port number -}; - - -int handle_svm_io(struct guest_info * info); + + int handle_shadow_paging(struct guest_info * info); int handle_svm_exit(struct guest_info * info); diff --git a/palacios/include/geekos/svm_io.h b/palacios/include/geekos/svm_io.h new file mode 100644 index 0000000..83ee21d --- /dev/null +++ b/palacios/include/geekos/svm_io.h @@ -0,0 +1,31 @@ +#ifndef __SVM_IO_H +#define __SVM_IO_H +#include +#include +#include + +struct svm_io_info { + uint_t type : 1 PACKED; // (0=out, 1=in) + uint_t rsvd : 1 PACKED; // Must be Zero + uint_t str : 1 PACKED; // string based io + uint_t rep : 1 PACKED; // repeated io + uint_t sz8 : 1 PACKED; // 8 bit op size + uint_t sz16 : 1 PACKED; // 16 bit op size + uint_t sz32 : 1 PACKED; // 32 bit op size + uint_t A16 : 1 PACKED; // 16 bit addr + uint_t A32 : 1 PACKED; // 32 bit addr + uint_t A64 : 1 PACKED; // 64 bit addr + uint_t rsvd2 : 6 PACKED; // Should be Zero + ushort_t port PACKED; // port number +}; + + +int handle_svm_io_in(struct guest_info * info); +int handle_svm_io_ins(struct guest_info * info); +int handle_svm_io_out(struct guest_info * info); +int handle_svm_io_outs(struct guest_info * info); + + + + +#endif diff --git a/palacios/include/geekos/vmm_io.h b/palacios/include/geekos/vmm_io.h index fde2ea6..8909d55 100644 --- a/palacios/include/geekos/vmm_io.h +++ b/palacios/include/geekos/vmm_io.h @@ -5,18 +5,18 @@ #include -// FOREACH_IO_HOOK(vmm_io_map_t io_map, vmm_io_hook_t * io_hook) -#define FOREACH_IO_HOOK(io_map, io_hook) for (io_hook = io_map.head; io_hook != NULL; io_hook = io_hook->next) +// FOREACH_IO_HOOK(vmm_io_map_t * io_map, vmm_io_hook_t * io_hook) +#define FOREACH_IO_HOOK(io_map, io_hook) for (io_hook = (io_map).head; io_hook != NULL; io_hook = (io_hook)->next) typedef struct vmm_io_hook { ushort_t port; // Reads data into the IO port (IN, INS) - int (*read)(ushort_t port, void * dst, uint_t length); + int (*read)(ushort_t port, void * dst, uint_t length, uint_t io_width); // Writes data from the IO port (OUT, OUTS) - int (*write)(ushort_t port, void * src, uint_t length); + int (*write)(ushort_t port, void * src, uint_t length, uint_t io_width); struct vmm_io_hook * next; struct vmm_io_hook * prev; @@ -37,11 +37,13 @@ void add_io_hook(vmm_io_map_t * io_map, vmm_io_hook_t * io_hook); +vmm_io_hook_t * get_io_hook(vmm_io_map_t * io_map, uint_t port); + /* External API */ void hook_io_port(vmm_io_map_t * io_map, uint_t port, - int (*read)(ushort_t port, void * dst, uint_t length), - int (*write)(ushort_t port, void * src, uint_t length)); + int (*read)(ushort_t port, void * dst, uint_t length, uint_t io_width), + int (*write)(ushort_t port, void * src, uint_t length, uint_t io_width)); void init_vmm_io_map(vmm_io_map_t * io_map); diff --git a/palacios/src/geekos/main.c b/palacios/src/geekos/main.c index 19933a5..9877cd7 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.28 $ + * $Revision: 1.29 $ * * This is free software. You are permitted to use, * redistribute, and modify it as specified in the file "COPYING". @@ -88,7 +88,7 @@ inline uchar_t MyIn_Byte(ushort_t port) -int IO_Read(ushort_t port, void * dst, uint_t length) { +int IO_Read(ushort_t port, void * dst, uint_t length, uint_t io_width) { uchar_t * iter = dst; uint_t i; @@ -102,7 +102,7 @@ int IO_Read(ushort_t port, void * dst, uint_t length) { -int IO_Write(ushort_t port, void * src, uint_t length) { +int IO_Write(ushort_t port, void * src, uint_t length, uint_t io_width) { uchar_t * iter = src; uint_t i; @@ -116,6 +116,14 @@ int IO_Write(ushort_t port, void * src, uint_t length) { } + +int IO_Write_to_Serial(ushort_t port, void * src, uint_t length, uint_t io_width) { + SerialPrint("Output from Guest on port %d (0x%x) Length=%d\n", port, port, length); + SerialMemDump(src, length); + return length; +} + + void BuzzVM() { int x; @@ -342,7 +350,7 @@ void Main(struct Boot_Info* bootInfo) add_shadow_region(&(vm_info.mem_map),ent); hook_io_port(&(vm_info.io_map), 0x61, &IO_Read, &IO_Write); - hook_io_port(&(vm_info.io_map), 0x05, &IO_Read, &IO_Write); + hook_io_port(&(vm_info.io_map), 0x05, &IO_Read, &IO_Write_to_Serial); /* vm_info.cr0 = 0; diff --git a/palacios/src/geekos/svm.c b/palacios/src/geekos/svm.c index 7d012e4..6870430 100644 --- a/palacios/src/geekos/svm.c +++ b/palacios/src/geekos/svm.c @@ -176,13 +176,9 @@ void Init_VMCB_Real(vmcb_t * vmcb, struct guest_info vm_info) { guest_state->rip = vm_info.rip; - - - guest_state->efer |= EFER_MSR_svm_enable; guest_state->rflags = 0x00000002; // The reserved bit is always 1 ctrl_area->svm_instrs.instrs.VMRUN = 1; - // guest_state->cr0 = 0x00000001; // PE ctrl_area->guest_ASID = 1; guest_state->cr0 = 0x60000010; @@ -286,6 +282,7 @@ void Init_VMCB_Real(vmcb_t * vmcb, struct guest_info vm_info) { guest_state->g_pat = 0x7040600070406ULL; + vm_info.shdw_pg_state.guest_cr0.e_reg.low = guest_state->cr0; guest_state->cr0 |= 0x80000000; } else if (vm_info.page_mode == NESTED_PAGING) { // Flush the TLB on entries/exits diff --git a/palacios/src/geekos/svm_ctrl_regs.c b/palacios/src/geekos/svm_ctrl_regs.c index 084becb..99d1f94 100644 --- a/palacios/src/geekos/svm_ctrl_regs.c +++ b/palacios/src/geekos/svm_ctrl_regs.c @@ -7,6 +7,13 @@ #include +/* Segmentation is a problem here... + * + * When we get a memory operand, presumably we use the default segment (which is?) + * unless an alternate segment was specfied in the prefix... + */ + + int handle_cr0_write(struct guest_info * info) { //vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data)); vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); @@ -18,7 +25,7 @@ int handle_cr0_write(struct guest_info * info) { int ret; // The real rip address is actually a combination of the rip + CS base - ret = read_guest_pa_memory(info, (addr_t)guest_state->rip, 15, instr); + ret = read_guest_pa_memory(info, (addr_t)guest_state->rip + (guest_state->cs.base << 4), 15, instr); if (ret != 15) { // I think we should inject a GPF into the guest PrintDebug("Could not read instruction (ret=%d)\n", ret); @@ -54,7 +61,7 @@ int handle_cr0_write(struct guest_info * info) { } else if (addr_type == MEM_OPERAND) { addr_t host_addr; - if (guest_pa_to_host_va(info, first_operand, &host_addr) == -1) { + if (guest_pa_to_host_va(info, first_operand + (guest_state->ds.base << 4), &host_addr) == -1) { // gpf the guest return -1; } @@ -110,7 +117,7 @@ int handle_cr0_write(struct guest_info * info) { PrintDebug("Protected Mode write to CR0\n"); // The real rip address is actually a combination of the rip + CS base - ret = read_guest_pa_memory(info, (addr_t)guest_state->rip, 15, instr); + ret = read_guest_pa_memory(info, (addr_t)guest_state->rip + guest_state->cs.base, 15, instr); if (ret != 0) { // I think we should inject a GPF into the guest PrintDebug("Could not read instruction (ret=%d)\n", ret); @@ -142,7 +149,7 @@ int handle_cr0_write(struct guest_info * info) { } else if (addr_type == MEM_OPERAND) { addr_t host_addr; - if (guest_pa_to_host_va(info, first_operand, &host_addr) == -1) { + if (guest_pa_to_host_va(info, first_operand + guest_state->ds.base, &host_addr) == -1) { // gpf the guest return -1; } @@ -191,7 +198,7 @@ int handle_cr0_read(struct guest_info * info) { int ret; // The real rip address is actually a combination of the rip + CS base - ret = read_guest_pa_memory(info, (addr_t)guest_state->rip, 15, instr); + ret = read_guest_pa_memory(info, (addr_t)guest_state->rip + (guest_state->cs.base << 4), 15, instr); if (ret != 15) { // I think we should inject a GPF into the guest PrintDebug("Could not read instruction (ret=%d)\n", ret); @@ -222,7 +229,7 @@ int handle_cr0_read(struct guest_info * info) { if (addr_type == MEM_OPERAND) { addr_t host_addr; - if (guest_pa_to_host_va(info, first_operand, &host_addr) == -1) { + if (guest_pa_to_host_va(info, first_operand + (guest_state->ds.base << 4), &host_addr) == -1) { // gpf the guest return -1; } @@ -243,6 +250,23 @@ int handle_cr0_read(struct guest_info * info) { } + } else if (info->cpu_mode == PROTECTED) { + int index = 0; + int ret; + + // The real rip address is actually a combination of the rip + CS base + ret = read_guest_pa_memory(info, (addr_t)guest_state->rip + guest_state->cs.base, 15, instr); + if (ret != 15) { + // I think we should inject a GPF into the guest + PrintDebug("Could not read instruction (ret=%d)\n", ret); + return -1; + } + + while (is_prefix_byte(instr[index])) { + index++; + } + + } diff --git a/palacios/src/geekos/svm_handler.c b/palacios/src/geekos/svm_handler.c index 6cd7afe..e35179b 100644 --- a/palacios/src/geekos/svm_handler.c +++ b/palacios/src/geekos/svm_handler.c @@ -1,6 +1,7 @@ #include #include #include +#include extern struct vmm_os_hooks * os_hooks; @@ -36,10 +37,24 @@ int handle_svm_exit(struct guest_info * info) { PrintDebug("io_info2 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info2)); PrintDebug("io_info2 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4)); + if (exit_code == VMEXIT_IOIO) { - handle_svm_io(info); - + struct svm_io_info * io_info = (struct svm_io_info *)&(guest_ctrl->exit_info1); + + if (io_info->type == 0) { + if (io_info->str) { + handle_svm_io_outs(info); + } else { + handle_svm_io_out(info); + } + } else { + if (io_info->str) { + handle_svm_io_ins(info); + } else { + handle_svm_io_in(info); + } + } } else if (exit_code == VMEXIT_CR0_WRITE) { PrintDebug("CR0 Write\n"); @@ -67,29 +82,6 @@ int handle_svm_exit(struct guest_info * info) { -// This should package up an IO request and call vmm_handle_io -int handle_svm_io(struct guest_info * info) { - vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data)); - vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); - - PrintDebug("Ctrl Area=%x\n", ctrl_area); - - // struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1); - - - - // PrintDebugVMCB((vmcb_t*)(info->vmm_data)); - - guest_state->rip = ctrl_area->exit_info2; - - - - - // PrintDebug("Exit On Port %d\n", io_info->port); - - return 0; -} - int handle_shadow_paging(struct guest_info * info) { vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data)); diff --git a/palacios/src/geekos/svm_io.c b/palacios/src/geekos/svm_io.c new file mode 100644 index 0000000..f44c2b6 --- /dev/null +++ b/palacios/src/geekos/svm_io.c @@ -0,0 +1,87 @@ +#include +#include + + + +// This should package up an IO request and call vmm_handle_io +int handle_svm_io_in(struct guest_info * info) { + vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data)); + // vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); + struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1); + + vmm_io_hook_t * hook = get_io_hook(&(info->io_map), io_info->port); + uint_t read_size = 0; + + if (hook == NULL) { + // error, we should not have exited on this port + return -1; + } + + PrintDebug("IN on port %d (0x%x)\n", io_info->port, io_info->port); + + if (io_info->sz8) { + read_size = 1; + } else if (io_info->sz16) { + read_size = 2; + } else if (io_info->sz32) { + read_size = 4; + } + + + if (hook->read(io_info->port, &(info->vm_regs.rax), read_size, read_size) != read_size) { + // not sure how we handle errors..... + return -1; + } + + info->rip = ctrl_area->exit_info2; + + return 0; +} + + +int handle_svm_io_ins(struct guest_info * info) { + + // PrintDebug("INS on port %d (0x%x)\n", io_info->port, io_info->port); + + return -1; + +} + +int handle_svm_io_out(struct guest_info * info) { + vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data)); + // vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); + struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1); + + vmm_io_hook_t * hook = get_io_hook(&(info->io_map), io_info->port); + uint_t write_size = 0; + + if (hook == NULL) { + // error, we should not have exited on this port + return -1; + } + + PrintDebug("OUT on port %d (0x%x)\n", io_info->port, io_info->port); + + if (io_info->sz8) { + write_size = 1; + } else if (io_info->sz16) { + write_size = 2; + } else if (io_info->sz32) { + write_size = 4; + } + + + if (hook->write(io_info->port, &(info->vm_regs.rax), write_size, write_size) != write_size) { + // not sure how we handle errors..... + return -1; + } + + info->rip = ctrl_area->exit_info2; + + return 0; +} + + +int handle_svm_io_outs(struct guest_info * info) { + return -1; +} diff --git a/palacios/src/geekos/vmm_io.c b/palacios/src/geekos/vmm_io.c index 9508ad1..a45e2ca 100644 --- a/palacios/src/geekos/vmm_io.c +++ b/palacios/src/geekos/vmm_io.c @@ -52,8 +52,8 @@ void add_io_hook(vmm_io_map_t * io_map, vmm_io_hook_t * io_hook) { } void hook_io_port(vmm_io_map_t * io_map, uint_t port, - int (*read)(ushort_t port, void * dst, uint_t length), - int (*write)(ushort_t port, void * src, uint_t length)) { + int (*read)(ushort_t port, void * dst, uint_t length, uint_t io_width), + int (*write)(ushort_t port, void * src, uint_t length, uint_t io_width)) { vmm_io_hook_t * io_hook = os_hooks->malloc(sizeof(vmm_io_hook_t)); io_hook->port = port; @@ -68,6 +68,18 @@ void hook_io_port(vmm_io_map_t * io_map, uint_t port, } +vmm_io_hook_t * get_io_hook(vmm_io_map_t * io_map, uint_t port) { + vmm_io_hook_t * tmp_hook; + FOREACH_IO_HOOK(*io_map, tmp_hook) { + if (tmp_hook->port == port) { + return tmp_hook; + } + } + return NULL; +} + + + void PrintDebugIOMap(vmm_io_map_t * io_map) { vmm_io_hook_t * iter = io_map->head;