aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2012-09-12 08:12:09 -0400
committerAvi Kivity <avi@redhat.com>2012-09-20 06:00:08 -0400
commit13d22b6aebb000aeaf137862c6c0e0c4d138d798 (patch)
treee643caac077496bdaaeaf7c12101b43f62b34393 /arch
parent97d64b788114be1c4dc4bfe7a8ba2bf9643fe6af (diff)
KVM: MMU: Simplify walk_addr_generic() loop
The page table walk is coded as an infinite loop, with a special case on the last pte. Code it as an ordinary loop with a termination condition on the last pte (large page or walk length exhausted), and put the last pte handling code after the loop where it belongs. Reviewed-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kvm/paging_tmpl.h60
1 files changed, 25 insertions, 35 deletions
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 8f6c59fadbbe..1b4c14d235a0 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -171,12 +171,15 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
171 gfn_t table_gfn; 171 gfn_t table_gfn;
172 unsigned index, pt_access, pte_access; 172 unsigned index, pt_access, pte_access;
173 gpa_t pte_gpa; 173 gpa_t pte_gpa;
174 bool eperm, last_gpte; 174 bool eperm;
175 int offset; 175 int offset;
176 const int write_fault = access & PFERR_WRITE_MASK; 176 const int write_fault = access & PFERR_WRITE_MASK;
177 const int user_fault = access & PFERR_USER_MASK; 177 const int user_fault = access & PFERR_USER_MASK;
178 const int fetch_fault = access & PFERR_FETCH_MASK; 178 const int fetch_fault = access & PFERR_FETCH_MASK;
179 u16 errcode = 0; 179 u16 errcode = 0;
180 gpa_t real_gpa;
181 gfn_t gfn;
182 u32 ac;
180 183
181 trace_kvm_mmu_pagetable_walk(addr, access); 184 trace_kvm_mmu_pagetable_walk(addr, access);
182retry_walk: 185retry_walk:
@@ -197,12 +200,16 @@ retry_walk:
197 ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || 200 ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) ||
198 (mmu->get_cr3(vcpu) & CR3_NONPAE_RESERVED_BITS) == 0); 201 (mmu->get_cr3(vcpu) & CR3_NONPAE_RESERVED_BITS) == 0);
199 202
200 pt_access = ACC_ALL; 203 pt_access = pte_access = ACC_ALL;
204 ++walker->level;
201 205
202 for (;;) { 206 do {
203 gfn_t real_gfn; 207 gfn_t real_gfn;
204 unsigned long host_addr; 208 unsigned long host_addr;
205 209
210 pt_access &= pte_access;
211 --walker->level;
212
206 index = PT_INDEX(addr, walker->level); 213 index = PT_INDEX(addr, walker->level);
207 214
208 table_gfn = gpte_to_gfn(pte); 215 table_gfn = gpte_to_gfn(pte);
@@ -239,39 +246,8 @@ retry_walk:
239 246
240 pte_access = pt_access & gpte_access(vcpu, pte); 247 pte_access = pt_access & gpte_access(vcpu, pte);
241 248
242 last_gpte = FNAME(is_last_gpte)(walker, vcpu, mmu, pte);
243
244 walker->ptes[walker->level - 1] = pte; 249 walker->ptes[walker->level - 1] = pte;
245 250 } while (!FNAME(is_last_gpte)(walker, vcpu, mmu, pte));
246 if (last_gpte) {
247 int lvl = walker->level;
248 gpa_t real_gpa;
249 gfn_t gfn;
250 u32 ac;
251
252 gfn = gpte_to_gfn_lvl(pte, lvl);
253 gfn += (addr & PT_LVL_OFFSET_MASK(lvl)) >> PAGE_SHIFT;
254
255 if (PTTYPE == 32 &&
256 walker->level == PT_DIRECTORY_LEVEL &&
257 is_cpuid_PSE36())
258 gfn += pse36_gfn_delta(pte);
259
260 ac = write_fault | fetch_fault | user_fault;
261
262 real_gpa = mmu->translate_gpa(vcpu, gfn_to_gpa(gfn),
263 ac);
264 if (real_gpa == UNMAPPED_GVA)
265 return 0;
266
267 walker->gfn = real_gpa >> PAGE_SHIFT;
268
269 break;
270 }
271
272 pt_access &= pte_access;
273 --walker->level;
274 }
275 251
276 eperm |= permission_fault(mmu, pte_access, access); 252 eperm |= permission_fault(mmu, pte_access, access);
277 if (unlikely(eperm)) { 253 if (unlikely(eperm)) {
@@ -279,6 +255,20 @@ retry_walk:
279 goto error; 255 goto error;
280 } 256 }
281 257
258 gfn = gpte_to_gfn_lvl(pte, walker->level);
259 gfn += (addr & PT_LVL_OFFSET_MASK(walker->level)) >> PAGE_SHIFT;
260
261 if (PTTYPE == 32 && walker->level == PT_DIRECTORY_LEVEL && is_cpuid_PSE36())
262 gfn += pse36_gfn_delta(pte);
263
264 ac = write_fault | fetch_fault | user_fault;
265
266 real_gpa = mmu->translate_gpa(vcpu, gfn_to_gpa(gfn), ac);
267 if (real_gpa == UNMAPPED_GVA)
268 return 0;
269
270 walker->gfn = real_gpa >> PAGE_SHIFT;
271
282 if (!write_fault) 272 if (!write_fault)
283 protect_clean_gpte(&pte_access, pte); 273 protect_clean_gpte(&pte_access, pte);
284 274