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.


Added support for using large shadow pages with 32-bit 4MB page table entries
[palacios.git] / palacios / src / palacios / mmu / vmm_shdw_pg_tlb_32.h
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21
22
23 static inline int activate_shadow_pt_32(struct guest_info * core) {
24     struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(core->ctrl_regs.cr3);
25     struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(core->shdw_pg_state.guest_cr3);
26     struct shadow_page_data * shdw_page = create_new_shadow_pt(core);
27
28     shdw_page->cr3 = shdw_page->page_pa;
29     
30     shadow_cr3->pdt_base_addr = PAGE_BASE_ADDR_4KB(shdw_page->page_pa);
31     PrintDebug( "Created new shadow page table %p\n", (void *)BASE_TO_PAGE_ADDR(shadow_cr3->pdt_base_addr));
32   
33     shadow_cr3->pwt = guest_cr3->pwt;
34     shadow_cr3->pcd = guest_cr3->pcd;
35
36     return 0;
37 }
38
39
40
41
42 /* 
43  * *
44  * * 
45  * * 32 bit Page table fault handlers
46  * *
47  * *
48  */
49 static int handle_4MB_shadow_pagefault_pde_32(struct guest_info * info,  addr_t fault_addr, pf_error_t error_code, 
50                                               pt_access_status_t shadow_pde_access, pde32_4MB_t * large_shadow_pde, 
51                                               pde32_4MB_t * large_guest_pde);
52 static int handle_4MB_shadow_pagefault_pte_32(struct guest_info * info,  addr_t fault_addr, pf_error_t error_code, 
53                                               pte32_t * shadow_pt, pde32_4MB_t * large_guest_pde);
54
55 static int handle_pte_shadow_pagefault_32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
56                                           pte32_t * shadow_pt,  pte32_t * guest_pt);
57
58
59 static inline int handle_shadow_pagefault_32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
60     pde32_t * guest_pd = NULL;
61     pde32_t * shadow_pd = CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
62     addr_t guest_cr3 = CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3);
63     pt_access_status_t guest_pde_access;
64     pt_access_status_t shadow_pde_access;
65     pde32_t * guest_pde = NULL;
66     pde32_t * shadow_pde = (pde32_t *)&(shadow_pd[PDE32_INDEX(fault_addr)]);
67
68     PrintDebug("Shadow page fault handler: %p\n", (void*) fault_addr );
69     PrintDebug("Handling PDE32 Fault\n");
70
71     if (v3_gpa_to_hva(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
72         PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
73         return -1;
74     } 
75
76     guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(fault_addr)]);
77
78
79     // Check the guest page permissions
80     guest_pde_access = v3_can_access_pde32(guest_pd, fault_addr, error_code);
81
82     // Check the shadow page permissions
83     shadow_pde_access = v3_can_access_pde32(shadow_pd, fault_addr, error_code);
84   
85     /* Was the page fault caused by the Guest's page tables? */
86     if (v3_is_guest_pf(guest_pde_access, shadow_pde_access) == 1) {
87         PrintDebug("Injecting PDE pf to guest: (guest access error=%d) (shdw access error=%d)  (pf error code=%d)\n", 
88                    *(uint_t *)&guest_pde_access, *(uint_t *)&shadow_pde_access, *(uint_t *)&error_code);
89         if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
90             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
91             return -1;
92         }
93         return 0;
94     }
95
96
97
98     if (shadow_pde_access == PT_ACCESS_USER_ERROR) {
99         // 
100         // PDE Entry marked non user
101         //
102         PrintDebug("Shadow Paging User access error (shadow_pde_access=0x%x, guest_pde_access=0x%x)\n", 
103                    shadow_pde_access, guest_pde_access);
104         
105         if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
106             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
107             return -1;
108         }
109         return 0;
110     } else if ((shadow_pde_access == PT_ACCESS_WRITE_ERROR) && 
111                (guest_pde->large_page == 1)) {
112         
113         ((pde32_4MB_t *)guest_pde)->dirty = 1;
114         shadow_pde->writable = guest_pde->writable;
115         return 0;
116     } else if ((shadow_pde_access != PT_ACCESS_NOT_PRESENT) &&
117                (shadow_pde_access != PT_ACCESS_OK)) {
118         // inject page fault in guest
119         if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
120             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
121             return -1;
122         }
123         PrintDebug("Unknown Error occurred (shadow_pde_access=%d)\n", shadow_pde_access);
124         PrintDebug("Manual Says to inject page fault into guest\n");
125         return 0;
126     }
127
128   
129     pte32_t * shadow_pt = NULL;
130     pte32_t * guest_pt = NULL;
131
132     // Get the next shadow page level, allocate if not present
133
134     if (shadow_pde_access == PT_ACCESS_NOT_PRESENT) {
135
136         if (info->use_large_pages && guest_pde->large_page) {
137             // Check underlying physical memory map to see if a large page is viable
138             addr_t guest_pa = BASE_TO_PAGE_ADDR_4MB(((pde32_4MB_t *)guest_pde)->page_base_addr);
139             addr_t host_pa;
140             if (v3_get_max_page_size(info, guest_pa, PAGE_SIZE_4MB) < PAGE_SIZE_4MB) {
141                 PrintDebug("Underlying physical memory map doesn't allow use of a large page.\n");
142                 // Fallthrough to small pages
143             } else if ((v3_gpa_to_hpa(info, guest_pa, &host_pa) != 0)
144                        || (v3_compute_page_alignment(host_pa) < PAGE_SIZE_4MB)) {
145                 PrintDebug("Host memory alignment doesn't allow use of a large page.\n");
146                 // Fallthrough to small pages
147             } else if (handle_4MB_shadow_pagefault_pde_32(info, fault_addr, error_code, shadow_pde_access,
148                                                           (pde32_4MB_t *)shadow_pde, (pde32_4MB_t *)guest_pde) == 0) {
149                 return 0;
150             } else {
151                 PrintError("Error handling large pagefault with large page\n");
152                 return -1;
153             }
154             // Fallthrough to handle the region with small pages
155         }
156
157         struct shadow_page_data * shdw_page =  create_new_shadow_pt(info);
158         shadow_pt = (pte32_t *)V3_VAddr((void *)shdw_page->page_pa);
159
160         shadow_pde->present = 1;
161         shadow_pde->user_page = guest_pde->user_page;
162
163
164         if (guest_pde->large_page == 0) {
165             shadow_pde->writable = guest_pde->writable;
166         } else {
167             // This large page flag is temporary until we can get a working cache....
168             ((pde32_4MB_t *)guest_pde)->vmm_info = V3_LARGE_PG;
169
170             if (error_code.write) {
171                 shadow_pde->writable = guest_pde->writable;
172                 ((pde32_4MB_t *)guest_pde)->dirty = 1;
173             } else {
174                 shadow_pde->writable = 0;
175                 ((pde32_4MB_t *)guest_pde)->dirty = 0;
176             }
177         }
178       
179
180         // VMM Specific options
181         shadow_pde->write_through = guest_pde->write_through;
182         shadow_pde->cache_disable = guest_pde->cache_disable;
183         shadow_pde->global_page = guest_pde->global_page;
184         //
185       
186         guest_pde->accessed = 1;
187       
188
189         shadow_pde->pt_base_addr = PAGE_BASE_ADDR(shdw_page->page_pa);
190     } else {
191         shadow_pt = (pte32_t *)V3_VAddr((void *)BASE_TO_PAGE_ADDR(shadow_pde->pt_base_addr));
192     }
193
194
195       
196     if (guest_pde->large_page == 0) {
197         if (v3_gpa_to_hva(info, BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr), (addr_t*)&guest_pt) == -1) {
198             // Machine check the guest
199             PrintDebug("Invalid Guest PTE Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr));
200             v3_raise_exception(info, MC_EXCEPTION);
201             return 0;
202         }
203
204         if (handle_pte_shadow_pagefault_32(info, fault_addr, error_code, shadow_pt, guest_pt)  == -1) {
205             PrintError("Error handling Page fault caused by PTE\n");
206             return -1;
207         }
208     } else {
209         if (handle_4MB_shadow_pagefault_pte_32(info, fault_addr, error_code, shadow_pt, (pde32_4MB_t *)guest_pde) == -1) {
210             PrintError("Error handling large pagefault\n");
211             return -1;
212         }       
213     }
214
215     return 0;
216 }
217
218
219 static int handle_pte_shadow_pagefault_32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
220                                           pte32_t * shadow_pt, pte32_t * guest_pt) {
221
222     pt_access_status_t guest_pte_access;
223     pt_access_status_t shadow_pte_access;
224     pte32_t * guest_pte = (pte32_t *)&(guest_pt[PTE32_INDEX(fault_addr)]);;
225     pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
226     addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) +  PAGE_OFFSET(fault_addr);
227
228     struct v3_mem_region * shdw_reg =  v3_get_mem_region(info->vm_info, info->cpu_id, guest_pa);
229
230     if (shdw_reg == NULL) {
231         // Inject a machine check in the guest
232         PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_pa);
233         v3_raise_exception(info, MC_EXCEPTION);
234         return 0;
235     }
236
237     // Check the guest page permissions
238     guest_pte_access = v3_can_access_pte32(guest_pt, fault_addr, error_code);
239
240     // Check the shadow page permissions
241     shadow_pte_access = v3_can_access_pte32(shadow_pt, fault_addr, error_code);
242   
243   
244     /* Was the page fault caused by the Guest's page tables? */
245     if (v3_is_guest_pf(guest_pte_access, shadow_pte_access) == 1) {
246
247         PrintDebug("Access error injecting pf to guest (guest access error=%d) (pf error code=%d)\n", 
248                    guest_pte_access, *(uint_t*)&error_code);
249         
250
251         //   inject:
252         if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
253             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
254             return -1;
255         }       
256
257         return 0; 
258     }
259
260   
261   
262     if (shadow_pte_access == PT_ACCESS_OK) {
263         // Inconsistent state...
264         // Guest Re-Entry will flush page tables and everything should now work
265         PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
266         return 0;
267     }
268
269
270     if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
271         // Page Table Entry Not Present
272         PrintDebug("guest_pa =%p\n", (void *)guest_pa);
273
274         if ((shdw_reg->flags.alloced == 1) && (shdw_reg->flags.read == 1)) {
275             addr_t shadow_pa = 0;
276
277             if (v3_gpa_to_hpa(info, guest_pa, &shadow_pa) == -1) {
278                 PrintError("could not translate page fault address (%p)\n", (void *)guest_pa);
279                 return -1;
280             }
281
282             shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
283
284             PrintDebug("\tMapping shadow page (%p)\n", (void *)BASE_TO_PAGE_ADDR(shadow_pte->page_base_addr));
285       
286             shadow_pte->present = guest_pte->present;
287             shadow_pte->user_page = guest_pte->user_page;
288       
289             //set according to VMM policy
290             shadow_pte->write_through = guest_pte->write_through;
291             shadow_pte->cache_disable = guest_pte->cache_disable;
292             shadow_pte->global_page = guest_pte->global_page;
293             //
294       
295             guest_pte->accessed = 1;
296       
297             if (guest_pte->dirty == 1) {
298                 shadow_pte->writable = guest_pte->writable;
299             } else if ((guest_pte->dirty == 0) && (error_code.write == 1)) {
300                 shadow_pte->writable = guest_pte->writable;
301                 guest_pte->dirty = 1;
302             } else if ((guest_pte->dirty == 0) && (error_code.write == 0)) {
303                 shadow_pte->writable = 0;
304             }
305
306
307             if (shdw_reg->flags.write == 0) {
308                 shadow_pte->writable = 0;
309             }
310
311         } else {
312             // Page fault on unhandled memory region
313             
314             if (shdw_reg->unhandled(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
315                 PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
316                 return -1;
317             }
318         }
319     } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
320         guest_pte->dirty = 1;
321
322         if (shdw_reg->flags.write == 1) {
323             PrintDebug("Shadow PTE Write Error\n");
324             shadow_pte->writable = guest_pte->writable;
325         } else {
326             if (shdw_reg->unhandled(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
327                 PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
328                 return -1;
329             }
330         }
331
332
333         return 0;
334
335     } else {
336         // Inject page fault into the guest     
337         if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
338             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
339             return -1;
340         }
341
342         PrintError("PTE Page fault fell through... Not sure if this should ever happen\n");
343         PrintError("Manual Says to inject page fault into guest\n");
344         return -1;
345     }
346
347     return 0;
348 }
349
350 // Handle a 4MB page fault with small pages in the PTE
351 static int handle_4MB_shadow_pagefault_pte_32(struct guest_info * info, 
352                                      addr_t fault_addr, pf_error_t error_code, 
353                                      pte32_t * shadow_pt, pde32_4MB_t * large_guest_pde) 
354 {
355     pt_access_status_t shadow_pte_access = v3_can_access_pte32(shadow_pt, fault_addr, error_code);
356     pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
357     addr_t guest_fault_pa = BASE_TO_PAGE_ADDR_4MB(large_guest_pde->page_base_addr) + PAGE_OFFSET_4MB(fault_addr);  
358
359
360     PrintDebug("Handling 4MB fault (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
361     PrintDebug("ShadowPT=%p, LargeGuestPDE=%p\n", shadow_pt, large_guest_pde);
362
363     struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->cpu_id, guest_fault_pa);
364
365  
366     if (shdw_reg == NULL) {
367         // Inject a machine check in the guest
368         PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_fault_pa);
369         v3_raise_exception(info, MC_EXCEPTION);
370         return -1;
371     }
372
373     if (shadow_pte_access == PT_ACCESS_OK) {
374         // Inconsistent state...
375         // Guest Re-Entry will flush tables and everything should now workd
376         PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
377         return 0;
378     }
379
380   
381     if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
382         // Get the guest physical address of the fault
383
384         if ((shdw_reg->flags.alloced == 1) && 
385             (shdw_reg->flags.read  == 1)) {
386             addr_t shadow_pa = 0;
387
388
389             if (v3_gpa_to_hpa(info, guest_fault_pa, &shadow_pa) == -1) {
390                 PrintError("could not translate page fault address (%p)\n", (void *)guest_fault_pa);
391                 return -1;
392             }
393
394             shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
395
396             PrintDebug("\tMapping shadow page (%p)\n", (void *)BASE_TO_PAGE_ADDR(shadow_pte->page_base_addr));
397
398             shadow_pte->present = 1;
399
400             /* We are assuming that the PDE entry has precedence
401              * so the Shadow PDE will mirror the guest PDE settings, 
402              * and we don't have to worry about them here
403              * Allow everything
404              */
405             shadow_pte->user_page = 1;
406
407             //set according to VMM policy
408             shadow_pte->write_through = large_guest_pde->write_through;
409             shadow_pte->cache_disable = large_guest_pde->cache_disable;
410             shadow_pte->global_page = large_guest_pde->global_page;
411             //
412       
413
414             if (shdw_reg->flags.write == 0) {
415                 shadow_pte->writable = 0;
416             } else {
417                 shadow_pte->writable = 1;
418             }
419
420         } else {
421             if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
422                 PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
423                 return -1;
424             }
425         }
426     } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
427
428         if (shdw_reg->flags.write == 0) {
429             if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
430                 PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
431                 return -1;
432             }
433         }
434
435     } else {
436         PrintError("Error in large page fault handler...\n");
437         PrintError("This case should have been handled at the top level handler\n");
438         return -1;
439     }
440
441     PrintDebug("Returning from large page->small page fault handler\n");
442     return 0;
443 }
444
445
446 // Handle a 4MB page fault with a 4MB page in the PDE
447 static int handle_4MB_shadow_pagefault_pde_32(struct guest_info * info, 
448                                      addr_t fault_addr, pf_error_t error_code, 
449                                      pt_access_status_t shadow_pde_access,
450                                      pde32_4MB_t * large_shadow_pde, pde32_4MB_t * large_guest_pde) 
451 {
452     addr_t guest_fault_pa = BASE_TO_PAGE_ADDR_4MB(large_guest_pde->page_base_addr) + PAGE_OFFSET_4MB(fault_addr);  
453
454
455     PrintDebug("Handling 4MB fault with large page (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
456     PrintDebug("LargeShadowPDE=%p, LargeGuestPDE=%p\n", large_shadow_pde, large_guest_pde);
457
458     struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->cpu_id, guest_fault_pa);
459
460  
461     if (shdw_reg == NULL) {
462         // Inject a machine check in the guest
463         PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_fault_pa);
464         v3_raise_exception(info, MC_EXCEPTION);
465         return -1;
466     }
467
468     if (shadow_pde_access == PT_ACCESS_OK) {
469         // Inconsistent state...
470         // Guest Re-Entry will flush tables and everything should now workd
471         PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
472         return 0;
473     }
474
475   
476     if (shadow_pde_access == PT_ACCESS_NOT_PRESENT) {
477         // Get the guest physical address of the fault
478
479         if ((shdw_reg->flags.alloced == 1) && 
480             (shdw_reg->flags.read  == 1)) {
481             addr_t shadow_pa = 0;
482
483
484             if (v3_gpa_to_hpa(info, guest_fault_pa, &shadow_pa) == -1) {
485                 PrintError("could not translate page fault address (%p)\n", (void *)guest_fault_pa);
486                 return -1;
487             }
488
489             PrintDebug("\tMapping shadow page (%p)\n", (void *)BASE_TO_PAGE_ADDR(shadow_pte->page_base_addr));
490
491             large_guest_pde->vmm_info = V3_LARGE_PG; /* For invalidations */
492             large_shadow_pde->page_base_addr = PAGE_BASE_ADDR_4MB(shadow_pa);
493             large_shadow_pde->large_page = 1;
494             large_shadow_pde->present = 1;
495             large_shadow_pde->user_page = 1;
496
497             if (shdw_reg->flags.write == 0) {
498                 large_shadow_pde->writable = 0;
499             } else {
500                 large_shadow_pde->writable = 1;
501             }
502
503             //set according to VMM policy
504             large_shadow_pde->write_through = large_guest_pde->write_through;
505             large_shadow_pde->cache_disable = large_guest_pde->cache_disable;
506             large_shadow_pde->global_page = large_guest_pde->global_page;
507             //
508
509         } else {
510             if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
511                 PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
512                 return -1;
513             }
514         }
515     } else if (shadow_pde_access == PT_ACCESS_WRITE_ERROR) {
516
517         if (shdw_reg->flags.write == 0) {
518             if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
519                 PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
520                 return -1;
521             }
522         }
523
524     } else {
525         PrintError("Error in large page fault handler...\n");
526         PrintError("This case should have been handled at the top level handler\n");
527         return -1;
528     }
529
530     PrintDebug("Returning from large page->large page fault handler\n");
531     return 0;
532 }
533
534 /* If we start to optimize we should look up the guest pages in the cache... */
535 static inline int handle_shadow_invlpg_32(struct guest_info * info, addr_t vaddr) {
536     pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
537     pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(vaddr)];
538
539     addr_t guest_cr3 =  CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3);
540     pde32_t * guest_pd = NULL;
541     pde32_t * guest_pde;
542
543     if (v3_gpa_to_hva(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
544         PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
545         return -1;
546     }
547   
548     guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(vaddr)]);
549   
550     if (guest_pde->large_page == 1) {
551         shadow_pde->present = 0;
552         PrintDebug("Invalidating Large Page\n");
553     } else if (shadow_pde->present == 1) {
554         pte32_t * shadow_pt = (pte32_t *)(addr_t)BASE_TO_PAGE_ADDR_4KB(shadow_pde->pt_base_addr);
555         pte32_t * shadow_pte = (pte32_t *) V3_VAddr( (void*) &shadow_pt[PTE32_INDEX(vaddr)] );
556     
557         PrintDebug("Setting not present\n");
558     
559         shadow_pte->present = 0;
560     }
561     return 0;
562 }