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 full io support
Jack Lange [Fri, 4 Apr 2008 06:01:57 +0000 (06:01 +0000)]
palacios/build/vm_kernel
palacios/include/geekos/svm.h
palacios/include/geekos/svm_io.h
palacios/include/geekos/vmm_ctrl_regs.h
palacios/include/geekos/vmm_emulate.h
palacios/include/geekos/vmm_io.h
palacios/src/geekos/main.c
palacios/src/geekos/svm_ctrl_regs.c
palacios/src/geekos/svm_io.c
palacios/src/geekos/svm_lowlevel.asm
palacios/src/geekos/vmm_io.c

index e6c7836..5b5ab6d 100755 (executable)
Binary files a/palacios/build/vm_kernel and b/palacios/build/vm_kernel differ
index ddd3414..8b606b4 100644 (file)
@@ -68,6 +68,8 @@ int init_svm_guest(struct guest_info *info);
 int start_svm_guest(struct guest_info * info);
 
 
+inline addr_t get_rip_linear(struct guest_info * info, addr_t rip, addr_t cs_base);
+
 
 
 #endif
index 83ee21d..361a1d9 100644 (file)
@@ -12,9 +12,9 @@ struct svm_io_info {
   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 addr16      : 1       PACKED;  // 16 bit addr
+  uint_t addr32      : 1       PACKED;  // 32 bit addr
+  uint_t addr64      : 1       PACKED;  // 64 bit addr
   uint_t rsvd2       : 6       PACKED;  // Should be Zero
   ushort_t port                PACKED;  // port number
 };
index f0d63fe..0bebdbc 100644 (file)
@@ -115,4 +115,33 @@ struct cr4_64 {
   uint_t rsvd2             : 32;
 };
 
+
+
+struct rflags {
+  uint_t cf                : 1;  // carry flag
+  uint_t rsvd1             : 1;  // Must be 1
+  uint_t pf                : 1;  // parity flag
+  uint_t rsvd2             : 1;  // Read as 0
+  uint_t af                : 1;  // Auxillary flag
+  uint_t rsvd3             : 1;  // Read as 0
+  uint_t zf                : 1;  // zero flag
+  uint_t sf                : 1;  // sign flag
+  uint_t tf                : 1;  // trap flag
+  uint_t intr              : 1;  // interrupt flag
+  uint_t df                : 1;  // direction flag
+  uint_t of                : 1;  // overflow flag
+  uint_t iopl              : 2;  // IO privilege level
+  uint_t nt                : 1;  // nested task
+  uint_t rsvd4             : 1;  // read as 0
+  uint_t rf                : 1;  // resume flag
+  uint_t vm                : 1;  // Virtual-8086 mode
+  uint_t ac                : 1;  // alignment check
+  uint_t vif               : 1;  // virtual interrupt flag
+  uint_t vip               : 1;  // virtual interrupt pending
+  uint_t id                : 1;  // ID flag
+  uint_t rsvd5             : 10; // Read as 0
+  uint_t rsvd6             : 32; // Read as 0
+};
+
+
 #endif
index 5157214..4b843cc 100644 (file)
@@ -150,6 +150,21 @@ static inline int is_prefix_byte(char byte) {
 
 
 
+static inline addr_t get_rip_linear(struct guest_info * info, addr_t rip, addr_t cs_base) {
+  switch (info->cpu_mode) {
+  case REAL:
+    return rip + (cs_base << 4);
+    break;
+  case PROTECTED:
+  case PROTECTED_PG:
+    return rip + cs_base;
+    break;
+  default:
+    return 0;
+  }
+}
+
+
 typedef enum {INVALID_ADDR_TYPE, REG, DISP0, DISP8, DISP16, DISP32} modrm_mode_t;
 typedef enum {INVALID_REG_SIZE, REG64, REG32, REG16, REG8} reg_size_t;
 typedef enum {INVALID_OPERAND, REG_OPERAND, MEM_OPERAND} operand_type_t;
index 8909d55..556be88 100644 (file)
@@ -13,10 +13,10 @@ 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, uint_t io_width);
+  int (*read)(ushort_t port, void * dst, uint_t length);
 
   // Writes data from the IO port (OUT, OUTS)
-  int (*write)(ushort_t port, void * src, uint_t length, uint_t io_width);
+  int (*write)(ushort_t port, void * src, uint_t length);
 
   struct vmm_io_hook * next;
   struct vmm_io_hook * prev;
@@ -42,8 +42,8 @@ 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, uint_t io_width),
-                 int (*write)(ushort_t port, void * src, uint_t length, uint_t io_width));
+                 int (*read)(ushort_t port, void * dst, uint_t length),
+                 int (*write)(ushort_t port, void * src, uint_t length));
 
 void init_vmm_io_map(vmm_io_map_t * io_map);
 
index 9877cd7..ea43291 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.29 $
+ * $Revision: 1.30 $
  * 
  * 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, uint_t io_width) {
+int IO_Read(ushort_t port, void * dst, uint_t length) {
   uchar_t * iter = dst;
   uint_t i;
 
@@ -102,7 +102,7 @@ int IO_Read(ushort_t port, void * dst, uint_t length, uint_t io_width) {
 
 
 
-int IO_Write(ushort_t port, void * src, uint_t length, uint_t io_width) {
+int IO_Write(ushort_t port, void * src, uint_t length) {
   uchar_t * iter = src;
   uint_t i;
 
@@ -117,9 +117,24 @@ int IO_Write(ushort_t port, void * src, uint_t length, uint_t io_width) {
 
 
 
-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);
+int IO_Write_to_Serial(ushort_t port, void * src, uint_t length) {
+  PrintBoth("Output from Guest on port %d (0x%x) Length=%d\n", port, port, length);
+  switch (length) {
+
+  case 1:
+    PrintBoth(">0x%.2x\n", *(char*)src);
+    break;
+  case 2:
+    PrintBoth(">0x%.4x\n", *(ushort_t*)src);
+    break;
+  case 4:
+    PrintBoth(">0x%.8x\n", *(uint_t*)src);
+    break;
+  default:
+    break;
+  }
+
+  //  SerialMemDump(src, length);
   return length;
 }
 
index 99d1f94..ffdd3de 100644 (file)
@@ -25,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 + (guest_state->cs.base << 4), 15, instr);
+    ret = read_guest_pa_memory(info, get_rip_linear(info, 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);
@@ -117,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 + guest_state->cs.base, 15, instr);
+    ret = read_guest_pa_memory(info, get_rip_linear(info, 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);
@@ -128,6 +128,8 @@ int handle_cr0_write(struct guest_info * info) {
       index++; 
     }
 
+
+    /* CHECK IF MOV_TO_CR CAN TAKE MEMORY OPERANDS... */
     if ((instr[index] == cr_access_byte) && 
        (instr[index + 1] == mov_to_cr_byte)) {
     
@@ -198,7 +200,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 + (guest_state->cs.base << 4), 15, instr);
+    ret = read_guest_pa_memory(info, get_rip_linear(info, 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);
@@ -255,7 +257,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 + guest_state->cs.base, 15, instr);
+    ret = read_guest_pa_memory(info, get_rip_linear(info, 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);
index f44c2b6..96c746d 100644 (file)
@@ -1,6 +1,8 @@
 #include <geekos/svm_io.h>
 #include <geekos/vmm_io.h>
-
+#include <geekos/vmm_ctrl_regs.h>
+#include <geekos/vmm_emulate.h>
+#include <geekos/vm_guest_mem.h>
 
 
 // This should package up an IO request and call vmm_handle_io
@@ -28,7 +30,7 @@ int handle_svm_io_in(struct guest_info * info) {
   }
 
 
-  if (hook->read(io_info->port, &(info->vm_regs.rax), read_size, read_size) != read_size) {
+  if (hook->read(io_info->port, &(info->vm_regs.rax), read_size) != read_size) {
     // not sure how we handle errors.....
     return -1;
   }
@@ -39,12 +41,93 @@ int handle_svm_io_in(struct guest_info * info) {
 }
 
 
+
+
+
+/* We might not handle wrap around of the RDI register correctly...
+ * In that if we do wrap around the effect will manifest in the higher bits of the register
+ */
 int handle_svm_io_ins(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;
+  addr_t base_addr = guest_state->es.base;
+  addr_t dst_addr = 0;
+  uint_t rep_num = 1;
+  ullong_t mask = 0;
+
+  // This is kind of hacky...
+  // direction can equal either 1 or -1
+  // We will multiply the final added offset by this value to go the correct direction
+  int direction = 1;
+  struct rflags * flags = (struct rflags *)&(guest_state->rflags);  
+  if (flags->df) {
+    direction = -1;
+  }
+
+
+  if (hook == NULL) {
+    // error, we should not have exited on this port
+    return -1;
+  }
+
+  PrintDebug("INS 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 (io_info->addr16) {
+    mask = 0xffff;
+  } else if (io_info->addr32) {
+    mask = 0xffffffff;
+  } else if (io_info->addr64) {
+    mask = 0xffffffffffffffffLL;
+  } else {
+    // should never happen
+    return -1;
+  }
+
+  if (io_info->rep) {
+    rep_num = info->vm_regs.rcx & mask;
+  }
+
 
-  //  PrintDebug("INS on  port %d (0x%x)\n", io_info->port, io_info->port);
 
-  return -1;
+  while (rep_num > 0) {
+    addr_t host_addr;
+    dst_addr = base_addr + (info->vm_regs.rdi & mask);
+    
+    if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
+      // either page fault or gpf...
+    }
 
+    if (hook->read(io_info->port, (char*)host_addr, read_size) != read_size) {
+      // not sure how we handle errors.....
+      return -1;
+    }
+
+    info->vm_regs.rdi += read_size * direction;
+
+    if (io_info->rep)
+      info->vm_regs.rcx--;
+    
+    rep_num--;
+  }
+
+
+  info->rip = ctrl_area->exit_info2;
+
+  return 0;
 }
 
 int handle_svm_io_out(struct guest_info * info) {
@@ -71,7 +154,7 @@ int handle_svm_io_out(struct guest_info * info) {
   }
 
 
-  if (hook->write(io_info->port, &(info->vm_regs.rax), write_size, write_size) != write_size) {
+  if (hook->write(io_info->port, &(info->vm_regs.rax), write_size) != write_size) {
     // not sure how we handle errors.....
     return -1;
   }
@@ -82,6 +165,92 @@ int handle_svm_io_out(struct guest_info * info) {
 }
 
 
+/* We might not handle wrap around of the RSI register correctly...
+ * In that if we do wrap around the effect will manifest in the higher bits of the register
+ */
+
 int handle_svm_io_outs(struct guest_info * info) {
-  return -1;
+  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;
+  addr_t base_addr = guest_state->ds.base;
+  addr_t dst_addr = 0;
+  uint_t rep_num = 1;
+  ullong_t mask = 0;
+
+  // This is kind of hacky...
+  // direction can equal either 1 or -1
+  // We will multiply the final added offset by this value to go the correct direction
+  int direction = 1;
+  struct rflags * flags = (struct rflags *)&(guest_state->rflags);  
+  if (flags->df) {
+    direction = -1;
+  }
+
+
+  if (hook == NULL) {
+    // error, we should not have exited on this port
+    return -1;
+  }
+
+  PrintDebug("OUTS 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 (io_info->addr16) {
+    mask = 0xffff;
+  } else if (io_info->addr32) {
+    mask = 0xffffffff;
+  } else if (io_info->addr64) {
+    mask = 0xffffffffffffffffLL;
+  } else {
+    // should never happen
+    return -1;
+  }
+
+  if (io_info->rep) {
+    rep_num = info->vm_regs.rcx & mask;
+  }
+
+
+  while (rep_num > 0) {
+    addr_t host_addr;
+    dst_addr = base_addr + (info->vm_regs.rsi & mask);
+    
+    if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
+      // either page fault or gpf...
+    }
+
+    if (hook->write(io_info->port, (char*)host_addr, write_size) != write_size) {
+      // not sure how we handle errors.....
+      return -1;
+    }
+
+    info->vm_regs.rsi += write_size * direction;
+
+    if (io_info->rep)
+      info->vm_regs.rcx--;
+    
+    rep_num--;
+  }
+
+
+  info->rip = ctrl_area->exit_info2;
+
+
+  return 0;
+
+
+
 }
index 3b100d3..5ce9650 100644 (file)
@@ -173,7 +173,8 @@ safe_svm_launch:
 
 ;;     mov     eax, [esp + 4]                  ;; mov guest GPR pointer to eax
 
-       Restore_SVM_Registers [esp + 4]         ;; Restore Guest GPR state
+       ;; this is plus 8 because we push eax in the macro
+       Restore_SVM_Registers [esp + 8]         ;; Restore Guest GPR state
        pop     eax                             ;; pop VMCB pointer into eax
 
        vmload
@@ -181,7 +182,8 @@ safe_svm_launch:
        vmsave
 
 ;;     pop     eax                             ;; pop Guest GPR pointer into eax
-       Save_SVM_Registers  [esp]               ;; save guest GPRs
+       ;; this is plus 4 because we push eax in the macro NEED TO CHANGE
+       Save_SVM_Registers  [esp+4]             ;; save guest GPRs
        
        add     esp, 4                          ;; skip past the gpr ptr
        
index a45e2ca..69e4abe 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, uint_t io_width),
-                 int (*write)(ushort_t port, void * src, uint_t length, uint_t io_width)) {
+                 int (*read)(ushort_t port, void * dst, uint_t length),
+                 int (*write)(ushort_t port, void * src, uint_t length)) {
   vmm_io_hook_t * io_hook = os_hooks->malloc(sizeof(vmm_io_hook_t));
 
   io_hook->port = port;