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 | |
| 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>
| -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 | ||
