aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2010-07-13 07:27:07 -0400
committerAvi Kivity <avi@redhat.com>2010-08-01 23:40:43 -0400
commita357bd229cdaf37a41798d238ab50b34c71dd0d6 (patch)
tree0a2801b53c7df2c8494bc5c572574cb29ad4aeee /arch/x86/kvm
parenta3aa51cfaafe9179add88db20506ccb07e030b47 (diff)
KVM: MMU: Add validate_direct_spte() helper
Add a helper to verify that a direct shadow page is valid wrt the required access permissions; drop the page if it is not valid. Reviewed-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> Signed-off-by: Avi Kivity <avi@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/mmu.c23
-rw-r--r--arch/x86/kvm/paging_tmpl.h27
2 files changed, 29 insertions, 21 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index b75d6cb44ab6..36c62f33513f 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -1500,6 +1500,29 @@ static void drop_large_spte(struct kvm_vcpu *vcpu, u64 *sptep)
1500 } 1500 }
1501} 1501}
1502 1502
1503static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep,
1504 unsigned direct_access)
1505{
1506 if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep)) {
1507 struct kvm_mmu_page *child;
1508
1509 /*
1510 * For the direct sp, if the guest pte's dirty bit
1511 * changed form clean to dirty, it will corrupt the
1512 * sp's access: allow writable in the read-only sp,
1513 * so we should update the spte at this point to get
1514 * a new sp with the correct access.
1515 */
1516 child = page_header(*sptep & PT64_BASE_ADDR_MASK);
1517 if (child->role.access == direct_access)
1518 return;
1519
1520 mmu_page_remove_parent_pte(child, sptep);
1521 __set_spte(sptep, shadow_trap_nonpresent_pte);
1522 kvm_flush_remote_tlbs(vcpu->kvm);
1523 }
1524}
1525
1503static void kvm_mmu_page_unlink_children(struct kvm *kvm, 1526static void kvm_mmu_page_unlink_children(struct kvm *kvm,
1504 struct kvm_mmu_page *sp) 1527 struct kvm_mmu_page *sp)
1505{ 1528{
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 0fb7068d64c7..0c7461d3a5be 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -338,30 +338,15 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
338 break; 338 break;
339 } 339 }
340 340
341 if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep)) { 341 if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep)
342 struct kvm_mmu_page *child; 342 && level == gw->level)
343 343 validate_direct_spte(vcpu, sptep, direct_access);
344 if (level != gw->level)
345 continue;
346
347 /*
348 * For the direct sp, if the guest pte's dirty bit
349 * changed form clean to dirty, it will corrupt the
350 * sp's access: allow writable in the read-only sp,
351 * so we should update the spte at this point to get
352 * a new sp with the correct access.
353 */
354 child = page_header(*sptep & PT64_BASE_ADDR_MASK);
355 if (child->role.access == direct_access)
356 continue;
357
358 mmu_page_remove_parent_pte(child, sptep);
359 __set_spte(sptep, shadow_trap_nonpresent_pte);
360 kvm_flush_remote_tlbs(vcpu->kvm);
361 }
362 344
363 drop_large_spte(vcpu, sptep); 345 drop_large_spte(vcpu, sptep);
364 346
347 if (is_shadow_present_pte(*sptep))
348 continue;
349
365 if (level <= gw->level) { 350 if (level <= gw->level) {
366 direct = 1; 351 direct = 1;
367 access = direct_access; 352 access = direct_access;