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.


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