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.


modified copyright tags
[palacios.git] / palacios / src / palacios / vmm_paging.c
1 /* (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> */
2 /* (c) 2008, The V3VEE Project <http://www.v3vee.org> */
3
4
5 #include <palacios/vmm_paging.h>
6
7 #include <palacios/vmm.h>
8
9 #include <palacios/vm_guest_mem.h>
10
11
12
13
14 void delete_page_tables_pde32(pde32_t * pde) {
15   int i;//, j;
16
17   if (pde == NULL) { 
18     return;
19   }
20
21   for (i = 0; (i < MAX_PDE32_ENTRIES); i++) {
22     if (pde[i].present) {
23       pte32_t * pte = (pte32_t *)(pde[i].pt_base_addr << PAGE_POWER);
24
25       /*
26         for (j = 0; (j < MAX_PTE32_ENTRIES); j++) {
27         if ((pte[j].present)) {
28         os_hooks->free_page((void *)(pte[j].page_base_addr << PAGE_POWER));
29         }
30         }
31       */
32       //PrintDebug("Deleting PTE %d (%x)\n", i, pte);
33       V3_FreePage(pte);
34     }
35   }
36
37   //  PrintDebug("Deleting PDE (%x)\n", pde);
38   V3_FreePage(pde);
39 }
40
41
42
43
44
45 int pt32_lookup(pde32_t * pd, addr_t vaddr, addr_t * paddr) {
46   addr_t pde_entry;
47   pde32_entry_type_t pde_entry_type;
48
49   if (pd == 0) {
50     return -1;
51   }
52
53   pde_entry_type = pde32_lookup(pd, vaddr, &pde_entry);
54
55   if (pde_entry_type == PDE32_ENTRY_PTE32) {
56     return pte32_lookup((pte32_t *)pde_entry, vaddr, paddr);
57   } else if (pde_entry_type == PDE32_ENTRY_LARGE_PAGE) {
58     *paddr = pde_entry;
59     return 0;
60   }
61
62   return -1;
63 }
64
65
66
67 /* We can't do a full lookup because we don't know what context the page tables are in...
68  * The entry addresses could be pointing to either guest physical memory or host physical memory
69  * Instead we just return the entry address, and a flag to show if it points to a pte or a large page...
70  */
71 pde32_entry_type_t pde32_lookup(pde32_t * pd, addr_t addr, addr_t * entry) {
72   pde32_t * pde_entry = &(pd[PDE32_INDEX(addr)]);
73
74   if (!pde_entry->present) {
75     *entry = 0;
76     return PDE32_ENTRY_NOT_PRESENT;
77   } else  {
78
79     if (pde_entry->large_page) {
80       pde32_4MB_t * large_pde = (pde32_4MB_t *)pde_entry;
81
82       *entry = PDE32_4MB_T_ADDR(*large_pde);
83       *entry += PD32_4MB_PAGE_OFFSET(addr);
84       return PDE32_ENTRY_LARGE_PAGE;
85     } else {
86       *entry = PDE32_T_ADDR(*pde_entry);
87       return PDE32_ENTRY_PTE32;
88     }
89   }  
90   return PDE32_ENTRY_NOT_PRESENT;
91 }
92
93
94
95 /* Takes a virtual addr (addr) and returns the physical addr (entry) as defined in the page table
96  */
97 int pte32_lookup(pte32_t * pt, addr_t addr, addr_t * entry) {
98   pte32_t * pte_entry = &(pt[PTE32_INDEX(addr)]);
99
100   if (!pte_entry->present) {
101     *entry = 0;
102     PrintDebug("Lookup at non present page (index=%d)\n", PTE32_INDEX(addr));
103     return -1;
104   } else {
105     *entry = PTE32_T_ADDR(*pte_entry) + PT32_PAGE_OFFSET(addr);
106     return 0;
107   }
108
109   return -1;
110 }
111
112
113
114 pt_access_status_t can_access_pde32(pde32_t * pde, addr_t addr, pf_error_t access_type) {
115   pde32_t * entry = &pde[PDE32_INDEX(addr)];
116
117   if (entry->present == 0) {
118     return PT_ENTRY_NOT_PRESENT;
119   } else if ((entry->writable == 0) && (access_type.write == 1)) {
120     return PT_WRITE_ERROR;
121   } else if ((entry->user_page == 0) && (access_type.user == 1)) {
122     // Check CR0.WP?
123     return PT_USER_ERROR;
124   }
125
126   return PT_ACCESS_OK;
127 }
128
129
130 pt_access_status_t can_access_pte32(pte32_t * pte, addr_t addr, pf_error_t access_type) {
131   pte32_t * entry = &pte[PTE32_INDEX(addr)];
132
133   if (entry->present == 0) {
134     return PT_ENTRY_NOT_PRESENT;
135   } else if ((entry->writable == 0) && (access_type.write == 1)) {
136     return PT_WRITE_ERROR;
137   } else if ((entry->user_page == 0) && (access_type.user == 1)) {
138     // Check CR0.WP?
139     return PT_USER_ERROR;
140   }
141
142   return PT_ACCESS_OK;
143 }
144
145
146
147
148 /* We generate a page table to correspond to a given memory layout
149  * pulling pages from the mem_list when necessary
150  * If there are any gaps in the layout, we add them as unmapped pages
151  */
152 pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info) {
153   ullong_t current_page_addr = 0;
154   int i, j;
155   struct shadow_map * map = &(guest_info->mem_map);
156
157   pde32_t * pde = V3_AllocPages(1);
158
159   for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
160     int pte_present = 0;
161     pte32_t * pte = V3_AllocPages(1);
162     
163
164     for (j = 0; j < MAX_PTE32_ENTRIES; j++) {
165       struct shadow_region * region = get_shadow_region_by_addr(map, current_page_addr);
166
167       if (!region || 
168           (region->host_type == HOST_REGION_HOOK) || 
169           (region->host_type == HOST_REGION_UNALLOCATED) || 
170           (region->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE) || 
171           (region->host_type == HOST_REGION_REMOTE) ||
172           (region->host_type == HOST_REGION_SWAPPED)) {
173         pte[j].present = 0;
174         pte[j].writable = 0;
175         pte[j].user_page = 0;
176         pte[j].write_through = 0;
177         pte[j].cache_disable = 0;
178         pte[j].accessed = 0;
179         pte[j].dirty = 0;
180         pte[j].pte_attr = 0;
181         pte[j].global_page = 0;
182         pte[j].vmm_info = 0;
183         pte[j].page_base_addr = 0;
184       } else {
185         addr_t host_addr;
186         pte[j].present = 1;
187         pte[j].writable = 1;
188         pte[j].user_page = 1;
189         pte[j].write_through = 0;
190         pte[j].cache_disable = 0;
191         pte[j].accessed = 0;
192         pte[j].dirty = 0;
193         pte[j].pte_attr = 0;
194         pte[j].global_page = 0;
195         pte[j].vmm_info = 0;
196
197         if (guest_pa_to_host_pa(guest_info, current_page_addr, &host_addr) == -1) {
198           // BIG ERROR
199           // PANIC
200           return NULL;
201         }
202         
203         pte[j].page_base_addr = host_addr >> 12;
204         
205         pte_present = 1;
206       }
207
208       current_page_addr += PAGE_SIZE;
209     }
210
211     if (pte_present == 0) { 
212       V3_FreePage(pte);
213
214       pde[i].present = 0;
215       pde[i].writable = 0;
216       pde[i].user_page = 0;
217       pde[i].write_through = 0;
218       pde[i].cache_disable = 0;
219       pde[i].accessed = 0;
220       pde[i].reserved = 0;
221       pde[i].large_page = 0;
222       pde[i].global_page = 0;
223       pde[i].vmm_info = 0;
224       pde[i].pt_base_addr = 0;
225     } else {
226       pde[i].present = 1;
227       pde[i].writable = 1;
228       pde[i].user_page = 1;
229       pde[i].write_through = 0;
230       pde[i].cache_disable = 0;
231       pde[i].accessed = 0;
232       pde[i].reserved = 0;
233       pde[i].large_page = 0;
234       pde[i].global_page = 0;
235       pde[i].vmm_info = 0;
236       pde[i].pt_base_addr = PAGE_ALIGNED_ADDR(pte);
237     }
238
239   }
240
241   return pde;
242 }
243
244
245
246
247
248
249 void PrintPDE32(addr_t virtual_address, pde32_t * pde)
250 {
251   PrintDebug("PDE %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
252              virtual_address,
253              (void *) (pde->pt_base_addr << PAGE_POWER),
254              pde->present,
255              pde->writable,
256              pde->user_page, 
257              pde->write_through,
258              pde->cache_disable,
259              pde->accessed,
260              pde->reserved,
261              pde->large_page,
262              pde->global_page,
263              pde->vmm_info);
264 }
265   
266 void PrintPTE32(addr_t virtual_address, pte32_t * pte)
267 {
268   PrintDebug("PTE %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, vmm_info=%x\n",
269              virtual_address,
270              (void*)(pte->page_base_addr << PAGE_POWER),
271              pte->present,
272              pte->writable,
273              pte->user_page,
274              pte->write_through,
275              pte->cache_disable,
276              pte->accessed,
277              pte->dirty,
278              pte->pte_attr,
279              pte->global_page,
280              pte->vmm_info);
281 }
282
283
284
285 void PrintPD32(pde32_t * pde)
286 {
287   int i;
288
289   PrintDebug("Page Directory at %p:\n", pde);
290   for (i = 0; (i < MAX_PDE32_ENTRIES); i++) { 
291     if ( pde[i].present) {
292       PrintPDE32((addr_t)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), &(pde[i]));
293     }
294   }
295 }
296
297 void PrintPT32(addr_t starting_address, pte32_t * pte) 
298 {
299   int i;
300
301   PrintDebug("Page Table at %p:\n", pte);
302   for (i = 0; (i < MAX_PTE32_ENTRIES) ; i++) { 
303     if (pte[i].present) {
304       PrintPTE32(starting_address + (PAGE_SIZE * i), &(pte[i]));
305     }
306   }
307 }
308
309
310
311
312
313 void PrintDebugPageTables(pde32_t * pde)
314 {
315   int i;
316   
317   PrintDebug("Dumping the pages starting with the pde page at %p\n", pde);
318
319   for (i = 0; (i < MAX_PDE32_ENTRIES); i++) { 
320     if (pde[i].present) {
321       PrintPDE32((addr_t)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), &(pde[i]));
322       PrintPT32((addr_t)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), (pte32_t *)(pde[i].pt_base_addr << PAGE_POWER));
323     }
324   }
325 }
326