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.


Range-based invalidation for nested and direct paging + use in memory region managment
Peter Dinda [Thu, 21 Feb 2013 22:29:52 +0000 (16:29 -0600)]
palacios/include/palacios/vmm_direct_paging.h
palacios/include/palacios/vmm_paging.h
palacios/src/palacios/vmm_direct_paging.c
palacios/src/palacios/vmm_direct_paging_32.h
palacios/src/palacios/vmm_direct_paging_32pae.h
palacios/src/palacios/vmm_direct_paging_64.h
palacios/src/palacios/vmm_mem.c

index 2d95d2c..6404e6f 100644 (file)
@@ -37,7 +37,14 @@ int v3_handle_nested_pagefault(struct guest_info * info, addr_t fault_addr, pf_e
 int v3_activate_passthrough_pt(struct guest_info * info);
 
 int v3_invalidate_passthrough_addr(struct guest_info * info, addr_t inv_addr);
+// The range invalidated is minimally [start, end]
+int v3_invalidate_passthrough_addr_range(struct guest_info * info, 
+                                        addr_t inv_addr_start, addr_t inv_addr_end);
+
 int v3_invalidate_nested_addr(struct guest_info * info, addr_t inv_addr);
+// The range invalidated is minimally [start, end]
+int v3_invalidate_nested_addr_range(struct guest_info * info, 
+                                   addr_t inv_addr_start, addr_t inv_addr_end);
 
 #endif // ! __V3VEE__
 
index 3026e67..9b95d1b 100644 (file)
@@ -133,12 +133,14 @@ typedef enum {PAGE_4KB, PAGE_2MB, PAGE_4MB, PAGE_1GB,
 #define PAGE_BASE_ADDR_2MB(x) ((x) >> 21)
 #define PAGE_BASE_ADDR_4MB(x) ((x) >> 22)
 #define PAGE_BASE_ADDR_1GB(x) ((x) >> 30)
+#define PAGE_BASE_ADDR_512GB(x) ((x) >> 39)
 
 #define BASE_TO_PAGE_ADDR(x) (((addr_t)x) << 12)
 #define BASE_TO_PAGE_ADDR_4KB(x) (((addr_t)x) << 12)
 #define BASE_TO_PAGE_ADDR_2MB(x) (((addr_t)x) << 21)
 #define BASE_TO_PAGE_ADDR_4MB(x) (((addr_t)x) << 22)
 #define BASE_TO_PAGE_ADDR_1GB(x) (((addr_t)x) << 30)
+#define BASE_TO_PAGE_ADDR_512GB(x) (((addr_t)x) << 39)
 /* *** */
 
 
@@ -166,6 +168,7 @@ typedef enum {PAGE_4KB, PAGE_2MB, PAGE_4MB, PAGE_1GB,
 #define PAGE_SIZE_2MB (4096 * 512)
 #define PAGE_SIZE_4MB (4096 * 1024)
 #define PAGE_SIZE_1GB 0x40000000
+#define PAGE_SIZE_512GB (512ULL * PAGE_SIZE_1GB)
 
 /* *** */
 
index 11c6b69..92601c4 100644 (file)
@@ -176,6 +176,28 @@ int v3_invalidate_passthrough_addr(struct guest_info * info, addr_t inv_addr) {
 }
 
 
+int v3_invalidate_passthrough_addr_range(struct guest_info * info, 
+                                        addr_t inv_addr_start, addr_t inv_addr_end) {
+    v3_cpu_mode_t mode = v3_get_vm_cpu_mode(info);
+
+    switch(mode) {
+       case REAL:
+       case PROTECTED:
+           return invalidate_addr_32_range(info, inv_addr_start, inv_addr_end);
+
+       case PROTECTED_PAE:
+       case LONG:
+       case LONG_32_COMPAT:
+           // Long mode will only use 32PAE page tables...
+           return invalidate_addr_32pae_range(info, inv_addr_start, inv_addr_end);
+
+       default:
+           PrintError(info->vm_info, info, "Unknown CPU Mode\n");
+           break;
+    }
+    return -1;
+}
+
 int v3_invalidate_nested_addr(struct guest_info * info, addr_t inv_addr) {
 
 #ifdef __V3_64BIT__
@@ -203,3 +225,32 @@ int v3_invalidate_nested_addr(struct guest_info * info, addr_t inv_addr) {
 
     return -1;
 }
+
+int v3_invalidate_nested_addr_range(struct guest_info * info, 
+                                   addr_t inv_addr_start, addr_t inv_addr_end) {
+
+#ifdef __V3_64BIT__
+    v3_cpu_mode_t mode = LONG;
+#else 
+    v3_cpu_mode_t mode = PROTECTED;
+#endif
+
+    switch(mode) {
+       case REAL:
+       case PROTECTED:
+           return invalidate_addr_32_range(info, inv_addr_start, inv_addr_end);
+
+       case PROTECTED_PAE:
+           return invalidate_addr_32pae_range(info, inv_addr_start, inv_addr_end);
+
+       case LONG:
+       case LONG_32_COMPAT:
+           return invalidate_addr_64_range(info, inv_addr_start, inv_addr_end);            
+       
+       default:
+           PrintError(info->vm_info, info, "Unknown CPU Mode\n");
+           break;
+    }
+
+    return -1;
+}
index 7f9ed84..e0ac13b 100644 (file)
@@ -106,7 +106,8 @@ static inline int handle_passthrough_pagefault_32(struct guest_info * info,
 
 
 
-static inline int invalidate_addr_32(struct guest_info * info, addr_t inv_addr) {
+static inline int invalidate_addr_32_internal(struct guest_info * info, addr_t inv_addr,
+                                             addr_t *actual_start, uint64_t *actual_size) {
     pde32_t * pde = NULL;
     pte32_t * pte = NULL;
 
@@ -126,11 +127,15 @@ static inline int invalidate_addr_32(struct guest_info * info, addr_t inv_addr)
     }    
 
     if (pde[pde_index].present == 0) {
+        *actual_start = BASE_TO_PAGE_ADDR_4MB(PAGE_BASE_ADDR_4MB(inv_addr));
+        *actual_size = PAGE_SIZE_4MB;
        return 0;
     } else if (pde[pde_index].large_page) {
        pde[pde_index].present = 0;
        pde[pde_index].writable = 0;
        pde[pde_index].user_page = 0;
+        *actual_start = BASE_TO_PAGE_ADDR_4MB(PAGE_BASE_ADDR_4MB(inv_addr));
+        *actual_size = PAGE_SIZE_4MB;
        return 0;
     }
 
@@ -140,8 +145,38 @@ static inline int invalidate_addr_32(struct guest_info * info, addr_t inv_addr)
     pte[pte_index].writable = 0;
     pte[pte_index].user_page = 0;
 
+    *actual_start = BASE_TO_PAGE_ADDR_4KB(PAGE_BASE_ADDR_4KB(inv_addr));
+    *actual_size = PAGE_SIZE_4KB;
+
     return 0;
 }
 
 
+static inline int invalidate_addr_32(struct guest_info * core, addr_t inv_addr)
+{
+  addr_t start;
+  uint64_t len;
+  
+  return invalidate_addr_32_internal(core,inv_addr,&start,&len);
+}
+   
+static inline int invalidate_addr_32_range(struct guest_info * core, addr_t inv_addr_start, addr_t inv_addr_end)
+{
+  addr_t next;
+  addr_t start;
+  uint64_t len;
+  int rc;
+  
+  for (next=inv_addr_start; next<=inv_addr_end; ) {
+    rc = invalidate_addr_32_internal(core,next,&start, &len);
+    if (rc) { 
+      return rc;
+    }
+    next = start + len;
+  }
+  return 0;
+}
+
+
+
 #endif
index ca32a84..e1a84f0 100644 (file)
@@ -113,7 +113,8 @@ static inline int handle_passthrough_pagefault_32pae(struct guest_info * info,
 }
 
 
-static inline int invalidate_addr_32pae(struct guest_info * info, addr_t inv_addr) {
+static inline int invalidate_addr_32pae_internal(struct guest_info * info, addr_t inv_addr,
+                                                addr_t *actual_start, uint64_t *actual_size) {
     pdpe32pae_t * pdpe = NULL;
     pde32pae_t * pde = NULL;
     pte32pae_t * pte = NULL;
@@ -137,15 +138,21 @@ static inline int invalidate_addr_32pae(struct guest_info * info, addr_t inv_add
 
 
     if (pdpe[pdpe_index].present == 0) {
+        *actual_start = BASE_TO_PAGE_ADDR_1GB(PAGE_BASE_ADDR_1GB(inv_addr));
+        *actual_size = PAGE_SIZE_1GB;
        return 0;
     }
 
     pde = V3_VAddr((void*)BASE_TO_PAGE_ADDR(pdpe[pdpe_index].pd_base_addr));
 
     if (pde[pde_index].present == 0) {
+        *actual_start = BASE_TO_PAGE_ADDR_2MB(PAGE_BASE_ADDR_2MB(inv_addr));
+        *actual_size = PAGE_SIZE_2MB;
        return 0;
     } else if (pde[pde_index].large_page) {
        pde[pde_index].present = 0;
+        *actual_start = BASE_TO_PAGE_ADDR_2MB(PAGE_BASE_ADDR_2MB(inv_addr));
+        *actual_size = PAGE_SIZE_2MB;
        return 0;
     }
 
@@ -153,9 +160,36 @@ static inline int invalidate_addr_32pae(struct guest_info * info, addr_t inv_add
 
     pte[pte_index].present = 0;
 
+    *actual_start = BASE_TO_PAGE_ADDR_4KB(PAGE_BASE_ADDR_4KB(inv_addr));
+    *actual_size = PAGE_SIZE_4KB;
     return 0;
 }
 
 
 
+static inline int invalidate_addr_32pae(struct guest_info * core, addr_t inv_addr)
+{
+  addr_t start;
+  uint64_t len;
+  
+  return invalidate_addr_32pae_internal(core,inv_addr,&start,&len);
+}
+   
+static inline int invalidate_addr_32pae_range(struct guest_info * core, addr_t inv_addr_start, addr_t inv_addr_end)
+{
+  addr_t next;
+  addr_t start;
+  uint64_t len;
+  int rc;
+  
+  for (next=inv_addr_start; next<=inv_addr_end; ) {
+    rc = invalidate_addr_32pae_internal(core,next,&start, &len);
+    if (rc) { 
+      return rc;
+    }
+    next = start + len;
+  }
+  return 0;
+}
+
 #endif
index a79d717..004eceb 100644 (file)
@@ -184,7 +184,8 @@ static inline int handle_passthrough_pagefault_64(struct guest_info * core, addr
     return 0;
 }
 
-static inline int invalidate_addr_64(struct guest_info * core, addr_t inv_addr) {
+static inline int invalidate_addr_64_internal(struct guest_info * core, addr_t inv_addr,
+                                             addr_t *actual_start, uint64_t *actual_size) {
     pml4e64_t * pml = NULL;
     pdpe64_t * pdpe = NULL;
     pde64_t * pde = NULL;
@@ -209,28 +210,38 @@ static inline int invalidate_addr_64(struct guest_info * core, addr_t inv_addr)
     }
 
     if (pml[pml_index].present == 0) {
-       return 0;
+        *actual_start = BASE_TO_PAGE_ADDR_512GB(PAGE_BASE_ADDR_512GB(inv_addr));
+        *actual_size = PAGE_SIZE_512GB;
+       return 0;
     }
 
     pdpe = V3_VAddr((void*)BASE_TO_PAGE_ADDR(pml[pml_index].pdp_base_addr));
 
     if (pdpe[pdpe_index].present == 0) {
+        *actual_start = BASE_TO_PAGE_ADDR_1GB(PAGE_BASE_ADDR_1GB(inv_addr));
+        *actual_size = PAGE_SIZE_1GB;
        return 0;
     } else if (pdpe[pdpe_index].large_page == 1) { // 1GiB
        pdpe[pdpe_index].present = 0;
        pdpe[pdpe_index].writable = 0;
        pdpe[pdpe_index].user_page = 0;
+        *actual_start = BASE_TO_PAGE_ADDR_1GB(PAGE_BASE_ADDR_1GB(inv_addr));
+        *actual_size = PAGE_SIZE_1GB;
        return 0;
     }
 
     pde = V3_VAddr((void*)BASE_TO_PAGE_ADDR(pdpe[pdpe_index].pd_base_addr));
 
     if (pde[pde_index].present == 0) {
+        *actual_start = BASE_TO_PAGE_ADDR_2MB(PAGE_BASE_ADDR_2MB(inv_addr));
+        *actual_size = PAGE_SIZE_2MB;
        return 0;
     } else if (pde[pde_index].large_page == 1) { // 2MiB
        pde[pde_index].present = 0;
        pde[pde_index].writable = 0;
        pde[pde_index].user_page = 0;
+        *actual_start = BASE_TO_PAGE_ADDR_2MB(PAGE_BASE_ADDR_2MB(inv_addr));
+        *actual_size = PAGE_SIZE_2MB;
        return 0;
     }
 
@@ -240,9 +251,37 @@ static inline int invalidate_addr_64(struct guest_info * core, addr_t inv_addr)
     pte[pte_index].writable = 0;
     pte[pte_index].user_page = 0;
 
+    *actual_start = BASE_TO_PAGE_ADDR_4KB(PAGE_BASE_ADDR_4KB(inv_addr));
+    *actual_size = PAGE_SIZE_4KB;
+
     return 0;
 }
 
+static inline int invalidate_addr_64(struct guest_info * core, addr_t inv_addr)
+{
+  addr_t start;
+  uint64_t len;
+  
+  return invalidate_addr_64_internal(core,inv_addr,&start,&len);
+}
+   
+static inline int invalidate_addr_64_range(struct guest_info * core, addr_t inv_addr_start, addr_t inv_addr_end)
+{
+  addr_t next;
+  addr_t start;
+  uint64_t len;
+  int rc;
+  
+  for (next=inv_addr_start; next<=inv_addr_end; ) {
+    rc = invalidate_addr_64_internal(core,next,&start, &len);
+    if (rc) { 
+      return rc;
+    }
+    next = start + len;
+  }
+  return 0;
+}
+
 
 
 #endif
index 6a4f5da..29579e5 100644 (file)
@@ -212,6 +212,7 @@ struct v3_mem_region * __insert_mem_region(struct v3_vm_info * vm,
 int v3_insert_mem_region(struct v3_vm_info * vm, struct v3_mem_region * region) {
     struct v3_mem_region * ret;
     int i = 0;
+    int rc;
 
     if ((ret = __insert_mem_region(vm, region))) {
        PrintError(vm, VCORE_NONE, "Internal insert failed returned region is from 0x%p to 0x%p on vcore %d\n", (void*)(ret->guest_start), (void*)(ret->guest_end), ret->core_id);
@@ -221,6 +222,7 @@ int v3_insert_mem_region(struct v3_vm_info * vm, struct v3_mem_region * region)
     v3_rb_insert_color(&(region->tree_node), &(vm->mem_map.mem_regions));
 
 
+    rc = 0;
 
     for (i = 0; i < vm->num_cores; i++) {
        struct guest_info * info = &(vm->cores[i]);
@@ -232,30 +234,17 @@ int v3_insert_mem_region(struct v3_vm_info * vm, struct v3_mem_region * region)
            v3_mem_mode_t mem_mode = v3_get_vm_mem_mode(info);
            
            if (mem_mode == PHYSICAL_MEM) {
-               addr_t cur_addr;
-               
-               for (cur_addr = region->guest_start;
-                    cur_addr < region->guest_end;
-                    cur_addr += PAGE_SIZE_4KB) {
-                   v3_invalidate_passthrough_addr(info, cur_addr);
-               }
+               rc |= v3_invalidate_passthrough_addr_range(info, region->guest_start, region->guest_end-1);
            } else {
-               v3_invalidate_shadow_pts(info);
+               rc |= v3_invalidate_shadow_pts(info);
            }
            
        } else if (info->shdw_pg_mode == NESTED_PAGING) {
-           addr_t cur_addr;
-           
-           for (cur_addr = region->guest_start;
-                cur_addr < region->guest_end;
-                cur_addr += PAGE_SIZE_4KB) {
-               
-               v3_invalidate_nested_addr(info, cur_addr);
-           }
+           rc |= v3_invalidate_nested_addr_range(info, region->guest_start, region->guest_end-1);
        }
     }
 
-    return 0;
+    return rc;
 }
                                                 
 
@@ -428,6 +417,7 @@ static struct v3_mem_region * get_overlapping_region(struct v3_vm_info * vm, uin
 
 void v3_delete_mem_region(struct v3_vm_info * vm, struct v3_mem_region * reg) {
     int i = 0;
+    int rc;
 
     if (reg == NULL) {
        return;
@@ -446,6 +436,8 @@ void v3_delete_mem_region(struct v3_vm_info * vm, struct v3_mem_region * reg) {
        return;
     }
 
+    rc = 0;
+
     for (i = 0; i < vm->num_cores; i++) {
        struct guest_info * info = &(vm->cores[i]);
 
@@ -456,26 +448,13 @@ void v3_delete_mem_region(struct v3_vm_info * vm, struct v3_mem_region * reg) {
            v3_mem_mode_t mem_mode = v3_get_vm_mem_mode(info);
            
            if (mem_mode == PHYSICAL_MEM) {
-               addr_t cur_addr;
-               
-               for (cur_addr = reg->guest_start;
-                    cur_addr < reg->guest_end;
-                    cur_addr += PAGE_SIZE_4KB) {
-                   v3_invalidate_passthrough_addr(info, cur_addr);
-               }
+             rc |= v3_invalidate_passthrough_addr_range(info,reg->guest_start, reg->guest_end-1);
            } else {
-               v3_invalidate_shadow_pts(info);
+             rc |= v3_invalidate_shadow_pts(info);
            }
            
        } else if (info->shdw_pg_mode == NESTED_PAGING) {
-           addr_t cur_addr;
-           
-           for (cur_addr = reg->guest_start;
-                cur_addr < reg->guest_end;
-                cur_addr += PAGE_SIZE_4KB) {
-               
-               v3_invalidate_nested_addr(info, cur_addr);
-           }
+         rc |= v3_invalidate_nested_addr_range(info,reg->guest_start, reg->guest_end-1);
        }
     }
 
@@ -484,6 +463,7 @@ void v3_delete_mem_region(struct v3_vm_info * vm, struct v3_mem_region * reg) {
     // flush virtual page tables 
     // 3 cases shadow, shadow passthrough, and nested
 
+    if (rc) { PrintError(vm, VCORE_NONE, "Error in deleting memory region\n"); }
 }
 
 // Determine if a given address can be handled by a large page of the requested size