1 #include <geekos/vmm_paging.h>
3 #include <geekos/vmm.h>
7 extern struct vmm_os_hooks * os_hooks;
9 void delete_page_tables_pde32(vmm_pde_t * pde) {
16 for (i = 0; (i < MAX_PAGE_DIR_ENTRIES); i++) {
18 vmm_pte_t * pte = (vmm_pte_t *)(pde[i].pt_base_addr << PAGE_POWER);
20 for (j = 0; (j < MAX_PAGE_TABLE_ENTRIES); j++) {
21 if ((pte[j].present)) {
22 os_hooks->free_page((void *)(pte[j].page_base_addr << PAGE_POWER));
26 os_hooks->free_page(pte);
30 os_hooks->free_page(pde);
34 int init_shadow_page_state(shadow_page_state_t * state) {
35 state->guest_mode = PDE32;
36 state->shadow_mode = PDE32;
38 state->guest_cr3.r_reg = 0;
39 state->shadow_cr3.r_reg = 0;
45 int wholesale_update_shadow_page_state(shadow_page_state_t * state, shadow_map_t * mem_map) {
47 vmm_pde_t * guest_pde;
48 vmm_pde_t * shadow_pde;
51 // For now, we'll only work with PDE32
52 if (state->guest_mode != PDE32) {
58 shadow_pde = (vmm_pde_t *)(CR3_TO_PDE(state->shadow_cr3.e_reg.low));
59 guest_pde = (vmm_pde_t *)(os_hooks->paddr_to_vaddr((void*)CR3_TO_PDE(state->guest_cr3.e_reg.low)));
61 // Delete the current page table
62 delete_page_tables_pde32(shadow_pde);
64 shadow_pde = os_hooks->allocate_pages(1);
67 state->shadow_cr3.e_reg.low = (addr_t)shadow_pde;
69 state->shadow_mode = PDE32;
72 for (i = 0; i < MAX_PAGE_DIR_ENTRIES; i++) {
73 shadow_pde[i] = guest_pde[i];
75 // The shadow can be identical to the guest if it's not present
76 if (!shadow_pde[i].present) {
80 if (shadow_pde[i].large_pages) {
81 // large page - just map it through shadow map to generate its physical location
82 addr_t guest_addr = PAGE_ADDR(shadow_pde[i].pt_base_addr);
84 shadow_region_t * ent;
86 ent = get_shadow_region_by_addr(mem_map, guest_addr);
89 // FIXME Panic here - guest is trying to map to physical memory
90 // it does not own in any way!
94 // FIXME Bounds check here to see if it's trying to trick us
96 switch (ent->host_type) {
97 case HOST_REGION_PHYSICAL_MEMORY:
98 // points into currently allocated physical memory, so we just
99 // set up the shadow to point to the mapped location
100 if (guest_paddr_to_host_paddr(ent, guest_addr, &host_addr)) {
105 shadow_pde[i].pt_base_addr = PAGE_ALIGNED_ADDR(host_addr);
106 // FIXME set vmm_info bits here
108 case HOST_REGION_UNALLOCATED:
109 // points to physical memory that is *allowed* but that we
110 // have not yet allocated. We mark as not present and set a
111 // bit to remind us to allocate it later
112 shadow_pde[i].present = 0;
113 // FIXME Set vminfo bits here so that we know that we will be
114 // allocating it later
116 case HOST_REGION_NOTHING:
117 // points to physical memory that is NOT ALLOWED.
118 // We will mark it as not present and set a bit to remind
119 // us that it's bad later and insert a GPF then
120 shadow_pde[i].present = 0;
122 case HOST_REGION_MEMORY_MAPPED_DEVICE:
123 case HOST_REGION_REMOTE:
124 case HOST_REGION_SWAPPED:
126 // Panic. Currently unhandled
131 vmm_pte_t * guest_pte;
132 vmm_pte_t * shadow_pte;
134 addr_t guest_pte_host_addr;
135 shadow_region_t * ent;
137 // small page - set PDE and follow down to the child table
138 shadow_pde[i] = guest_pde[i];
140 guest_addr = PAGE_ADDR(guest_pde[i].pt_base_addr);
142 // Allocate a new second level page table for the shadow
143 shadow_pte = os_hooks->allocate_pages(1);
145 // make our first level page table in the shadow point to it
146 shadow_pde[i].pt_base_addr = PAGE_ALIGNED_ADDR(shadow_pte);
148 ent = get_shadow_region_by_addr(mem_map, guest_addr);
151 /* JRL: This is bad.... */
152 // For now the guest Page Table must always be mapped to host physical memory
153 /* If we swap out a page table or if it isn't present for some reason, this turns real ugly */
155 if ((!ent) || (ent->host_type != HOST_REGION_PHYSICAL_MEMORY)) {
156 // FIXME Panic here - guest is trying to map to physical memory
157 // it does not own in any way!
161 // Address of the relevant second level page table in the guest
162 if (guest_paddr_to_host_paddr(ent, guest_addr, &guest_pte_host_addr)) {
168 // host_addr now contains the host physical address for the guest's 2nd level page table
169 // Now we transform it to relevant virtual address
170 guest_pte = os_hooks->paddr_to_vaddr((void *)guest_pte_host_addr);
172 // Now we walk through the second level guest page table
173 // and clone it into the shadow
174 for (j = 0; j < MAX_PAGE_TABLE_ENTRIES; j++) {
175 shadow_pte[j] = guest_pte[j];
177 addr_t guest_addr = PAGE_ADDR(shadow_pte[j].page_base_addr);
179 shadow_region_t * ent;
181 ent = get_shadow_region_by_addr(mem_map, guest_addr);
184 // FIXME Panic here - guest is trying to map to physical memory
185 // it does not own in any way!
189 switch (ent->host_type) {
190 case HOST_REGION_PHYSICAL_MEMORY:
194 // points into currently allocated physical memory, so we just
195 // set up the shadow to point to the mapped location
196 if (guest_paddr_to_host_paddr(ent, guest_addr, &host_addr)) {
201 shadow_pte[j].page_base_addr = PAGE_ALIGNED_ADDR(host_addr);
202 // FIXME set vmm_info bits here
205 case HOST_REGION_UNALLOCATED:
206 // points to physical memory that is *allowed* but that we
207 // have not yet allocated. We mark as not present and set a
208 // bit to remind us to allocate it later
209 shadow_pte[j].present = 0;
210 // FIXME Set vminfo bits here so that we know that we will be
211 // allocating it later
213 case HOST_REGION_NOTHING:
214 // points to physical memory that is NOT ALLOWED.
215 // We will mark it as not present and set a bit to remind
216 // us that it's bad later and insert a GPF then
217 shadow_pte[j].present = 0;
219 case HOST_REGION_MEMORY_MAPPED_DEVICE:
220 case HOST_REGION_REMOTE:
221 case HOST_REGION_SWAPPED:
223 // Panic. Currently unhandled
236 /* We generate a page table to correspond to a given memory layout
237 * pulling pages from the mem_list when necessary
238 * If there are any gaps in the layout, we add them as unmapped pages
240 vmm_pde_t * create_passthrough_pde32_pts(shadow_map_t * map) {
241 ullong_t current_page_addr = 0;
245 vmm_pde_t * pde = os_hooks->allocate_pages(1);
247 for (i = 0; i < MAX_PAGE_DIR_ENTRIES; i++) {
249 vmm_pte_t * pte = os_hooks->allocate_pages(1);
252 for (j = 0; j < MAX_PAGE_TABLE_ENTRIES; j++) {
253 shadow_region_t * region = get_shadow_region_by_addr(map, current_page_addr);
256 (region->host_type == HOST_REGION_NOTHING) ||
257 (region->host_type == HOST_REGION_UNALLOCATED) ||
258 (region->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE) ||
259 (region->host_type == HOST_REGION_REMOTE) ||
260 (region->host_type == HOST_REGION_SWAPPED)) {
266 pte[j].global_page = 0;
268 pte[j].page_base_addr = 0;
272 pte[j].flags = VM_READ | VM_WRITE | VM_EXEC | VM_USER;
277 pte[j].global_page = 0;
280 if (guest_paddr_to_host_paddr(region, current_page_addr, &host_addr) == -1) {
286 pte[j].page_base_addr = host_addr >> 12;
291 current_page_addr += PAGE_SIZE;
294 if (pte_present == 0) {
295 os_hooks->free_page(pte);
301 pde[i].large_pages = 0;
302 pde[i].global_page = 0;
304 pde[i].pt_base_addr = 0;
307 pde[i].flags = VM_READ | VM_WRITE | VM_EXEC | VM_USER;
310 pde[i].large_pages = 0;
311 pde[i].global_page = 0;
313 pde[i].pt_base_addr = PAGE_ALIGNED_ADDR(pte);
327 void PrintPDE(void * virtual_address, vmm_pde_t * pde)
329 PrintDebug("PDE %p -> %p : present=%x, flags=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
331 (void *) (pde->pt_base_addr << PAGE_POWER),
341 void PrintPTE(void * virtual_address, vmm_pte_t * pte)
343 PrintDebug("PTE %p -> %p : present=%x, flags=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, vmm_info=%x\n",
345 (void*)(pte->page_base_addr << PAGE_POWER),
357 void PrintPD(vmm_pde_t * pde)
361 PrintDebug("Page Directory at %p:\n", pde);
362 for (i = 0; (i < MAX_PAGE_DIR_ENTRIES) && pde[i].present; i++) {
363 PrintPDE((void*)(PAGE_SIZE * MAX_PAGE_TABLE_ENTRIES * i), &(pde[i]));
367 void PrintPT(void * starting_address, vmm_pte_t * pte)
371 PrintDebug("Page Table at %p:\n", pte);
372 for (i = 0; (i < MAX_PAGE_TABLE_ENTRIES) && pte[i].present; i++) {
373 PrintPTE(starting_address + (PAGE_SIZE * i), &(pte[i]));
381 void PrintDebugPageTables(vmm_pde_t * pde)
385 PrintDebug("Dumping the pages starting with the pde page at %p\n", pde);
387 for (i = 0; (i < MAX_PAGE_DIR_ENTRIES) && pde[i].present; i++) {
388 PrintPDE((void *)(PAGE_SIZE * MAX_PAGE_TABLE_ENTRIES * i), &(pde[i]));
389 PrintPT((void *)(PAGE_SIZE * MAX_PAGE_TABLE_ENTRIES * i), (void *)(pde[i].pt_base_addr << PAGE_POWER));
397 pml4e64_t * generate_guest_page_tables_64(vmm_mem_layout_t * layout, vmm_mem_list_t * list) {
398 pml4e64_t * pml = os_hooks->allocate_pages(1);
400 ullong_t current_page_addr = 0;
401 uint_t layout_index = 0;
402 uint_t list_index = 0;
403 ullong_t layout_addr = 0;
404 uint_t num_entries = layout->num_pages; // The number of pages left in the layout
406 for (m = 0; m < MAX_PAGE_MAP_ENTRIES_64; m++ ) {
407 if (num_entries == 0) {
417 pml[m].pdp_base_addr_lo = 0;
418 pml[m].pdp_base_addr_hi = 0;
419 pml[m].available = 0;
420 pml[m].no_execute = 0;
422 pdpe64_t * pdpe = os_hooks->allocate_pages(1);
433 pml[m].pdp_base_addr_lo = PAGE_ALLIGNED_ADDR(pdpe) & 0xfffff;
434 pml[m].pdp_base_addr_hi = 0;
435 pml[m].available = 0;
436 pml[m].no_execute = 0;
438 for (k = 0; k < MAX_PAGE_DIR_PTR_ENTRIES_64; k++) {
439 if (num_entries == 0) {
441 pdpe[k].writable = 0;
445 pdpe[k].accessed = 0;
446 pdpe[k].reserved = 0;
447 pdpe[k].large_pages = 0;
449 pdpe[k].vmm_info = 0;
450 pdpe[k].pd_base_addr_lo = 0;
451 pdpe[k].pd_base_addr_hi = 0;
452 pdpe[k].available = 0;
453 pdpe[k].no_execute = 0;
455 pde64_t * pde = os_hooks->allocate_pages(1);
458 pdpe[k].writable = 1;
462 pdpe[k].accessed = 0;
463 pdpe[k].reserved = 0;
464 pdpe[k].large_pages = 0;
466 pdpe[k].vmm_info = 0;
467 pdpe[k].pd_base_addr_lo = PAGE_ALLIGNED_ADDR(pde) & 0xfffff;
468 pdpe[k].pd_base_addr_hi = 0;
469 pdpe[k].available = 0;
470 pdpe[k].no_execute = 0;
474 for (i = 0; i < MAX_PAGE_DIR_ENTRIES_64; i++) {
475 if (num_entries == 0) {
480 pde[i].large_pages = 0;
481 pde[i].reserved2 = 0;
483 pde[i].pt_base_addr_lo = 0;
484 pde[i].pt_base_addr_hi = 0;
485 pde[i].available = 0;
486 pde[i].no_execute = 0;
488 pte64_t * pte = os_hooks->allocate_pages(1);
491 pde[i].flags = VM_READ | VM_WRITE | VM_EXEC | VM_USER;
494 pde[i].large_pages = 0;
495 pde[i].reserved2 = 0;
497 pde[i].pt_base_addr_lo = PAGE_ALLIGNED_ADDR(pte) & 0xfffff;
498 pde[i].pt_base_addr_hi = 0;
499 pde[i].available = 0;
500 pde[i].no_execute = 0;
503 for (j = 0; j < MAX_PAGE_TABLE_ENTRIES_64; j++) {
504 layout_addr = get_mem_layout_addr(layout, layout_index);
506 if ((current_page_addr < layout_addr) || (num_entries == 0)) {
507 // We have a gap in the layout, fill with unmapped page
513 pte[j].global_page = 0;
515 pte[j].page_base_addr_lo = 0;
516 pte[j].page_base_addr_hi = 0;
517 pte[j].available = 0;
518 pte[j].no_execute = 0;
520 current_page_addr += PAGE_SIZE;
521 } else if (current_page_addr == layout_addr) {
522 // Set up the Table entry to map correctly to the layout region
523 layout_region_t * page_region = get_mem_layout_region(layout, layout_addr);
525 if (page_region->type == UNMAPPED) {
530 pte[j].flags = VM_READ | VM_WRITE | VM_EXEC | VM_USER;
536 pte[j].global_page = 0;
538 pte[j].available = 0;
539 pte[j].no_execute = 0;
541 if (page_region->type == UNMAPPED) {
542 pte[j].page_base_addr_lo = 0;
543 pte[j].page_base_addr_hi = 0;
544 } else if (page_region->type == SHARED) {
545 addr_t host_addr = page_region->host_addr + (layout_addr - page_region->start);
547 pte[j].page_base_addr_lo = PAGE_ALLIGNED_ADDR(host_addr) & 0xfffff;
548 pte[j].page_base_addr_hi = 0;
549 pte[j].vmm_info = SHARED_PAGE;
550 } else if (page_region->type == GUEST) {
551 addr_t list_addr = get_mem_list_addr(list, list_index++);
553 if (list_addr == -1) {
556 //free_guest_page_tables(pde);
559 PrintDebug("Adding guest page (%x)\n", list_addr);
560 pte[j].page_base_addr_lo = PAGE_ALLIGNED_ADDR(list_addr) & 0xfffff;
561 pte[j].page_base_addr_hi = 0;
563 // Reset this when we move over to dynamic page allocation
564 // pte[j].vmm_info = GUEST_PAGE;
565 pte[j].vmm_info = SHARED_PAGE;
569 current_page_addr += PAGE_SIZE;
573 PrintDebug("Error creating page table...\n");
575 // free_guest_page_tables64(pde);