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.


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