arm64: Dealing with VHE-only CPUs
Marc Zyngier
maintainerv2 cover arm64: Dealing with VHE-only CPUs
This short series is a rewrite of [0] after some reviewing from Will. It simplifies the esoteric "stay at EL2" path, and move the feature override code where it actually belongs, allowing us to tell the user that no, nVHE isn't a thing on these system.
Additional bonus: the box can now boot without CONFIG_ARM64_VHE (and without KVM, of course), though that's a pretty weird state.
This allows the infamous M1 to boot (tested on a M1 Mini).
Hector, feel free to pull these two patches as a preamble to the next version of your series, though I'd expect this to go via the arm64 tree for obvious reasons.
* From v1 [1]:
- added a comment describing the mapping various states the override mask/val tuple can describe
- added a patch to prevent KVM from initialising, treating the lact of CONFIG_ARM64_VHE as a mismatched boot
[0] https://lore.kernel.org/r/[email protected]
[1] https://lore.kernel.org/r/[email protected]
Marc Zyngier (3):
arm64: cpufeature: Allow early filtering of feature override
arm64: Cope with CPUs stuck in VHE mode
arm64: Allow nVHE impaired CPUs to boot without CONFIG_ARM64_VHE
arch/arm64/include/asm/cpufeature.h | 17 +++++++++++++ arch/arm64/include/asm/virt.h | 18 +++++++++---- arch/arm64/kernel/cpufeature.c | 6 +++++ arch/arm64/kernel/head.S | 39 ++++++++++++++++++++++++++--- arch/arm64/kernel/hyp-stub.S | 8 +++--- arch/arm64/kernel/idreg-override.c | 26 ++++++++++++++++++- arch/arm64/kvm/va_layout.c | 9 +++++++ 7 files changed, 110 insertions(+), 13 deletions(-)
Signature · 7 lines
2.29.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Marc Zyngier
maintainerPATCH v2 1/3 arm64: cpufeature: Allow early filtering of feature override
Some CPUs are broken enough that some overrides need to be rejected at the earliest opportunity. In some cases, that's right at cpu feature override time.
Provide the necessary infrastructure to filter out overrides, and to report such filtered out overrides to the core cpufeature code.
--- arch/arm64/include/asm/cpufeature.h | 17 +++++++++++++++++ arch/arm64/kernel/cpufeature.c | 6 ++++++ arch/arm64/kernel/idreg-override.c | 13 +++++++++++++ 3 files changed, 36 insertions(+)
arch/arm64/include/asm/cpufeature.h +17 -0
@@ -63,6 +63,23 @@ struct arm64_ftr_bits {s64 safe_val;/* safe value for FTR_EXACT features */ }; +/* +* Describe the early feature override to the core override code: +* +* @val Values that are to be merged into the final +* sanitised value of the register. Only the bitfields +* set to 1 in @mask are valid +* @mask Mask of the features that are overriden by @val +* +* A @mask field set to full-1 indicates that the corresponding field +* in @val is a valid override. +* +* A @mask field set to full-0 with the corresponding @val field set +* to full-0 denotes that this field has no override +* +* A @mask field set to full-0 with the corresponding @val field set +* to full-1 denotes thath this field has an invalid override. +*/ struct arm64_ftr_override {u64 val;u64 mask;
arch/arm64/kernel/cpufeature.c +6 -0
@@ -809,6 +809,12 @@ static void __init init_cpu_ftr_reg(u32 sys_reg, u64 new) reg->name, ftrp->shift + ftrp->width -1 , ftrp->shift, str, tmp); + }else if ((ftr_mask & reg->override->val) == ftr_mask) { + reg->override->val &= ~ftr_mask; +pr_warn ("%s[%d:%d]: impossible override, ignored\n" , + reg->name, + ftrp->shift + ftrp->width -1 , + ftrp->shift); } val =arm64_ftr_set_value (ftrp, val, ftr_new);
arch/arm64/kernel/idreg-override.c +13 -0
@@ -25,6 +25,7 @@ struct ftr_set_desc {struct {char name[FTR_DESC_FIELD_LEN ];u8 shift; +bool (*filter)(u64 val); } fields[]; };
@@ -124,6 +125,18 @@ static void __init match_options(const char *cmdline)if (find_field (cmdline, regs[i], f, &v))continue ; +/* +* If an override gets filtered out, advertise +* it by setting the value to 0xf, but +* clearing the mask... Yes, this is fragile. +*/ +if (regs[i]->fields[f].filter && + !regs[i]->fields[f].filter (v)) { + regs[i]->override->val |= mask; + regs[i]->override->mask &= ~mask; +continue ; + } + regs[i]->override->val &= ~mask; regs[i]->override->val |= (v << shift) & mask; regs[i]->override->mask |= mask;
Signature · 7 lines
2.29.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 1/3] arm64: cpufeature: Allow early filtering of feature override
Quoted 1 line · Marc Zyngier
+ * @mask Mask of the features that are overriden by @val
FYI, I checkpatched this by accident and it pointed out a typo ('overridden').
It also complained about a tab thing in the next patch (the last hunk has a tab followed by 8 spaces), though that was just carried over from the line before the patch.
Signature · 7 lines
Hector Martin ([email protected]) Public Key: https://mrcn.st/pub _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Marc Zyngier
maintainerRe: [PATCH v2 1/3] arm64: cpufeature: Allow early filtering of feature override
Quoted 6 lines · Hector Martin
Quoted 1 line · Marc Zyngier
+ * @mask Mask of the features that are overriden by @val
FYI, I checkpatched this by accident and it pointed out a typo ('overridden').
My prefered fix would be not to run checkpatch, but since you found it... ;-)
Quoted 3 lines
It also complained about a tab thing in the next patch (the last hunk has a tab followed by 8 spaces), though that was just carried over from the line before the patch.
Fixed both in v3 which I just posted.
Thanks,
M.
Signature · 6 lines
Without deviation from the norm, progress is not possible. _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Marc Zyngier
maintainerPATCH v2 2/3 arm64: Cope with CPUs stuck in VHE mode
In reply to Marc ZyngierIt seems that the CPUs part of the SoC known as Apple M1 have the terrible habit of being stuck with HCR_EL2.E2H==1, in violation of the architecture.
Try and work around this deplorable state of affairs by detecting the stuck bit early and short-circuit the nVHE dance. Additional filtering code ensures that attempts at switching to nVHE from the command-line are also ignored.
It is still unknown whether there are many more such nuggets to be found...
--- arch/arm64/kernel/head.S | 39 +++++++++++++++++++++++++++--- arch/arm64/kernel/hyp-stub.S | 8 +++--- arch/arm64/kernel/idreg-override.c | 13 +++++++++- 3 files changed, 52 insertions(+), 8 deletions(-)
arch/arm64/kernel/head.S +36 -3
@@ -477,14 +477,13 @@ EXPORT_SYMBOL(kimage_vaddr) * booted in EL1 or EL2 respectively. */ SYM_FUNC_START(init_kernel_el) - mov_q x0, INIT_SCTLR_EL1_MMU_OFF - msr sctlr_el1, x0 - mrs x0, CurrentEL cmp x0, #CurrentEL_EL2 b.eq init_el2 SYM_INNER_LABEL(init_el1, SYM_L_LOCAL) + mov_q x0, INIT_SCTLR_EL1_MMU_OFF + msr sctlr_el1, x0 isb mov_q x0, INIT_PSTATE_EL1 msr spsr_el1, x0
@@ -504,9 +503,43 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL) msr vbar_el2, x0 isb + /* + * Fruity CPUs seem to have HCR_EL2.E2H set to RES1, + * making it impossible to start in nVHE mode. Is that + * compliant with the architecture? Absolutely not! + */ + mrs x0, hcr_el2 + and x0, x0, #HCR_E2H + cbz x0, 1f + + /* Switching to VHE requires a sane SCTLR_EL1 as a start */ + mov_q x0, INIT_SCTLR_EL1_MMU_OFF + msr_s SYS_SCTLR_EL12, x0 + + /* + * Force an eret into a helper "function", and let it return + * to our original caller... This makes sure that we have + * initialised the basic PSTATE state. + */ + mov x0, #INIT_PSTATE_EL2 + msr spsr_el1, x0 + adr x0, __cpu_stick_to_vhe + msr elr_el1, x0 + eret + +1: + mov_q x0, INIT_SCTLR_EL1_MMU_OFF + msr sctlr_el1, x0 + msr elr_el2, lr mov w0, #BOOT_CPU_MODE_EL2 eret + +__cpu_stick_to_vhe: + mov x0, #HVC_VHE_RESTART + hvc #0 + mov x0, #BOOT_CPU_MODE_EL2 + ret SYM_FUNC_END(init_kernel_el) /*
arch/arm64/kernel/hyp-stub.S +4 -4
@@ -27,12 +27,12 @@ SYM_CODE_START(__hyp_stub_vectors) ventry el2_fiq_invalid // FIQ EL2t ventry el2_error_invalid // Error EL2t - ventry el2_sync_invalid // Synchronous EL2h + ventry elx_sync // Synchronous EL2h ventry el2_irq_invalid // IRQ EL2h ventry el2_fiq_invalid // FIQ EL2h ventry el2_error_invalid // Error EL2h - ventry el1_sync // Synchronous 64-bit EL1 + ventry elx_sync // Synchronous 64-bit EL1 ventry el1_irq_invalid // IRQ 64-bit EL1 ventry el1_fiq_invalid // FIQ 64-bit EL1 ventry el1_error_invalid // Error 64-bit EL1
@@ -45,7 +45,7 @@ SYM_CODE_END(__hyp_stub_vectors) .align 11 -SYM_CODE_START_LOCAL(el1_sync) +SYM_CODE_START_LOCAL(elx_sync) cmp x0, #HVC_SET_VECTORS b.ne 1f msr vbar_el2, x1
@@ -71,7 +71,7 @@ SYM_CODE_START_LOCAL(el1_sync) 9: mov x0, xzr eret -SYM_CODE_END(el1_sync) +SYM_CODE_END(elx_sync) // nVHE? No way! Give me the real thing! SYM_CODE_START_LOCAL(mutate_to_vhe)
arch/arm64/kernel/idreg-override.c +12 -1
@@ -29,11 +29,22 @@ struct ftr_set_desc { } fields[]; }; +static bool __init mmfr1_vh_filter (u64 val) +{ +/* +* If we ever reach this point while running VHE, we're +* guaranteed to be on one of these funky, VHE-stuck CPUs. If +* the user was trying to force nVHE on us, proceed with +* attitude adjustment. +*/ +return !(is_kernel_in_hyp_mode () && val ==0 ); +} +static const struct ftr_set_desc mmfr1__initconst = { .name ="id_aa64mmfr1" , .override = &id_aa64mmfr1_override, .fields = { - {"vh" ,ID_AA64MMFR1_VHE_SHIFT }, + {"vh" ,ID_AA64MMFR1_VHE_SHIFT , mmfr1_vh_filter }, {} }, };
Signature · 7 lines
2.29.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Re: [PATCH v2 2/3] arm64: Cope with CPUs stuck in VHE mode
Quoted 12 lines · Marc Zyngier
It seems that the CPUs part of the SoC known as Apple M1 have the terrible habit of being stuck with HCR_EL2.E2H==1, in violation of the architecture.
Try and work around this deplorable state of affairs by detecting the stuck bit early and short-circuit the nVHE dance. Additional filtering code ensures that attempts at switching to nVHE from the command-line are also ignored.
It is still unknown whether there are many more such nuggets to be found...
Quoted 7 lines
Reported-by Hector Martin <[email protected]>Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/kernel/head.S | 39 +++++++++++++++++++++++++++--- arch/arm64/kernel/hyp-stub.S | 8 +++--- arch/arm64/kernel/idreg-override.c | 13 +++++++++- 3 files changed, 52 insertions(+), 8 deletions(-)
Will
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Marc Zyngier
maintainerPATCH v2 3/3 arm64: Allow nVHE impaired CPUs to boot without CONFIG_ARM64_VHE
In reply to Marc ZyngierCPUs stuck in VHE mode need some additional care if the kernel is compiled without CONFIG_ARM64_VHE.
Treat this case as another version of a mismatched boot, and prevent KVM from being initialised. The machine will boot in some bizarre state, using TPIDR_EL1 instead of TPIDR_EL2, but otherwise be functional.
--- arch/arm64/include/asm/virt.h | 18 +++++++++++++----- arch/arm64/kvm/va_layout.c | 9 +++++++++ 2 files changed, 22 insertions(+), 5 deletions(-)
arch/arm64/include/asm/virt.h +13 -5
@@ -72,6 +72,11 @@ void __hyp_reset_vectors(void);DECLARE_STATIC_KEY_FALSE (kvm_protected_mode_initialized); +static inline bool is_kernel_in_hyp_mode (void ) +{ +return read_sysreg (CurrentEL) == CurrentEL_EL2; +} +/* Reports the availability of HYP mode */ static inline bool is_hyp_mode_available (void ) {
@@ -83,6 +88,10 @@ static inline bool is_hyp_mode_available(void) static_branch_likely(&kvm_protected_mode_initialized))return true; +/* Catch braindead CPUs */ +if (!IS_ENABLED (CONFIG_ARM64_VHE ) &&is_kernel_in_hyp_mode ()) +return false; +return (__boot_cpu_mode[0 ] ==BOOT_CPU_MODE_EL2 && __boot_cpu_mode[1 ] ==BOOT_CPU_MODE_EL2 ); }
@@ -98,12 +107,11 @@ static inline bool is_hyp_mode_mismatched(void) static_branch_likely(&kvm_protected_mode_initialized))return false; -return __boot_cpu_mode[0 ] != __boot_cpu_mode[1 ]; -} +/* Catch braindead CPUs */ +if (!IS_ENABLED (CONFIG_ARM64_VHE ) &&is_kernel_in_hyp_mode ()) +return true; -static inline bool is_kernel_in_hyp_mode (void ) -{ -return read_sysreg (CurrentEL) == CurrentEL_EL2; +return __boot_cpu_mode[0 ] != __boot_cpu_mode[1 ]; } static __always_inline bool has_vhe(void)
arch/arm64/kvm/va_layout.c +9 -0
@@ -156,6 +156,9 @@ void __init kvm_update_va_mask(struct alt_instr *alt, {int i; +if (!is_hyp_mode_available ()) +return ; +BUG_ON (nr_inst !=5 );for (i =0 ; i < nr_inst; i++) {
@@ -191,6 +194,9 @@ void kvm_patch_vector_branch(struct alt_instr *alt,u64 addr;u32 insn; +if (!is_hyp_mode_available ()) +return ; +BUG_ON (nr_inst !=4 );if (!cpus_have_const_cap (ARM64_SPECTRE_V3A ) ||WARN_ON_ONCE (has_vhe ()))
@@ -244,6 +250,9 @@ static void generate_mov_q(u64 val, __le32 *origptr, __le32 *updptr, int nr_inst {u32 insn, oinsn, rd; +if (!is_hyp_mode_available ()) +return ; +BUG_ON (nr_inst !=4 );/* Compute target register */
Signature · 7 lines
2.29.2 _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Will Deacon
maintainerRe: [PATCH v2 3/3] arm64: Allow nVHE impaired CPUs to boot without CONFIG_ARM64_VHE
Quoted 8 lines · Marc Zyngier
CPUs stuck in VHE mode need some additional care if the kernel is compiled without
CONFIG_ARM64_VHE.Treat this case as another version of a mismatched boot, and prevent KVM from being initialised. The machine will boot in some bizarre state, using
TPIDR_EL1instead ofTPIDR_EL2, but otherwise be functional.
Quoted 5 lines
Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/include/asm/virt.h | 18 +++++++++++++----- arch/arm64/kvm/va_layout.c | 9 +++++++++ 2 files changed, 22 insertions(+), 5 deletions(-)
Hmm, I think we definitely need _something_ here, but it's a bit annoying to put ourselves into this weird state just for the sake of one stupid machine.
What if we dropped CONFIG_ARM64_VHE and made the VHE code unconditional instead? Is there a good reason to allow it to be disabled nowadays?
Will
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Marc Zyngier
maintainerRe: [PATCH v2 3/3] arm64: Allow nVHE impaired CPUs to boot without CONFIG_ARM64_VHE
Quoted 15 lines · Will Deacon
Quoted 8 lines · Marc Zyngier
CPUs stuck in VHE mode need some additional care if the kernel is compiled without
CONFIG_ARM64_VHE.Treat this case as another version of a mismatched boot, and prevent KVM from being initialised. The machine will boot in some bizarre state, using
TPIDR_EL1instead ofTPIDR_EL2, but otherwise be functional.Quoted 5 lines
Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/include/asm/virt.h | 18 +++++++++++++----- arch/arm64/kvm/va_layout.c | 9 +++++++++ 2 files changed, 22 insertions(+), 5 deletions(-)
Quoted 3 lines
Hmm, I think we definitely need _something_ here, but it's a bit annoying to put ourselves into this weird state just for the sake of one stupid machine.
Which is why I'm not keen at all on this patch, and I'm happy to see the machine die a painful death. We really can't be blamed for terminally buggy HW, which the M1 obviously is.
Quoted 2 lines
What if we dropped
CONFIG_ARM64_VHEand made the VHE code unconditional instead? Is there a good reason to allow it to be disabled nowadays?
What do we do for the other camp, aka people really wanting to run nVHE without any command line parameter? I can't see why you'd want to do that, but hey, that's only me.
I'd be quite happy to see CONFIG_ARM64_VHE go though. Let me know if you want a patch doing that instead.
Thanks,
M.
Signature · 6 lines
Jazz is not dead. It just smells funny... _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Will Deacon
maintainerRe: [PATCH v2 3/3] arm64: Allow nVHE impaired CPUs to boot without CONFIG_ARM64_VHE
Quoted 16 lines · Marc Zyngier
Quoted 15 lines · Will Deacon
Quoted 13 lines · Marc Zyngier
CPUs stuck in VHE mode need some additional care if the kernel is compiled without
CONFIG_ARM64_VHE.Treat this case as another version of a mismatched boot, and prevent KVM from being initialised. The machine will boot in some bizarre state, using
TPIDR_EL1instead ofTPIDR_EL2, but otherwise be functional.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/include/asm/virt.h | 18 +++++++++++++----- arch/arm64/kvm/va_layout.c | 9 +++++++++ 2 files changed, 22 insertions(+), 5 deletions(-)
Quoted 8 lines
Quoted 4 lines
Hmm, I think we definitely need _something_ here, but it's a bit annoying
to put ourselves into this weird state just for the sake of one stupid machine.Which is why I'm not keen at all on this patch, and I'm happy to see the machine die a painful death. We really can't be blamed for terminally buggy HW, which the M1 obviously is.
Perhaps, but it's not clear at all how the problem manifests and so we _will_ be blamed when things go wonky, especially as the real culprits all seem to be hiding...
Quoted 6 lines
Quoted 2 lines
What if we dropped
CONFIG_ARM64_VHEand made the VHE code unconditional instead? Is there a good reason to allow it to be disabled nowadays?What do we do for the other camp, aka people really wanting to run nVHE without any command line parameter? I can't see why you'd want to do that, but hey, that's only me.
They can pass the command-line parameter, no? If we ever get CMDLINE_EXTEND support back, they could even add it in there!
Quoted 2 lines
I'd be quite happy to see
CONFIG_ARM64_VHEgo though. Let me know if you want a patch doing that instead.
Yes please.
Will
_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Marc Zyngier
maintainerRe: [PATCH v2 3/3] arm64: Allow nVHE impaired CPUs to boot without CONFIG_ARM64_VHE
Quoted 34 lines · Will Deacon
Quoted 16 lines · Marc Zyngier
Quoted 15 lines · Will Deacon
Quoted 13 lines · Marc Zyngier
CPUs stuck in VHE mode need some additional care if the kernel is compiled without
CONFIG_ARM64_VHE.Treat this case as another version of a mismatched boot, and prevent KVM from being initialised. The machine will boot in some bizarre state, using
TPIDR_EL1instead ofTPIDR_EL2, but otherwise be functional.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/include/asm/virt.h | 18 +++++++++++++----- arch/arm64/kvm/va_layout.c | 9 +++++++++ 2 files changed, 22 insertions(+), 5 deletions(-)Quoted 8 lines
Quoted 4 lines
Hmm, I think we definitely need _something_ here, but it's a bit annoying
to put ourselves into this weird state just for the sake of one stupid machine.Which is why I'm not keen at all on this patch, and I'm happy to see the machine die a painful death. We really can't be blamed for terminally buggy HW, which the M1 obviously is.
Perhaps, but it's not clear at all how the problem manifests and so we _will_ be blamed when things go wonky, especially as the real culprits all seem to be hiding...
Quoted 3 lines
Quoted 2 lines
What if we dropped
CONFIG_ARM64_VHEand made the VHE code unconditional instead? Is there a good reason to allow it to be disabled nowadays?
Quoted 6 lines
Quoted 3 lines
What do we do for the other camp, aka people really wanting to run nVHE without any command line parameter? I can't see why you'd want to do that, but hey, that's only me.
They can pass the command-line parameter, no? If we ever get
CMDLINE_EXTENDsupport back, they could even add it in there!
My point was that they could do it *without* the parameter. No skin off my nose anyway.
Quoted 5 lines
Quoted 3 lines
I'd be quite happy to see
CONFIG_ARM64_VHEgo though. Let me know if you want a patch doing that instead.Yes please.
Right, let me repost the series then.
M.
Signature · 6 lines
Without deviation from the norm, progress is not possible. _______________________________________________ linux-arm-kernel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-arm-kernel