summaryrefslogtreecommitdiff
path: root/arch/arm64/kvm/emulate-nested.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/kvm/emulate-nested.c')
-rw-r--r--arch/arm64/kvm/emulate-nested.c105
1 files changed, 63 insertions, 42 deletions
diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 834f13fb1fb7..22d497554c94 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -70,6 +70,7 @@ enum cgt_group_id {
CGT_HCR_ENSCXT,
CGT_HCR_TTLBIS,
CGT_HCR_TTLBOS,
+ CGT_HCR_TID5,
CGT_MDCR_TPMCR,
CGT_MDCR_TPM,
@@ -308,6 +309,12 @@ static const struct trap_bits coarse_trap_bits[] = {
.mask = HCR_TTLBOS,
.behaviour = BEHAVE_FORWARD_RW,
},
+ [CGT_HCR_TID5] = {
+ .index = HCR_EL2,
+ .value = HCR_TID5,
+ .mask = HCR_TID5,
+ .behaviour = BEHAVE_FORWARD_RW,
+ },
[CGT_MDCR_TPMCR] = {
.index = MDCR_EL2,
.value = MDCR_EL2_TPMCR,
@@ -665,6 +672,7 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = {
SR_TRAP(SYS_CCSIDR2_EL1, CGT_HCR_TID2_TID4),
SR_TRAP(SYS_CLIDR_EL1, CGT_HCR_TID2_TID4),
SR_TRAP(SYS_CSSELR_EL1, CGT_HCR_TID2_TID4),
+ SR_TRAP(SYS_GMID_EL1, CGT_HCR_TID5),
SR_RANGE_TRAP(SYS_ID_PFR0_EL1,
sys_reg(3, 0, 0, 7, 7), CGT_HCR_TID3),
SR_TRAP(SYS_ICC_SGI0R_EL1, CGT_HCR_IMO_FMO_ICH_HCR_TC),
@@ -1166,6 +1174,7 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = {
SR_TRAP(SYS_DBGWCRn_EL1(12), CGT_MDCR_TDE_TDA),
SR_TRAP(SYS_DBGWCRn_EL1(13), CGT_MDCR_TDE_TDA),
SR_TRAP(SYS_DBGWCRn_EL1(14), CGT_MDCR_TDE_TDA),
+ SR_TRAP(SYS_DBGWCRn_EL1(15), CGT_MDCR_TDE_TDA),
SR_TRAP(SYS_DBGCLAIMSET_EL1, CGT_MDCR_TDE_TDA),
SR_TRAP(SYS_DBGCLAIMCLR_EL1, CGT_MDCR_TDE_TDA),
SR_TRAP(SYS_DBGAUTHSTATUS_EL1, CGT_MDCR_TDE_TDA),
@@ -2105,23 +2114,24 @@ static u32 encoding_next(u32 encoding)
}
#define FGT_MASKS(__n, __m) \
- struct fgt_masks __n = { .str = #__m, .res0 = __m, }
-
-FGT_MASKS(hfgrtr_masks, HFGRTR_EL2_RES0);
-FGT_MASKS(hfgwtr_masks, HFGWTR_EL2_RES0);
-FGT_MASKS(hfgitr_masks, HFGITR_EL2_RES0);
-FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2_RES0);
-FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2_RES0);
-FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2_RES0);
-FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2_RES0);
-FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2_RES0);
-FGT_MASKS(hfgitr2_masks, HFGITR2_EL2_RES0);
-FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2_RES0);
-FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2_RES0);
+ struct fgt_masks __n = { .str = #__m, .res0 = __m ## _RES0, .res1 = __m ## _RES1 }
+
+FGT_MASKS(hfgrtr_masks, HFGRTR_EL2);
+FGT_MASKS(hfgwtr_masks, HFGWTR_EL2);
+FGT_MASKS(hfgitr_masks, HFGITR_EL2);
+FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2);
+FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2);
+FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2);
+FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2);
+FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2);
+FGT_MASKS(hfgitr2_masks, HFGITR2_EL2);
+FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2);
+FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2);
static __init bool aggregate_fgt(union trap_config tc)
{
struct fgt_masks *rmasks, *wmasks;
+ u64 rresx, wresx;
switch (tc.fgt) {
case HFGRTR_GROUP:
@@ -2154,24 +2164,27 @@ static __init bool aggregate_fgt(union trap_config tc)
break;
}
+ rresx = rmasks->res0 | rmasks->res1;
+ if (wmasks)
+ wresx = wmasks->res0 | wmasks->res1;
+
/*
* A bit can be reserved in either the R or W register, but
* not both.
*/
- if ((BIT(tc.bit) & rmasks->res0) &&
- (!wmasks || (BIT(tc.bit) & wmasks->res0)))
+ if ((BIT(tc.bit) & rresx) && (!wmasks || (BIT(tc.bit) & wresx)))
return false;
if (tc.pol)
- rmasks->mask |= BIT(tc.bit) & ~rmasks->res0;
+ rmasks->mask |= BIT(tc.bit) & ~rresx;
else
- rmasks->nmask |= BIT(tc.bit) & ~rmasks->res0;
+ rmasks->nmask |= BIT(tc.bit) & ~rresx;
if (wmasks) {
if (tc.pol)
- wmasks->mask |= BIT(tc.bit) & ~wmasks->res0;
+ wmasks->mask |= BIT(tc.bit) & ~wresx;
else
- wmasks->nmask |= BIT(tc.bit) & ~wmasks->res0;
+ wmasks->nmask |= BIT(tc.bit) & ~wresx;
}
return true;
@@ -2180,7 +2193,6 @@ static __init bool aggregate_fgt(union trap_config tc)
static __init int check_fgt_masks(struct fgt_masks *masks)
{
unsigned long duplicate = masks->mask & masks->nmask;
- u64 res0 = masks->res0;
int ret = 0;
if (duplicate) {
@@ -2194,10 +2206,14 @@ static __init int check_fgt_masks(struct fgt_masks *masks)
ret = -EINVAL;
}
- masks->res0 = ~(masks->mask | masks->nmask);
- if (masks->res0 != res0)
- kvm_info("Implicit %s = %016llx, expecting %016llx\n",
- masks->str, masks->res0, res0);
+ if ((masks->res0 | masks->res1 | masks->mask | masks->nmask) != GENMASK(63, 0) ||
+ (masks->res0 & masks->res1) || (masks->res0 & masks->mask) ||
+ (masks->res0 & masks->nmask) || (masks->res1 & masks->mask) ||
+ (masks->res1 & masks->nmask) || (masks->mask & masks->nmask)) {
+ kvm_info("Inconsistent masks for %s (%016llx, %016llx, %016llx, %016llx)\n",
+ masks->str, masks->res0, masks->res1, masks->mask, masks->nmask);
+ masks->res0 = ~(masks->res1 | masks->mask | masks->nmask);
+ }
return ret;
}
@@ -2269,9 +2285,6 @@ int __init populate_nv_trap_config(void)
kvm_info("nv: %ld coarse grained trap handlers\n",
ARRAY_SIZE(encoding_to_cgt));
- if (!cpus_have_final_cap(ARM64_HAS_FGT))
- goto check_mcb;
-
for (int i = 0; i < ARRAY_SIZE(encoding_to_fgt); i++) {
const struct encoding_to_trap_config *fgt = &encoding_to_fgt[i];
union trap_config tc;
@@ -2291,6 +2304,15 @@ int __init populate_nv_trap_config(void)
}
tc.val |= fgt->tc.val;
+
+ if (!aggregate_fgt(tc)) {
+ ret = -EINVAL;
+ print_nv_trap_error(fgt, "FGT bit is reserved", ret);
+ }
+
+ if (!cpus_have_final_cap(ARM64_HAS_FGT))
+ continue;
+
prev = xa_store(&sr_forward_xa, enc,
xa_mk_value(tc.val), GFP_KERNEL);
@@ -2298,11 +2320,6 @@ int __init populate_nv_trap_config(void)
ret = xa_err(prev);
print_nv_trap_error(fgt, "Failed FGT insertion", ret);
}
-
- if (!aggregate_fgt(tc)) {
- ret = -EINVAL;
- print_nv_trap_error(fgt, "FGT bit is reserved", ret);
- }
}
}
@@ -2318,7 +2335,6 @@ int __init populate_nv_trap_config(void)
kvm_info("nv: %ld fine grained trap handlers\n",
ARRAY_SIZE(encoding_to_fgt));
-check_mcb:
for (int id = __MULTIPLE_CONTROL_BITS__; id < __COMPLEX_CONDITIONS__; id++) {
const enum cgt_group_id *cgids;
@@ -2420,15 +2436,7 @@ static enum trap_behaviour compute_trap_behaviour(struct kvm_vcpu *vcpu,
static u64 kvm_get_sysreg_res0(struct kvm *kvm, enum vcpu_sysreg sr)
{
- struct kvm_sysreg_masks *masks;
-
- /* Only handle the VNCR-backed regs for now */
- if (sr < __VNCR_START__)
- return 0;
-
- masks = kvm->arch.sysreg_masks;
-
- return masks->mask[sr - __VNCR_START__].res0;
+ return kvm_get_sysreg_resx(kvm, sr).res0;
}
static bool check_fgt_bit(struct kvm_vcpu *vcpu, enum vcpu_sysreg sr,
@@ -2581,6 +2589,19 @@ local:
params = esr_sys64_to_params(esr);
/*
+ * This implements the pseudocode UnimplementedIDRegister()
+ * helper for the purpose of dealing with FEAT_IDST.
+ */
+ if (in_feat_id_space(&params)) {
+ if (kvm_has_feat(vcpu->kvm, ID_AA64MMFR2_EL1, IDS, IMP))
+ kvm_inject_sync(vcpu, kvm_vcpu_get_esr(vcpu));
+ else
+ kvm_inject_undefined(vcpu);
+
+ return true;
+ }
+
+ /*
* Check for the IMPDEF range, as per DDI0487 J.a,
* D18.3.2 Reserved encodings for IMPLEMENTATION
* DEFINED registers.