KVM: arm64: Allow using VHE in the nVHE hypervisor
Subsystems (6)
Marc Zyngier
maintainercover KVM: arm64: Allow using VHE in the nVHE hypervisor
KVM (on ARMv8.0) and pKVM (on all revisions of the architecture) uses the split hypervisor model that makes the EL2 code more or less standalone. For this, we totally ignore the VHE mode and stick with the good old v8.0 EL2 setup.
This is all good, but means that the EL2 code is limited in what it can do with its own address space. This series proposes to remove this limitation and to allow VHE to be used even with the split hypervisor model. This has some potential isolation benefits[1], and *maybe* allow deviant systems to eventually run pKVM.
It introduce a new "mode" for KVM called hVHE, in reference to the nVHE mode, and indicating that only the hypervisor is using VHE. Note that this is all this series does. No effort is made to improve the VA space management, which will be the subject of another series if this one ever makes it.
This has been lightly tested on a M1 box, with no measurable change in performance.
Thanks,
M.
[1] https://www.youtube.com/watch?v=1F_Mf2j9eIo&list=PLbzoR-pLrL6qWL3v2KOcvwZ54-w0z5uXV&index=11
Marc Zyngier (17):
arm64: Turn kaslr_feature_override into a generic SW feature override
arm64: Add KVM_HVHE capability and has_hvhe() predicate
arm64: Don't enable VHE for the kernel if OVERRIDE_HVHE is set
arm64: Prevent the use of is_kernel_in_hyp_mode() in hypervisor code
arm64: Allow EL1 physical timer access when running VHE
arm64: Use CPACR_EL1 format to set CPTR_EL2 when E2H is set
KVM: arm64: Elide kern_hyp_va() in VHE-specific parts of the
hypervisor
KVM: arm64: Remove alternatives from sysreg accessors in VHE
hypervisor context
KVM: arm64: Key use of VHE instructions in nVHE code off
ARM64_KVM_HVHE
KVM: arm64: Force HCR_EL2.E2H when ARM64_KVM_HVHE is set
KVM: arm64: Disable TTBR1_EL2 when using ARM64_KVM_HVHE
KVM: arm64: Adjust EL2 stage-1 leaf AP bits when ARM64_KVM_HVHE is set
KVM: arm64: Rework CPTR_EL2 programming for HVHE configuration
KVM: arm64: Program the timer traps with VHE layout in hVHE mode
KVM: arm64: Force HCR_E2H in guest context when ARM64_KVM_HVHE is set
arm64: Allow arm64_sw.hvhe on command line
KVM: arm64: Terrible timer hack for M1 with hVHE
arch/arm64/include/asm/arch_timer.h | 8 ++++ arch/arm64/include/asm/cpufeature.h | 5 +++ arch/arm64/include/asm/el2_setup.h | 16 +++++++- arch/arm64/include/asm/kvm_arm.h | 3 -- arch/arm64/include/asm/kvm_asm.h | 1 + arch/arm64/include/asm/kvm_emulate.h | 33 +++++++++++++++- arch/arm64/include/asm/kvm_hyp.h | 37 +++++++++++++----- arch/arm64/include/asm/kvm_mmu.h | 4 ++ arch/arm64/include/asm/virt.h | 15 +++++++- arch/arm64/kernel/cpufeature.c | 17 +++++++++ arch/arm64/kernel/hyp-stub.S | 21 ++++++++++- arch/arm64/kernel/idreg-override.c | 25 ++++++++----- arch/arm64/kernel/image-vars.h | 3 ++ arch/arm64/kernel/kaslr.c | 6 +-- arch/arm64/kvm/arch_timer.c | 5 +++ arch/arm64/kvm/arm.c | 12 +++++- arch/arm64/kvm/fpsimd.c | 4 +- arch/arm64/kvm/hyp/include/hyp/switch.h | 2 +- arch/arm64/kvm/hyp/nvhe/hyp-main.c | 17 ++++++++- arch/arm64/kvm/hyp/nvhe/pkvm.c | 27 ++++++++++--- arch/arm64/kvm/hyp/nvhe/switch.c | 28 ++++++++------ arch/arm64/kvm/hyp/nvhe/timer-sr.c | 29 ++++++++++---- arch/arm64/kvm/hyp/pgtable.c | 6 ++- arch/arm64/kvm/hyp/vhe/switch.c | 2 +- arch/arm64/tools/cpucaps | 1 + drivers/irqchip/irq-apple-aic.c | 50 ++++++++++++++++++++++++- 26 files changed, 312 insertions(+), 65 deletions(-)
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 1/17 arm64: Turn kaslr_feature_override into a generic SW feature override
Disabling KASLR from the command line is implemented as a feature override. Repaint it slightly so that it can further be used as more generic infrastructure for SW override purposes.
--- arch/arm64/include/asm/cpufeature.h | 4 ++++ arch/arm64/kernel/cpufeature.c | 2 ++ arch/arm64/kernel/idreg-override.c | 16 ++++++---------- arch/arm64/kernel/kaslr.c | 6 +++--- 4 files changed, 15 insertions(+), 13 deletions(-)
arch/arm64/include/asm/cpufeature.h +4 -0
@@ -15,6 +15,8 @@#define MAX_CPU_FEATURES 128#define cpu_feature (x) KERNEL_HWCAP_ ## x +#define ARM64_SW_FEATURE_OVERRIDE_NOKASLR 0 +#ifndef __ASSEMBLY__#include <linux/bug.h>
@@ -914,6 +916,8 @@ extern struct arm64_ftr_override id_aa64smfr0_override;extern struct arm64_ftr_override id_aa64isar1_override;extern struct arm64_ftr_override id_aa64isar2_override; +extern struct arm64_ftr_override arm64_sw_feature_override; +u32 get_kvm_ipa_limit (void );void dump_cpu_features (void );
arch/arm64/kernel/cpufeature.c +2 -0
@@ -620,6 +620,8 @@ struct arm64_ftr_override __ro_after_init id_aa64smfr0_override;struct arm64_ftr_override __ro_after_init id_aa64isar1_override;struct arm64_ftr_override __ro_after_init id_aa64isar2_override; +struct arm64_ftr_override arm64_sw_feature_override; + static const struct __ftr_reg_entry { u32 sys_id; struct arm64_ftr_reg *reg;
arch/arm64/kernel/idreg-override.c +6 -10
@@ -137,15 +137,11 @@ static const struct ftr_set_desc smfr0 __initconst = { }, }; -extern struct arm64_ftr_override kaslr_feature_override; - -static const struct ftr_set_desc kaslr__initconst = { - .name ="kaslr" , -#ifdef CONFIG_RANDOMIZE_BASE - .override = &kaslr_feature_override, -#endif +static const struct ftr_set_desc sw_features__initconst = { + .name ="arm64_sw" , + .override = &arm64_sw_feature_override, .fields = { -FIELD ("disabled" ,0 ,NULL ), +FIELD ("nokaslr" ,ARM64_SW_FEATURE_OVERRIDE_NOKASLR ,NULL ), {} }, };
@@ -157,7 +153,7 @@ static const struct ftr_set_desc * const regs[] __initconst = { &isar1, &isar2, &smfr0, - &kaslr, + &sw_features, }; static const struct {
@@ -174,7 +170,7 @@ static const struct { "id_aa64isar1.api=0 id_aa64isar1.apa=0 " "id_aa64isar2.gpa3=0 id_aa64isar2.apa3=0" }, { "arm64.nomte", "id_aa64pfr1.mte=0" }, - { "nokaslr", "kaslr.disabled=1" }, + { "nokaslr", "arm64_sw.nokaslr=1" }, }; static int __init find_field(const char *cmdline,
arch/arm64/kernel/kaslr.c +3 -3
@@ -23,8 +23,6 @@u64 __ro_after_init module_alloc_base;u16 __initdata memstart_offset_seed; -struct arm64_ftr_override kaslr_feature_override__initdata ; -static int __init kaslr_init (void ) {u64 module_range;
@@ -36,7 +34,9 @@ static int __init kaslr_init(void)*/ module_alloc_base = (u64 )_etext -MODULES_VSIZE ; -if (kaslr_feature_override.val & kaslr_feature_override.mask &0xf ) { +if (cpuid_feature_extract_unsigned_field (arm64_sw_feature_override.val & + arm64_sw_feature_override.mask, +ARM64_SW_FEATURE_OVERRIDE_NOKASLR )) {pr_info ("KASLR disabled on command line\n" );return 0 ; }
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 2/17 arm64: Add KVM_HVHE capability and has_hvhe() predicate
In reply to Marc ZyngierExpose a capability keying the hVHE feature as well as a new predicate testing it. Nothing is so far using it, and nothing is enabling it yet.
--- arch/arm64/include/asm/cpufeature.h | 1 + arch/arm64/include/asm/virt.h | 8 ++++++++ arch/arm64/kernel/cpufeature.c | 15 +++++++++++++++ arch/arm64/tools/cpucaps | 1 + 4 files changed, 25 insertions(+)
arch/arm64/include/asm/cpufeature.h +1 -0
@@ -16,6 +16,7 @@#define cpu_feature (x) KERNEL_HWCAP_ ## x#define ARM64_SW_FEATURE_OVERRIDE_NOKASLR 0 +#define ARM64_SW_FEATURE_OVERRIDE_HVHE 4#ifndef __ASSEMBLY__
arch/arm64/include/asm/virt.h +8 -0
@@ -140,6 +140,14 @@ static __always_inline bool is_protected_kvm_enabled(void)return cpus_have_final_cap (ARM64_KVM_PROTECTED_MODE ); } +static __always_inline bool has_hvhe(void) +{ +if (is_vhe_hyp_code ()) +return false; + +return cpus_have_final_cap (ARM64_KVM_HVHE ); +} +static inline bool is_hyp_nvhe (void ) {return is_hyp_mode_available () && !is_kernel_in_hyp_mode ();
arch/arm64/kernel/cpufeature.c +15 -0
@@ -1932,6 +1932,15 @@ static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused)write_sysreg (read_sysreg (tpidr_el1), tpidr_el2); } +static bool hvhe_possible (const struct arm64_cpu_capabilities *entry, +int __unused) +{ +u64 val; + + val = arm64_sw_feature_override.val & arm64_sw_feature_override.mask; +return cpuid_feature_extract_unsigned_field (val,ARM64_SW_FEATURE_OVERRIDE_HVHE ); +} +#ifdef CONFIG_ARM64_PAN static void cpu_enable_pan (const struct arm64_cpu_capabilities *__unused) {
@@ -2642,6 +2651,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_cpuid_feature, .cpu_enable = cpu_trap_el0_impdef, }, + { + .desc = "VHE for hypervisor only", + .capability = ARM64_KVM_HVHE, + .type = ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE, + .matches = hvhe_possible, + }, {}, };
arch/arm64/tools/cpucaps +1 -0
@@ -43,6 +43,7 @@ HAS_TLB_RANGE HAS_VIRT_HOST_EXTN HAS_WFXT HW_DBM +KVM_HVHE KVM_PROTECTED_MODE MISMATCHED_CACHE_TYPE MTE
Signature · 1 line
2.34.1
Re: [PATCH 02/17] arm64: Add KVM_HVHE capability and has_hvhe() predicate
Quoted 6 lines · Marc Zyngier
arch/arm64/kernel/cpufeature.c +0
-0@@ -1932,6 +1932,15 @@ static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused)write_sysreg (read_sysreg (tpidr_el1), tpidr_el2);
arch/arm64/kernel/cpufeature.c static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused) · line 1942
Quoted 10 lines
arch/arm64/kernel/cpufeature.c +8
-0} +static bool hvhe_possible (const struct arm64_cpu_capabilities *entry, +int __unused) +{ +u64 val; + + val = arm64_sw_feature_override.val & arm64_sw_feature_override.mask; +return cpuid_feature_extract_unsigned_field (val,ARM64_SW_FEATURE_OVERRIDE_HVHE ); +}
Does this need to test ID_AA64MMFR1_EL1.VH as well? Otherwise I don't see what would stop us from attempting hVHE on a system with asymmetric support for VHE, as the software override was only evaluated on the boot CPU.
Quoted 32 lines
arch/arm64/kernel/cpufeature.c +7
-0+#ifdef CONFIG_ARM64_PAN static void cpu_enable_pan (const struct arm64_cpu_capabilities *__unused) {@@ -2642,6 +2651,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_cpuid_feature, .cpu_enable = cpu_trap_el0_impdef, }, + { + .desc = "VHE for hypervisor only", + .capability = ARM64_KVM_HVHE, + .type = ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE, + .matches = hvhe_possible, + }, {}, };arch/arm64/tools/cpucaps +1
-0@@ -43,6 +43,7 @@ HAS_TLB_RANGE HAS_VIRT_HOST_EXTN HAS_WFXT HW_DBM +KVM_HVHE KVM_PROTECTED_MODE MISMATCHED_CACHE_TYPE MTESignature · 1 line
2.34.1
Signature · 2 lines
Thanks, Oliver
Marc Zyngier
maintainerPATCH 3/17 arm64: Don't enable VHE for the kernel if OVERRIDE_HVHE is set
In reply to Marc ZyngierIf the OVERRIDE_HVHE SW override is set (as a precursor of the KVM_HVHE capability), do not enable VHE for the kernel and drop to EL1 as if VHE was either disabled or unavailable.
Further changes will enable VHE at EL2 only, with the kernel still running at EL1.
--- arch/arm64/kernel/hyp-stub.S | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
arch/arm64/kernel/hyp-stub.S +9 -1
@@ -157,7 +157,15 @@ SYM_CODE_START_LOCAL(__finalise_el2) tbnz x1, #0, 1f // Needs to be VHE capable, obviously - check_override id_aa64mmfr1 ID_AA64MMFR1_EL1_VH_SHIFT 2f 1f + check_override id_aa64mmfr1 ID_AA64MMFR1_EL1_VH_SHIFT 0f 1f + +0: // Check whether we only want the hypervisor to run VHE, not the kernel + adr_l x1, arm64_sw_feature_override + ldr x2, [x1, FTR_OVR_VAL_OFFSET] + ldr x1, [x1, FTR_OVR_MASK_OFFSET] + and x2, x2, x1 + ubfx x2, x2, #ARM64_SW_FEATURE_OVERRIDE_HVHE, #4 + cbz x2, 2f 1: mov_q x0, HVC_STUB_ERR eret
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 4/17 arm64: Prevent the use of is_kernel_in_hyp_mode() in hypervisor code
In reply to Marc ZyngierUsing is_kernel_in_hyp_mode() in hypervisor code is a pretty bad mistake. This helper only checks for CurrentEL being EL2, which is always true.
Make the link fail if using the helper in hypervisor context by referencing a non-existent function. Whilst we're at it, flag the helper as __always_inline, which it really should be.
--- arch/arm64/include/asm/virt.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/arm64/include/asm/virt.h +6 -1
@@ -110,8 +110,13 @@ static inline bool is_hyp_mode_mismatched(void)return __boot_cpu_mode[0 ] != __boot_cpu_mode[1 ]; } -static inline bool is_kernel_in_hyp_mode (void ) +extern void gotcha_is_kernel_in_hyp_mode (void ); + +static __always_inline bool is_kernel_in_hyp_mode(void) { +#if defined(__KVM_NVHE_HYPERVISOR__) || defined(__KVM_VHE_HYPERVISOR__) +gotcha_is_kernel_in_hyp_mode (); +#endif return read_sysreg (CurrentEL) == CurrentEL_EL2; }
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 5/17 arm64: Allow EL1 physical timer access when running VHE
In reply to Marc ZyngierTo initialise the timer access from EL2 when HCR_EL2.E2H is set, we must make use the CNTHCTL_EL2 formap used is appropriate.
This amounts to shifting the timer/counter enable bits by 10 to the left.
--- arch/arm64/include/asm/el2_setup.h | 5 +++++ 1 file changed, 5 insertions(+)
arch/arm64/include/asm/el2_setup.h +5 -0
@@ -34,6 +34,11 @@*/ .macro __init_el2_timers mov x0, #3 // Enable EL1 physical timers +mrs x1, hcr_el2 + and x1, x1, #HCR_E2H + cbz x1, .LnVHE_\@ + lsl x0, x0, #10 +.LnVHE_\@: msr cnthctl_el2, x0 msr cntvoff_el2, xzr // Clear virtual offset .endm
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 6/17 arm64: Use CPACR_EL1 format to set CPTR_EL2 when E2H is set
In reply to Marc ZyngierWhen HCR_EL2.E2H is set, the CPTR_EL2 register takes the CPACR_EL1 format. Yes, this is good fun.
Hack the bits of startup code that assume E2H=0 while setting up CPTR_EL2 to make them grok the CPTR_EL1 format.
--- arch/arm64/include/asm/el2_setup.h | 11 +++++++++-- arch/arm64/kernel/hyp-stub.S | 11 +++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-)
arch/arm64/include/asm/el2_setup.h +9 -2
@@ -129,8 +129,15 @@ .endm /* Coprocessor traps */ -.macro __init_el2_nvhe_cptr +.macro __init_el2_cptr + mrs x1, hcr_el2 + and x1, x1, #HCR_E2H + cbz x1, .LnVHE_\@ + mov x0, #(CPACR_EL1_FPEN_EL1EN | CPACR_EL1_FPEN_EL0EN) + b .Lset_cptr_\@ +.LnVHE_\@: mov x0, #0x33ff +.Lset_cptr_\@: msr cptr_el2, x0 // Disable copro. traps to EL2 .endm
@@ -196,7 +203,7 @@__init_el2_gicv3 __init_el2_hstr__init_el2_nvhe_idregs - __init_el2_nvhe_cptr + __init_el2_cptr__init_el2_fgt __init_el2_nvhe_prepare_eret .endm
arch/arm64/kernel/hyp-stub.S +11 -0
@@ -102,7 +102,18 @@ SYM_CODE_START_LOCAL(__finalise_el2) .Linit_sve: /* SVE register access */ mrs x0, cptr_el2 // Disable SVE traps + + mrs x1, hcr_el2 + and x1, x1, #HCR_E2H + cbz x1, .Lcptr_nvhe + + // VHE case + orr x0, x0, #(CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN) + b .Lset_cptr + +.Lcptr_nvhe: // nVHE case bic x0, x0, #CPTR_EL2_TZ +.Lset_cptr: msr cptr_el2, x0 isb mov x1, #ZCR_ELx_LEN_MASK // SVE: Enable full vector
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 7/17 KVM: arm64: Elide kern_hyp_va() in VHE-specific parts of the hypervisor
In reply to Marc ZyngierFor VHE-specific hypervisor code, kern_hyp_va() is a NOP.
Actually, it is a whole range of NOPs. It'd be much better if this code simply didn't exist. Let's just do that.
--- arch/arm64/include/asm/kvm_mmu.h | 4 ++++ 1 file changed, 4 insertions(+)
arch/arm64/include/asm/kvm_mmu.h +4 -0
@@ -63,6 +63,7 @@* specific registers encoded in the instructions). */ .macro kern_hyp_va reg +#ifndef __KVM_VHE_HYPERVISOR__alternative_cb ARM64_ALWAYS_SYSTEM , kvm_update_va_mask and \reg, \reg, #1 /* mask with va_mask */ ror \reg, \reg, #1 /* rotate to the first tag bit */
@@ -70,6 +71,7 @@ alternative_cb ARM64_ALWAYS_SYSTEM, kvm_update_va_mask add \reg, \reg, #0, lsl 12 /* insert the top 12 bits of the tag */ ror \reg, \reg, #63 /* rotate back */ alternative_cb_end +#endif .endm/*
@@ -126,6 +128,7 @@ void kvm_apply_hyp_relocations(void);static __always_inline unsigned long __kern_hyp_va (unsigned long v) { +#ifndef __KVM_VHE_HYPERVISOR__ asm volatile(ALTERNATIVE_CB("and %0, %0, #1\n""ror %0, %0, #1\n" "add %0, %0, #0\n"
@@ -134,6 +137,7 @@ static __always_inline unsigned long __kern_hyp_va(unsigned long v) ARM64_ALWAYS_SYSTEM, kvm_update_va_mask) : "+r" (v)); +#endif return v; }
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 8/17 KVM: arm64: Remove alternatives from sysreg accessors in VHE hypervisor context
In reply to Marc ZyngierIn the VHE hypervisor code, we should be using the remapped VHE accessors, no ifs, no buts. No need to generate any alternative.
--- arch/arm64/include/asm/kvm_hyp.h | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-)
arch/arm64/include/asm/kvm_hyp.h +19 -6
@@ -16,6 +16,23 @@ DECLARE_PER_CPU(struct kvm_cpu_context, kvm_hyp_ctxt); DECLARE_PER_CPU(unsigned long, kvm_hyp_vector); DECLARE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params); +/* +* Unified accessors for registers that have a different encoding +* between VHE and non-VHE. They must be specified without their "ELx" +* encoding, but with the SYS_ prefix, as defined in asm/sysreg.h. +*/ + +#if defined(__KVM_VHE_HYPERVISOR__) + +#define read_sysreg_el0 (r) read_sysreg_s(r##_EL02) +#define write_sysreg_el0 (v,r) write_sysreg_s(v, r##_EL02) +#define read_sysreg_el1 (r) read_sysreg_s(r##_EL12) +#define write_sysreg_el1 (v,r) write_sysreg_s(v, r##_EL12) +#define read_sysreg_el2 (r) read_sysreg_s(r##_EL1) +#define write_sysreg_el2 (v,r) write_sysreg_s(v, r##_EL1) + +#else // !__KVM_VHE_HYPERVISOR__ +#define read_sysreg_elx (r,nvh,vh) \ ({ \ u64 reg; \
@@ -35,12 +52,6 @@ DECLARE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params); : : "rZ" (__val)); \ } while (0) -/* -* Unified accessors for registers that have a different encoding -* between VHE and non-VHE. They must be specified without their "ELx" -* encoding, but with the SYS_ prefix, as defined in asm/sysreg.h. - */ -#define read_sysreg_el0 (r) read_sysreg_elx(r, _EL0, _EL02)#define write_sysreg_el0 (v,r) write_sysreg_elx(v, r, _EL0, _EL02)#define read_sysreg_el1 (r) read_sysreg_elx(r, _EL1, _EL12)
@@ -48,6 +59,8 @@ DECLARE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);#define read_sysreg_el2 (r) read_sysreg_elx(r, _EL2, _EL1)#define write_sysreg_el2 (v,r) write_sysreg_elx(v, r, _EL2, _EL1) +#endif // __KVM_VHE_HYPERVISOR__ +/* * Without an __arch_swab32(), we fall back to ___constant_swab32(), but the * static inline can allow the compiler to out-of-line this. KVM always wants
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 9/17 KVM: arm64: Key use of VHE instructions in nVHE code off ARM64_KVM_HVHE
In reply to Marc ZyngierWe can now start with the fun stuff: if we enable VHE *only* for the hypervisor, we need to generate the VHE instructions when accessing the system registers.
For this, reporpose the alternative sequence to be keyed off ARM64_KVM_HVHE in the nVHE hypervisor code, and only there.
--- arch/arm64/include/asm/kvm_hyp.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
arch/arm64/include/asm/kvm_hyp.h +9 -3
@@ -33,12 +33,18 @@ DECLARE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);#else // !__KVM_VHE_HYPERVISOR__ +#if defined(__KVM_NVHE_HYPERVISOR__) +#define VHE_ALT_KEY ARM64_KVM_HVHE +#else +#define VHE_ALT_KEY ARM64_HAS_VIRT_HOST_EXTN +#endif +#define read_sysreg_elx (r,nvh,vh) \ ({ \ u64 reg; \ - asm volatile(ALTERNATIVE(__mrs_s("%0", r##nvh), \ + asm volatile(ALTERNATIVE(__mrs_s("%0", r##nvh), \ __mrs_s("%0", r##vh), \ - ARM64_HAS_VIRT_HOST_EXTN) \ + VHE_ALT_KEY) \ : "=r" (reg)); \ reg; \ })
@@ -48,7 +54,7 @@ DECLARE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);u64 __val = (u64)(v); \ asm volatile(ALTERNATIVE(__msr_s(r##nvh, "%x0"), \ __msr_s(r##vh, "%x0"), \ - ARM64_HAS_VIRT_HOST_EXTN) \ + VHE_ALT_KEY) \ : : "rZ" (__val)); \ } while (0)
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 10/17 KVM: arm64: Force HCR_EL2.E2H when ARM64_KVM_HVHE is set
In reply to Marc ZyngierObviously, in order to be able to use VHE whilst at EL2, we need to set HCR_EL2.E2H. Do so when ARM64_KVM_HVHE is set.
--- arch/arm64/kvm/arm.c | 2 ++ 1 file changed, 2 insertions(+)
arch/arm64/kvm/arm.c +2 -0
@@ -1558,6 +1558,8 @@ static void cpu_prepare_hyp_mode(int cpu) params->hcr_el2 =HCR_HOST_NVHE_PROTECTED_FLAGS ; else params->hcr_el2 = HCR_HOST_NVHE_FLAGS; +if (cpus_have_final_cap (ARM64_KVM_HVHE )) + params->hcr_el2 |=HCR_E2H ; params->vttbr = params->vtcr =0 ;/*
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 11/17 KVM: arm64: Disable TTBR1_EL2 when using ARM64_KVM_HVHE
In reply to Marc ZyngierWhen using hVHE, we end-up with two TTBRs at EL2. That's great, but we're not quite ready for this just yet.
Disable TTBR1_EL2 by setting TCR_EL2.EPD1 so that we only translate via TTBR0_EL2.
--- arch/arm64/kvm/arm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
arch/arm64/kvm/arm.c +7 -1
@@ -1548,7 +1548,13 @@ static void cpu_prepare_hyp_mode(int cpu)* * So use the same T0SZ value we use for the ID map. */ - tcr = (read_sysreg (tcr_el1) &TCR_EL2_MASK ) |TCR_EL2_RES1 ; + tcr =read_sysreg (tcr_el1); +if (cpus_have_final_cap (ARM64_KVM_HVHE )) { + tcr |=TCR_EPD1_MASK ; + }else { + tcr &=TCR_EL2_MASK ; + tcr |=TCR_EL2_RES1 ; + } tcr &= ~TCR_T0SZ_MASK ; tcr |= (idmap_t0sz &GENMASK (TCR_TxSZ_WIDTH -1 ,0 )) <<TCR_T0SZ_OFFSET ; params->tcr_el2 = tcr;
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 12/17 KVM: arm64: Adjust EL2 stage-1 leaf AP bits when ARM64_KVM_HVHE is set
In reply to Marc ZyngierEl2 stage-1 page-table format is subtly (and annoyingly) different when HCR_EL2.E2H is set.
Take the ARM64_KVM_HVHE configuration into account when setting the AP bits.
--- arch/arm64/kvm/hyp/pgtable.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
arch/arm64/kvm/hyp/pgtable.c +4 -2
@@ -21,8 +21,10 @@#define KVM_PTE_LEAF_ATTR_LO_S1_ATTRIDX GENMASK(4, 2)#define KVM_PTE_LEAF_ATTR_LO_S1_AP GENMASK(7, 6) -#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RO 3 -#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RW 1 +#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RO \ + ({ cpus_have_final_cap(ARM64_KVM_HVHE) ? 2 : 3; }) +#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RW \ + ({ cpus_have_final_cap(ARM64_KVM_HVHE) ? 0 : 1; })#define KVM_PTE_LEAF_ATTR_LO_S1_SH GENMASK(9, 8)#define KVM_PTE_LEAF_ATTR_LO_S1_SH_IS 3#define KVM_PTE_LEAF_ATTR_LO_S1_AF BIT(10)
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 13/17 KVM: arm64: Rework CPTR_EL2 programming for HVHE configuration
In reply to Marc ZyngierJust like we repainted the early arm64 code, we need to update the CPTR_EL2 accesses that are taking place in the nVHE code when hVHE is used, making them look as if they were CPACR_EL1 accesses. Just like the VHE code.
--- arch/arm64/include/asm/kvm_arm.h | 3 --- arch/arm64/include/asm/kvm_emulate.h | 31 +++++++++++++++++++++++++ arch/arm64/kvm/arm.c | 2 +- arch/arm64/kvm/fpsimd.c | 4 ++-- arch/arm64/kvm/hyp/include/hyp/switch.h | 2 +- arch/arm64/kvm/hyp/nvhe/hyp-main.c | 6 ++++- arch/arm64/kvm/hyp/nvhe/pkvm.c | 24 ++++++++++++++----- arch/arm64/kvm/hyp/nvhe/switch.c | 28 ++++++++++++---------- arch/arm64/kvm/hyp/vhe/switch.c | 2 +- 9 files changed, 75 insertions(+), 27 deletions(-)
arch/arm64/include/asm/kvm_arm.h +0 -3
@@ -284,7 +284,6 @@#define CPTR_EL2_TFP (1 << CPTR_EL2_TFP_SHIFT)#define CPTR_EL2_TZ (1 << 8)#define CPTR_NVHE_EL2_RES1 0x000032ff/* known RES1 bits in CPTR_EL2 (nVHE) */ -#define CPTR_EL2_DEFAULT CPTR_NVHE_EL2_RES1#define CPTR_NVHE_EL2_RES0 (GENMASK(63, 32) | \ GENMASK(29, 21) | \ GENMASK(19, 14) | \
@@ -358,7 +357,5 @@ ECN(BKPT32), ECN(VECTOR32), ECN(BRK64)#define CPACR_EL1_TTA (1 << 28) -#define CPACR_EL1_DEFAULT (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN |\ - CPACR_EL1_ZEN_EL1EN)#endif /* __ARM64_KVM_ARM_H__ */
arch/arm64/include/asm/kvm_emulate.h +31 -0
@@ -490,4 +490,35 @@ static inline bool vcpu_has_feature(struct kvm_vcpu *vcpu, int feature)return test_bit (feature, vcpu->arch.features); } +static __always_inline u64 kvm_get_reset_cptr_el2(struct kvm_vcpu *vcpu) +{ +u64 val; + +if (has_vhe ()) { + val = (CPACR_EL1_FPEN_EL0EN |CPACR_EL1_FPEN_EL1EN | +CPACR_EL1_ZEN_EL1EN ); + }else if (has_hvhe ()) { + val = (CPACR_EL1_FPEN_EL0EN |CPACR_EL1_FPEN_EL1EN ); + }else { + val =CPTR_NVHE_EL2_RES1 ; + +if (vcpu_has_sve (vcpu) && + (vcpu->arch.fp_state ==FP_STATE_GUEST_OWNED )) + val |=CPTR_EL2_TZ ; +if (cpus_have_final_cap (ARM64_SME )) + val &= ~CPTR_EL2_TSM ; + } + +return val; +} + +static __always_inline void kvm_reset_cptr_el2(struct kvm_vcpu *vcpu) +{ +u64 val =kvm_get_reset_cptr_el2 (vcpu); + +if (has_vhe () ||has_hvhe ()) +write_sysreg (val, cpacr_el1); +else +write_sysreg (val, cptr_el2); +}#endif /* __ARM64_KVM_EMULATE_H__ */
arch/arm64/kvm/arm.c +1 -1
@@ -1194,7 +1194,7 @@ static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu, }vcpu_reset_hcr (vcpu); - vcpu->arch.cptr_el2 =CPTR_EL2_DEFAULT ; + vcpu->arch.cptr_el2 =kvm_get_reset_cptr_el2 (vcpu);/* * Handle the "start in power-off" case.
arch/arm64/kvm/fpsimd.c +2 -2
@@ -160,7 +160,7 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)/* * If we have VHE then the Hyp code will reset CPACR_EL1 to -* CPACR_EL1_DEFAULT and we need to reenable SME. +* the default value and we need to reenable SME. */ if (has_vhe () &&system_supports_sme ()) {/* Also restore EL0 state seen on entry */
@@ -189,7 +189,7 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)/* * The FPSIMD/SVE state in the CPU has not been touched, and we * have SVE (and VHE): CPACR_EL1 (alias CPTR_EL2) has been -* reset to CPACR_EL1_DEFAULT by the Hyp code, disabling SVE +* reset by kvm_reset_cptr_el2() in the Hyp code, disabling SVE * for EL0. To avoid spurious traps, restore the trap state * seen by kvm_arch_vcpu_load_fp(): */
arch/arm64/kvm/hyp/include/hyp/switch.h +1 -1
@@ -163,7 +163,7 @@ static bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)/* Valid trap. Switch the context: */ /* First disable enough traps to allow us to update the registers */ -if (has_vhe ()) { +if (has_vhe () ||has_hvhe ()) { reg =CPACR_EL1_FPEN_EL0EN |CPACR_EL1_FPEN_EL1EN ;if (sve_guest) reg |=CPACR_EL1_ZEN_EL0EN |CPACR_EL1_ZEN_EL1EN ;
arch/arm64/kvm/hyp/nvhe/hyp-main.c +5 -1
@@ -286,7 +286,11 @@ void handle_trap(struct kvm_cpu_context *host_ctxt)handle_host_smc (host_ctxt);break ;case ESR_ELx_EC_SVE: -sysreg_clear_set (cptr_el2,CPTR_EL2_TZ ,0 ); +if (has_hvhe ()) +sysreg_clear_set (cpacr_el1,0 , (CPACR_EL1_ZEN_EL1EN | +CPACR_EL1_ZEN_EL0EN )); +else +sysreg_clear_set (cptr_el2,CPTR_EL2_TZ ,0 );isb ();sve_cond_update_zcr_vq (ZCR_ELx_LEN_MASK,SYS_ZCR_EL2 );break ;
arch/arm64/kvm/hyp/nvhe/pkvm.c +18 -6
@@ -18,6 +18,7 @@ static void pvm_init_traps_aa64pfr0(struct kvm_vcpu *vcpu)u64 hcr_set =HCR_RW ;u64 hcr_clear =0 ;u64 cptr_set =0 ; +u64 cptr_clear =0 ;/* Protected KVM does not support AArch32 guests. */ BUILD_BUG_ON(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL0),
@@ -48,12 +49,17 @@ static void pvm_init_traps_aa64pfr0(struct kvm_vcpu *vcpu) }/* Trap SVE */ -if (!FIELD_GET (ARM64_FEATURE_MASK (ID_AA64PFR0_EL1_SVE ), feature_ids)) - cptr_set |=CPTR_EL2_TZ ; +if (!FIELD_GET (ARM64_FEATURE_MASK (ID_AA64PFR0_EL1_SVE ), feature_ids)) { +if (has_hvhe ()) + cptr_clear |=CPACR_EL1_ZEN_EL0EN |CPACR_EL1_ZEN_EL1EN ; +else + cptr_set |=CPTR_EL2_TZ ; + } vcpu->arch.hcr_el2 |= hcr_set; vcpu->arch.hcr_el2 &= ~hcr_clear; vcpu->arch.cptr_el2 |= cptr_set; + vcpu->arch.cptr_el2 &= ~cptr_clear; }/*
@@ -111,8 +117,12 @@ static void pvm_init_traps_aa64dfr0(struct kvm_vcpu *vcpu) mdcr_set |=MDCR_EL2_TTRF ;/* Trap Trace */ -if (!FIELD_GET (ARM64_FEATURE_MASK (ID_AA64DFR0_EL1_TraceVer), feature_ids)) - cptr_set |=CPTR_EL2_TTA ; +if (!FIELD_GET (ARM64_FEATURE_MASK (ID_AA64DFR0_EL1_TraceVer), feature_ids)) { +if (has_hvhe ()) + cptr_set |=CPACR_EL1_TTA ; +else + cptr_set |=CPTR_EL2_TTA ; + } vcpu->arch.mdcr_el2 |= mdcr_set; vcpu->arch.mdcr_el2 &= ~mdcr_clear;
@@ -167,8 +177,10 @@ static void pvm_init_trap_regs(struct kvm_vcpu *vcpu)/* Clear res0 and set res1 bits to trap potential new features. */ vcpu->arch.hcr_el2 &= ~(HCR_RES0 ); vcpu->arch.mdcr_el2 &= ~(MDCR_EL2_RES0 ); - vcpu->arch.cptr_el2 |=CPTR_NVHE_EL2_RES1 ; - vcpu->arch.cptr_el2 &= ~(CPTR_NVHE_EL2_RES0 ); +if (!has_hvhe ()) { + vcpu->arch.cptr_el2 |=CPTR_NVHE_EL2_RES1 ; + vcpu->arch.cptr_el2 &= ~(CPTR_NVHE_EL2_RES0 ); + } }/*
arch/arm64/kvm/hyp/nvhe/switch.c +16 -12
@@ -44,13 +44,24 @@ static void __activate_traps(struct kvm_vcpu *vcpu)__activate_traps_common (vcpu); val = vcpu->arch.cptr_el2; - val |=CPTR_EL2_TTA |CPTR_EL2_TAM ; + val |=CPTR_EL2_TAM ;/* Same bit irrespective of E2H */ + val |=has_hvhe () ?CPACR_EL1_TTA :CPTR_EL2_TTA ; +if (cpus_have_final_cap (ARM64_SME )) { +if (has_hvhe ()) + val &= ~(CPACR_EL1_SMEN_EL1EN |CPACR_EL1_SMEN_EL0EN ); +else + val |=CPTR_EL2_TSM ; + } +if (!guest_owns_fp_regs (vcpu)) { - val |=CPTR_EL2_TFP |CPTR_EL2_TZ ; +if (has_hvhe ()) + val &= ~(CPACR_EL1_FPEN_EL0EN |CPACR_EL1_FPEN_EL1EN | +CPACR_EL1_ZEN_EL0EN |CPACR_EL1_ZEN_EL1EN ); +else + val |=CPTR_EL2_TFP |CPTR_EL2_TZ ; +__activate_traps_fpsimd32 (vcpu); } -if (cpus_have_final_cap (ARM64_SME )) - val |=CPTR_EL2_TSM ;write_sysreg (val, cptr_el2);write_sysreg (__this_cpu_read (kvm_hyp_vector), vbar_el2);
@@ -85,7 +96,6 @@ static void __activate_traps(struct kvm_vcpu *vcpu)static void __deactivate_traps (struct kvm_vcpu *vcpu) {extern char __kvm_hyp_host_vector[]; -u64 cptr;___deactivate_traps (vcpu);
@@ -124,13 +134,7 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)write_sysreg_s (val,SYS_HFGWTR_EL2 ); } - cptr =CPTR_EL2_DEFAULT ; -if (vcpu_has_sve (vcpu) && (vcpu->arch.fp_state ==FP_STATE_GUEST_OWNED )) - cptr |=CPTR_EL2_TZ ; -if (cpus_have_final_cap (ARM64_SME )) - cptr &= ~CPTR_EL2_TSM ; - -write_sysreg (cptr, cptr_el2); +kvm_reset_cptr_el2 (vcpu);write_sysreg (__kvm_hyp_host_vector, vbar_el2); }
arch/arm64/kvm/hyp/vhe/switch.c +1 -1
@@ -92,7 +92,7 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)write_sysreg (read_sysreg (sctlr_el2) | SCTLR_ELx_ENTP2, sctlr_el2); -write_sysreg (CPACR_EL1_DEFAULT , cpacr_el1); +kvm_reset_cptr_el2 (vcpu);if (!arm64_kernel_unmapped_at_el0 ()) host_vectors =__this_cpu_read (this_cpu_vector);
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 14/17 KVM: arm64: Program the timer traps with VHE layout in hVHE mode
In reply to Marc ZyngierJust like the rest of the timer code, we need to shift the enable bits around when HCR_EL2.E2H is set, which is the case in hVHE mode.
--- arch/arm64/kvm/hyp/nvhe/timer-sr.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
arch/arm64/kvm/hyp/nvhe/timer-sr.c +13 -7
@@ -16,33 +16,39 @@ void __kvm_timer_set_cntvoff(u64 cntvoff) }/* -* Should only be called on non-VHE systems. +* Should only be called on non-VHE or hVHE setups. * VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe(). */ void __timer_disable_traps (struct kvm_vcpu *vcpu) { -u64 val; +u64 val, shift =0 ; + +if (has_hvhe ()) + shift =10 ;/* Allow physical timer/counter access for the host */ val =read_sysreg (cnthctl_el2); - val |=CNTHCTL_EL1PCTEN |CNTHCTL_EL1PCEN ; + val |= (CNTHCTL_EL1PCTEN |CNTHCTL_EL1PCEN ) << shift;write_sysreg (val, cnthctl_el2); }/* -* Should only be called on non-VHE systems. +* Should only be called on non-VHE or hVHE setups. * VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe(). */ void __timer_enable_traps (struct kvm_vcpu *vcpu) { -u64 val; +u64 val, shift =0 ;/* * Disallow physical timer access for the guest * Physical counter access is allowed */ +if (has_hvhe ()) + shift =10 ; + val =read_sysreg (cnthctl_el2); - val &= ~CNTHCTL_EL1PCEN ; - val |=CNTHCTL_EL1PCTEN ; + val &= ~(CNTHCTL_EL1PCEN << shift); + val |=CNTHCTL_EL1PCTEN << shift;write_sysreg (val, cnthctl_el2); }
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 15/17 KVM: arm64: Force HCR_E2H in guest context when ARM64_KVM_HVHE is set
In reply to Marc ZyngierAlso make sure HCR_EL2.E2H is set when switching HCR_EL2 in guest context.
--- arch/arm64/include/asm/kvm_emulate.h | 2 +- arch/arm64/kvm/hyp/nvhe/pkvm.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-)
arch/arm64/include/asm/kvm_emulate.h +1 -1
@@ -64,7 +64,7 @@ static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)static inline void vcpu_reset_hcr (struct kvm_vcpu *vcpu) { vcpu->arch.hcr_el2 =HCR_GUEST_FLAGS ; -if (is_kernel_in_hyp_mode ()) +if (has_vhe () ||has_hvhe ()) vcpu->arch.hcr_el2 |=HCR_E2H ;if (cpus_have_const_cap (ARM64_HAS_RAS_EXTN )) {/* route synchronous external abort exceptions to EL2 */
arch/arm64/kvm/hyp/nvhe/pkvm.c +3 -0
@@ -35,6 +35,9 @@ static void pvm_init_traps_aa64pfr0(struct kvm_vcpu *vcpu)BUILD_BUG_ON (!FIELD_GET (ARM64_FEATURE_MASK (ID_AA64PFR0_EL1_AdvSIMD),PVM_ID_AA64PFR0_ALLOW )); +if (has_hvhe ()) + hcr_set |=HCR_E2H ; +/* Trap RAS unless all current versions are supported */ if (FIELD_GET (ARM64_FEATURE_MASK (ID_AA64PFR0_EL1_RAS ), feature_ids) <ID_AA64PFR0_EL1_RAS_V1P1 ) {
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 16/17 arm64: Allow arm64_sw.hvhe on command line
In reply to Marc ZyngierAdd the arm64_sw.hvhe=1 option to force the use of the hVHE mode in the hypervisor code only.
This enables the hVHE mode of operation when using KVM on VHE hardware.
--- arch/arm64/kernel/idreg-override.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
arch/arm64/kernel/idreg-override.c +11 -0
@@ -137,11 +137,22 @@ static const struct ftr_set_desc smfr0 __initconst = { }, }; +static bool __init hvhe_filter (u64 val) +{ +u64 mmfr1 =read_sysreg (id_aa64mmfr1_el1); + +return (val ==1 && +lower_32_bits (__boot_status) ==BOOT_CPU_MODE_EL2 && +cpuid_feature_extract_unsigned_field (mmfr1, +ID_AA64MMFR1_EL1_VH_SHIFT )); +} +static const struct ftr_set_desc sw_features__initconst = { .name ="arm64_sw" , .override = &arm64_sw_feature_override, .fields = {FIELD ("nokaslr" ,ARM64_SW_FEATURE_OVERRIDE_NOKASLR ,NULL ), +FIELD ("hvhe" ,ARM64_SW_FEATURE_OVERRIDE_HVHE , hvhe_filter), {} }, };
Signature · 1 line
2.34.1
Marc Zyngier
maintainerPATCH 17/17 KVM: arm64: Terrible timer hack for M1 with hVHE
In reply to Marc ZyngierAs our M1 friend doesn't have a GIC, it relies on a special hack to deal with masking the guest timers, in the form of an IMPDEF system register.
Unfortunately, this sysreg is EL2-only, which means that the kernel cannot mask the interrupts itself, but has to kindly ask EL2 to do it. Yes, this is terrible, but we should be used to it by now.
Add a M1-specific hypercall to deal with this. No, I'm not seriously suggesting we merge this crap.
--- arch/arm64/include/asm/arch_timer.h | 8 +++++ arch/arm64/include/asm/kvm_asm.h | 1 + arch/arm64/kernel/image-vars.h | 3 ++ arch/arm64/kvm/arch_timer.c | 5 +++ arch/arm64/kvm/hyp/nvhe/hyp-main.c | 11 +++++++ arch/arm64/kvm/hyp/nvhe/timer-sr.c | 9 ++++++ drivers/irqchip/irq-apple-aic.c | 50 +++++++++++++++++++++++++++-- 7 files changed, 85 insertions(+), 2 deletions(-)
arch/arm64/include/asm/arch_timer.h +8 -0
@@ -232,4 +232,12 @@ static inline bool arch_timer_have_evtstrm_feature(void) {return cpu_have_named_feature (EVTSTRM ); } + +#ifdef CONFIG_APPLE_AIC +#define SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2 sys_reg(3, 5, 15, 1, 3) +DECLARE_STATIC_KEY_FALSE (aic_impdef_timer_control); +#endif + +void __aic_timer_fiq_clear_set (u64 clear,u64 set); +#endif
arch/arm64/include/asm/kvm_asm.h +1 -0
@@ -75,6 +75,7 @@ enum __kvm_host_smccc_func { __KVM_HOST_SMCCC_FUNC___vgic_v3_write_vmcr, __KVM_HOST_SMCCC_FUNC___vgic_v3_save_aprs, __KVM_HOST_SMCCC_FUNC___vgic_v3_restore_aprs, + __KVM_HOST_SMCCC_FUNC___aic_timer_fiq_clear_set, __KVM_HOST_SMCCC_FUNC___pkvm_vcpu_init_traps, };
arch/arm64/kernel/image-vars.h +3 -0
@@ -130,6 +130,9 @@ KVM_NVHE_ALIAS(__hyp_rodata_end);/* pKVM static key */ KVM_NVHE_ALIAS (kvm_protected_mode_initialized); +/* Hack for M1 timer control in hVHE mode */ +KVM_NVHE_ALIAS (aic_impdef_timer_control); +#endif /* CONFIG_KVM */ #endif /* __ARM64_KERNEL_IMAGE_VARS_H */
arch/arm64/kvm/arch_timer.c +5 -0
@@ -998,6 +998,11 @@ static int timer_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)return 0 ; } +void __aic_timer_fiq_clear_set (u64 clear,u64 set) +{ +kvm_call_hyp_nvhe (__aic_timer_fiq_clear_set, clear, set); +} +static int timer_irq_set_irqchip_state (struct irq_data *d,enum irqchip_irq_state which,bool val) {
arch/arm64/kvm/hyp/nvhe/hyp-main.c +11 -0
@@ -116,6 +116,16 @@ static void handle___vgic_v3_restore_aprs(struct kvm_cpu_context *host_ctxt)__vgic_v3_restore_aprs (kern_hyp_va (cpu_if)); } +#define SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2 sys_reg(3, 5, 15, 1, 3) + +static void handle___aic_timer_fiq_clear_set (struct kvm_cpu_context *host_ctxt) +{ +DECLARE_REG (u64, clear, host_ctxt,1 ); +DECLARE_REG (u64, set, host_ctxt,2 ); + +__aic_timer_fiq_clear_set (clear, set); +} +static void handle___pkvm_init (struct kvm_cpu_context *host_ctxt) {DECLARE_REG (phys_addr_t, phys, host_ctxt,1 );
@@ -219,6 +229,7 @@ static const hcall_t host_hcall[] = {HANDLE_FUNC (__vgic_v3_write_vmcr),HANDLE_FUNC (__vgic_v3_save_aprs),HANDLE_FUNC (__vgic_v3_restore_aprs), +HANDLE_FUNC (__aic_timer_fiq_clear_set), HANDLE_FUNC(__pkvm_vcpu_init_traps), };
arch/arm64/kvm/hyp/nvhe/timer-sr.c +9 -0
@@ -52,3 +52,12 @@ void __timer_enable_traps(struct kvm_vcpu *vcpu) val |=CNTHCTL_EL1PCTEN << shift;write_sysreg (val, cnthctl_el2); } + + +void __aic_timer_fiq_clear_set (u64 clear,u64 set) +{ +#ifdef CONFIG_APPLE_AIC +if (has_hvhe () &&static_branch_likely (&aic_impdef_timer_control)) +sysreg_clear_set_s (SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2 , clear, set); +#endif +}
drivers/irqchip/irq-apple-aic.c +48 -2
92 lines not on this page · raw message
Signature · 1 line
2.34.1