Skip to content

Commit 105485a

Browse files
author
Marc Zyngier
committed
KVM: arm64: Fix handling of FEAT_GTG for unimplemented granule sizes
Booting an EL2 guest on a system only supporting a subset of the possible page sizes leads to interesting situations. For example, on a system that only supports 4kB and 64kB, and is booted with a 4kB kernel, we end-up advertising 16kB support at stage-2, which is pretty weird. That's because we consider that any S2 bigger than our base granule is fair game, irrespective of what the HW actually supports. While this is not impossible to support (KVM would happily handle it), it is likely to be confusing for the guest. Add new checks that will verify that this granule size is actually supported before publishing it to the guest. Fixes: e7ef6ed ("KVM: arm64: Enforce NV limits on a per-idregs basis") Reviewed-by: Oliver Upton <[email protected]> Signed-off-by: Marc Zyngier <[email protected]>
1 parent 0e02219 commit 105485a

File tree

1 file changed

+23
-3
lines changed

1 file changed

+23
-3
lines changed

arch/arm64/kvm/nested.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,21 @@ static void kvm_map_l1_vncr(struct kvm_vcpu *vcpu)
14021402
}
14031403
}
14041404

1405+
#define has_tgran_2(__r, __sz) \
1406+
({ \
1407+
u64 _s1, _s2, _mmfr0 = __r; \
1408+
\
1409+
_s2 = SYS_FIELD_GET(ID_AA64MMFR0_EL1, \
1410+
TGRAN##__sz##_2, _mmfr0); \
1411+
\
1412+
_s1 = SYS_FIELD_GET(ID_AA64MMFR0_EL1, \
1413+
TGRAN##__sz, _mmfr0); \
1414+
\
1415+
((_s2 != ID_AA64MMFR0_EL1_TGRAN##__sz##_2_NI && \
1416+
_s2 != ID_AA64MMFR0_EL1_TGRAN##__sz##_2_TGRAN##__sz) || \
1417+
(_s2 == ID_AA64MMFR0_EL1_TGRAN##__sz##_2_TGRAN##__sz && \
1418+
_s1 != ID_AA64MMFR0_EL1_TGRAN##__sz##_NI)); \
1419+
})
14051420
/*
14061421
* Our emulated CPU doesn't support all the possible features. For the
14071422
* sake of simplicity (and probably mental sanity), wipe out a number
@@ -1411,6 +1426,8 @@ static void kvm_map_l1_vncr(struct kvm_vcpu *vcpu)
14111426
*/
14121427
u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val)
14131428
{
1429+
u64 orig_val = val;
1430+
14141431
switch (reg) {
14151432
case SYS_ID_AA64ISAR0_EL1:
14161433
/* Support everything but TME */
@@ -1480,13 +1497,16 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val)
14801497
*/
14811498
switch (PAGE_SIZE) {
14821499
case SZ_4K:
1483-
val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR0_EL1, TGRAN4_2, IMP);
1500+
if (has_tgran_2(orig_val, 4))
1501+
val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR0_EL1, TGRAN4_2, IMP);
14841502
fallthrough;
14851503
case SZ_16K:
1486-
val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR0_EL1, TGRAN16_2, IMP);
1504+
if (has_tgran_2(orig_val, 16))
1505+
val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR0_EL1, TGRAN16_2, IMP);
14871506
fallthrough;
14881507
case SZ_64K:
1489-
val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR0_EL1, TGRAN64_2, IMP);
1508+
if (has_tgran_2(orig_val, 64))
1509+
val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR0_EL1, TGRAN64_2, IMP);
14901510
break;
14911511
}
14921512

0 commit comments

Comments
 (0)