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.


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