Skip to content

Commit 13d22b6

Browse files
committed
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 <[email protected]> Signed-off-by: Avi Kivity <[email protected]>
1 parent 97d64b7 commit 13d22b6

File tree

1 file changed

+25
-35
lines changed

1 file changed

+25
-35
lines changed

arch/x86/kvm/paging_tmpl.h

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,15 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
171171
gfn_t table_gfn;
172172
unsigned index, pt_access, pte_access;
173173
gpa_t pte_gpa;
174-
bool eperm, last_gpte;
174+
bool eperm;
175175
int offset;
176176
const int write_fault = access & PFERR_WRITE_MASK;
177177
const int user_fault = access & PFERR_USER_MASK;
178178
const int fetch_fault = access & PFERR_FETCH_MASK;
179179
u16 errcode = 0;
180+
gpa_t real_gpa;
181+
gfn_t gfn;
182+
u32 ac;
180183

181184
trace_kvm_mmu_pagetable_walk(addr, access);
182185
retry_walk:
@@ -197,12 +200,16 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
197200
ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) ||
198201
(mmu->get_cr3(vcpu) & CR3_NONPAE_RESERVED_BITS) == 0);
199202

200-
pt_access = ACC_ALL;
203+
pt_access = pte_access = ACC_ALL;
204+
++walker->level;
201205

202-
for (;;) {
206+
do {
203207
gfn_t real_gfn;
204208
unsigned long host_addr;
205209

210+
pt_access &= pte_access;
211+
--walker->level;
212+
206213
index = PT_INDEX(addr, walker->level);
207214

208215
table_gfn = gpte_to_gfn(pte);
@@ -239,46 +246,29 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
239246

240247
pte_access = pt_access & gpte_access(vcpu, pte);
241248

242-
last_gpte = FNAME(is_last_gpte)(walker, vcpu, mmu, pte);
243-
244249
walker->ptes[walker->level - 1] = pte;
245-
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-
}
250+
} while (!FNAME(is_last_gpte)(walker, vcpu, mmu, pte));
275251

276252
eperm |= permission_fault(mmu, pte_access, access);
277253
if (unlikely(eperm)) {
278254
errcode |= PFERR_PRESENT_MASK;
279255
goto error;
280256
}
281257

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+
282272
if (!write_fault)
283273
protect_clean_gpte(&pte_access, pte);
284274

0 commit comments

Comments
 (0)