Skip to content

Commit 49da987

Browse files
ouptonMarc Zyngier
authored andcommitted
KVM: arm64: nv: Don't erroneously claim FEAT_DoubleLock for NV VMs
ID_AA64DFR0_EL1.DoubleLock is one of those annoying signed feature fields where a non-negative value implies that a feature is implemented and a negative value implies that it is not. While the intention of masking this field was likely to hide the feature, KVM actually advertises it, even on unsupporting hardware. Remove FEAT_DoubleLock from the mask, making the NI value visible to the VM. Take care to accept the old, incorrect values for this field as we've lied to userspace. Signed-off-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent d3c35b7 commit 49da987

File tree

2 files changed

+25
-1
lines changed

2 files changed

+25
-1
lines changed

arch/arm64/kvm/nested.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1582,7 +1582,6 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val)
15821582
ID_AA64DFR0_EL1_MTPMU |
15831583
ID_AA64DFR0_EL1_TraceBuffer |
15841584
ID_AA64DFR0_EL1_TraceFilt |
1585-
ID_AA64DFR0_EL1_DoubleLock |
15861585
ID_AA64DFR0_EL1_PMSVer |
15871586
ID_AA64DFR0_EL1_CTX_CMPs |
15881587
ID_AA64DFR0_EL1_SEBEP |

arch/arm64/kvm/sys_regs.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,6 +1997,26 @@ static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
19971997
return val;
19981998
}
19991999

2000+
/*
2001+
* Older versions of KVM erroneously claim support for FEAT_DoubleLock with
2002+
* NV-enabled VMs on unsupporting hardware. Silently ignore the incorrect
2003+
* value if it is consistent with the bug.
2004+
*/
2005+
static bool ignore_feat_doublelock(struct kvm_vcpu *vcpu, u64 val)
2006+
{
2007+
u8 host, user;
2008+
2009+
if (!vcpu_has_nv(vcpu))
2010+
return false;
2011+
2012+
host = SYS_FIELD_GET(ID_AA64DFR0_EL1, DoubleLock,
2013+
read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1));
2014+
user = SYS_FIELD_GET(ID_AA64DFR0_EL1, DoubleLock, val);
2015+
2016+
return host == ID_AA64DFR0_EL1_DoubleLock_NI &&
2017+
user == ID_AA64DFR0_EL1_DoubleLock_IMP;
2018+
}
2019+
20002020
static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
20012021
const struct sys_reg_desc *rd,
20022022
u64 val)
@@ -2028,6 +2048,11 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
20282048
if (debugver < ID_AA64DFR0_EL1_DebugVer_IMP)
20292049
return -EINVAL;
20302050

2051+
if (ignore_feat_doublelock(vcpu, val)) {
2052+
val &= ~ID_AA64DFR0_EL1_DoubleLock;
2053+
val |= SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, DoubleLock, NI);
2054+
}
2055+
20312056
return set_id_reg(vcpu, rd, val);
20322057
}
20332058

0 commit comments

Comments
 (0)