* [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor
@ 2022-10-20 9:07 Marc Zyngier
2022-10-20 9:07 ` [PATCH 01/17] arm64: Turn kaslr_feature_override into a generic SW feature override Marc Zyngier
` (16 more replies)
0 siblings, 17 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
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(-)
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 01/17] arm64: Turn kaslr_feature_override into a generic SW feature override
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 02/17] arm64: Add KVM_HVHE capability and has_hvhe() predicate Marc Zyngier
` (15 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
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(-)
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index f73f11b55042..f44a7860636f 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -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);
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 6062454a9067..a3959e9f7d55 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -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;
diff --git a/arch/arm64/kernel/idreg-override.c b/arch/arm64/kernel/idreg-override.c
index 95133765ed29..4e8ef5e05db7 100644
--- a/arch/arm64/kernel/idreg-override.c
+++ b/arch/arm64/kernel/idreg-override.c
@@ -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,
diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c
index 325455d16dbc..7b39283278e5 100644
--- a/arch/arm64/kernel/kaslr.c
+++ b/arch/arm64/kernel/kaslr.c
@@ -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;
}
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 02/17] arm64: Add KVM_HVHE capability and has_hvhe() predicate
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
2022-10-20 9:07 ` [PATCH 01/17] arm64: Turn kaslr_feature_override into a generic SW feature override Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2023-06-01 7:01 ` Oliver Upton
2022-10-20 9:07 ` [PATCH 03/17] arm64: Don't enable VHE for the kernel if OVERRIDE_HVHE is set Marc Zyngier
` (14 subsequent siblings)
16 siblings, 1 reply; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
Expose 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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
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(+)
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index f44a7860636f..2d41015429b3 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -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__
diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
index 4eb601e7de50..b11a1c8c8b36 100644
--- a/arch/arm64/include/asm/virt.h
+++ b/arch/arm64/include/asm/virt.h
@@ -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();
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index a3959e9f7d55..efac89c4c548 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -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,
+ },
{},
};
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index f1c0347ec31a..cee2be85b89b 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -43,6 +43,7 @@ HAS_TLB_RANGE
HAS_VIRT_HOST_EXTN
HAS_WFXT
HW_DBM
+KVM_HVHE
KVM_PROTECTED_MODE
MISMATCHED_CACHE_TYPE
MTE
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 03/17] arm64: Don't enable VHE for the kernel if OVERRIDE_HVHE is set
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
2022-10-20 9:07 ` [PATCH 01/17] arm64: Turn kaslr_feature_override into a generic SW feature override Marc Zyngier
2022-10-20 9:07 ` [PATCH 02/17] arm64: Add KVM_HVHE capability and has_hvhe() predicate Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 04/17] arm64: Prevent the use of is_kernel_in_hyp_mode() in hypervisor code Marc Zyngier
` (13 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
If 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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kernel/hyp-stub.S | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
index 2ee18c860f2a..0601cc9592bd 100644
--- a/arch/arm64/kernel/hyp-stub.S
+++ b/arch/arm64/kernel/hyp-stub.S
@@ -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
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 04/17] arm64: Prevent the use of is_kernel_in_hyp_mode() in hypervisor code
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (2 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 03/17] arm64: Don't enable VHE for the kernel if OVERRIDE_HVHE is set Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 05/17] arm64: Allow EL1 physical timer access when running VHE Marc Zyngier
` (12 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
Using 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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/virt.h | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
index b11a1c8c8b36..5f84a87a6a2d 100644
--- a/arch/arm64/include/asm/virt.h
+++ b/arch/arm64/include/asm/virt.h
@@ -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;
}
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 05/17] arm64: Allow EL1 physical timer access when running VHE
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (3 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 04/17] arm64: Prevent the use of is_kernel_in_hyp_mode() in hypervisor code Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 06/17] arm64: Use CPACR_EL1 format to set CPTR_EL2 when E2H is set Marc Zyngier
` (11 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
To 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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/el2_setup.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
index 668569adf4d3..fa1045f709bb 100644
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@ -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
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 06/17] arm64: Use CPACR_EL1 format to set CPTR_EL2 when E2H is set
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (4 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 05/17] arm64: Allow EL1 physical timer access when running VHE Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 07/17] KVM: arm64: Elide kern_hyp_va() in VHE-specific parts of the hypervisor Marc Zyngier
` (10 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
When 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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/el2_setup.h | 11 +++++++++--
arch/arm64/kernel/hyp-stub.S | 11 +++++++++++
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
index fa1045f709bb..605ff1a482db 100644
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@ -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
diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
index 0601cc9592bd..7d2f24ae8c98 100644
--- a/arch/arm64/kernel/hyp-stub.S
+++ b/arch/arm64/kernel/hyp-stub.S
@@ -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
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 07/17] KVM: arm64: Elide kern_hyp_va() in VHE-specific parts of the hypervisor
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (5 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 06/17] arm64: Use CPACR_EL1 format to set CPTR_EL2 when E2H is set Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 08/17] KVM: arm64: Remove alternatives from sysreg accessors in VHE hypervisor context Marc Zyngier
` (9 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
For 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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/kvm_mmu.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 7784081088e7..e32725e90360 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -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;
}
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 08/17] KVM: arm64: Remove alternatives from sysreg accessors in VHE hypervisor context
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (6 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 07/17] KVM: arm64: Elide kern_hyp_va() in VHE-specific parts of the hypervisor Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 09/17] KVM: arm64: Key use of VHE instructions in nVHE code off ARM64_KVM_HVHE Marc Zyngier
` (8 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
In the VHE hypervisor code, we should be using the remapped VHE
accessors, no ifs, no buts. No need to generate any alternative.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/kvm_hyp.h | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index aa7fa2a08f06..461fc0dc4a70 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -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
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 09/17] KVM: arm64: Key use of VHE instructions in nVHE code off ARM64_KVM_HVHE
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (7 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 08/17] KVM: arm64: Remove alternatives from sysreg accessors in VHE hypervisor context Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 10/17] KVM: arm64: Force HCR_EL2.E2H when ARM64_KVM_HVHE is set Marc Zyngier
` (7 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
We 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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/kvm_hyp.h | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 461fc0dc4a70..e45215a62b43 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -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)
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 10/17] KVM: arm64: Force HCR_EL2.E2H when ARM64_KVM_HVHE is set
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (8 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 09/17] KVM: arm64: Key use of VHE instructions in nVHE code off ARM64_KVM_HVHE Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 11/17] KVM: arm64: Disable TTBR1_EL2 when using ARM64_KVM_HVHE Marc Zyngier
` (6 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
Obviously, 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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/arm.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 94d33e296e10..85df7ce0b051 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -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;
/*
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 11/17] KVM: arm64: Disable TTBR1_EL2 when using ARM64_KVM_HVHE
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (9 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 10/17] KVM: arm64: Force HCR_EL2.E2H when ARM64_KVM_HVHE is set Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 12/17] KVM: arm64: Adjust EL2 stage-1 leaf AP bits when ARM64_KVM_HVHE is set Marc Zyngier
` (5 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
When 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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/arm.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 85df7ce0b051..cf0f15f4d69a 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -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;
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 12/17] KVM: arm64: Adjust EL2 stage-1 leaf AP bits when ARM64_KVM_HVHE is set
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (10 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 11/17] KVM: arm64: Disable TTBR1_EL2 when using ARM64_KVM_HVHE Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 13/17] KVM: arm64: Rework CPTR_EL2 programming for HVHE configuration Marc Zyngier
` (4 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
El2 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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/hyp/pgtable.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index cdf8e76b0be1..50caaf735f52 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -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)
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 13/17] KVM: arm64: Rework CPTR_EL2 programming for HVHE configuration
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (11 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 12/17] KVM: arm64: Adjust EL2 stage-1 leaf AP bits when ARM64_KVM_HVHE is set Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 14/17] KVM: arm64: Program the timer traps with VHE layout in hVHE mode Marc Zyngier
` (3 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
Just 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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
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(-)
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 8aa8492dafc0..e187f84cef2c 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -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__ */
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 9bdba47f7e14..82a9af885f2e 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -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__ */
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index cf0f15f4d69a..b6c9bfa8492f 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -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.
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index ec8e4494873d..15bbde102d06 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -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():
*/
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 6cbbb6c02f66..9dc7197dca4f 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -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;
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 3cea4b6ac23e..14695e29a2be 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -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;
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 85d3b7ae720f..d58314461595 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -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);
+ }
}
/*
diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index 8e9d49a964be..d0b27c33af56 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -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);
}
diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
index 7acb87eaa092..7e7f7112e174 100644
--- a/arch/arm64/kvm/hyp/vhe/switch.c
+++ b/arch/arm64/kvm/hyp/vhe/switch.c
@@ -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);
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 14/17] KVM: arm64: Program the timer traps with VHE layout in hVHE mode
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (12 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 13/17] KVM: arm64: Rework CPTR_EL2 programming for HVHE configuration Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 15/17] KVM: arm64: Force HCR_E2H in guest context when ARM64_KVM_HVHE is set Marc Zyngier
` (2 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
Just 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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/timer-sr.c b/arch/arm64/kvm/hyp/nvhe/timer-sr.c
index 9072e71693ba..143cdc1d107f 100644
--- a/arch/arm64/kvm/hyp/nvhe/timer-sr.c
+++ b/arch/arm64/kvm/hyp/nvhe/timer-sr.c
@@ -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);
}
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 15/17] KVM: arm64: Force HCR_E2H in guest context when ARM64_KVM_HVHE is set
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (13 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 14/17] KVM: arm64: Program the timer traps with VHE layout in hVHE mode Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 16/17] arm64: Allow arm64_sw.hvhe on command line Marc Zyngier
2022-10-20 9:07 ` [PATCH 17/17] KVM: arm64: Terrible timer hack for M1 with hVHE Marc Zyngier
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
Also make sure HCR_EL2.E2H is set when switching HCR_EL2 in guest
context.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/kvm_emulate.h | 2 +-
arch/arm64/kvm/hyp/nvhe/pkvm.c | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 82a9af885f2e..9fd952361d2e 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -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 */
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index d58314461595..2864037eaf8b 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -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) {
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 16/17] arm64: Allow arm64_sw.hvhe on command line
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (14 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 15/17] KVM: arm64: Force HCR_E2H in guest context when ARM64_KVM_HVHE is set Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
2022-10-20 9:07 ` [PATCH 17/17] KVM: arm64: Terrible timer hack for M1 with hVHE Marc Zyngier
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
Add 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.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kernel/idreg-override.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm64/kernel/idreg-override.c b/arch/arm64/kernel/idreg-override.c
index 4e8ef5e05db7..7f3d7835ceaa 100644
--- a/arch/arm64/kernel/idreg-override.c
+++ b/arch/arm64/kernel/idreg-override.c
@@ -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),
{}
},
};
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 17/17] KVM: arm64: Terrible timer hack for M1 with hVHE
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
` (15 preceding siblings ...)
2022-10-20 9:07 ` [PATCH 16/17] arm64: Allow arm64_sw.hvhe on command line Marc Zyngier
@ 2022-10-20 9:07 ` Marc Zyngier
16 siblings, 0 replies; 19+ messages in thread
From: Marc Zyngier @ 2022-10-20 9:07 UTC (permalink / raw)
To: kvmarm, kvmarm, kvm, linux-arm-kernel
Cc: James Morse, Suzuki K Poulose, Alexandru Elisei, Oliver Upton,
Quentin Perret, Will Deacon, Fuad Tabba
As 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.
Not-seriously-suggested-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
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(-)
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
index af1fafbe7e1d..3817e923f52c 100644
--- a/arch/arm64/include/asm/arch_timer.h
+++ b/arch/arm64/include/asm/arch_timer.h
@@ -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
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 53035763e48e..d8855749920a 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -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,
};
diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
index 8151412653de..11a2c0cd12cf 100644
--- a/arch/arm64/kernel/image-vars.h
+++ b/arch/arm64/kernel/image-vars.h
@@ -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 */
diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index bb24a76b4224..b22a08597f2e 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -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)
{
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 14695e29a2be..8149635e5bc9 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -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),
};
diff --git a/arch/arm64/kvm/hyp/nvhe/timer-sr.c b/arch/arm64/kvm/hyp/nvhe/timer-sr.c
index 143cdc1d107f..a0266391e1b3 100644
--- a/arch/arm64/kvm/hyp/nvhe/timer-sr.c
+++ b/arch/arm64/kvm/hyp/nvhe/timer-sr.c
@@ -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
+}
diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c
index 1c2813ad8bbe..4e0442bedb2e 100644
--- a/drivers/irqchip/irq-apple-aic.c
+++ b/drivers/irqchip/irq-apple-aic.c
@@ -180,7 +180,6 @@
#define IPI_SR_PENDING BIT(0)
/* Guest timer FIQ enable register */
-#define SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2 sys_reg(3, 5, 15, 1, 3)
#define VM_TMR_FIQ_ENABLE_V BIT(0)
#define VM_TMR_FIQ_ENABLE_P BIT(1)
@@ -230,6 +229,8 @@
static DEFINE_STATIC_KEY_TRUE(use_fast_ipi);
+DEFINE_STATIC_KEY_FALSE(aic_impdef_timer_control);
+
struct aic_info {
int version;
@@ -450,6 +451,40 @@ static unsigned long aic_fiq_get_idx(struct irq_data *d)
return AIC_HWIRQ_IRQ(irqd_to_hwirq(d));
}
+void __weak __aic_timer_fiq_clear_set(u64 clear, u64 set) { }
+
+static bool aic_check_timer_enabled(int timer)
+{
+ if (IS_ENABLED(CONFIG_KVM) &&
+ static_branch_unlikely(&aic_impdef_timer_control))
+ return __this_cpu_read(aic_fiq_unmasked) & BIT(timer);
+ return true;
+}
+
+static void aic_hvhe_timer_mask(int timer, bool mask)
+{
+ u64 clr, set, bit;
+
+ if (!(IS_ENABLED(CONFIG_KVM) &&
+ static_branch_unlikely(&aic_impdef_timer_control)))
+ return;
+
+ if (timer == AIC_TMR_EL0_VIRT)
+ bit = VM_TMR_FIQ_ENABLE_V;
+ else
+ bit = VM_TMR_FIQ_ENABLE_P;
+
+ if (mask) {
+ clr = bit;
+ set = 0;
+ } else {
+ clr = 0;
+ set = bit;
+ }
+
+ __aic_timer_fiq_clear_set(clr, set);
+}
+
static void aic_fiq_set_mask(struct irq_data *d)
{
/* Only the guest timers have real mask bits, unfortunately. */
@@ -462,6 +497,9 @@ static void aic_fiq_set_mask(struct irq_data *d)
sysreg_clear_set_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2, VM_TMR_FIQ_ENABLE_V, 0);
isb();
break;
+ case AIC_TMR_EL0_VIRT:
+ aic_hvhe_timer_mask(AIC_TMR_EL0_VIRT, true);
+ break;
default:
break;
}
@@ -478,6 +516,9 @@ static void aic_fiq_clear_mask(struct irq_data *d)
sysreg_clear_set_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2, 0, VM_TMR_FIQ_ENABLE_V);
isb();
break;
+ case AIC_TMR_EL0_VIRT:
+ aic_hvhe_timer_mask(AIC_TMR_EL0_VIRT, false);
+ break;
default:
break;
}
@@ -537,7 +578,8 @@ static void __exception_irq_entry aic_handle_fiq(struct pt_regs *regs)
generic_handle_domain_irq(aic_irqc->hw_domain,
AIC_FIQ_HWIRQ(AIC_TMR_EL0_PHYS));
- if (TIMER_FIRING(read_sysreg(cntv_ctl_el0)))
+ if (TIMER_FIRING(read_sysreg(cntv_ctl_el0)) &&
+ aic_check_timer_enabled(AIC_TMR_EL0_VIRT))
generic_handle_domain_irq(aic_irqc->hw_domain,
AIC_FIQ_HWIRQ(AIC_TMR_EL0_VIRT));
@@ -1174,6 +1216,10 @@ static int __init aic_of_ic_init(struct device_node *node, struct device_node *p
if (static_branch_likely(&use_fast_ipi))
pr_info("Using Fast IPIs");
+ /* Caps are not final at this stage :-/ */
+ if (cpus_have_cap(ARM64_KVM_HVHE))
+ static_branch_enable(&aic_impdef_timer_control);
+
cpuhp_setup_state(CPUHP_AP_IRQ_APPLE_AIC_STARTING,
"irqchip/apple-aic/ipi:starting",
aic_init_cpu, NULL);
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH 02/17] arm64: Add KVM_HVHE capability and has_hvhe() predicate
2022-10-20 9:07 ` [PATCH 02/17] arm64: Add KVM_HVHE capability and has_hvhe() predicate Marc Zyngier
@ 2023-06-01 7:01 ` Oliver Upton
0 siblings, 0 replies; 19+ messages in thread
From: Oliver Upton @ 2023-06-01 7:01 UTC (permalink / raw)
To: Marc Zyngier
Cc: kvmarm, kvmarm, kvm, linux-arm-kernel, James Morse,
Suzuki K Poulose, Alexandru Elisei, Quentin Perret, Will Deacon,
Fuad Tabba
On Thu, Oct 20, 2022 at 10:07:12AM +0100, Marc Zyngier wrote:
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index a3959e9f7d55..efac89c4c548 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -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);
> +}
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.
> +
> #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,
> + },
> {},
> };
>
> diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
> index f1c0347ec31a..cee2be85b89b 100644
> --- a/arch/arm64/tools/cpucaps
> +++ b/arch/arm64/tools/cpucaps
> @@ -43,6 +43,7 @@ HAS_TLB_RANGE
> HAS_VIRT_HOST_EXTN
> HAS_WFXT
> HW_DBM
> +KVM_HVHE
> KVM_PROTECTED_MODE
> MISMATCHED_CACHE_TYPE
> MTE
> --
> 2.34.1
>
--
Thanks,
Oliver
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2023-06-01 7:02 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-10-20 9:07 [PATCH 00/17] KVM: arm64: Allow using VHE in the nVHE hypervisor Marc Zyngier
2022-10-20 9:07 ` [PATCH 01/17] arm64: Turn kaslr_feature_override into a generic SW feature override Marc Zyngier
2022-10-20 9:07 ` [PATCH 02/17] arm64: Add KVM_HVHE capability and has_hvhe() predicate Marc Zyngier
2023-06-01 7:01 ` Oliver Upton
2022-10-20 9:07 ` [PATCH 03/17] arm64: Don't enable VHE for the kernel if OVERRIDE_HVHE is set Marc Zyngier
2022-10-20 9:07 ` [PATCH 04/17] arm64: Prevent the use of is_kernel_in_hyp_mode() in hypervisor code Marc Zyngier
2022-10-20 9:07 ` [PATCH 05/17] arm64: Allow EL1 physical timer access when running VHE Marc Zyngier
2022-10-20 9:07 ` [PATCH 06/17] arm64: Use CPACR_EL1 format to set CPTR_EL2 when E2H is set Marc Zyngier
2022-10-20 9:07 ` [PATCH 07/17] KVM: arm64: Elide kern_hyp_va() in VHE-specific parts of the hypervisor Marc Zyngier
2022-10-20 9:07 ` [PATCH 08/17] KVM: arm64: Remove alternatives from sysreg accessors in VHE hypervisor context Marc Zyngier
2022-10-20 9:07 ` [PATCH 09/17] KVM: arm64: Key use of VHE instructions in nVHE code off ARM64_KVM_HVHE Marc Zyngier
2022-10-20 9:07 ` [PATCH 10/17] KVM: arm64: Force HCR_EL2.E2H when ARM64_KVM_HVHE is set Marc Zyngier
2022-10-20 9:07 ` [PATCH 11/17] KVM: arm64: Disable TTBR1_EL2 when using ARM64_KVM_HVHE Marc Zyngier
2022-10-20 9:07 ` [PATCH 12/17] KVM: arm64: Adjust EL2 stage-1 leaf AP bits when ARM64_KVM_HVHE is set Marc Zyngier
2022-10-20 9:07 ` [PATCH 13/17] KVM: arm64: Rework CPTR_EL2 programming for HVHE configuration Marc Zyngier
2022-10-20 9:07 ` [PATCH 14/17] KVM: arm64: Program the timer traps with VHE layout in hVHE mode Marc Zyngier
2022-10-20 9:07 ` [PATCH 15/17] KVM: arm64: Force HCR_E2H in guest context when ARM64_KVM_HVHE is set Marc Zyngier
2022-10-20 9:07 ` [PATCH 16/17] arm64: Allow arm64_sw.hvhe on command line Marc Zyngier
2022-10-20 9:07 ` [PATCH 17/17] KVM: arm64: Terrible timer hack for M1 with hVHE Marc Zyngier
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).