diff options
author | Avi Kivity <avi@qumranet.com> | 2007-12-09 09:15:46 -0500 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 10:53:20 -0500 |
commit | fe135d2ceb3d7dc08151b3cbad96565d02cc8676 (patch) | |
tree | 7dec07ec0a32a53f003551802cb73c4ce3373527 /drivers | |
parent | b3e4e63fd9ee8cd5d9047b89e0d463d5c48ee5b5 (diff) |
KVM: MMU: Simplify calculation of pte access
The nx bit is awkwardly placed in the 63rd bit position; furthermore it
has a reversed meaning compared to the other bits, which means we can't use
a bitwise and to calculate compounded access masks.
So, we simplify things by creating a new 3-bit exec/write/user access word,
and doing all calculations in that.
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/kvm/mmu.c | 14 | ||||
-rw-r--r-- | drivers/kvm/paging_tmpl.h | 58 |
2 files changed, 43 insertions, 29 deletions
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index 62a74151f847..f8a2137c64a2 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c | |||
@@ -85,7 +85,8 @@ static int dbg = 1; | |||
85 | #define PT_PAGE_SIZE_MASK (1ULL << 7) | 85 | #define PT_PAGE_SIZE_MASK (1ULL << 7) |
86 | #define PT_PAT_MASK (1ULL << 7) | 86 | #define PT_PAT_MASK (1ULL << 7) |
87 | #define PT_GLOBAL_MASK (1ULL << 8) | 87 | #define PT_GLOBAL_MASK (1ULL << 8) |
88 | #define PT64_NX_MASK (1ULL << 63) | 88 | #define PT64_NX_SHIFT 63 |
89 | #define PT64_NX_MASK (1ULL << PT64_NX_SHIFT) | ||
89 | 90 | ||
90 | #define PT_PAT_SHIFT 7 | 91 | #define PT_PAT_SHIFT 7 |
91 | #define PT_DIR_PAT_SHIFT 12 | 92 | #define PT_DIR_PAT_SHIFT 12 |
@@ -153,6 +154,11 @@ static int dbg = 1; | |||
153 | 154 | ||
154 | #define RMAP_EXT 4 | 155 | #define RMAP_EXT 4 |
155 | 156 | ||
157 | #define ACC_EXEC_MASK 1 | ||
158 | #define ACC_WRITE_MASK PT_WRITABLE_MASK | ||
159 | #define ACC_USER_MASK PT_USER_MASK | ||
160 | #define ACC_ALL (ACC_EXEC_MASK | ACC_WRITE_MASK | ACC_USER_MASK) | ||
161 | |||
156 | struct kvm_rmap_desc { | 162 | struct kvm_rmap_desc { |
157 | u64 *shadow_ptes[RMAP_EXT]; | 163 | u64 *shadow_ptes[RMAP_EXT]; |
158 | struct kvm_rmap_desc *more; | 164 | struct kvm_rmap_desc *more; |
@@ -921,7 +927,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, struct page *page) | |||
921 | >> PAGE_SHIFT; | 927 | >> PAGE_SHIFT; |
922 | new_table = kvm_mmu_get_page(vcpu, pseudo_gfn, | 928 | new_table = kvm_mmu_get_page(vcpu, pseudo_gfn, |
923 | v, level - 1, | 929 | v, level - 1, |
924 | 1, 3, &table[index]); | 930 | 1, ACC_ALL, &table[index]); |
925 | if (!new_table) { | 931 | if (!new_table) { |
926 | pgprintk("nonpaging_map: ENOMEM\n"); | 932 | pgprintk("nonpaging_map: ENOMEM\n"); |
927 | kvm_release_page_clean(page); | 933 | kvm_release_page_clean(page); |
@@ -988,7 +994,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) | |||
988 | 994 | ||
989 | ASSERT(!VALID_PAGE(root)); | 995 | ASSERT(!VALID_PAGE(root)); |
990 | sp = kvm_mmu_get_page(vcpu, root_gfn, 0, | 996 | sp = kvm_mmu_get_page(vcpu, root_gfn, 0, |
991 | PT64_ROOT_LEVEL, 0, 0, NULL); | 997 | PT64_ROOT_LEVEL, 0, ACC_ALL, NULL); |
992 | root = __pa(sp->spt); | 998 | root = __pa(sp->spt); |
993 | ++sp->root_count; | 999 | ++sp->root_count; |
994 | vcpu->mmu.root_hpa = root; | 1000 | vcpu->mmu.root_hpa = root; |
@@ -1009,7 +1015,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) | |||
1009 | root_gfn = 0; | 1015 | root_gfn = 0; |
1010 | sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, | 1016 | sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, |
1011 | PT32_ROOT_LEVEL, !is_paging(vcpu), | 1017 | PT32_ROOT_LEVEL, !is_paging(vcpu), |
1012 | 0, NULL); | 1018 | ACC_ALL, NULL); |
1013 | root = __pa(sp->spt); | 1019 | root = __pa(sp->spt); |
1014 | ++sp->root_count; | 1020 | ++sp->root_count; |
1015 | vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK; | 1021 | vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK; |
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h index 8086f827120f..7688cbf413c8 100644 --- a/drivers/kvm/paging_tmpl.h +++ b/drivers/kvm/paging_tmpl.h | |||
@@ -66,7 +66,8 @@ struct guest_walker { | |||
66 | int level; | 66 | int level; |
67 | gfn_t table_gfn[PT_MAX_FULL_LEVELS]; | 67 | gfn_t table_gfn[PT_MAX_FULL_LEVELS]; |
68 | pt_element_t pte; | 68 | pt_element_t pte; |
69 | pt_element_t inherited_ar; | 69 | unsigned pt_access; |
70 | unsigned pte_access; | ||
70 | gfn_t gfn; | 71 | gfn_t gfn; |
71 | u32 error_code; | 72 | u32 error_code; |
72 | }; | 73 | }; |
@@ -110,7 +111,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker, | |||
110 | { | 111 | { |
111 | pt_element_t pte; | 112 | pt_element_t pte; |
112 | gfn_t table_gfn; | 113 | gfn_t table_gfn; |
113 | unsigned index; | 114 | unsigned index, pt_access, pte_access; |
114 | gpa_t pte_gpa; | 115 | gpa_t pte_gpa; |
115 | 116 | ||
116 | pgprintk("%s: addr %lx\n", __FUNCTION__, addr); | 117 | pgprintk("%s: addr %lx\n", __FUNCTION__, addr); |
@@ -128,7 +129,7 @@ walk: | |||
128 | ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || | 129 | ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || |
129 | (vcpu->cr3 & CR3_NONPAE_RESERVED_BITS) == 0); | 130 | (vcpu->cr3 & CR3_NONPAE_RESERVED_BITS) == 0); |
130 | 131 | ||
131 | walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK; | 132 | pt_access = ACC_ALL; |
132 | 133 | ||
133 | for (;;) { | 134 | for (;;) { |
134 | index = PT_INDEX(addr, walker->level); | 135 | index = PT_INDEX(addr, walker->level); |
@@ -165,6 +166,14 @@ walk: | |||
165 | pte |= PT_ACCESSED_MASK; | 166 | pte |= PT_ACCESSED_MASK; |
166 | } | 167 | } |
167 | 168 | ||
169 | pte_access = pte & (PT_WRITABLE_MASK | PT_USER_MASK); | ||
170 | pte_access |= ACC_EXEC_MASK; | ||
171 | #if PTTYPE == 64 | ||
172 | if (is_nx(vcpu)) | ||
173 | pte_access &= ~(pte >> PT64_NX_SHIFT); | ||
174 | #endif | ||
175 | pte_access &= pt_access; | ||
176 | |||
168 | if (walker->level == PT_PAGE_TABLE_LEVEL) { | 177 | if (walker->level == PT_PAGE_TABLE_LEVEL) { |
169 | walker->gfn = gpte_to_gfn(pte); | 178 | walker->gfn = gpte_to_gfn(pte); |
170 | break; | 179 | break; |
@@ -180,7 +189,7 @@ walk: | |||
180 | break; | 189 | break; |
181 | } | 190 | } |
182 | 191 | ||
183 | walker->inherited_ar &= pte; | 192 | pt_access = pte_access; |
184 | --walker->level; | 193 | --walker->level; |
185 | } | 194 | } |
186 | 195 | ||
@@ -197,7 +206,10 @@ walk: | |||
197 | } | 206 | } |
198 | 207 | ||
199 | walker->pte = pte; | 208 | walker->pte = pte; |
200 | pgprintk("%s: pte %llx\n", __FUNCTION__, (u64)pte); | 209 | walker->pt_access = pt_access; |
210 | walker->pte_access = pte_access; | ||
211 | pgprintk("%s: pte %llx pte_access %x pt_access %x\n", | ||
212 | __FUNCTION__, (u64)pte, pt_access, pte_access); | ||
201 | return 1; | 213 | return 1; |
202 | 214 | ||
203 | not_present: | 215 | not_present: |
@@ -218,7 +230,8 @@ err: | |||
218 | } | 230 | } |
219 | 231 | ||
220 | static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, | 232 | static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, |
221 | u64 *shadow_pte, u64 access_bits, | 233 | u64 *shadow_pte, unsigned pt_access, |
234 | unsigned pte_access, | ||
222 | int user_fault, int write_fault, | 235 | int user_fault, int write_fault, |
223 | int *ptwrite, struct guest_walker *walker, | 236 | int *ptwrite, struct guest_walker *walker, |
224 | gfn_t gfn) | 237 | gfn_t gfn) |
@@ -228,12 +241,11 @@ static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, | |||
228 | int was_rmapped = is_rmap_pte(*shadow_pte); | 241 | int was_rmapped = is_rmap_pte(*shadow_pte); |
229 | struct page *page; | 242 | struct page *page; |
230 | 243 | ||
231 | pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d" | 244 | pgprintk("%s: spte %llx gpte %llx access %x write_fault %d" |
232 | " user_fault %d gfn %lx\n", | 245 | " user_fault %d gfn %lx\n", |
233 | __FUNCTION__, *shadow_pte, (u64)gpte, access_bits, | 246 | __FUNCTION__, *shadow_pte, (u64)gpte, pt_access, |
234 | write_fault, user_fault, gfn); | 247 | write_fault, user_fault, gfn); |
235 | 248 | ||
236 | access_bits &= gpte; | ||
237 | /* | 249 | /* |
238 | * We don't set the accessed bit, since we sometimes want to see | 250 | * We don't set the accessed bit, since we sometimes want to see |
239 | * whether the guest actually used the pte (in order to detect | 251 | * whether the guest actually used the pte (in order to detect |
@@ -242,12 +254,12 @@ static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, | |||
242 | spte = PT_PRESENT_MASK | PT_DIRTY_MASK; | 254 | spte = PT_PRESENT_MASK | PT_DIRTY_MASK; |
243 | spte |= gpte & PT64_NX_MASK; | 255 | spte |= gpte & PT64_NX_MASK; |
244 | if (!dirty) | 256 | if (!dirty) |
245 | access_bits &= ~PT_WRITABLE_MASK; | 257 | pte_access &= ~ACC_WRITE_MASK; |
246 | 258 | ||
247 | page = gfn_to_page(vcpu->kvm, gfn); | 259 | page = gfn_to_page(vcpu->kvm, gfn); |
248 | 260 | ||
249 | spte |= PT_PRESENT_MASK; | 261 | spte |= PT_PRESENT_MASK; |
250 | if (access_bits & PT_USER_MASK) | 262 | if (pte_access & ACC_USER_MASK) |
251 | spte |= PT_USER_MASK; | 263 | spte |= PT_USER_MASK; |
252 | 264 | ||
253 | if (is_error_page(page)) { | 265 | if (is_error_page(page)) { |
@@ -259,7 +271,7 @@ static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, | |||
259 | 271 | ||
260 | spte |= page_to_phys(page); | 272 | spte |= page_to_phys(page); |
261 | 273 | ||
262 | if ((access_bits & PT_WRITABLE_MASK) | 274 | if ((pte_access & ACC_WRITE_MASK) |
263 | || (write_fault && !is_write_protection(vcpu) && !user_fault)) { | 275 | || (write_fault && !is_write_protection(vcpu) && !user_fault)) { |
264 | struct kvm_mmu_page *shadow; | 276 | struct kvm_mmu_page *shadow; |
265 | 277 | ||
@@ -273,7 +285,7 @@ static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, | |||
273 | if (shadow) { | 285 | if (shadow) { |
274 | pgprintk("%s: found shadow page for %lx, marking ro\n", | 286 | pgprintk("%s: found shadow page for %lx, marking ro\n", |
275 | __FUNCTION__, gfn); | 287 | __FUNCTION__, gfn); |
276 | access_bits &= ~PT_WRITABLE_MASK; | 288 | pte_access &= ~ACC_WRITE_MASK; |
277 | if (is_writeble_pte(spte)) { | 289 | if (is_writeble_pte(spte)) { |
278 | spte &= ~PT_WRITABLE_MASK; | 290 | spte &= ~PT_WRITABLE_MASK; |
279 | kvm_x86_ops->tlb_flush(vcpu); | 291 | kvm_x86_ops->tlb_flush(vcpu); |
@@ -285,7 +297,7 @@ static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, | |||
285 | 297 | ||
286 | unshadowed: | 298 | unshadowed: |
287 | 299 | ||
288 | if (access_bits & PT_WRITABLE_MASK) | 300 | if (pte_access & ACC_WRITE_MASK) |
289 | mark_page_dirty(vcpu->kvm, gfn); | 301 | mark_page_dirty(vcpu->kvm, gfn); |
290 | 302 | ||
291 | pgprintk("%s: setting spte %llx\n", __FUNCTION__, spte); | 303 | pgprintk("%s: setting spte %llx\n", __FUNCTION__, spte); |
@@ -317,8 +329,8 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page, | |||
317 | if (bytes < sizeof(pt_element_t)) | 329 | if (bytes < sizeof(pt_element_t)) |
318 | return; | 330 | return; |
319 | pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte); | 331 | pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte); |
320 | FNAME(set_pte)(vcpu, gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0, | 332 | FNAME(set_pte)(vcpu, gpte, spte, ACC_ALL, ACC_ALL, |
321 | 0, NULL, NULL, gpte_to_gfn(gpte)); | 333 | 0, 0, NULL, NULL, gpte_to_gfn(gpte)); |
322 | } | 334 | } |
323 | 335 | ||
324 | /* | 336 | /* |
@@ -331,6 +343,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
331 | hpa_t shadow_addr; | 343 | hpa_t shadow_addr; |
332 | int level; | 344 | int level; |
333 | u64 *shadow_ent; | 345 | u64 *shadow_ent; |
346 | unsigned access = walker->pt_access; | ||
334 | 347 | ||
335 | if (!is_present_pte(walker->pte)) | 348 | if (!is_present_pte(walker->pte)) |
336 | return NULL; | 349 | return NULL; |
@@ -349,7 +362,6 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
349 | u64 shadow_pte; | 362 | u64 shadow_pte; |
350 | int metaphysical; | 363 | int metaphysical; |
351 | gfn_t table_gfn; | 364 | gfn_t table_gfn; |
352 | unsigned hugepage_access = 0; | ||
353 | 365 | ||
354 | shadow_ent = ((u64 *)__va(shadow_addr)) + index; | 366 | shadow_ent = ((u64 *)__va(shadow_addr)) + index; |
355 | if (is_shadow_present_pte(*shadow_ent)) { | 367 | if (is_shadow_present_pte(*shadow_ent)) { |
@@ -365,20 +377,15 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
365 | if (level - 1 == PT_PAGE_TABLE_LEVEL | 377 | if (level - 1 == PT_PAGE_TABLE_LEVEL |
366 | && walker->level == PT_DIRECTORY_LEVEL) { | 378 | && walker->level == PT_DIRECTORY_LEVEL) { |
367 | metaphysical = 1; | 379 | metaphysical = 1; |
368 | hugepage_access = walker->pte; | ||
369 | hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK; | ||
370 | if (!is_dirty_pte(walker->pte)) | 380 | if (!is_dirty_pte(walker->pte)) |
371 | hugepage_access &= ~PT_WRITABLE_MASK; | 381 | access &= ~ACC_WRITE_MASK; |
372 | hugepage_access >>= PT_WRITABLE_SHIFT; | ||
373 | if (walker->pte & PT64_NX_MASK) | ||
374 | hugepage_access |= (1 << 2); | ||
375 | table_gfn = gpte_to_gfn(walker->pte); | 382 | table_gfn = gpte_to_gfn(walker->pte); |
376 | } else { | 383 | } else { |
377 | metaphysical = 0; | 384 | metaphysical = 0; |
378 | table_gfn = walker->table_gfn[level - 2]; | 385 | table_gfn = walker->table_gfn[level - 2]; |
379 | } | 386 | } |
380 | shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1, | 387 | shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1, |
381 | metaphysical, hugepage_access, | 388 | metaphysical, access, |
382 | shadow_ent); | 389 | shadow_ent); |
383 | shadow_addr = __pa(shadow_page->spt); | 390 | shadow_addr = __pa(shadow_page->spt); |
384 | shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK | 391 | shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK |
@@ -387,7 +394,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
387 | } | 394 | } |
388 | 395 | ||
389 | FNAME(set_pte)(vcpu, walker->pte, shadow_ent, | 396 | FNAME(set_pte)(vcpu, walker->pte, shadow_ent, |
390 | walker->inherited_ar, user_fault, write_fault, | 397 | access, walker->pte_access & access, |
398 | user_fault, write_fault, | ||
391 | ptwrite, walker, walker->gfn); | 399 | ptwrite, walker, walker->gfn); |
392 | 400 | ||
393 | return shadow_ent; | 401 | return shadow_ent; |