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.


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