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.


reworked the hash table implementation
Jack Lange [Fri, 22 Aug 2008 21:44:04 +0000 (21:44 +0000)]
added simple shadow page table caching

palacios/include/palacios/vmm_hashtable.h
palacios/include/palacios/vmm_paging.h
palacios/include/palacios/vmm_shadow_paging.h
palacios/src/palacios/svm_handler.c
palacios/src/palacios/vmm_config.c
palacios/src/palacios/vmm_ctrl_regs.c
palacios/src/palacios/vmm_hashtable.c
palacios/src/palacios/vmm_paging.c
palacios/src/palacios/vmm_shadow_paging.c

index e64fd8c..9e81e4f 100644 (file)
@@ -71,18 +71,18 @@ ulong_t hash_buffer(uchar_t * msg, uint_t length);
 
 
 #define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype)            \
-  int fnname (struct hashtable * htable, keytype * key, valuetype * value) { \
-    return hashtable_insert(htable, key, value);                       \
+  int fnname (struct hashtable * htable, keytype key, valuetype value) { \
+    return hashtable_insert(htable, (addr_t)key, (addr_t)value);               \
   }
 
 #define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype)            \
-  valuetype * fnname (struct hashtable * htable, keytype * key) {      \
-    return (valuetype *) (hashtable_search(htable, key));              \
+  valuetype * fnname (struct hashtable * htable, keytype  key) {       \
+    return (valuetype *) (hashtable_search(htable, (addr_t)key));              \
   }
 
-#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype)            \
-  valuetype * fnname (struct hashtable * htable, keytype * key) {      \
-    return (valuetype *) (hashtable_remove(htable, key));              \
+#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype, free_key)  \
+  valuetype * fnname (struct hashtable * htable, keytype key) {        \
+    return (valuetype *) (hashtable_remove(htable, (addr_t)key, free_key));    \
   }
 
 
@@ -91,10 +91,10 @@ ulong_t hash_buffer(uchar_t * msg, uint_t length);
 
 
 struct hashtable * create_hashtable(uint_t min_size,
-                                   uint_t (*hashfunction) (void * key),
-                                   int (*key_eq_fn) (void * key1, void * key2));
+                                   uint_t (*hashfunction) (addr_t key),
+                                   int (*key_eq_fn) (addr_t key1, addr_t key2));
 
-void hashtable_destroy(struct hashtable * htable, int free_values);
+void hashtable_destroy(struct hashtable * htable, int free_values, int free_keys);
 
 /*
  * returns non-zero for successful insertion
@@ -108,16 +108,16 @@ void hashtable_destroy(struct hashtable * htable, int free_values);
  * entries is reversed.
  * If in doubt, remove before insert.
  */
-int hashtable_insert(struct hashtable * htable, void * key, void * value);
+int hashtable_insert(struct hashtable * htable, addr_t key, addr_t value);
 
-int hashtable_change(struct hashtable * htable, void * key, void * value);
+int hashtable_change(struct hashtable * htable, addr_t key, addr_t value, int free_value);
 
 
 // returns the value associated with the key, or NULL if none found
-void * hashtable_search(struct hashtable * htable, void * key);
+addr_t hashtable_search(struct hashtable * htable, addr_t key);
 
 // returns the value associated with the key, or NULL if none found
-void * hashtable_remove(struct hashtable * htable, void * key);
+addr_t hashtable_remove(struct hashtable * htable, addr_t key, int free_key);
 
 uint_t hashtable_count(struct hashtable * htable);
 
@@ -147,7 +147,7 @@ struct hashtable_iter * create_hashtable_iterator(struct hashtable * htable);
 
 /* - return the value of the (key,value) pair at the current position */
 //extern inline 
-void * hashtable_get_iter_key(struct hashtable_iter * iter);
+addr_t  hashtable_get_iter_key(struct hashtable_iter * iter);
 /* {
    return iter->entry->key;
    }
@@ -156,7 +156,7 @@ void * hashtable_get_iter_key(struct hashtable_iter * iter);
 
 /* value - return the value of the (key,value) pair at the current position */
 //extern inline 
-void * hashtable_get_iter_value(struct hashtable_iter * iter);
+addr_t hashtable_get_iter_value(struct hashtable_iter * iter);
 /* {
    return iter->entry->value;
    }
@@ -172,13 +172,13 @@ int hashtable_iterator_advance(struct hashtable_iter * iter);
  *          removing. ie: beware memory leaks!
  *          returns zero if advanced to end of table 
  */
-int hashtable_iterator_remove(struct hashtable_iter * iter);
+int hashtable_iterator_remove(struct hashtable_iter * iter, int free_key);
 
 
 /* search - overwrite the supplied iterator, to point to the entry
  *          matching the supplied key.
  *          returns zero if not found. */
-int hashtable_iterator_search(struct hashtable_iter * iter, struct hashtable * htable, void * key);
+int hashtable_iterator_search(struct hashtable_iter * iter, struct hashtable * htable, addr_t key);
 
 
 
index 29bb19f..687b440 100644 (file)
@@ -121,6 +121,7 @@ the host state in the vmcs before entering the guest.
 
 /* Page Table Flag Values */
 #define PT32_HOOK 0x1
+#define PT32_GUEST_PT 0x2
 
 
 #endif
index 853f851..1bc2838 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <palacios/vmm_util.h>
 #include <palacios/vmm_paging.h>
+#include <palacios/vmm_hashtable.h>
 
 struct shadow_page_state {
 
@@ -23,6 +24,12 @@ struct shadow_page_state {
   ullong_t                shadow_cr3;
 
 
+  // Hash table that ties a CR3 value to a hash table pointer for the PT entries
+  struct hashtable *  cr3_cache;
+  // Hash table that contains a mapping of guest pte addresses to host pte addresses
+  struct hashtable *  cached_ptes;
+  addr_t cached_cr3;
+
 };
 
 
@@ -31,7 +38,7 @@ struct guest_info;
 
 
 
-
+int cache_page_tables32(struct guest_info * info, addr_t  pde);
 
 int init_shadow_page_state(struct guest_info * info);
 
index 8a1a32f..ad4fe4c 100644 (file)
@@ -452,7 +452,6 @@ int handle_svm_exit(struct guest_info * info) {
 
 
 const uchar_t * vmexit_code_to_str(uint_t exit_code) {
-
   switch(exit_code) {
   case VMEXIT_CR0_READ:
     return VMEXIT_CR0_READ_STR;
index 39790c8..5ef7461 100644 (file)
 
 
 
-/*static int mem_test_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
- int foo = 20;
+static int mem_test_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
+  int foo = 20;
 
 
   memcpy(dst, &foo, length);
 
   PrintDebug("Passthrough mem read returning: %d (length=%d)\n", foo + (guest_addr & 0xfff), length);
   return length;
-  }*/
+}
 
 static int passthrough_mem_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
     memcpy(dst, (void*)guest_addr, length);
@@ -98,9 +98,11 @@ int config_guest(struct guest_info * info, void * config_ptr) {
       //     
   add_shadow_region_passthrough(info, 0x0, 0xa0000, (addr_t)V3_AllocPages(160));
   
-  //add_shadow_region_passthrough(info, 0xa0000, 0xc0000, 0xa0000); 
-  hook_guest_mem(info, 0xa0000, 0xc0000, passthrough_mem_read, passthrough_mem_write, NULL);
-  
+  if (1) {
+    add_shadow_region_passthrough(info, 0xa0000, 0xc0000, 0xa0000); 
+  } else {
+    hook_guest_mem(info, 0xa0000, 0xc0000, passthrough_mem_read, passthrough_mem_write, NULL);
+  }  
   
   // TEMP
   //add_shadow_region_passthrough(info, 0xc0000, 0xc8000, 0xc0000);
@@ -116,18 +118,15 @@ int config_guest(struct guest_info * info, void * config_ptr) {
   }
   
   
+  if (1) {
   add_shadow_region_passthrough(info, 0x100000, 0x1000000, (addr_t)V3_AllocPages(4096));
- /* MEMORY HOOK TEST */
-  /*  { 
-   
+  } else {
+    /* MEMORY HOOK TEST */
     add_shadow_region_passthrough(info, 0x100000, 0xa00000, (addr_t)V3_AllocPages(2304));
-    hook_guest_mem(info, 0xa00000, 0xa01000, mem_test_read, passthrough_mem_write, NULL);
-    
+    hook_guest_mem(info, 0xa00000, 0xa01000, mem_test_read, passthrough_mem_write, NULL); 
     add_shadow_region_passthrough(info, 0xa01000, 0x1000000, (addr_t)V3_AllocPages(1791));
-
   }
-*/
+
     add_shadow_region_passthrough(info, 0x1000000, 0x8000000, (addr_t)V3_AllocPages(32768));
  
   // test - give linux accesss to PCI space - PAD
index 89d896b..4575f99 100644 (file)
 #endif
 
 
-// Set to 1 if CR3 reload with same value shall not
-// force a shadow page table flush
-// It makes windows loading MUCH faster. 
-// Note that this optimization appears to fail with a 2.6 linux kernel
-#define CR3_RELOAD_OPTIMIZATION 1
-
-
-
-
 
 
 
@@ -247,11 +238,20 @@ int handle_cr3_write(struct guest_info * info) {
       struct cr3_32 * new_cr3 = (struct cr3_32 *)(dec_instr.src_operand.operand);      
       struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
       struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
+      int cached = 0;
       
+
       PrintDebug("Old Shadow CR3=%x; Old Guest CR3=%x\n", 
                 *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
       
-      if (!CR3_RELOAD_OPTIMIZATION || !CR3_32_SAME_BASE(new_cr3, guest_cr3)) { 
+
+      cached = cache_page_tables32(info, CR3_TO_PDE32(*(addr_t *)new_cr3));
+      if (cached == -1) {
+       PrintError("CR3 Cache failed\n");
+       return -1;
+      } else if (cached == 0) {
+
+
        addr_t shadow_pt;
 
        
@@ -262,7 +262,9 @@ int handle_cr3_write(struct guest_info * info) {
        shadow_pt =  create_new_shadow_pt32();
        
        shadow_cr3->pdt_base_addr = PD32_BASE_ADDR(shadow_pt);    
-      } 
+      } else {
+       PrintDebug("Reusing cached shadow Page table\n");
+      }
       
       shadow_cr3->pwt = new_cr3->pwt;
       shadow_cr3->pcd = new_cr3->pcd;
@@ -337,3 +339,7 @@ int handle_cr3_read(struct guest_info * info) {
 
   return 0;
 }
+
+
+
+
index 3b742f1..533eaf6 100644 (file)
@@ -10,8 +10,8 @@
 
 
 struct hash_entry {
-  void * key;
-  void * value;
+  addr_t key;
+  addr_t value;
   uint_t hash;
   struct hash_entry * next;
 };
@@ -22,8 +22,8 @@ struct hashtable {
     uint_t entry_count;
     uint_t load_limit;
     uint_t prime_index;
-    uint_t (*hash_fn) (void * key);
-    int (*eq_fn) (void * key1, void * key2);
+    uint_t (*hash_fn) (addr_t key);
+    int (*eq_fn) (addr_t key1, addr_t key2);
 };
 
 
@@ -32,7 +32,7 @@ struct hashtable {
 
 
 
-uint_t do_hash(struct hashtable * htable, void * key) {
+uint_t do_hash(struct hashtable * htable, addr_t key) {
   /* Aim to protect against poor hash functions by adding logic here
    * - logic taken from java 1.4 hashtable source */
   uint_t i = htable->hash_fn(key);
@@ -159,8 +159,8 @@ const float max_load_factor = 0.65;
 
 /*****************************************************************************/
 struct hashtable * create_hashtable(uint_t min_size,
-                                   uint_t (*hash_fn) (void *),
-                                   int (*eq_fn) (void *, void *)) {
+                                   uint_t (*hash_fn) (addr_t),
+                                   int (*eq_fn) (addr_t, addr_t)) {
     struct hashtable * htable;
     uint_t prime_index;
     uint_t size = primes[0];
@@ -294,7 +294,7 @@ uint_t hashtable_count(struct hashtable * htable) {
 }
 
 /*****************************************************************************/
-int hashtable_insert(struct hashtable * htable, void * key, void * value) {
+int hashtable_insert(struct hashtable * htable, addr_t key, addr_t value) {
     /* This method allows duplicate keys - but they shouldn't be used */
     uint_t index;
     struct hash_entry * new_entry;
@@ -331,7 +331,7 @@ int hashtable_insert(struct hashtable * htable, void * key, void * value) {
 
 
 
-int hashtable_change(struct hashtable * htable, void * key, void * value) {
+int hashtable_change(struct hashtable * htable, addr_t key, addr_t value, int free_value) {
     struct hash_entry * tmp_entry;
     uint_t hash_value;
     uint_t index;
@@ -345,10 +345,13 @@ int hashtable_change(struct hashtable * htable, void * key, void * value) {
     while (tmp_entry != NULL) {
         /* Check hash value to short circuit heavier comparison */
         if ((hash_value == tmp_entry->hash) && (htable->eq_fn(key, tmp_entry->key))) {
-            V3_Free(tmp_entry->value);
-            tmp_entry->value = value;
 
-            return -1;
+         if (free_value) {
+            V3_Free((void *)(tmp_entry->value));
+         }
+
+         tmp_entry->value = value;
+         return -1;
         }
         tmp_entry = tmp_entry->next;
     }
@@ -360,7 +363,7 @@ int hashtable_change(struct hashtable * htable, void * key, void * value) {
 
 /*****************************************************************************/
 /* returns value associated with key */
-void * hashtable_search(struct hashtable * htable, void * key) {
+addr_t hashtable_search(struct hashtable * htable, addr_t key) {
   struct hash_entry * cursor;
   uint_t hash_value;
   uint_t index;
@@ -381,18 +384,18 @@ void * hashtable_search(struct hashtable * htable, void * key) {
     cursor = cursor->next;
   }
   
-  return NULL;
+  return (addr_t)NULL;
 }
 
 /*****************************************************************************/
 /* returns value associated with key */
-void * hashtable_remove(struct hashtable * htable, void * key) {
+addr_t hashtable_remove(struct hashtable * htable, addr_t key, int free_key) {
   /* TODO: consider compacting the table when the load factor drops enough,
    *       or provide a 'compact' method. */
   
   struct hash_entry * cursor;
   struct hash_entry ** entry_ptr;
-  void * value;
+  addr_t value;
   uint_t hash_value;
   uint_t index;
   
@@ -412,7 +415,9 @@ void * hashtable_remove(struct hashtable * htable, void * key) {
       htable->entry_count--;
       value = cursor->value;
       
-      freekey(cursor->key);
+      if (free_key) {
+       freekey((void *)(cursor->key));
+      }
       V3_Free(cursor);
       
       return value;
@@ -421,12 +426,12 @@ void * hashtable_remove(struct hashtable * htable, void * key) {
     entry_ptr = &(cursor->next);
     cursor = cursor->next;
   }
-  return NULL;
+  return (addr_t)NULL;
 }
 
 /*****************************************************************************/
 /* destroy */
-void hashtable_destroy(struct hashtable * htable, int free_values) {
+void hashtable_destroy(struct hashtable * htable, int free_values, int free_keys) {
   uint_t i;
   struct hash_entry * cursor;;
   struct hash_entry **table = htable->table;
@@ -441,8 +446,10 @@ void hashtable_destroy(struct hashtable * htable, int free_values) {
        tmp = cursor; 
        cursor = cursor->next; 
 
-       freekey(tmp->key); 
-       V3_Free(tmp->value); 
+       if (free_keys) {
+         freekey((void *)(tmp->key)); 
+       }
+       V3_Free((void *)(tmp->value)); 
        V3_Free(tmp); 
       }
     }
@@ -455,8 +462,10 @@ void hashtable_destroy(struct hashtable * htable, int free_values) {
 
        tmp = cursor; 
        cursor = cursor->next; 
-
-       freekey(tmp->key); 
+       
+       if (free_keys) {
+         freekey((void *)(tmp->key)); 
+       }
        V3_Free(tmp); 
       }
     }
@@ -505,11 +514,11 @@ struct hashtable_iter * create_hashtable_iterator(struct hashtable * htable) {
 }
 
 
-void * hashtable_get_iter_key(struct hashtable_iter * iter) {
+addr_t hashtable_get_iter_key(struct hashtable_iter * iter) {
   return iter->entry->key; 
 }
 
-void * hashtable_get_iter_value(struct hashtable_iter * iter) { 
+addr_t hashtable_get_iter_value(struct hashtable_iter * iter) { 
   return iter->entry->value; 
 }
 
@@ -566,7 +575,7 @@ int hashtable_iterator_advance(struct hashtable_iter * iter) {
  *          If you want the value, read it before you remove:
  *          beware memory leaks if you don't.
  *          Returns zero if end of iteration. */
-int hashtable_iterator_remove(struct hashtable_iter * iter) {
+int hashtable_iterator_remove(struct hashtable_iter * iter, int free_key) {
   struct hash_entry * remember_entry; 
   struct hash_entry * remember_parent;
   int ret;
@@ -584,8 +593,10 @@ int hashtable_iterator_remove(struct hashtable_iter * iter) {
   /* itr->e is now outside the hashtable */
   remember_entry = iter->entry;
   iter->htable->entry_count--;
-  freekey(remember_entry->key);
-  
+  if (free_key) {
+    freekey((void *)(remember_entry->key));
+  }
+
   /* Advance the iterator, correcting the parent */
   remember_parent = iter->parent;
   ret = hashtable_iterator_advance(iter);
@@ -601,7 +612,7 @@ int hashtable_iterator_remove(struct hashtable_iter * iter) {
 
 /* returns zero if not found */
 int hashtable_iterator_search(struct hashtable_iter * iter,
-                             struct hashtable * htable, void * key) {
+                             struct hashtable * htable, addr_t key) {
   struct hash_entry * entry;
   struct hash_entry * parent;
   uint_t hash_value;
index d8900df..d62fcf5 100644 (file)
@@ -5,7 +5,7 @@
 #include <palacios/vm_guest_mem.h>
 
 
-extern struct vmm_os_hooks * os_hooks;
+
 
 void delete_page_tables_pde32(pde32_t * pde) {
   int i;//, j;
@@ -26,12 +26,12 @@ void delete_page_tables_pde32(pde32_t * pde) {
        }
       */
       //PrintDebug("Deleting PTE %d (%x)\n", i, pte);
-      os_hooks->free_page(pte);
+      V3_FreePage(pte);
     }
   }
 
   //  PrintDebug("Deleting PDE (%x)\n", pde);
-  os_hooks->free_page(pde);
+  V3_FreePage(pde);
 }
 
 
@@ -150,11 +150,11 @@ pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info) {
   int i, j;
   struct shadow_map * map = &(guest_info->mem_map);
 
-  pde32_t * pde = os_hooks->allocate_pages(1);
+  pde32_t * pde = V3_AllocPages(1);
 
   for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
     int pte_present = 0;
-    pte32_t * pte = os_hooks->allocate_pages(1);
+    pte32_t * pte = V3_AllocPages(1);
     
 
     for (j = 0; j < MAX_PTE32_ENTRIES; j++) {
@@ -205,7 +205,7 @@ pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info) {
     }
 
     if (pte_present == 0) { 
-      os_hooks->free_page(pte);
+      V3_FreePage(pte);
 
       pde[i].present = 0;
       pde[i].writable = 0;
index bc5441b..7dc6422 100644 (file)
 
 
 
+
+
+DEFINE_HASHTABLE_INSERT(add_cr3_to_cache, addr_t, struct hashtable *);
+DEFINE_HASHTABLE_SEARCH(find_cr3_in_cache, addr_t, struct hashtable *);
+DEFINE_HASHTABLE_REMOVE(del_cr3_from_cache, addr_t, struct hashtable *, 0);
+
+
+DEFINE_HASHTABLE_INSERT(add_pte_map, addr_t, addr_t);
+DEFINE_HASHTABLE_SEARCH(find_pte_map, addr_t, addr_t);
+DEFINE_HASHTABLE_REMOVE(del_pte_map, addr_t, addr_t, 0);
+
+
+
+
+static uint_t pte_hash_fn(addr_t key) {
+  return hash_long(key, 32);
+}
+
+static int pte_equals(addr_t key1, addr_t key2) {
+  return (key1 == key2);
+}
+
+static uint_t cr3_hash_fn(addr_t key) {
+  return hash_long(key, 32);
+}
+
+static int cr3_equals(addr_t key1, addr_t key2) {
+  return (key1 == key2);
+}
+
+
 static int handle_shadow_pte32_fault(struct guest_info* info, 
                                     addr_t fault_addr, 
                                     pf_error_t error_code,
@@ -33,12 +64,116 @@ int init_shadow_page_state(struct guest_info * info) {
   state->guest_cr3 = 0;
   state->shadow_cr3 = 0;
 
+
+  state->cr3_cache = create_hashtable(0, &cr3_hash_fn, &cr3_equals);
+
+  state->cached_cr3 = 0;
+  state->cached_ptes = NULL;
+
   return 0;
 }
 
 
 
 
+/*
+ For now we'll do something a little more lightweight
+int cache_page_tables32(struct guest_info * info, addr_t pde) {
+  struct shadow_page_state * state = &(info->shdw_pg_state);
+  addr_t pde_host_addr;
+  pde32_t * tmp_pde;
+  struct hashtable * pte_cache = NULL;
+  int i = 0;
+
+
+  pte_cache = (struct hashtable *)find_cr3_in_cache(state->cr3_cache, pde);
+  if (pte_cache != NULL) {
+    PrintError("CR3 already present in cache\n");
+    state->current_ptes = pte_cache;
+    return 1;
+  } else {
+    PrintError("Creating new CR3 cache entry\n");
+    pte_cache = create_hashtable(0, &pte_hash_fn, &pte_equals);
+    state->current_ptes = pte_cache;
+    add_cr3_to_cache(state->cr3_cache, pde, pte_cache);
+  }
+
+  if (guest_pa_to_host_va(info, pde, &pde_host_addr) == -1) {
+    PrintError("Could not lookup host address of guest PDE\n");
+    return -1;
+  }
+
+  tmp_pde = (pde32_t *)pde_host_addr;
+
+  add_pte_map(pte_cache, pde, pde_host_addr);
+
+
+  for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
+    if ((tmp_pde[i].present) && (tmp_pde[i].large_page == 0)) {
+      addr_t pte_host_addr;
+
+      if (guest_pa_to_host_va(info, (addr_t)(PDE32_T_ADDR(tmp_pde[i])), &pte_host_addr) == -1) {
+       PrintError("Could not lookup host address of guest PDE\n");
+       return -1;
+      }
+
+      add_pte_map(pte_cache, (addr_t)(PDE32_T_ADDR(tmp_pde[i])), pte_host_addr); 
+    }
+  }
+
+
+  return 0;
+}
+*/
+
+int cache_page_tables32(struct guest_info * info, addr_t pde) {
+  struct shadow_page_state * state = &(info->shdw_pg_state);
+  addr_t pde_host_addr;
+  pde32_t * tmp_pde;
+  struct hashtable * pte_cache = NULL;
+  int i = 0;
+
+  if (pde == state->cached_cr3) {
+    return 1;
+  }
+
+  if (state->cached_ptes != NULL) {
+    hashtable_destroy(state->cached_ptes, 0, 0);
+    state->cached_ptes = NULL;
+  }
+
+  state->cached_cr3 = pde;
+
+  pte_cache = create_hashtable(0, &pte_hash_fn, &pte_equals);
+  state->cached_ptes = pte_cache;
+
+  if (guest_pa_to_host_pa(info, pde, &pde_host_addr) == -1) {
+    PrintError("Could not lookup host address of guest PDE\n");
+    return -1;
+  }
+
+  tmp_pde = (pde32_t *)pde_host_addr;
+
+  add_pte_map(pte_cache, pde, pde_host_addr);
+
+
+  for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
+    if ((tmp_pde[i].present) && (tmp_pde[i].large_page == 0)) {
+      addr_t pte_host_addr;
+
+      if (guest_pa_to_host_pa(info, (addr_t)(PDE32_T_ADDR(tmp_pde[i])), &pte_host_addr) == -1) {
+       PrintError("Could not lookup host address of guest PDE\n");
+       return -1;
+      }
+
+      add_pte_map(pte_cache, (addr_t)(PDE32_T_ADDR(tmp_pde[i])), pte_host_addr); 
+    }
+  }
+
+  return 0;
+
+}
+
 
 
 int v3_replace_shdw_page32(struct guest_info * info, addr_t location, pte32_t * new_page, pte32_t * old_page) {
@@ -173,6 +308,7 @@ static int handle_large_pagefault32(struct guest_info * info,
     }
 
     if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
+      struct shadow_page_state * state = &(info->shdw_pg_state);
       addr_t shadow_pa = get_shadow_addr(info, guest_fault_pa);
 
       shadow_pte->page_base_addr = PT32_BASE_ADDR(shadow_pa);
@@ -185,7 +321,16 @@ static int handle_large_pagefault32(struct guest_info * info,
        * Allow everything
        */
       shadow_pte->user_page = 1;
-      shadow_pte->writable = 1;
+
+      if (find_pte_map(state->cached_ptes, PT32_PAGE_ADDR(guest_fault_pa)) != NULL) {
+       // Check if the entry is a page table...
+       PrintDebug("Marking page as Guest Page Table (large page)\n");
+       shadow_pte->vmm_info = PT32_GUEST_PT;
+       shadow_pte->writable = 0;
+      } else {
+       shadow_pte->writable = 1;
+      }
+
 
       //set according to VMM policy
       shadow_pte->write_through = 0;
@@ -200,6 +345,14 @@ static int handle_large_pagefault32(struct guest_info * info,
        return -1;
       }
     }
+  } else if ((shadow_pte_access == PT_WRITE_ERROR) && 
+            (shadow_pte->vmm_info == PT32_GUEST_PT)) {
+
+    struct shadow_page_state * state = &(info->shdw_pg_state);
+    PrintDebug("Write operation on Guest PAge Table Page (large page)\n");
+    state->cached_cr3 = 0;
+    shadow_pte->writable = 1;
+
   } else {
     PrintError("Error in large page fault handler...\n");
     PrintError("This case should have been handled at the top level handler\n");
@@ -307,6 +460,7 @@ static int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr
       // Page Directory Entry marked read-only
       // Its a large page and we need to update the dirty bit in the guest
       //
+
       PrintDebug("Large page write error... Setting dirty bit and returning\n");
       ((pde32_4MB_t *)guest_pde)->dirty = 1;
       shadow_pde->writable = guest_pde->writable;
@@ -408,6 +562,7 @@ static int handle_shadow_pte32_fault(struct guest_info * info,
     // else...
 
     if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
+      struct shadow_page_state * state = &(info->shdw_pg_state);
       addr_t shadow_pa = get_shadow_addr(info, guest_pa);
       
       shadow_pte->page_base_addr = PT32_BASE_ADDR(shadow_pa);
@@ -423,14 +578,31 @@ static int handle_shadow_pte32_fault(struct guest_info * info,
       
       guest_pte->accessed = 1;
       
+      if (find_pte_map(state->cached_ptes, PT32_PAGE_ADDR(guest_pa)) != NULL) {
+       // Check if the entry is a page table...
+       PrintDebug("Marking page as Guest Page Table\n", shadow_pte->writable);
+       shadow_pte->vmm_info = PT32_GUEST_PT;
+      }
+
       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;
+       
+       if (shadow_pte->vmm_info == PT32_GUEST_PT) {
+         // Well that was quick...
+         struct shadow_page_state * state = &(info->shdw_pg_state);
+         PrintDebug("Immediate Write operation on Guest PAge Table Page\n");
+         state->cached_cr3 = 0;
+       }
+
       } else if ((guest_pte->dirty = 0) && (error_code.write == 0)) {
        shadow_pte->writable = 0;
       }
+
+
+
     } else {
       // Page fault handled by hook functions
       if (handle_special_page_fault(info, fault_addr, guest_pa, error_code) == -1) {
@@ -445,6 +617,13 @@ static int handle_shadow_pte32_fault(struct guest_info * info,
     PrintDebug("Shadow PTE Write Error\n");
     guest_pte->dirty = 1;
     shadow_pte->writable = guest_pte->writable;
+
+    if (shadow_pte->vmm_info == PT32_GUEST_PT) {
+      struct shadow_page_state * state = &(info->shdw_pg_state);
+      PrintDebug("Write operation on Guest PAge Table Page\n");
+      state->cached_cr3 = 0;
+    }
+    
     return 0;
 
   } else {