xen-vtx-unstable

view xen/include/asm-x86/shadow_64.h @ 6568:dd668f7527cb

merge?
author cl349@firebug.cl.cam.ac.uk
date Thu Sep 01 10:16:14 2005 +0000 (2005-09-01)
parents 38312fe7ec38 832cb25d1f55
children 8b87d43412bf 291e816acbf4
line source
1 /******************************************************************************
2 * include/asm-x86/shadow_64.h
3 *
4 * Copyright (c) 2005 Michael A Fetterman
5 * Based on an earlier implementation by Ian Pratt et al
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 /*
22 * Jun Nakajima <jun.nakajima@intel.com>
23 * Chengyuan Li <chengyuan.li@intel.com>
24 *
25 * Extended to support 64-bit guests.
26 */
27 #ifndef _XEN_SHADOW_64_H
28 #define _XEN_SHADOW_64_H
29 #include <asm/shadow.h>
31 #define READ_FAULT 0
32 #define WRITE_FAULT 1
34 #define ERROR_W 2
35 #define ERROR_U 4
36 #define X86_64_SHADOW_DEBUG 0
38 #if X86_64_SHADOW_DEBUG
39 #define ESH_LOG(_f, _a...) \
40 printk(_f, ##_a)
41 #else
42 #define ESH_LOG(_f, _a...) ((void)0)
43 #endif
45 #define L4 4UL
46 #define L3 3UL
47 #define L2 2UL
48 #define L1 1UL
49 #define L_MASK 0xff
51 #define ROOT_LEVEL_64 L4
52 #define ROOT_LEVEL_32 L2
54 #define SHADOW_ENTRY (2UL << 16)
55 #define GUEST_ENTRY (1UL << 16)
57 #define GET_ENTRY (2UL << 8)
58 #define SET_ENTRY (1UL << 8)
60 #define PAGETABLE_ENTRIES (1<<PAGETABLE_ORDER)
62 typedef struct { intpte_t lo; } pgentry_64_t;
63 #define shadow_level_to_type(l) (l << 29)
64 #define shadow_type_to_level(t) (t >> 29)
66 #define entry_get_value(_x) ((_x).lo)
67 #define entry_get_pfn(_x) \
68 (((_x).lo & (PADDR_MASK&PAGE_MASK)) >> PAGE_SHIFT)
69 #define entry_get_paddr(_x) (((_x).lo & (PADDR_MASK&PAGE_MASK)))
70 #define entry_get_flags(_x) (get_pte_flags((_x).lo))
72 #define entry_empty() ((pgentry_64_t) { 0 })
73 #define entry_from_pfn(pfn, flags) \
74 ((pgentry_64_t) { ((intpte_t)(pfn) << PAGE_SHIFT) | put_pte_flags(flags) })
75 #define entry_add_flags(x, flags) ((x).lo |= put_pte_flags(flags))
76 #define entry_remove_flags(x, flags) ((x).lo &= ~put_pte_flags(flags))
77 #define entry_has_changed(x,y,flags) \
78 ( !!(((x).lo ^ (y).lo) & ((PADDR_MASK&PAGE_MASK)|put_pte_flags(flags))) )
79 static inline int table_offset_64(unsigned long va, int level)
80 {
81 switch(level) {
82 case 1:
83 return (((va) >> L1_PAGETABLE_SHIFT) & (L1_PAGETABLE_ENTRIES - 1));
84 case 2:
85 return (((va) >> L2_PAGETABLE_SHIFT) & (L2_PAGETABLE_ENTRIES - 1));
86 case 3:
87 return (((va) >> L3_PAGETABLE_SHIFT) & (L3_PAGETABLE_ENTRIES - 1));
88 #if CONFIG_PAGING_LEVELS >= 4
89 case 4:
90 return (((va) >> L4_PAGETABLE_SHIFT) & (L4_PAGETABLE_ENTRIES - 1));
91 #endif
92 default:
93 //printk("<table_offset_64> level %d is too big\n", level);
94 return -1;
95 }
96 }
98 static inline void free_out_of_sync_state(struct domain *d)
99 {
100 struct out_of_sync_entry *entry;
102 // NB: Be careful not to call something that manipulates this list
103 // while walking it. Remove one item at a time, and always
104 // restart from start of list.
105 //
106 while ( (entry = d->arch.out_of_sync) )
107 {
108 d->arch.out_of_sync = entry->next;
109 release_out_of_sync_entry(d, entry);
111 entry->next = d->arch.out_of_sync_free;
112 d->arch.out_of_sync_free = entry;
113 }
114 }
116 static inline pgentry_64_t *__entry(
117 struct vcpu *v, u64 va, u32 flag)
118 {
119 int i;
120 pgentry_64_t *le_e;
121 pgentry_64_t *le_p;
122 unsigned long mfn;
123 int index;
124 u32 level = flag & L_MASK;
125 struct domain *d = v->domain;
127 index = table_offset_64(va, ROOT_LEVEL_64);
128 if (flag & SHADOW_ENTRY)
129 le_e = (pgentry_64_t *)&v->arch.shadow_vtable[index];
130 else
131 le_e = (pgentry_64_t *)&v->arch.guest_vtable[index];
133 /*
134 * If it's not external mode, then mfn should be machine physical.
135 */
136 for (i = ROOT_LEVEL_64 - level; i > 0; i--) {
137 if (unlikely(!(entry_get_flags(*le_e) & _PAGE_PRESENT)))
138 return NULL;
139 mfn = entry_get_value(*le_e) >> PAGE_SHIFT;
140 if ((flag & GUEST_ENTRY) && shadow_mode_translate(d))
141 mfn = get_mfn_from_pfn(mfn);
142 le_p = (pgentry_64_t *)phys_to_virt(mfn << PAGE_SHIFT);
143 index = table_offset_64(va, (level + i - 1));
144 le_e = &le_p[index];
146 }
147 return le_e;
149 }
151 static inline pgentry_64_t *__rw_entry(
152 struct vcpu *ed, u64 va, void *e_p, u32 flag)
153 {
154 pgentry_64_t *le_e = __entry(ed, va, flag);
155 pgentry_64_t *e = (pgentry_64_t *)e_p;
156 if (le_e == NULL)
157 return NULL;
159 if (e) {
160 if (flag & SET_ENTRY)
161 *le_e = *e;
162 else
163 *e = *le_e;
164 }
165 return le_e;
166 }
167 #define __shadow_set_l4e(v, va, value) \
168 __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | L4)
169 #define __shadow_get_l4e(v, va, sl4e) \
170 __rw_entry(v, va, sl4e, SHADOW_ENTRY | GET_ENTRY | L4)
171 #define __shadow_set_l3e(v, va, value) \
172 __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | L3)
173 #define __shadow_get_l3e(v, va, sl3e) \
174 __rw_entry(v, va, sl3e, SHADOW_ENTRY | GET_ENTRY | L3)
175 #define __shadow_set_l2e(v, va, value) \
176 __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | L2)
177 #define __shadow_get_l2e(v, va, sl2e) \
178 __rw_entry(v, va, sl2e, SHADOW_ENTRY | GET_ENTRY | L2)
179 #define __shadow_set_l1e(v, va, value) \
180 __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | L1)
181 #define __shadow_get_l1e(v, va, sl1e) \
182 __rw_entry(v, va, sl1e, SHADOW_ENTRY | GET_ENTRY | L1)
184 #define __guest_set_l4e(v, va, value) \
185 __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | L4)
186 #define __guest_get_l4e(v, va, gl4e) \
187 __rw_entry(v, va, gl4e, GUEST_ENTRY | GET_ENTRY | L4)
188 #define __guest_set_l3e(v, va, value) \
189 __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | L3)
190 #define __guest_get_l3e(v, va, sl3e) \
191 __rw_entry(v, va, gl3e, GUEST_ENTRY | GET_ENTRY | L3)
193 static inline void * __guest_set_l2e(
194 struct vcpu *v, u64 va, void *value, int size)
195 {
196 switch(size) {
197 case 4:
198 // 32-bit guest
199 {
200 l2_pgentry_32_t *l2va;
202 l2va = (l2_pgentry_32_t *)v->arch.guest_vtable;
203 if (value)
204 l2va[l2_table_offset_32(va)] = *(l2_pgentry_32_t *)value;
205 return &l2va[l2_table_offset_32(va)];
206 }
207 case 8:
208 return __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | L2);
209 default:
210 BUG();
211 return NULL;
212 }
213 return NULL;
214 }
216 #define __guest_set_l2e(v, va, value) \
217 ( __typeof__(value) )__guest_set_l2e(v, (u64)va, value, sizeof(*value))
219 static inline void * __guest_get_l2e(
220 struct vcpu *v, u64 va, void *gl2e, int size)
221 {
222 switch(size) {
223 case 4:
224 // 32-bit guest
225 {
226 l2_pgentry_32_t *l2va;
227 l2va = (l2_pgentry_32_t *)v->arch.guest_vtable;
228 if (gl2e)
229 *(l2_pgentry_32_t *)gl2e = l2va[l2_table_offset_32(va)];
230 return &l2va[l2_table_offset_32(va)];
231 }
232 case 8:
233 return __rw_entry(v, va, gl2e, GUEST_ENTRY | GET_ENTRY | L2);
234 default:
235 BUG();
236 return NULL;
237 }
238 return NULL;
239 }
241 #define __guest_get_l2e(v, va, gl2e) \
242 (__typeof__ (gl2e))__guest_get_l2e(v, (u64)va, gl2e, sizeof(*gl2e))
244 static inline void * __guest_set_l1e(
245 struct vcpu *v, u64 va, void *value, int size)
246 {
247 switch(size) {
248 case 4:
249 // 32-bit guest
250 {
251 l2_pgentry_32_t gl2e;
252 l1_pgentry_32_t *l1va;
253 unsigned long l1mfn;
255 if (!__guest_get_l2e(v, va, &gl2e))
256 return NULL;
257 if (unlikely(!(l2e_get_flags_32(gl2e) & _PAGE_PRESENT)))
258 return NULL;
260 l1mfn = get_mfn_from_pfn(
261 l2e_get_pfn(gl2e));
263 l1va = (l1_pgentry_32_t *)
264 phys_to_virt(l1mfn << L1_PAGETABLE_SHIFT);
265 if (value)
266 l1va[l1_table_offset_32(va)] = *(l1_pgentry_32_t *)value;
268 return &l1va[l1_table_offset_32(va)];
269 }
271 case 8:
272 return __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | L1);
273 default:
274 BUG();
275 return NULL;
276 }
277 return NULL;
278 }
280 #define __guest_set_l1e(v, va, value) \
281 ( __typeof__(value) )__guest_set_l1e(v, (u64)va, value, sizeof(*value))
283 static inline void * __guest_get_l1e(
284 struct vcpu *v, u64 va, void *gl1e, int size)
285 {
286 switch(size) {
287 case 4:
288 // 32-bit guest
289 {
290 l2_pgentry_32_t gl2e;
291 l1_pgentry_32_t *l1va;
292 unsigned long l1mfn;
294 if (!(__guest_get_l2e(v, va, &gl2e)))
295 return NULL;
298 if (unlikely(!(l2e_get_flags_32(gl2e) & _PAGE_PRESENT)))
299 return NULL;
302 l1mfn = get_mfn_from_pfn(
303 l2e_get_pfn(gl2e));
304 l1va = (l1_pgentry_32_t *) phys_to_virt(
305 l1mfn << L1_PAGETABLE_SHIFT);
306 if (gl1e)
307 *(l1_pgentry_32_t *)gl1e = l1va[l1_table_offset_32(va)];
309 return &l1va[l1_table_offset_32(va)];
310 }
311 case 8:
312 // 64-bit guest
313 return __rw_entry(v, va, gl1e, GUEST_ENTRY | GET_ENTRY | L1);
314 default:
315 BUG();
316 return NULL;
317 }
318 return NULL;
319 }
321 #define __guest_get_l1e(v, va, gl1e) \
322 ( __typeof__(gl1e) )__guest_get_l1e(v, (u64)va, gl1e, sizeof(*gl1e))
324 static inline void entry_general(
325 struct domain *d,
326 pgentry_64_t *gle_p,
327 pgentry_64_t *sle_p,
328 unsigned long smfn, u32 level)
330 {
331 pgentry_64_t gle = *gle_p;
332 pgentry_64_t sle;
334 sle = entry_empty();
335 if ( (entry_get_flags(gle) & _PAGE_PRESENT) && (smfn != 0) )
336 {
337 if ((entry_get_flags(gle) & _PAGE_PSE) && level == L2) {
338 sle = entry_from_pfn(smfn, entry_get_flags(gle));
339 entry_remove_flags(sle, _PAGE_PSE);
341 if ( shadow_mode_log_dirty(d) ||
342 !(entry_get_flags(gle) & _PAGE_DIRTY) )
343 {
344 pgentry_64_t *l1_p;
345 int i;
347 l1_p =(pgentry_64_t *)map_domain_page(smfn);
348 for (i = 0; i < L1_PAGETABLE_ENTRIES; i++)
349 entry_remove_flags(l1_p[i], _PAGE_RW);
351 unmap_domain_page(l1_p);
352 }
353 } else {
354 sle = entry_from_pfn(smfn,
355 (entry_get_flags(gle) | _PAGE_RW | _PAGE_ACCESSED) & ~_PAGE_AVAIL);
356 entry_add_flags(gle, _PAGE_ACCESSED);
357 }
358 // XXX mafetter: Hmm...
359 // Shouldn't the dirty log be checked/updated here?
360 // Actually, it needs to be done in this function's callers.
361 //
362 *gle_p = gle;
363 }
365 if ( entry_get_value(sle) || entry_get_value(gle) )
366 SH_VVLOG("%s: gpde=%lx, new spde=%lx", __func__,
367 entry_get_value(gle), entry_get_value(sle));
369 *sle_p = sle;
370 }
372 static inline void entry_propagate_from_guest(
373 struct domain *d, pgentry_64_t *gle_p, pgentry_64_t *sle_p, u32 level)
374 {
375 pgentry_64_t gle = *gle_p;
376 unsigned long smfn = 0;
378 if ( entry_get_flags(gle) & _PAGE_PRESENT ) {
379 if ((entry_get_flags(gle) & _PAGE_PSE) && level == L2) {
380 smfn = __shadow_status(d, entry_get_value(gle) >> PAGE_SHIFT, PGT_fl1_shadow);
381 } else {
382 smfn = __shadow_status(d, entry_get_pfn(gle),
383 shadow_level_to_type((level -1 )));
384 }
385 }
386 entry_general(d, gle_p, sle_p, smfn, level);
388 }
390 static int inline
391 validate_entry_change(
392 struct domain *d,
393 pgentry_64_t *new_gle_p,
394 pgentry_64_t *shadow_le_p,
395 u32 level)
396 {
397 pgentry_64_t old_sle, new_sle;
398 pgentry_64_t new_gle = *new_gle_p;
400 old_sle = *shadow_le_p;
401 entry_propagate_from_guest(d, &new_gle, &new_sle, level);
403 ESH_LOG("old_sle: %lx, new_gle: %lx, new_sle: %lx\n",
404 entry_get_value(old_sle), entry_get_value(new_gle),
405 entry_get_value(new_sle));
407 if ( ((entry_get_value(old_sle) | entry_get_value(new_sle)) & _PAGE_PRESENT) &&
408 entry_has_changed(old_sle, new_sle, _PAGE_PRESENT) )
409 {
410 perfc_incrc(validate_entry_changes);
412 if ( (entry_get_flags(new_sle) & _PAGE_PRESENT) &&
413 !get_shadow_ref(entry_get_pfn(new_sle)) )
414 BUG();
415 if ( entry_get_flags(old_sle) & _PAGE_PRESENT )
416 put_shadow_ref(entry_get_pfn(old_sle));
417 }
419 *shadow_le_p = new_sle;
421 return 1;
422 }
424 /*
425 * Check P, R/W, U/S bits in the guest page table.
426 * If the fault belongs to guest return 1,
427 * else return 0.
428 */
429 static inline int guest_page_fault(struct vcpu *v,
430 unsigned long va, unsigned int error_code, pgentry_64_t *gpl2e, pgentry_64_t *gpl1e)
431 {
432 struct domain *d = v->domain;
433 pgentry_64_t gle, *lva;
434 unsigned long mfn;
435 int i;
437 __rw_entry(v, va, &gle, GUEST_ENTRY | GET_ENTRY | L4);
438 if (unlikely(!(entry_get_flags(gle) & _PAGE_PRESENT)))
439 return 1;
441 if (error_code & ERROR_W) {
442 if (unlikely(!(entry_get_flags(gle) & _PAGE_RW)))
443 return 1;
444 }
445 if (error_code & ERROR_U) {
446 if (unlikely(!(entry_get_flags(gle) & _PAGE_USER)))
447 return 1;
448 }
449 for (i = L3; i >= L1; i--) {
450 /*
451 * If it's not external mode, then mfn should be machine physical.
452 */
453 mfn = __gpfn_to_mfn(d, (entry_get_paddr(gle) >> PAGE_SHIFT));
454 if (mfn == -1)
455 return 1;
457 lva = (pgentry_64_t *) phys_to_virt(
458 mfn << PAGE_SHIFT);
459 gle = lva[table_offset_64(va, i)];
461 if (unlikely(!(entry_get_flags(gle) & _PAGE_PRESENT)))
462 return 1;
464 if (error_code & ERROR_W) {
465 if (unlikely(!(entry_get_flags(gle) & _PAGE_RW)))
466 return 1;
467 }
468 if (error_code & ERROR_U) {
469 if (unlikely(!(entry_get_flags(gle) & _PAGE_USER)))
470 return 1;
471 }
473 if (i == L2) {
474 if (gpl2e)
475 *gpl2e = gle;
477 if (likely(entry_get_flags(gle) & _PAGE_PSE))
478 return 0;
480 }
482 if (i == L1)
483 if (gpl1e)
484 *gpl1e = gle;
485 }
486 return 0;
487 }
489 static inline unsigned long gva_to_gpa(unsigned long gva)
490 {
491 struct vcpu *v = current;
492 pgentry_64_t gl1e = {0};
493 pgentry_64_t gl2e = {0};
494 unsigned long gpa;
496 if (guest_page_fault(v, gva, 0, &gl2e, &gl1e))
497 return 0;
498 if (entry_get_flags(gl2e) & _PAGE_PSE)
499 gpa = entry_get_paddr(gl2e) + (gva & ((1 << L2_PAGETABLE_SHIFT) - 1));
500 else
501 gpa = entry_get_paddr(gl1e) + (gva & ~PAGE_MASK);
503 return gpa;
505 }
506 #endif