Skip to content

Commit dabf9f7

Browse files
author
Marc Zyngier
committed
KVM: arm64: Report faults from S1 walk setup at the expected start level
Translation faults from TTBR must be reported on the start level, and not level-0. Enforcing this requires moving quite a lot of code around so that the start level can be computed early enough that it is usable. Reviewed-by: Oliver Upton <[email protected]> Signed-off-by: Marc Zyngier <[email protected]>
1 parent 5da3a3b commit dabf9f7

File tree

1 file changed

+54
-49
lines changed

1 file changed

+54
-49
lines changed

arch/arm64/kvm/at.c

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,6 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
154154

155155
va55 = va & BIT(55);
156156

157-
if (wi->regime == TR_EL2 && va55)
158-
goto addrsz;
159-
160157
wi->s2 = wi->regime == TR_EL10 && (hcr & (HCR_VM | HCR_DC));
161158

162159
switch (wi->regime) {
@@ -179,6 +176,46 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
179176
BUG();
180177
}
181178

179+
/* Someone was silly enough to encode TG0/TG1 differently */
180+
if (va55 && wi->regime != TR_EL2) {
181+
wi->txsz = FIELD_GET(TCR_T1SZ_MASK, tcr);
182+
tg = FIELD_GET(TCR_TG1_MASK, tcr);
183+
184+
switch (tg << TCR_TG1_SHIFT) {
185+
case TCR_TG1_4K:
186+
wi->pgshift = 12; break;
187+
case TCR_TG1_16K:
188+
wi->pgshift = 14; break;
189+
case TCR_TG1_64K:
190+
default: /* IMPDEF: treat any other value as 64k */
191+
wi->pgshift = 16; break;
192+
}
193+
} else {
194+
wi->txsz = FIELD_GET(TCR_T0SZ_MASK, tcr);
195+
tg = FIELD_GET(TCR_TG0_MASK, tcr);
196+
197+
switch (tg << TCR_TG0_SHIFT) {
198+
case TCR_TG0_4K:
199+
wi->pgshift = 12; break;
200+
case TCR_TG0_16K:
201+
wi->pgshift = 14; break;
202+
case TCR_TG0_64K:
203+
default: /* IMPDEF: treat any other value as 64k */
204+
wi->pgshift = 16; break;
205+
}
206+
}
207+
208+
wi->pa52bit = has_52bit_pa(vcpu, wi, tcr);
209+
210+
ia_bits = get_ia_size(wi);
211+
212+
/* AArch64.S1StartLevel() */
213+
stride = wi->pgshift - 3;
214+
wi->sl = 3 - (((ia_bits - 1) - wi->pgshift) / stride);
215+
216+
if (wi->regime == TR_EL2 && va55)
217+
goto addrsz;
218+
182219
tbi = (wi->regime == TR_EL2 ?
183220
FIELD_GET(TCR_EL2_TBI, tcr) :
184221
(va55 ?
@@ -248,46 +285,15 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
248285
/* R_BVXDG */
249286
wi->hpd |= (wi->poe || wi->e0poe);
250287

251-
/* Someone was silly enough to encode TG0/TG1 differently */
252-
if (va55) {
253-
wi->txsz = FIELD_GET(TCR_T1SZ_MASK, tcr);
254-
tg = FIELD_GET(TCR_TG1_MASK, tcr);
255-
256-
switch (tg << TCR_TG1_SHIFT) {
257-
case TCR_TG1_4K:
258-
wi->pgshift = 12; break;
259-
case TCR_TG1_16K:
260-
wi->pgshift = 14; break;
261-
case TCR_TG1_64K:
262-
default: /* IMPDEF: treat any other value as 64k */
263-
wi->pgshift = 16; break;
264-
}
265-
} else {
266-
wi->txsz = FIELD_GET(TCR_T0SZ_MASK, tcr);
267-
tg = FIELD_GET(TCR_TG0_MASK, tcr);
268-
269-
switch (tg << TCR_TG0_SHIFT) {
270-
case TCR_TG0_4K:
271-
wi->pgshift = 12; break;
272-
case TCR_TG0_16K:
273-
wi->pgshift = 14; break;
274-
case TCR_TG0_64K:
275-
default: /* IMPDEF: treat any other value as 64k */
276-
wi->pgshift = 16; break;
277-
}
278-
}
279-
280288
/* R_PLCGL, R_YXNYW */
281289
if (!kvm_has_feat_enum(vcpu->kvm, ID_AA64MMFR2_EL1, ST, 48_47)) {
282290
if (wi->txsz > 39)
283-
goto transfault_l0;
291+
goto transfault;
284292
} else {
285293
if (wi->txsz > 48 || (BIT(wi->pgshift) == SZ_64K && wi->txsz > 47))
286-
goto transfault_l0;
294+
goto transfault;
287295
}
288296

289-
wi->pa52bit = has_52bit_pa(vcpu, wi, tcr);
290-
291297
/* R_GTJBY, R_SXWGM */
292298
switch (BIT(wi->pgshift)) {
293299
case SZ_4K:
@@ -300,28 +306,22 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
300306
}
301307

302308
if ((lva && wi->txsz < 12) || (!lva && wi->txsz < 16))
303-
goto transfault_l0;
304-
305-
ia_bits = get_ia_size(wi);
309+
goto transfault;
306310

307311
/* R_YYVYV, I_THCZK */
308312
if ((!va55 && va > GENMASK(ia_bits - 1, 0)) ||
309313
(va55 && va < GENMASK(63, ia_bits)))
310-
goto transfault_l0;
314+
goto transfault;
311315

312316
/* I_ZFSYQ */
313317
if (wi->regime != TR_EL2 &&
314318
(tcr & (va55 ? TCR_EPD1_MASK : TCR_EPD0_MASK)))
315-
goto transfault_l0;
319+
goto transfault;
316320

317321
/* R_BNDVG and following statements */
318322
if (kvm_has_feat(vcpu->kvm, ID_AA64MMFR2_EL1, E0PD, IMP) &&
319323
wi->as_el0 && (tcr & (va55 ? TCR_E0PD1 : TCR_E0PD0)))
320-
goto transfault_l0;
321-
322-
/* AArch64.S1StartLevel() */
323-
stride = wi->pgshift - 3;
324-
wi->sl = 3 - (((ia_bits - 1) - wi->pgshift) / stride);
324+
goto transfault;
325325

326326
ps = (wi->regime == TR_EL2 ?
327327
FIELD_GET(TCR_EL2_PS_MASK, tcr) : FIELD_GET(TCR_IPS_MASK, tcr));
@@ -351,12 +351,17 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
351351

352352
return 0;
353353

354-
addrsz: /* Address Size Fault level 0 */
354+
addrsz:
355+
/*
356+
* Address Size Fault level 0 to indicate it comes from TTBR.
357+
* yes, this is an oddity.
358+
*/
355359
fail_s1_walk(wr, ESR_ELx_FSC_ADDRSZ_L(0), false);
356360
return -EFAULT;
357361

358-
transfault_l0: /* Translation Fault level 0 */
359-
fail_s1_walk(wr, ESR_ELx_FSC_FAULT_L(0), false);
362+
transfault:
363+
/* Translation Fault on start level */
364+
fail_s1_walk(wr, ESR_ELx_FSC_FAULT_L(wi->sl), false);
360365
return -EFAULT;
361366
}
362367

0 commit comments

Comments
 (0)