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 emulator
Jack Lange [Sun, 3 Aug 2008 01:21:43 +0000 (01:21 +0000)]
12 files changed:
palacios/include/palacios/vmm_emulator.h [new file with mode: 0644]
palacios/include/palacios/vmm_shadow_paging.h
palacios/src/devices/generic.c
palacios/src/geekos/trap.c
palacios/src/geekos/vm.c
palacios/src/palacios/svm.c
palacios/src/palacios/svm_handler.c
palacios/src/palacios/vmm_config.c
palacios/src/palacios/vmm_ctrl_regs.c
palacios/src/palacios/vmm_emulator.c [new file with mode: 0644]
palacios/src/palacios/vmm_mem.c
palacios/src/palacios/vmm_shadow_paging.c

diff --git a/palacios/include/palacios/vmm_emulator.h b/palacios/include/palacios/vmm_emulator.h
new file mode 100644 (file)
index 0000000..3780d1c
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef __VMM_EMULATOR_H__
+#define __VMM_EMULATOR_H__
+
+#ifdef __V3VEE__
+
+#include <palacios/vmm_list.h>
+#include <palacios/vmm_shadow_paging.h>
+#include <palacios/vmm_paging.h>
+
+
+
+
+
+struct emulated_page {
+  addr_t page_addr;
+  addr_t va;
+  pte32_t pte;
+  struct list_head page_list;
+};
+
+struct saved_page {
+  addr_t va;
+  pte32_t pte;
+  struct list_head page_list;
+};
+
+
+struct write_region {
+  void * write_data;
+  
+  uint_t length;
+  int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data);
+  addr_t write_addr;
+  void * private_data;
+  
+  struct list_head write_list;
+};
+
+
+struct emulation_state {
+  uint_t num_emulated_pages;
+  struct list_head emulated_pages;
+
+  uint_t num_saved_pages;
+  struct list_head saved_pages;
+
+  uint_t num_write_regions;
+  struct list_head write_regions;
+
+  uint_t running : 1;
+  uint_t instr_length;
+};
+
+
+int init_emulator(struct guest_info * info);
+
+
+int v3_emulation_exit_handler(struct guest_info * info);
+
+int v3_emulate_memory_write(struct guest_info * info, addr_t fault_gva,
+                           int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data), 
+                           addr_t write_addr, void * private_data);
+int v3_emulate_memory_read(struct guest_info * info, addr_t fault_gva, 
+                          int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data), 
+                          addr_t read_addr, void * private_data);
+
+
+#endif // !__V3VEE__
+
+#endif
index 779f323..853f851 100644 (file)
@@ -40,6 +40,12 @@ addr_t create_new_shadow_pt32();
 int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
 int handle_shadow_invlpg(struct guest_info * info);
 
+
+
+
+int v3_replace_shdw_page(struct guest_info * info, addr_t location, void * new_page, void* old_page);
+int v3_replace_shdw_page32(struct guest_info * info, addr_t location, pte32_t * new_page, pte32_t * old_page); 
+
 #endif // ! __V3VEE__
 
 #endif
index 8d329f5..13d9b9c 100644 (file)
@@ -4,12 +4,10 @@
 #include <geekos/io.h>
 
 
-#define GENERIC_DEBUG 1
 
-#if GENERIC_DEBUG
-#define GENERIC_DEBUG_PRINT(first, rest...) PrintDebug(first, ##rest) 
-#else
-#define GENERIC_DEBUG_PRINT(first, rest...)
+#ifndef DEBUG_GENERIC
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
 #endif
 
 
@@ -35,7 +33,7 @@ struct generic_internal {
 
 int generic_reset_device(struct vm_device * dev)
 {
-  GENERIC_DEBUG_PRINT("generic: reset device\n");
+  PrintDebug("generic: reset device\n");
  
   return 0;
 
@@ -47,14 +45,14 @@ int generic_reset_device(struct vm_device * dev)
 
 int generic_start_device(struct vm_device *dev)
 {
-  GENERIC_DEBUG_PRINT("generic: start device\n");
+  PrintDebug("generic: start device\n");
   return 0;
 }
 
 
 int generic_stop_device(struct vm_device *dev)
 {
-  GENERIC_DEBUG_PRINT("generic: stop device\n");
+  PrintDebug("generic: stop device\n");
   return 0;
 }
 
@@ -68,13 +66,13 @@ int generic_write_port_passthrough(ushort_t port,
 {
   uint_t i;
 
-  GENERIC_DEBUG_PRINT("generic: writing 0x");
+  PrintDebug("generic: writing 0x");
 
   for (i = 0; i < length; i++) { 
-    GENERIC_DEBUG_PRINT("%x", ((uchar_t*)src)[i]);
+    PrintDebug("%x", ((uchar_t*)src)[i]);
   }
   
-  GENERIC_DEBUG_PRINT(" to port 0x%x ... ", port);
+  PrintDebug(" to port 0x%x ... ", port);
 
   switch (length) {
   case 1:
@@ -92,7 +90,7 @@ int generic_write_port_passthrough(ushort_t port,
     }
   }
 
-  GENERIC_DEBUG_PRINT(" done\n");
+  PrintDebug(" done\n");
   
   return length;
 }
@@ -104,7 +102,7 @@ int generic_read_port_passthrough(ushort_t port,
 {
   uint_t i;
 
-  GENERIC_DEBUG_PRINT("generic: reading 0x%x bytes from port 0x%x ...", length, port);
+  PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
 
   switch (length) {
   case 1:
@@ -122,13 +120,13 @@ int generic_read_port_passthrough(ushort_t port,
     }
   }
 
-  GENERIC_DEBUG_PRINT(" done ... read 0x");
+  PrintDebug(" done ... read 0x");
 
   for (i = 0; i < length; i++) { 
-    GENERIC_DEBUG_PRINT("%x", ((uchar_t*)src)[i]);
+    PrintDebug("%x", ((uchar_t*)src)[i]);
   }
 
-  GENERIC_DEBUG_PRINT("\n");
+  PrintDebug("\n");
 
   return length;
 }
@@ -140,15 +138,15 @@ int generic_write_port_ignore(ushort_t port,
 {
   uint_t i;
 
-  GENERIC_DEBUG_PRINT("generic: writing 0x");
+  PrintDebug("generic: writing 0x");
 
   for (i = 0; i < length; i++) { 
-    GENERIC_DEBUG_PRINT("%x", ((uchar_t*)src)[i]);
+    PrintDebug("%x", ((uchar_t*)src)[i]);
   }
   
-  GENERIC_DEBUG_PRINT(" to port 0x%x ... ", port);
+  PrintDebug(" to port 0x%x ... ", port);
 
-  GENERIC_DEBUG_PRINT(" ignored\n");
+  PrintDebug(" ignored\n");
   
   return length;
 }
@@ -159,10 +157,10 @@ int generic_read_port_ignore(ushort_t port,
                             struct vm_device * dev)
 {
 
-  GENERIC_DEBUG_PRINT("generic: reading 0x%x bytes from port 0x%x ...", length, port);
+  PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
 
   memset((char*)src,0,length);
-  GENERIC_DEBUG_PRINT(" ignored (return zeroed buffer)\n");
+  PrintDebug(" ignored (return zeroed buffer)\n");
 
   return length;
 }
@@ -186,58 +184,58 @@ int generic_init_device(struct vm_device * dev)
   struct generic_internal *state = (struct generic_internal *)(dev->private_data);
   uint_t i, j;
 
-  GENERIC_DEBUG_PRINT("generic: init_device\n");
+  PrintDebug("generic: init_device\n");
 
   // Would read state here
 
   generic_reset_device(dev);
 
   for (i = 0; i < state->num_port_ranges; i++) { 
-    GENERIC_DEBUG_PRINT("generic: hooking ports 0x%x to 0x%x as %x\n", state->port_ranges[i][0], state->port_ranges[i][1], state->port_ranges[i][2]==GENERIC_PRINT_AND_PASSTHROUGH ? "print-and-passthrough" : "print-and-ignore");
+    PrintDebug("generic: hooking ports 0x%x to 0x%x as %x\n", state->port_ranges[i][0], state->port_ranges[i][1], state->port_ranges[i][2]==GENERIC_PRINT_AND_PASSTHROUGH ? "print-and-passthrough" : "print-and-ignore");
 
 #if PORT_HOOKS
     for (j = state->port_ranges[i][0]; j <= state->port_ranges[i][1]; j++) { 
       if (state->port_ranges[i][2]==GENERIC_PRINT_AND_PASSTHROUGH) { 
        if (dev_hook_io(dev, j, &generic_read_port_passthrough, &generic_write_port_passthrough)) { 
-         GENERIC_DEBUG_PRINT("generic: can't hook port 0x%x (already hooked?)\n", j);
+         PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", j);
        }
       } else if (state->port_ranges[i][2]==GENERIC_PRINT_AND_IGNORE) { 
        if (dev_hook_io(dev, j, &generic_read_port_ignore, &generic_write_port_ignore)) { 
-         GENERIC_DEBUG_PRINT("generic: can't hook port 0x%x (already hooked?)\n", j);
+         PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", j);
        }
       } 
     }
 #else
-    GENERIC_DEBUG_PRINT("generic: hooking ports not supported\n");
+    PrintDebug("generic: hooking ports not supported\n");
 #endif
 
   }
 
   for (i = 0; i < state->num_address_ranges; i++) { 
-    GENERIC_DEBUG_PRINT("generic: hooking addresses 0x%x to 0x%x\n",state->address_ranges[i][0],state->address_ranges[i][1]); 
+    PrintDebug("generic: hooking addresses 0x%x to 0x%x\n",state->address_ranges[i][0],state->address_ranges[i][1]); 
 
 #if MEM_HOOKS
     if (dev_hook_mem(dev, state->address_ranges[i][0], state->address_ranges[i][1])) {
-      GENERIC_DEBUG_PRINT("generic: Can't hook addresses 0x%x to 0x%x (already hooked?)\n",
+      PrintDebug("generic: Can't hook addresses 0x%x to 0x%x (already hooked?)\n",
                  state->address_ranges[i][0], state->address_ranges[i][1]); 
     }
 #else
-    GENERIC_DEBUG_PRINT("generic: hooking addresses not supported\n");
+    PrintDebug("generic: hooking addresses not supported\n");
 #endif
 
   }
 
   for (i = 0; i < state->num_irq_ranges; i++) { 
-    GENERIC_DEBUG_PRINT("generic: hooking irqs 0x%x to 0x%x\n",state->irq_ranges[i][0],state->irq_ranges[i][1]);
+    PrintDebug("generic: hooking irqs 0x%x to 0x%x\n",state->irq_ranges[i][0],state->irq_ranges[i][1]);
 
 #if IRQ_HOOKS
     for (j = state->irq_ranges[i][0]; j <= state->irq_ranges[i][1]; j++) { 
       if (dev_hook_irq(dev, j, &generic_interrupt)) { 
-       GENERIC_DEBUG_PRINT("generic: can't hook irq  0x%x (already hooked?)\n", j);
+       PrintDebug("generic: can't hook irq  0x%x (already hooked?)\n", j);
       }
     }
 #else
-    GENERIC_DEBUG_PRINT("generic: hooking irqs not supported\n");
+    PrintDebug("generic: hooking irqs not supported\n");
 #endif
 
   }
@@ -250,48 +248,48 @@ int generic_deinit_device(struct vm_device *dev)
   struct generic_internal *state = (struct generic_internal *)(dev->private_data);
   uint_t i, j;
 
-  GENERIC_DEBUG_PRINT("generic: deinit_device\n");
+  PrintDebug("generic: deinit_device\n");
 
   for (i = 0; i < state->num_irq_ranges; i++) { 
-    GENERIC_DEBUG_PRINT("generic: unhooking irqs 0x%x to 0x%x\n", state->irq_ranges[i][0], state->irq_ranges[i][1]);
+    PrintDebug("generic: unhooking irqs 0x%x to 0x%x\n", state->irq_ranges[i][0], state->irq_ranges[i][1]);
 
 #if IRQ_HOOKS
     for (j = state->irq_ranges[i][0]; j <= state->irq_ranges[i][1]; j++) { 
       if (dev_unhook_irq(dev, j)) {
-       GENERIC_DEBUG_PRINT("generic: can't unhook irq 0x%x (already unhooked?)\n",j);
+       PrintDebug("generic: can't unhook irq 0x%x (already unhooked?)\n",j);
       }
     }
 #else
-    GENERIC_DEBUG_PRINT("generic: unhooking irqs not supported\n");
+    PrintDebug("generic: unhooking irqs not supported\n");
 #endif
 
   }
 
   for (i = 0; i < state->num_address_ranges; i++) { 
-    GENERIC_DEBUG_PRINT("generic: unhooking addresses 0x%x to 0x%x\n",state->address_ranges[i][0],state->address_ranges[i][1]); 
+    PrintDebug("generic: unhooking addresses 0x%x to 0x%x\n",state->address_ranges[i][0],state->address_ranges[i][1]); 
 
 #if MEM_HOOKS
     if (dev_unhook_mem(dev, state->address_ranges[i][0], state->address_ranges[i][1])) {
-      GENERIC_DEBUG_PRINT("generic: Can't unhook addresses 0x%x to 0x%x (already unhooked?)\n",
+      PrintDebug("generic: Can't unhook addresses 0x%x to 0x%x (already unhooked?)\n",
                  state->address_ranges[i][0], state->address_ranges[i][1]); 
     }
 #else
-    GENERIC_DEBUG_PRINT("generic: unhooking addresses not supported\n");
+    PrintDebug("generic: unhooking addresses not supported\n");
 #endif
 
   }
 
   for (i = 0; i < state->num_port_ranges; i++) { 
-    GENERIC_DEBUG_PRINT("generic: unhooking ports 0x%x to 0x%x\n",state->port_ranges[i][0],state->port_ranges[i][1]);
+    PrintDebug("generic: unhooking ports 0x%x to 0x%x\n",state->port_ranges[i][0],state->port_ranges[i][1]);
 
 #if PORT_HOOKS
     for (j = state->port_ranges[i][0]; j <= state->port_ranges[i][1]; j++) { 
       if (dev_unhook_io(dev, j)) {
-       GENERIC_DEBUG_PRINT("generic: can't unhook port 0x%x (already unhooked?)\n", j);
+       PrintDebug("generic: can't unhook port 0x%x (already unhooked?)\n", j);
       }
     }
 #else
-    GENERIC_DEBUG_PRINT("generic: unhooking ports not supported\n");
+    PrintDebug("generic: unhooking ports not supported\n");
 #endif
 
   }
index f1bbf28..6b8629d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Trap handlers
  * Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
- * $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".
@@ -25,7 +25,7 @@
 static void GPF_Handler(struct Interrupt_State* state)
 {
     /* Send the thread to the reaper... */
-  SerialPrintLevel(1000,"Exception %d received, killing thread %p\n",state->intNum, g_currentThread);
+  SerialPrintLevel(1000,"VMM: Exception %d received, killing thread %p\n",state->intNum, g_currentThread);
   Dump_Interrupt_State(state);
   
   Exit(-1);
index a46bc76..70da496 100644 (file)
@@ -164,7 +164,7 @@ void BuzzVM()
 }
 
 
-
+/*
 int passthrough_mem_read(void * guest_addr, void * dst, uint_t length, void * priv_data) {
   memcpy(dst, (void*)guest_addr, length);
   return length;
@@ -174,7 +174,7 @@ int passthrough_mem_write(void * guest_addr, void * src, uint_t length, void * p
   memcpy((void*)guest_addr, src, length);
   return length;
 }
-
+*/
 
 
 /* We need a configuration mechanism, so we can wrap this completely inside the VMM code, 
index 121da9f..9d6fdab 100644 (file)
@@ -68,6 +68,20 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info *vm_info) {
   guest_state->efer |= EFER_MSR_svm_enable;
   guest_state->rflags = 0x00000002; // The reserved bit is always 1
   ctrl_area->svm_instrs.VMRUN = 1;
+  ctrl_area->svm_instrs.VMMCALL = 1;
+  ctrl_area->svm_instrs.VMLOAD = 1;
+  ctrl_area->svm_instrs.VMSAVE = 1;
+  ctrl_area->svm_instrs.STGI = 1;
+  ctrl_area->svm_instrs.CLGI = 1;
+  ctrl_area->svm_instrs.SKINIT = 1;
+  ctrl_area->svm_instrs.RDTSCP = 1;
+  ctrl_area->svm_instrs.ICEBP = 1;
+  ctrl_area->svm_instrs.WBINVD = 1;
+  ctrl_area->svm_instrs.MONITOR = 1;
+  ctrl_area->svm_instrs.MWAIT_always = 1;
+  ctrl_area->svm_instrs.MWAIT_if_armed = 1;
+
+
   ctrl_area->instrs.HLT = 1;
   // guest_state->cr0 = 0x00000001;    // PE 
   ctrl_area->guest_ASID = 1;
index 73f154a..96ab5fb 100644 (file)
@@ -7,7 +7,7 @@
 #include <palacios/svm_halt.h>
 #include <palacios/svm_pause.h>
 #include <palacios/vmm_intr.h>
-
+#include <palacios/vmm_emulator.h>
 
 int handle_svm_exit(struct guest_info * info) {
   vmcb_ctrl_t * guest_ctrl = 0;
@@ -192,6 +192,17 @@ int handle_svm_exit(struct guest_info * info) {
     if (handle_svm_pause(info) == -1) { 
       return -1;
     }
+  } else if (exit_code == VMEXIT_VMMCALL) {
+    PrintDebug("VMMCALL\n");
+    if (info->run_state == VM_EMULATING) {
+      if (v3_emulation_exit_handler(info) == -1) {
+       return -1;
+      }
+    } else {
+      PrintError("VMMCALL with not emulator...\n");
+      return -1;
+    }
+
   } else {
     addr_t rip_addr;
     char buf[15];
index 8e80bfd..1e3e2f3 100644 (file)
 #include <devices/generic.h>
 
 
+static int passthrough_mem_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
+  //  memcpy(dst, (void*)guest_addr, length);
+  int foo = 20;
+
+
+  memcpy(dst, &foo, length);
+
+  PrintDebug("Passthrough mem read returning: %d (length=%d)\n", foo + (guest_addr & 0xfff), length);
+  return length;
+}
+
+static int passthrough_mem_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) {
+  memcpy((void*)guest_addr, src, length);
+  return length;
+}
+
+
 
 int config_guest(struct guest_info * info, void * config_ptr) {
 
@@ -94,11 +111,18 @@ int config_guest(struct guest_info * info, void * config_ptr) {
   }
   
   
-  //add_shadow_region_passthrough(info, 0x100000, 0x2000000, (addr_t)Allocate_VMM_Pages(8192));
-  add_shadow_region_passthrough(info, 0x100000, 0x1000000, (addr_t)V3_AllocPages(4096));
-  
-  add_shadow_region_passthrough(info, 0x1000000, 0x8000000, (addr_t)V3_AllocPages(32768));
-  
+  //  add_shadow_region_passthrough(info, 0x100000, 0x1000000, (addr_t)V3_AllocPages(4096));
+  { 
+    /* MEMORY HOOK TEST */
+    add_shadow_region_passthrough(info, 0x100000, 0xa00000, (addr_t)V3_AllocPages(2304));
+    hook_guest_mem(info, 0xa00000, 0xa01000, passthrough_mem_read, passthrough_mem_write, NULL);
+    
+    add_shadow_region_passthrough(info, 0xa01000, 0x1000000, (addr_t)V3_AllocPages(1791));
+
+  }
+    add_shadow_region_passthrough(info, 0x1000000, 0x8000000, (addr_t)V3_AllocPages(32768));
   // test - give linux accesss to PCI space - PAD
   add_shadow_region_passthrough(info, 0xc0000000,0xffffffff,0xc0000000);
   
@@ -138,7 +162,7 @@ int config_guest(struct guest_info * info, void * config_ptr) {
 #endif
       
 
-#if 1      
+#if 0      
       // Make the Serial ports invisible 
 
       {0x3f8, 0x3f8+7, GENERIC_PRINT_AND_IGNORE},      // COM 1
index 2e566ef..152a7c0 100644 (file)
@@ -45,11 +45,13 @@ int handle_cr0_write(struct guest_info * info) {
     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
   }
 
-  if (ret != 15) {
+  /* The IFetch will already have faulted in the necessary bytes for the full instruction
+    if (ret != 15) {
     // I think we should inject a GPF into the guest
     PrintError("Could not read instruction (ret=%d)\n", ret);
     return -1;
-  }
+    }
+  */
 
   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
     PrintError("Could not decode instruction\n");
@@ -157,11 +159,13 @@ int handle_cr0_read(struct guest_info * info) {
     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
   }
 
-  if (ret != 15) {
-    // I think we should inject a GPF into the guest
-    PrintError("Could not read instruction (ret=%d)\n", ret);
-    return -1;
-  }
+  /* The IFetch will already have faulted in the necessary bytes for the full instruction
+     if (ret != 15) {
+     // I think we should inject a GPF into the guest
+     PrintError("Could not read instruction (ret=%d)\n", ret);
+     return -1;
+     }
+  */
 
   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
     PrintError("Could not decode instruction\n");
@@ -220,11 +224,13 @@ int handle_cr3_write(struct guest_info * info) {
     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
   }
 
-  if (ret != 15) {
-    // I think we should inject a GPF into the guest
-    PrintError("Could not read instruction (ret=%d)\n", ret);
-    return -1;
-  }
+  /* The IFetch will already have faulted in the necessary bytes for the full instruction
+     if (ret != 15) {
+     // I think we should inject a GPF into the guest
+     PrintError("Could not read instruction (ret=%d)\n", ret);
+     return -1;
+     }
+  */
 
   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
     PrintError("Could not decode instruction\n");
@@ -297,11 +303,13 @@ int handle_cr3_read(struct guest_info * info) {
     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
   }
 
-  if (ret != 15) {
-    // I think we should inject a GPF into the guest
-    PrintError("Could not read instruction (ret=%d)\n", ret);
-    return -1;
-  }
+  /* The IFetch will already have faulted in the necessary bytes for the full instruction
+     if (ret != 15) {
+     // I think we should inject a GPF into the guest
+     PrintError("Could not read instruction (ret=%d)\n", ret);
+     return -1;
+     }
+  */
 
   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
     PrintError("Could not decode instruction\n");
diff --git a/palacios/src/palacios/vmm_emulator.c b/palacios/src/palacios/vmm_emulator.c
new file mode 100644 (file)
index 0000000..fcce7c3
--- /dev/null
@@ -0,0 +1,298 @@
+#include <palacios/vmm.h>
+#include <palacios/vmm_emulator.h>
+#include <palacios/vm_guest_mem.h>
+#include <palacios/vmm_decoder.h>
+
+static const char VMMCALL[3] = {0x0f, 0x01, 0xd9};
+
+int init_emulator(struct guest_info * info) {
+  struct emulation_state * emulator = &(info->emulator);
+
+  emulator->num_emulated_pages = 0;
+  INIT_LIST_HEAD(&(emulator->emulated_pages));
+
+
+  emulator->num_saved_pages = 0;
+  INIT_LIST_HEAD(&(emulator->saved_pages));
+  
+  emulator->num_write_regions = 0;
+  INIT_LIST_HEAD(&(emulator->write_regions));
+
+  emulator->running = 0;
+  emulator->instr_length = 0;
+
+  return 0;
+}
+
+static addr_t get_new_page() {
+  void * page = V3_AllocPages(1);
+  memset(page, 0, PAGE_SIZE);
+
+  return (addr_t)page;
+}
+
+
+static int setup_code_page(struct guest_info * info, char * instr, struct basic_instr_info * instr_info ) {
+  addr_t code_page_offset = PT32_PAGE_OFFSET(info->rip);
+  addr_t code_page = get_new_page();
+  struct emulated_page * new_code_page = V3_Malloc(sizeof(struct emulated_page));
+  struct saved_page * saved_code_page = V3_Malloc(sizeof(struct saved_page));
+
+
+  saved_code_page->va = PT32_PAGE_ADDR(info->rip);
+
+  new_code_page->page_addr = code_page; 
+  new_code_page->va = PT32_PAGE_ADDR(info->rip);
+
+  new_code_page->pte.present = 1;
+  new_code_page->pte.writable = 0;
+  new_code_page->pte.user_page = 1;
+  new_code_page->pte.page_base_addr = PT32_BASE_ADDR(code_page);
+
+  memcpy((void *)(code_page + code_page_offset), instr, instr_info->instr_length);
+  memcpy((void *)(code_page + code_page_offset + instr_info->instr_length), VMMCALL, 3);
+
+  PrintDebug("New Instr Stream:\n");
+  PrintTraceMemDump((void *)(code_page + code_page_offset), 32);
+  PrintDebug("rip =%x\n", info->rip);
+
+
+
+
+  v3_replace_shdw_page32(info, new_code_page->va, &(new_code_page->pte), &(saved_code_page->pte));
+
+
+  list_add(&(new_code_page->page_list), &(info->emulator.emulated_pages));
+  info->emulator.num_emulated_pages++;
+
+  list_add(&(saved_code_page->page_list), &(info->emulator.saved_pages));
+  info->emulator.num_saved_pages++;
+
+  return 0;
+}
+
+
+// get the current instr
+// check if rep + remove
+// put into new page, vmexit after
+// replace new page with current eip page
+// 
+int v3_emulate_memory_read(struct guest_info * info, addr_t read_gva, 
+                          int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data), 
+                          addr_t read_gpa, void * private_data) {
+  struct basic_instr_info instr_info;
+  char instr[15];
+  int ret;
+  struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
+  addr_t data_addr_offset = PT32_PAGE_OFFSET(read_gva);
+  pte32_t saved_pte;
+
+  PrintDebug("Emulating Read\n");
+
+  if (info->mem_mode == PHYSICAL_MEM) { 
+    ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+  } else { 
+    ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+  }
+
+  PrintDebug("Instr (15 bytes) at %x:\n", instr);
+  PrintTraceMemDump(instr, 15);
+  
+  if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
+    PrintError("Could not do a basic memory instruction decode\n");
+    V3_Free(data_page);
+    return -1;
+  }
+
+  if (instr_info.has_rep == 1) {
+    PrintError("We currently don't handle rep* instructions\n");
+    V3_Free(data_page);
+    return -1;
+  }
+
+
+  data_page->page_addr = get_new_page();
+  data_page->va = PT32_PAGE_ADDR(read_gva);
+  data_page->pte.present = 1;
+  data_page->pte.writable = 0;
+  data_page->pte.user_page = 1;
+  data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
+
+
+  // Read the data directly onto the emulated page
+  if (read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data) != instr_info.op_size) {
+    PrintError("Read error in emulator\n");
+    V3_FreePage((void *)(data_page->page_addr));
+    V3_Free(data_page);
+    return -1;
+  }
+
+  v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
+
+
+  list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
+  info->emulator.num_emulated_pages++;
+
+  if (saved_pte.present == 1) {
+    struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
+    saved_data_page->pte = saved_pte;
+    saved_data_page->va = PT32_PAGE_ADDR(read_gva);
+
+    list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
+    info->emulator.num_saved_pages++;
+  }
+
+
+  setup_code_page(info, instr, &instr_info);
+
+  info->emulator.running = 1;
+  info->run_state = VM_EMULATING;
+  info->emulator.instr_length = instr_info.instr_length;
+
+  return 0;
+}
+
+
+
+int v3_emulate_memory_write(struct guest_info * info, addr_t write_gva,
+                           int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data), 
+                           addr_t write_gpa, void * private_data) {
+
+  struct basic_instr_info instr_info;
+  char instr[15];
+  int ret;
+  struct write_region * write_op = V3_Malloc(sizeof(struct write_region ));
+  struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
+  addr_t data_addr_offset = PT32_PAGE_OFFSET(write_gva);
+  pte32_t saved_pte;
+
+  PrintDebug("Emulating Write\n");
+
+  if (info->mem_mode == PHYSICAL_MEM) { 
+    ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+  } else { 
+    ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+  }
+  
+  if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
+    PrintError("Could not do a basic memory instruction decode\n");
+    V3_Free(write_op);
+    V3_Free(data_page);
+    return -1;
+  }
+
+  if (instr_info.has_rep == 1) {
+    PrintError("We currently don't handle rep* instructions\n");
+    V3_Free(write_op);
+    V3_Free(data_page);
+    return -1;
+  }
+
+
+  data_page->page_addr = get_new_page();
+  data_page->va = PT32_PAGE_ADDR(write_gva);
+  data_page->pte.present = 1;
+  data_page->pte.writable = 1;
+  data_page->pte.user_page = 1;
+  data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
+
+
+
+  write_op->write = write;
+  write_op->write_addr = write_gpa;
+  write_op->length = instr_info.op_size;
+  write_op->private_data = private_data;
+
+  write_op->write_data = (void *)(data_page->page_addr + data_addr_offset);
+
+  list_add(&(write_op->write_list), &(info->emulator.write_regions));
+  info->emulator.num_write_regions--;
+
+  v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
+
+
+  list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
+  info->emulator.num_emulated_pages++;
+
+  if (saved_pte.present == 1) {
+    struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
+    saved_data_page->pte = saved_pte;
+    saved_data_page->va = PT32_PAGE_ADDR(write_gva);
+
+    list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
+    info->emulator.num_saved_pages++;
+  }
+
+
+  if (info->emulator.running == 0) {
+    setup_code_page(info, instr, &instr_info);
+    info->emulator.running = 1;
+    info->run_state = VM_EMULATING;
+    info->emulator.instr_length = instr_info.instr_length;
+  }
+
+  return 0;
+}
+
+
+// end emulation
+int v3_emulation_exit_handler(struct guest_info * info) {
+  struct saved_page * svpg, * p_svpg;
+  struct emulated_page * empg, * p_empg;
+  struct write_region * wr_reg, * p_wr_reg;
+  pte32_t dummy_pte;
+
+  // Complete the writes
+  // delete writes
+  // swap out emulated pages with blank dummies
+  // swap in saved pages
+  // increment rip
+  
+  PrintDebug("V3 Emulation Exit Handler\n");
+
+  list_for_each_entry_safe(wr_reg, p_wr_reg, &(info->emulator.write_regions), write_list) {
+    wr_reg->write(wr_reg->write_addr, wr_reg->write_data, wr_reg->length, wr_reg->private_data);
+    PrintDebug("Writing \n");
+    
+    list_del(&(wr_reg->write_list));
+    V3_Free(wr_reg);
+
+  }
+  info->emulator.num_write_regions = 0;
+
+
+  *(uint_t *)&dummy_pte = 0;
+  
+  list_for_each_entry_safe(empg, p_empg, &(info->emulator.emulated_pages), page_list) {
+    pte32_t empte32_t;
+
+    PrintDebug("wiping page %x\n", empg->va); 
+
+    v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t);
+    V3_FreePage((void *)(empg->page_addr));
+
+    list_del(&(empg->page_list));
+    V3_Free(empg);
+  }
+  info->emulator.num_emulated_pages = 0;
+
+  list_for_each_entry_safe(svpg, p_svpg, &(info->emulator.saved_pages), page_list) {
+
+    PrintDebug("Setting Saved page %x back\n", svpg->va); 
+    v3_replace_shdw_page32(info, empg->va, &(svpg->pte), &dummy_pte);
+    
+    list_del(&(svpg->page_list));
+    V3_Free(svpg);
+  }
+  info->emulator.num_saved_pages = 0;
+
+  info->run_state = VM_RUNNING;
+  info->emulator.running = 0;
+  //info->rip += info->emulator.instr_length;
+
+  info->emulator.instr_length = 0;
+
+  PrintDebug("returning from emulation\n");
+
+  return 0;
+}
index 7480da7..752ae2b 100644 (file)
@@ -71,37 +71,41 @@ struct vmm_mem_hook * get_mem_hook(struct guest_info * info, addr_t guest_addr)
 
 
 /* mem_addr is the guest physical memory address */
-static int mem_hook_dispatch(struct guest_info * info, addr_t fault_addr, addr_t guest_phys_page,  pf_error_t access_info, struct vmm_mem_hook * hook) {
+static int mem_hook_dispatch(struct guest_info * info, 
+                            addr_t fault_gva, addr_t fault_gpa,  
+                            pf_error_t access_info, struct vmm_mem_hook * hook) 
+{
 
   // emulate and then dispatch 
   // or dispatch and emulate
 
 
   if (access_info.write == 1) {
-    void * src = NULL;
-    uint_t length = 0;
-
-    PrintDebug("Memory hook write\n");
-    return -1;
-
-    if (hook->write(fault_addr, src, length, hook->priv_data) != length) {
+    if (v3_emulate_memory_write(info, fault_gva, hook->write, fault_gpa, hook->priv_data) == -1) {
+      PrintError("Memory write emulation failed\n");
       return -1;
     }
+    
   } else {
-    PrintDebug("Memory hook read\n");
-    return -1;
+    if (v3_emulate_memory_read(info, fault_gva, hook->read, fault_gpa, hook->priv_data) == -1) {
+      PrintError("Memory read emulation failed\n");
+      return -1;
+    }
   }    
 
-  return -1;
+  return 0;
 }
 
 
-int handle_special_page_fault(struct guest_info * info, addr_t fault_addr, addr_t guest_phys_page, pf_error_t access_info) {
-  struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), guest_phys_page);
+int handle_special_page_fault(struct guest_info * info, 
+                             addr_t fault_gva, addr_t fault_gpa, 
+                             pf_error_t access_info) 
+{
+  struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), fault_gpa);
 
   switch (reg->host_type) {
   case HOST_REGION_HOOK:
-    return mem_hook_dispatch(info, fault_addr, guest_phys_page, access_info, (struct vmm_mem_hook *)(reg->host_addr));
+    return mem_hook_dispatch(info, fault_gva, fault_gpa, access_info, (struct vmm_mem_hook *)(reg->host_addr));
   default:
     return -1;
   }
index 9e70bb2..bc5441b 100644 (file)
@@ -17,7 +17,6 @@
 
 
 
-
 static int handle_shadow_pte32_fault(struct guest_info* info, 
                                     addr_t fault_addr, 
                                     pf_error_t error_code,
@@ -37,6 +36,38 @@ int init_shadow_page_state(struct guest_info * info) {
   return 0;
 }
 
+
+
+
+
+
+int v3_replace_shdw_page32(struct guest_info * info, addr_t location, pte32_t * new_page, pte32_t * old_page) {
+  pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32(info->shdw_pg_state.shadow_cr3);
+  pde32_t * shadow_pde =  (pde32_t *)&(shadow_pd[PDE32_INDEX(location)]);
+
+  if (shadow_pde->large_page == 0) {
+    pte32_t * shadow_pt = (pte32_t *)PDE32_T_ADDR((*shadow_pde));
+    pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(location)]);
+
+    //if (shadow_pte->present == 1) {
+    *(uint_t *)old_page = *(uint_t *)shadow_pte;
+    //}
+
+    *(uint_t *)shadow_pte = *(uint_t *)new_page;
+
+  } else {
+    // currently unhandled
+    return -1;
+  }
+  
+  return 0;
+}
+
+
+
+
+
+
 int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
   
   if (info->mem_mode == PHYSICAL_MEM) {
@@ -164,7 +195,7 @@ static int handle_large_pagefault32(struct guest_info * info,
       
     } else {
       // Handle hooked pages as well as other special pages
-      if (handle_special_page_fault(info, fault_addr, PT32_PAGE_ADDR(guest_fault_pa), error_code) == -1) {
+      if (handle_special_page_fault(info, fault_addr, guest_fault_pa, error_code) == -1) {
        PrintError("Special Page Fault handler returned error for address: %x\n", fault_addr);
        return -1;
       }
@@ -361,7 +392,7 @@ static int handle_shadow_pte32_fault(struct guest_info * info,
 
   if (shadow_pte_access == PT_ENTRY_NOT_PRESENT) {
 
-    addr_t guest_pa = PTE32_T_ADDR((*guest_pte));
+    addr_t guest_pa = PTE32_T_ADDR((*guest_pte)) +  PT32_PAGE_OFFSET(fault_addr);
 
     // Page Table Entry Not Present