aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-12-09 10:00:02 -0500
committerAvi Kivity <avi@qumranet.com>2008-01-30 10:53:20 -0500
commit41074d07c78b086b18fc2af590caef05dbcca568 (patch)
tree1e07a3d17d718d61bbb45e427c7e7980f2b7ad2e
parentbedbe4ee86195dcd899577828714cc1413beb571 (diff)
KVM: MMU: Fix inherited permissions for emulated guest pte updates
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>
-rw-r--r--drivers/kvm/kvm.h4
-rw-r--r--drivers/kvm/mmu.c4
-rw-r--r--drivers/kvm/paging_tmpl.h4
3 files changed, 7 insertions, 5 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 0d3555bf5333..ceefb4427dbd 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -55,7 +55,7 @@ struct kvm_pte_chain {
55 * bits 4:7 - page table level for this shadow (1-4) 55 * bits 4:7 - page table level for this shadow (1-4)
56 * bits 8:9 - page table quadrant for 2-level guests 56 * bits 8:9 - page table quadrant for 2-level guests
57 * bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode) 57 * bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode)
58 * bits 17:19 - "access" - the user, writable, and nx bits of a huge page pde 58 * bits 17:19 - common access permissions for all ptes in this shadow page
59 */ 59 */
60union kvm_mmu_page_role { 60union kvm_mmu_page_role {
61 unsigned word; 61 unsigned word;
@@ -65,7 +65,7 @@ union kvm_mmu_page_role {
65 unsigned quadrant : 2; 65 unsigned quadrant : 2;
66 unsigned pad_for_nice_hex_output : 6; 66 unsigned pad_for_nice_hex_output : 6;
67 unsigned metaphysical : 1; 67 unsigned metaphysical : 1;
68 unsigned hugepage_access : 3; 68 unsigned access : 3;
69 }; 69 };
70}; 70};
71 71
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index f8a2137c64a2..cace1e41b683 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -680,7 +680,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
680 gva_t gaddr, 680 gva_t gaddr,
681 unsigned level, 681 unsigned level,
682 int metaphysical, 682 int metaphysical,
683 unsigned hugepage_access, 683 unsigned access,
684 u64 *parent_pte) 684 u64 *parent_pte)
685{ 685{
686 union kvm_mmu_page_role role; 686 union kvm_mmu_page_role role;
@@ -694,7 +694,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
694 role.glevels = vcpu->mmu.root_level; 694 role.glevels = vcpu->mmu.root_level;
695 role.level = level; 695 role.level = level;
696 role.metaphysical = metaphysical; 696 role.metaphysical = metaphysical;
697 role.hugepage_access = hugepage_access; 697 role.access = access;
698 if (vcpu->mmu.root_level <= PT32_ROOT_LEVEL) { 698 if (vcpu->mmu.root_level <= PT32_ROOT_LEVEL) {
699 quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level)); 699 quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level));
700 quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; 700 quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index 1fc4f9b321ee..211fef83be5d 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -327,6 +327,7 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
327 int offset_in_pte) 327 int offset_in_pte)
328{ 328{
329 pt_element_t gpte; 329 pt_element_t gpte;
330 unsigned pte_access;
330 331
331 gpte = *(const pt_element_t *)pte; 332 gpte = *(const pt_element_t *)pte;
332 if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) { 333 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,
337 if (bytes < sizeof(pt_element_t)) 338 if (bytes < sizeof(pt_element_t))
338 return; 339 return;
339 pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte); 340 pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte);
340 FNAME(set_pte)(vcpu, gpte, spte, ACC_ALL, ACC_ALL, 341 pte_access = page->role.access & FNAME(gpte_access)(vcpu, gpte);
342 FNAME(set_pte)(vcpu, gpte, spte, page->role.access, pte_access,
341 0, 0, NULL, NULL, gpte_to_gfn(gpte)); 343 0, 0, NULL, NULL, gpte_to_gfn(gpte));
342} 344}
343 345