diff options
Diffstat (limited to 'drivers/kvm')
-rw-r--r-- | drivers/kvm/kvm.h | 2 | ||||
-rw-r--r-- | drivers/kvm/mmu.c | 8 | ||||
-rw-r--r-- | drivers/kvm/paging_tmpl.h | 7 |
3 files changed, 13 insertions, 4 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index 7361c45d70c..f5e343cb06b 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h | |||
@@ -109,6 +109,7 @@ struct kvm_pte_chain { | |||
109 | * bits 4:7 - page table level for this shadow (1-4) | 109 | * bits 4:7 - page table level for this shadow (1-4) |
110 | * bits 8:9 - page table quadrant for 2-level guests | 110 | * bits 8:9 - page table quadrant for 2-level guests |
111 | * bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode) | 111 | * bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode) |
112 | * bits 17:18 - "access" - the user and writable bits of a huge page pde | ||
112 | */ | 113 | */ |
113 | union kvm_mmu_page_role { | 114 | union kvm_mmu_page_role { |
114 | unsigned word; | 115 | unsigned word; |
@@ -118,6 +119,7 @@ union kvm_mmu_page_role { | |||
118 | unsigned quadrant : 2; | 119 | unsigned quadrant : 2; |
119 | unsigned pad_for_nice_hex_output : 6; | 120 | unsigned pad_for_nice_hex_output : 6; |
120 | unsigned metaphysical : 1; | 121 | unsigned metaphysical : 1; |
122 | unsigned hugepage_access : 2; | ||
121 | }; | 123 | }; |
122 | }; | 124 | }; |
123 | 125 | ||
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index 2930d7cc7c0..c738fb1cea3 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c | |||
@@ -568,6 +568,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, | |||
568 | gva_t gaddr, | 568 | gva_t gaddr, |
569 | unsigned level, | 569 | unsigned level, |
570 | int metaphysical, | 570 | int metaphysical, |
571 | unsigned hugepage_access, | ||
571 | u64 *parent_pte) | 572 | u64 *parent_pte) |
572 | { | 573 | { |
573 | union kvm_mmu_page_role role; | 574 | union kvm_mmu_page_role role; |
@@ -581,6 +582,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, | |||
581 | role.glevels = vcpu->mmu.root_level; | 582 | role.glevels = vcpu->mmu.root_level; |
582 | role.level = level; | 583 | role.level = level; |
583 | role.metaphysical = metaphysical; | 584 | role.metaphysical = metaphysical; |
585 | role.hugepage_access = hugepage_access; | ||
584 | if (vcpu->mmu.root_level <= PT32_ROOT_LEVEL) { | 586 | if (vcpu->mmu.root_level <= PT32_ROOT_LEVEL) { |
585 | quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level)); | 587 | quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level)); |
586 | quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; | 588 | quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; |
@@ -780,7 +782,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, hpa_t p) | |||
780 | >> PAGE_SHIFT; | 782 | >> PAGE_SHIFT; |
781 | new_table = kvm_mmu_get_page(vcpu, pseudo_gfn, | 783 | new_table = kvm_mmu_get_page(vcpu, pseudo_gfn, |
782 | v, level - 1, | 784 | v, level - 1, |
783 | 1, &table[index]); | 785 | 1, 0, &table[index]); |
784 | if (!new_table) { | 786 | if (!new_table) { |
785 | pgprintk("nonpaging_map: ENOMEM\n"); | 787 | pgprintk("nonpaging_map: ENOMEM\n"); |
786 | return -ENOMEM; | 788 | return -ENOMEM; |
@@ -835,7 +837,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) | |||
835 | 837 | ||
836 | ASSERT(!VALID_PAGE(root)); | 838 | ASSERT(!VALID_PAGE(root)); |
837 | page = kvm_mmu_get_page(vcpu, root_gfn, 0, | 839 | page = kvm_mmu_get_page(vcpu, root_gfn, 0, |
838 | PT64_ROOT_LEVEL, 0, NULL); | 840 | PT64_ROOT_LEVEL, 0, 0, NULL); |
839 | root = page->page_hpa; | 841 | root = page->page_hpa; |
840 | ++page->root_count; | 842 | ++page->root_count; |
841 | vcpu->mmu.root_hpa = root; | 843 | vcpu->mmu.root_hpa = root; |
@@ -852,7 +854,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) | |||
852 | root_gfn = 0; | 854 | root_gfn = 0; |
853 | page = kvm_mmu_get_page(vcpu, root_gfn, i << 30, | 855 | page = kvm_mmu_get_page(vcpu, root_gfn, i << 30, |
854 | PT32_ROOT_LEVEL, !is_paging(vcpu), | 856 | PT32_ROOT_LEVEL, !is_paging(vcpu), |
855 | NULL); | 857 | 0, NULL); |
856 | root = page->page_hpa; | 858 | root = page->page_hpa; |
857 | ++page->root_count; | 859 | ++page->root_count; |
858 | vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK; | 860 | vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK; |
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h index 17bd4400c92..b94010dad80 100644 --- a/drivers/kvm/paging_tmpl.h +++ b/drivers/kvm/paging_tmpl.h | |||
@@ -247,6 +247,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
247 | u64 shadow_pte; | 247 | u64 shadow_pte; |
248 | int metaphysical; | 248 | int metaphysical; |
249 | gfn_t table_gfn; | 249 | gfn_t table_gfn; |
250 | unsigned hugepage_access = 0; | ||
250 | 251 | ||
251 | if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) { | 252 | if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) { |
252 | if (level == PT_PAGE_TABLE_LEVEL) | 253 | if (level == PT_PAGE_TABLE_LEVEL) |
@@ -276,6 +277,9 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
276 | if (level - 1 == PT_PAGE_TABLE_LEVEL | 277 | if (level - 1 == PT_PAGE_TABLE_LEVEL |
277 | && walker->level == PT_DIRECTORY_LEVEL) { | 278 | && walker->level == PT_DIRECTORY_LEVEL) { |
278 | metaphysical = 1; | 279 | metaphysical = 1; |
280 | hugepage_access = *guest_ent; | ||
281 | hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK; | ||
282 | hugepage_access >>= PT_WRITABLE_SHIFT; | ||
279 | table_gfn = (*guest_ent & PT_BASE_ADDR_MASK) | 283 | table_gfn = (*guest_ent & PT_BASE_ADDR_MASK) |
280 | >> PAGE_SHIFT; | 284 | >> PAGE_SHIFT; |
281 | } else { | 285 | } else { |
@@ -283,7 +287,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
283 | table_gfn = walker->table_gfn[level - 2]; | 287 | table_gfn = walker->table_gfn[level - 2]; |
284 | } | 288 | } |
285 | shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1, | 289 | shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1, |
286 | metaphysical, shadow_ent); | 290 | metaphysical, hugepage_access, |
291 | shadow_ent); | ||
287 | shadow_addr = shadow_page->page_hpa; | 292 | shadow_addr = shadow_page->page_hpa; |
288 | shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK | 293 | shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK |
289 | | PT_WRITABLE_MASK | PT_USER_MASK; | 294 | | PT_WRITABLE_MASK | PT_USER_MASK; |