KVM: MMU: Fix inherited permissions for emulated guest pte updates
authorAvi Kivity <avi@qumranet.com>
Sun, 9 Dec 2007 15:00:02 +0000 (17:00 +0200)
committerAvi Kivity <avi@qumranet.com>
Wed, 30 Jan 2008 15:53:20 +0000 (17:53 +0200)
When we emulate a guest pte write, we fail to apply the correct inherited
permissions from the parent ptes.  Now that we store inherited permissions
in the shadow page, we can use that to update the pte permissions correctly.

Signed-off-by: Avi Kivity <avi@qumranet.com>
drivers/kvm/kvm.h
drivers/kvm/mmu.c
drivers/kvm/paging_tmpl.h

index 0d3555bf533360f0711d491b4f13aff9c0db7138..ceefb4427dbd6eb9f88349693982e176146da927 100644 (file)
@@ -55,7 +55,7 @@ struct kvm_pte_chain {
  *   bits 4:7 - page table level for this shadow (1-4)
  *   bits 8:9 - page table quadrant for 2-level guests
  *   bit   16 - "metaphysical" - gfn is not a real page (huge page/real mode)
- *   bits 17:19 - "access" - the user, writable, and nx bits of a huge page pde
+ *   bits 17:19 - common access permissions for all ptes in this shadow page
  */
 union kvm_mmu_page_role {
        unsigned word;
@@ -65,7 +65,7 @@ union kvm_mmu_page_role {
                unsigned quadrant : 2;
                unsigned pad_for_nice_hex_output : 6;
                unsigned metaphysical : 1;
-               unsigned hugepage_access : 3;
+               unsigned access : 3;
        };
 };
 
index f8a2137c64a218d02a92f43dcbdc44690bbcaf43..cace1e41b683dfcb515aff991cc9c0590a91ddfb 100644 (file)
@@ -680,7 +680,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
                                             gva_t gaddr,
                                             unsigned level,
                                             int metaphysical,
-                                            unsigned hugepage_access,
+                                            unsigned access,
                                             u64 *parent_pte)
 {
        union kvm_mmu_page_role role;
@@ -694,7 +694,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
        role.glevels = vcpu->mmu.root_level;
        role.level = level;
        role.metaphysical = metaphysical;
-       role.hugepage_access = hugepage_access;
+       role.access = access;
        if (vcpu->mmu.root_level <= PT32_ROOT_LEVEL) {
                quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level));
                quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
index 1fc4f9b321eebd7c70b2b613ea933be7f1d64f4d..211fef83be5da898432d312c73ff34eff887ce0c 100644 (file)
@@ -327,6 +327,7 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
                              int offset_in_pte)
 {
        pt_element_t gpte;
+       unsigned pte_access;
 
        gpte = *(const pt_element_t *)pte;
        if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) {
@@ -337,7 +338,8 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
        if (bytes < sizeof(pt_element_t))
                return;
        pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte);
-       FNAME(set_pte)(vcpu, gpte, spte, ACC_ALL, ACC_ALL,
+       pte_access = page->role.access & FNAME(gpte_access)(vcpu, gpte);
+       FNAME(set_pte)(vcpu, gpte, spte, page->role.access, pte_access,
                       0, 0, NULL, NULL, gpte_to_gfn(gpte));
 }