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.


more shadow paging changes
Jack Lange [Tue, 13 May 2008 21:39:40 +0000 (21:39 +0000)]
palacios/build/rombios
palacios/build/vm_kernel
palacios/include/palacios/vmm.h
palacios/include/palacios/vmm_paging.h
palacios/include/palacios/vmm_shadow_paging.h
palacios/src/palacios/vm_guest_mem.c
palacios/src/palacios/vmm_paging.c
palacios/src/palacios/vmm_shadow_paging.c

index 4170a27..8f8992b 100644 (file)
Binary files a/palacios/build/rombios and b/palacios/build/rombios differ
index 1931d93..b5e8488 100755 (executable)
Binary files a/palacios/build/vm_kernel and b/palacios/build/vm_kernel differ
index 92597ff..01d4d35 100644 (file)
@@ -46,6 +46,7 @@
 #define V3_AllocPages(ptr, num_pages)                  \
   do {                                                 \
     extern struct vmm_os_hooks * os_hooks;             \
+    ptr = 0;                                           \
     if ((os_hooks) && (os_hooks)->allocate_pages) {    \
       ptr = (os_hooks)->allocate_pages(num_pages);     \
     }                                                  \
@@ -56,6 +57,7 @@
 #define V3_Malloc(type, var, size)                     \
   do {                                                 \
     extern struct vmm_os_hooks * os_hooks;             \
+    var = 0;                                           \
     if ((os_hooks) && (os_hooks)->malloc) {            \
       var = (type)(os_hooks)->malloc(size);            \
     }                                                  \
index edc1d6f..5cbdbd3 100644 (file)
@@ -115,32 +115,51 @@ the host state in the vmcs before entering the guest.
 #define PDE32_T_ADDR(x) ((x.pt_base_addr) << 12)
 #define PTE32_T_ADDR(x) ((x.page_base_addr) << 12)
 
-#define VM_WRITE     1
-#define VM_USER      2
-#define VM_NOCACHE   8
-#define VM_READ      0
-#define VM_EXEC      0
-
 
 #endif
 
 /* PDE 32 bit PAGE STRUCTURES */
-typedef enum {NOT_PRESENT, PTE32, LARGE_PAGE} pde32_entry_type_t;
+typedef enum {PDE32_ENTRY_NOT_PRESENT, PDE32_ENTRY_PTE32, PDE32_ENTRY_LARGE_PAGE} pde32_entry_type_t;
+typedef enum {PT_ACCESS_OK, PT_ENTRY_NOT_PRESENT, PT_WRITE_ERROR, PT_USER_ERROR} pt_access_status_t;
 
 typedef struct pde32 {
   uint_t present         : 1;
-  uint_t flags           : 4;
+  uint_t writable        : 1;
+  uint_t user_page       : 1;
+  uint_t write_through   : 1;
+  uint_t cache_disable   : 1;
   uint_t accessed        : 1;
   uint_t reserved        : 1;
-  uint_t large_pages     : 1;
+  uint_t large_page     : 1;
   uint_t global_page     : 1;
   uint_t vmm_info        : 3;
   uint_t pt_base_addr    : 20;
 } pde32_t;
 
+typedef struct pde32_4MB {
+  uint_t present         : 1;
+  uint_t writable        : 1;
+  uint_t user_page       : 1;
+  uint_t write_through   : 1;
+  uint_t cache_disable   : 1;
+  uint_t accessed        : 1;
+  uint_t dirty           : 1;
+  uint_t one             : 1;
+  uint_t global_page     : 1;
+  uint_t vmm_info        : 3;
+  uint_t pat             : 1;
+  uint_t page_base_addr_lo: 8;
+  uint_t zero            : 1;
+  uint_t page_base_addr_hi: 10;
+
+} pde32_4MB_t;
+
 typedef struct pte32 {
   uint_t present         : 1;
-  uint_t flags           : 4;
+  uint_t writable        : 1;
+  uint_t user_page       : 1;
+  uint_t write_through   : 1;
+  uint_t cache_disable   : 1;
   uint_t accessed        : 1;
   uint_t dirty           : 1;
   uint_t pte_attr        : 1;
@@ -248,6 +267,9 @@ pde32_entry_type_t pde32_lookup(pde32_t * pde, addr_t addr, addr_t * entry);
 int pte32_lookup(pte32_t * pte, addr_t addr, addr_t * entry);
 
 
+pt_access_status_t can_access_pde32(pde32_t * pde, addr_t addr, pf_error_t access_type);
+pt_access_status_t can_access_pte32(pte32_t * pte, addr_t addr, pf_error_t access_type);
+
 
 struct guest_info;
 
index 049ac50..695e0f6 100644 (file)
@@ -43,4 +43,18 @@ addr_t setup_shadow_pte32(struct guest_info * info, addr_t pt_host_addr);
 int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
 int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
 
+int handle_shadow_pde32_fault(struct guest_info * info, 
+                             addr_t fault_addr, 
+                             pf_error_t error_code, 
+                             pde32_t * shadow_pde, 
+                             pde32_t * guest_pde);
+
+
+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);
+
+
 #endif
index 5f5d3a3..7e45c0c 100644 (file)
@@ -126,13 +126,13 @@ int guest_va_to_guest_pa(struct guest_info * guest_info, addr_t guest_va, addr_t
        }
 
        switch (pde32_lookup(pde, guest_va, &tmp_pa)) {
-       case NOT_PRESENT: 
+       case PDE32_ENTRY_NOT_PRESENT: 
          *guest_pa = 0;
          return -1;
-       case LARGE_PAGE:
+       case PDE32_ENTRY_LARGE_PAGE:
          *guest_pa = tmp_pa;
          return 0;
-       case PTE32:
+       case PDE32_ENTRY_PTE32:
          {
            pte32_t * pte;
 
index c437c4e..516073a 100644 (file)
@@ -46,21 +46,24 @@ pde32_entry_type_t pde32_lookup(pde32_t * pde, addr_t addr, addr_t * entry) {
 
   if (!pde_entry->present) {
     *entry = 0;
-    return NOT_PRESENT;
+    return PDE32_ENTRY_NOT_PRESENT;
   } else  {
     *entry = PAGE_ADDR(pde_entry->pt_base_addr);
     
-    if (pde_entry->large_pages) {
+    if (pde_entry->large_page) {
       *entry += PAGE_OFFSET(addr);
-      return LARGE_PAGE;
+      return PDE32_ENTRY_LARGE_PAGE;
     } else {
-      return PTE32;
+      return PDE32_ENTRY_PTE32;
     }
   }  
-  return NOT_PRESENT;
+  return PDE32_ENTRY_NOT_PRESENT;
 }
 
 
+
+/* Takes a virtual addr (addr) and returns the physical addr (entry) as defined in the page table
+ */
 int pte32_lookup(pte32_t * pte, addr_t addr, addr_t * entry) {
   pte32_t * pte_entry = &(pte[PTE32_INDEX(addr)]);
 
@@ -78,7 +81,36 @@ int pte32_lookup(pte32_t * pte, addr_t addr, addr_t * entry) {
 
 
 
+pt_access_status_t can_access_pde32(pde32_t * pde, addr_t addr, pf_error_t access_type) {
+  pde32_t * entry = &pde[PDE32_INDEX(addr)];
+
+  if (entry->present == 0) {
+    return PT_ENTRY_NOT_PRESENT;
+  } else if ((entry->writable == 0) && (access_type.write == 1)) {
+    return PT_WRITE_ERROR;
+  } else if ((entry->user_page == 0) && (access_type.user == 1)) {
+    // Check CR0.WP
+    return PT_USER_ERROR;
+  }
+
+  return PT_ACCESS_OK;
+}
+
+
+pt_access_status_t can_access_pte32(pte32_t * pte, addr_t addr, pf_error_t access_type) {
+  pte32_t * entry = &pte[PTE32_INDEX(addr)];
+
+  if (entry->present == 0) {
+    return PT_ENTRY_NOT_PRESENT;
+  } else if ((entry->writable == 0) && (access_type.write == 1)) {
+    return PT_WRITE_ERROR;
+  } else if ((entry->user_page == 0) && (access_type.user == 1)) {
+    // Check CR0.WP
+    return PT_USER_ERROR;
+  }
 
+  return PT_ACCESS_OK;
+}
 
 
 
@@ -110,7 +142,10 @@ pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info) {
          (region->host_type == HOST_REGION_REMOTE) ||
          (region->host_type == HOST_REGION_SWAPPED)) {
        pte[j].present = 0;
-       pte[j].flags = 0;
+       pte[j].writable = 0;
+       pte[j].user_page = 0;
+       pte[j].write_through = 0;
+       pte[j].cache_disable = 0;
        pte[j].accessed = 0;
        pte[j].dirty = 0;
        pte[j].pte_attr = 0;
@@ -120,8 +155,10 @@ pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info) {
       } else {
        addr_t host_addr;
        pte[j].present = 1;
-       pte[j].flags = VM_READ | VM_WRITE | VM_EXEC | VM_USER;   
-       
+       pte[j].writable = 1;
+       pte[j].user_page = 1;
+       pte[j].write_through = 0;
+       pte[j].cache_disable = 0;
        pte[j].accessed = 0;
        pte[j].dirty = 0;
        pte[j].pte_attr = 0;
@@ -146,19 +183,25 @@ pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info) {
       os_hooks->free_page(pte);
 
       pde[i].present = 0;
-      pde[i].flags = 0;
+      pde[i].writable = 0;
+      pde[i].user_page = 0;
+      pde[i].write_through = 0;
+      pde[i].cache_disable = 0;
       pde[i].accessed = 0;
       pde[i].reserved = 0;
-      pde[i].large_pages = 0;
+      pde[i].large_page = 0;
       pde[i].global_page = 0;
       pde[i].vmm_info = 0;
       pde[i].pt_base_addr = 0;
     } else {
       pde[i].present = 1;
-      pde[i].flags = VM_READ | VM_WRITE | VM_EXEC | VM_USER;
+      pde[i].writable = 1;
+      pde[i].user_page = 1;
+      pde[i].write_through = 0;
+      pde[i].cache_disable = 0;
       pde[i].accessed = 0;
       pde[i].reserved = 0;
-      pde[i].large_pages = 0;
+      pde[i].large_page = 0;
       pde[i].global_page = 0;
       pde[i].vmm_info = 0;
       pde[i].pt_base_addr = PAGE_ALIGNED_ADDR(pte);
@@ -176,30 +219,36 @@ pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info) {
 
 void PrintPDE32(addr_t virtual_address, pde32_t * pde)
 {
-  PrintDebug("PDE %p -> %p : present=%x, flags=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
-             virtual_address,
-             (void *) (pde->pt_base_addr << PAGE_POWER),
-             pde->present,
-             pde->flags,
-             pde->accessed,
-             pde->reserved,
-             pde->large_pages,
-             pde->global_page,
-             pde->vmm_info);
+  PrintDebug("PDE %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
+            virtual_address,
+            (void *) (pde->pt_base_addr << PAGE_POWER),
+            pde->present,
+            pde->writable,
+            pde->user_page, 
+            pde->write_through,
+            pde->cache_disable,
+            pde->accessed,
+            pde->reserved,
+            pde->large_page,
+            pde->global_page,
+            pde->vmm_info);
 }
   
 void PrintPTE32(addr_t virtual_address, pte32_t * pte)
 {
-  PrintDebug("PTE %p -> %p : present=%x, flags=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, vmm_info=%x\n",
-             virtual_address,
-             (void*)(pte->page_base_addr << PAGE_POWER),
-             pte->present,
-             pte->flags,
-             pte->accessed,
-             pte->dirty,
-             pte->pte_attr,
-             pte->global_page,
-             pte->vmm_info);
+  PrintDebug("PTE %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, vmm_info=%x\n",
+            virtual_address,
+            (void*)(pte->page_base_addr << PAGE_POWER),
+            pte->present,
+            pte->writable,
+            pte->user_page,
+            pte->write_through,
+            pte->cache_disable,
+            pte->accessed,
+            pte->dirty,
+            pte->pte_attr,
+            pte->global_page,
+            pte->vmm_info);
 }
 
 
index 57fade1..3350f43 100644 (file)
@@ -4,7 +4,7 @@
 #include <palacios/vmm.h>
 #include <palacios/vm_guest_mem.h>
 
-extern struct vmm_os_hooks * os_hooks;
+
 
 
 int init_shadow_page_state(struct shadow_page_state * state) {
@@ -30,32 +30,170 @@ int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_er
   pde32_t * guest_pde = NULL;
   pde32_t * shadow_pde = (pde32_t *)CR3_TO_PDE32(info->shdw_pg_state.shadow_cr3);
   addr_t guest_cr3 = CR3_TO_PDE32(info->shdw_pg_state.guest_cr3);
+  pt_access_status_t guest_pde_access;
+  pt_access_status_t shadow_pde_access;
+  pde32_t * guest_pde_entry = NULL;
+  pde32_t * shadow_pde_entry = (pde32_t *)&(shadow_pde[PDE32_INDEX(fault_addr)]);
 
   if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pde) == -1) {
+    PrintDebug("Invalid Guest PDE Address: 0x%x\n", guest_cr3);
     return -1;
   }
 
-  if (error_code.present == 0) {
-    // Faulted because page was not present...
-    if (shadow_pde[PDE32_INDEX(fault_addr)].present) {
-      
-      
+
+  guest_pde_entry = (pde32_t *)&(guest_pde[PDE32_INDEX(fault_addr)]);
+
+  // Check the guest page permissions
+  guest_pde_access = can_access_pde32(guest_pde, fault_addr, error_code);
+
+  if (guest_pde_access != PT_ACCESS_OK) {
+
+    //
+    // inject page fault to the guest (Guest PDE fault)
+    //
+
+    PrintDebug("Guest Page fault (currently not handled)\n");
+    return -1;
+  }
+
+  shadow_pde_access = can_access_pde32(shadow_pde, fault_addr, error_code);
+
+
+  if (shadow_pde_access == PT_ENTRY_NOT_PRESENT) {
+    pte32_t * shadow_pte = NULL;
+
+    V3_AllocPages(shadow_pte, 1);
+    memset(shadow_pte, 0, PAGE_SIZE);
+
+    shadow_pde_entry->pt_base_addr = PD32_BASE_ADDR(shadow_pte);
+    
+
+    shadow_pde_entry->present = 1;
+    shadow_pde_entry->user_page = guest_pde_entry->user_page;
+    
+    // VMM Specific options
+    shadow_pde_entry->write_through = 0;
+    shadow_pde_entry->cache_disable = 0;
+    shadow_pde_entry->global_page = 0;
+    //
+
+    guest_pde_entry->accessed = 1;
+
+    if (guest_pde_entry->large_page == 0) {
+      shadow_pde_entry->writable = guest_pde_entry->writable;
     } else {
+      /*
+       * Check the Intel manual because we are ignoring Large Page issues here
+       */
+    }
+
+  } else if (shadow_pde_access == PT_WRITE_ERROR) {
+
+    //
+    // Page Directory Entry marked read-only
+    //
+
+    PrintDebug("Shadow Paging Write Error\n");
+    return -1;
+  } else if (shadow_pde_access == PT_USER_ERROR) {
+
+    //
+    // Page Directory Entry marked non-user
+    //
+    
+    PrintDebug("Shadow Paging User access error\n");
+    return -1;
+  } else if (shadow_pde_access == PT_ACCESS_OK) {
+    pte32_t * shadow_pte = (pte32_t *)PDE32_T_ADDR((*shadow_pde_entry));
+    pte32_t * guest_pte = NULL;
+
+    // Page Table entry fault
+    
+    if (guest_pa_to_host_va(info, PDE32_T_ADDR((*guest_pde_entry)), (addr_t*)&guest_pte) == -1) {
+      PrintDebug("Invalid Guest PTE Address: 0x%x\n", PDE32_T_ADDR((*guest_pde_entry)));
       return -1;
-    }    
+    }
+
+
+    if (handle_shadow_pte32_fault(info, fault_addr, error_code, shadow_pte, guest_pte)  == -1) {
+      PrintDebug("Error handling Page fault caused by PTE\n");
+      return -1;
+    }
+
+ }
+
+  PrintDebugPageTables(shadow_pde);
+
+  return 0;
+}
+
+
+
+/* 
+ * 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, 
+                             addr_t fault_addr, 
+                             pf_error_t error_code,
+                             pte32_t * shadow_pte, 
+                             pte32_t * guest_pte) {
+
+  pt_access_status_t guest_pte_access;
+  pt_access_status_t shadow_pte_access;
+  //  pte32_t * guest_pte_entry = (pte32_t *)&(guest_pte[PTE32_INDEX(fault_addr)]);;
+  //  pte32_t * shadow_pte_entry = (pte32_t *)&(shadow_pte[PTE32_INDEX(fault_addr)]);
+
+
+  // Check the guest page permissions
+  guest_pte_access = can_access_pte32(guest_pte, fault_addr, error_code);
+
+  if (guest_pte_access != PT_ACCESS_OK) {
+
+    //
+    // Inject page fault into the guest                
+    //
+
+    PrintDebug("Guest Page fault (currently not handled)\n");
+    return -1;
   }
 
-  // Checks:
-  // Shadow PDE
-  // Guest PDE
-  // Shadow PTE
-  // Guest PTE
-  // Mem Map
-  
-  return -1;
+
+  shadow_pte_access = can_access_pte32(shadow_pte, fault_addr, error_code);
+
+  if (shadow_pte_access == PT_ENTRY_NOT_PRESENT) {
+
+    //
+    // Page Table Entry Not Present
+    //
+
+  } else if (shadow_pte_access == PT_WRITE_ERROR) {
+
+    //
+    // Page Table Entry marked read-only
+    //
+
+    PrintDebug("Shadow Paging Write Error\n");
+    return -1;
+  } else if (shadow_pte_access == PT_USER_ERROR) {
+
+    //
+    // Page Table Entry marked non-user
+    //
+    
+    PrintDebug("Shadow Paging User access error\n");
+    return -1;
+  } else if (shadow_pte_access == PT_ACCESS_OK) {
+
+    PrintDebug("Page Fault occurred for No Reason\n");
+    return -1;
+  }
+
+
+  return 0;
 }
 
 
+
 addr_t create_new_shadow_pt32(struct guest_info * info) {
   void * host_pde = 0;