Skip to content

Commit b2a324f

Browse files
author
Marc Zyngier
committed
KVM: arm64: Use HCR_EL2 feature map to drive fixed-value bits
Similarly to other registers, describe which HCR_EL2 bit depends on which feature, and use this to compute the RES0 status of these bits. An additional complexity stems from the status of some bits such as E2H and RW, which do not had a RESx status, but still take a fixed value due to implementation choices in KVM. Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent beed444 commit b2a324f

File tree

2 files changed

+150
-37
lines changed

2 files changed

+150
-37
lines changed

arch/arm64/kvm/config.c

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ struct reg_bits_to_feat_map {
6969
#define FEAT_TRBE ID_AA64DFR0_EL1, TraceBuffer, IMP
7070
#define FEAT_DoubleLock ID_AA64DFR0_EL1, DoubleLock, IMP
7171
#define FEAT_TRF ID_AA64DFR0_EL1, TraceFilt, IMP
72+
#define FEAT_AA32EL0 ID_AA64PFR0_EL1, EL0, AARCH32
73+
#define FEAT_AA32EL1 ID_AA64PFR0_EL1, EL1, AARCH32
7274
#define FEAT_AA64EL1 ID_AA64PFR0_EL1, EL1, IMP
75+
#define FEAT_AA64EL3 ID_AA64PFR0_EL1, EL3, IMP
7376
#define FEAT_AIE ID_AA64MMFR3_EL1, AIE, IMP
7477
#define FEAT_S2POE ID_AA64MMFR3_EL1, S2POE, IMP
7578
#define FEAT_S1POE ID_AA64MMFR3_EL1, S1POE, IMP
@@ -92,6 +95,7 @@ struct reg_bits_to_feat_map {
9295
#define FEAT_PAN2 ID_AA64MMFR1_EL1, PAN, PAN2
9396
#define FEAT_DPB2 ID_AA64ISAR1_EL1, DPB, DPB2
9497
#define FEAT_AMUv1 ID_AA64PFR0_EL1, AMU, IMP
98+
#define FEAT_AMUv1p1 ID_AA64PFR0_EL1, AMU, V1P1
9599
#define FEAT_CMOW ID_AA64MMFR1_EL1, CMOW, IMP
96100
#define FEAT_D128 ID_AA64MMFR3_EL1, D128, IMP
97101
#define FEAT_DoubleFault2 ID_AA64PFR1_EL1, DF2, IMP
@@ -102,6 +106,31 @@ struct reg_bits_to_feat_map {
102106
#define FEAT_SYSREG128 ID_AA64ISAR2_EL1, SYSREG_128, IMP
103107
#define FEAT_TCR2 ID_AA64MMFR3_EL1, TCRX, IMP
104108
#define FEAT_XS ID_AA64ISAR1_EL1, XS, IMP
109+
#define FEAT_EVT ID_AA64MMFR2_EL1, EVT, IMP
110+
#define FEAT_EVT_TTLBxS ID_AA64MMFR2_EL1, EVT, TTLBxS
111+
#define FEAT_MTE2 ID_AA64PFR1_EL1, MTE, MTE2
112+
#define FEAT_RME ID_AA64PFR0_EL1, RME, IMP
113+
#define FEAT_S2FWB ID_AA64MMFR2_EL1, FWB, IMP
114+
#define FEAT_TME ID_AA64ISAR0_EL1, TME, IMP
115+
#define FEAT_TWED ID_AA64MMFR1_EL1, TWED, IMP
116+
#define FEAT_E2H0 ID_AA64MMFR4_EL1, E2H0, IMP
117+
118+
static bool not_feat_aa64el3(struct kvm *kvm)
119+
{
120+
return !kvm_has_feat(kvm, FEAT_AA64EL3);
121+
}
122+
123+
static bool feat_nv2(struct kvm *kvm)
124+
{
125+
return ((kvm_has_feat(kvm, ID_AA64MMFR4_EL1, NV_frac, NV2_ONLY) &&
126+
kvm_has_feat_enum(kvm, ID_AA64MMFR2_EL1, NV, NI)) ||
127+
kvm_has_feat(kvm, ID_AA64MMFR2_EL1, NV, NV2));
128+
}
129+
130+
static bool feat_nv2_e2h0_ni(struct kvm *kvm)
131+
{
132+
return feat_nv2(kvm) && !kvm_has_feat(kvm, FEAT_E2H0);
133+
}
105134

106135
static bool feat_rasv1p1(struct kvm *kvm)
107136
{
@@ -151,6 +180,31 @@ static bool feat_sme_smps(struct kvm *kvm)
151180
(read_sysreg_s(SYS_SMIDR_EL1) & SMIDR_EL1_SMPS));
152181
}
153182

183+
static bool compute_hcr_rw(struct kvm *kvm, u64 *bits)
184+
{
185+
/* This is purely academic: AArch32 and NV are mutually exclusive */
186+
if (bits) {
187+
if (kvm_has_feat(kvm, FEAT_AA32EL1))
188+
*bits &= ~HCR_EL2_RW;
189+
else
190+
*bits |= HCR_EL2_RW;
191+
}
192+
193+
return true;
194+
}
195+
196+
static bool compute_hcr_e2h(struct kvm *kvm, u64 *bits)
197+
{
198+
if (bits) {
199+
if (kvm_has_feat(kvm, FEAT_E2H0))
200+
*bits &= ~HCR_EL2_E2H;
201+
else
202+
*bits |= HCR_EL2_E2H;
203+
}
204+
205+
return true;
206+
}
207+
154208
static const struct reg_bits_to_feat_map hfgrtr_feat_map[] = {
155209
NEEDS_FEAT(HFGRTR_EL2_nAMAIR2_EL1 |
156210
HFGRTR_EL2_nMAIR2_EL1,
@@ -564,6 +618,77 @@ static const struct reg_bits_to_feat_map hcrx_feat_map[] = {
564618
NEEDS_FEAT(HCRX_EL2_EnAS0, FEAT_LS64_ACCDATA),
565619
};
566620

621+
static const struct reg_bits_to_feat_map hcr_feat_map[] = {
622+
NEEDS_FEAT(HCR_EL2_TID0, FEAT_AA32EL0),
623+
NEEDS_FEAT_FIXED(HCR_EL2_RW, compute_hcr_rw),
624+
NEEDS_FEAT(HCR_EL2_HCD, not_feat_aa64el3),
625+
NEEDS_FEAT(HCR_EL2_AMO |
626+
HCR_EL2_BSU |
627+
HCR_EL2_CD |
628+
HCR_EL2_DC |
629+
HCR_EL2_FB |
630+
HCR_EL2_FMO |
631+
HCR_EL2_ID |
632+
HCR_EL2_IMO |
633+
HCR_EL2_MIOCNCE |
634+
HCR_EL2_PTW |
635+
HCR_EL2_SWIO |
636+
HCR_EL2_TACR |
637+
HCR_EL2_TDZ |
638+
HCR_EL2_TGE |
639+
HCR_EL2_TID1 |
640+
HCR_EL2_TID2 |
641+
HCR_EL2_TID3 |
642+
HCR_EL2_TIDCP |
643+
HCR_EL2_TPCP |
644+
HCR_EL2_TPU |
645+
HCR_EL2_TRVM |
646+
HCR_EL2_TSC |
647+
HCR_EL2_TSW |
648+
HCR_EL2_TTLB |
649+
HCR_EL2_TVM |
650+
HCR_EL2_TWE |
651+
HCR_EL2_TWI |
652+
HCR_EL2_VF |
653+
HCR_EL2_VI |
654+
HCR_EL2_VM |
655+
HCR_EL2_VSE,
656+
FEAT_AA64EL1),
657+
NEEDS_FEAT(HCR_EL2_AMVOFFEN, FEAT_AMUv1p1),
658+
NEEDS_FEAT(HCR_EL2_EnSCXT, feat_csv2_2_csv2_1p2),
659+
NEEDS_FEAT(HCR_EL2_TICAB |
660+
HCR_EL2_TID4 |
661+
HCR_EL2_TOCU,
662+
FEAT_EVT),
663+
NEEDS_FEAT(HCR_EL2_TTLBIS |
664+
HCR_EL2_TTLBOS,
665+
FEAT_EVT_TTLBxS),
666+
NEEDS_FEAT(HCR_EL2_TLOR, FEAT_LOR),
667+
NEEDS_FEAT(HCR_EL2_ATA |
668+
HCR_EL2_DCT |
669+
HCR_EL2_TID5,
670+
FEAT_MTE2),
671+
NEEDS_FEAT(HCR_EL2_AT | /* Ignore the original FEAT_NV */
672+
HCR_EL2_NV2 |
673+
HCR_EL2_NV,
674+
feat_nv2),
675+
NEEDS_FEAT(HCR_EL2_NV1, feat_nv2_e2h0_ni), /* Missing from JSON */
676+
NEEDS_FEAT(HCR_EL2_API |
677+
HCR_EL2_APK,
678+
feat_pauth),
679+
NEEDS_FEAT(HCR_EL2_TEA |
680+
HCR_EL2_TERR,
681+
FEAT_RAS),
682+
NEEDS_FEAT(HCR_EL2_FIEN, feat_rasv1p1),
683+
NEEDS_FEAT(HCR_EL2_GPF, FEAT_RME),
684+
NEEDS_FEAT(HCR_EL2_FWB, FEAT_S2FWB),
685+
NEEDS_FEAT(HCR_EL2_TME, FEAT_TME),
686+
NEEDS_FEAT(HCR_EL2_TWEDEL |
687+
HCR_EL2_TWEDEn,
688+
FEAT_TWED),
689+
NEEDS_FEAT_FIXED(HCR_EL2_E2H, compute_hcr_e2h),
690+
};
691+
567692
static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
568693
int map_size, u64 res0, const char *str)
569694
{
@@ -593,6 +718,8 @@ void __init check_feature_map(void)
593718
hafgrtr_masks.res0, hafgrtr_masks.str);
594719
check_feat_map(hcrx_feat_map, ARRAY_SIZE(hcrx_feat_map),
595720
__HCRX_EL2_RES0, "HCRX_EL2");
721+
check_feat_map(hcr_feat_map, ARRAY_SIZE(hcr_feat_map),
722+
HCR_EL2_RES0, "HCR_EL2");
596723
}
597724

598725
static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map)
@@ -651,6 +778,17 @@ static u64 compute_res0_bits(struct kvm *kvm,
651778
require, exclude | FIXED_VALUE);
652779
}
653780

781+
static u64 compute_fixed_bits(struct kvm *kvm,
782+
const struct reg_bits_to_feat_map *map,
783+
int map_size,
784+
u64 *fixed_bits,
785+
unsigned long require,
786+
unsigned long exclude)
787+
{
788+
return __compute_fixed_bits(kvm, map, map_size, fixed_bits,
789+
require | FIXED_VALUE, exclude);
790+
}
791+
654792
void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt)
655793
{
656794
u64 val = 0;
@@ -691,6 +829,8 @@ void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt)
691829

692830
void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *res1)
693831
{
832+
u64 fixed = 0, mask;
833+
694834
switch (reg) {
695835
case HFGRTR_EL2:
696836
*res0 = compute_res0_bits(kvm, hfgrtr_feat_map,
@@ -734,6 +874,15 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
734874
*res0 |= __HCRX_EL2_RES0;
735875
*res1 = __HCRX_EL2_RES1;
736876
break;
877+
case HCR_EL2:
878+
mask = compute_fixed_bits(kvm, hcr_feat_map,
879+
ARRAY_SIZE(hcr_feat_map), &fixed,
880+
0, 0);
881+
*res0 = compute_res0_bits(kvm, hcr_feat_map,
882+
ARRAY_SIZE(hcr_feat_map), 0, 0);
883+
*res0 |= HCR_EL2_RES0 | (mask & ~fixed);
884+
*res1 = HCR_EL2_RES1 | (mask & fixed);
885+
break;
737886
default:
738887
WARN_ON_ONCE(1);
739888
*res0 = *res1 = 0;

arch/arm64/kvm/nested.c

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,43 +1018,7 @@ int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu)
10181018
set_sysreg_masks(kvm, VMPIDR_EL2, res0, res1);
10191019

10201020
/* HCR_EL2 */
1021-
res0 = BIT(48);
1022-
res1 = HCR_RW;
1023-
if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, TWED, IMP))
1024-
res0 |= GENMASK(63, 59);
1025-
if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, MTE, MTE2))
1026-
res0 |= (HCR_TID5 | HCR_DCT | HCR_ATA);
1027-
if (!kvm_has_feat(kvm, ID_AA64MMFR2_EL1, EVT, TTLBxS))
1028-
res0 |= (HCR_TTLBIS | HCR_TTLBOS);
1029-
if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, CSV2, CSV2_2) &&
1030-
!kvm_has_feat(kvm, ID_AA64PFR1_EL1, CSV2_frac, CSV2_1p2))
1031-
res0 |= HCR_ENSCXT;
1032-
if (!kvm_has_feat(kvm, ID_AA64MMFR2_EL1, EVT, IMP))
1033-
res0 |= (HCR_TOCU | HCR_TICAB | HCR_TID4);
1034-
if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, AMU, V1P1))
1035-
res0 |= HCR_AMVOFFEN;
1036-
if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, RAS, V1P1))
1037-
res0 |= HCR_FIEN;
1038-
if (!kvm_has_feat(kvm, ID_AA64MMFR2_EL1, FWB, IMP))
1039-
res0 |= HCR_FWB;
1040-
/* Implementation choice: NV2 is the only supported config */
1041-
if (!kvm_has_feat(kvm, ID_AA64MMFR4_EL1, NV_frac, NV2_ONLY))
1042-
res0 |= (HCR_NV2 | HCR_NV | HCR_AT);
1043-
if (!kvm_has_feat(kvm, ID_AA64MMFR4_EL1, E2H0, NI))
1044-
res0 |= HCR_NV1;
1045-
if (!(kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_PTRAUTH_ADDRESS) &&
1046-
kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_PTRAUTH_GENERIC)))
1047-
res0 |= (HCR_API | HCR_APK);
1048-
if (!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TME, IMP))
1049-
res0 |= BIT(39);
1050-
if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, RAS, IMP))
1051-
res0 |= (HCR_TEA | HCR_TERR);
1052-
if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, LO, IMP))
1053-
res0 |= HCR_TLOR;
1054-
if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, VH, IMP))
1055-
res0 |= HCR_E2H;
1056-
if (!kvm_has_feat(kvm, ID_AA64MMFR4_EL1, E2H0, IMP))
1057-
res1 |= HCR_E2H;
1021+
get_reg_fixed_bits(kvm, HCR_EL2, &res0, &res1);
10581022
set_sysreg_masks(kvm, HCR_EL2, res0, res1);
10591023

10601024
/* HCRX_EL2 */

0 commit comments

Comments
 (0)