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.


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