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.


New Shadow paging implementation to allow pluggable shadow paging implementations
Jack Lange [Thu, 4 Feb 2010 21:30:50 +0000 (15:30 -0600)]
13 files changed:
Kconfig
palacios/include/palacios/vm_guest.h
palacios/include/palacios/vmm_shadow_paging.h
palacios/src/palacios/Makefile
palacios/src/palacios/vm_guest.c
palacios/src/palacios/vmm.c
palacios/src/palacios/vmm_config.c
palacios/src/palacios/vmm_shadow_paging.c
palacios/src/palacios/vmm_shdw_pg_swapbypass.c [new file with mode: 0644]
palacios/src/palacios/vmm_shdw_pg_tlb.c [new file with mode: 0644]
palacios/src/palacios/vmm_shdw_pg_tlb_32.h [new file with mode: 0644]
palacios/src/palacios/vmm_shdw_pg_tlb_32pae.h [moved from palacios/src/palacios/vmm_shadow_paging_32pae.h with 100% similarity]
palacios/src/palacios/vmm_shdw_pg_tlb_64.h [new file with mode: 0644]

diff --git a/Kconfig b/Kconfig
index 95ea8e7..adf2abf 100644 (file)
--- a/Kconfig
+++ b/Kconfig
@@ -115,204 +115,32 @@ config VNET
         help
           Enable the Vnet in Palacios
 
-config BUILT_IN_STDLIB
-       bool "Enable Built in versions of stdlib functions"
-       default y if KITTEN
-       help 
-         Not all host OSes provide link targets for stdlib functions
-         Palacios provides internal implementations of these functions, that you can select from this list
-
-config BUILT_IN_MEMSET
-       bool "memset()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of memset
-
-
-config BUILT_IN_MEMCPY
-       bool "memcpy()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of memcpy
-
-config BUILT_IN_MEMMOVE
-       bool "memmove()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of memmove
-
-config BUILT_IN_MEMCMP
-       bool "memcmp()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of memcmp
-
-config BUILT_IN_STRLEN
-       bool "strlen()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of strlen
-
-config BUILT_IN_STRNLEN
-       bool "strnlen()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of strnlen
-
-
-config BUILT_IN_STRCMP
-       bool "strcmp()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of strcmp
-
-
-config BUILT_IN_STRCASECMP
-       bool "strcasecmp()"
-       default y if KITTEN
-       depends on BUILT_IN_STDLIB
-       help
-         This enables Palacios' internal implementation of strcasecmp
-
-config BUILT_IN_STRNCMP
-       bool "strncmp()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of strncmp
-
-config BUILT_IN_STRNCASECMP
-       bool "strncasecmp()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help
-         This enables Palacios' internal implementation of strncasecmp
-
-
-config BUILT_IN_STRCAT
-       bool "strcat()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of strcat
-
-config BUILT_IN_STRNCAT
-       bool "strncat()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of strncat
-
-config BUILT_IN_STRCPY
-       bool "strcpy()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of strcpy
-
-config BUILT_IN_STRNCPY
-       bool "strncpy()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of strncpy
-
-config BUILT_IN_STRDUP
-       bool "strdup()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of strdup
-
-config BUILT_IN_STRSTR
-       bool "strstr()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help
-         This enables Palacios internal implementation of strstr
-
-
-config BUILT_IN_ATOI
-       bool "atoi()"
-       default y if KITTEN
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of atoi
-
-config BUILT_IN_STRCHR
-       bool "strchr()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of strchr
-
-config BUILT_IN_STRRCHR
-       bool "strrchr()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of strrchr
-
-config BUILT_IN_STRPBRK
-       bool "strpbrk()"
-       default n
-       depends on BUILT_IN_STDLIB
-       help 
-         This enables Palacios' internal implementation of strpbrk
-
-
-config BUILT_IN_STDIO
-       bool "Enable Built in versions of stdio functions"
-       default n
-       help 
-         Not all host OSes provide link targets for stdio functions
-         Palacios provides internal implementations of these functions, that you can select from this list
-
+endmenu
 
 
-config BUILT_IN_SPRINTF
-       bool "sprintf()"
-       default n
-       depends on BUILT_IN_STDIO
-       help 
-         This enables Palacios' internal implementation of sprintf
+source "Kconfig.stdlibs"
 
 
-config BUILT_IN_SNPRINTF
-       bool "snprintf()"
-       default n
-       depends on BUILT_IN_STDIO
-       help 
-         This enables Palacios' internal implementation of snprintf
 
+menu "Virtual Paging"
 
-config BUILT_IN_VSPRINTF
-       bool "vsprintf()"
-       default n
-       depends on BUILT_IN_STDIO
+config SHADOW_PAGING
+       bool "Enable shadow paging"
+       default y
        help 
-         This enables Palacios' internal implementation of vsprintf
+          Enables shadow paging for virtual machines
 
 
-config BUILT_IN_VSNRPRINTF
-       bool "vsnrprintf()"
-       default n
-       depends on BUILT_IN_STDIO
+config SHADOW_PAGING_VTLB
+       bool "Virtual TLB"
+       default y
+       depends on SHADOW_PAGING
        help 
-         This enables Palacios' internal implementation of vsnrprintf
+          Enables Virtual TLB implemenation for shadow paging
 
 endmenu
 
 
-
-
 menu "Symbiotic Functions"
 
 config SYMBIOTIC
index bf9d302..37ae5b8 100644 (file)
@@ -150,7 +150,7 @@ struct guest_info {
     struct vm_time time_state;
 
     v3_paging_mode_t shdw_pg_mode;
-    struct shadow_page_state shdw_pg_state;
+    struct v3_shdw_pg_state shdw_pg_state;
     addr_t direct_map_pt;
 
 
@@ -207,6 +207,8 @@ struct v3_vm_info {
     struct v3_mem_map mem_map;
 
 
+    struct v3_shdw_impl_state shdw_impl;
+
     struct v3_io_map io_map;
     struct v3_msr_map msr_map;
     struct v3_cpuid_map cpuid_map;
index cd0cb7a..a88270b 100644 (file)
 #include <palacios/vmm_list.h>
 #include <palacios/vmm_msr.h>
 
+#include <palacios/vmm_config.h>
 
-struct shadow_page_state {
+
+struct guest_info;
+
+struct v3_shdw_pg_impl {
+    char * name;
+    int (*init)(struct v3_vm_info * vm, v3_cfg_tree_t * cfg);
+    int (*deinit)(struct v3_vm_info * vm);
+    int (*local_init)(struct guest_info * core);
+    int (*handle_pagefault)(struct guest_info * core, addr_t fault_addr, pf_error_t error_code);
+    int (*handle_invlpg)(struct guest_info * core, addr_t vaddr);
+    int (*activate_shdw_pt)(struct guest_info * core);
+    int (*invalidate_shdw_pt)(struct guest_info * core);
+};
+
+
+
+struct v3_shdw_impl_state {
+    
+    struct v3_shdw_pg_impl * current_impl;
+    void * impl_data;
+};
+
+struct v3_shdw_pg_state {
 
     // virtualized control registers
     v3_reg_t guest_cr3;
     v3_reg_t guest_cr0;
     v3_msr_t guest_efer;
 
-    // list of allocated shadow pages
-    struct list_head page_list;
-
+    void * local_impl_data;
 
 #ifdef CONFIG_SHADOW_PAGING_TELEMETRY
     uint_t guest_faults;
@@ -49,20 +70,42 @@ struct shadow_page_state {
 
 
 
-struct guest_info;
 
 
-int v3_init_shadow_page_state(struct guest_info * info);
+
+int v3_init_shdw_impl(struct v3_vm_info * vm);
+int v3_init_shdw_pg_state(struct guest_info * info);
 
 
+/* Handler implementations */
 int v3_handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
 int v3_handle_shadow_invlpg(struct guest_info * info);
 
-
+/* Actions.. */
 int v3_activate_shadow_pt(struct guest_info * info);
 int v3_invalidate_shadow_pts(struct guest_info * info);
 
 
+/* Utility functions for shadow paging implementations */
+int v3_inject_guest_pf(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
+int v3_is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access);
+
+
+
+
+
+int V3_init_shdw_paging();
+
+#define register_shdw_pg_impl(impl)                                    \
+    static struct v3_shdw_pg_impl * _v3_shdw_pg_impl                   \
+    __attribute__((used))                                              \
+       __attribute__((unused, __section__ ("_v3_shdw_pg_impls"),       \
+                      aligned(sizeof(addr_t))))                        \
+       = impl;
+
+
+
+
 #endif // ! __V3VEE__
 
 #endif
index c669cd0..c081e91 100644 (file)
@@ -52,6 +52,8 @@ obj-$(CONFIG_VMX) +=          vmx.o \
                        vmx_assist.o
 
 
+obj-$(CONFIG_SHADOW_PAGING_VTLB) += vmm_shdw_pg_tlb.o
+
 
 obj-$(CONFIG_INSTRUMENT_VMM) += vmm_instrument.o
 obj-$(CONFIG_TELEMETRY) += vmm_telemetry.o 
index e295c1a..87f4f31 100644 (file)
@@ -421,6 +421,14 @@ int v3_init_vm(struct v3_vm_info * vm) {
        return -1;
     }
 
+
+    if (v3_init_shdw_impl(vm) == -1) {
+       PrintError("VM initialization error in shadow implementaion\n");
+       return -1;
+    }
+
+
+
 #ifdef CONFIG_SYMBIOTIC
     v3_init_sym_iface(vm);
 #endif
@@ -475,7 +483,7 @@ int v3_init_core(struct guest_info * core) {
 #endif
 
     if (core->shdw_pg_mode == SHADOW_PAGING) {
-       v3_init_shadow_page_state(core);
+       v3_init_shdw_pg_state(core);
     }
 
     v3_init_time(core);
index 3f5fa6c..cf0d4bd 100644 (file)
@@ -80,6 +80,9 @@ void Init_V3(struct v3_os_hooks * hooks, int num_cpus) {
     // Register all the possible device types
     v3_init_devices();
 
+    // Register all shadow paging handlers
+    V3_init_shdw_paging();
+
 #ifdef INSTRUMENT_VMM
     v3_init_instrumentation();
 #endif
index 7e92869..b622295 100644 (file)
@@ -250,7 +250,8 @@ static int pre_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * vm_cfg) {
 
 static int pre_config_core(struct guest_info * info, v3_cfg_tree_t * core_cfg) {
     extern v3_cpu_arch_t v3_cpu_types[];
-    char * paging = v3_cfg_val(core_cfg, "paging");
+    v3_cfg_tree_t * paging_cfg = v3_cfg_subtree(core_cfg, "paging");
+    char * paging = v3_cfg_val(paging_cfg, "mode");
 
 
     
index a6817f9..33671a7 100644 (file)
@@ -31,6 +31,8 @@
 #include <palacios/vmm_direct_paging.h>
 
 
+
+
 #ifdef CONFIG_SHADOW_PAGING_TELEMETRY
 #include <palacios/vmm_telemetry.h>
 #endif
 #endif
 
 
-/*** 
- ***  There be dragons
- ***/
 
+static struct hashtable * master_shdw_pg_table = NULL;
 
-struct shadow_page_data {
-    v3_reg_t cr3;
-    addr_t page_pa;
-  
-    struct list_head page_list_node;
-};
+static uint_t shdw_pg_hash_fn(addr_t key) {
+    char * name = (char *)key;
+    return v3_hash_buffer((uint8_t *)name, strlen(name));
+}
+
+static int shdw_pg_eq_fn(addr_t key1, addr_t key2) {
+    char * name1 = (char *)key1;
+    char * name2 = (char *)key2;
+
+    return (strcmp(name1, name2) == 0);
+}
 
 
+int V3_init_shdw_paging() {
+    extern struct v3_shdw_pg_impl * __start__v3_shdw_pg_impls[];
+    extern struct v3_shdw_pg_impl * __stop__v3_shdw_pg_impls[];
+    struct v3_shdw_pg_impl ** tmp_impl = __start__v3_shdw_pg_impls;
+    int i = 0;
 
-static struct shadow_page_data * create_new_shadow_pt(struct guest_info * info);
-static int inject_guest_pf(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
-static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access);
+    master_shdw_pg_table = v3_create_htable(0, shdw_pg_hash_fn, shdw_pg_eq_fn);
 
 
-#include "vmm_shadow_paging_32.h"
-#include "vmm_shadow_paging_32pae.h"
-#include "vmm_shadow_paging_64.h"
+    while (tmp_impl != __stop__v3_shdw_pg_impls) {
+       V3_Print("Registering Shadow Paging Impl (%s)\n", (*tmp_impl)->name);
 
+       if (v3_htable_search(master_shdw_pg_table, (addr_t)((*tmp_impl)->name))) {
+           PrintError("Multiple instances of shadow paging impl (%s)\n", (*tmp_impl)->name);
+           return -1;
+       }
+
+       if (v3_htable_insert(master_shdw_pg_table, 
+                            (addr_t)((*tmp_impl)->name),
+                            (addr_t)(*tmp_impl)) == 0) {
+           PrintError("Could not register shadow paging impl (%s)\n", (*tmp_impl)->name);
+           return -1;
+       }
+
+       tmp_impl = &(__start__v3_shdw_pg_impls[++i]);
+    }
+
+    return 0;
+}
+
+
+
+/*** 
+ ***  There be dragons
+ ***/
 
 
 #ifdef CONFIG_SHADOW_PAGING_TELEMETRY
@@ -83,17 +113,24 @@ static void telemetry_cb(struct v3_vm_info * vm, void * private_data, char * hdr
 
 
 
-int v3_init_shadow_page_state(struct guest_info * info) {
-    struct shadow_page_state * state = &(info->shdw_pg_state);
+int v3_init_shdw_pg_state(struct guest_info * core) {
+    struct v3_shdw_pg_state * state = &(core->shdw_pg_state);
+    struct v3_shdw_pg_impl * impl = core->vm_info->shdw_impl.current_impl;
   
+
     state->guest_cr3 = 0;
     state->guest_cr0 = 0;
     state->guest_efer.value = 0x0LL;
 
-    INIT_LIST_HEAD(&(state->page_list));
+
+    if (impl->local_init(core) == -1) {
+       PrintError("Error in Shadow paging local initialization (%s)\n", impl->name);
+       return -1;
+    }
+
 
 #ifdef CONFIG_SHADOW_PAGING_TELEMETRY
-    v3_add_telemetry_cb(info->vm_info, telemetry_cb, NULL);
+    v3_add_telemetry_cb(core->vm_info, telemetry_cb, NULL);
 #endif
   
     return 0;
@@ -101,59 +138,65 @@ int v3_init_shadow_page_state(struct guest_info * info) {
 
 
 
-// Reads the guest CR3 register
-// creates new shadow page tables
-// updates the shadow CR3 register to point to the new pts
-int v3_activate_shadow_pt(struct guest_info * info) {
-    switch (v3_get_vm_cpu_mode(info)) {
-
-       case PROTECTED:
-           return activate_shadow_pt_32(info);
-       case PROTECTED_PAE:
-           return activate_shadow_pt_32pae(info);
-       case LONG:
-       case LONG_32_COMPAT:
-       case LONG_16_COMPAT:
-           return activate_shadow_pt_64(info);
-       default:
-           PrintError("Invalid CPU mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(info)));
-           return -1;
+int v3_init_shdw_impl(struct v3_vm_info * vm) {
+    struct v3_shdw_impl_state * impl_state = &(vm->shdw_impl);
+    v3_cfg_tree_t * pg_cfg = v3_cfg_subtree(vm->cfg_data->cfg, "paging");
+    char * impl_name = v3_cfg_val(pg_cfg, "mode");
+    struct v3_shdw_pg_impl * impl = NULL;
+   
+    V3_Print("Initialization of Shadow Paging implementation\n");
+
+    impl = (struct v3_shdw_pg_impl *)v3_htable_search(master_shdw_pg_table, (addr_t)impl_name);
+
+    if (impl == NULL) {
+       PrintError("Could not find shadow paging impl (%s)\n", impl_name);
+       return -1;
     }
+   
+    impl_state->current_impl = impl;
+
+    if (impl->init(vm, pg_cfg) == -1) {
+       PrintError("Could not initialize Shadow paging implemenation (%s)\n", impl->name);
+       return -1;
+    }
+
+    
+
 
     return 0;
 }
 
 
+// Reads the guest CR3 register
+// creates new shadow page tables
+// updates the shadow CR3 register to point to the new pts
+int v3_activate_shadow_pt(struct guest_info * core) {
+    struct v3_shdw_impl_state * state = &(core->vm_info->shdw_impl);
+    struct v3_shdw_pg_impl * impl = state->current_impl;
+    return impl->activate_shdw_pt(core);
+}
+
+
 
 // This must flush any caches
 // and reset the cr3 value to the correct value
-int v3_invalidate_shadow_pts(struct guest_info * info) {
-    return v3_activate_shadow_pt(info);
+int v3_invalidate_shadow_pts(struct guest_info * core) {
+    struct v3_shdw_impl_state * state = &(core->vm_info->shdw_impl);
+    struct v3_shdw_pg_impl * impl = state->current_impl;
+    return impl->invalidate_shdw_pt(core);
 }
 
 
-int v3_handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
+int v3_handle_shadow_pagefault(struct guest_info * core, addr_t fault_addr, pf_error_t error_code) {
   
-    if (v3_get_vm_mem_mode(info) == PHYSICAL_MEM) {
+    if (v3_get_vm_mem_mode(core) == PHYSICAL_MEM) {
        // If paging is not turned on we need to handle the special cases
-       return v3_handle_passthrough_pagefault(info, fault_addr, error_code);
-    } else if (v3_get_vm_mem_mode(info) == VIRTUAL_MEM) {
-
-       switch (v3_get_vm_cpu_mode(info)) {
-           case PROTECTED:
-               return handle_shadow_pagefault_32(info, fault_addr, error_code);
-               break;
-           case PROTECTED_PAE:
-               return handle_shadow_pagefault_32pae(info, fault_addr, error_code);
-           case LONG:
-           case LONG_32_COMPAT:
-           case LONG_16_COMPAT:
-               return handle_shadow_pagefault_64(info, fault_addr, error_code);
-               break;
-           default:
-               PrintError("Unhandled CPU Mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(info)));
-               return -1;
-       }
+       return v3_handle_passthrough_pagefault(core, fault_addr, error_code);
+    } else if (v3_get_vm_mem_mode(core) == VIRTUAL_MEM) {
+       struct v3_shdw_impl_state * state = &(core->vm_info->shdw_impl);
+       struct v3_shdw_pg_impl * impl = state->current_impl;
+
+       return impl->handle_pagefault(core, fault_addr, error_code);
     } else {
        PrintError("Invalid Memory mode\n");
        return -1;
@@ -161,23 +204,23 @@ int v3_handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_e
 }
 
 
-int v3_handle_shadow_invlpg(struct guest_info * info) {
+int v3_handle_shadow_invlpg(struct guest_info * core) {
     uchar_t instr[15];
     struct x86_instr dec_instr;
     int ret = 0;
     addr_t vaddr = 0;
 
-    if (v3_get_vm_mem_mode(info) != VIRTUAL_MEM) {
+    if (v3_get_vm_mem_mode(core) != VIRTUAL_MEM) {
        // Paging must be turned on...
        // should handle with some sort of fault I think
        PrintError("ERROR: INVLPG called in non paged mode\n");
        return -1;
     }
 
-    if (v3_get_vm_mem_mode(info) == PHYSICAL_MEM) { 
-       ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+    if (v3_get_vm_mem_mode(core) == PHYSICAL_MEM) { 
+       ret = read_guest_pa_memory(core, get_addr_linear(core, core->rip, &(core->segments.cs)), 15, instr);
     } else { 
-       ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+       ret = read_guest_va_memory(core, get_addr_linear(core, core->rip, &(core->segments.cs)), 15, instr);
     }
 
     if (ret == -1) {
@@ -185,7 +228,7 @@ int v3_handle_shadow_invlpg(struct guest_info * info) {
        return -1;
     }
 
-    if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
+    if (v3_decode(core, (addr_t)instr, &dec_instr) == -1) {
        PrintError("Decoding Error\n");
        return -1;
     }
@@ -199,81 +242,33 @@ int v3_handle_shadow_invlpg(struct guest_info * info) {
 
     vaddr = dec_instr.dst_operand.operand;
 
-    info->rip += dec_instr.instr_length;
-
-    switch (v3_get_vm_cpu_mode(info)) {
-       case PROTECTED:
-           return handle_shadow_invlpg_32(info, vaddr);
-       case PROTECTED_PAE:
-           return handle_shadow_invlpg_32pae(info, vaddr);
-       case LONG:
-       case LONG_32_COMPAT:
-       case LONG_16_COMPAT:
-           return handle_shadow_invlpg_64(info, vaddr);
-       default:
-           PrintError("Invalid CPU mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(info)));
-           return -1;
-    }
-}
-
+    core->rip += dec_instr.instr_length;
 
+    {
+       struct v3_shdw_impl_state * state = &(core->vm_info->shdw_impl);
+       struct v3_shdw_pg_impl * impl = state->current_impl;
 
-
-static struct shadow_page_data * create_new_shadow_pt(struct guest_info * info) {
-    struct shadow_page_state * state = &(info->shdw_pg_state);
-    v3_reg_t cur_cr3 = info->ctrl_regs.cr3;
-    struct shadow_page_data * page_tail = NULL;
-    addr_t shdw_page = 0;
-
-    if (!list_empty(&(state->page_list))) {
-       page_tail = list_tail_entry(&(state->page_list), struct shadow_page_data, page_list_node);
-    
-       if (page_tail->cr3 != cur_cr3) {
-           PrintDebug("Reusing old shadow Page: %p (cur_CR3=%p)(page_cr3=%p) \n",
-                      (void *)(addr_t)page_tail->page_pa, 
-                      (void *)(addr_t)cur_cr3, 
-                      (void *)(addr_t)(page_tail->cr3));
-
-           list_move(&(page_tail->page_list_node), &(state->page_list));
-
-           memset(V3_VAddr((void *)(page_tail->page_pa)), 0, PAGE_SIZE_4KB);
-
-
-           return page_tail;
-       }
+       return impl->handle_invlpg(core, vaddr);
     }
+}
 
-    // else  
-
-    page_tail = (struct shadow_page_data *)V3_Malloc(sizeof(struct shadow_page_data));
-    page_tail->page_pa = (addr_t)V3_AllocPages(1);
-
-    PrintDebug("Allocating new shadow Page: %p (cur_cr3=%p)\n", 
-              (void *)(addr_t)page_tail->page_pa, 
-              (void *)(addr_t)cur_cr3);
 
-    page_tail->cr3 = cur_cr3;
-    list_add(&(page_tail->page_list_node), &(state->page_list));
 
-    shdw_page = (addr_t)V3_VAddr((void *)(page_tail->page_pa));
-    memset((void *)shdw_page, 0, PAGE_SIZE_4KB);
 
-    return page_tail;
-}
 
 
-static int inject_guest_pf(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
-    info->ctrl_regs.cr2 = fault_addr;
+int v3_inject_guest_pf(struct guest_info * core, addr_t fault_addr, pf_error_t error_code) {
+    core->ctrl_regs.cr2 = fault_addr;
 
 #ifdef CONFIG_SHADOW_PAGING_TELEMETRY
-    info->shdw_pg_state.guest_faults++;
+    core->shdw_pg_state.guest_faults++;
 #endif
 
-    return v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
+    return v3_raise_exception_with_error(core, PF_EXCEPTION, *(uint_t *)&error_code);
 }
 
 
-static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access) {
+int v3_is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access) {
     /* 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,
diff --git a/palacios/src/palacios/vmm_shdw_pg_swapbypass.c b/palacios/src/palacios/vmm_shdw_pg_swapbypass.c
new file mode 100644 (file)
index 0000000..282c697
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm_shadow_paging.h>
+
+
+struct shadow_page_data {
+    v3_reg_t cr3;
+    addr_t page_pa;
+  
+    struct list_head page_list_node;
+};
+
+
+struct vtlb_state {
+    struct list_head page_list;
+
+};
+
+
+static struct shadow_page_data * create_new_shadow_pt(struct guest_info * info);
+
+
+#include "vmm_shdw_pg_tlb_32.h"
+#include "vmm_shdw_pg_tlb_32pae.h"
+#include "vmm_shdw_pg_tlb_64.h"
+
+
+static struct shadow_page_data * create_new_shadow_pt(struct guest_info * info) {
+    struct shadow_page_state * state = &(info->shdw_pg_state);
+    v3_reg_t cur_cr3 = info->ctrl_regs.cr3;
+    struct shadow_page_data * page_tail = NULL;
+    addr_t shdw_page = 0;
+
+    if (!list_empty(&(state->page_list))) {
+       page_tail = list_tail_entry(&(state->page_list), struct shadow_page_data, page_list_node);
+    
+       if (page_tail->cr3 != cur_cr3) {
+           PrintDebug("Reusing old shadow Page: %p (cur_CR3=%p)(page_cr3=%p) \n",
+                      (void *)(addr_t)page_tail->page_pa, 
+                      (void *)(addr_t)cur_cr3, 
+                      (void *)(addr_t)(page_tail->cr3));
+
+           list_move(&(page_tail->page_list_node), &(state->page_list));
+
+           memset(V3_VAddr((void *)(page_tail->page_pa)), 0, PAGE_SIZE_4KB);
+
+
+           return page_tail;
+       }
+    }
+
+    // else  
+
+    page_tail = (struct shadow_page_data *)V3_Malloc(sizeof(struct shadow_page_data));
+    page_tail->page_pa = (addr_t)V3_AllocPages(1);
+
+    PrintDebug("Allocating new shadow Page: %p (cur_cr3=%p)\n", 
+              (void *)(addr_t)page_tail->page_pa, 
+              (void *)(addr_t)cur_cr3);
+
+    page_tail->cr3 = cur_cr3;
+    list_add(&(page_tail->page_list_node), &(state->page_list));
+
+    shdw_page = (addr_t)V3_VAddr((void *)(page_tail->page_pa));
+    memset((void *)shdw_page, 0, PAGE_SIZE_4KB);
+
+    return page_tail;
+}
+
+
+
+static int vtlb_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data) {
+    struct vtlb_state * state = V3_Malloc(sizeof(struct vtlb_state));
+
+    INIT_LIST_HEAD(&(state->page_list));
+
+    *priv_data = state;
+
+    return 0;
+}
+
+
+int vtlb_activate_shdw_pt(struct guest_info * core, void * priv_data) {
+    switch (v3_get_vm_cpu_mode(core)) {
+
+       case PROTECTED:
+           return activate_shadow_pt_32(core);
+       case PROTECTED_PAE:
+           return activate_shadow_pt_32pae(core);
+       case LONG:
+       case LONG_32_COMPAT:
+       case LONG_16_COMPAT:
+           return activate_shadow_pt_64(core);
+       default:
+           PrintError("Invalid CPU mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(core)));
+           return -1;
+    }
+
+    return 0;
+}
+
+int vtlb_invalidate_shdw_pt(struct guest_info * core, void * priv_data) {
+    return vtlb_activate_shdw_pt(core, priv_data);
+}
+
+
+int vtlb_handle_pf(struct guest_info * core, addr_t fault_addr, pf_error_t err_code, void * priv_data) {
+
+       switch (v3_get_vm_cpu_mode(core)) {
+           case PROTECTED:
+               return handle_shadow_pagefault_32(core, fault_addr, error_code);
+               break;
+           case PROTECTED_PAE:
+               return handle_shadow_pagefault_32pae(core, fault_addr, error_code);
+           case LONG:
+           case LONG_32_COMPAT:
+           case LONG_16_COMPAT:
+               return handle_shadow_pagefault_64(core, fault_addr, error_code);
+               break;
+           default:
+               PrintError("Unhandled CPU Mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(core)));
+               return -1;
+       }
+}
+
+
+int vtlb_handle_invlpg(struct guest_info * core, addr_t vaddr, void * priv_data) {
+
+    switch (v3_get_vm_cpu_mode(core)) {
+       case PROTECTED:
+           return handle_shadow_invlpg_32(core, vaddr);
+       case PROTECTED_PAE:
+           return handle_shadow_invlpg_32pae(core, vaddr);
+       case LONG:
+       case LONG_32_COMPAT:
+       case LONG_16_COMPAT:
+           return handle_shadow_invlpg_64(core, vaddr);
+       default:
+           PrintError("Invalid CPU mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(core)));
+           return -1;
+    }
+}
diff --git a/palacios/src/palacios/vmm_shdw_pg_tlb.c b/palacios/src/palacios/vmm_shdw_pg_tlb.c
new file mode 100644 (file)
index 0000000..4477786
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm_shadow_paging.h>
+#include <palacios/vmm_ctrl_regs.h>
+
+#include <palacios/vm_guest.h>
+#include <palacios/vm_guest_mem.h>
+
+struct shadow_page_data {
+    v3_reg_t cr3;
+    addr_t page_pa;
+  
+    struct list_head page_list_node;
+};
+
+
+struct vtlb_local_state {
+    struct list_head page_list;
+
+};
+
+
+static struct shadow_page_data * create_new_shadow_pt(struct guest_info * core);
+
+
+#include "vmm_shdw_pg_tlb_32.h"
+#include "vmm_shdw_pg_tlb_32pae.h"
+#include "vmm_shdw_pg_tlb_64.h"
+
+
+static struct shadow_page_data * create_new_shadow_pt(struct guest_info * core) {
+    struct v3_shdw_pg_state * state = &(core->shdw_pg_state);
+    struct vtlb_local_state * impl_state = (struct vtlb_local_state *)(state->local_impl_data);
+    v3_reg_t cur_cr3 = core->ctrl_regs.cr3;
+    struct shadow_page_data * page_tail = NULL;
+    addr_t shdw_page = 0;
+
+    if (!list_empty(&(impl_state->page_list))) {
+       page_tail = list_tail_entry(&(impl_state->page_list), struct shadow_page_data, page_list_node);
+
+
+       if (page_tail->cr3 != cur_cr3) {
+           PrintDebug("Reusing old shadow Page: %p (cur_CR3=%p)(page_cr3=%p) \n",
+                      (void *)(addr_t)page_tail->page_pa, 
+                      (void *)(addr_t)cur_cr3, 
+                      (void *)(addr_t)(page_tail->cr3));
+
+           list_move(&(page_tail->page_list_node), &(impl_state->page_list));
+
+           memset(V3_VAddr((void *)(page_tail->page_pa)), 0, PAGE_SIZE_4KB);
+
+
+           return page_tail;
+       }
+    }
+
+    // else  
+
+    page_tail = (struct shadow_page_data *)V3_Malloc(sizeof(struct shadow_page_data));
+    page_tail->page_pa = (addr_t)V3_AllocPages(1);
+
+    PrintDebug("Allocating new shadow Page: %p (cur_cr3=%p)\n", 
+              (void *)(addr_t)page_tail->page_pa, 
+              (void *)(addr_t)cur_cr3);
+
+    page_tail->cr3 = cur_cr3;
+    list_add(&(page_tail->page_list_node), &(impl_state->page_list));
+
+    shdw_page = (addr_t)V3_VAddr((void *)(page_tail->page_pa));
+    memset((void *)shdw_page, 0, PAGE_SIZE_4KB);
+
+    return page_tail;
+}
+
+
+
+static int vtlb_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
+
+    V3_Print("VTLB initialization\n");
+    return 0;
+}
+
+static int vtlb_deinit(struct v3_vm_info * vm) {
+    return -1;
+}
+
+static int vtlb_local_init(struct guest_info * core) {
+    struct v3_shdw_pg_state * state = &(core->shdw_pg_state);
+    struct vtlb_local_state * vtlb_state = NULL;
+
+    V3_Print("VTLB local initialization\n");
+
+
+    vtlb_state = (struct vtlb_local_state *)V3_Malloc(sizeof(struct vtlb_local_state));
+
+    INIT_LIST_HEAD(&(vtlb_state->page_list));
+
+    state->local_impl_data = vtlb_state;
+
+    return 0;
+}
+
+
+static int vtlb_activate_shdw_pt(struct guest_info * core) {
+    switch (v3_get_vm_cpu_mode(core)) {
+
+       case PROTECTED:
+           return activate_shadow_pt_32(core);
+       case PROTECTED_PAE:
+           return activate_shadow_pt_32pae(core);
+       case LONG:
+       case LONG_32_COMPAT:
+       case LONG_16_COMPAT:
+           return activate_shadow_pt_64(core);
+       default:
+           PrintError("Invalid CPU mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(core)));
+           return -1;
+    }
+
+    return 0;
+}
+
+static int vtlb_invalidate_shdw_pt(struct guest_info * core) {
+    return vtlb_activate_shdw_pt(core);
+}
+
+
+static int vtlb_handle_pf(struct guest_info * core, addr_t fault_addr, pf_error_t error_code) {
+
+       switch (v3_get_vm_cpu_mode(core)) {
+           case PROTECTED:
+               return handle_shadow_pagefault_32(core, fault_addr, error_code);
+               break;
+           case PROTECTED_PAE:
+               return handle_shadow_pagefault_32pae(core, fault_addr, error_code);
+           case LONG:
+           case LONG_32_COMPAT:
+           case LONG_16_COMPAT:
+               return handle_shadow_pagefault_64(core, fault_addr, error_code);
+               break;
+           default:
+               PrintError("Unhandled CPU Mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(core)));
+               return -1;
+       }
+}
+
+
+static int vtlb_handle_invlpg(struct guest_info * core, addr_t vaddr) {
+
+    switch (v3_get_vm_cpu_mode(core)) {
+       case PROTECTED:
+           return handle_shadow_invlpg_32(core, vaddr);
+       case PROTECTED_PAE:
+           return handle_shadow_invlpg_32pae(core, vaddr);
+       case LONG:
+       case LONG_32_COMPAT:
+       case LONG_16_COMPAT:
+           return handle_shadow_invlpg_64(core, vaddr);
+       default:
+           PrintError("Invalid CPU mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(core)));
+           return -1;
+    }
+}
+
+static struct v3_shdw_pg_impl vtlb_impl =  {
+    .name = "VTLB",
+    .init = vtlb_init,
+    .deinit = vtlb_deinit,
+    .local_init = vtlb_local_init,
+    .handle_pagefault = vtlb_handle_pf,
+    .handle_invlpg = vtlb_handle_invlpg,
+    .activate_shdw_pt = vtlb_activate_shdw_pt,
+    .invalidate_shdw_pt = vtlb_invalidate_shdw_pt
+};
+
+
+
+
+
+register_shdw_pg_impl(&vtlb_impl);
diff --git a/palacios/src/palacios/vmm_shdw_pg_tlb_32.h b/palacios/src/palacios/vmm_shdw_pg_tlb_32.h
new file mode 100644 (file)
index 0000000..15d92ac
--- /dev/null
@@ -0,0 +1,545 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+
+
+static inline int activate_shadow_pt_32(struct guest_info * core) {
+    struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(core->ctrl_regs.cr3);
+    struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(core->shdw_pg_state.guest_cr3);
+    struct shadow_page_data * shdw_page = create_new_shadow_pt(core);
+
+    shdw_page->cr3 = shdw_page->page_pa;
+    
+    shadow_cr3->pdt_base_addr = PAGE_BASE_ADDR_4KB(shdw_page->page_pa);
+    PrintDebug( "Created new shadow page table %p\n", (void *)BASE_TO_PAGE_ADDR(shadow_cr3->pdt_base_addr));
+  
+    shadow_cr3->pwt = guest_cr3->pwt;
+    shadow_cr3->pcd = guest_cr3->pcd;
+  
+#ifdef CONFIG_SYMBIOTIC_SWAP
+    v3_swap_flush(core->vm_info);
+#endif
+
+    return 0;
+}
+
+
+
+
+/* 
+ * *
+ * * 
+ * * 32 bit Page table fault handlers
+ * *
+ * *
+ */
+static int handle_4MB_shadow_pagefault_32(struct guest_info * info,  addr_t fault_addr, pf_error_t error_code, 
+                                         pte32_t * shadow_pt, pde32_4MB_t * large_guest_pde);
+
+static int handle_pte_shadow_pagefault_32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
+                                         pte32_t * shadow_pt,  pte32_t * guest_pt);
+
+
+static inline int handle_shadow_pagefault_32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
+    pde32_t * guest_pd = NULL;
+    pde32_t * shadow_pd = CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
+    addr_t guest_cr3 = CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3);
+    pt_access_status_t guest_pde_access;
+    pt_access_status_t shadow_pde_access;
+    pde32_t * guest_pde = NULL;
+    pde32_t * shadow_pde = (pde32_t *)&(shadow_pd[PDE32_INDEX(fault_addr)]);
+
+    PrintDebug("Shadow page fault handler: %p\n", (void*) fault_addr );
+    PrintDebug("Handling PDE32 Fault\n");
+
+    if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
+       PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
+       return -1;
+    } 
+
+    guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(fault_addr)]);
+
+
+    // Check the guest page permissions
+    guest_pde_access = v3_can_access_pde32(guest_pd, fault_addr, error_code);
+
+    // Check the shadow page permissions
+    shadow_pde_access = v3_can_access_pde32(shadow_pd, fault_addr, error_code);
+  
+    /* Was the page fault caused by the Guest's page tables? */
+    if (v3_is_guest_pf(guest_pde_access, shadow_pde_access) == 1) {
+       PrintDebug("Injecting PDE pf to guest: (guest access error=%d) (shdw access error=%d)  (pf error code=%d)\n", 
+                  *(uint_t *)&guest_pde_access, *(uint_t *)&shadow_pde_access, *(uint_t *)&error_code);
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
+           return -1;
+       }
+       return 0;
+    }
+
+
+
+    if (shadow_pde_access == PT_ACCESS_USER_ERROR) {
+       // 
+       // PDE Entry marked non user
+       //
+       PrintDebug("Shadow Paging User access error (shadow_pde_access=0x%x, guest_pde_access=0x%x)\n", 
+                  shadow_pde_access, guest_pde_access);
+       
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
+           return -1;
+       }
+       return 0;
+    } else if ((shadow_pde_access == PT_ACCESS_WRITE_ERROR) && 
+              (guest_pde->large_page == 1)) {
+       
+       ((pde32_4MB_t *)guest_pde)->dirty = 1;
+       shadow_pde->writable = guest_pde->writable;
+       return 0;
+    } else if ((shadow_pde_access != PT_ACCESS_NOT_PRESENT) &&
+              (shadow_pde_access != PT_ACCESS_OK)) {
+       // inject page fault in guest
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
+           return -1;
+       }
+       PrintDebug("Unknown Error occurred (shadow_pde_access=%d)\n", shadow_pde_access);
+       PrintDebug("Manual Says to inject page fault into guest\n");
+       return 0;
+    }
+
+  
+    pte32_t * shadow_pt = NULL;
+    pte32_t * guest_pt = NULL;
+
+    // Get the next shadow page level, allocate if not present
+
+    if (shadow_pde_access == PT_ACCESS_NOT_PRESENT) {
+       struct shadow_page_data * shdw_page =  create_new_shadow_pt(info);
+       shadow_pt = (pte32_t *)V3_VAddr((void *)shdw_page->page_pa);
+
+       shadow_pde->present = 1;
+       shadow_pde->user_page = guest_pde->user_page;
+
+
+       if (guest_pde->large_page == 0) {
+           shadow_pde->writable = guest_pde->writable;
+       } else {
+           // This large page flag is temporary until we can get a working cache....
+           ((pde32_4MB_t *)guest_pde)->vmm_info = V3_LARGE_PG;
+
+           if (error_code.write) {
+               shadow_pde->writable = guest_pde->writable;
+               ((pde32_4MB_t *)guest_pde)->dirty = 1;
+           } else {
+               shadow_pde->writable = 0;
+               ((pde32_4MB_t *)guest_pde)->dirty = 0;
+           }
+       }
+      
+
+       // VMM Specific options
+       shadow_pde->write_through = guest_pde->write_through;
+       shadow_pde->cache_disable = guest_pde->cache_disable;
+       shadow_pde->global_page = guest_pde->global_page;
+       //
+      
+       guest_pde->accessed = 1;
+      
+
+
+
+       shadow_pde->pt_base_addr = PAGE_BASE_ADDR(shdw_page->page_pa);
+    } else {
+       shadow_pt = (pte32_t *)V3_VAddr((void *)BASE_TO_PAGE_ADDR(shadow_pde->pt_base_addr));
+    }
+
+
+      
+    if (guest_pde->large_page == 0) {
+       if (guest_pa_to_host_va(info, BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr), (addr_t*)&guest_pt) == -1) {
+           // Machine check the guest
+           PrintDebug("Invalid Guest PTE Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr));
+           v3_raise_exception(info, MC_EXCEPTION);
+           return 0;
+       }
+
+       if (handle_pte_shadow_pagefault_32(info, fault_addr, error_code, shadow_pt, guest_pt)  == -1) {
+           PrintError("Error handling Page fault caused by PTE\n");
+           return -1;
+       }
+    } else {
+       if (handle_4MB_shadow_pagefault_32(info, fault_addr, error_code, shadow_pt, (pde32_4MB_t *)guest_pde) == -1) {
+           PrintError("Error handling large pagefault\n");
+           return -1;
+       }       
+    }
+
+    return 0;
+}
+
+
+static int handle_pte_shadow_pagefault_32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
+                                         pte32_t * shadow_pt, pte32_t * guest_pt) {
+
+    pt_access_status_t guest_pte_access;
+    pt_access_status_t shadow_pte_access;
+    pte32_t * guest_pte = (pte32_t *)&(guest_pt[PTE32_INDEX(fault_addr)]);;
+    pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
+    addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) +  PAGE_OFFSET(fault_addr);
+
+    struct v3_shadow_region * shdw_reg =  v3_get_shadow_region(info->vm_info, info->cpu_id, guest_pa);
+
+    if (shdw_reg == NULL) {
+       // Inject a machine check in the guest
+       PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_pa);
+       v3_raise_exception(info, MC_EXCEPTION);
+       return 0;
+    }
+
+    // Check the guest page permissions
+    guest_pte_access = v3_can_access_pte32(guest_pt, fault_addr, error_code);
+
+    // Check the shadow page permissions
+    shadow_pte_access = v3_can_access_pte32(shadow_pt, fault_addr, error_code);
+  
+  
+    /* Was the page fault caused by the Guest's page tables? */
+    if (v3_is_guest_pf(guest_pte_access, shadow_pte_access) == 1) {
+
+       PrintDebug("Access error injecting pf to guest (guest access error=%d) (pf error code=%d)\n", 
+                  guest_pte_access, *(uint_t*)&error_code);
+       
+#ifdef CONFIG_SYMBIOTIC_SWAP
+       if (is_swapped_pte32(guest_pte)) {
+
+           pf_error_t swap_perms;
+
+
+           /*
+           int sym_ret = v3_get_vaddr_perms(info, fault_addr, guest_pte, &swap_perms);
+           sym_ret = 0;
+           */
+           addr_t swp_pg_addr = 0;
+
+
+
+#ifdef CONFIG_SYMBIOTIC_SWAP_TELEMETRY
+           if (error_code.write == 0) {
+               info->vm_info->swap_state.read_faults++;
+           } else {
+               info->vm_info->swap_state.write_faults++;
+           }
+#endif
+
+
+           swp_pg_addr = v3_get_swapped_pg_addr(info->vm_info,  guest_pte);
+
+           if (swp_pg_addr != 0) {
+               PrintDebug("Swapped page address=%p\n", (void *)swp_pg_addr);
+
+               /*
+               if (info->cpl == 0) {
+                   PrintError("Swapped Page fault in kernel mode.... bad...\n");
+                   goto inject;
+               }
+               */
+
+               int sym_ret = v3_get_vaddr_perms(info, fault_addr, guest_pte, &swap_perms);
+
+               if (sym_ret == -1) {
+                   PrintError("Symcall error...\n");
+                   return -1;
+               } else if (sym_ret == 0) {
+
+
+                   if (swap_perms.present == 0) {
+                       PrintError("Nonpresent swapped page\n");
+                   }
+                   
+                   // swap_perms.write ==1 || error_code.write == 0
+                   // swap_perms.user == 0 || error_code.user == 1
+                   
+                   // This checks for permissions violations that require a guest PF injection
+                   if ( (swap_perms.present == 1) && 
+                        ( (swap_perms.write == 1) || 
+                          (error_code.write == 0) ) &&
+                        ( (swap_perms.user == 1) || 
+                          (error_code.user == 0) ) ) {
+                       addr_t swp_pg_pa = 0;
+                       
+                       swp_pg_pa = v3_map_swp_page(info->vm_info, shadow_pte, guest_pte, (void *)swp_pg_addr);
+
+                       PrintDebug("Page fault on swapped out page (vaddr=%p) (pte=%x) (error_code=%x)\n", 
+                                  (void *)fault_addr, *(uint32_t *)guest_pte, *(uint32_t *)&error_code);
+                       
+                       shadow_pte->writable = swap_perms.write;
+                       shadow_pte->user_page = swap_perms.user;
+                       
+                       shadow_pte->write_through = 0;
+                       shadow_pte->cache_disable = 0;
+                       shadow_pte->global_page = 0;
+                       
+                       shadow_pte->present = 1;
+                       
+                       shadow_pte->page_base_addr = swp_pg_pa;
+                       
+#ifdef CONFIG_SYMBIOTIC_SWAP_TELEMETRY
+                       info->vm_info->swap_state.mapped_pages++;
+#endif
+                       //              PrintError("Swap fault handled\n");
+                       return 0;
+                   }
+               }
+           } else {
+               PrintDebug("Not a sym swappable page\n");
+           }
+
+       }
+#endif
+       //   inject:
+
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
+           return -1;
+       }       
+
+       return 0; 
+    }
+
+  
+  
+    if (shadow_pte_access == PT_ACCESS_OK) {
+       // Inconsistent state...
+       // Guest Re-Entry will flush page tables and everything should now work
+       PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
+       return 0;
+    }
+
+
+    if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
+       // Page Table Entry Not Present
+       PrintDebug("guest_pa =%p\n", (void *)guest_pa);
+
+       if ((shdw_reg->host_type == SHDW_REGION_ALLOCATED) ||
+           (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK)) {
+           addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, info->cpu_id, guest_pa);
+      
+           shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
+
+           PrintDebug("\tMapping shadow page (%p)\n", (void *)BASE_TO_PAGE_ADDR(shadow_pte->page_base_addr));
+      
+           shadow_pte->present = guest_pte->present;
+           shadow_pte->user_page = guest_pte->user_page;
+      
+           //set according to VMM policy
+           shadow_pte->write_through = guest_pte->write_through;
+           shadow_pte->cache_disable = guest_pte->cache_disable;
+           shadow_pte->global_page = guest_pte->global_page;
+           //
+      
+           guest_pte->accessed = 1;
+      
+           if (guest_pte->dirty == 1) {
+               shadow_pte->writable = guest_pte->writable;
+           } else if ((guest_pte->dirty == 0) && (error_code.write == 1)) {
+               shadow_pte->writable = guest_pte->writable;
+               guest_pte->dirty = 1;
+           } else if ((guest_pte->dirty == 0) && (error_code.write == 0)) {
+               shadow_pte->writable = 0;
+           }
+
+
+
+           // Write hooks trump all, and are set Read Only
+           if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
+               shadow_pte->writable = 0;
+           }
+
+       } else {
+           // Page fault handled by hook functions
+
+           if (v3_handle_mem_full_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
+               PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
+               return -1;
+           }
+       }
+    } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
+       guest_pte->dirty = 1;
+
+       if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
+           if (v3_handle_mem_wr_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
+               PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
+               return -1;
+           }
+       } else {
+           PrintDebug("Shadow PTE Write Error\n");
+           shadow_pte->writable = guest_pte->writable;
+       }
+
+
+       return 0;
+
+    } else {
+       // Inject page fault into the guest     
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
+           return -1;
+       }
+
+       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;
+    }
+
+    return 0;
+}
+
+
+
+static int handle_4MB_shadow_pagefault_32(struct guest_info * info, 
+                                    addr_t fault_addr, pf_error_t error_code, 
+                                    pte32_t * shadow_pt, pde32_4MB_t * large_guest_pde) 
+{
+    pt_access_status_t shadow_pte_access = v3_can_access_pte32(shadow_pt, fault_addr, error_code);
+    pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
+    addr_t guest_fault_pa = BASE_TO_PAGE_ADDR_4MB(large_guest_pde->page_base_addr) + PAGE_OFFSET_4MB(fault_addr);  
+
+
+    PrintDebug("Handling 4MB fault (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
+    PrintDebug("ShadowPT=%p, LargeGuestPDE=%p\n", shadow_pt, large_guest_pde);
+
+    struct v3_shadow_region * shdw_reg = v3_get_shadow_region(info->vm_info, info->cpu_id, guest_fault_pa);
+
+    if (shdw_reg == NULL) {
+       // Inject a machine check in the guest
+       PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_fault_pa);
+       v3_raise_exception(info, MC_EXCEPTION);
+       return -1;
+    }
+
+    if (shadow_pte_access == PT_ACCESS_OK) {
+       // Inconsistent state...
+       // Guest Re-Entry will flush tables and everything should now workd
+       PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
+       return 0;
+    }
+
+  
+    if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
+       // Get the guest physical address of the fault
+
+       if ((shdw_reg->host_type == SHDW_REGION_ALLOCATED) || 
+           (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK)) {
+           addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, info->cpu_id, guest_fault_pa);
+
+           shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
+
+           PrintDebug("\tMapping shadow page (%p)\n", (void *)BASE_TO_PAGE_ADDR(shadow_pte->page_base_addr));
+
+           shadow_pte->present = 1;
+
+           /* We are assuming that the PDE entry has precedence
+            * so the Shadow PDE will mirror the guest PDE settings, 
+            * and we don't have to worry about them here
+            * Allow everything
+            */
+           shadow_pte->user_page = 1;
+
+           if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
+               shadow_pte->writable = 0;
+           } else {
+               shadow_pte->writable = 1;
+           }
+
+           //set according to VMM policy
+           shadow_pte->write_through = large_guest_pde->write_through;
+           shadow_pte->cache_disable = large_guest_pde->cache_disable;
+           shadow_pte->global_page = large_guest_pde->global_page;
+           //
+      
+       } else {
+           if (v3_handle_mem_full_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
+               PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
+               return -1;
+           }
+       }
+    } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
+
+       if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
+
+           if (v3_handle_mem_wr_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
+               PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
+               return -1;
+           }
+       }
+
+    } else {
+       PrintError("Error in large page fault handler...\n");
+       PrintError("This case should have been handled at the top level handler\n");
+       return -1;
+    }
+
+    PrintDebug("Returning from large page fault handler\n");
+    return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/* If we start to optimize we should look up the guest pages in the cache... */
+static inline int handle_shadow_invlpg_32(struct guest_info * info, addr_t vaddr) {
+    pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
+    pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(vaddr)];
+
+    addr_t guest_cr3 =  CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3);
+    pde32_t * guest_pd = NULL;
+    pde32_t * guest_pde;
+
+    if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
+       PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
+       return -1;
+    }
+  
+    guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(vaddr)]);
+  
+    if (guest_pde->large_page == 1) {
+       shadow_pde->present = 0;
+       PrintDebug("Invalidating Large Page\n");
+    } else if (shadow_pde->present == 1) {
+       pte32_t * shadow_pt = (pte32_t *)(addr_t)BASE_TO_PAGE_ADDR_4KB(shadow_pde->pt_base_addr);
+       pte32_t * shadow_pte = (pte32_t *) V3_VAddr( (void*) &shadow_pt[PTE32_INDEX(vaddr)] );
+    
+       PrintDebug("Setting not present\n");
+    
+       shadow_pte->present = 0;
+    }
+    return 0;
+}
diff --git a/palacios/src/palacios/vmm_shdw_pg_tlb_64.h b/palacios/src/palacios/vmm_shdw_pg_tlb_64.h
new file mode 100644 (file)
index 0000000..8f01d7c
--- /dev/null
@@ -0,0 +1,697 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+static inline int activate_shadow_pt_64(struct guest_info * info) {
+    struct cr3_64 * shadow_cr3 = (struct cr3_64 *)&(info->ctrl_regs.cr3);
+    struct cr3_64 * guest_cr3 = (struct cr3_64 *)&(info->shdw_pg_state.guest_cr3);
+    struct shadow_page_data * shadow_pt = create_new_shadow_pt(info);
+    addr_t shadow_pt_addr = shadow_pt->page_pa;
+
+    // Because this is a new CR3 load the allocated page is the new CR3 value
+    shadow_pt->cr3 = shadow_pt->page_pa;
+
+    PrintDebug("Top level Shadow page pa=%p\n", (void *)shadow_pt_addr);
+
+    shadow_cr3->pml4t_base_addr = PAGE_BASE_ADDR_4KB(shadow_pt_addr);
+    PrintDebug("Creating new 64 bit shadow page table %p\n", (void *)BASE_TO_PAGE_ADDR(shadow_cr3->pml4t_base_addr));
+
+  
+    shadow_cr3->pwt = guest_cr3->pwt;
+    shadow_cr3->pcd = guest_cr3->pcd;
+
+    return 0;
+}
+
+
+
+
+
+
+/* 
+ * *
+ * * 
+ * * 64 bit Page table fault handlers
+ * *
+ * *
+ */
+
+static int handle_2MB_shadow_pagefault_64(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
+                                         pte64_t * shadow_pt, pde64_2MB_t * large_guest_pde);
+
+static int handle_pte_shadow_pagefault_64(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
+                                         pte64_t * shadow_pt, pte64_t * guest_pt);
+
+static int handle_pde_shadow_pagefault_64(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
+                                         pde64_t * shadow_pd, pde64_t * guest_pd);
+
+static int handle_pdpe_shadow_pagefault_64(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
+                                          pdpe64_t * shadow_pdp, pdpe64_t * guest_pdp);
+
+
+static inline int handle_shadow_pagefault_64(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
+    pml4e64_t * guest_pml = NULL;
+    pml4e64_t * shadow_pml = CR3_TO_PML4E64_VA(info->ctrl_regs.cr3);
+    addr_t guest_cr3 = CR3_TO_PML4E64_PA(info->shdw_pg_state.guest_cr3);
+    pt_access_status_t guest_pml4e_access;
+    pt_access_status_t shadow_pml4e_access;
+    pml4e64_t * guest_pml4e = NULL;
+    pml4e64_t * shadow_pml4e = (pml4e64_t *)&(shadow_pml[PML4E64_INDEX(fault_addr)]);
+
+    PrintDebug("64 bit Shadow page fault handler: %p\n", (void *)fault_addr);
+    PrintDebug("Handling PML fault\n");
+
+    if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pml) == -1) {
+       PrintError("Invalid Guest PML4E Address: 0x%p\n",  (void *)guest_cr3);
+       return -1;
+    } 
+
+    guest_pml4e = (pml4e64_t *)&(guest_pml[PML4E64_INDEX(fault_addr)]);
+
+    PrintDebug("Checking Guest %p\n", (void *)guest_pml);
+    // Check the guest page permissions
+    guest_pml4e_access = v3_can_access_pml4e64(guest_pml, fault_addr, error_code);
+
+    PrintDebug("Checking shadow %p\n", (void *)shadow_pml);
+    // Check the shadow page permissions
+    shadow_pml4e_access = v3_can_access_pml4e64(shadow_pml, fault_addr, error_code);
+  
+    /* Was the page fault caused by the Guest's page tables? */
+    if (v3_is_guest_pf(guest_pml4e_access, shadow_pml4e_access) == 1) {
+       PrintDebug("Injecting PML4E pf to guest: (guest access error=%d) (pf error code=%d)\n", 
+                  *(uint_t *)&guest_pml4e_access, *(uint_t *)&error_code);
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault\n");
+           return -1;
+       }
+       return 0;
+    }
+
+    if (shadow_pml4e_access == PT_ACCESS_USER_ERROR) {
+       //
+       // PML4 Entry marked non-user
+       //      
+       PrintDebug("Shadow Paging User access error (shadow_pml4e_access=0x%x, guest_pml4e_access=0x%x)\n", 
+                  shadow_pml4e_access, guest_pml4e_access);
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault\n");
+           return -1;
+       }
+       return 0;
+    } else if ((shadow_pml4e_access != PT_ACCESS_NOT_PRESENT) &&
+              (shadow_pml4e_access != PT_ACCESS_OK)) {
+       // inject page fault in guest
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault\n");
+           return -1;
+       }
+       PrintDebug("Unknown Error occurred (shadow_pde_access=%d)\n", shadow_pml4e_access);
+       PrintDebug("Manual Says to inject page fault into guest\n");
+       return 0;
+    }
+
+
+    pdpe64_t * shadow_pdp = NULL;
+    pdpe64_t * guest_pdp = NULL;
+
+    // Get the next shadow page level, allocate if not present
+
+    if (shadow_pml4e_access == PT_ACCESS_NOT_PRESENT) {
+       struct shadow_page_data * shdw_page =  create_new_shadow_pt(info);
+       shadow_pdp = (pdpe64_t *)V3_VAddr((void *)shdw_page->page_pa);
+
+
+       shadow_pml4e->present = 1;
+       shadow_pml4e->user_page = guest_pml4e->user_page;
+       shadow_pml4e->writable = guest_pml4e->writable;
+       shadow_pml4e->cache_disable = guest_pml4e->cache_disable;
+       shadow_pml4e->write_through = guest_pml4e->write_through;
+    
+       guest_pml4e->accessed = 1;
+    
+       shadow_pml4e->pdp_base_addr = PAGE_BASE_ADDR(shdw_page->page_pa);
+    } else {
+       shadow_pdp = (pdpe64_t *)V3_VAddr((void *)(addr_t)BASE_TO_PAGE_ADDR(shadow_pml4e->pdp_base_addr));
+    }
+
+    // Continue processing at the next level
+
+    if (guest_pa_to_host_va(info, BASE_TO_PAGE_ADDR(guest_pml4e->pdp_base_addr), (addr_t *)&guest_pdp) == -1) {
+       // Machine check the guest
+       PrintError("Invalid Guest PDP Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pml4e->pdp_base_addr));
+       v3_raise_exception(info, MC_EXCEPTION);
+       return 0;
+    }
+  
+    if (handle_pdpe_shadow_pagefault_64(info, fault_addr, error_code, shadow_pdp, guest_pdp) == -1) {
+       PrintError("Error handling Page fault caused by PDPE\n");
+       return -1;
+    }
+
+    return 0;
+}
+
+
+
+// For now we are not going to handle 1 Gigabyte pages
+static int handle_pdpe_shadow_pagefault_64(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
+                                          pdpe64_t * shadow_pdp, pdpe64_t * guest_pdp) {
+    pt_access_status_t guest_pdpe_access;
+    pt_access_status_t shadow_pdpe_access;
+    pdpe64_t * guest_pdpe = (pdpe64_t *)&(guest_pdp[PDPE64_INDEX(fault_addr)]);
+    pdpe64_t * shadow_pdpe = (pdpe64_t *)&(shadow_pdp[PDPE64_INDEX(fault_addr)]);
+    PrintDebug("Handling PDP fault\n");
+
+    if (fault_addr==0) { 
+       PrintDebug("Guest Page Tree for guest virtual address zero fault\n");
+       PrintGuestPageTree(info,fault_addr,(addr_t)(info->shdw_pg_state.guest_cr3));
+       PrintDebug("Host Page Tree for guest virtual address zero fault\n");
+       PrintHostPageTree(info,fault_addr,(addr_t)(info->ctrl_regs.cr3));
+    }
+
+    // Check the guest page permissions
+    guest_pdpe_access = v3_can_access_pdpe64(guest_pdp, fault_addr, error_code);
+
+    // Check the shadow page permissions
+    shadow_pdpe_access = v3_can_access_pdpe64(shadow_pdp, fault_addr, error_code);
+  
+    /* Was the page fault caused by the Guest's page tables? */
+    if (v3_is_guest_pf(guest_pdpe_access, shadow_pdpe_access) == 1) {
+       PrintDebug("Injecting PDPE pf to guest: (guest access error=%d) (pf error code=%d)\n", 
+                  *(uint_t *)&guest_pdpe_access, *(uint_t *)&error_code);
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault\n");
+           return -1;
+       }
+       return 0;
+    }
+
+    if (shadow_pdpe_access == PT_ACCESS_USER_ERROR) {
+       //
+       // PML4 Entry marked non-user
+       //      
+       PrintDebug("Shadow Paging User access error (shadow_pdpe_access=0x%x, guest_pdpe_access=0x%x)\n", 
+                  shadow_pdpe_access, guest_pdpe_access);
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault\n");
+           return -1;
+       }
+       return 0;
+    } else if ((shadow_pdpe_access != PT_ACCESS_NOT_PRESENT) &&
+              (shadow_pdpe_access != PT_ACCESS_OK)) {
+       // inject page fault in guest
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault\n");
+           return -1;
+       }
+       PrintDebug("Unknown Error occurred (shadow_pde_access=%d)\n", shadow_pdpe_access);
+       PrintDebug("Manual Says to inject page fault into guest\n");
+       return 0;
+    }
+
+
+    pde64_t * shadow_pd = NULL;
+    pde64_t * guest_pd = NULL;
+
+    // Get the next shadow page level, allocate if not present
+
+    if (shadow_pdpe_access == PT_ACCESS_NOT_PRESENT) {
+       struct shadow_page_data * shdw_page = create_new_shadow_pt(info);
+       shadow_pd = (pde64_t *)V3_VAddr((void *)shdw_page->page_pa);
+
+
+       shadow_pdpe->present = 1;
+       shadow_pdpe->user_page = guest_pdpe->user_page;
+       shadow_pdpe->writable = guest_pdpe->writable;
+       shadow_pdpe->write_through = guest_pdpe->write_through;
+       shadow_pdpe->cache_disable = guest_pdpe->cache_disable;
+
+    
+       guest_pdpe->accessed = 1;
+    
+       shadow_pdpe->pd_base_addr = PAGE_BASE_ADDR(shdw_page->page_pa);
+    } else {
+       shadow_pd = (pde64_t *)V3_VAddr((void *)(addr_t)BASE_TO_PAGE_ADDR(shadow_pdpe->pd_base_addr));
+    }
+
+    // Continue processing at the next level
+
+    if (guest_pa_to_host_va(info, BASE_TO_PAGE_ADDR(guest_pdpe->pd_base_addr), (addr_t *)&guest_pd) == -1) {
+       // Machine check the guest
+       PrintError("Invalid Guest PTE Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pdpe->pd_base_addr));
+       v3_raise_exception(info, MC_EXCEPTION);
+       return 0;
+    }
+  
+    if (handle_pde_shadow_pagefault_64(info, fault_addr, error_code, shadow_pd, guest_pd) == -1) {
+       PrintError("Error handling Page fault caused by PDE\n");
+       return -1;
+    }
+
+    return 0;
+}
+
+
+static int handle_pde_shadow_pagefault_64(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
+                                         pde64_t * shadow_pd, pde64_t * guest_pd) {
+    pt_access_status_t guest_pde_access;
+    pt_access_status_t shadow_pde_access;
+    pde64_t * guest_pde = (pde64_t *)&(guest_pd[PDE64_INDEX(fault_addr)]);
+    pde64_t * shadow_pde = (pde64_t *)&(shadow_pd[PDE64_INDEX(fault_addr)]);
+
+    PrintDebug("Handling PDE fault\n");
+    // Check the guest page permissions
+    guest_pde_access = v3_can_access_pde64(guest_pd, fault_addr, error_code);
+
+    // Check the shadow page permissions
+    shadow_pde_access = v3_can_access_pde64(shadow_pd, fault_addr, error_code);
+  
+    /* Was the page fault caused by the Guest's page tables? */
+    if (v3_is_guest_pf(guest_pde_access, shadow_pde_access) == 1) {
+       PrintDebug("Injecting PDE pf to guest: (guest access error=%d) (pf error code=%d)\n", 
+                  *(uint_t *)&guest_pde_access, *(uint_t *)&error_code);
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault\n");
+           return -1;
+       }
+       return 0;
+    }
+
+    if (shadow_pde_access == PT_ACCESS_USER_ERROR) {
+       //
+       // PDE Entry marked non-user
+       //      
+       PrintDebug("Shadow Paging User access error (shadow_pdpe_access=0x%x, guest_pdpe_access=0x%x)\n", 
+                  shadow_pde_access, guest_pde_access);
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault\n");
+           return -1;
+       }
+       return 0;
+
+    } else if ((shadow_pde_access == PT_ACCESS_WRITE_ERROR) && 
+              (guest_pde->large_page == 1)) {
+
+       ((pde64_2MB_t *)guest_pde)->dirty = 1;
+       shadow_pde->writable = guest_pde->writable;
+
+       //PrintDebug("Returning due to large page Write Error\n");
+       //PrintHostPageTree(info, fault_addr, info->ctrl_regs.cr3);
+
+       return 0;
+    } else if ((shadow_pde_access != PT_ACCESS_NOT_PRESENT) &&
+              (shadow_pde_access != PT_ACCESS_OK)) {
+       // inject page fault in guest
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault\n");
+           return -1;
+       }
+       PrintDebug("Unknown Error occurred (shadow_pde_access=%d)\n", shadow_pde_access);
+       PrintDebug("Manual Says to inject page fault into guest\n");
+       return 0;
+    }
+
+
+    pte64_t * shadow_pt = NULL;
+    pte64_t * guest_pt = NULL;
+
+    // Get the next shadow page level, allocate if not present
+
+    if (shadow_pde_access == PT_ACCESS_NOT_PRESENT) {
+       struct shadow_page_data * shdw_page = create_new_shadow_pt(info);
+       shadow_pt = (pte64_t *)V3_VAddr((void *)shdw_page->page_pa);
+
+       PrintDebug("Creating new shadow PT: %p\n", shadow_pt);
+
+       shadow_pde->present = 1;
+       shadow_pde->user_page = guest_pde->user_page;
+
+
+       if (guest_pde->large_page == 0) {
+           shadow_pde->writable = guest_pde->writable;
+       } else {
+           // This large page flag is temporary until we can get a working cache....
+           ((pde64_2MB_t *)guest_pde)->vmm_info = V3_LARGE_PG;
+
+           if (error_code.write) {
+               shadow_pde->writable = guest_pde->writable;
+               ((pde64_2MB_t *)guest_pde)->dirty = 1;  
+           } else {
+               shadow_pde->writable = 0;
+               ((pde64_2MB_t *)guest_pde)->dirty = 0;
+           }
+       }
+    
+       // VMM Specific options
+       shadow_pde->write_through = guest_pde->write_through;
+       shadow_pde->cache_disable = guest_pde->cache_disable;
+       shadow_pde->global_page = guest_pde->global_page;
+       //
+    
+       guest_pde->accessed = 1;
+    
+       shadow_pde->pt_base_addr = PAGE_BASE_ADDR(shdw_page->page_pa);
+    } else {
+       shadow_pt = (pte64_t *)V3_VAddr((void *)BASE_TO_PAGE_ADDR(shadow_pde->pt_base_addr));
+    }
+
+    // Continue processing at the next level
+    if (guest_pde->large_page == 0) {
+       if (guest_pa_to_host_va(info, BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr), (addr_t *)&guest_pt) == -1) {
+           // Machine check the guest
+           PrintError("Invalid Guest PTE Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr));
+           v3_raise_exception(info, MC_EXCEPTION);
+           return 0;
+       }
+    
+       if (handle_pte_shadow_pagefault_64(info, fault_addr, error_code, shadow_pt, guest_pt) == -1) {
+           PrintError("Error handling Page fault caused by PDE\n");
+           return -1;
+       }
+    } else {
+       if (handle_2MB_shadow_pagefault_64(info, fault_addr, error_code, shadow_pt, (pde64_2MB_t *)guest_pde) == -1) {
+           PrintError("Error handling large pagefault\n");
+           return -1;
+       } 
+    }
+
+    return 0;
+}
+
+
+static int handle_pte_shadow_pagefault_64(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
+                                         pte64_t * shadow_pt, pte64_t * guest_pt) {
+    pt_access_status_t guest_pte_access;
+    pt_access_status_t shadow_pte_access;
+    pte64_t * guest_pte = (pte64_t *)&(guest_pt[PTE64_INDEX(fault_addr)]);;
+    pte64_t * shadow_pte = (pte64_t *)&(shadow_pt[PTE64_INDEX(fault_addr)]);
+    addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) +  PAGE_OFFSET(fault_addr);
+    //  struct shadow_page_state * state = &(info->shdw_pg_state);
+
+    PrintDebug("Handling PTE fault\n");
+
+    struct v3_shadow_region * shdw_reg =  v3_get_shadow_region(info->vm_info, info->cpu_id, guest_pa);
+
+
+
+    if (shdw_reg == NULL) {
+       // Inject a machine check in the guest
+       PrintError("Invalid Guest Address in page table (0x%p)\n", (void *)guest_pa);
+       v3_raise_exception(info, MC_EXCEPTION);
+       return 0;
+    }
+
+    // Check the guest page permissions
+    guest_pte_access = v3_can_access_pte64(guest_pt, fault_addr, error_code);
+
+    // Check the shadow page permissions
+    shadow_pte_access = v3_can_access_pte64(shadow_pt, fault_addr, error_code);
+
+    /* Was the page fault caused by the Guest's page tables? */
+    if (v3_is_guest_pf(guest_pte_access, shadow_pte_access) == 1) {
+
+       PrintDebug("Access error injecting pf to guest (guest access error=%d) (pf error code=%d)\n", 
+                  guest_pte_access, *(uint_t*)&error_code);    
+
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault\n");
+           return -1;
+       }
+
+       return 0; 
+    }
+
+    if (shadow_pte_access == PT_ACCESS_OK) {
+       // Inconsistent state...
+       // Guest Re-Entry will flush page tables and everything should now work
+       PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
+       return 0;
+    }
+
+
+    if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
+       // Page Table Entry Not Present
+       PrintDebug("guest_pa =%p\n", (void *)guest_pa);
+
+       if ((shdw_reg->host_type == SHDW_REGION_ALLOCATED) ||
+           (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK)) {
+           addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, info->cpu_id, guest_pa);
+      
+           shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
+      
+           shadow_pte->present = guest_pte->present;
+           shadow_pte->user_page = guest_pte->user_page;
+      
+           //set according to VMM policy
+           shadow_pte->write_through = guest_pte->write_through;
+           shadow_pte->cache_disable = guest_pte->cache_disable;
+           shadow_pte->global_page = guest_pte->global_page;
+           //
+      
+           guest_pte->accessed = 1;
+      
+           if (guest_pte->dirty == 1) {
+               shadow_pte->writable = guest_pte->writable;
+           } else if ((guest_pte->dirty == 0) && (error_code.write == 1)) {
+               shadow_pte->writable = guest_pte->writable;
+               guest_pte->dirty = 1;
+           } else if ((guest_pte->dirty == 0) && (error_code.write == 0)) {
+               shadow_pte->writable = 0;
+           }
+
+
+           // Write hooks trump all, and are set Read Only
+           if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
+               shadow_pte->writable = 0;
+           }
+
+       } else {
+           // Page fault handled by hook functions
+
+           if (v3_handle_mem_full_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
+               PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
+               return -1;
+           }
+       }
+    } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
+       guest_pte->dirty = 1;
+
+       if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
+           if (v3_handle_mem_wr_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
+               PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
+               return -1;
+           }
+       } else {
+           PrintDebug("Shadow PTE Write Error\n");
+           shadow_pte->writable = guest_pte->writable;
+       }
+
+
+       return 0;
+
+    } else {
+       // Inject page fault into the guest     
+       if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
+           PrintError("Could not inject guest page fault\n");
+           return -1;
+       }
+       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;
+    }
+
+    return 0;
+}
+
+
+
+static int handle_2MB_shadow_pagefault_64(struct guest_info * info, 
+                                         addr_t fault_addr, pf_error_t error_code, 
+                                         pte64_t * shadow_pt, pde64_2MB_t * large_guest_pde) 
+{
+    pt_access_status_t shadow_pte_access = v3_can_access_pte64(shadow_pt, fault_addr, error_code);
+    pte64_t * shadow_pte = (pte64_t *)&(shadow_pt[PTE64_INDEX(fault_addr)]);
+    addr_t guest_fault_pa = BASE_TO_PAGE_ADDR_2MB(large_guest_pde->page_base_addr) + PAGE_OFFSET_2MB(fault_addr);
+    //  struct shadow_page_state * state = &(info->shdw_pg_state);
+
+    PrintDebug("Handling 2MB fault (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
+    PrintDebug("ShadowPT=%p, LargeGuestPDE=%p\n", shadow_pt, large_guest_pde);
+
+    struct v3_shadow_region * shdw_reg = v3_get_shadow_region(info->vm_info, info->cpu_id, guest_fault_pa);
+
+    if (shdw_reg == NULL) {
+       // Inject a machine check in the guest
+       PrintError("Invalid Guest Address in page table (0x%p)\n", (void *)guest_fault_pa);
+       v3_raise_exception(info, MC_EXCEPTION);
+       return 0;
+    }
+
+    if (shadow_pte_access == PT_ACCESS_OK) {
+       // Inconsistent state...
+       // Guest Re-Entry will flush tables and everything should now workd
+       PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
+       //PrintHostPageTree(info, fault_addr, info->ctrl_regs.cr3);
+       return 0;
+    }
+
+  
+    if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
+       // Get the guest physical address of the fault
+
+       if ((shdw_reg->host_type == SHDW_REGION_ALLOCATED) || 
+           (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK)) {
+           addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, info->cpu_id, guest_fault_pa);
+
+           shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
+
+           shadow_pte->present = 1;
+
+           /* We are assuming that the PDE entry has precedence
+            * so the Shadow PDE will mirror the guest PDE settings, 
+            * and we don't have to worry about them here
+            * Allow everything
+            */
+           shadow_pte->user_page = 1;
+
+           if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
+               shadow_pte->writable = 0;
+           } else {
+               shadow_pte->writable = 1;
+           }
+
+           //set according to VMM policy
+           shadow_pte->write_through = large_guest_pde->write_through;
+           shadow_pte->cache_disable = large_guest_pde->cache_disable;
+           shadow_pte->global_page = large_guest_pde->global_page;
+           //
+      
+       } else {
+           if (v3_handle_mem_full_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
+               PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
+               return -1;
+           }
+       }
+    } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
+
+       if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
+
+           if (v3_handle_mem_wr_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
+               PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
+               return -1;
+           }
+       }
+
+    } else {
+       PrintError("Error in large page fault handler...\n");
+       PrintError("This case should have been handled at the top level handler\n");
+       return -1;
+    }
+
+    //  PrintHostPageTree(info, fault_addr, info->ctrl_regs.cr3);
+    PrintDebug("Returning from large page fault handler\n");
+    return 0;
+}
+
+
+
+
+static int invalidation_cb_64(struct guest_info * info, page_type_t type, 
+                             addr_t vaddr, addr_t page_ptr, addr_t page_pa, 
+                             void * private_data) {
+
+    switch (type) {
+       case PAGE_PML464:
+           {    
+               pml4e64_t * pml = (pml4e64_t *)page_ptr;
+
+               if (pml[PML4E64_INDEX(vaddr)].present == 0) {
+                   return 1;
+               }
+               return 0;
+           }
+       case PAGE_PDP64:
+           {
+               pdpe64_t * pdp = (pdpe64_t *)page_ptr;
+               pdpe64_t * pdpe = &(pdp[PDPE64_INDEX(vaddr)]);
+
+               if (pdpe->present == 0) {
+                   return 1;
+               }
+     
+               if (pdpe->vmm_info == V3_LARGE_PG) {
+                   PrintError("1 Gigabyte pages not supported\n");
+                   return -1;
+
+                   pdpe->present = 0;
+                   return 1;
+               }
+
+               return 0;
+           }
+       case PAGE_PD64:
+           {
+               pde64_t * pd = (pde64_t *)page_ptr;
+               pde64_t * pde = &(pd[PDE64_INDEX(vaddr)]);
+
+               if (pde->present == 0) {
+                   return 1;
+               }
+      
+               if (pde->vmm_info == V3_LARGE_PG) {
+                   pde->present = 0;
+                   return 1;
+               }
+
+               return 0;
+           }
+       case PAGE_PT64:
+           {
+               pte64_t * pt = (pte64_t *)page_ptr;
+
+               pt[PTE64_INDEX(vaddr)].present = 0;
+
+               return 1;
+           }
+       default:
+           PrintError("Invalid Page Type\n");
+           return -1;
+
+    }
+
+    // should not get here
+    PrintError("Should not get here....\n");
+    return -1;
+}
+
+
+static inline int handle_shadow_invlpg_64(struct guest_info * info, addr_t vaddr) {
+    PrintDebug("INVLPG64 - %p\n",(void*)vaddr);
+
+    int ret =  v3_drill_host_pt_64(info, info->ctrl_regs.cr3, vaddr, invalidation_cb_64, NULL);
+    if (ret == -1) {
+       PrintError("Page table drill returned error.... \n");
+       PrintHostPageTree(info, vaddr, info->ctrl_regs.cr3);
+    }
+
+    return (ret == -1) ? -1 : 0; 
+}