aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-12-09 09:15:46 -0500
committerAvi Kivity <avi@qumranet.com>2008-01-30 10:53:20 -0500
commitfe135d2ceb3d7dc08151b3cbad96565d02cc8676 (patch)
tree7dec07ec0a32a53f003551802cb73c4ce3373527 /drivers
parentb3e4e63fd9ee8cd5d9047b89e0d463d5c48ee5b5 (diff)
KVM: MMU: Simplify calculation of pte access
The nx bit is awkwardly placed in the 63rd bit position; furthermore it has a reversed meaning compared to the other bits, which means we can't use a bitwise and to calculate compounded access masks. So, we simplify things by creating a new 3-bit exec/write/user access word, and doing all calculations in that. Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/kvm/mmu.c14
-rw-r--r--drivers/kvm/paging_tmpl.h58
2 files changed, 43 insertions, 29 deletions
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 62a74151f847..f8a2137c64a2 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -85,7 +85,8 @@ static int dbg = 1;
85#define PT_PAGE_SIZE_MASK (1ULL << 7) 85#define PT_PAGE_SIZE_MASK (1ULL << 7)
86#define PT_PAT_MASK (1ULL << 7) 86#define PT_PAT_MASK (1ULL << 7)
87#define PT_GLOBAL_MASK (1ULL << 8) 87#define PT_GLOBAL_MASK (1ULL << 8)
88#define PT64_NX_MASK (1ULL << 63) 88#define PT64_NX_SHIFT 63
89#define PT64_NX_MASK (1ULL << PT64_NX_SHIFT)
89 90
90#define PT_PAT_SHIFT 7 91#define PT_PAT_SHIFT 7
91#define PT_DIR_PAT_SHIFT 12 92#define PT_DIR_PAT_SHIFT 12
@@ -153,6 +154,11 @@ static int dbg = 1;
153 154
154#define RMAP_EXT 4 155#define RMAP_EXT 4
155 156
157#define ACC_EXEC_MASK 1
158#define ACC_WRITE_MASK PT_WRITABLE_MASK
159#define ACC_USER_MASK PT_USER_MASK
160#define ACC_ALL (ACC_EXEC_MASK | ACC_WRITE_MASK | ACC_USER_MASK)
161
156struct kvm_rmap_desc { 162struct kvm_rmap_desc {
157 u64 *shadow_ptes[RMAP_EXT]; 163 u64 *shadow_ptes[RMAP_EXT];
158 struct kvm_rmap_desc *more; 164 struct kvm_rmap_desc *more;
@@ -921,7 +927,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, struct page *page)
921 >> PAGE_SHIFT; 927 >> PAGE_SHIFT;
922 new_table = kvm_mmu_get_page(vcpu, pseudo_gfn, 928 new_table = kvm_mmu_get_page(vcpu, pseudo_gfn,
923 v, level - 1, 929 v, level - 1,
924 1, 3, &table[index]); 930 1, ACC_ALL, &table[index]);
925 if (!new_table) { 931 if (!new_table) {
926 pgprintk("nonpaging_map: ENOMEM\n"); 932 pgprintk("nonpaging_map: ENOMEM\n");
927 kvm_release_page_clean(page); 933 kvm_release_page_clean(page);
@@ -988,7 +994,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
988 994
989 ASSERT(!VALID_PAGE(root)); 995 ASSERT(!VALID_PAGE(root));
990 sp = kvm_mmu_get_page(vcpu, root_gfn, 0, 996 sp = kvm_mmu_get_page(vcpu, root_gfn, 0,
991 PT64_ROOT_LEVEL, 0, 0, NULL); 997 PT64_ROOT_LEVEL, 0, ACC_ALL, NULL);
992 root = __pa(sp->spt); 998 root = __pa(sp->spt);
993 ++sp->root_count; 999 ++sp->root_count;
994 vcpu->mmu.root_hpa = root; 1000 vcpu->mmu.root_hpa = root;
@@ -1009,7 +1015,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
1009 root_gfn = 0; 1015 root_gfn = 0;
1010 sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, 1016 sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
1011 PT32_ROOT_LEVEL, !is_paging(vcpu), 1017 PT32_ROOT_LEVEL, !is_paging(vcpu),
1012 0, NULL); 1018 ACC_ALL, NULL);
1013 root = __pa(sp->spt); 1019 root = __pa(sp->spt);
1014 ++sp->root_count; 1020 ++sp->root_count;
1015 vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK; 1021 vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK;
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index 8086f827120f..7688cbf413c8 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -66,7 +66,8 @@ struct guest_walker {
66 int level; 66 int level;
67 gfn_t table_gfn[PT_MAX_FULL_LEVELS]; 67 gfn_t table_gfn[PT_MAX_FULL_LEVELS];
68 pt_element_t pte; 68 pt_element_t pte;
69 pt_element_t inherited_ar; 69 unsigned pt_access;
70 unsigned pte_access;
70 gfn_t gfn; 71 gfn_t gfn;
71 u32 error_code; 72 u32 error_code;
72}; 73};
@@ -110,7 +111,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
110{ 111{
111 pt_element_t pte; 112 pt_element_t pte;
112 gfn_t table_gfn; 113 gfn_t table_gfn;
113 unsigned index; 114 unsigned index, pt_access, pte_access;
114 gpa_t pte_gpa; 115 gpa_t pte_gpa;
115 116
116 pgprintk("%s: addr %lx\n", __FUNCTION__, addr); 117 pgprintk("%s: addr %lx\n", __FUNCTION__, addr);
@@ -128,7 +129,7 @@ walk:
128 ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || 129 ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) ||
129 (vcpu->cr3 & CR3_NONPAE_RESERVED_BITS) == 0); 130 (vcpu->cr3 & CR3_NONPAE_RESERVED_BITS) == 0);
130 131
131 walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK; 132 pt_access = ACC_ALL;
132 133
133 for (;;) { 134 for (;;) {
134 index = PT_INDEX(addr, walker->level); 135 index = PT_INDEX(addr, walker->level);
@@ -165,6 +166,14 @@ walk:
165 pte |= PT_ACCESSED_MASK; 166 pte |= PT_ACCESSED_MASK;
166 } 167 }
167 168
169 pte_access = pte & (PT_WRITABLE_MASK | PT_USER_MASK);
170 pte_access |= ACC_EXEC_MASK;
171#if PTTYPE == 64
172 if (is_nx(vcpu))
173 pte_access &= ~(pte >> PT64_NX_SHIFT);
174#endif
175 pte_access &= pt_access;
176
168 if (walker->level == PT_PAGE_TABLE_LEVEL) { 177 if (walker->level == PT_PAGE_TABLE_LEVEL) {
169 walker->gfn = gpte_to_gfn(pte); 178 walker->gfn = gpte_to_gfn(pte);
170 break; 179 break;
@@ -180,7 +189,7 @@ walk:
180 break; 189 break;
181 } 190 }
182 191
183 walker->inherited_ar &= pte; 192 pt_access = pte_access;
184 --walker->level; 193 --walker->level;
185 } 194 }
186 195
@@ -197,7 +206,10 @@ walk:
197 } 206 }
198 207
199 walker->pte = pte; 208 walker->pte = pte;
200 pgprintk("%s: pte %llx\n", __FUNCTION__, (u64)pte); 209 walker->pt_access = pt_access;
210 walker->pte_access = pte_access;
211 pgprintk("%s: pte %llx pte_access %x pt_access %x\n",
212 __FUNCTION__, (u64)pte, pt_access, pte_access);
201 return 1; 213 return 1;
202 214
203not_present: 215not_present:
@@ -218,7 +230,8 @@ err:
218} 230}
219 231
220static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, 232static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte,
221 u64 *shadow_pte, u64 access_bits, 233 u64 *shadow_pte, unsigned pt_access,
234 unsigned pte_access,
222 int user_fault, int write_fault, 235 int user_fault, int write_fault,
223 int *ptwrite, struct guest_walker *walker, 236 int *ptwrite, struct guest_walker *walker,
224 gfn_t gfn) 237 gfn_t gfn)
@@ -228,12 +241,11 @@ static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte,
228 int was_rmapped = is_rmap_pte(*shadow_pte); 241 int was_rmapped = is_rmap_pte(*shadow_pte);
229 struct page *page; 242 struct page *page;
230 243
231 pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d" 244 pgprintk("%s: spte %llx gpte %llx access %x write_fault %d"
232 " user_fault %d gfn %lx\n", 245 " user_fault %d gfn %lx\n",
233 __FUNCTION__, *shadow_pte, (u64)gpte, access_bits, 246 __FUNCTION__, *shadow_pte, (u64)gpte, pt_access,
234 write_fault, user_fault, gfn); 247 write_fault, user_fault, gfn);
235 248
236 access_bits &= gpte;
237 /* 249 /*
238 * We don't set the accessed bit, since we sometimes want to see 250 * We don't set the accessed bit, since we sometimes want to see
239 * whether the guest actually used the pte (in order to detect 251 * whether the guest actually used the pte (in order to detect
@@ -242,12 +254,12 @@ static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte,
242 spte = PT_PRESENT_MASK | PT_DIRTY_MASK; 254 spte = PT_PRESENT_MASK | PT_DIRTY_MASK;
243 spte |= gpte & PT64_NX_MASK; 255 spte |= gpte & PT64_NX_MASK;
244 if (!dirty) 256 if (!dirty)
245 access_bits &= ~PT_WRITABLE_MASK; 257 pte_access &= ~ACC_WRITE_MASK;
246 258
247 page = gfn_to_page(vcpu->kvm, gfn); 259 page = gfn_to_page(vcpu->kvm, gfn);
248 260
249 spte |= PT_PRESENT_MASK; 261 spte |= PT_PRESENT_MASK;
250 if (access_bits & PT_USER_MASK) 262 if (pte_access & ACC_USER_MASK)
251 spte |= PT_USER_MASK; 263 spte |= PT_USER_MASK;
252 264