Skip to content

Commit 4e76efd

Browse files
James Morsegregkh
authored andcommitted
KVM: arm64: Disable MPAM visibility by default and ignore VMM writes
commit 6685f5d upstream. commit 011e5f5 ("arm64/cpufeature: Add remaining feature bits in ID_AA64PFR0 register") exposed the MPAM field of AA64PFR0_EL1 to guests, but didn't add trap handling. A previous patch supplied the missing trap handling. Existing VMs that have the MPAM field of ID_AA64PFR0_EL1 set need to be migratable, but there is little point enabling the MPAM CPU interface on new VMs until there is something a guest can do with it. Clear the MPAM field from the guest's ID_AA64PFR0_EL1 and on hardware that supports MPAM, politely ignore the VMMs attempts to set this bit. Guests exposed to this bug have the sanitised value of the MPAM field, so only the correct value needs to be ignored. This means the field can continue to be used to block migration to incompatible hardware (between MPAM=1 and MPAM=5), and the VMM can't rely on the field being ignored. Signed-off-by: James Morse <[email protected]> Co-developed-by: Joey Gouly <[email protected]> Signed-off-by: Joey Gouly <[email protected]> Reviewed-by: Gavin Shan <[email protected]> Tested-by: Shameer Kolothum <[email protected]> Reviewed-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]> Acked-by: Marc Zyngier <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent e2ccaf2 commit 4e76efd

File tree

1 file changed

+50
-2
lines changed

1 file changed

+50
-2
lines changed

arch/arm64/kvm/sys_regs.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,6 +1330,7 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
13301330
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE);
13311331

13321332
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SME);
1333+
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MPAM_frac);
13331334
break;
13341335
case SYS_ID_AA64ISAR1_EL1:
13351336
if (!vcpu_has_ptrauth(vcpu))
@@ -1472,6 +1473,13 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
14721473

14731474
val &= ~ID_AA64PFR0_EL1_AMU_MASK;
14741475

1476+
/*
1477+
* MPAM is disabled by default as KVM also needs a set of PARTID to
1478+
* program the MPAMVPMx_EL2 PARTID remapping registers with. But some
1479+
* older kernels let the guest see the ID bit.
1480+
*/
1481+
val &= ~ID_AA64PFR0_EL1_MPAM_MASK;
1482+
14751483
return val;
14761484
}
14771485

@@ -1560,6 +1568,42 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu,
15601568
return set_id_reg(vcpu, rd, val);
15611569
}
15621570

1571+
static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
1572+
const struct sys_reg_desc *rd, u64 user_val)
1573+
{
1574+
u64 hw_val = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
1575+
u64 mpam_mask = ID_AA64PFR0_EL1_MPAM_MASK;
1576+
1577+
/*
1578+
* Commit 011e5f5bf529f ("arm64/cpufeature: Add remaining feature bits
1579+
* in ID_AA64PFR0 register") exposed the MPAM field of AA64PFR0_EL1 to
1580+
* guests, but didn't add trap handling. KVM doesn't support MPAM and
1581+
* always returns an UNDEF for these registers. The guest must see 0
1582+
* for this field.
1583+
*
1584+
* But KVM must also accept values from user-space that were provided
1585+
* by KVM. On CPUs that support MPAM, permit user-space to write
1586+
* the sanitizied value to ID_AA64PFR0_EL1.MPAM, but ignore this field.
1587+
*/
1588+
if ((hw_val & mpam_mask) == (user_val & mpam_mask))
1589+
user_val &= ~ID_AA64PFR0_EL1_MPAM_MASK;
1590+
1591+
return set_id_reg(vcpu, rd, user_val);
1592+
}
1593+
1594+
static int set_id_aa64pfr1_el1(struct kvm_vcpu *vcpu,
1595+
const struct sys_reg_desc *rd, u64 user_val)
1596+
{
1597+
u64 hw_val = read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1);
1598+
u64 mpam_mask = ID_AA64PFR1_EL1_MPAM_frac_MASK;
1599+
1600+
/* See set_id_aa64pfr0_el1 for comment about MPAM */
1601+
if ((hw_val & mpam_mask) == (user_val & mpam_mask))
1602+
user_val &= ~ID_AA64PFR1_EL1_MPAM_frac_MASK;
1603+
1604+
return set_id_reg(vcpu, rd, user_val);
1605+
}
1606+
15631607
/*
15641608
* cpufeature ID register user accessors
15651609
*
@@ -2018,10 +2062,14 @@ static const struct sys_reg_desc sys_reg_descs[] = {
20182062
{ SYS_DESC(SYS_ID_AA64PFR0_EL1),
20192063
.access = access_id_reg,
20202064
.get_user = get_id_reg,
2021-
.set_user = set_id_reg,
2065+
.set_user = set_id_aa64pfr0_el1,
20222066
.reset = read_sanitised_id_aa64pfr0_el1,
20232067
.val = ID_AA64PFR0_EL1_CSV2_MASK | ID_AA64PFR0_EL1_CSV3_MASK, },
2024-
ID_SANITISED(ID_AA64PFR1_EL1),
2068+
{ SYS_DESC(SYS_ID_AA64PFR1_EL1),
2069+
.access = access_id_reg,
2070+
.get_user = get_id_reg,
2071+
.set_user = set_id_aa64pfr1_el1,
2072+
.reset = kvm_read_sanitised_id_reg, },
20252073
ID_UNALLOCATED(4,2),
20262074
ID_UNALLOCATED(4,3),
20272075
ID_SANITISED(ID_AA64ZFR0_EL1),

0 commit comments

Comments
 (0)