Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


added support for in/out instructions
Jack Lange [Fri, 4 Apr 2008 00:28:23 +0000 (00:28 +0000)]
palacios/build/Makefile
palacios/include/geekos/svm_handler.h
palacios/include/geekos/svm_io.h [new file with mode: 0644]
palacios/include/geekos/vmm_io.h
palacios/src/geekos/main.c
palacios/src/geekos/svm.c
palacios/src/geekos/svm_ctrl_regs.c
palacios/src/geekos/svm_handler.c
palacios/src/geekos/svm_io.c [new file with mode: 0644]
palacios/src/geekos/vmm_io.c

index 7a42b22..fad3695 100644 (file)
@@ -1,6 +1,6 @@
 # Makefile for GeekOS kernel, userspace, and tools
 # Copyright (c) 2004,2005 David H. Hovemeyer <daveho@cs.umd.edu>
-# $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
index b09ac60..21f030f 100644 (file)
 /******************************************/
 
 
-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 (file)
index 0000000..83ee21d
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __SVM_IO_H
+#define __SVM_IO_H
+#include <geekos/vm_guest.h>
+#include <geekos/vmcb.h>
+#include <geekos/vmm.h>
+
+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
index fde2ea6..8909d55 100644 (file)
@@ -5,18 +5,18 @@
 
 #include <geekos/vmm_util.h>
 
-// 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);
 
index 19933a5..9877cd7 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
  * Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
  * Copyright (c) 2004, Iulian Neamtiu <neamtiu@cs.umd.edu>
- * $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;
index 7d012e4..6870430 100644 (file)
@@ -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
index 084becb..99d1f94 100644 (file)
@@ -7,6 +7,13 @@
 #include <geekos/vmm_ctrl_regs.h>
 
 
+/* 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++; 
+    }
+
+
   }
 
 
index 6cd7afe..e35179b 100644 (file)
@@ -1,6 +1,7 @@
 #include <geekos/svm_handler.h>
 #include <geekos/vmm.h>
 #include <geekos/svm_ctrl_regs.h>
+#include <geekos/svm_io.h>
 
 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 (file)
index 0000000..f44c2b6
--- /dev/null
@@ -0,0 +1,87 @@
+#include <geekos/svm_io.h>
+#include <geekos/vmm_io.h>
+
+
+
+// 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;
+}
index 9508ad1..a45e2ca 100644 (file)
@@ -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;