Develop and Download Open Source Software

Browse Subversion Repository

Contents of /branches/ept-devel/vmm/core/vt_ept.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (show annotations) (download) (as text)
Sat May 5 12:42:38 2012 UTC (12 months, 2 weeks ago) by yuichi_xy
File MIME type: text/x-csrc
File size: 10158 byte(s)
EPT が有効な場合は、 Guest OS が指定した PAT を物理 PAT として使用するようにした。つまり、VM-entry/VM-exitで Guest 用 PAT と Host 用 PAT を切り替える。
1 /*
2 * Copyright (c) 2007, 2008 University of Tsukuba
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. Neither the name of the University of Tsukuba nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29 /*
30 * Copyright (c) 2010-2012 Yuichi Watanabe
31 */
32
33 #include <core/mm.h>
34 #include <core/printf.h>
35 #include <core/thread.h>
36 #include "apic_pass.h"
37 #include "asm.h"
38 #include "cpu_mmu.h"
39 #include "mm.h"
40 #include "mtrr.h"
41 #include "vt_internal.h"
42 #include "constants.h"
43 #include "current.h"
44
45 #define EPT_MAX_LEVEL 4
46 #define EPT_LEVEL_STRIDE (9)
47 #define EPT_LEVEL_MASK ((1 << EPT_LEVEL_STRIDE) - 1)
48
49 #define EPT_READ 0x1
50 #define EPT_WRITE 0x2
51 #define EPT_EXECUTE 0x4
52 #define EPT_VAILED_MASK 0x7
53 #define EPT_MEMTYPE_TO_PTE(memtype) ((memtype) << 3)
54
55 #define VMCS_EPT_POINTER_ADDR_WB 0x6
56 #define VMCS_EPT_POINTER_ADDR_EPT_LENGTH ((EPT_MAX_LEVEL - 1) << 3)
57
58 #define VMCS_EXIT_QUALIFICATION_READ_BIT 0x1
59 #define VMCS_EXIT_QUALIFICATION_WRITE_BIT 0x2
60 #define VMCS_EXIT_QUALIFICATION_INST_BIT 0x4
61 #define VMCS_EXIT_QUALIFICATION_LINEAR_ADDR_VALID_BIT 0x80
62
63
64 #define ept_offset(addr, level) \
65 ((addr >> (PAGE_SHIFT + (level - 1) * EPT_LEVEL_STRIDE)) \
66 & EPT_LEVEL_MASK)
67
68 static void
69 vt_ept_invalidate_tlb(void)
70 {
71 struct {
72 u64 ept_l4tbl;
73 u64 reserved;
74 } desc;
75
76 desc.ept_l4tbl = current->vm->vt.ept_l4tbl;
77 desc.reserved = 0;
78 asm_invept(&desc);
79 }
80
81 void
82 vt_ept_init(void)
83 {
84 struct vt_vm_data *vt_data = &current->vm->vt;
85 u32 ctls;
86 u32 ctls_or, ctls_and;
87 u32 ctls2_or, ctls2_and;
88 u32 exit_ctls_or, exit_ctls_and;
89 u32 entry_ctls_or, entry_ctls_and;
90 void *vaddr;
91 vmmerr_t err;
92 u64 pat;
93
94 asm_rdmsr32(MSR_IA32_VMX_PROCBASED_CTLS, &ctls_or, &ctls_and);
95 if ((ctls_and & VMCS_PROC_BASED_VMEXEC_CTL_SEC_CTL_BIT) == 0 ||
96 ctls_or & VMCS_PROC_BASED_VMEXEC_CTL_INVLPGEXIT_BIT) {
97 return;
98 }
99 asm_rdmsr32(MSR_IA32_VMX_PROCBASED_CTLS2, &ctls2_or, &ctls2_and);
100 if ((ctls2_and & VMCS_PROC_BASED_VMEXEC_CTL2_EPT_BIT) == 0) {
101 return;
102 }
103
104 asm_rdmsr32(MSR_IA32_VMX_EXIT_CTLS, &exit_ctls_or, &exit_ctls_and);
105 if ((exit_ctls_or & VMCS_VMEXIT_CTL_LOAD_IA32_PAT_BIT) ||
106 (exit_ctls_and & VMCS_VMEXIT_CTL_LOAD_IA32_PAT_BIT) == 0) {
107 return;
108 }
109 asm_rdmsr32 (MSR_IA32_VMX_ENTRY_CTLS, &entry_ctls_or, &entry_ctls_and);
110 if ((entry_ctls_or & VMCS_VMENTRY_CTL_LOAD_IA32_PAT_BIT) ||
111 (entry_ctls_and & VMCS_VMENTRY_CTL_LOAD_IA32_PAT_BIT) == 0) {
112 return;
113 }
114
115 if (cpu_is_bsp()) {
116 printf("Enabling EPT\n");
117 }
118
119 current->u.vt.ept_enabled = true;
120
121 spinlock_lock(&vt_data->ept_lock);
122 if (vt_data->ept_l4tbl == 0) {
123 err = alloc_page(&vaddr, &vt_data->ept_l4tbl);
124 if (err) {
125 panic("Failed to allocate a ept l4tbl.");
126 }
127 memset(vaddr, 0, PAGE_SIZE);
128 }
129 spinlock_unlock(&vt_data->ept_lock);
130
131 ctls = ctls2_or | VMCS_PROC_BASED_VMEXEC_CTL2_EPT_BIT;
132 asm_vmwrite32(VMCS_PROC_BASED_VMEXEC_CTL2, ctls);
133
134 asm_vmread32(VMCS_PROC_BASED_VMEXEC_CTL, &ctls);
135 ctls &= ~VMCS_PROC_BASED_VMEXEC_CTL_INVLPGEXIT_BIT;
136 ctls |= VMCS_PROC_BASED_VMEXEC_CTL_SEC_CTL_BIT;
137 asm_vmwrite32(VMCS_PROC_BASED_VMEXEC_CTL, ctls);
138
139 asm_vmwrite32(VMCS_EXCEPTION_BMP, 0xffffbfff);
140 asm_vmwrite32(VMCS_PAGEFAULT_ERRCODE_MASK, 0);
141 asm_vmwrite32(VMCS_PAGEFAULT_ERRCODE_MATCH, 0xffffffff);
142
143 asm_vmwrite64(VMCS_EPT_POINTER_ADDR,
144 vt_data->ept_l4tbl |
145 VMCS_EPT_POINTER_ADDR_WB |
146 VMCS_EPT_POINTER_ADDR_EPT_LENGTH);
147
148 asm_vmread32(VMCS_VMEXIT_CTL, &ctls);
149 ctls |= VMCS_VMEXIT_CTL_LOAD_IA32_PAT_BIT;
150 asm_vmwrite32(VMCS_VMEXIT_CTL, ctls);
151
152 asm_vmread32(VMCS_VMENTRY_CTL, &ctls);
153 ctls |= VMCS_VMENTRY_CTL_LOAD_IA32_PAT_BIT;
154 asm_vmwrite32(VMCS_VMENTRY_CTL, ctls);
155
156 asm_rdmsr64(MSR_IA32_PAT, &pat);
157 asm_vmwrite64(VMCS_HOST_IA32_PAT, pat);
158
159 /*
160 * Guest IA32_PAT will be set by msr_init
161 * so that we don't need to set guest IA32_PAT here.
162 */
163 }
164
165 static u64 *
166 vt_ept_walk(phys_t gphys, void *ept_l4tbl)
167 {
168 u64 *tbl;
169 int offset;
170 u64 *pte;
171 int cur_level;
172 void *vaddr;
173 phys_t phys;
174 vmmerr_t ret;
175
176 tbl = ept_l4tbl;
177
178 for (cur_level = EPT_MAX_LEVEL; cur_level >= 2; cur_level--) {
179 offset = ept_offset(gphys, cur_level);
180 pte = &tbl[offset];
181
182 if ((*pte & EPT_VAILED_MASK) == 0) {
183 ret = alloc_page(&vaddr, &phys);
184 if (ret != VMMERR_SUCCESS) {
185 return NULL;
186 }
187 memset(vaddr, 0, PAGE_SIZE);
188
189 *pte = (phys & PAGE_MASK) |
190 EPT_READ | EPT_WRITE | EPT_EXECUTE;
191 } else {
192 phys = *pte & PAGE_MASK;
193 vaddr = (void *)phys_to_virt(phys);
194 }
195 tbl = (u64 *)vaddr;
196 };
197
198 return tbl + ept_offset(gphys, cur_level);
199 }
200
201 static void
202 vt_ept_generate_pagefault(vmmerr_t vmmerr)
203 {
204 bool wr, us;
205 ulong linear_addr;
206 ulong qual;
207
208 asm_vmread(VMCS_EXIT_QUALIFICATION, &qual);
209 if ((qual & VMCS_EXIT_QUALIFICATION_LINEAR_ADDR_VALID_BIT) == 0) {
210 panic("EPT violation without linear address. qual 0x%lx",
211 qual);
212 }
213 wr = qual & VMCS_EXIT_QUALIFICATION_WRITE_BIT ? true : false;
214 us = seg_user_mode();
215 asm_vmread(VMCS_GUEST_LINEAR_ADDR, &linear_addr);
216 printf("vt_ept_generate_pagefault 0x%lx wr %d us %d\n",
217 linear_addr, wr, us);
218 mmu_generate_pagefault(vmmerr, wr, us, linear_addr);
219 }
220
221 void
222 vt_ept_violation(void)
223 {
224 struct vt_vm_data *vt_data = &current->vm->vt;
225 void *ept_l4tbl;
226 u64 *pte;
227 u8 memtype;
228 phys_t gphys;
229 phys_t hphys;
230 vmmerr_t ret;
231
232 asm_vmread64(VMCS_GUEST_PHYS_ADDR, &gphys);
233
234 mmio_lock();
235 ret = mmio_pagefault(gphys);
236 mmio_unlock();
237 if (ret != VMMERR_NODEV) {
238 if (ret == VMMERR_SUCCESS) {
239 return;
240 }
241 if (ret < VMMERR_PAGE_NOT_PRESENT ||
242 ret > VMMERR_PAGE_BAD_RESERVED_BIT) {
243 panic("Failed to emulate accessing to MMIO area. ret 0x%x",
244 ret);
245 }
246 vt_ept_generate_pagefault(ret);
247 return;
248 }
249
250 hphys = current->vm->gmm.gp2hp(gphys);
251 if (hphys == GMM_NO_MAPPING) {
252 ret = cpu_interpreter();
253 if (ret == VMMERR_SUCCESS) {
254 return;
255 }
256 if (ret < VMMERR_PAGE_NOT_PRESENT ||
257 ret > VMMERR_PAGE_BAD_RESERVED_BIT) {
258 panic("Failed to emulate accessing to no mapping area. ret 0x%x",
259 ret);
260 }
261 vt_ept_generate_pagefault(ret);
262 return;
263 }
264
265 memtype = mtrr_get_mem_type(hphys);
266
267 spinlock_lock(&vt_data->ept_lock);
268 ept_l4tbl = (void *)phys_to_virt(vt_data->ept_l4tbl);
269 pte = vt_ept_walk(gphys, ept_l4tbl);
270
271 if (*pte & EPT_VAILED_MASK) {
272 if ((*pte & PAGE_MASK) != (hphys & PAGE_MASK)) {
273 panic("EPT PTE is already set. "
274 "gphys 0x%llx, hphys 0x%llx, pte 0x%llx",
275 gphys, hphys, *pte);
276 }
277 } else {
278 *pte = (hphys & PAGE_MASK) |
279 EPT_READ | EPT_WRITE | EPT_EXECUTE |
280 EPT_MEMTYPE_TO_PTE(memtype);
281 }
282
283 spinlock_unlock(&vt_data->ept_lock);
284
285 }
286
287 void
288 vt_ept_pg_change(bool pg)
289 {
290 ulong cr4;
291 u32 ctls;
292
293 if (!current->u.vt.ept_enabled) {
294 return;
295 }
296
297 if (pg) {
298 /*
299 * - Enable EPT.
300 * - Don't cause VM-exit on invlpg.
301 * - Don't cause VM-exit on page fault.
302 * - Load IA32_PAT on VM-exit and VM-entry.
303 * - Set Guest CR3 to the value set by guest software
304 * instead of shadow table.
305 */
306 asm_vmread32(VMCS_PROC_BASED_VMEXEC_CTL2, &ctls);
307 ctls |= VMCS_PROC_BASED_VMEXEC_CTL2_EPT_BIT;
308 asm_vmwrite32(VMCS_PROC_BASED_VMEXEC_CTL2, ctls);
309
310 asm_vmread32(VMCS_PROC_BASED_VMEXEC_CTL, &ctls);
311 ctls &= ~VMCS_PROC_BASED_VMEXEC_CTL_INVLPGEXIT_BIT;
312 asm_vmwrite32(VMCS_PROC_BASED_VMEXEC_CTL, ctls);
313
314 asm_vmwrite32(VMCS_EXCEPTION_BMP, 0xffffbfff);
315 asm_vmwrite32(VMCS_PAGEFAULT_ERRCODE_MASK, 0);
316 asm_vmwrite32(VMCS_PAGEFAULT_ERRCODE_MATCH, 0xffffffff);
317
318 asm_vmread32(VMCS_VMEXIT_CTL, &ctls);
319 ctls |= VMCS_VMEXIT_CTL_LOAD_IA32_PAT_BIT;
320 asm_vmwrite32(VMCS_VMEXIT_CTL, ctls);
321
322 asm_vmread32(VMCS_VMENTRY_CTL, &ctls);
323 ctls |= VMCS_VMENTRY_CTL_LOAD_IA32_PAT_BIT;
324 asm_vmwrite32(VMCS_VMENTRY_CTL, ctls);
325
326 asm_vmwrite32(VMCS_GUEST_CR3, current->u.vt.vr.cr3);
327 } else {
328 /*
329 * - Disable EPT.
330 * - Cause VM-exit on invlpg.
331 * - Cause VM-exit on page fault.
332 * - Don't load IA32_PAT on VM-exit and VM-entry.
333 *
334 * Guest CR3 will be updated by cpu_mmu_spt_updatecr3,
335 * so that we don't need to set guest CR3 here.
336 */
337 asm_vmread32(VMCS_PROC_BASED_VMEXEC_CTL2, &ctls);
338 ctls &= ~VMCS_PROC_BASED_VMEXEC_CTL2_EPT_BIT;
339 asm_vmwrite32(VMCS_PROC_BASED_VMEXEC_CTL2, ctls);
340
341 asm_vmread32(VMCS_PROC_BASED_VMEXEC_CTL, &ctls);
342 ctls |= VMCS_PROC_BASED_VMEXEC_CTL_INVLPGEXIT_BIT;
343 asm_vmwrite32(VMCS_PROC_BASED_VMEXEC_CTL, ctls);
344
345 asm_vmwrite32(VMCS_EXCEPTION_BMP, 0xffffffff);
346 asm_vmwrite32(VMCS_PAGEFAULT_ERRCODE_MASK, 0);
347 asm_vmwrite32(VMCS_PAGEFAULT_ERRCODE_MATCH, 0);
348
349 asm_vmread32(VMCS_VMEXIT_CTL, &ctls);
350 ctls &= ~VMCS_VMEXIT_CTL_LOAD_IA32_PAT_BIT;
351 asm_vmwrite32(VMCS_VMEXIT_CTL, ctls);
352
353 asm_vmread32(VMCS_VMENTRY_CTL, &ctls);
354 ctls &= ~VMCS_VMENTRY_CTL_LOAD_IA32_PAT_BIT;
355 asm_vmwrite32(VMCS_VMENTRY_CTL, ctls);
356 }
357 vt_read_control_reg(CONTROL_REG_CR4, &cr4);
358 vt_write_control_reg(CONTROL_REG_CR4, cr4);
359
360 vt_ept_invalidate_tlb();
361 }

SourceForge.JP is a Japanese version of SourceForge.net. For developments that are not related to Japan, we recommend you to use SourceForge.net.