Skip to content

Commit 6141570

Browse files
Marc Zyngierchazy
authored andcommitted
arm64: KVM: Warn when PARange is less than 40 bits
We always thought that 40bits of PA range would be the minimum people would actually build. Anything less is terrifyingly small. Turns out that we were both right and wrong. Nobody has ever built such a system, but the ARM Foundation Model has a PARange set to 36bits. Just because we can. Oh well. Now, the KVM API explicitely says that we offer a 40bit PA space to the VM, so we shouldn't run KVM on the Foundation Model at all. That being said, this patch offers a less agressive alternative, and loudly warns about the configuration being unsupported. You'll still be able to run VMs (at your own risks, though). This is just a workaround until we have a proper userspace API where we report the PARange to userspace. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
1 parent 1c5631c commit 6141570

File tree

4 files changed

+44
-10
lines changed

4 files changed

+44
-10
lines changed

arch/arm64/include/asm/kvm_arm.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,7 @@
151151
*/
152152
#define VTCR_EL2_FLAGS (VTCR_EL2_TG0_64K | VTCR_EL2_SH0_INNER | \
153153
VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \
154-
VTCR_EL2_SL0_LVL1 | VTCR_EL2_T0SZ_40B | \
155-
VTCR_EL2_RES1)
154+
VTCR_EL2_SL0_LVL1 | VTCR_EL2_RES1)
156155
#define VTTBR_X (38 - VTCR_EL2_T0SZ_40B)
157156
#else
158157
/*
@@ -163,8 +162,7 @@
163162
*/
164163
#define VTCR_EL2_FLAGS (VTCR_EL2_TG0_4K | VTCR_EL2_SH0_INNER | \
165164
VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \
166-
VTCR_EL2_SL0_LVL1 | VTCR_EL2_T0SZ_40B | \
167-
VTCR_EL2_RES1)
165+
VTCR_EL2_SL0_LVL1 | VTCR_EL2_RES1)
168166
#define VTTBR_X (37 - VTCR_EL2_T0SZ_40B)
169167
#endif
170168

arch/arm64/include/asm/kvm_asm.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ extern void __vgic_v3_init_lrs(void);
5454

5555
extern u32 __kvm_get_mdcr_el2(void);
5656

57-
extern void __init_stage2_translation(void);
57+
extern u32 __init_stage2_translation(void);
5858

5959
#endif
6060

arch/arm64/include/asm/kvm_host.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,11 +370,12 @@ int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,
370370
int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu,
371371
struct kvm_device_attr *attr);
372372

373-
/* #define kvm_call_hyp(f, ...) __kvm_call_hyp(kvm_ksym_ref(f), ##__VA_ARGS__) */
374-
375373
static inline void __cpu_init_stage2(void)
376374
{
377-
kvm_call_hyp(__init_stage2_translation);
375+
u32 parange = kvm_call_hyp(__init_stage2_translation);
376+
377+
WARN_ONCE(parange < 40,
378+
"PARange is %d bits, unsupported configuration!", parange);
378379
}
379380

380381
#endif /* __ARM64_KVM_HOST_H__ */

arch/arm64/kvm/hyp/s2-setup.c

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,50 @@
2020
#include <asm/kvm_asm.h>
2121
#include <asm/kvm_hyp.h>
2222

23-
void __hyp_text __init_stage2_translation(void)
23+
u32 __hyp_text __init_stage2_translation(void)
2424
{
2525
u64 val = VTCR_EL2_FLAGS;
26+
u64 parange;
2627
u64 tmp;
2728

2829
/*
2930
* Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS
3031
* bits in VTCR_EL2. Amusingly, the PARange is 4 bits, while
3132
* PS is only 3. Fortunately, bit 19 is RES0 in VTCR_EL2...
3233
*/
33-
val |= (read_sysreg(id_aa64mmfr0_el1) & 7) << 16;
34+
parange = read_sysreg(id_aa64mmfr0_el1) & 7;
35+
val |= parange << 16;
36+
37+
/* Compute the actual PARange... */
38+
switch (parange) {
39+
case 0:
40+
parange = 32;
41+
break;
42+
case 1:
43+
parange = 36;
44+
break;
45+
case 2:
46+
parange = 40;
47+
break;
48+
case 3:
49+
parange = 42;
50+
break;
51+
case 4:
52+
parange = 44;
53+
break;
54+
case 5:
55+
default:
56+
parange = 48;
57+
break;
58+
}
59+
60+
/*
61+
* ... and clamp it to 40 bits, unless we have some braindead
62+
* HW that implements less than that. In all cases, we'll
63+
* return that value for the rest of the kernel to decide what
64+
* to do.
65+
*/
66+
val |= 64 - (parange > 40 ? 40 : parange);
3467

3568
/*
3669
* Read the VMIDBits bits from ID_AA64MMFR1_EL1 and set the VS
@@ -42,4 +75,6 @@ void __hyp_text __init_stage2_translation(void)
4275
VTCR_EL2_VS_8BIT;
4376

4477
write_sysreg(val, vtcr_el2);
78+
79+
return parange;
4580
}

0 commit comments

Comments
 (0)