Skip to content

Commit a9bc4a1

Browse files
committed
KVM: arm64: Reject attempts to set invalid debug arch version
The debug architecture is mandatory in ARMv8, so KVM should not allow userspace to configure a vCPU with less than that. Of course, this isn't handled elegantly by the generic ID register plumbing, as the respective ID register fields have a nonzero starting value. Add an explicit check for debug versions less than v8 of the architecture. Reviewed-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent 5a23e5c commit a9bc4a1

File tree

1 file changed

+29
-3
lines changed

1 file changed

+29
-3
lines changed

arch/arm64/kvm/sys_regs.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,8 +1216,14 @@ static s64 kvm_arm64_ftr_safe_value(u32 id, const struct arm64_ftr_bits *ftrp,
12161216
/* Some features have different safe value type in KVM than host features */
12171217
switch (id) {
12181218
case SYS_ID_AA64DFR0_EL1:
1219-
if (kvm_ftr.shift == ID_AA64DFR0_EL1_PMUVer_SHIFT)
1219+
switch (kvm_ftr.shift) {
1220+
case ID_AA64DFR0_EL1_PMUVer_SHIFT:
12201221
kvm_ftr.type = FTR_LOWER_SAFE;
1222+
break;
1223+
case ID_AA64DFR0_EL1_DebugVer_SHIFT:
1224+
kvm_ftr.type = FTR_LOWER_SAFE;
1225+
break;
1226+
}
12211227
break;
12221228
case SYS_ID_DFR0_EL1:
12231229
if (kvm_ftr.shift == ID_DFR0_EL1_PerfMon_SHIFT)
@@ -1476,14 +1482,22 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
14761482
return val;
14771483
}
14781484

1485+
#define ID_REG_LIMIT_FIELD_ENUM(val, reg, field, limit) \
1486+
({ \
1487+
u64 __f_val = FIELD_GET(reg##_##field##_MASK, val); \
1488+
(val) &= ~reg##_##field##_MASK; \
1489+
(val) |= FIELD_PREP(reg##_##field##_MASK, \
1490+
min(__f_val, (u64)reg##_##field##_##limit)); \
1491+
(val); \
1492+
})
1493+
14791494
static u64 read_sanitised_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
14801495
const struct sys_reg_desc *rd)
14811496
{
14821497
u64 val = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1);
14831498

14841499
/* Limit debug to ARMv8.0 */
1485-
val &= ~ID_AA64DFR0_EL1_DebugVer_MASK;
1486-
val |= SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, DebugVer, IMP);
1500+
val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, IMP);
14871501

14881502
/*
14891503
* Only initialize the PMU version if the vCPU was configured with one.
@@ -1503,6 +1517,7 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
15031517
const struct sys_reg_desc *rd,
15041518
u64 val)
15051519
{
1520+
u8 debugver = SYS_FIELD_GET(ID_AA64DFR0_EL1, DebugVer, val);
15061521
u8 pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, val);
15071522

15081523
/*
@@ -1522,6 +1537,13 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
15221537
if (pmuver == ID_AA64DFR0_EL1_PMUVer_IMP_DEF)
15231538
val &= ~ID_AA64DFR0_EL1_PMUVer_MASK;
15241539

1540+
/*
1541+
* ID_AA64DFR0_EL1.DebugVer is one of those awkward fields with a
1542+
* nonzero minimum safe value.
1543+
*/
1544+
if (debugver < ID_AA64DFR0_EL1_DebugVer_IMP)
1545+
return -EINVAL;
1546+
15251547
return set_id_reg(vcpu, rd, val);
15261548
}
15271549

@@ -1543,6 +1565,7 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu,
15431565
u64 val)
15441566
{
15451567
u8 perfmon = SYS_FIELD_GET(ID_DFR0_EL1, PerfMon, val);
1568+
u8 copdbg = SYS_FIELD_GET(ID_DFR0_EL1, CopDbg, val);
15461569

15471570
if (perfmon == ID_DFR0_EL1_PerfMon_IMPDEF) {
15481571
val &= ~ID_DFR0_EL1_PerfMon_MASK;
@@ -1558,6 +1581,9 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu,
15581581
if (perfmon != 0 && perfmon < ID_DFR0_EL1_PerfMon_PMUv3)
15591582
return -EINVAL;
15601583

1584+
if (copdbg < ID_DFR0_EL1_CopDbg_Armv8)
1585+
return -EINVAL;
1586+
15611587
return set_id_reg(vcpu, rd, val);
15621588
}
15631589

0 commit comments

Comments
 (0)