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.


*** empty log message ***
[palacios.git] / palacios / src / geekos / vmm_paging.c
1 #include <geekos/vmm_paging.h>
2
3 #include <geekos/vmm.h>
4
5
6
7 extern struct vmm_os_hooks * os_hooks;
8
9 void delete_page_tables_pde32(vmm_pde_t * pde) {
10   int i, j;
11
12   if (pde==NULL) { 
13     return ;
14   }
15
16   for (i = 0; (i < MAX_PAGE_DIR_ENTRIES); i++) {
17     if (pde[i].present) {
18       vmm_pte_t * pte = (vmm_pte_t *)(pde[i].pt_base_addr << PAGE_POWER);
19       
20       for (j = 0; (j < MAX_PAGE_TABLE_ENTRIES); j++) {
21         if ((pte[j].present) && (pte[j].vmm_info & GUEST_PAGE)){
22           os_hooks->free_page((void *)(pte[j].page_base_addr  << PAGE_POWER));
23         }
24       }
25       
26       os_hooks->free_page(pte);
27     }
28   }
29
30   os_hooks->free_page(pde);
31 }
32
33
34 int init_shadow_paging_state(shadow_paging_state_t *state)
35 {
36   state->guest_page_directory_type=state->shadow_page_directory_type=PDE32;
37   
38   state->guest_page_directory=state->shadow_page_directory=NULL;
39
40   init_shadow_map(&(state->shadow_map));
41   return 0;
42 }
43   
44
45 int wholesale_update_shadow_paging_state(shadow_paging_state_t *state)
46 {
47   unsigned i, j;
48   vmm_pde_t *cur_guest_pde, *cur_shadow_pde;
49   vmm_pte_t *cur_guest_pte, *cur_shadow_pte;
50
51   // For now, we'll only work with PDE32
52   if (state->guest_page_directory_type!=PDE32) { 
53     return -1;
54   }
55   
56   cur_shadow_pde=(vmm_pde_t*)(state->shadow_page_directory);
57   
58   cur_guest_pde = (vmm_pde_t*)(os_hooks->physical_to_virtual(state->guest_page_directory));
59
60   // Delete the current page table
61   delete_page_tables_pde32(cur_shadow_pde);
62
63   cur_shadow_pde = os_hooks->allocate_pages(1);
64
65   state->shadow_page_directory = cur_shadow_pde;
66   state->shadow_page_directory_type=PDE32;
67
68   
69   for (i=0;i<MAX_PAGE_DIR_ENTRIES;i++) { 
70     cur_shadow_pde[i] = cur_guest_pde[i];
71     // The shadow can be identical to the guest if it's not present
72     if (!cur_shadow_pde[i].present) { 
73       continue;
74     }
75     if (cur_shadow_pde[i].large_pages) { 
76       // large page - just map it through shadow map to generate its physical location
77       addr_t guest_addr = PAGE_ADDR(cur_shadow_pde[i].pt_base_addr);
78       addr_t host_addr;
79       shadow_map_entry_t *ent;
80
81       ent = get_shadow_map_region_by_addr(&(state->shadow_map),guest_addr);
82       
83       if (!ent) { 
84         // FIXME Panic here - guest is trying to map to physical memory
85         // it does not own in any way!
86         return -1;
87       }
88
89       // FIXME Bounds check here to see if it's trying to trick us
90       
91       switch (ent->host_type) { 
92       case HOST_REGION_PHYSICAL_MEMORY:
93         // points into currently allocated physical memory, so we just
94         // set up the shadow to point to the mapped location
95         if (map_guest_physical_to_host_physical(ent,guest_addr,&host_addr)) { 
96           // Panic here
97           return -1;
98         }
99         cur_shadow_pde[i].pt_base_addr = PAGE_ALIGNED_ADDR(host_addr);
100         // FIXME set vmm_info bits here
101         break;
102       case HOST_REGION_UNALLOCATED:
103         // points to physical memory that is *allowed* but that we
104         // have not yet allocated.  We mark as not present and set a
105         // bit to remind us to allocate it later
106         cur_shadow_pde[i].present=0;
107         // FIXME Set vminfo bits here so that we know that we will be
108         // allocating it later
109         break;
110       case HOST_REGION_NOTHING:
111         // points to physical memory that is NOT ALLOWED.   
112         // We will mark it as not present and set a bit to remind
113         // us that it's bad later and insert a GPF then
114         cur_shadow_pde[i].present=0;
115         break;
116       case HOST_REGION_MEMORY_MAPPED_DEVICE:
117       case HOST_REGION_REMOTE:
118       case HOST_REGION_SWAPPED:
119       default:
120         // Panic.  Currently unhandled
121         return -1;
122         break;
123       }
124     } else {
125       addr_t host_addr;
126       addr_t guest_addr;
127
128       // small page - set PDE and follow down to the child table
129       cur_shadow_pde[i] = cur_guest_pde[i];
130       
131       // Allocate a new second level page table for the shadow
132       cur_shadow_pte = os_hooks->allocate_pages(1);
133
134       // make our first level page table in teh shadow point to it
135       cur_shadow_pde[i].pt_base_addr = PAGE_ALIGNED_ADDR(cur_shadow_pte);
136
137       shadow_map_entry_t *ent;
138       
139       guest_addr=PAGE_ADDR(cur_guest_pde[i].pt_base_addr);
140
141       ent = get_shadow_map_region_by_addr(&(state->shadow_map),guest_addr);
142       
143       if (!ent) { 
144         // FIXME Panic here - guest is trying to map to physical memory
145         // it does not own in any way!
146         return -1;
147       }
148
149       // Address of the relevant second level page table in the guest
150       if (map_guest_physical_to_host_physical(ent,guest_addr,&host_addr)) { 
151         // Panic here
152         return -1;
153       }
154       // host_addr now contains the host physical address for the guest's 2nd level page table
155
156       // Now we transform it to relevant virtual address
157       cur_guest_pte = os_hooks->physical_to_virtual((void*)host_addr);
158
159       // Now we walk through the second level guest page table
160       // and clone it into the shadow
161       for (j=0;j<MAX_PAGE_TABLE_ENTRIES;j++) { 
162         cur_shadow_pte[j] = cur_guest_pte[j];
163
164         addr_t guest_addr = PAGE_ADDR(cur_shadow_pte[j].page_base_addr);
165         
166         shadow_map_entry_t *ent;
167
168         ent = get_shadow_map_region_by_addr(&(state->shadow_map),guest_addr);
169       
170         if (!ent) { 
171           // FIXME Panic here - guest is trying to map to physical memory
172           // it does not own in any way!
173           return -1;
174         }
175
176         switch (ent->host_type) { 
177         case HOST_REGION_PHYSICAL_MEMORY:
178           // points into currently allocated physical memory, so we just
179           // set up the shadow to point to the mapped location
180           if (map_guest_physical_to_host_physical(ent,guest_addr,&host_addr)) { 
181             // Panic here
182             return -1;
183           }
184           cur_shadow_pte[j].page_base_addr = PAGE_ALIGNED_ADDR(host_addr);
185           // FIXME set vmm_info bits here
186           break;
187         case HOST_REGION_UNALLOCATED:
188           // points to physical memory that is *allowed* but that we
189           // have not yet allocated.  We mark as not present and set a
190           // bit to remind us to allocate it later
191           cur_shadow_pte[j].present=0;
192           // FIXME Set vminfo bits here so that we know that we will be
193           // allocating it later
194           break;
195         case HOST_REGION_NOTHING:
196           // points to physical memory that is NOT ALLOWED.   
197           // We will mark it as not present and set a bit to remind
198           // us that it's bad later and insert a GPF then
199           cur_shadow_pte[j].present=0;
200           break;
201         case HOST_REGION_MEMORY_MAPPED_DEVICE:
202         case HOST_REGION_REMOTE:
203         case HOST_REGION_SWAPPED:
204         default:
205           // Panic.  Currently unhandled
206           return -1;
207         break;
208         }
209       }
210     }
211   }
212   return 0;
213 }
214       
215
216
217 #if 0
218 /* We generate a page table to correspond to a given memory layout
219  * pulling pages from the mem_list when necessary
220  * If there are any gaps in the layout, we add them as unmapped pages
221  */
222 vmm_pde_t * generate_guest_page_tables(vmm_mem_layout_t * layout, vmm_mem_list_t * list) {
223   ullong_t current_page_addr = 0;
224   uint_t layout_index = 0;
225   uint_t list_index = 0;
226   ullong_t layout_addr = 0;
227   int i, j;
228   uint_t num_entries = layout->num_pages;  // The number of pages left in the layout
229
230
231   
232
233   vmm_pde_t * pde = os_hooks->allocate_pages(1);
234
235   for (i = 0; i < MAX_PAGE_DIR_ENTRIES; i++) {
236     if (num_entries == 0) { 
237       pde[i].present = 0;
238       pde[i].flags = 0;
239       pde[i].accessed = 0;
240       pde[i].reserved = 0;
241       pde[i].large_pages = 0;
242       pde[i].global_page = 0;
243       pde[i].vmm_info = 0;
244       pde[i].pt_base_addr = 0;
245     } else {
246       vmm_pte_t * pte = os_hooks->allocate_pages(1);
247
248       pde[i].present = 1;
249       pde[i].flags = VM_READ | VM_WRITE | VM_EXEC | VM_USER;
250       pde[i].accessed = 0;
251       pde[i].reserved = 0;
252       pde[i].large_pages = 0;
253       pde[i].global_page = 0;
254       pde[i].vmm_info = 0;
255       pde[i].pt_base_addr = PAGE_ALLIGNED_ADDR(pte);
256
257
258
259       for (j = 0; j < MAX_PAGE_TABLE_ENTRIES; j++) {
260         layout_addr = get_mem_layout_addr(layout, layout_index);
261         
262         if ((current_page_addr < layout_addr) || (num_entries == 0)) {
263           // We have a gap in the layout, fill with unmapped page
264           pte[j].present = 0;
265           pte[j].flags = 0;
266           pte[j].accessed = 0;
267           pte[j].dirty = 0;
268           pte[j].pte_attr = 0;
269           pte[j].global_page = 0;
270           pte[j].vmm_info = 0;
271           pte[j].page_base_addr = 0;
272
273           current_page_addr += PAGE_SIZE;
274         } else if (current_page_addr == layout_addr) {
275           // Set up the Table entry to map correctly to the layout region
276           layout_region_t * page_region = get_mem_layout_region(layout, layout_addr);
277
278           if (page_region->type == UNMAPPED) {
279             pte[j].present = 0;
280             pte[j].flags = 0;
281           } else {
282             pte[j].present = 1;
283             pte[j].flags = VM_READ | VM_WRITE | VM_EXEC | VM_USER;
284           }         
285
286           pte[j].accessed = 0;
287           pte[j].dirty = 0;
288           pte[j].pte_attr = 0;
289           pte[j].global_page = 0;
290           pte[j].vmm_info = 0;
291
292           if (page_region->type == UNMAPPED) {
293             pte[j].page_base_addr = 0;
294           } else if (page_region->type == SHARED) {
295             addr_t host_addr = page_region->host_addr + (layout_addr - page_region->start);
296
297             pte[j].page_base_addr = host_addr >> 12;
298             pte[j].vmm_info = SHARED_PAGE;
299           } else if (page_region->type == GUEST) {
300             addr_t list_addr =  get_mem_list_addr(list, list_index++);
301             
302             if (list_addr == -1) {
303               // error
304               // cleanup...
305               free_guest_page_tables(pde);
306               return NULL;
307             }
308             PrintDebug("Adding guest page (%x)\n", list_addr);
309             pte[j].page_base_addr = list_addr >> 12;
310             
311             // Reset this when we move over to dynamic page allocation
312             //      pte[j].vmm_info = GUEST_PAGE;           
313             pte[j].vmm_info = SHARED_PAGE;
314           }
315
316           num_entries--;
317           current_page_addr += PAGE_SIZE;
318           layout_index++;
319         } else {
320           // error
321           PrintDebug("Error creating page table...\n");
322           // cleanup
323           free_guest_page_tables(pde);
324           return NULL;
325         }
326       }
327     }
328   }
329
330   return pde;
331 }
332
333 #endif
334
335
336
337
338
339 void PrintPDE(void * virtual_address, vmm_pde_t * pde)
340 {
341   PrintDebug("PDE %p -> %p : present=%x, flags=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
342               virtual_address,
343               (void *) (pde->pt_base_addr << PAGE_POWER),
344               pde->present,
345               pde->flags,
346               pde->accessed,
347               pde->reserved,
348               pde->large_pages,
349               pde->global_page,
350               pde->vmm_info);
351 }
352   
353 void PrintPTE(void * virtual_address, vmm_pte_t * pte)
354 {
355   PrintDebug("PTE %p -> %p : present=%x, flags=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, vmm_info=%x\n",
356               virtual_address,
357               (void*)(pte->page_base_addr << PAGE_POWER),
358               pte->present,
359               pte->flags,
360               pte->accessed,
361               pte->dirty,
362               pte->pte_attr,
363               pte->global_page,
364               pte->vmm_info);
365 }
366
367
368
369 void PrintPD(vmm_pde_t * pde)
370 {
371   int i;
372
373   PrintDebug("Page Directory at %p:\n", pde);
374   for (i = 0; (i < MAX_PAGE_DIR_ENTRIES) && pde[i].present; i++) { 
375     PrintPDE((void*)(PAGE_SIZE * MAX_PAGE_TABLE_ENTRIES * i), &(pde[i]));
376   }
377 }
378
379 void PrintPT(void * starting_address, vmm_pte_t * pte) 
380 {
381   int i;
382
383   PrintDebug("Page Table at %p:\n", pte);
384   for (i = 0; (i < MAX_PAGE_TABLE_ENTRIES) && pte[i].present; i++) { 
385     PrintPTE(starting_address + (PAGE_SIZE * i), &(pte[i]));
386   }
387 }
388
389
390
391
392
393 void PrintDebugPageTables(vmm_pde_t * pde)
394 {
395   int i;
396   
397   PrintDebug("Dumping the pages starting with the pde page at %p\n", pde);
398
399   for (i = 0; (i < MAX_PAGE_DIR_ENTRIES) && pde[i].present; i++) { 
400     PrintPDE((void *)(PAGE_SIZE * MAX_PAGE_TABLE_ENTRIES * i), &(pde[i]));
401     PrintPT((void *)(PAGE_SIZE * MAX_PAGE_TABLE_ENTRIES * i), (void *)(pde[i].pt_base_addr << PAGE_POWER));
402   }
403 }
404     
405     
406
407 #if 0
408
409 pml4e64_t * generate_guest_page_tables_64(vmm_mem_layout_t * layout, vmm_mem_list_t * list) {
410   pml4e64_t * pml = os_hooks->allocate_pages(1);
411   int i, j, k, m;
412   ullong_t current_page_addr = 0;
413   uint_t layout_index = 0;
414   uint_t list_index = 0;
415   ullong_t layout_addr = 0;
416   uint_t num_entries = layout->num_pages;  // The number of pages left in the layout
417
418   for (m = 0; m < MAX_PAGE_MAP_ENTRIES_64; m++ ) {
419     if (num_entries == 0) {
420       pml[m].present = 0;
421       pml[m].writable = 0;
422       pml[m].user = 0;
423       pml[m].pwt = 0;
424       pml[m].pcd = 0;
425       pml[m].accessed = 0;
426       pml[m].reserved = 0;
427       pml[m].zero = 0;
428       pml[m].vmm_info = 0;
429       pml[m].pdp_base_addr_lo = 0;
430       pml[m].pdp_base_addr_hi = 0;
431       pml[m].available = 0;
432       pml[m].no_execute = 0;
433     } else {
434       pdpe64_t * pdpe = os_hooks->allocate_pages(1);
435       
436       pml[m].present = 1;
437       pml[m].writable = 1;
438       pml[m].user = 1;
439       pml[m].pwt = 0;
440       pml[m].pcd = 0;
441       pml[m].accessed = 0;
442       pml[m].reserved = 0;
443       pml[m].zero = 0;
444       pml[m].vmm_info = 0;
445       pml[m].pdp_base_addr_lo = PAGE_ALLIGNED_ADDR(pdpe) & 0xfffff;
446       pml[m].pdp_base_addr_hi = 0;
447       pml[m].available = 0;
448       pml[m].no_execute = 0;
449
450       for (k = 0; k < MAX_PAGE_DIR_PTR_ENTRIES_64; k++) {
451         if (num_entries == 0) {
452           pdpe[k].present = 0;
453           pdpe[k].writable = 0;
454           pdpe[k].user = 0;
455           pdpe[k].pwt = 0;
456           pdpe[k].pcd = 0;
457           pdpe[k].accessed = 0;
458           pdpe[k].reserved = 0;
459           pdpe[k].large_pages = 0;
460           pdpe[k].zero = 0;
461           pdpe[k].vmm_info = 0;
462           pdpe[k].pd_base_addr_lo = 0;
463           pdpe[k].pd_base_addr_hi = 0;
464           pdpe[k].available = 0;
465           pdpe[k].no_execute = 0;
466         } else {
467           pde64_t * pde = os_hooks->allocate_pages(1);
468
469           pdpe[k].present = 1;
470           pdpe[k].writable = 1;
471           pdpe[k].user = 1;
472           pdpe[k].pwt = 0;
473           pdpe[k].pcd = 0;
474           pdpe[k].accessed = 0;
475           pdpe[k].reserved = 0;
476           pdpe[k].large_pages = 0;
477           pdpe[k].zero = 0;
478           pdpe[k].vmm_info = 0;
479           pdpe[k].pd_base_addr_lo = PAGE_ALLIGNED_ADDR(pde) & 0xfffff;
480           pdpe[k].pd_base_addr_hi = 0;
481           pdpe[k].available = 0;
482           pdpe[k].no_execute = 0;
483
484
485
486           for (i = 0; i < MAX_PAGE_DIR_ENTRIES_64; i++) {
487             if (num_entries == 0) { 
488               pde[i].present = 0;
489               pde[i].flags = 0;
490               pde[i].accessed = 0;
491               pde[i].reserved = 0;
492               pde[i].large_pages = 0;
493               pde[i].reserved2 = 0;
494               pde[i].vmm_info = 0;
495               pde[i].pt_base_addr_lo = 0;
496               pde[i].pt_base_addr_hi = 0;
497               pde[i].available = 0;
498               pde[i].no_execute = 0;
499             } else {
500               pte64_t * pte = os_hooks->allocate_pages(1);
501               
502               pde[i].present = 1;
503               pde[i].flags = VM_READ | VM_WRITE | VM_EXEC | VM_USER;
504               pde[i].accessed = 0;
505               pde[i].reserved = 0;
506               pde[i].large_pages = 0;
507               pde[i].reserved2 = 0;
508               pde[i].vmm_info = 0;
509               pde[i].pt_base_addr_lo = PAGE_ALLIGNED_ADDR(pte) & 0xfffff;
510               pde[i].pt_base_addr_hi = 0;
511               pde[i].available = 0;
512               pde[i].no_execute = 0;
513
514               
515               for (j = 0; j < MAX_PAGE_TABLE_ENTRIES_64; j++) {
516                 layout_addr = get_mem_layout_addr(layout, layout_index);
517                 
518                 if ((current_page_addr < layout_addr) || (num_entries == 0)) {
519                   // We have a gap in the layout, fill with unmapped page
520                   pte[j].present = 0;
521                   pte[j].flags = 0;
522                   pte[j].accessed = 0;
523                   pte[j].dirty = 0;
524                   pte[j].pte_attr = 0;
525                   pte[j].global_page = 0;
526                   pte[j].vmm_info = 0;
527                   pte[j].page_base_addr_lo = 0;
528                   pte[j].page_base_addr_hi = 0;
529                   pte[j].available = 0;
530                   pte[j].no_execute = 0;
531
532                   current_page_addr += PAGE_SIZE;
533                 } else if (current_page_addr == layout_addr) {
534                   // Set up the Table entry to map correctly to the layout region
535                   layout_region_t * page_region = get_mem_layout_region(layout, layout_addr);
536                   
537                   if (page_region->type == UNMAPPED) {
538                     pte[j].present = 0;
539                     pte[j].flags = 0;
540                   } else {
541                     pte[j].present = 1;
542                     pte[j].flags = VM_READ | VM_WRITE | VM_EXEC | VM_USER;
543                   }         
544                   
545                   pte[j].accessed = 0;
546                   pte[j].dirty = 0;
547                   pte[j].pte_attr = 0;
548                   pte[j].global_page = 0;
549                   pte[j].vmm_info = 0;
550                   pte[j].available = 0;
551                   pte[j].no_execute = 0;
552
553                   if (page_region->type == UNMAPPED) {
554                     pte[j].page_base_addr_lo = 0;
555                     pte[j].page_base_addr_hi = 0;
556                   } else if (page_region->type == SHARED) {
557                     addr_t host_addr = page_region->host_addr + (layout_addr - page_region->start);
558                     
559                     pte[j].page_base_addr_lo = PAGE_ALLIGNED_ADDR(host_addr) & 0xfffff;
560                     pte[j].page_base_addr_hi = 0;
561                     pte[j].vmm_info = SHARED_PAGE;
562                   } else if (page_region->type == GUEST) {
563                     addr_t list_addr =  get_mem_list_addr(list, list_index++);
564                     
565                     if (list_addr == -1) {
566                       // error
567                       // cleanup...
568                       //free_guest_page_tables(pde);
569                       return NULL;
570                     }
571                     PrintDebug("Adding guest page (%x)\n", list_addr);
572                     pte[j].page_base_addr_lo = PAGE_ALLIGNED_ADDR(list_addr) & 0xfffff;
573                     pte[j].page_base_addr_hi = 0;
574
575                     // Reset this when we move over to dynamic page allocation
576                     //      pte[j].vmm_info = GUEST_PAGE;           
577                     pte[j].vmm_info = SHARED_PAGE;
578                   }
579                   
580                   num_entries--;
581                   current_page_addr += PAGE_SIZE;
582                   layout_index++;
583                 } else {
584                   // error
585                   PrintDebug("Error creating page table...\n");
586                   // cleanup
587                   //              free_guest_page_tables64(pde);
588                   return NULL;
589                 }
590               }
591             }
592           }
593         }
594       }
595     }
596   }
597   return pml;
598 }
599
600 #endif