Develop and Download Open Source Software

Browse Subversion Repository

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 25 - (show annotations) (download) (as text)
Fri May 4 15:02:17 2012 UTC (12 months, 2 weeks ago) by yuichi_xy
File MIME type: text/x-csrc
File size: 13497 byte(s)
BIOS が設定した MTTR の値から物理メモリアドレス領域のキャッシュ属性を取得し、EPT に反映するようにした。不要な関数テーブルである struct cpuid_func と struct msr_func を削除した。
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/assert.h>
34 #include <core/string.h>
35 #include <core/mm.h>
36 #include <core/printf.h>
37 #include "constants.h"
38 #include "cpu_mmu.h"
39 #include "current.h"
40 #include "mm.h"
41 #include "msr_pass.h"
42 #include "panic.h"
43
44 #define USER_MODE()\
45 seg_user_mode();
46
47 struct get_pte_data {
48 unsigned int pg : 1; /* PG (Paging): CR0 bit 31 */
49 unsigned int wp : 1; /* WP (Write Protect): CR0 bit 16 */
50 unsigned int pse : 1; /* PSE (Page Size Extensions): CR4 bit 4 */
51 unsigned int pae : 1; /* PAE (Physical Address Extensions):CR4bit5 */
52 unsigned int lme : 1; /* LME (Long Mode Enable): MSR(EFER) bit 8 */
53 unsigned int nxe : 1; /* NXE (No-Execute Enable):MSR(EFER) bit 10 */
54 unsigned int write : 1; /* Write access. Set D bit if 1 */
55 unsigned int user : 1; /* User access */
56 unsigned int exec : 1; /* Execution */
57 };
58
59 static u64 reserved_bit_table[2][3][5] = {
60 /* NXE = 0 */
61 {
62 /* levels = 2 (32-bit, PAE = 0, PSE = 1) */
63 {
64 0x0000000000200000ULL, /* PDE, 4-MByte page */
65 0x0000000000000000ULL, /* PTE */
66 0x0000000000000000ULL, /* PDE, 4-KByte page */
67 0xFFFFFFFFFFFFFFFFULL, /* PDPTE */
68 0xFFFFFFFFFFFFFFFFULL, /* PML4E */
69 },
70 /* levels = 3 (32-bit, PAE = 1) */
71 {
72 0xFFFFFF00001FE000ULL, /* PDE, 2-MByte page */
73 0xFFFFFF0000000000ULL, /* PTE */
74 0xFFFFFF0000000000ULL, /* PDE, 4-KByte page */
75 0xFFFFFF00000001E6ULL, /* PDPTE */
76 0xFFFFFFFFFFFFFFFFULL, /* PML4E */
77 },
78 /* levels = 4 (64-bit) */
79 {
80 0x800FFF00001FE000ULL, /* PDE, 2-MByte page */
81 0x800FFF0000000000ULL, /* PTE */
82 0x800FFF0000000000ULL, /* PDE, 4-KByte page */
83 0x800FFF0000000000ULL, /* PDPTE */
84 0x800FFF0000000000ULL, /* PML4E */
85 },
86 },
87 /* NXE = 1 */
88 {
89 /* levels = 2 (32-bit, PAE = 0, PSE = 1) */
90 {
91 0x0000000000200000ULL, /* PDE, 4-MByte page */
92 0x0000000000000000ULL, /* PTE */
93 0x0000000000000000ULL, /* PDE, 4-KByte page */
94 0xFFFFFFFFFFFFFFFFULL, /* PDPTE */
95 0xFFFFFFFFFFFFFFFFULL, /* PML4E */
96 },
97 /* levels = 3 (32-bit, PAE = 1) */
98 {
99 0x7FFFFF00001FE000ULL, /* PDE, 2-MByte page */
100 0x7FFFFF0000000000ULL, /* PTE */
101 0x7FFFFF0000000000ULL, /* PDE, 4-KByte page */
102 0xFFFFFF00000001E6ULL, /* PDPTE */
103 0xFFFFFFFFFFFFFFFFULL, /* PML4E */
104 },
105 /* levels = 4 (64-bit) */
106 {
107 0x000FFF00001FE000ULL, /* PDE, 2-MByte page */
108 0x000FFF0000000000ULL, /* PTE */
109 0x000FFF0000000000ULL, /* PDE, 4-KByte page */
110 0x000FFF0000000000ULL, /* PDPTE */
111 0x000FFF0000000000ULL, /* PML4E */
112 },
113 },
114 };
115
116 static bool
117 test_pmap_entry_reserved_bit (u64 entry, int level, int levels,
118 struct get_pte_data d)
119 {
120 u64 mask;
121
122 if (!d.pae && !d.pse) /* PAE = 0, PSE = 0 */
123 return false; /* No reserved bits checked */
124 if (level == 2 && (entry & PDE_PS_BIT))
125 level = 0;
126 mask = reserved_bit_table[d.nxe][levels - 2][level];
127 ASSERT (mask != 0xFFFFFFFFFFFFFFFFULL);
128 if (entry & mask)
129 return true;
130 return false;
131 }
132
133 static bool
134 set_ad_bit (pmap_t *m, u64 entry, bool seta, bool setd)
135 {
136 if (entry & PDE_A_BIT)
137 seta = false;
138 if (entry & PDE_D_BIT)
139 setd = false;
140 if (seta || setd) {
141 if (seta)
142 entry |= PDE_A_BIT;
143 if (setd)
144 entry |= PDE_D_BIT;
145 return pmap_write (m, entry, 0xFFF);
146 } else {
147 return false;
148 }
149 }
150
151 /* simplify1: entries[0] & entries[1] are generated when paging is disabled */
152 /* simplify2: entries[2] (PDPTE) |= RW|US|A when 32-bit PAE */
153 /* simplify3: entries[1] (PDE) &= ~PS when PSE is disabled */
154 /* simplify : entries[] are 64-bit when PAE is disabled */
155 /* simplify : entries[0] (PTE) will be generated when it is in a large page */
156 static vmmerr_t
157 get_pte_sub (ulong virt, ulong cr3, struct get_pte_data d, u64 entries[5],
158 int *plevels)
159 {
160 pmap_t m;
161 int levels;
162 int i;
163 u64 entry;
164 vmmerr_t r;
165
166 if (!d.pg) {
167 /* Paging disabled */
168 /* simplify1 */
169 entries[0] = (virt & PTE_ADDR_MASK64) | PTE_P_BIT | PTE_RW_BIT
170 | PTE_US_BIT | PTE_A_BIT | PTE_D_BIT;
171 entries[1] = PDE_P_BIT | PDE_RW_BIT | PDE_US_BIT | PDE_A_BIT
172 | PDE_D_BIT | PDE_PS_BIT;
173 *plevels = 1;
174 return VMMERR_SUCCESS;
175 }
176 /* Paging enabled */
177 if (d.lme) {
178 d.pae = 1;
179 d.pse = 1;
180 levels = 4;
181 } else if (d.pae) {
182 d.pse = 1;
183 levels = 3;
184 } else {
185 levels = 2;
186 }
187 *plevels = levels;
188 pmap_open_guest (&m, cr3, levels, true);
189 pmap_setvirt (&m, virt, levels + 1);
190 entry = pmap_read (&m);
191 entry |= PDE_RW_BIT | PDE_US_BIT | PDE_A_BIT;
192 entries[levels] = entry;
193 for (i = levels; i >= 1; i--) {
194 pmap_setlevel (&m, i);
195 retry:
196 entry = pmap_read (&m);
197 if (!(entry & PDE_P_BIT))
198 goto ret_nopage;
199 if (test_pmap_entry_reserved_bit (entry, i, levels, d))
200 goto ret_reserved;
201 if (levels == 3 && i == 3) /* simplify2 */
202 entry |= PDE_RW_BIT | PDE_US_BIT | PDE_A_BIT;
203 if (!(entry & PDE_US_BIT) && d.user)
204 goto ret_noaccess;
205 if (!(entry & PDE_RW_BIT) && d.write && (d.wp || d.user))
206 goto ret_noaccess;
207 if ((entry & PDE_NX_BIT) && d.exec && d.nxe)
208 goto ret_noexec;
209 if (i == 2 && !d.pse) /* simplify3 */
210 entry &= ~(u64)PDE_PS_BIT;
211 if ((i == 2 && (entry & PDE_PS_BIT)) || i == 1) {
212 if (set_ad_bit (&m, entry, true, d.write))
213 goto retry;
214 } else {
215 if (set_ad_bit (&m, entry, true, false))
216 goto retry;
217 }
218 entries[i - 1] = entry;
219 }
220 r = VMMERR_SUCCESS;
221 ret:
222 pmap_close (&m);
223 return r;
224 ret_nopage:
225 r = VMMERR_PAGE_NOT_PRESENT;
226 goto ret;
227 ret_reserved:
228 r = VMMERR_PAGE_BAD_RESERVED_BIT;
229 goto ret;
230 ret_noaccess:
231 r = VMMERR_PAGE_NOT_ACCESSIBLE;
232 goto ret;
233 ret_noexec:
234 r = VMMERR_PAGE_NOT_EXECUTABLE;
235 goto ret;
236 }
237
238 vmmerr_t
239 mmu_get_pte (ulong virt, ulong cr0, ulong cr3, ulong cr4, u64 efer,
240 bool write, bool user, bool exec, u64 entries[5],
241 int *plevels)
242 {
243 struct get_pte_data d;
244
245 d.pg = !!(cr0 & CR0_PG_BIT);
246 d.wp = !!(cr0 & CR0_WP_BIT);
247 d.pse = !!(cr4 & CR4_PSE_BIT);
248 d.pae = !!(cr4 & CR4_PAE_BIT);
249 d.lme = !!(efer & MSR_IA32_EFER_LME_BIT);
250 d.nxe = !!(efer & MSR_IA32_EFER_NXE_BIT);
251 d.write = write;
252 d.user = user;
253 d.exec = exec;
254 return get_pte_sub (virt, cr3, d, entries, plevels);
255 }
256
257 static vmmerr_t
258 get_pte (ulong virt, bool wr, bool us, bool ex, u64 *pte)
259 {
260 int levels;
261 vmmerr_t r;
262 u64 entries[5];
263 u64 efer;
264 ulong cr0, cr3, cr4;
265
266 current->vmctl.read_control_reg (CONTROL_REG_CR0, &cr0);
267 current->vmctl.read_control_reg (CONTROL_REG_CR3, &cr3);
268 current->vmctl.read_control_reg (CONTROL_REG_CR4, &cr4);
269 current->vmctl.read_msr (MSR_IA32_EFER, &efer);
270 r = mmu_get_pte (virt, cr0, cr3, cr4, efer, wr, us, ex, entries,
271 &levels);
272 if (r == VMMERR_SUCCESS)
273 *pte = entries[0];
274 return r;
275 }
276
277 vmmerr_t
278 write_linearaddr_b (ulong linear, u8 data)
279 {
280 u64 pte;
281 bool us;
282 vmmerr_t err;
283
284 us = USER_MODE();
285 err = get_pte(linear, true, us, false, &pte);
286 if (err) {
287 mmu_generate_pagefault(err, true, us, linear);
288 return err;
289 }
290 write_gphys_b((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
291 msr_pte_to_cache_flag(pte));
292 return VMMERR_SUCCESS;
293 }
294
295 vmmerr_t
296 write_linearaddr_w (ulong linear, u16 data)
297 {
298 u64 pte;
299 bool us;
300 vmmerr_t err;
301
302 if ((linear & 0xFFF) == 0xFFF) {
303 RIE (write_linearaddr_b (linear, data));
304 RIE (write_linearaddr_b (linear + 1, data >> 8));
305 return VMMERR_SUCCESS;
306 }
307
308 us = USER_MODE();
309 err = get_pte(linear, true, us, false, &pte);
310 if (err) {
311 mmu_generate_pagefault(err, true, us, linear);
312 return err;
313 }
314 write_gphys_w ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
315 msr_pte_to_cache_flag(pte));
316 return VMMERR_SUCCESS;
317 }
318
319 vmmerr_t
320 write_linearaddr_l (ulong linear, u32 data)
321 {
322 u64 pte;
323 bool us;
324 vmmerr_t err;
325
326 if ((linear & 0xFFF) >= 0xFFD) {
327 RIE (write_linearaddr_w (linear, data));
328 RIE (write_linearaddr_w (linear + 2, data >> 16));
329 return VMMERR_SUCCESS;
330 }
331 us = USER_MODE();
332 err = get_pte(linear, true, us, false, &pte);
333 if (err) {
334 mmu_generate_pagefault(err, true, us, linear);
335 return err;
336 }
337 write_gphys_l ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
338 msr_pte_to_cache_flag(pte));
339 return VMMERR_SUCCESS;
340 }
341
342 vmmerr_t
343 write_linearaddr_q (ulong linear, u64 data)
344 {
345 u64 pte;
346 bool us;
347 vmmerr_t err;
348
349 if ((linear & 0xFFF) >= 0xFF9) {
350 RIE (write_linearaddr_l (linear, data));
351 RIE (write_linearaddr_l (linear + 4, data >> 32));
352 return VMMERR_SUCCESS;
353 }
354 us = USER_MODE();
355 err = get_pte(linear, true, us, false, &pte);
356 if (err) {
357 mmu_generate_pagefault(err, true, us, linear);
358 return err;
359 }
360 write_gphys_q ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
361 msr_pte_to_cache_flag(pte));
362 return VMMERR_SUCCESS;
363 }
364
365 vmmerr_t
366 read_linearaddr_b (ulong linear, void *data)
367 {
368 u64 pte;
369 bool us;
370 vmmerr_t err;
371
372 us = USER_MODE();
373 err = get_pte(linear, false, us, false /* FIXME */, &pte);
374 if (err) {
375 mmu_generate_pagefault(err, false, us, linear);
376 return err;
377 }
378 read_gphys_b ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
379 msr_pte_to_cache_flag(pte));
380 return VMMERR_SUCCESS;
381 }
382
383 vmmerr_t
384 read_linearaddr_w (ulong linear, void *data)
385 {
386 u64 pte;
387 bool us;
388 vmmerr_t err;
389
390 if ((linear & 0xFFF) == 0xFFF) {
391 RIE (read_linearaddr_b (linear, ((u8 *)data)));
392 RIE (read_linearaddr_b (linear + 1, ((u8 *)data + 1)));
393 return VMMERR_SUCCESS;
394 }
395 us = USER_MODE();
396 err = get_pte(linear, false, us, false /* FIXME */, &pte);
397 if (err) {
398 mmu_generate_pagefault(err, false, us, linear);
399 return err;
400 }
401 read_gphys_w ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
402 msr_pte_to_cache_flag(pte));
403 return VMMERR_SUCCESS;
404 }
405
406 vmmerr_t
407 read_linearaddr_l (ulong linear, void *data)
408 {
409 u64 pte;
410 bool us;
411 vmmerr_t err;
412
413 if ((linear & 0xFFF) >= 0xFFD) {
414 RIE (read_linearaddr_w (linear, ((u8 *)data)));
415 RIE (read_linearaddr_w (linear + 2, ((u8 *)data + 2)));
416 return VMMERR_SUCCESS;
417 }
418 us = USER_MODE();
419 err = get_pte(linear, false, us, false /* FIXME */, &pte);
420 if (err) {
421 mmu_generate_pagefault(err, false, us, linear);
422 return err;
423 }
424 read_gphys_l ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
425 msr_pte_to_cache_flag(pte));
426 return VMMERR_SUCCESS;
427 }
428
429 vmmerr_t
430 read_linearaddr_q (ulong linear, void *data)
431 {
432 u64 pte;
433 bool us;
434 vmmerr_t err;
435
436 if ((linear & 0xFFF) >= 0xFF9) {
437 RIE (read_linearaddr_l (linear, ((u8 *)data)));
438 RIE (read_linearaddr_l (linear + 4, ((u8 *)data + 4)));
439 return VMMERR_SUCCESS;
440 }
441 us = USER_MODE();
442 err = get_pte(linear, false, us, false /* FIXME */, &pte);
443 if (err) {
444 mmu_generate_pagefault(err, false, us, linear);
445 return err;
446 }
447 read_gphys_q ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), data,
448 msr_pte_to_cache_flag(pte));
449 return VMMERR_SUCCESS;
450 }
451
452 /* access a TSS during a task switch */
453 /* According to the manual, a processor uses contiguous physical addresses */
454 /* to access a TSS during a task switch */
455 vmmerr_t
456 read_linearaddr_tss (ulong linear, void *tss, uint len)
457 {
458 u64 pte;
459 void *p;
460
461 RIE (get_pte (linear, false, false, false, &pte));
462 p = mapmem_gphys ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), len, 0);
463 if (!p)
464 return VMMERR_NOMEM;
465 memcpy (tss, p, len);
466 unmapmem (p, len);
467 return VMMERR_SUCCESS;
468 }
469
470 vmmerr_t
471 write_linearaddr_tss (ulong linear, void *tss, uint len)
472 {
473 u64 pte;
474 void *p;
475
476 RIE (get_pte (linear, true, false, false, &pte));
477 p = mapmem_gphys ((pte & PTE_ADDR_MASK64) | (linear & 0xFFF), len,
478 MAPMEM_WRITE);
479 if (!p)
480 return VMMERR_NOMEM;
481 memcpy (p, tss, len);
482 unmapmem (p, len);
483 return VMMERR_SUCCESS;
484 }
485
486 void
487 mmu_generate_pagefault(vmmerr_t vmmerr, bool wr, bool us, ulong cr2)
488 {
489 u32 err = 0;
490
491 switch (vmmerr) {
492 case VMMERR_PAGE_NOT_PRESENT:
493 break;
494 case VMMERR_PAGE_NOT_ACCESSIBLE:
495 err = PAGEFAULT_ERR_P_BIT;
496 break;
497 case VMMERR_PAGE_BAD_RESERVED_BIT:
498 err = PAGEFAULT_ERR_P_BIT | PAGEFAULT_ERR_RSVD_BIT;
499 break;
500 case VMMERR_PAGE_NOT_EXECUTABLE:
501 err = PAGEFAULT_ERR_P_BIT | PAGEFAULT_ERR_ID_BIT;
502 break;
503 default:
504 panic("mmu_generate_pagefault: Unknown vmmerr. 0x%x", vmmerr);
505 }
506 if (wr) {
507 err |= PAGEFAULT_ERR_WR_BIT;
508 }
509 if (us) {
510 err |= PAGEFAULT_ERR_US_BIT;
511 }
512 current->vmctl.generate_pagefault (err, cr2);
513 }

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