Skip to content

Commit 262cd16

Browse files
committed
Merge branch kvm-arm64/feat_e2h0 into kvmarm/next
* kvm-arm64/feat_e2h0: : Support for FEAT_E2H0, courtesy of Marc Zyngier : : As described in the cover letter: : : Since ARMv8.1, the architecture has grown the VHE feature, which makes : EL2 a superset of EL1. With ARMv9.5 (and retroactively allowed from : ARMv8.1), the architecture allows implementations to have VHE as the : *only* implemented behaviour, meaning that HCR_EL2.E2H can be : implemented as RES1. As a follow-up, HCR_EL2.NV1 can also be : implemented as RES0, making the VHE-ness of the architecture : recursive. : : This series adds support for detecting the architectural feature of E2H : being RES1, leveraging the existing infrastructure for handling : out-of-spec CPUs that are VHE-only. Additionally, the (incomplete) NV : infrastructure in KVM is updated to enforce E2H=1 for guest hypervisors : on implementations that do not support NV1. arm64: cpufeatures: Fix FEAT_NV check when checking for FEAT_NV1 arm64: cpufeatures: Only check for NV1 if NV is present arm64: cpufeatures: Add missing ID_AA64MMFR4_EL1 to __read_sysreg_by_encoding() KVM: arm64: Handle Apple M2 as not having HCR_EL2.NV1 implemented KVM: arm64: Force guest's HCR_EL2.E2H RES1 when NV1 is not implemented KVM: arm64: Expose ID_AA64MMFR4_EL1 to guests arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative arm64: cpufeature: Detect HCR_EL2.NV1 being RES0 arm64: cpufeature: Add ID_AA64MMFR4_EL1 handling arm64: sysreg: Add layout for ID_AA64MMFR4_EL1 arm64: cpufeature: Correctly display signed override values arm64: cpufeatures: Correctly handle signed values arm64: Add macro to compose a sysreg field value Signed-off-by: Oliver Upton <[email protected]>
2 parents 6613476 + 9aa030c commit 262cd16

File tree

11 files changed

+178
-23
lines changed

11 files changed

+178
-23
lines changed

arch/arm64/include/asm/cpu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct cpuinfo_arm64 {
5656
u64 reg_id_aa64mmfr1;
5757
u64 reg_id_aa64mmfr2;
5858
u64 reg_id_aa64mmfr3;
59+
u64 reg_id_aa64mmfr4;
5960
u64 reg_id_aa64pfr0;
6061
u64 reg_id_aa64pfr1;
6162
u64 reg_id_aa64zfr0;

arch/arm64/include/asm/cpufeature.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ struct arm64_cpu_capabilities {
363363
u8 field_pos;
364364
u8 field_width;
365365
u8 min_field_value;
366+
u8 max_field_value;
366367
u8 hwcap_type;
367368
bool sign;
368369
unsigned long hwcap;

arch/arm64/include/asm/kvm_emulate.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,8 @@ static inline bool vcpu_is_el2(const struct kvm_vcpu *vcpu)
209209

210210
static inline bool __vcpu_el2_e2h_is_set(const struct kvm_cpu_context *ctxt)
211211
{
212-
return ctxt_sys_reg(ctxt, HCR_EL2) & HCR_E2H;
212+
return (!cpus_have_final_cap(ARM64_HAS_HCR_NV1) ||
213+
(ctxt_sys_reg(ctxt, HCR_EL2) & HCR_E2H));
213214
}
214215

215216
static inline bool vcpu_el2_e2h_is_set(const struct kvm_vcpu *vcpu)

arch/arm64/include/asm/sysreg.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1181,14 +1181,17 @@
11811181
par; \
11821182
})
11831183

1184+
#define SYS_FIELD_VALUE(reg, field, val) reg##_##field##_##val
1185+
11841186
#define SYS_FIELD_GET(reg, field, val) \
11851187
FIELD_GET(reg##_##field##_MASK, val)
11861188

11871189
#define SYS_FIELD_PREP(reg, field, val) \
11881190
FIELD_PREP(reg##_##field##_MASK, val)
11891191

11901192
#define SYS_FIELD_PREP_ENUM(reg, field, val) \
1191-
FIELD_PREP(reg##_##field##_MASK, reg##_##field##_##val)
1193+
FIELD_PREP(reg##_##field##_MASK, \
1194+
SYS_FIELD_VALUE(reg, field, val))
11921195

11931196
#endif
11941197

arch/arm64/kernel/cpufeature.c

Lines changed: 95 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,42 @@ void dump_cpu_features(void)
140140
pr_emerg("0x%*pb\n", ARM64_NCAPS, &system_cpucaps);
141141
}
142142

143+
#define __ARM64_MAX_POSITIVE(reg, field) \
144+
((reg##_##field##_SIGNED ? \
145+
BIT(reg##_##field##_WIDTH - 1) : \
146+
BIT(reg##_##field##_WIDTH)) - 1)
147+
148+
#define __ARM64_MIN_NEGATIVE(reg, field) BIT(reg##_##field##_WIDTH - 1)
149+
150+
#define __ARM64_CPUID_FIELDS(reg, field, min_value, max_value) \
151+
.sys_reg = SYS_##reg, \
152+
.field_pos = reg##_##field##_SHIFT, \
153+
.field_width = reg##_##field##_WIDTH, \
154+
.sign = reg##_##field##_SIGNED, \
155+
.min_field_value = min_value, \
156+
.max_field_value = max_value,
157+
158+
/*
159+
* ARM64_CPUID_FIELDS() encodes a field with a range from min_value to
160+
* an implicit maximum that depends on the sign-ess of the field.
161+
*
162+
* An unsigned field will be capped at all ones, while a signed field
163+
* will be limited to the positive half only.
164+
*/
143165
#define ARM64_CPUID_FIELDS(reg, field, min_value) \
144-
.sys_reg = SYS_##reg, \
145-
.field_pos = reg##_##field##_SHIFT, \
146-
.field_width = reg##_##field##_WIDTH, \
147-
.sign = reg##_##field##_SIGNED, \
148-
.min_field_value = reg##_##field##_##min_value,
166+
__ARM64_CPUID_FIELDS(reg, field, \
167+
SYS_FIELD_VALUE(reg, field, min_value), \
168+
__ARM64_MAX_POSITIVE(reg, field))
169+
170+
/*
171+
* ARM64_CPUID_FIELDS_NEG() encodes a field with a range from an
172+
* implicit minimal value to max_value. This should be used when
173+
* matching a non-implemented property.
174+
*/
175+
#define ARM64_CPUID_FIELDS_NEG(reg, field, max_value) \
176+
__ARM64_CPUID_FIELDS(reg, field, \
177+
__ARM64_MIN_NEGATIVE(reg, field), \
178+
SYS_FIELD_VALUE(reg, field, max_value))
149179

150180
#define __ARM64_FTR_BITS(SIGNED, VISIBLE, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
151181
{ \
@@ -407,6 +437,11 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr3[] = {
407437
ARM64_FTR_END,
408438
};
409439

440+
static const struct arm64_ftr_bits ftr_id_aa64mmfr4[] = {
441+
S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR4_EL1_E2H0_SHIFT, 4, 0),
442+
ARM64_FTR_END,
443+
};
444+
410445
static const struct arm64_ftr_bits ftr_ctr[] = {
411446
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RES1 */
412447
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_EL0_DIC_SHIFT, 1, 1),
@@ -724,6 +759,7 @@ static const struct __ftr_reg_entry {
724759
&id_aa64mmfr1_override),
725760
ARM64_FTR_REG(SYS_ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2),
726761
ARM64_FTR_REG(SYS_ID_AA64MMFR3_EL1, ftr_id_aa64mmfr3),
762+
ARM64_FTR_REG(SYS_ID_AA64MMFR4_EL1, ftr_id_aa64mmfr4),
727763

728764
/* Op1 = 1, CRn = 0, CRm = 0 */
729765
ARM64_FTR_REG(SYS_GMID_EL1, ftr_gmid),
@@ -919,7 +955,8 @@ static void init_cpu_ftr_reg(u32 sys_reg, u64 new)
919955
pr_warn("%s[%d:%d]: %s to %llx\n",
920956
reg->name,
921957
ftrp->shift + ftrp->width - 1,
922-
ftrp->shift, str, tmp);
958+
ftrp->shift, str,
959+
tmp & (BIT(ftrp->width) - 1));
923960
} else if ((ftr_mask & reg->override->val) == ftr_mask) {
924961
reg->override->val &= ~ftr_mask;
925962
pr_warn("%s[%d:%d]: impossible override, ignored\n",
@@ -1047,6 +1084,7 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
10471084
init_cpu_ftr_reg(SYS_ID_AA64MMFR1_EL1, info->reg_id_aa64mmfr1);
10481085
init_cpu_ftr_reg(SYS_ID_AA64MMFR2_EL1, info->reg_id_aa64mmfr2);
10491086
init_cpu_ftr_reg(SYS_ID_AA64MMFR3_EL1, info->reg_id_aa64mmfr3);
1087+
init_cpu_ftr_reg(SYS_ID_AA64MMFR4_EL1, info->reg_id_aa64mmfr4);
10501088
init_cpu_ftr_reg(SYS_ID_AA64PFR0_EL1, info->reg_id_aa64pfr0);
10511089
init_cpu_ftr_reg(SYS_ID_AA64PFR1_EL1, info->reg_id_aa64pfr1);
10521090
init_cpu_ftr_reg(SYS_ID_AA64ZFR0_EL1, info->reg_id_aa64zfr0);
@@ -1418,6 +1456,7 @@ u64 __read_sysreg_by_encoding(u32 sys_id)
14181456
read_sysreg_case(SYS_ID_AA64MMFR1_EL1);
14191457
read_sysreg_case(SYS_ID_AA64MMFR2_EL1);
14201458
read_sysreg_case(SYS_ID_AA64MMFR3_EL1);
1459+
read_sysreg_case(SYS_ID_AA64MMFR4_EL1);
14211460
read_sysreg_case(SYS_ID_AA64ISAR0_EL1);
14221461
read_sysreg_case(SYS_ID_AA64ISAR1_EL1);
14231462
read_sysreg_case(SYS_ID_AA64ISAR2_EL1);
@@ -1451,11 +1490,28 @@ has_always(const struct arm64_cpu_capabilities *entry, int scope)
14511490
static bool
14521491
feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry)
14531492
{
1454-
int val = cpuid_feature_extract_field_width(reg, entry->field_pos,
1455-
entry->field_width,
1456-
entry->sign);
1493+
int val, min, max;
1494+
u64 tmp;
1495+
1496+
val = cpuid_feature_extract_field_width(reg, entry->field_pos,
1497+
entry->field_width,
1498+
entry->sign);
1499+
1500+
tmp = entry->min_field_value;
1501+
tmp <<= entry->field_pos;
14571502

1458-
return val >= entry->min_field_value;
1503+
min = cpuid_feature_extract_field_width(tmp, entry->field_pos,
1504+
entry->field_width,
1505+
entry->sign);
1506+
1507+
tmp = entry->max_field_value;
1508+
tmp <<= entry->field_pos;
1509+
1510+
max = cpuid_feature_extract_field_width(tmp, entry->field_pos,
1511+
entry->field_width,
1512+
entry->sign);
1513+
1514+
return val >= min && val <= max;
14591515
}
14601516

14611517
static u64
@@ -1739,6 +1795,28 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
17391795
return !meltdown_safe;
17401796
}
17411797

1798+
static bool has_nv1(const struct arm64_cpu_capabilities *entry, int scope)
1799+
{
1800+
/*
1801+
* Although the Apple M2 family appears to support NV1, the
1802+
* PTW barfs on the nVHE EL2 S1 page table format. Pretend
1803+
* that it doesn't support NV1 at all.
1804+
*/
1805+
static const struct midr_range nv1_ni_list[] = {
1806+
MIDR_ALL_VERSIONS(MIDR_APPLE_M2_BLIZZARD),
1807+
MIDR_ALL_VERSIONS(MIDR_APPLE_M2_AVALANCHE),
1808+
MIDR_ALL_VERSIONS(MIDR_APPLE_M2_BLIZZARD_PRO),
1809+
MIDR_ALL_VERSIONS(MIDR_APPLE_M2_AVALANCHE_PRO),
1810+
MIDR_ALL_VERSIONS(MIDR_APPLE_M2_BLIZZARD_MAX),
1811+
MIDR_ALL_VERSIONS(MIDR_APPLE_M2_AVALANCHE_MAX),
1812+
{}
1813+
};
1814+
1815+
return (__system_matches_cap(ARM64_HAS_NESTED_VIRT) &&
1816+
!(has_cpuid_feature(entry, scope) ||
1817+
is_midr_in_range_list(read_cpuid_id(), nv1_ni_list)));
1818+
}
1819+
17421820
#if defined(ID_AA64MMFR0_EL1_TGRAN_LPA2) && defined(ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2)
17431821
static bool has_lpa2_at_stage1(u64 mmfr0)
17441822
{
@@ -2739,6 +2817,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
27392817
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
27402818
.matches = has_lpa2,
27412819
},
2820+
{
2821+
.desc = "NV1",
2822+
.capability = ARM64_HAS_HCR_NV1,
2823+
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
2824+
.matches = has_nv1,
2825+
ARM64_CPUID_FIELDS_NEG(ID_AA64MMFR4_EL1, E2H0, NI_NV1)
2826+
},
27422827
{},
27432828
};
27442829

arch/arm64/kernel/cpuinfo.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
447447
info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
448448
info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
449449
info->reg_id_aa64mmfr3 = read_cpuid(ID_AA64MMFR3_EL1);
450+
info->reg_id_aa64mmfr4 = read_cpuid(ID_AA64MMFR4_EL1);
450451
info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
451452
info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
452453
info->reg_id_aa64zfr0 = read_cpuid(ID_AA64ZFR0_EL1);

arch/arm64/kernel/head.S

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -584,25 +584,32 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
584584
mov_q x1, INIT_SCTLR_EL1_MMU_OFF
585585

586586
/*
587-
* Fruity CPUs seem to have HCR_EL2.E2H set to RES1,
588-
* making it impossible to start in nVHE mode. Is that
589-
* compliant with the architecture? Absolutely not!
587+
* Compliant CPUs advertise their VHE-onlyness with
588+
* ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be
589+
* RES1 in that case.
590+
*
591+
* Fruity CPUs seem to have HCR_EL2.E2H set to RES1, but
592+
* don't advertise it (they predate this relaxation).
590593
*/
594+
mrs_s x0, SYS_ID_AA64MMFR4_EL1
595+
ubfx x0, x0, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
596+
tbnz x0, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f
597+
591598
mrs x0, hcr_el2
592599
and x0, x0, #HCR_E2H
593-
cbz x0, 1f
594-
600+
cbz x0, 2f
601+
1:
595602
/* Set a sane SCTLR_EL1, the VHE way */
596603
pre_disable_mmu_workaround
597604
msr_s SYS_SCTLR_EL12, x1
598605
mov x2, #BOOT_CPU_FLAG_E2H
599-
b 2f
606+
b 3f
600607

601-
1:
608+
2:
602609
pre_disable_mmu_workaround
603610
msr sctlr_el1, x1
604611
mov x2, xzr
605-
2:
612+
3:
606613
__init_el2_nvhe_prepare_eret
607614

608615
mov w0, #BOOT_CPU_MODE_EL2

arch/arm64/kvm/nested.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ static u64 limit_nv_id_reg(u32 id, u64 val)
133133
val |= FIELD_PREP(NV_FTR(MMFR2, TTL), 0b0001);
134134
break;
135135

136+
case SYS_ID_AA64MMFR4_EL1:
137+
val = 0;
138+
if (!cpus_have_final_cap(ARM64_HAS_HCR_NV1))
139+
val |= FIELD_PREP(NV_FTR(MMFR4, E2H0),
140+
ID_AA64MMFR4_EL1_E2H0_NI_NV1);
141+
break;
142+
136143
case SYS_ID_AA64DFR0_EL1:
137144
/* Only limited support for PMU, Debug, BPs and WPs */
138145
val &= (NV_FTR(DFR0, PMUVer) |

arch/arm64/kvm/sys_regs.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,7 +1685,8 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
16851685
u64 __f_val = FIELD_GET(reg##_##field##_MASK, val); \
16861686
(val) &= ~reg##_##field##_MASK; \
16871687
(val) |= FIELD_PREP(reg##_##field##_MASK, \
1688-
min(__f_val, (u64)reg##_##field##_##limit)); \
1688+
min(__f_val, \
1689+
(u64)SYS_FIELD_VALUE(reg, field, limit))); \
16891690
(val); \
16901691
})
16911692

@@ -2174,6 +2175,16 @@ static bool access_spsr(struct kvm_vcpu *vcpu,
21742175
return true;
21752176
}
21762177

2178+
static u64 reset_hcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
2179+
{
2180+
u64 val = r->val;
2181+
2182+
if (!cpus_have_final_cap(ARM64_HAS_HCR_NV1))
2183+
val |= HCR_E2H;
2184+
2185+
return __vcpu_sys_reg(vcpu, r->reg) = val;
2186+
}
2187+
21772188
/*
21782189
* Architected system registers.
21792190
* Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
@@ -2349,7 +2360,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
23492360
ID_AA64MMFR2_EL1_NV |
23502361
ID_AA64MMFR2_EL1_CCIDX)),
23512362
ID_SANITISED(ID_AA64MMFR3_EL1),
2352-
ID_UNALLOCATED(7,4),
2363+
ID_SANITISED(ID_AA64MMFR4_EL1),
23532364
ID_UNALLOCATED(7,5),
23542365
ID_UNALLOCATED(7,6),
23552366
ID_UNALLOCATED(7,7),
@@ -2665,7 +2676,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
26652676
EL2_REG_VNCR(VMPIDR_EL2, reset_unknown, 0),
26662677
EL2_REG(SCTLR_EL2, access_rw, reset_val, SCTLR_EL2_RES1),
26672678
EL2_REG(ACTLR_EL2, access_rw, reset_val, 0),
2668-
EL2_REG_VNCR(HCR_EL2, reset_val, 0),
2679+
EL2_REG_VNCR(HCR_EL2, reset_hcr, 0),
26692680
EL2_REG(MDCR_EL2, access_rw, reset_val, 0),
26702681
EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_NVHE_EL2_RES1),
26712682
EL2_REG_VNCR(HSTR_EL2, reset_val, 0),

arch/arm64/tools/cpucaps

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ HAS_GENERIC_AUTH_IMP_DEF
3535
HAS_GIC_CPUIF_SYSREGS
3636
HAS_GIC_PRIO_MASKING
3737
HAS_GIC_PRIO_RELAXED_SYNC
38+
HAS_HCR_NV1
3839
HAS_HCX
3940
HAS_LDAPR
4041
HAS_LPA2

0 commit comments

Comments
 (0)