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.


code clean up
[palacios.git] / palacios / src / palacios / vmm_shadow_paging.c
index eeb4fda..0097853 100644 (file)
@@ -5,9 +5,26 @@
 #include <palacios/vm_guest_mem.h>
 #include <palacios/vmm_decoder.h>
 
+#ifndef DEBUG_SHADOW_PAGING
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
+#endif
 
 
-int init_shadow_page_state(struct shadow_page_state * state) {
+
+
+
+
+static int handle_shadow_pte32_fault(struct guest_info* info, 
+                                    addr_t fault_addr, 
+                                    pf_error_t error_code,
+                                    pte32_t * shadow_pte, 
+                                    pte32_t * guest_pte);
+
+static int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
+
+int init_shadow_page_state(struct guest_info * info) {
+  struct shadow_page_state * state = &(info->shdw_pg_state);
   state->guest_mode = PDE32;
   state->shadow_mode = PDE32;
   
@@ -30,14 +47,12 @@ int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_erro
       break;
     case PROTECTED_PAE:
     case LONG:
-      // currently not handled
-      return -1;
-      break;
     default:
+      PrintError("Unhandled CPU Mode\n");
       return -1;
     }
   } else {
-    PrintDebug("Invalid Memory mode\n");
+    PrintError("Invalid Memory mode\n");
     return -1;
   }
 }
@@ -45,7 +60,7 @@ int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_erro
 addr_t create_new_shadow_pt32(struct guest_info * info) {
   void * host_pde = 0;
 
-  V3_AllocPages(host_pde, 1);
+  host_pde = V3_AllocPages(1);
   memset(host_pde, 0, PAGE_SIZE);
 
   return (addr_t)host_pde;
@@ -65,7 +80,7 @@ static int handle_pd32_nonaligned_4MB_page(struct guest_info * info, pte32_t * p
 
     if (host_page_type == HOST_REGION_INVALID) {
       // Currently we don't support this, but in theory we could
-      PrintDebug("Invalid Host Memory Type\n");
+      PrintError("Invalid Host Memory Type\n");
       return -1;
     } else if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
       addr_t shadow_pa = get_shadow_addr(info, guest_pa);
@@ -80,14 +95,14 @@ static int handle_pd32_nonaligned_4MB_page(struct guest_info * info, pte32_t * p
       pte_cursor->global_page = 0;
 
     } else {
-      PrintDebug("Unsupported Host Memory Type\n");
+      PrintError("Unsupported Host Memory Type\n");
       return -1;
     }
   }
   return 0;
 }
 
-int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
+static int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
   pde32_t * guest_pd = NULL;
   pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32(info->shdw_pg_state.shadow_cr3);
   addr_t guest_cr3 = CR3_TO_PDE32(info->shdw_pg_state.guest_cr3);
@@ -97,7 +112,7 @@ int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_er
   pde32_t * shadow_pde = (pde32_t *)&(shadow_pd[PDE32_INDEX(fault_addr)]);
 
   if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
-    PrintDebug("Invalid Guest PDE Address: 0x%x\n", guest_cr3);
+    PrintError("Invalid Guest PDE Address: 0x%x\n", guest_cr3);
     return -1;
   }
 
@@ -116,27 +131,34 @@ int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_er
      the reason for the fault was that the page is not present in the shadow, 
      _THEN_ we have to map the shadow page in and reexecute, this will generate 
      a permissions fault which is _THEN_ valid to send to the guest
+     _UNLESS_ both the guest and shadow have marked the page as not present
 
      whew...
   */
   if ((guest_pde_access != PT_ACCESS_OK) &&
-      ( (shadow_pde_access != PT_ENTRY_NOT_PRESENT) &&
-       (guest_pde_access != PT_ENTRY_NOT_PRESENT))) { // aka (guest permission error)
+      (
+       ( (shadow_pde_access != PT_ENTRY_NOT_PRESENT) &&
+        (guest_pde_access != PT_ENTRY_NOT_PRESENT))  // aka (guest permission error)
+       || 
+       ( (shadow_pde_access == PT_ENTRY_NOT_PRESENT) && 
+       (guest_pde_access == PT_ENTRY_NOT_PRESENT)))) {
     // inject page fault to the guest (Guest PDE fault)
 
        info->ctrl_regs.cr2 = fault_addr;
-    raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
+    v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
 
 
     PrintDebug("Injecting PDE pf to guest: (guest access error=%d) (pf error code=%d)\n", guest_pde_access, error_code);
     return 0;
 
-    PrintDebug("Guest CR3=%x\n", guest_cr3);
-    PrintDebug("Guest PD\n");
-    PrintPD32(guest_pd);
-    PrintDebug("Shadow PD\n");
-    PrintPD32(shadow_pd);
-
+#ifdef DEBUG_SHADOW_PAGING
+       PrintDebug("Guest CR3=%x\n", guest_cr3);
+       PrintDebug("Guest PD\n");
+       PrintPD32(guest_pd);
+       PrintDebug("Shadow PD\n");
+       PrintPD32(shadow_pd);
+#endif
 
     return -1;
   }
@@ -163,7 +185,7 @@ int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_er
     if (guest_pde->large_page == 0) {
       pte32_t * shadow_pt = NULL;
       
-      V3_AllocPages(shadow_pt, 1);
+      shadow_pt = V3_AllocPages(1);
       memset(shadow_pt, 0, PAGE_SIZE);
       
       shadow_pde->pt_base_addr = PD32_BASE_ADDR(shadow_pt);
@@ -186,8 +208,8 @@ int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_er
 
       if (host_page_type == HOST_REGION_INVALID) {
 
-       raise_exception(info, MC_EXCEPTION);
-       PrintDebug("Invalid guest address in large page (0x%x)\n", guest_start_addr);
+       v3_raise_exception(info, MC_EXCEPTION);
+       PrintError("Invalid guest address in large page (0x%x)\n", guest_start_addr);
        return -1;
       } else if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
        addr_t host_start_addr = 0;
@@ -229,20 +251,20 @@ int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_er
 
          shadow_pde->large_page = 0;
       
-         V3_AllocPages(shadow_pt, 1);
+         shadow_pt = V3_AllocPages(1);
          memset(shadow_pt, 0, PAGE_SIZE);
 
          if (handle_pd32_nonaligned_4MB_page(info, shadow_pt, guest_start_addr, large_shadow_pde) == -1) {
-           PrintDebug("Non Aligned Large Page Error\n");
+           PrintError("Non Aligned Large Page Error\n");
            V3_Free(shadow_pt);
            return -1;
          }
 
 
-         /*
+#ifdef DEBUG_SHADOW_PAGING
            PrintDebug("non-aligned Shadow PT\n");
            PrintPT32(PT32_PAGE_ADDR(fault_addr), shadow_pt);     
-         */
+#endif
          shadow_pde->pt_base_addr = PD32_BASE_ADDR(shadow_pt);
        }
 
@@ -250,7 +272,7 @@ int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_er
       } else {
        // Handle hooked pages as well as other special pages
        if (handle_special_page_fault(info, fault_addr, error_code) == -1) {
-         PrintDebug("Special Page Fault handler returned error for address: %x\n", fault_addr);
+         PrintError("Special Page Fault handler returned error for address: %x\n", fault_addr);
          return -1;
        }
       }
@@ -274,8 +296,11 @@ int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_er
     // Page Directory Entry marked non-user
     //
     
-    PrintDebug("Shadow Paging User access error\n");
-    return -1;
+    PrintDebug("Shadow Paging User access error (shadow_pde_access=0x%x, guest_pde_access=0x%x - injecting into guest\n", shadow_pde_access, guest_pde_access);
+    info->ctrl_regs.cr2 = fault_addr;
+    v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
+    return 0;
+
   } else if (shadow_pde_access == PT_ACCESS_OK) {
     pte32_t * shadow_pt = (pte32_t *)PDE32_T_ADDR((*shadow_pde));
     pte32_t * guest_pt = NULL;
@@ -286,27 +311,30 @@ int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_er
       PrintDebug("Invalid Guest PTE Address: 0x%x\n", PDE32_T_ADDR((*guest_pde)));
       // Machine check the guest
 
-      raise_exception(info, MC_EXCEPTION);
+      v3_raise_exception(info, MC_EXCEPTION);
       
       return 0;
     }
 
 
     if (handle_shadow_pte32_fault(info, fault_addr, error_code, shadow_pt, guest_pt)  == -1) {
-      PrintDebug("Error handling Page fault caused by PTE\n");
+      PrintError("Error handling Page fault caused by PTE\n");
       return -1;
     }
 
  } else {
     // Unknown error raise page fault in guest
     info->ctrl_regs.cr2 = fault_addr;
-    raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
+    v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
 
     // For debugging we will return an error here for the time being, 
     // this probably shouldn't ever happen
     PrintDebug("Unknown Error occurred\n");
     PrintDebug("Manual Says to inject page fault into guest\n");
-    return -1;
+
+
+    return 0;
+
   }
 
   //PrintDebugPageTables(shadow_pd);
@@ -319,7 +347,7 @@ int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_er
 /* 
  * We assume the the guest pte pointer has already been translated to a host virtual address
  */
-int handle_shadow_pte32_fault(struct guest_info * info, 
+static int handle_shadow_pte32_fault(struct guest_info * info, 
                              addr_t fault_addr, 
                              pf_error_t error_code,
                              pte32_t * shadow_pt, 
@@ -337,24 +365,36 @@ int handle_shadow_pte32_fault(struct guest_info * info,
   // Check the shadow page permissions
   shadow_pte_access = can_access_pte32(shadow_pt, fault_addr, error_code);
   
+#ifdef DEBUG_SHADOW_PAGING
+  PrintDebug("Guest PTE: (access=%d)\n\t", guest_pte_access);
+  PrintPTE32(fault_addr, guest_pte);
+  PrintDebug("Shadow PTE: (access=%d)\n\t", shadow_pte_access);
+  PrintPTE32(fault_addr, shadow_pte);
+#endif
+  
   /* This should be redone, 
      but basically the reasoning is that there can be multiple reasons for a page fault:
      If there is a permissions failure for a page present in the guest _BUT_ 
      the reason for the fault was that the page is not present in the shadow, 
      _THEN_ we have to map the shadow page in and reexecute, this will generate 
      a permissions fault which is _THEN_ valid to send to the guest
+     _UNLESS_ both the guest and shadow have marked the page as not present
 
      whew...
   */
   if ((guest_pte_access != PT_ACCESS_OK) && 
-      ((shadow_pte_access != PT_ENTRY_NOT_PRESENT) &&
-       (guest_pte_access != PT_ENTRY_NOT_PRESENT))) { // aka (guest permission error)
+      ( 
+       ((shadow_pte_access != PT_ENTRY_NOT_PRESENT) &&
+       (guest_pte_access != PT_ENTRY_NOT_PRESENT)) // aka (guest permission error)
+       ||
+       ((shadow_pte_access == PT_ENTRY_NOT_PRESENT) &&
+       (guest_pte_access == PT_ENTRY_NOT_PRESENT)))) {
     // Inject page fault into the guest        
     
     info->ctrl_regs.cr2 = fault_addr;
-    raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
+    v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
     
-    PrintDebug("Access error injecting pf to guest (guest access error=%d) (pf error code=%d)\n", guest_pte_access, error_code);
+    PrintDebug("Access error injecting pf to guest (guest access error=%d) (pf error code=%d)\n", guest_pte_access, *(uint_t*)&error_code);
     return 0; 
   }
   
@@ -377,13 +417,14 @@ int handle_shadow_pte32_fault(struct guest_info * info,
     if (host_page_type == HOST_REGION_INVALID) {
       // Inject a machine check in the guest
 
-      raise_exception(info, MC_EXCEPTION);
-
+      v3_raise_exception(info, MC_EXCEPTION);
+#ifdef DEBUG_SHADOW_PAGING
       PrintDebug("Invalid Guest Address in page table (0x%x)\n", guest_pa);
       PrintDebug("fault_addr=0x%x next are guest and shadow ptes \n",fault_addr);
       PrintPTE32(fault_addr,guest_pte);
       PrintPTE32(fault_addr,shadow_pte);
       PrintDebug("Done.\n");
+#endif
       return 0;
 
     } else if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
@@ -414,7 +455,7 @@ int handle_shadow_pte32_fault(struct guest_info * info,
     } else {
       // Page fault handled by hook functions
       if (handle_special_page_fault(info, fault_addr, error_code) == -1) {
-       PrintDebug("Special Page fault handler returned error for address: %x\n", fault_addr);
+       PrintError("Special Page fault handler returned error for address: %x\n", fault_addr);
        return -1;
       }
     }
@@ -431,10 +472,10 @@ int handle_shadow_pte32_fault(struct guest_info * info,
     // Inject page fault into the guest        
        
     info->ctrl_regs.cr2 = fault_addr;
-    raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
+    v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
 
-    PrintDebug("PTE Page fault fell through... Not sure if this should ever happen\n");
-    PrintDebug("Manual Says to inject page fault into guest\n");
+    PrintError("PTE Page fault fell through... Not sure if this should ever happen\n");
+    PrintError("Manual Says to inject page fault into guest\n");
     return -1;
   }
 
@@ -452,7 +493,7 @@ int handle_shadow_invlpg(struct guest_info * info) {
   if (info->mem_mode != VIRTUAL_MEM) {
     // Paging must be turned on...
     // should handle with some sort of fault I think
-    PrintDebug("ERROR: INVLPG called in non paged mode\n");
+    PrintError("ERROR: INVLPG called in non paged mode\n");
     return -1;
   }
 
@@ -464,7 +505,7 @@ int handle_shadow_invlpg(struct guest_info * info) {
 
     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
     if (ret != 15) {
-      PrintDebug("Could not read instruction 0x%x (ret=%d)\n", info->rip, ret);
+      PrintError("Could not read instruction 0x%x (ret=%d)\n", info->rip, ret);
       return -1;
     }
 
@@ -486,7 +527,7 @@ int handle_shadow_invlpg(struct guest_info * info) {
       pde32_t * guest_pd = NULL;
 
       if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
-       PrintDebug("Invalid Guest PDE Address: 0x%x\n", guest_cr3);
+       PrintError("Invalid Guest PDE Address: 0x%x\n", guest_cr3);
        return -1;
       }
 
@@ -517,8 +558,12 @@ int handle_shadow_invlpg(struct guest_info * info) {
          if (shadow_pde->present == 1) {
            pte32_t * shadow_pt = (pte32_t *)PDE32_T_ADDR((*shadow_pde));
            pte32_t * shadow_pte = (pte32_t *)&shadow_pt[PTE32_INDEX(first_operand)];
+
+#ifdef DEBUG_SHADOW_PAGING
            PrintDebug("Setting not present\n");
            PrintPTE32(first_operand, shadow_pte);
+#endif
+
            shadow_pte->present = 0;
          }
        }
@@ -526,11 +571,11 @@ int handle_shadow_invlpg(struct guest_info * info) {
        info->rip += index;
 
       } else {
-       PrintDebug("Invalid Operand type\n");
+       PrintError("Invalid Operand type\n");
        return -1;
       }
     } else {
-      PrintDebug("invalid Instruction Opcode\n");
+      PrintError("invalid Instruction Opcode\n");
       PrintTraceMemDump(instr, 15);
       return -1;
     }
@@ -540,83 +585,3 @@ int handle_shadow_invlpg(struct guest_info * info) {
 }
 
 
-
-/* Deprecated */
-/*
-addr_t setup_shadow_pt32(struct guest_info * info, addr_t virt_cr3) {
-  addr_t cr3_guest_addr = CR3_TO_PDE32(virt_cr3);
-  pde32_t * guest_pde;
-  pde32_t * host_pde = NULL;
-  int i;
-  
-  // Setup up guest_pde to point to the PageDir in host addr
-  if (guest_pa_to_host_va(info, cr3_guest_addr, (addr_t*)&guest_pde) == -1) {
-    return 0;
-  }
-  
-  V3_AllocPages(host_pde, 1);
-  memset(host_pde, 0, PAGE_SIZE);
-
-  for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
-    if (guest_pde[i].present == 1) {
-      addr_t pt_host_addr;
-      addr_t host_pte;
-
-      if (guest_pa_to_host_va(info, PDE32_T_ADDR(guest_pde[i]), &pt_host_addr) == -1) {
-       return 0;
-      }
-
-      if ((host_pte = setup_shadow_pte32(info, pt_host_addr)) == 0) {
-       return 0;
-      }
-
-      host_pde[i].present = 1;
-      host_pde[i].pt_base_addr = PD32_BASE_ADDR(host_pte);
-
-      //
-      // Set Page DIR flags
-      //
-    }
-  }
-
-  PrintDebugPageTables(host_pde);
-
-  return (addr_t)host_pde;
-}
-
-
-
-addr_t setup_shadow_pte32(struct guest_info * info, addr_t pt_host_addr) {
-  pte32_t * guest_pte = (pte32_t *)pt_host_addr;
-  pte32_t * host_pte = NULL;
-  int i;
-
-  V3_AllocPages(host_pte, 1);
-  memset(host_pte, 0, PAGE_SIZE);
-
-  for (i = 0; i < MAX_PTE32_ENTRIES; i++) {
-    if (guest_pte[i].present == 1) {
-      addr_t guest_pa = PTE32_T_ADDR(guest_pte[i]);
-      shadow_mem_type_t page_type;
-      addr_t host_pa = 0;
-
-      page_type = get_shadow_addr_type(info, guest_pa);
-
-      if (page_type == HOST_REGION_PHYSICAL_MEMORY) {
-       host_pa = get_shadow_addr(info, guest_pa);
-      } else {
-       
-       //
-       // Setup various memory types
-       //
-      }
-
-      host_pte[i].page_base_addr = PT32_BASE_ADDR(host_pa);
-      host_pte[i].present = 1;
-    }
-  }
-
-  return (addr_t)host_pte;
-}
-
-*/