Skip to content

Commit 2292552

Browse files
Marc Zyngierchristofferdall-arm
authored andcommitted
arm64: KVM: Don't generate UNDEF when LORegion feature is present
We currently hide the LORegion feature, and generate an UNDEF if the guest dares using the corresponding registers. This is a bit extreme, as ARMv8.1 guarantees the feature to be present. The guest should check the feature register before doing anything, but we could also give the guest some slack (read "allow the guest to be a bit stupid"). So instead of unconditionnaly deliver an exception, let's only do it when the host doesn't support LORegion at all (or when the feature has been sanitized out), and treat the registers as RAZ/WI otherwise (with the exception of LORID_EL1 being RO). Fixes: cc33c4e ("arm64/kvm: Prohibit guest LOR accesses") Suggested-by: Richard Henderson <richard.henderson@linaro.org> Acked-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
1 parent e08d8d2 commit 2292552

File tree

1 file changed

+27
-15
lines changed

1 file changed

+27
-15
lines changed

arch/arm64/kvm/sys_regs.c

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -314,12 +314,29 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu,
314314
return read_zero(vcpu, p);
315315
}
316316

317-
static bool trap_undef(struct kvm_vcpu *vcpu,
318-
struct sys_reg_params *p,
319-
const struct sys_reg_desc *r)
317+
/*
318+
* ARMv8.1 mandates at least a trivial LORegion implementation, where all the
319+
* RW registers are RES0 (which we can implement as RAZ/WI). On an ARMv8.0
320+
* system, these registers should UNDEF. LORID_EL1 being a RO register, we
321+
* treat it separately.
322+
*/
323+
static bool trap_loregion(struct kvm_vcpu *vcpu,
324+
struct sys_reg_params *p,
325+
const struct sys_reg_desc *r)
320326
{
321-
kvm_inject_undefined(vcpu);
322-
return false;
327+
u64 val = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
328+
u32 sr = sys_reg((u32)r->Op0, (u32)r->Op1,
329+
(u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
330+
331+
if (!(val & (0xfUL << ID_AA64MMFR1_LOR_SHIFT))) {
332+
kvm_inject_undefined(vcpu);
333+
return false;
334+
}
335+
336+
if (p->is_write && sr == SYS_LORID_EL1)
337+
return write_to_read_only(vcpu, p, r);
338+
339+
return trap_raz_wi(vcpu, p, r);
323340
}
324341

325342
static bool trap_oslsr_el1(struct kvm_vcpu *vcpu,
@@ -1048,11 +1065,6 @@ static u64 read_id_reg(struct sys_reg_desc const *r, bool raz)
10481065
if (val & ptrauth_mask)
10491066
kvm_debug("ptrauth unsupported for guests, suppressing\n");
10501067
val &= ~ptrauth_mask;
1051-
} else if (id == SYS_ID_AA64MMFR1_EL1) {
1052-
if (val & (0xfUL << ID_AA64MMFR1_LOR_SHIFT))
1053-
kvm_debug("LORegions unsupported for guests, suppressing\n");
1054-
1055-
val &= ~(0xfUL << ID_AA64MMFR1_LOR_SHIFT);
10561068
}
10571069

10581070
return val;
@@ -1338,11 +1350,11 @@ static const struct sys_reg_desc sys_reg_descs[] = {
13381350
{ SYS_DESC(SYS_MAIR_EL1), access_vm_reg, reset_unknown, MAIR_EL1 },
13391351
{ SYS_DESC(SYS_AMAIR_EL1), access_vm_reg, reset_amair_el1, AMAIR_EL1 },
13401352

1341-
{ SYS_DESC(SYS_LORSA_EL1), trap_undef },
1342-
{ SYS_DESC(SYS_LOREA_EL1), trap_undef },
1343-
{ SYS_DESC(SYS_LORN_EL1), trap_undef },
1344-
{ SYS_DESC(SYS_LORC_EL1), trap_undef },
1345-
{ SYS_DESC(SYS_LORID_EL1), trap_undef },
1353+
{ SYS_DESC(SYS_LORSA_EL1), trap_loregion },
1354+
{ SYS_DESC(SYS_LOREA_EL1), trap_loregion },
1355+
{ SYS_DESC(SYS_LORN_EL1), trap_loregion },
1356+
{ SYS_DESC(SYS_LORC_EL1), trap_loregion },
1357+
{ SYS_DESC(SYS_LORID_EL1), trap_loregion },
13461358

13471359
{ SYS_DESC(SYS_VBAR_EL1), NULL, reset_val, VBAR_EL1, 0 },
13481360
{ SYS_DESC(SYS_DISR_EL1), NULL, reset_val, DISR_EL1, 0 },

0 commit comments

Comments
 (0)