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.


moving along...
Jack Lange [Thu, 3 Apr 2008 07:15:47 +0000 (07:15 +0000)]
more complicated guest kernel that jumps to protected mode and then executes an out instruction....

palacios/build/vm_kernel
palacios/include/geekos/svm_ctrl_regs.h
palacios/include/geekos/vmm_emulate.h
palacios/src/geekos/main.c
palacios/src/geekos/svm_ctrl_regs.c

index cba609a..e6c7836 100755 (executable)
Binary files a/palacios/build/vm_kernel and b/palacios/build/vm_kernel differ
index 44f6b7a..2ca33d3 100644 (file)
@@ -20,7 +20,10 @@ static const uchar_t mov_from_cr_byte = 0x20;
 
 
 int handle_cr0_write(struct guest_info * info);
+int handle_cr0_read(struct guest_info * info);
 
+int handle_cr3_write(struct guest_info * info);
+int handle_cr3_read(struct guest_info * info);
 
 
 
index 6a6c144..5c0c9c5 100644 (file)
@@ -191,19 +191,23 @@ static inline addr_t decode_register(struct guest_gprs * gprs, char reg_code, re
 
 
 
-static inline operand_type_t decode_operands16(struct guest_gprs * gprs, 
-                                              char * modrm_instr, 
-                                              addr_t * first_operand,
-                                              addr_t * second_operand, 
-                                              reg_size_t reg_size) {
+static inline operand_type_t decode_operands16(struct guest_gprs * gprs, // input/output
+                                              char * modrm_instr,       // input
+                                              int * offset,             // output
+                                              addr_t * first_operand,   // output
+                                              addr_t * second_operand,  // output
+                                              reg_size_t reg_size) {    // input
   
   struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr;
   addr_t base_addr = 0;
   modrm_mode_t mod_mode = 0;
   operand_type_t addr_type = INVALID_OPERAND;
+  char * instr_cursor = modrm_instr;
 
   PrintDebug("ModRM mod=%d\n", modrm->mod);
 
+  instr_cursor += 1;
+
   if (modrm->mod == 3) {
     mod_mode = REG;
     addr_type = REG_OPERAND;
@@ -255,15 +259,20 @@ static inline operand_type_t decode_operands16(struct guest_gprs * gprs,
       break;
     }
 
+
+
     if (mod_mode == DISP8) {
-      base_addr += (uchar_t)*(modrm_instr + 1);
+      base_addr += (uchar_t)*(instr_cursor);
+      instr_cursor += 1;
     } else if (mod_mode == DISP16) {
-      base_addr += (ushort_t)*(modrm_instr + 1);
+      base_addr += (ushort_t)*(instr_cursor);
+      instr_cursor += 2;
     }
     
     *first_operand = base_addr;
   }
 
+  *offset +=  (instr_cursor - modrm_instr);
   *second_operand = decode_register(gprs, modrm->reg, reg_size);
 
   return addr_type;
@@ -271,12 +280,13 @@ static inline operand_type_t decode_operands16(struct guest_gprs * gprs,
 
 
 
-static inline operand_type_t decode_operands32(struct guest_gprs * gprs, 
-                                   char * modrm_instr,
-                                   addr_t * first_operand,
-                                   addr_t * second_operand, 
-                                   reg_size_t reg_size) {
-
+static inline operand_type_t decode_operands32(struct guest_gprs * gprs, // input/output
+                                              char * modrm_instr,       // input
+                                              int * offset,             // output
+                                              addr_t * first_operand,   // output
+                                              addr_t * second_operand,  // output
+                                              reg_size_t reg_size) {    // input
+  
   char * instr_cursor = modrm_instr;
   struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr;
   addr_t base_addr = 0;
@@ -284,6 +294,10 @@ static inline operand_type_t decode_operands32(struct guest_gprs * gprs,
   uint_t has_sib_byte = 0;
   operand_type_t addr_type = INVALID_OPERAND;
 
+
+
+  instr_cursor += 1;
+
   if (modrm->mod == 3) {
     mod_mode = REG;
     addr_type = REG_OPERAND;
@@ -341,6 +355,8 @@ static inline operand_type_t decode_operands32(struct guest_gprs * gprs,
       struct sib_byte * sib = (struct sib_byte *)(instr_cursor);
       int scale = 1;
 
+      instr_cursor += 1;
+
 
       if (sib->scale == 1) {
        scale = 2;
@@ -412,18 +428,21 @@ static inline operand_type_t decode_operands32(struct guest_gprs * gprs,
 
     } 
 
-    instr_cursor += 1;
 
     if (mod_mode == DISP8) {
       base_addr += (uchar_t)*(instr_cursor);
+      instr_cursor += 1;
     } else if (mod_mode == DISP32) {
       base_addr += (uint_t)*(instr_cursor);
+      instr_cursor += 4;
     }
     
 
     *first_operand = base_addr;
   }
 
+  *offset += (instr_cursor - modrm_instr);
+
   *second_operand = decode_register(gprs, modrm->reg, reg_size);
 
   return addr_type;
index 85019d5..19933a5 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.27 $
+ * $Revision: 1.28 $
  * 
  * This is free software.  You are permitted to use,
  * redistribute, and modify it as specified in the file "COPYING".
@@ -342,6 +342,8 @@ 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);
+      
       /*
       vm_info.cr0 = 0;
       vm_info.cs.base=0xf000;
index 1ae1ccf..084becb 100644 (file)
@@ -19,7 +19,7 @@ int handle_cr0_write(struct guest_info * info) {
 
     // 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);
-    if (ret != 0) {
+    if (ret != 15) {
       // I think we should inject a GPF into the guest
       PrintDebug("Could not read instruction (ret=%d)\n", ret);
       return -1;
@@ -37,26 +37,42 @@ int handle_cr0_write(struct guest_info * info) {
       addr_t second_operand;
       struct cr0_real *old_cr0;
       struct cr0_real *new_cr0;
-     
+      operand_type_t addr_type;
+      char new_cr0_val = 0;
       // LMSW
       // decode mod/RM
       index += 2;
  
       old_cr0 = (struct cr0_real*)&(guest_state->cr0);
 
-      if (decode_operands16(&(info->vm_regs), instr + index, &first_operand, &second_operand, REG16) != 0) {
+
+      addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG16);
+
+
+      if (addr_type == REG_OPERAND) {
+       new_cr0 = (struct cr0_real *)first_operand;
+      } else if (addr_type == MEM_OPERAND) {
+       addr_t host_addr;
+
+       if (guest_pa_to_host_va(info, first_operand, &host_addr) == -1) {
+         // gpf the guest
+         return -1;
+       }
+
+       new_cr0 = (struct cr0_real *)host_addr;
+      } else {
        // error... don't know what to do
        return -1;
       }
-      
-      index += 3;
-
-      new_cr0 = (struct cr0_real *)first_operand;
-
+                
       if ((new_cr0->pe == 1) && (old_cr0->pe == 0)) {
        info->cpu_mode = PROTECTED;
+      } else if ((new_cr0->pe == 0) && (old_cr0->pe == 1)) {
+       info->cpu_mode = REAL;
       }
       
+      new_cr0_val = *(char*)(new_cr0) & 0x0f;
+
 
       if (info->page_mode == SHADOW_PAGING) {
        struct cr0_real * virt_cr0 = (struct cr0_real*)&(info->shdw_pg_state.guest_cr0);
@@ -64,11 +80,15 @@ int handle_cr0_write(struct guest_info * info) {
        /* struct cr0_real is only 4 bits wide, 
         * so we can overwrite the old_cr0 without worrying about the shadow fields
         */
-       *old_cr0 = *new_cr0;
-       *virt_cr0 = *new_cr0;
+       *(char*)old_cr0 &= 0xf0;
+       *(char*)old_cr0 |= new_cr0_val;
+       
+       *(char*)virt_cr0 &= 0xf0;
+       *(char*)virt_cr0 |= new_cr0_val;
       } else {
        // for now we just pass through....
-       *old_cr0 = *new_cr0;
+       *(char*)old_cr0 &= 0xf0;
+       *(char*)old_cr0 |= new_cr0_val;
       }
 
       PrintDebug("index = %d, rip = %x\n", index, (ulong_t)(info->rip));
@@ -84,8 +104,75 @@ int handle_cr0_write(struct guest_info * info) {
 
 
   } else if (info->cpu_mode == PROTECTED) {
+    int index = 0;
+    int ret;
+
     PrintDebug("Protected Mode write to CR0\n");
-    while(1);
+
+    // 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);
+    if (ret != 0) {
+      // 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++; 
+    }
+
+    if ((instr[index] == cr_access_byte) && 
+       (instr[index + 1] == mov_to_cr_byte)) {
+    
+      addr_t first_operand;
+      addr_t second_operand;
+      struct cr0_32 *old_cr0;
+      struct cr0_32 *new_cr0;
+      operand_type_t addr_type;
+
+      index += 2;
+      old_cr0 = (struct cr0_32*)&(guest_state->cr0);
+
+      addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
+
+
+      if (addr_type == REG_OPERAND) {
+       new_cr0 = (struct cr0_32 *)first_operand;
+      } else if (addr_type == MEM_OPERAND) {
+       addr_t host_addr;
+
+       if (guest_pa_to_host_va(info, first_operand, &host_addr) == -1) {
+         // gpf the guest
+         return -1;
+       }
+
+       new_cr0 = (struct cr0_32 *)host_addr;
+      } else {
+       // error... don't know what to do
+       return -1;
+      }
+
+
+      if (info->page_mode == SHADOW_PAGING) {
+       struct cr0_32 * virt_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
+
+       if ((new_cr0->pg == 1) && (virt_cr0->pg == 0)){
+         info->cpu_mode = PROTECTED_PG;
+
+         // Activate Shadow Paging
+       }
+
+       *virt_cr0 = *new_cr0;
+       *old_cr0 = *new_cr0;
+      } else {
+       // fill in
+      }
+
+      info->rip += index;
+
+    }
+    
   } else {
     PrintDebug("Unknown Mode write to CR0\n");
     while(1);
@@ -94,3 +181,70 @@ int handle_cr0_write(struct guest_info * info) {
 }
 
 
+int handle_cr0_read(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));
+  char instr[15];
+
+  if (info->cpu_mode == REAL) {
+    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, 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++; 
+    }
+
+    if ((instr[index] == cr_access_byte) && 
+       (instr[index + 1] == smsw_byte) && 
+       (MODRM_REG(instr[index + 2]) == smsw_reg_byte)) {
+
+      addr_t first_operand;
+      addr_t second_operand;
+      struct cr0_real *cr0;
+      operand_type_t addr_type;
+      char cr0_val = 0;
+
+      index += 2;
+      
+      cr0 = (struct cr0_real*)&(guest_state->cr0);
+      
+      
+      addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG16);
+      
+      if (addr_type == MEM_OPERAND) {
+       addr_t host_addr;
+       
+       if (guest_pa_to_host_va(info, first_operand, &host_addr) == -1) {
+         // gpf the guest
+         return -1;
+       }
+       
+       first_operand = host_addr;
+      } else {
+       // error... don't know what to do
+       return -1;
+      }
+
+      cr0_val = *(char*)cr0 & 0x0f;
+
+
+      *(char *)first_operand &= 0xf0;
+      *(char *)first_operand |= cr0_val;
+
+      info->rip += index;
+
+    }
+
+  }
+
+
+  return 0;
+}