diff options
author | Avi Kivity <avi@redhat.com> | 2012-09-12 08:12:09 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2012-09-20 06:00:08 -0400 |
commit | 13d22b6aebb000aeaf137862c6c0e0c4d138d798 (patch) | |
tree | e643caac077496bdaaeaf7c12101b43f62b34393 /arch | |
parent | 97d64b788114be1c4dc4bfe7a8ba2bf9643fe6af (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.h | 60 |
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); |
182 | retry_walk: | 185 | retry_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 | ||