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.


changed debug output to be more granular
[palacios.git] / palacios / src / palacios / vmm_shadow_paging.c
1 #include <palacios/vmm_shadow_paging.h>
2
3
4 #include <palacios/vmm.h>
5 #include <palacios/vm_guest_mem.h>
6 #include <palacios/vmm_decoder.h>
7
8 #ifndef DEBUG_SHADOW_PAGING
9 #undef PrintDebug
10 #define PrintDebug(fmt, args...)
11 #endif
12
13
14 int init_shadow_page_state(struct shadow_page_state * state) {
15   state->guest_mode = PDE32;
16   state->shadow_mode = PDE32;
17   
18   state->guest_cr3 = 0;
19   state->shadow_cr3 = 0;
20
21   return 0;
22 }
23
24 int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
25   
26   if (info->mem_mode == PHYSICAL_MEM) {
27     // If paging is not turned on we need to handle the special cases
28     return handle_special_page_fault(info, fault_addr, error_code);
29   } else if (info->mem_mode == VIRTUAL_MEM) {
30
31     switch (info->cpu_mode) {
32     case PROTECTED:
33       return handle_shadow_pagefault32(info, fault_addr, error_code);
34       break;
35     case PROTECTED_PAE:
36     case LONG:
37     default:
38       PrintError("Unhandled CPU Mode\n");
39       return -1;
40     }
41   } else {
42     PrintError("Invalid Memory mode\n");
43     return -1;
44   }
45 }
46
47 addr_t create_new_shadow_pt32(struct guest_info * info) {
48   void * host_pde = 0;
49
50   V3_AllocPages(host_pde, 1);
51   memset(host_pde, 0, PAGE_SIZE);
52
53   return (addr_t)host_pde;
54 }
55
56
57 static int handle_pd32_nonaligned_4MB_page(struct guest_info * info, pte32_t * pt, addr_t guest_addr, pde32_4MB_t * large_shadow_pde) {
58   uint_t i = 0;
59   pte32_t * pte_cursor;
60   addr_t guest_pa = 0;
61
62   for (i = 0; i < 1024; i++) {
63     guest_pa = guest_addr + (PAGE_SIZE * i);
64     host_region_type_t host_page_type = get_shadow_addr_type(info, guest_pa);
65     
66     pte_cursor = &(pt[i]);
67
68     if (host_page_type == HOST_REGION_INVALID) {
69       // Currently we don't support this, but in theory we could
70       PrintError("Invalid Host Memory Type\n");
71       return -1;
72     } else if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
73       addr_t shadow_pa = get_shadow_addr(info, guest_pa);
74
75
76       pte_cursor->page_base_addr = PT32_BASE_ADDR(shadow_pa);
77       pte_cursor->present = 1;
78       pte_cursor->writable = large_shadow_pde->writable;
79       pte_cursor->user_page = large_shadow_pde->user_page;
80       pte_cursor->write_through = 0;  
81       pte_cursor->cache_disable = 0;
82       pte_cursor->global_page = 0;
83
84     } else {
85       PrintError("Unsupported Host Memory Type\n");
86       return -1;
87     }
88   }
89   return 0;
90 }
91
92 int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
93   pde32_t * guest_pd = NULL;
94   pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32(info->shdw_pg_state.shadow_cr3);
95   addr_t guest_cr3 = CR3_TO_PDE32(info->shdw_pg_state.guest_cr3);
96   pt_access_status_t guest_pde_access;
97   pt_access_status_t shadow_pde_access;
98   pde32_t * guest_pde = NULL;
99   pde32_t * shadow_pde = (pde32_t *)&(shadow_pd[PDE32_INDEX(fault_addr)]);
100
101   if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
102     PrintError("Invalid Guest PDE Address: 0x%x\n", guest_cr3);
103     return -1;
104   }
105
106
107   guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(fault_addr)]);
108
109   // Check the guest page permissions
110   guest_pde_access = can_access_pde32(guest_pd, fault_addr, error_code);
111
112   // Check the shadow page permissions
113   shadow_pde_access = can_access_pde32(shadow_pd, fault_addr, error_code);
114   
115   /* This should be redone, 
116      but basically the reasoning is that there can be multiple reasons for a page fault:
117      If there is a permissions failure for a page present in the guest _BUT_ 
118      the reason for the fault was that the page is not present in the shadow, 
119      _THEN_ we have to map the shadow page in and reexecute, this will generate 
120      a permissions fault which is _THEN_ valid to send to the guest
121      _UNLESS_ both the guest and shadow have marked the page as not present
122
123      whew...
124   */
125   if ((guest_pde_access != PT_ACCESS_OK) &&
126       (
127        ( (shadow_pde_access != PT_ENTRY_NOT_PRESENT) &&
128          (guest_pde_access != PT_ENTRY_NOT_PRESENT))  // aka (guest permission error)
129        || 
130        ( (shadow_pde_access == PT_ENTRY_NOT_PRESENT) && 
131         (guest_pde_access == PT_ENTRY_NOT_PRESENT)))) {
132     // inject page fault to the guest (Guest PDE fault)
133
134         info->ctrl_regs.cr2 = fault_addr;
135     raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
136
137
138     PrintDebug("Injecting PDE pf to guest: (guest access error=%d) (pf error code=%d)\n", guest_pde_access, error_code);
139     return 0;
140
141  
142 #ifdef DEBUG_SHADOW_PAGING
143         PrintDebug("Guest CR3=%x\n", guest_cr3);
144         PrintDebug("Guest PD\n");
145         PrintPD32(guest_pd);
146         PrintDebug("Shadow PD\n");
147         PrintPD32(shadow_pd);
148 #endif
149
150     return -1;
151   }
152
153
154   //shadow_pde_access = can_access_pde32(shadow_pd, fault_addr, error_code);
155
156
157   if (shadow_pde_access == PT_ENTRY_NOT_PRESENT) {
158
159     shadow_pde->present = 1;
160     shadow_pde->user_page = guest_pde->user_page;
161     shadow_pde->large_page = guest_pde->large_page;
162
163
164     // VMM Specific options
165     shadow_pde->write_through = 0;
166     shadow_pde->cache_disable = 0;
167     shadow_pde->global_page = 0;
168     //
169
170     guest_pde->accessed = 1;
171     
172     if (guest_pde->large_page == 0) {
173       pte32_t * shadow_pt = NULL;
174       
175       V3_AllocPages(shadow_pt, 1);
176       memset(shadow_pt, 0, PAGE_SIZE);
177       
178       shadow_pde->pt_base_addr = PD32_BASE_ADDR(shadow_pt);
179
180       shadow_pde->writable = guest_pde->writable;
181     } else {
182       struct shadow_region * mem_reg;
183       pde32_4MB_t * large_guest_pde = (pde32_4MB_t *)guest_pde;
184       pde32_4MB_t * large_shadow_pde = (pde32_4MB_t *)shadow_pde;
185       host_region_type_t host_page_type;
186       addr_t guest_start_addr = PDE32_4MB_T_ADDR(*large_guest_pde);
187       //    addr_t guest_end_addr = guest_start_addr + PAGE_SIZE_4MB; // start address + 4MB
188
189
190       // Check that the Guest PDE entry points to valid memory
191       // else Machine Check the guest
192       PrintDebug("Large Page: Page Base Addr=%x\n", guest_start_addr);
193
194       host_page_type = get_shadow_addr_type(info, guest_start_addr);
195
196       if (host_page_type == HOST_REGION_INVALID) {
197
198         raise_exception(info, MC_EXCEPTION);
199         PrintError("Invalid guest address in large page (0x%x)\n", guest_start_addr);
200         return -1;
201       } else if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
202         addr_t host_start_addr = 0;
203         addr_t region_end_addr = 0;
204
205         // Check for a large enough region in host memory
206         mem_reg = get_shadow_region_by_addr(&(info->mem_map), guest_start_addr);
207         PrintDebug("Host region: host_addr=%x (guest_start=%x, end=%x)\n", 
208                    mem_reg->host_addr, mem_reg->guest_start, mem_reg->guest_end);
209         host_start_addr = mem_reg->host_addr + (guest_start_addr - mem_reg->guest_start);
210         region_end_addr = mem_reg->host_addr + (mem_reg->guest_end - mem_reg->guest_start);
211
212         PrintDebug("Host Start Addr=%x; Region End Addr=%x\n", host_start_addr, region_end_addr);
213
214
215
216
217         //4f
218         if (large_guest_pde->dirty == 1) { // dirty
219           large_shadow_pde->writable = guest_pde->writable;
220         } else if (error_code.write == 1) { // not dirty, access is write
221           large_shadow_pde->writable = guest_pde->writable;
222           large_guest_pde->dirty = 1;
223         } else { // not dirty, access is read
224           large_shadow_pde->writable = 0;
225         }
226
227
228         // Check if the region is at least an additional 4MB
229
230
231         //4b.
232         if ((PD32_4MB_PAGE_OFFSET(host_start_addr) == 0) && 
233             (region_end_addr >= host_start_addr + PAGE_SIZE_4MB)) {     // if 4MB boundary
234           large_shadow_pde->page_base_addr = PD32_4MB_BASE_ADDR(host_start_addr);
235         } else {          // else generate 4k pages
236           pte32_t * shadow_pt = NULL;
237           PrintDebug("Handling non aligned large page\n");
238
239           shadow_pde->large_page = 0;
240       
241           V3_AllocPages(shadow_pt, 1);
242           memset(shadow_pt, 0, PAGE_SIZE);
243
244           if (handle_pd32_nonaligned_4MB_page(info, shadow_pt, guest_start_addr, large_shadow_pde) == -1) {
245             PrintError("Non Aligned Large Page Error\n");
246             V3_Free(shadow_pt);
247             return -1;
248           }
249
250
251 #ifdef DEBUG_SHADOW_PAGING
252             PrintDebug("non-aligned Shadow PT\n");
253             PrintPT32(PT32_PAGE_ADDR(fault_addr), shadow_pt);     
254 #endif
255           shadow_pde->pt_base_addr = PD32_BASE_ADDR(shadow_pt);
256         }
257
258         
259       } else {
260         // Handle hooked pages as well as other special pages
261         if (handle_special_page_fault(info, fault_addr, error_code) == -1) {
262           PrintError("Special Page Fault handler returned error for address: %x\n", fault_addr);
263           return -1;
264         }
265       }
266     }
267
268   } else if ((shadow_pde_access == PT_WRITE_ERROR) && 
269              (guest_pde->large_page = 1) && 
270              (((pde32_4MB_t *)guest_pde)->dirty == 0)) {
271
272     //
273     // Page Directory Entry marked read-only
274     //
275
276     ((pde32_4MB_t *)guest_pde)->dirty = 1;
277     shadow_pde->writable = guest_pde->writable;
278     return 0;
279
280   } else if (shadow_pde_access == PT_USER_ERROR) {
281
282     //
283     // Page Directory Entry marked non-user
284     //
285     
286     PrintDebug("Shadow Paging User access error (shadow_pde_access=0x%x, guest_pde_access=0x%x - injecting into guest\n", shadow_pde_access, guest_pde_access);
287     info->ctrl_regs.cr2 = fault_addr;
288     raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
289     return 0;
290
291   } else if (shadow_pde_access == PT_ACCESS_OK) {
292     pte32_t * shadow_pt = (pte32_t *)PDE32_T_ADDR((*shadow_pde));
293     pte32_t * guest_pt = NULL;
294
295     // Page Table Entry fault
296     
297     if (guest_pa_to_host_va(info, PDE32_T_ADDR((*guest_pde)), (addr_t*)&guest_pt) == -1) {
298       PrintDebug("Invalid Guest PTE Address: 0x%x\n", PDE32_T_ADDR((*guest_pde)));
299       // Machine check the guest
300
301       raise_exception(info, MC_EXCEPTION);
302       
303       return 0;
304     }
305
306
307     if (handle_shadow_pte32_fault(info, fault_addr, error_code, shadow_pt, guest_pt)  == -1) {
308       PrintError("Error handling Page fault caused by PTE\n");
309       return -1;
310     }
311
312  } else {
313     // Unknown error raise page fault in guest
314     info->ctrl_regs.cr2 = fault_addr;
315     raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
316
317     // For debugging we will return an error here for the time being, 
318     // this probably shouldn't ever happen
319     PrintDebug("Unknown Error occurred\n");
320     PrintDebug("Manual Says to inject page fault into guest\n");
321
322
323     return 0;
324
325   }
326
327   //PrintDebugPageTables(shadow_pd);
328   PrintDebug("Returning end of PDE function (rip=%x)\n", info->rip);
329   return 0;
330 }
331
332
333
334 /* 
335  * We assume the the guest pte pointer has already been translated to a host virtual address
336  */
337 int handle_shadow_pte32_fault(struct guest_info * info, 
338                               addr_t fault_addr, 
339                               pf_error_t error_code,
340                               pte32_t * shadow_pt, 
341                               pte32_t * guest_pt) {
342
343   pt_access_status_t guest_pte_access;
344   pt_access_status_t shadow_pte_access;
345   pte32_t * guest_pte = (pte32_t *)&(guest_pt[PTE32_INDEX(fault_addr)]);;
346   pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
347
348
349   // Check the guest page permissions
350   guest_pte_access = can_access_pte32(guest_pt, fault_addr, error_code);
351
352   // Check the shadow page permissions
353   shadow_pte_access = can_access_pte32(shadow_pt, fault_addr, error_code);
354   
355 #ifdef DEBUG_SHADOW_PAGING
356   PrintDebug("Guest PTE: (access=%d)\n\t", guest_pte_access);
357   PrintPTE32(fault_addr, guest_pte);
358   PrintDebug("Shadow PTE: (access=%d)\n\t", shadow_pte_access);
359   PrintPTE32(fault_addr, shadow_pte);
360 #endif
361   
362   /* This should be redone, 
363      but basically the reasoning is that there can be multiple reasons for a page fault:
364      If there is a permissions failure for a page present in the guest _BUT_ 
365      the reason for the fault was that the page is not present in the shadow, 
366      _THEN_ we have to map the shadow page in and reexecute, this will generate 
367      a permissions fault which is _THEN_ valid to send to the guest
368      _UNLESS_ both the guest and shadow have marked the page as not present
369
370      whew...
371   */
372   if ((guest_pte_access != PT_ACCESS_OK) && 
373       ( 
374        ((shadow_pte_access != PT_ENTRY_NOT_PRESENT) &&
375         (guest_pte_access != PT_ENTRY_NOT_PRESENT)) // aka (guest permission error)
376        ||
377        ((shadow_pte_access == PT_ENTRY_NOT_PRESENT) &&
378         (guest_pte_access == PT_ENTRY_NOT_PRESENT)))) {
379     // Inject page fault into the guest 
380     
381     info->ctrl_regs.cr2 = fault_addr;
382     raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
383     
384     PrintDebug("Access error injecting pf to guest (guest access error=%d) (pf error code=%d)\n", guest_pte_access, *(uint_t*)&error_code);
385     return 0; 
386   }
387   
388   
389
390
391   if (shadow_pte_access == PT_ACCESS_OK) {
392     // Inconsistent state...
393     // Guest Re-Entry will flush page tables and everything should now work
394     PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
395     return 0;
396   } else if (shadow_pte_access == PT_ENTRY_NOT_PRESENT) {
397     addr_t shadow_pa;
398     addr_t guest_pa = PTE32_T_ADDR((*guest_pte));
399
400     // Page Table Entry Not Present
401
402     host_region_type_t host_page_type = get_shadow_addr_type(info, guest_pa);
403
404     if (host_page_type == HOST_REGION_INVALID) {
405       // Inject a machine check in the guest
406
407       raise_exception(info, MC_EXCEPTION);
408 #ifdef DEBUG_SHADOW_PAGING
409       PrintDebug("Invalid Guest Address in page table (0x%x)\n", guest_pa);
410       PrintDebug("fault_addr=0x%x next are guest and shadow ptes \n",fault_addr);
411       PrintPTE32(fault_addr,guest_pte);
412       PrintPTE32(fault_addr,shadow_pte);
413       PrintDebug("Done.\n");
414 #endif
415       return 0;
416
417     } else if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
418       
419       shadow_pa = get_shadow_addr(info, guest_pa);
420       
421       shadow_pte->page_base_addr = PT32_BASE_ADDR(shadow_pa);
422       
423       shadow_pte->present = guest_pte->present;
424       shadow_pte->user_page = guest_pte->user_page;
425       
426       //set according to VMM policy
427       shadow_pte->write_through = 0;
428       shadow_pte->cache_disable = 0;
429       shadow_pte->global_page = 0;
430       //
431       
432       guest_pte->accessed = 1;
433       
434       if (guest_pte->dirty == 1) {
435         shadow_pte->writable = guest_pte->writable;
436       } else if ((guest_pte->dirty == 0) && (error_code.write == 1)) {
437         shadow_pte->writable = guest_pte->writable;
438         guest_pte->dirty = 1;
439       } else if ((guest_pte->dirty = 0) && (error_code.write == 0)) {
440         shadow_pte->writable = 0;
441       }
442     } else {
443       // Page fault handled by hook functions
444       if (handle_special_page_fault(info, fault_addr, error_code) == -1) {
445         PrintError("Special Page fault handler returned error for address: %x\n", fault_addr);
446         return -1;
447       }
448     }
449
450   } else if ((shadow_pte_access == PT_WRITE_ERROR) &&
451              (guest_pte->dirty == 0)) {
452     guest_pte->dirty = 1;
453     shadow_pte->writable = guest_pte->writable;
454
455     PrintDebug("Shadow PTE Write Error\n");
456
457     return 0;
458   } else {
459     // Inject page fault into the guest 
460         
461     info->ctrl_regs.cr2 = fault_addr;
462     raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
463
464     PrintError("PTE Page fault fell through... Not sure if this should ever happen\n");
465     PrintError("Manual Says to inject page fault into guest\n");
466     return -1;
467   }
468
469   PrintDebug("Returning end of function\n");
470   return 0;
471 }
472
473
474
475
476
477
478 /* Currently Does not work with Segmentation!!! */
479 int handle_shadow_invlpg(struct guest_info * info) {
480   if (info->mem_mode != VIRTUAL_MEM) {
481     // Paging must be turned on...
482     // should handle with some sort of fault I think
483     PrintError("ERROR: INVLPG called in non paged mode\n");
484     return -1;
485   }
486
487
488   if (info->cpu_mode == PROTECTED) {
489     char instr[15];
490     int ret;
491     int index = 0;
492
493     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
494     if (ret != 15) {
495       PrintError("Could not read instruction 0x%x (ret=%d)\n", info->rip, ret);
496       return -1;
497     }
498
499    
500     /* Can INVLPG work with Segments?? */
501     while (is_prefix_byte(instr[index])) {
502       index++;
503     }
504     
505     
506     if ((instr[index] == (uchar_t)0x0f) &&
507         (instr[index + 1] == (uchar_t)0x01)) {
508
509       addr_t first_operand;
510       addr_t second_operand;
511       operand_type_t addr_type;
512       addr_t guest_cr3 = CR3_TO_PDE32(info->shdw_pg_state.guest_cr3);
513
514       pde32_t * guest_pd = NULL;
515
516       if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
517         PrintError("Invalid Guest PDE Address: 0x%x\n", guest_cr3);
518         return -1;
519       }
520
521       
522
523
524       index += 2;
525
526       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
527
528       if (addr_type == MEM_OPERAND) {
529         pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32(info->shdw_pg_state.shadow_cr3);
530         pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(first_operand)];
531         pde32_t * guest_pde;
532
533         //PrintDebug("PDE Index=%d\n", PDE32_INDEX(first_operand));
534         //PrintDebug("FirstOperand = %x\n", first_operand);
535
536         PrintDebug("Invalidating page for %x\n", first_operand);
537
538         guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(first_operand)]);
539
540         if (guest_pde->large_page == 1) {
541           shadow_pde->present = 0;
542           PrintDebug("Invalidating Large Page\n");
543         } else {
544          
545           if (shadow_pde->present == 1) {
546             pte32_t * shadow_pt = (pte32_t *)PDE32_T_ADDR((*shadow_pde));
547             pte32_t * shadow_pte = (pte32_t *)&shadow_pt[PTE32_INDEX(first_operand)];
548
549 #ifdef DEBUG_SHADOW_PAGING
550             PrintDebug("Setting not present\n");
551             PrintPTE32(first_operand, shadow_pte);
552 #endif
553
554             shadow_pte->present = 0;
555           }
556         }
557
558         info->rip += index;
559
560       } else {
561         PrintError("Invalid Operand type\n");
562         return -1;
563       }
564     } else {
565       PrintError("invalid Instruction Opcode\n");
566       PrintTraceMemDump(instr, 15);
567       return -1;
568     }
569   }
570
571   return 0;
572 }
573
574
575
576 /* Deprecated */
577 /*
578 addr_t setup_shadow_pt32(struct guest_info * info, addr_t virt_cr3) {
579   addr_t cr3_guest_addr = CR3_TO_PDE32(virt_cr3);
580   pde32_t * guest_pde;
581   pde32_t * host_pde = NULL;
582   int i;
583   
584   // Setup up guest_pde to point to the PageDir in host addr
585   if (guest_pa_to_host_va(info, cr3_guest_addr, (addr_t*)&guest_pde) == -1) {
586     return 0;
587   }
588   
589   V3_AllocPages(host_pde, 1);
590   memset(host_pde, 0, PAGE_SIZE);
591
592   for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
593     if (guest_pde[i].present == 1) {
594       addr_t pt_host_addr;
595       addr_t host_pte;
596
597       if (guest_pa_to_host_va(info, PDE32_T_ADDR(guest_pde[i]), &pt_host_addr) == -1) {
598         return 0;
599       }
600
601       if ((host_pte = setup_shadow_pte32(info, pt_host_addr)) == 0) {
602         return 0;
603       }
604
605       host_pde[i].present = 1;
606       host_pde[i].pt_base_addr = PD32_BASE_ADDR(host_pte);
607
608       //
609       // Set Page DIR flags
610       //
611     }
612   }
613
614   PrintDebugPageTables(host_pde);
615
616   return (addr_t)host_pde;
617 }
618
619
620
621 addr_t setup_shadow_pte32(struct guest_info * info, addr_t pt_host_addr) {
622   pte32_t * guest_pte = (pte32_t *)pt_host_addr;
623   pte32_t * host_pte = NULL;
624   int i;
625
626   V3_AllocPages(host_pte, 1);
627   memset(host_pte, 0, PAGE_SIZE);
628
629   for (i = 0; i < MAX_PTE32_ENTRIES; i++) {
630     if (guest_pte[i].present == 1) {
631       addr_t guest_pa = PTE32_T_ADDR(guest_pte[i]);
632       shadow_mem_type_t page_type;
633       addr_t host_pa = 0;
634
635       page_type = get_shadow_addr_type(info, guest_pa);
636
637       if (page_type == HOST_REGION_PHYSICAL_MEMORY) {
638         host_pa = get_shadow_addr(info, guest_pa);
639       } else {
640         
641         //
642         // Setup various memory types
643         //
644       }
645
646       host_pte[i].page_base_addr = PT32_BASE_ADDR(host_pa);
647       host_pte[i].present = 1;
648     }
649   }
650
651   return (addr_t)host_pte;
652 }
653
654 */