diff options
author | Avi Kivity <avi@redhat.com> | 2010-07-13 07:27:07 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-08-01 23:40:43 -0400 |
commit | a357bd229cdaf37a41798d238ab50b34c71dd0d6 (patch) | |
tree | 0a2801b53c7df2c8494bc5c572574cb29ad4aeee /arch | |
parent | a3aa51cfaafe9179add88db20506ccb07e030b47 (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')
-rw-r--r-- | arch/x86/kvm/mmu.c | 23 | ||||
-rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 27 |
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 | ||
1503 | static 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 | |||
1503 | static void kvm_mmu_page_unlink_children(struct kvm *kvm, | 1526 | static 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; |