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.


Functional 2 core linux guest
[palacios.git] / palacios / src / palacios / vmm_direct_paging_64.h
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, Steven Jaconette <stevenjaconette2007@u.northwestern.edu>
11  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
12  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
13  * All rights reserved.
14  *
15  * Author: Steven Jaconette <stevenjaconette2007@u.northwestern.edu>
16  *
17  * This is free software.  You are permitted to use,
18  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
19  */
20
21 #ifndef __VMM_DIRECT_PAGING_64_H__
22 #define __VMM_DIRECT_PAGING_64_H__
23
24 #include <palacios/vmm_mem.h>
25 #include <palacios/vmm_paging.h>
26 #include <palacios/vmm.h>
27 #include <palacios/vm_guest_mem.h>
28 #include <palacios/vm_guest.h>
29
30 // Reference: AMD Software Developer Manual Vol.2 Ch.5 "Page Translation and Protection"
31
32 static inline int handle_passthrough_pagefault_64(struct guest_info * info, 
33                                                   addr_t fault_addr, 
34                                                   pf_error_t error_code) {
35     pml4e64_t * pml      = NULL;
36     pdpe64_t * pdpe      = NULL;
37     pde64_t * pde        = NULL;
38     pde64_2MB_t * pde2mb = NULL;
39     pte64_t * pte        = NULL;
40     addr_t host_addr     = 0;
41
42     int pml_index  = PML4E64_INDEX(fault_addr);
43     int pdpe_index = PDPE64_INDEX(fault_addr);
44     int pde_index  = PDE64_INDEX(fault_addr);
45     int pte_index  = PTE64_INDEX(fault_addr);
46
47     struct v3_mem_region * region =  v3_get_mem_region(info->vm_info, info->cpu_id, fault_addr);
48     struct v3_mem_region * base_reg = &(info->vm_info->mem_map.base_region);
49
50     /* If the guest has been configured for 2MiB pages, then we must check for hooked regions of
51      * memory which may overlap with the 2MiB page containing the faulting address (due to
52      * potentially differing access policies in place for e.g. i/o devices and APIC). A 2MiB page
53      * can be used if a) no region overlaps the page [or b) a region does overlap but fully contains
54      * the page]. The [bracketed] text pertains to the #if 0'd code below, state D. TODO modify this
55      * note if someone decides to enable this optimization. It can be tested with the SeaStar
56      * mapping.
57      *
58      * Examples: (CAPS regions are returned by v3_get_next_mem_region; state A returns the base reg)
59      *
60      *    |region| |region|                               2MiB mapped (state A)
61      *                   |reg|          |REG|             2MiB mapped (state B)
62      *   |region|     |reg|   |REG| |region|   |reg|      4KiB mapped (state C)
63      *        |reg|  |reg|   |--REGION---|                [2MiB mapped (state D)]
64      * |--------------------------------------------|     RAM
65      *                             ^                      fault addr
66      * |----|----|----|----|----|page|----|----|----|     2MB pages
67      *                           >>>>>>>>>>>>>>>>>>>>     search space
68      */
69     addr_t pg_start = 0UL, pg_end = 0UL; // 2MiB page containing the faulting address
70     struct v3_mem_region * pg_next_reg = NULL; // next immediate mem reg after page start addr
71     bool use_large_page = false;
72
73     if (region == NULL) {
74         PrintError("%s: invalid region, addr=%p\n", __FUNCTION__, (void *)fault_addr);
75         return -1;
76     }
77
78     // set use_large_page here
79     if (info->vm_info->paging_size == PAGING_2MB) {
80
81         // guest page maps to a host page + offset (so when we shift, it aligns with a host page)
82         pg_start = PAGE_ADDR_2MB(fault_addr);
83         pg_end = (pg_start + PAGE_SIZE_2MB);
84
85         PrintDebug("%s: page   [%p,%p) contains address\n", __FUNCTION__, (void *)pg_start, (void *)pg_end);
86
87         pg_next_reg = v3_get_next_mem_region(info->vm_info, info->cpu_id, pg_start);
88
89         if (pg_next_reg == NULL) {
90             PrintError("%s: Error: address not in base region, %p\n", __FUNCTION__, (void *)fault_addr);
91             return -1;
92         }
93
94         if ((pg_next_reg->guest_start == base_reg->guest_start) &&
95                 (pg_next_reg->guest_end == base_reg->guest_end)) { // next region == base region
96             use_large_page = 1; // State A
97         } else {
98 #if 0       // State B/C and D optimization
99             use_large_page = (pg_next_reg->guest_end >= pg_end) &&
100                 ((pg_next_reg->guest_start >= pg_end) || (pg_next_reg->guest_start <= pg_start));
101             PrintDebug("%s: region [%p,%p) %s partial overlap with page\n", __FUNCTION__,
102                     (void *)pg_next_reg->guest_start, (void *)pg_next_reg->guest_end,
103                     (use_large_page ? "does not have" : "has"));
104 #else       // State B/C
105             use_large_page = (pg_next_reg->guest_start >= pg_end);
106             PrintDebug("%s: region [%p,%p) %s overlap with page\n", __FUNCTION__,
107                     (void *)pg_next_reg->guest_start, (void *)pg_next_reg->guest_end,
108                     (use_large_page ? "does not have" : "has"));
109 #endif
110         }
111     }
112
113     PrintDebug("%s: Address gets a 2MiB page? %s\n", __FUNCTION__, (use_large_page ? "yes" : "no"));
114
115     // Lookup the correct PML address based on the PAGING MODE
116     if (info->shdw_pg_mode == SHADOW_PAGING) {
117         pml = CR3_TO_PML4E64_VA(info->ctrl_regs.cr3);
118     } else {
119         pml = CR3_TO_PML4E64_VA(info->direct_map_pt);
120     }
121
122     //Fix up the PML entry
123     if (pml[pml_index].present == 0) {
124         pdpe = (pdpe64_t *)create_generic_pt_page();
125    
126         // Set default PML Flags...
127         pml[pml_index].present = 1;
128         pml[pml_index].writable = 1;
129         pml[pml_index].user_page = 1;
130
131         pml[pml_index].pdp_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pdpe));
132     } else {
133         pdpe = V3_VAddr((void*)BASE_TO_PAGE_ADDR_4KB(pml[pml_index].pdp_base_addr));
134     }
135
136     // Fix up the PDPE entry
137     if (pdpe[pdpe_index].present == 0) {
138         pde = (pde64_t *)create_generic_pt_page();
139         
140         // Set default PDPE Flags...
141         pdpe[pdpe_index].present = 1;
142         pdpe[pdpe_index].writable = 1;
143         pdpe[pdpe_index].user_page = 1;
144
145         pdpe[pdpe_index].pd_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pde));
146     } else {
147         pde = V3_VAddr((void*)BASE_TO_PAGE_ADDR_4KB(pdpe[pdpe_index].pd_base_addr));
148     }
149
150     // Fix up the 2MiB PDE and exit here
151     if (use_large_page) {
152
153         pde2mb = (pde64_2MB_t *)pde; // all but these two lines are the same for PTE
154         pde2mb[pde_index].large_page = 1;
155
156         if (pde2mb[pde_index].present == 0) {
157             pde2mb[pde_index].user_page = 1;
158
159             if ((region->flags.alloced == 1) && (region->flags.read == 1)) {
160                 // Full access
161                 pde2mb[pde_index].present = 1;
162
163                 if (region->flags.write == 1) {
164                     pde2mb[pde_index].writable = 1;
165                 } else {
166                     pde2mb[pde_index].writable = 0;
167                 }
168
169                 if (v3_gpa_to_hpa(info, fault_addr, &host_addr) == -1) {
170                     PrintError("Error Could not translate fault addr (%p)\n", (void *)fault_addr);
171                     return -1;
172                 }
173
174                 pde2mb[pde_index].page_base_addr = PAGE_BASE_ADDR_2MB(host_addr);
175             } else {
176                 return region->unhandled(info, fault_addr, fault_addr, region, error_code);
177             }
178         } else {
179             // We fix all permissions on the first pass,
180             // so we only get here if its an unhandled exception
181
182             return region->unhandled(info, fault_addr, fault_addr, region, error_code);
183         }
184     }
185
186     // Continue with the 4KiB page heirarchy
187
188     // Fix up the PDE entry
189     if (pde[pde_index].present == 0) {
190         pte = (pte64_t *)create_generic_pt_page();
191         
192         pde[pde_index].present = 1;
193         pde[pde_index].writable = 1;
194         pde[pde_index].user_page = 1;
195         
196         pde[pde_index].pt_base_addr = PAGE_BASE_ADDR_4KB((addr_t)V3_PAddr(pte));
197     } else {
198         pte = V3_VAddr((void*)BASE_TO_PAGE_ADDR_4KB(pde[pde_index].pt_base_addr));
199     }
200
201
202     // Fix up the PTE entry
203     if (pte[pte_index].present == 0) {
204         pte[pte_index].user_page = 1;
205         
206         if ((region->flags.alloced == 1) && 
207             (region->flags.read == 1)) {
208             // Full access
209             pte[pte_index].present = 1;
210
211             if (region->flags.write == 1) {
212                 pte[pte_index].writable = 1;
213             } else {
214                 pte[pte_index].writable = 0;
215             }
216
217             if (v3_gpa_to_hpa(info, fault_addr, &host_addr) == -1) {
218                 PrintError("Error Could not translate fault addr (%p)\n", (void *)fault_addr);
219                 return -1;
220             }
221
222             pte[pte_index].page_base_addr = PAGE_BASE_ADDR_4KB(host_addr);
223         } else {
224             return region->unhandled(info, fault_addr, fault_addr, region, error_code);
225         }
226     } else {
227         // We fix all permissions on the first pass, 
228         // so we only get here if its an unhandled exception
229
230         return region->unhandled(info, fault_addr, fault_addr, region, error_code);
231     }
232
233     return 0;
234 }
235
236 static inline int invalidate_addr_64(struct guest_info * info, addr_t inv_addr) {
237     pml4e64_t * pml = NULL;
238     pdpe64_t * pdpe = NULL;
239     pde64_t * pde = NULL;
240     pte64_t * pte = NULL;
241
242
243     // TODO:
244     // Call INVLPGA
245
246     // clear the page table entry
247     int pml_index = PML4E64_INDEX(inv_addr);
248     int pdpe_index = PDPE64_INDEX(inv_addr);
249     int pde_index = PDE64_INDEX(inv_addr);
250     int pte_index = PTE64_INDEX(inv_addr);
251
252     
253     // Lookup the correct PDE address based on the PAGING MODE
254     if (info->shdw_pg_mode == SHADOW_PAGING) {
255         pml = CR3_TO_PML4E64_VA(info->ctrl_regs.cr3);
256     } else {
257         pml = CR3_TO_PML4E64_VA(info->direct_map_pt);
258     }
259
260     if (pml[pml_index].present == 0) {
261         return 0;
262     }
263
264     pdpe = V3_VAddr((void*)BASE_TO_PAGE_ADDR(pml[pml_index].pdp_base_addr));
265
266     if (pdpe[pdpe_index].present == 0) {
267         return 0;
268     } else if (pdpe[pdpe_index].large_page == 1) { // 1GiB
269         pdpe[pdpe_index].present = 0;
270         return 0;
271     }
272
273     pde = V3_VAddr((void*)BASE_TO_PAGE_ADDR(pdpe[pdpe_index].pd_base_addr));
274
275     if (pde[pde_index].present == 0) {
276         return 0;
277     } else if (pde[pde_index].large_page == 1) { // 2MiB
278         pde[pde_index].present = 0;
279         return 0;
280     }
281
282     pte = V3_VAddr((void*)BASE_TO_PAGE_ADDR(pde[pde_index].pt_base_addr));
283
284     pte[pte_index].present = 0; // 4KiB
285
286     return 0;
287 }
288
289
290
291 #endif