* [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling
@ 2026-05-29 15:55 Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 01/26] KVM: arm64: Extract some feature related changes to kvm_feature.h Steffen Eiden
` (25 more replies)
0 siblings, 26 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Add system register handling for KVM/arm64 on s390. Restructure and share
KVM/arm64 code, introduce ARM guest management functions for s390 hosts,
and implement host sysreg & exception handling.
Changes in detail:
arm64:
Refactor arm64 feature detection and ID register handling to make it
generic and reusable across architectures.
Restructure ID register storage and core register handling. Refactor core
registers to use functions instead of direct memory access.
Move arm64-specific definitions (CPU types, cache, KVM features, ID
registers, system registers) to shared locations for reuse by other
architectures.
s390:
Add s390 instruction support for ARM guest management: easr/sasr for
system register access, QAAF for feature queries, and ptff extensions
for guest time handling.
Implement complete sysreg handling for s390 including feature
sanitisation, register enumeration and access, exception injection,
and finalized page fault handling.
The series builds upon the foundation established in the first series and
requires the first series v3[1] as base.
Steffen
[1] https://lore.kernel.org/lkml/20260529155050.2902245-1-seiden@linux.ibm.com/
Andreas Grapentin (1):
KVM: arm64: Fix set_oslsr_el1 to write to OSLAR_EL1
Steffen Eiden (25):
KVM: arm64: Extract some feature related changes to kvm_feature.h
KVM: arm64: Remove __expand_field_sign_(un)signed
KVM: arm64: Generalize get_idreg_field_*()
KVM: arm64: Generalize kvm_cmp_feat_*()
KVM: arm64: Generalize kvm_has_feat_*
KVM: arm64: Remove get_idreg_field_*() and kvm_cmp_feat_*()
KVM: arm64: Remove kvm_has_feat_range
KVM: arm64: Split up feature sysreg sanitisation
KVM: arm64: Refactor idreg caching into dedicated structure
KVM: arm64: Move definitions from sys_regs.c to sys_regs.h
KVM: arm64: Add PVM_ prefix to avoid name collisions
s390: Introduce read/write ARM sysreg instructions
s390: Introduce Query Available Arm features
s390: Add functions to query arm guest time
KVM: s390: arm64: Add sysreg related functions and definitions
arm64: Extract cputype definitions.
arm64: Extract cache definitions
KVM: arm64: Share KVM feature detection macros
KVM: arm64: Share ID reg handling
KVM: arm64: Share sys-reg handling
KVM: arm64: Refactor core reg handling
KVM: s390: arm64: Implement feature sanitisation
KVM: s390: arm64: Implement sysreg handling
KVM: s390: arm64: Implement exception injection
KVM: s390: arm64: Finalize page fault handling
arch/arm64/include/asm/cache.h | 19 +-
arch/arm64/include/asm/cputype.h | 246 +---
arch/arm64/include/asm/kvm_emulate.h | 1 +
arch/arm64/include/asm/kvm_feature.h | 27 +
arch/arm64/include/asm/kvm_host.h | 137 +-
arch/arm64/include/asm/kvm_nested.h | 1 +
arch/arm64/kvm/arm.c | 2 +-
arch/arm64/kvm/at.c | 1 +
arch/arm64/kvm/config.c | 3 +-
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 1 +
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 1 +
arch/arm64/kvm/hyp/nvhe/pkvm.c | 7 +-
arch/arm64/kvm/hyp/nvhe/sys_regs.c | 55 +-
arch/arm64/kvm/nested.c | 2 +-
arch/arm64/kvm/sys_regs.c | 1307 +----------------
arch/arm64/kvm/sys_regs.h | 276 ----
arch/arm64/kvm/trace_handle_exit.h | 36 +-
arch/arm64/kvm/vgic-sys-reg-v3.c | 2 +-
arch/arm64/kvm/vgic/vgic-init.c | 1 +
arch/arm64/kvm/vgic/vgic.h | 1 +
arch/s390/include/asm/kvm_emulate.h | 34 +
arch/s390/include/asm/kvm_feature.h | 111 ++
arch/s390/include/asm/kvm_host_arm64.h | 168 ++-
arch/s390/include/asm/kvm_host_arm64_types.h | 97 ++
arch/s390/include/asm/kvm_nested.h | 5 +
arch/s390/include/asm/sae-asm.h | 48 +
arch/s390/include/asm/sae.h | 86 ++
arch/s390/include/asm/timex.h | 49 +
arch/s390/kernel/dis.c | 1 +
arch/s390/kernel/time.c | 1 +
arch/s390/kvm/arm64/Makefile | 3 +
arch/s390/kvm/arm64/arm.c | 44 +-
arch/s390/kvm/arm64/exception.c | 105 ++
arch/s390/kvm/arm64/feature.c | 170 +++
arch/s390/kvm/arm64/guest.c | 20 +-
arch/s390/kvm/arm64/handle_exit.c | 1 +
arch/s390/kvm/arm64/inject_fault.c | 72 +-
arch/s390/kvm/arm64/mmu.c | 62 +-
arch/s390/kvm/arm64/reset.c | 5 +
arch/s390/kvm/arm64/sys_regs.c | 769 ++++++++++
arch/s390/kvm/arm64/trace.h | 33 +
arch/s390/tools/opcodes.txt | 3 +
include/arch/arm64/asm/cache-defs.h | 22 +
.../arch/arm64/asm/cputype-defs.h | 92 +-
include/arch/arm64/asm/sysreg-defs.h | 9 +
include/kvm/arm64/kvm_feature.h | 68 +
include/kvm/arm64/kvm_host.h | 52 +
include/kvm/arm64/sys_regs.h | 548 +++++++
virt/kvm/arm64/Makefile.kvm | 1 +
virt/kvm/arm64/guest.c | 100 +-
virt/kvm/arm64/mmio.c | 1 +
virt/kvm/arm64/sys_regs.c | 1039 +++++++++++++
virt/kvm/arm64/trace.h | 34 +
53 files changed, 3838 insertions(+), 2141 deletions(-)
create mode 100644 arch/arm64/include/asm/kvm_feature.h
delete mode 100644 arch/arm64/kvm/sys_regs.h
create mode 100644 arch/s390/include/asm/kvm_feature.h
create mode 100644 arch/s390/include/asm/sae-asm.h
create mode 100644 arch/s390/kvm/arm64/exception.c
create mode 100644 arch/s390/kvm/arm64/feature.c
create mode 100644 arch/s390/kvm/arm64/sys_regs.c
create mode 100644 arch/s390/kvm/arm64/trace.h
create mode 100644 include/arch/arm64/asm/cache-defs.h
copy arch/arm64/include/asm/cputype.h => include/arch/arm64/asm/cputype-defs.h (85%)
create mode 100644 include/kvm/arm64/kvm_feature.h
create mode 100644 include/kvm/arm64/sys_regs.h
create mode 100644 virt/kvm/arm64/sys_regs.c
base-commit: 4095afb932d1a98a6fcb3f4f490964949d0de338
--
2.53.0
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v1 01/26] KVM: arm64: Extract some feature related changes to kvm_feature.h
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 02/26] KVM: arm64: Remove __expand_field_sign_(un)signed Steffen Eiden
` (24 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Move definitions related to kvm feature handling to a separate header.
Add flexibility through separation of concerns and allow sharing those
definitions in the future.
Co-developed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/kvm_emulate.h | 1 +
arch/arm64/include/asm/kvm_feature.h | 93 ++++++++++++++++++++++
arch/arm64/include/asm/kvm_host.h | 84 -------------------
arch/arm64/include/asm/kvm_nested.h | 1 +
arch/arm64/kvm/at.c | 1 +
arch/arm64/kvm/config.c | 1 +
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 1 +
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 1 +
arch/arm64/kvm/hyp/nvhe/sys_regs.c | 1 +
arch/arm64/kvm/vgic/vgic.h | 1 +
10 files changed, 101 insertions(+), 84 deletions(-)
create mode 100644 arch/arm64/include/asm/kvm_feature.h
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 41eac2b5de14..2cb8511baddc 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -16,6 +16,7 @@
#include <asm/debug-monitors.h>
#include <asm/esr.h>
+#include <asm/kvm_feature.h>
#include <asm/kvm_hyp.h>
#include <asm/kvm_nested.h>
#include <asm/ptrace.h>
diff --git a/arch/arm64/include/asm/kvm_feature.h b/arch/arm64/include/asm/kvm_feature.h
new file mode 100644
index 000000000000..8d0c65246aa0
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_feature.h
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ARM64_KVM_FEATURE_H__
+#define __ARM64_KVM_FEATURE_H__
+
+#include <linux/types.h>
+#include <linux/bitfield.h>
+#include <asm/sysreg-defs.h>
+
+#define __expand_field_sign_unsigned(id, fld, val) \
+ ((u64)SYS_FIELD_VALUE(id, fld, val))
+
+#define __expand_field_sign_signed(id, fld, val) \
+ ({ \
+ u64 __val = SYS_FIELD_VALUE(id, fld, val); \
+ sign_extend64(__val, id##_##fld##_WIDTH - 1); \
+ })
+
+#define get_idreg_field_unsigned(kvm, id, fld) \
+ ({ \
+ u64 __val = kvm_read_vm_id_reg((kvm), SYS_##id); \
+ FIELD_GET(id##_##fld##_MASK, __val); \
+ })
+
+#define get_idreg_field_signed(kvm, id, fld) \
+ ({ \
+ u64 __val = get_idreg_field_unsigned(kvm, id, fld); \
+ sign_extend64(__val, id##_##fld##_WIDTH - 1); \
+ })
+
+#define get_idreg_field_enum(kvm, id, fld) \
+ get_idreg_field_unsigned(kvm, id, fld)
+
+#define kvm_cmp_feat_signed(kvm, id, fld, op, limit) \
+ (get_idreg_field_signed((kvm), id, fld) op __expand_field_sign_signed(id, fld, limit))
+
+#define kvm_cmp_feat_unsigned(kvm, id, fld, op, limit) \
+ (get_idreg_field_unsigned((kvm), id, fld) op __expand_field_sign_unsigned(id, fld, limit))
+
+#define kvm_cmp_feat(kvm, id, fld, op, limit) \
+ (id##_##fld##_SIGNED ? \
+ kvm_cmp_feat_signed(kvm, id, fld, op, limit) : \
+ kvm_cmp_feat_unsigned(kvm, id, fld, op, limit))
+
+#define __kvm_has_feat(kvm, id, fld, limit) \
+ kvm_cmp_feat(kvm, id, fld, >=, limit)
+
+#define kvm_has_feat(kvm, ...) __kvm_has_feat(kvm, __VA_ARGS__)
+
+#define __kvm_has_feat_enum(kvm, id, fld, val) \
+ kvm_cmp_feat_unsigned(kvm, id, fld, ==, val)
+
+#define kvm_has_feat_enum(kvm, ...) __kvm_has_feat_enum(kvm, __VA_ARGS__)
+
+#define kvm_has_feat_range(kvm, id, fld, min, max) \
+ (kvm_cmp_feat(kvm, id, fld, >=, min) && \
+ kvm_cmp_feat(kvm, id, fld, <=, max))
+
+/* Check for a given level of PAuth support */
+#define kvm_has_pauth(k, l) \
+ ({ \
+ bool pa, pi, pa3; \
+ \
+ pa = kvm_has_feat((k), ID_AA64ISAR1_EL1, APA, l); \
+ pa &= kvm_has_feat((k), ID_AA64ISAR1_EL1, GPA, IMP); \
+ pi = kvm_has_feat((k), ID_AA64ISAR1_EL1, API, l); \
+ pi &= kvm_has_feat((k), ID_AA64ISAR1_EL1, GPI, IMP); \
+ pa3 = kvm_has_feat((k), ID_AA64ISAR2_EL1, APA3, l); \
+ pa3 &= kvm_has_feat((k), ID_AA64ISAR2_EL1, GPA3, IMP); \
+ \
+ (pa + pi + pa3) == 1; \
+ })
+
+#define kvm_has_fpmr(k) \
+ (system_supports_fpmr() && \
+ kvm_has_feat((k), ID_AA64PFR2_EL1, FPMR, IMP))
+
+#define kvm_has_tcr2(k) \
+ (kvm_has_feat((k), ID_AA64MMFR3_EL1, TCRX, IMP))
+
+#define kvm_has_s1pie(k) \
+ (kvm_has_feat((k), ID_AA64MMFR3_EL1, S1PIE, IMP))
+
+#define kvm_has_s1poe(k) \
+ (system_supports_poe() && \
+ kvm_has_feat((k), ID_AA64MMFR3_EL1, S1POE, IMP))
+
+#define kvm_has_ras(k) \
+ (kvm_has_feat((k), ID_AA64PFR0_EL1, RAS, IMP))
+
+#define kvm_has_sctlr2(k) \
+ (kvm_has_feat((k), ID_AA64MMFR3_EL1, SCTLRX, IMP))
+
+#endif /* __ARM64_KVM_FEATURE_H__*/
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 2db51746b4d8..4c2c62b8b506 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1423,90 +1423,6 @@ static inline u64 *__vm_id_reg(struct kvm_arch *ka, u32 reg)
void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);
-#define __expand_field_sign_unsigned(id, fld, val) \
- ((u64)SYS_FIELD_VALUE(id, fld, val))
-
-#define __expand_field_sign_signed(id, fld, val) \
- ({ \
- u64 __val = SYS_FIELD_VALUE(id, fld, val); \
- sign_extend64(__val, id##_##fld##_WIDTH - 1); \
- })
-
-#define get_idreg_field_unsigned(kvm, id, fld) \
- ({ \
- u64 __val = kvm_read_vm_id_reg((kvm), SYS_##id); \
- FIELD_GET(id##_##fld##_MASK, __val); \
- })
-
-#define get_idreg_field_signed(kvm, id, fld) \
- ({ \
- u64 __val = get_idreg_field_unsigned(kvm, id, fld); \
- sign_extend64(__val, id##_##fld##_WIDTH - 1); \
- })
-
-#define get_idreg_field_enum(kvm, id, fld) \
- get_idreg_field_unsigned(kvm, id, fld)
-
-#define kvm_cmp_feat_signed(kvm, id, fld, op, limit) \
- (get_idreg_field_signed((kvm), id, fld) op __expand_field_sign_signed(id, fld, limit))
-
-#define kvm_cmp_feat_unsigned(kvm, id, fld, op, limit) \
- (get_idreg_field_unsigned((kvm), id, fld) op __expand_field_sign_unsigned(id, fld, limit))
-
-#define kvm_cmp_feat(kvm, id, fld, op, limit) \
- (id##_##fld##_SIGNED ? \
- kvm_cmp_feat_signed(kvm, id, fld, op, limit) : \
- kvm_cmp_feat_unsigned(kvm, id, fld, op, limit))
-
-#define __kvm_has_feat(kvm, id, fld, limit) \
- kvm_cmp_feat(kvm, id, fld, >=, limit)
-
-#define kvm_has_feat(kvm, ...) __kvm_has_feat(kvm, __VA_ARGS__)
-
-#define __kvm_has_feat_enum(kvm, id, fld, val) \
- kvm_cmp_feat_unsigned(kvm, id, fld, ==, val)
-
-#define kvm_has_feat_enum(kvm, ...) __kvm_has_feat_enum(kvm, __VA_ARGS__)
-
-#define kvm_has_feat_range(kvm, id, fld, min, max) \
- (kvm_cmp_feat(kvm, id, fld, >=, min) && \
- kvm_cmp_feat(kvm, id, fld, <=, max))
-
-/* Check for a given level of PAuth support */
-#define kvm_has_pauth(k, l) \
- ({ \
- bool pa, pi, pa3; \
- \
- pa = kvm_has_feat((k), ID_AA64ISAR1_EL1, APA, l); \
- pa &= kvm_has_feat((k), ID_AA64ISAR1_EL1, GPA, IMP); \
- pi = kvm_has_feat((k), ID_AA64ISAR1_EL1, API, l); \
- pi &= kvm_has_feat((k), ID_AA64ISAR1_EL1, GPI, IMP); \
- pa3 = kvm_has_feat((k), ID_AA64ISAR2_EL1, APA3, l); \
- pa3 &= kvm_has_feat((k), ID_AA64ISAR2_EL1, GPA3, IMP); \
- \
- (pa + pi + pa3) == 1; \
- })
-
-#define kvm_has_fpmr(k) \
- (system_supports_fpmr() && \
- kvm_has_feat((k), ID_AA64PFR2_EL1, FPMR, IMP))
-
-#define kvm_has_tcr2(k) \
- (kvm_has_feat((k), ID_AA64MMFR3_EL1, TCRX, IMP))
-
-#define kvm_has_s1pie(k) \
- (kvm_has_feat((k), ID_AA64MMFR3_EL1, S1PIE, IMP))
-
-#define kvm_has_s1poe(k) \
- (system_supports_poe() && \
- kvm_has_feat((k), ID_AA64MMFR3_EL1, S1POE, IMP))
-
-#define kvm_has_ras(k) \
- (kvm_has_feat((k), ID_AA64PFR0_EL1, RAS, IMP))
-
-#define kvm_has_sctlr2(k) \
- (kvm_has_feat((k), ID_AA64MMFR3_EL1, SCTLRX, IMP))
-
static inline bool kvm_arch_has_irq_bypass(void)
{
return true;
diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h
index dc2957662ff2..5da9ffae4f73 100644
--- a/arch/arm64/include/asm/kvm_nested.h
+++ b/arch/arm64/include/asm/kvm_nested.h
@@ -5,6 +5,7 @@
#include <linux/bitfield.h>
#include <linux/kvm_host.h>
#include <asm/kvm_emulate.h>
+#include <asm/kvm_feature.h>
#include <asm/kvm_pgtable.h>
static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c
index 9f8f0ae8e86e..ae91734dde37 100644
--- a/arch/arm64/kvm/at.c
+++ b/arch/arm64/kvm/at.c
@@ -7,6 +7,7 @@
#include <linux/kvm_host.h>
#include <asm/esr.h>
+#include <asm/kvm_feature.h>
#include <asm/kvm_hyp.h>
#include <asm/kvm_mmu.h>
#include <asm/lsui.h>
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 0622162b089e..014fe04daabf 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -6,6 +6,7 @@
#include <linux/kvm_host.h>
#include <asm/kvm_emulate.h>
+#include <asm/kvm_feature.h>
#include <asm/kvm_nested.h>
#include <asm/sysreg.h>
diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
index a17cbe7582de..dd824096dfc1 100644
--- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
+++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
@@ -13,6 +13,7 @@
#include <asm/kprobes.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_emulate.h>
+#include <asm/kvm_feature.h>
#include <asm/kvm_hyp.h>
#include <asm/kvm_mmu.h>
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 06db299c37a8..3e5c9107d78f 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -10,6 +10,7 @@
#include <asm/pgtable-types.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_emulate.h>
+#include <asm/kvm_feature.h>
#include <asm/kvm_host.h>
#include <asm/kvm_hyp.h>
#include <asm/kvm_hypevents.h>
diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
index 8c3fbb413a06..b5a0de84ce01 100644
--- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
+++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
@@ -7,6 +7,7 @@
#include <linux/irqchip/arm-gic-v3.h>
#include <asm/kvm_asm.h>
+#include <asm/kvm_feature.h>
#include <asm/kvm_mmu.h>
#include <hyp/adjust_pc.h>
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 9d941241c8a2..b275d3cabe21 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -6,6 +6,7 @@
#define __KVM_ARM_VGIC_NEW_H__
#include <linux/irqchip/arm-gic-common.h>
+#include <asm/kvm_feature.h>
#include <asm/kvm_mmu.h>
#define PRODUCT_ID_KVM 0x4b /* ASCII code K */
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 02/26] KVM: arm64: Remove __expand_field_sign_(un)signed
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 01/26] KVM: arm64: Extract some feature related changes to kvm_feature.h Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 03/26] KVM: arm64: Generalize get_idreg_field_*() Steffen Eiden
` (23 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
__expand_field_sign_unsigned is a very small abstraction that makes it
harder to see what's happening when looking at the caller. Just inline
it. Create a macro S64_SYS_FIELD_VALUE that is a sign extended
SYS_FIELD_VALUE. Then also get rid of __expand_field_sign_signed.
Co-developed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/kvm_feature.h | 13 ++-----------
include/arch/arm64/asm/sysreg-defs.h | 8 ++++++++
2 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_feature.h b/arch/arm64/include/asm/kvm_feature.h
index 8d0c65246aa0..d580f4ffab34 100644
--- a/arch/arm64/include/asm/kvm_feature.h
+++ b/arch/arm64/include/asm/kvm_feature.h
@@ -6,15 +6,6 @@
#include <linux/bitfield.h>
#include <asm/sysreg-defs.h>
-#define __expand_field_sign_unsigned(id, fld, val) \
- ((u64)SYS_FIELD_VALUE(id, fld, val))
-
-#define __expand_field_sign_signed(id, fld, val) \
- ({ \
- u64 __val = SYS_FIELD_VALUE(id, fld, val); \
- sign_extend64(__val, id##_##fld##_WIDTH - 1); \
- })
-
#define get_idreg_field_unsigned(kvm, id, fld) \
({ \
u64 __val = kvm_read_vm_id_reg((kvm), SYS_##id); \
@@ -31,10 +22,10 @@
get_idreg_field_unsigned(kvm, id, fld)
#define kvm_cmp_feat_signed(kvm, id, fld, op, limit) \
- (get_idreg_field_signed((kvm), id, fld) op __expand_field_sign_signed(id, fld, limit))
+ (get_idreg_field_signed((kvm), id, fld) op S64_SYS_FIELD_VALUE(id, fld, limit))
#define kvm_cmp_feat_unsigned(kvm, id, fld, op, limit) \
- (get_idreg_field_unsigned((kvm), id, fld) op __expand_field_sign_unsigned(id, fld, limit))
+ (get_idreg_field_unsigned((kvm), id, fld) op (u64)SYS_FIELD_VALUE(id, fld, limit))
#define kvm_cmp_feat(kvm, id, fld, op, limit) \
(id##_##fld##_SIGNED ? \
diff --git a/include/arch/arm64/asm/sysreg-defs.h b/include/arch/arm64/asm/sysreg-defs.h
index 27646c91e15c..3e280d4156ce 100644
--- a/include/arch/arm64/asm/sysreg-defs.h
+++ b/include/arch/arm64/asm/sysreg-defs.h
@@ -998,9 +998,17 @@
#ifndef __ASSEMBLER__
#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/types.h>
#define SYS_FIELD_VALUE(reg, field, val) reg##_##field##_##val
+#define S64_SYS_FIELD_VALUE(id, fld, val) \
+ ({ \
+ u64 __val = SYS_FIELD_VALUE(id, fld, val); \
+ sign_extend64(__val, id##_##fld##_WIDTH - 1); \
+ })
+
#define SYS_FIELD_GET(reg, field, val) \
FIELD_GET(reg##_##field##_MASK, val)
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 03/26] KVM: arm64: Generalize get_idreg_field_*()
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 01/26] KVM: arm64: Extract some feature related changes to kvm_feature.h Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 02/26] KVM: arm64: Remove __expand_field_sign_(un)signed Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 04/26] KVM: arm64: Generalize kvm_cmp_feat_*() Steffen Eiden
` (22 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Introduce intermediate macros that extract the value from a passed
parameter instead of reading the VM's ID register. Allow using other
sources of ID register values, i.e. read directly from the hardware or
during a sequence of sanitization steps.
Co-developed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/kvm_feature.h | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_feature.h b/arch/arm64/include/asm/kvm_feature.h
index d580f4ffab34..067550d5b208 100644
--- a/arch/arm64/include/asm/kvm_feature.h
+++ b/arch/arm64/include/asm/kvm_feature.h
@@ -6,20 +6,23 @@
#include <linux/bitfield.h>
#include <asm/sysreg-defs.h>
-#define get_idreg_field_unsigned(kvm, id, fld) \
- ({ \
- u64 __val = kvm_read_vm_id_reg((kvm), SYS_##id); \
- FIELD_GET(id##_##fld##_MASK, __val); \
- })
+#define extract_id_field_unsigned(val, id, fld) \
+ (FIELD_GET(id##_##fld##_MASK, (val)))
-#define get_idreg_field_signed(kvm, id, fld) \
+#define extract_id_field_signed(val, id, fld) \
({ \
- u64 __val = get_idreg_field_unsigned(kvm, id, fld); \
+ u64 __val = extract_id_field_unsigned((val), id, fld); \
sign_extend64(__val, id##_##fld##_WIDTH - 1); \
})
+#define get_idreg_field_unsigned(kvm, id, fld) \
+ extract_id_field_unsigned(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld)
+
+#define get_idreg_field_signed(kvm, id, fld) \
+ extract_id_field_signed(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld)
+
#define get_idreg_field_enum(kvm, id, fld) \
- get_idreg_field_unsigned(kvm, id, fld)
+ extract_id_field_unsigned(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld)
#define kvm_cmp_feat_signed(kvm, id, fld, op, limit) \
(get_idreg_field_signed((kvm), id, fld) op S64_SYS_FIELD_VALUE(id, fld, limit))
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 04/26] KVM: arm64: Generalize kvm_cmp_feat_*()
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (2 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 03/26] KVM: arm64: Generalize get_idreg_field_*() Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 05/26] KVM: arm64: Generalize kvm_has_feat_* Steffen Eiden
` (21 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Introduce an intermediate macro that extracts the value from a passed
parameter instead of reading the VM's ID register. Allow using other
sources of ID register values, i.e. read directly from the hardware or
during a sequence of sanitization steps.
Co-developed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/kvm_feature.h | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_feature.h b/arch/arm64/include/asm/kvm_feature.h
index 067550d5b208..6dd7b4a4929c 100644
--- a/arch/arm64/include/asm/kvm_feature.h
+++ b/arch/arm64/include/asm/kvm_feature.h
@@ -15,6 +15,17 @@
sign_extend64(__val, id##_##fld##_WIDTH - 1); \
})
+#define cmp_id_feat_signed(val, id, fld, op, limit) \
+ (extract_id_field_signed((val), id, fld) op S64_SYS_FIELD_VALUE(id, fld, limit))
+
+#define cmp_id_feat_unsigned(val, id, fld, op, limit) \
+ (extract_id_field_unsigned((val), id, fld) op (u64)SYS_FIELD_VALUE(id, fld, limit))
+
+#define cmp_id_feat(val, id, fld, op, limit) \
+ (id##_##fld##_SIGNED ? \
+ cmp_id_feat_signed(val, id, fld, op, limit) : \
+ cmp_id_feat_unsigned(val, id, fld, op, limit))
+
#define get_idreg_field_unsigned(kvm, id, fld) \
extract_id_field_unsigned(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld)
@@ -25,15 +36,13 @@
extract_id_field_unsigned(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld)
#define kvm_cmp_feat_signed(kvm, id, fld, op, limit) \
- (get_idreg_field_signed((kvm), id, fld) op S64_SYS_FIELD_VALUE(id, fld, limit))
+ cmp_id_feat_signed(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, op, limit)
#define kvm_cmp_feat_unsigned(kvm, id, fld, op, limit) \
- (get_idreg_field_unsigned((kvm), id, fld) op (u64)SYS_FIELD_VALUE(id, fld, limit))
+ cmp_id_feat_unsigned(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, op, limit)
#define kvm_cmp_feat(kvm, id, fld, op, limit) \
- (id##_##fld##_SIGNED ? \
- kvm_cmp_feat_signed(kvm, id, fld, op, limit) : \
- kvm_cmp_feat_unsigned(kvm, id, fld, op, limit))
+ cmp_id_feat(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, op, limit)
#define __kvm_has_feat(kvm, id, fld, limit) \
kvm_cmp_feat(kvm, id, fld, >=, limit)
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 05/26] KVM: arm64: Generalize kvm_has_feat_*
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (3 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 04/26] KVM: arm64: Generalize kvm_cmp_feat_*() Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 06/26] KVM: arm64: Remove get_idreg_field_*() and kvm_cmp_feat_*() Steffen Eiden
` (20 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Introduce an intermediate macro that extracts the value from a passed
parameter instead of reading the VM's ID register. Allow using other
sources of ID register values, i.e. read directly from the hardware or
during a sequence of sanitization steps.
Co-developed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/kvm_feature.h | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_feature.h b/arch/arm64/include/asm/kvm_feature.h
index 6dd7b4a4929c..b627696ac648 100644
--- a/arch/arm64/include/asm/kvm_feature.h
+++ b/arch/arm64/include/asm/kvm_feature.h
@@ -26,6 +26,16 @@
cmp_id_feat_signed(val, id, fld, op, limit) : \
cmp_id_feat_unsigned(val, id, fld, op, limit))
+#define id_has_feat(val, id, fld, limit) \
+ cmp_id_feat(val, id, fld, >=, limit)
+
+#define id_has_feat_enum(val, id, fld, variant) \
+ cmp_id_feat_unsigned(val, id, fld, ==, variant)
+
+#define id_has_feat_range(val, id, fld, min, max) \
+ (cmp_id_feat(val, id, fld, >=, min) && \
+ cmp_id_feat(val, id, fld, <=, max))
+
#define get_idreg_field_unsigned(kvm, id, fld) \
extract_id_field_unsigned(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld)
@@ -45,18 +55,17 @@
cmp_id_feat(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, op, limit)
#define __kvm_has_feat(kvm, id, fld, limit) \
- kvm_cmp_feat(kvm, id, fld, >=, limit)
+ id_has_feat(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, limit)
#define kvm_has_feat(kvm, ...) __kvm_has_feat(kvm, __VA_ARGS__)
#define __kvm_has_feat_enum(kvm, id, fld, val) \
- kvm_cmp_feat_unsigned(kvm, id, fld, ==, val)
+ id_has_feat_enum(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, val)
#define kvm_has_feat_enum(kvm, ...) __kvm_has_feat_enum(kvm, __VA_ARGS__)
#define kvm_has_feat_range(kvm, id, fld, min, max) \
- (kvm_cmp_feat(kvm, id, fld, >=, min) && \
- kvm_cmp_feat(kvm, id, fld, <=, max))
+ id_has_feat_range(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, min, max)
/* Check for a given level of PAuth support */
#define kvm_has_pauth(k, l) \
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 06/26] KVM: arm64: Remove get_idreg_field_*() and kvm_cmp_feat_*()
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (4 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 05/26] KVM: arm64: Generalize kvm_has_feat_* Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 07/26] KVM: arm64: Remove kvm_has_feat_range Steffen Eiden
` (19 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
These macros are now unused after generalizing the feature detection
code in the parent commit. The functionality is preserved through the
new generalized macros that operate on register values directly.
Co-developed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/kvm_feature.h | 18 ------------------
1 file changed, 18 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_feature.h b/arch/arm64/include/asm/kvm_feature.h
index b627696ac648..da9ba5041f44 100644
--- a/arch/arm64/include/asm/kvm_feature.h
+++ b/arch/arm64/include/asm/kvm_feature.h
@@ -36,24 +36,6 @@
(cmp_id_feat(val, id, fld, >=, min) && \
cmp_id_feat(val, id, fld, <=, max))
-#define get_idreg_field_unsigned(kvm, id, fld) \
- extract_id_field_unsigned(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld)
-
-#define get_idreg_field_signed(kvm, id, fld) \
- extract_id_field_signed(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld)
-
-#define get_idreg_field_enum(kvm, id, fld) \
- extract_id_field_unsigned(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld)
-
-#define kvm_cmp_feat_signed(kvm, id, fld, op, limit) \
- cmp_id_feat_signed(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, op, limit)
-
-#define kvm_cmp_feat_unsigned(kvm, id, fld, op, limit) \
- cmp_id_feat_unsigned(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, op, limit)
-
-#define kvm_cmp_feat(kvm, id, fld, op, limit) \
- cmp_id_feat(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, op, limit)
-
#define __kvm_has_feat(kvm, id, fld, limit) \
id_has_feat(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, limit)
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 07/26] KVM: arm64: Remove kvm_has_feat_range
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (5 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 06/26] KVM: arm64: Remove get_idreg_field_*() and kvm_cmp_feat_*() Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 08/26] KVM: arm64: Split up feature sysreg sanitisation Steffen Eiden
` (18 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
It is (and has been) unused.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/kvm_feature.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_feature.h b/arch/arm64/include/asm/kvm_feature.h
index da9ba5041f44..27a472d2343e 100644
--- a/arch/arm64/include/asm/kvm_feature.h
+++ b/arch/arm64/include/asm/kvm_feature.h
@@ -46,8 +46,6 @@
#define kvm_has_feat_enum(kvm, ...) __kvm_has_feat_enum(kvm, __VA_ARGS__)
-#define kvm_has_feat_range(kvm, id, fld, min, max) \
- id_has_feat_range(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, min, max)
/* Check for a given level of PAuth support */
#define kvm_has_pauth(k, l) \
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 08/26] KVM: arm64: Split up feature sysreg sanitisation
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (6 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 07/26] KVM: arm64: Remove kvm_has_feat_range Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 09/26] KVM: arm64: Refactor idreg caching into dedicated structure Steffen Eiden
` (17 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Split ID register sanitisation into distinct stages:
1) static KVM limits (kvm_max_possible_guest_ftr_reg)
2) host-specific (kvm_sanitised_host_ftr_reg)
3) per-vcpu configuration (kvm_sanitise_vcpu_ftr_reg)
This refactoring improves code organization by separating concerns.
Static limits apply regardless of host or guest configuration. Host
capability checks handle features like GIC, GCIE, and Spectre
mitigations. Per-vcpu feature configuration manages SVE, MTE, PMU, and
similar guest-specific features. Additionally, this enables other
architectures to add different host-implementation-based sanitisation in
the future.
Remove helper functions sanitise_id_aa64{pfr0,pfr1,dfr0}_el1
in favor of organized logic.
Co-developed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/kvm/sys_regs.c | 291 ++++++++++++++++++++------------------
1 file changed, 153 insertions(+), 138 deletions(-)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 2434bcc2d50d..b9aa892616ab 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1841,54 +1841,86 @@ static u8 pmuver_to_perfmon(u8 pmuver)
}
}
-static u64 sanitise_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, u64 val);
-static u64 sanitise_id_aa64pfr1_el1(const struct kvm_vcpu *vcpu, u64 val);
-static u64 sanitise_id_aa64pfr2_el1(const struct kvm_vcpu *vcpu, u64 val);
-static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val);
-
-/* Read a sanitised cpufeature ID register by sys_reg_desc */
-static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *r)
+/*
+ * Sanitise based on the host implementation.
+ */
+static u64 kvm_sanitised_host_ftr_reg(u32 id)
{
- u32 id = reg_to_encoding(r);
- u64 val;
-
- if (sysreg_visible_as_raz(vcpu, r))
- return 0;
-
- val = read_sanitised_ftr_reg(id);
+ u64 val = read_sanitised_ftr_reg(id);
switch (id) {
- case SYS_ID_AA64DFR0_EL1:
- val = sanitise_id_aa64dfr0_el1(vcpu, val);
+ case SYS_ID_AA64ISAR2_EL1:
+ if (!cpus_have_final_cap(ARM64_HAS_WFXT) ||
+ has_broken_cntvoff())
+ val &= ~ID_AA64ISAR2_EL1_WFxT;
break;
case SYS_ID_AA64PFR0_EL1:
- val = sanitise_id_aa64pfr0_el1(vcpu, val);
+ /*
+ * The default is to expose CSV2 == 1 if the HW isn't affected.
+ * Although this is a per-CPU feature, we make it global because
+ * asymmetric systems are just a nuisance.
+ *
+ * Userspace can override this as long as it doesn't promise
+ * the impossible.
+ */
+ if (arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED) {
+ val &= ~ID_AA64PFR0_EL1_CSV2_MASK;
+ val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, CSV2, IMP);
+ }
+ if (arm64_get_meltdown_state() == SPECTRE_UNAFFECTED) {
+ val &= ~ID_AA64PFR0_EL1_CSV3_MASK;
+ val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, CSV3, IMP);
+ }
+ if (vgic_host_has_gicv3()) {
+ val &= ~ID_AA64PFR0_EL1_GIC_MASK;
+ val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, GIC, IMP);
+ }
break;
- case SYS_ID_AA64PFR1_EL1:
- val = sanitise_id_aa64pfr1_el1(vcpu, val);
+ case SYS_ID_AA64PFR1_EL1: {
+ u64 pfr0_host = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
+
+ if (!(cpus_have_final_cap(ARM64_HAS_RASV1P1_EXTN) &&
+ SYS_FIELD_GET(ID_AA64PFR0_EL1, RAS, pfr0_host) == ID_AA64PFR0_EL1_RAS_IMP))
+ val &= ~ID_AA64PFR1_EL1_RAS_frac;
break;
+ }
case SYS_ID_AA64PFR2_EL1:
- val = sanitise_id_aa64pfr2_el1(vcpu, val);
+ if (vgic_host_has_gicv5())
+ val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR2_EL1, GCIE, IMP);
break;
- case SYS_ID_AA64ISAR1_EL1:
- if (!vcpu_has_ptrauth(vcpu))
- val &= ~(ID_AA64ISAR1_EL1_APA |
- ID_AA64ISAR1_EL1_API |
- ID_AA64ISAR1_EL1_GPA |
- ID_AA64ISAR1_EL1_GPI);
+ case SYS_ID_AA64MMFR3_EL1:
+ if (!system_supports_poe())
+ val &= ~ID_AA64MMFR3_EL1_S1POE;
+ break;
+ }
+
+ return val;
+}
+
+/*
+ * Statically sanitise the host's feature register, independent of the guest's
+ * configuration and host implementation.
+ */
+static u64 kvm_max_possible_guest_ftr_reg(u32 id, u64 val)
+{
+ switch (id) {
+ case SYS_ID_AA64DFR0_EL1:
+ val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8);
+
+ /* Hide SPE from guests */
+ val &= ~ID_AA64DFR0_EL1_PMSVer_MASK;
+
+ /* Hide BRBE from guests */
+ val &= ~ID_AA64DFR0_EL1_BRBE_MASK;
break;
case SYS_ID_AA64ISAR2_EL1:
- if (!vcpu_has_ptrauth(vcpu))
- val &= ~(ID_AA64ISAR2_EL1_APA3 |
- ID_AA64ISAR2_EL1_GPA3);
- if (!cpus_have_final_cap(ARM64_HAS_WFXT) ||
- has_broken_cntvoff())
+ /* Mask WFxT field unless *both* WFET & WFIT are present. */
+ if (!id_has_feat(val, ID_AA64ISAR2_EL1, WFxT, IMP))
val &= ~ID_AA64ISAR2_EL1_WFxT;
break;
case SYS_ID_AA64ISAR3_EL1:
val &= ID_AA64ISAR3_EL1_FPRCVT | ID_AA64ISAR3_EL1_LSFE |
- ID_AA64ISAR3_EL1_FAMINMAX | ID_AA64ISAR3_EL1_LSUI;
+ ID_AA64ISAR3_EL1_FAMINMAX | ID_AA64ISAR3_EL1_LSUI;
break;
case SYS_ID_AA64MMFR2_EL1:
val &= ~ID_AA64MMFR2_EL1_CCIDX_MASK;
@@ -1899,13 +1931,81 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
ID_AA64MMFR3_EL1_SCTLRX |
ID_AA64MMFR3_EL1_S1POE |
ID_AA64MMFR3_EL1_S1PIE;
-
- if (!system_supports_poe())
- val &= ~ID_AA64MMFR3_EL1_S1POE;
break;
case SYS_ID_MMFR4_EL1:
val &= ~ID_MMFR4_EL1_CCIDX;
break;
+ case SYS_ID_AA64PFR0_EL1:
+ val &= ~ID_AA64PFR0_EL1_AMU_MASK;
+ /*
+ * MPAM is disabled by default as KVM also needs a set of PARTID to
+ * program the MPAMVPMx_EL2 PARTID remapping registers with. But some
+ * older kernels let the guest see the ID bit.
+ */
+ val &= ~ID_AA64PFR0_EL1_MPAM_MASK;
+ break;
+ case SYS_ID_AA64PFR1_EL1:
+ val &= ~ID_AA64PFR1_EL1_SME;
+ val &= ~ID_AA64PFR1_EL1_RNDR_trap;
+ val &= ~ID_AA64PFR1_EL1_NMI;
+ val &= ~ID_AA64PFR1_EL1_GCS;
+ val &= ~ID_AA64PFR1_EL1_THE;
+ val &= ~ID_AA64PFR1_EL1_MTEX;
+ val &= ~ID_AA64PFR1_EL1_PFAR;
+ val &= ~ID_AA64PFR1_EL1_MPAM_frac;
+ break;
+ case SYS_ID_AA64PFR2_EL1:
+ val &= ID_AA64PFR2_EL1_FPMR |
+ ID_AA64PFR2_EL1_MTEFAR |
+ ID_AA64PFR2_EL1_MTESTOREONLY;
+ break;
+ }
+
+ return val;
+}
+
+/*
+ * Sanitise based on vCPU configuration.
+ */
+static u64 kvm_sanitise_vcpu_ftr_reg(const struct kvm_vcpu *vcpu, u32 id, u64 val)
+{
+ switch (id) {
+ case SYS_ID_AA64DFR0_EL1:
+ /*
+ * Only initialize the PMU version if the vCPU was configured with one.
+ */
+ val &= ~ID_AA64DFR0_EL1_PMUVer_MASK;
+ if (kvm_vcpu_has_pmu(vcpu))
+ val |= SYS_FIELD_PREP(ID_AA64DFR0_EL1, PMUVer,
+ kvm_arm_pmu_get_pmuver_limit());
+ break;
+ case SYS_ID_AA64PFR0_EL1:
+ if (!vcpu_has_sve(vcpu))
+ val &= ~ID_AA64PFR0_EL1_SVE_MASK;
+ break;
+ case SYS_ID_AA64PFR1_EL1:
+ if (!kvm_has_mte(vcpu->kvm)) {
+ val &= ~ID_AA64PFR1_EL1_MTE;
+ val &= ~ID_AA64PFR1_EL1_MTE_frac;
+ }
+ break;
+ case SYS_ID_AA64PFR2_EL1:
+ if (!kvm_has_mte(vcpu->kvm)) {
+ val &= ~ID_AA64PFR2_EL1_MTEFAR;
+ val &= ~ID_AA64PFR2_EL1_MTESTOREONLY;
+ }
+ break;
+ case SYS_ID_AA64ISAR1_EL1:
+ if (!vcpu_has_ptrauth(vcpu))
+ val &= ~(ID_AA64ISAR1_EL1_APA |
+ ID_AA64ISAR1_EL1_API |
+ ID_AA64ISAR1_EL1_GPA |
+ ID_AA64ISAR1_EL1_GPI);
+ break;
+ case SYS_ID_AA64ISAR2_EL1:
+ if (!vcpu_has_ptrauth(vcpu))
+ val &= ~(ID_AA64ISAR2_EL1_APA3 |
+ ID_AA64ISAR2_EL1_GPA3);
}
if (vcpu_has_nv(vcpu))
@@ -1914,6 +2014,23 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
return val;
}
+/* Read a sanitised cpufeature ID register by sys_reg_desc */
+static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *r)
+{
+ u32 id = reg_to_encoding(r);
+ u64 val;
+
+ if (sysreg_visible_as_raz(vcpu, r))
+ return 0;
+
+ val = kvm_sanitised_host_ftr_reg(id);
+ val = kvm_max_possible_guest_ftr_reg(id, val);
+ val = kvm_sanitise_vcpu_ftr_reg(vcpu, id, val);
+
+ return val;
+}
+
static u64 kvm_read_sanitised_id_reg(struct kvm_vcpu *vcpu,
const struct sys_reg_desc *r)
{
@@ -2046,108 +2163,6 @@ static unsigned int fp8_visibility(const struct kvm_vcpu *vcpu,
return REG_HIDDEN;
}
-static u64 sanitise_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
-{
- if (!vcpu_has_sve(vcpu))
- val &= ~ID_AA64PFR0_EL1_SVE_MASK;
-
- /*
- * The default is to expose CSV2 == 1 if the HW isn't affected.
- * Although this is a per-CPU feature, we make it global because
- * asymmetric systems are just a nuisance.
- *
- * Userspace can override this as long as it doesn't promise
- * the impossible.
- */
- if (arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED) {
- val &= ~ID_AA64PFR0_EL1_CSV2_MASK;
- val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, CSV2, IMP);
- }
- if (arm64_get_meltdown_state() == SPECTRE_UNAFFECTED) {
- val &= ~ID_AA64PFR0_EL1_CSV3_MASK;
- val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, CSV3, IMP);
- }
-
- if (vgic_host_has_gicv3()) {
- val &= ~ID_AA64PFR0_EL1_GIC_MASK;
- val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, GIC, IMP);
- }
-
- val &= ~ID_AA64PFR0_EL1_AMU_MASK;
-
- /*
- * MPAM is disabled by default as KVM also needs a set of PARTID to
- * program the MPAMVPMx_EL2 PARTID remapping registers with. But some
- * older kernels let the guest see the ID bit.
- */
- val &= ~ID_AA64PFR0_EL1_MPAM_MASK;
-
- return val;
-}
-
-static u64 sanitise_id_aa64pfr1_el1(const struct kvm_vcpu *vcpu, u64 val)
-{
- u64 pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
-
- if (!kvm_has_mte(vcpu->kvm)) {
- val &= ~ID_AA64PFR1_EL1_MTE;
- val &= ~ID_AA64PFR1_EL1_MTE_frac;
- }
-
- if (!(cpus_have_final_cap(ARM64_HAS_RASV1P1_EXTN) &&
- SYS_FIELD_GET(ID_AA64PFR0_EL1, RAS, pfr0) == ID_AA64PFR0_EL1_RAS_IMP))
- val &= ~ID_AA64PFR1_EL1_RAS_frac;
-
- val &= ~ID_AA64PFR1_EL1_SME;
- val &= ~ID_AA64PFR1_EL1_RNDR_trap;
- val &= ~ID_AA64PFR1_EL1_NMI;
- val &= ~ID_AA64PFR1_EL1_GCS;
- val &= ~ID_AA64PFR1_EL1_THE;
- val &= ~ID_AA64PFR1_EL1_MTEX;
- val &= ~ID_AA64PFR1_EL1_PFAR;
- val &= ~ID_AA64PFR1_EL1_MPAM_frac;
-
- return val;
-}
-
-static u64 sanitise_id_aa64pfr2_el1(const struct kvm_vcpu *vcpu, u64 val)
-{
- val &= ID_AA64PFR2_EL1_FPMR |
- ID_AA64PFR2_EL1_MTEFAR |
- ID_AA64PFR2_EL1_MTESTOREONLY;
-
- if (!kvm_has_mte(vcpu->kvm)) {
- val &= ~ID_AA64PFR2_EL1_MTEFAR;
- val &= ~ID_AA64PFR2_EL1_MTESTOREONLY;
- }
-
- if (vgic_host_has_gicv5())
- val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR2_EL1, GCIE, IMP);
-
- return val;
-}
-
-static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
-{
- val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8);
-
- /*
- * Only initialize the PMU version if the vCPU was configured with one.
- */
- val &= ~ID_AA64DFR0_EL1_PMUVer_MASK;
- if (kvm_vcpu_has_pmu(vcpu))
- val |= SYS_FIELD_PREP(ID_AA64DFR0_EL1, PMUVer,
- kvm_arm_pmu_get_pmuver_limit());
-
- /* Hide SPE from guests */
- val &= ~ID_AA64DFR0_EL1_PMSVer_MASK;
-
- /* Hide BRBE from guests */
- val &= ~ID_AA64DFR0_EL1_BRBE_MASK;
-
- return val;
-}
-
/*
* Older versions of KVM erroneously claim support for FEAT_DoubleLock with
* NV-enabled VMs on unsupporting hardware. Silently ignore the incorrect
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 09/26] KVM: arm64: Refactor idreg caching into dedicated structure
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (7 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 08/26] KVM: arm64: Split up feature sysreg sanitisation Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-06-01 22:28 ` Oliver Upton
2026-05-29 15:55 ` [PATCH v1 10/26] KVM: arm64: Fix set_oslsr_el1 to write to OSLAR_EL1 Steffen Eiden
` (16 subsequent siblings)
25 siblings, 1 reply; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Move VM-wide ID register emulation fields from struct kvm_arch into a
new struct kvm_vm_id_regs to prepare future sharing of these fields and
functions using them. Update all users to use the new structure. No
functional changes.
Co-developed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/kvm_host.h | 50 ++++++++++++++++--------------
arch/arm64/kvm/config.c | 2 +-
arch/arm64/kvm/hyp/nvhe/pkvm.c | 7 +++--
arch/arm64/kvm/hyp/nvhe/sys_regs.c | 4 +--
arch/arm64/kvm/sys_regs.c | 2 +-
5 files changed, 35 insertions(+), 30 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 4c2c62b8b506..a8efff6ea01d 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -352,22 +352,7 @@ struct kvm_arch {
struct kvm_smccc_features smccc_feat;
struct maple_tree smccc_filter;
- /*
- * Emulated CPU ID registers per VM
- * (Op0, Op1, CRn, CRm, Op2) of the ID registers to be saved in it
- * is (3, 0, 0, crm, op2), where 1<=crm<8, 0<=op2<8.
- *
- * These emulated idregs are VM-wide, but accessed from the context of a vCPU.
- * Atomic access to multiple idregs are guarded by kvm_arch.config_lock.
- */
-#define IDREG_IDX(id) (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))
-#define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
- u64 id_regs[KVM_ARM_ID_REG_NUM];
-
- u64 midr_el1;
- u64 revidr_el1;
- u64 aidr_el1;
- u64 ctr_el0;
+ struct kvm_vm_id_regs id_regs;
/* Masks for VNCR-backed and general EL2 sysregs */
struct kvm_sysreg_masks *sysreg_masks;
@@ -1399,19 +1384,38 @@ static inline void kvm_hyp_reserve(void) { }
void kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu);
bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu);
-static inline u64 *__vm_id_reg(struct kvm_arch *ka, u32 reg)
+struct kvm_vm_id_regs {
+ /*
+ * Emulated CPU ID registers per VM
+ * (Op0, Op1, CRn, CRm, Op2) of the ID registers to be saved in it
+ * is (3, 0, 0, crm, op2), where 1<=crm<8, 0<=op2<8.
+ *
+ * These emulated idregs are VM-wide, but accessed from the context of a vCPU.
+ * Atomic access to multiple idregs are guarded by kvm_arch.config_lock.
+ */
+#define IDREG_IDX(id) (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))
+#define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
+ u64 normal[KVM_ARM_ID_REG_NUM];
+
+ u64 midr_el1;
+ u64 revidr_el1;
+ u64 aidr_el1;
+ u64 ctr_el0;
+};
+
+static inline u64 *__vm_id_reg(struct kvm_vm_id_regs *id_regs, u32 reg)
{
switch (reg) {
case sys_reg(3, 0, 0, 1, 0) ... sys_reg(3, 0, 0, 7, 7):
- return &ka->id_regs[IDREG_IDX(reg)];
+ return &id_regs->normal[IDREG_IDX(reg)];
case SYS_CTR_EL0:
- return &ka->ctr_el0;
+ return &id_regs->ctr_el0;
case SYS_MIDR_EL1:
- return &ka->midr_el1;
+ return &id_regs->midr_el1;
case SYS_REVIDR_EL1:
- return &ka->revidr_el1;
+ return &id_regs->revidr_el1;
case SYS_AIDR_EL1:
- return &ka->aidr_el1;
+ return &id_regs->aidr_el1;
default:
WARN_ON_ONCE(1);
return NULL;
@@ -1419,7 +1423,7 @@ static inline u64 *__vm_id_reg(struct kvm_arch *ka, u32 reg)
}
#define kvm_read_vm_id_reg(kvm, reg) \
- ({ u64 __val = *__vm_id_reg(&(kvm)->arch, reg); __val; })
+ ({ u64 __val = *__vm_id_reg(&(kvm)->arch.id_regs, reg); __val; })
void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 014fe04daabf..58a439c3ab9c 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -1398,7 +1398,7 @@ void __init check_feature_map(void)
static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map)
{
- u64 regval = kvm->arch.id_regs[map->regidx];
+ u64 regval = kvm->arch.id_regs.normal[map->regidx];
u64 regfld = (regval >> map->shift) & GENMASK(map->width - 1, 0);
if (map->sign) {
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index eb1c10120f9f..94620f142f42 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -343,7 +343,7 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
DECLARE_BITMAP(allowed_features, KVM_VCPU_MAX_FEATURES);
/* CTR_EL0 is always under host control, even for protected VMs. */
- hyp_vm->kvm.arch.ctr_el0 = host_kvm->arch.ctr_el0;
+ hyp_vm->kvm.arch.id_regs.ctr_el0 = host_kvm->arch.id_regs.ctr_el0;
/* Preserve the vgic model so that GICv3 emulation works */
hyp_vm->kvm.arch.vgic.vgic_model = host_kvm->arch.vgic.vgic_model;
@@ -358,7 +358,7 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
KVM_VCPU_MAX_FEATURES);
if (test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &host_arch_flags))
- hyp_vm->kvm.arch.midr_el1 = host_kvm->arch.midr_el1;
+ hyp_vm->kvm.arch.id_regs.midr_el1 = host_kvm->arch.id_regs.midr_el1;
return;
}
@@ -493,7 +493,8 @@ static int vm_copy_id_regs(struct pkvm_hyp_vcpu *hyp_vcpu)
if (test_and_set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags))
return 0;
- memcpy(kvm->arch.id_regs, host_kvm->arch.id_regs, sizeof(kvm->arch.id_regs));
+ memcpy(kvm->arch.id_regs.normal, host_kvm->arch.id_regs.normal,
+ sizeof(kvm->arch.id_regs.normal));
return 0;
}
diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
index b5a0de84ce01..e8d773d38905 100644
--- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
+++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
@@ -292,7 +292,7 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
return 0;
if (reg >= sys_reg(3, 0, 0, 1, 0) && reg <= sys_reg(3, 0, 0, 7, 7))
- return kvm->arch.id_regs[IDREG_IDX(reg)];
+ return kvm->arch.id_regs.normal[IDREG_IDX(reg)];
return 0;
}
@@ -543,7 +543,7 @@ void kvm_init_pvm_id_regs(struct kvm_vcpu *vcpu)
* for protected VMs.
*/
for (r = sys_reg(3, 0, 0, 4, 0); r <= sys_reg(3, 0, 0, 7, 7); r += sys_reg(0, 0, 0, 0, 1))
- ka->id_regs[IDREG_IDX(r)] = pvm_calc_id_reg(vcpu, r);
+ ka->id_regs.normal[IDREG_IDX(r)] = pvm_calc_id_reg(vcpu, r);
set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags);
}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index b9aa892616ab..195ecdac7bd6 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -2477,7 +2477,7 @@ static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val)
{
- u64 *p = __vm_id_reg(&kvm->arch, reg);
+ u64 *p = __vm_id_reg(&kvm->arch.id_regs, reg);
lockdep_assert_held(&kvm->arch.config_lock);
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 10/26] KVM: arm64: Fix set_oslsr_el1 to write to OSLAR_EL1
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (8 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 09/26] KVM: arm64: Refactor idreg caching into dedicated structure Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-06-01 22:21 ` Oliver Upton
2026-05-29 15:55 ` [PATCH v1 11/26] KVM: arm64: Move definitions from sys_regs.c to sys_regs.h Steffen Eiden
` (15 subsequent siblings)
25 siblings, 1 reply; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
From: Andreas Grapentin <gra@linux.ibm.com>
The set_oslsr_el1() function was incorrectly writing directly to the
OSLSR_EL1 register, which is architecturally a read-only status register
that reflects the state of the OS Lock.
Fix this by extracting the OSLK bit from the user-provided value and
writing it to OSLAR_EL1 (OS Lock Access Register) instead, which is the
proper control register for managing the OS Lock state. OSLSR_EL1 will
then reflect this state when read.
This ensures the implementation follows the ARM architecture
specification where OSLAR_EL1 controls the lock and OSLSR_EL1 provides
status information.
Signed-off-by: Andreas Grapentin <gra@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/kvm_host.h | 1 +
arch/arm64/kvm/sys_regs.c | 10 +++++++++-
include/arch/arm64/asm/sysreg-defs.h | 1 +
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index a8efff6ea01d..5734e93cad57 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -408,6 +408,7 @@ enum vcpu_sysreg {
PAR_EL1, /* Physical Address Register */
MDCCINT_EL1, /* Monitor Debug Comms Channel Interrupt Enable Reg */
OSLSR_EL1, /* OS Lock Status Register */
+ OSLAR_EL1, /* OS Lock Access Register */
DISR_EL1, /* Deferred Interrupt Status Register */
/* Performance Monitors Registers */
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 195ecdac7bd6..6522f9302967 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -822,6 +822,8 @@ static bool trap_oslsr_el1(struct kvm_vcpu *vcpu,
static int set_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
u64 val)
{
+ u64 oslk;
+
/*
* The only modifiable bit is the OSLK bit. Refuse the write if
* userspace attempts to change any other bit in the register.
@@ -829,7 +831,13 @@ static int set_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
if ((val ^ rd->val) & ~OSLSR_EL1_OSLK)
return -EINVAL;
- __vcpu_assign_sys_reg(vcpu, rd->reg, val);
+ /*
+ * Redirect the write to the proper control register.
+ * OSLSR is read-only
+ */
+ oslk = SYS_FIELD_GET(OSLSR_EL1, OSLK, val);
+ __vcpu_assign_sys_reg(vcpu, OSLAR_EL1,
+ SYS_FIELD_PREP(OSLAR_EL1, OSLK, oslk));
return 0;
}
diff --git a/include/arch/arm64/asm/sysreg-defs.h b/include/arch/arm64/asm/sysreg-defs.h
index 3e280d4156ce..c6bdb0f11e1b 100644
--- a/include/arch/arm64/asm/sysreg-defs.h
+++ b/include/arch/arm64/asm/sysreg-defs.h
@@ -129,6 +129,7 @@
#define OSLSR_EL1_OSLM_NI 0
#define OSLSR_EL1_OSLM_IMPLEMENTED BIT(3)
#define OSLSR_EL1_OSLK BIT(1)
+#define OSLSR_EL1_OSLK_MASK BIT(1)
#define SYS_OSDLR_EL1 sys_reg(2, 0, 1, 3, 4)
#define SYS_DBGPRCR_EL1 sys_reg(2, 0, 1, 4, 4)
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 11/26] KVM: arm64: Move definitions from sys_regs.c to sys_regs.h
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (9 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 10/26] KVM: arm64: Fix set_oslsr_el1 to write to OSLAR_EL1 Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 12/26] KVM: arm64: Add PVM_ prefix to avoid name collisions Steffen Eiden
` (14 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Make kvm_sanitised_host_ftr_reg() and kvm_read_sanitised_id_reg()
available to enable code sharing with s390. Move some helper and ID
register macro definitions to the header file. No functional changes.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/kvm/sys_regs.c | 12 ++----
arch/arm64/kvm/sys_regs.h | 87 +++++++++++++++++++++++++++++++++++++++
2 files changed, 90 insertions(+), 9 deletions(-)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 6522f9302967..46b24529ec70 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1852,7 +1852,7 @@ static u8 pmuver_to_perfmon(u8 pmuver)
/*
* Sanitise based on the host implementation.
*/
-static u64 kvm_sanitised_host_ftr_reg(u32 id)
+u64 kvm_sanitised_host_ftr_reg(u32 id)
{
u64 val = read_sanitised_ftr_reg(id);
@@ -2039,8 +2039,8 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
return val;
}
-static u64 kvm_read_sanitised_id_reg(struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *r)
+u64 kvm_read_sanitised_id_reg(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *r)
{
return __kvm_read_sanitised_id_reg(vcpu, r);
}
@@ -2123,12 +2123,6 @@ static unsigned int aa32_id_visibility(const struct kvm_vcpu *vcpu,
return id_visibility(vcpu, r);
}
-static unsigned int raz_visibility(const struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *r)
-{
- return REG_RAZ;
-}
-
/* cpufeature ID register access trap handlers */
static bool access_id_reg(struct kvm_vcpu *vcpu,
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index 2a983664220c..75d581050b09 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -108,6 +108,12 @@ struct sys_reg_desc {
#define REG_RAZ (1 << 1) /* RAZ from userspace and guest */
#define REG_USER_WI (1 << 2) /* WI from userspace only */
+static inline unsigned int raz_visibility(const struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *r)
+{
+ return REG_RAZ;
+}
+
static __printf(2, 3)
inline void print_sys_reg_msg(const struct sys_reg_params *p,
char *fmt, ...)
@@ -237,6 +243,12 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index);
int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu);
+u64 kvm_read_sanitised_id_reg(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *r);
+
+/* Implemented by each architecture */
+u64 kvm_sanitised_host_ftr_reg(u32 id);
+
#define AA32(_x) .aarch32_map = AA32_##_x
#define Op0(_x) .Op0 = _x
#define Op1(_x) .Op1 = _x
@@ -257,6 +269,81 @@ int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu);
CRn(sys_reg_CRn(reg)), CRm(sys_reg_CRm(reg)), \
Op2(sys_reg_Op2(reg))
+/*
+ * Since reset() callback and field val are not used for idregs, they will be
+ * used for specific purposes for idregs.
+ * The reset() would return KVM sanitised register value. The value would be the
+ * same as the host kernel sanitised value if there is no KVM sanitisation.
+ * The val would be used as a mask indicating writable fields for the idreg.
+ * Only bits with 1 are writable from userspace. This mask might not be
+ * necessary in the future whenever all ID registers are enabled as writable
+ * from userspace.
+ */
+
+#define ID_DESC_DEFAULT_CALLBACKS \
+ .access = access_id_reg, \
+ .get_user = get_id_reg, \
+ .set_user = set_id_reg, \
+ .visibility = id_visibility, \
+ .reset = kvm_read_sanitised_id_reg
+
+#define ID_DESC(name) \
+ SYS_DESC(SYS_##name), \
+ ID_DESC_DEFAULT_CALLBACKS
+
+/* sys_reg_desc initialiser for known cpufeature ID registers */
+#define ID_SANITISED(name) { \
+ ID_DESC(name), \
+ .val = 0, \
+}
+
+/* sys_reg_desc initialiser for writable ID registers */
+#define ID_WRITABLE(name, mask) { \
+ ID_DESC(name), \
+ .val = mask, \
+}
+
+/*
+ * 32bit ID regs are fully writable when the guest is 32bit
+ * capable. Nothing in the KVM code should rely on 32bit features
+ * anyway, only 64bit, so let the VMM do its worse.
+ */
+#define AA32_ID_WRITABLE(name) { \
+ ID_DESC(name), \
+ .visibility = aa32_id_visibility, \
+ .val = GENMASK(31, 0), \
+}
+
+/* sys_reg_desc initialiser for cpufeature ID registers that need filtering */
+#define ID_FILTERED(sysreg, name, mask) { \
+ ID_DESC(sysreg), \
+ .set_user = set_##name, \
+ .val = (mask), \
+}
+
+/*
+ * sys_reg_desc initialiser for architecturally unallocated cpufeature ID
+ * register with encoding Op0=3, Op1=0, CRn=0, CRm=crm, Op2=op2
+ * (1 <= crm < 8, 0 <= Op2 < 8).
+ */
+#define ID_UNALLOCATED(crm, op2) { \
+ .name = "S3_0_0_" #crm "_" #op2, \
+ Op0(3), Op1(0), CRn(0), CRm(crm), Op2(op2), \
+ ID_DESC_DEFAULT_CALLBACKS, \
+ .visibility = raz_visibility, \
+ .val = 0, \
+}
+
+/*
+ * sys_reg_desc initialiser for known ID registers that we hide from guests.
+ * For now, these are exposed just like unallocated ID regs: they appear
+ * RAZ for the guest.
+ */
+#define ID_HIDDEN(name) { \
+ ID_DESC(name), \
+ .visibility = raz_visibility, \
+ .val = 0, \
+}
#define ID_REG_LIMIT_FIELD_ENUM(val, reg, field, limit) \
({ \
u64 __f_val = FIELD_GET(reg##_##field##_MASK, val); \
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 12/26] KVM: arm64: Add PVM_ prefix to avoid name collisions
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (10 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 11/26] KVM: arm64: Move definitions from sys_regs.c to sys_regs.h Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-06-01 22:23 ` Oliver Upton
2026-05-29 15:55 ` [PATCH v1 13/26] s390: Introduce read/write ARM sysreg instructions Steffen Eiden
` (13 subsequent siblings)
25 siblings, 1 reply; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Rename ID_UNALLOCATED to PVM_ID_UNALLOCATED and read_id_reg to
pvm_read_id_reg to prevent future name collisions with other subsystems.
While at it, fix whitespace issues in the macro invocations
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/kvm/hyp/nvhe/sys_regs.c | 48 +++++++++++++++---------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
index e8d773d38905..08b14053568b 100644
--- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
+++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
@@ -282,8 +282,8 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
inject_sync64(vcpu, (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT));
}
-static u64 read_id_reg(const struct kvm_vcpu *vcpu,
- struct sys_reg_desc const *r)
+static u64 pvm_read_id_reg(const struct kvm_vcpu *vcpu,
+ struct sys_reg_desc const *r)
{
struct kvm *kvm = vcpu->kvm;
u32 reg = reg_to_encoding(r);
@@ -341,7 +341,7 @@ static bool pvm_access_id_aarch64(struct kvm_vcpu *vcpu,
return false;
}
- p->regval = read_id_reg(vcpu, r);
+ p->regval = pvm_read_id_reg(vcpu, r);
return true;
}
@@ -379,7 +379,7 @@ static bool pvm_idst_access(struct kvm_vcpu *vcpu,
* register with encoding Op0=3, Op1=0, CRn=0, CRm=crm, Op2=op2
* (1 <= crm < 8, 0 <= Op2 < 8).
*/
-#define ID_UNALLOCATED(crm, op2) { \
+#define PVM_ID_UNALLOCATED(crm, op2) { \
Op0(3), Op1(0), CRn(0), CRm(crm), Op2(op2), \
.access = pvm_access_id_aarch64, \
}
@@ -438,46 +438,46 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {
AARCH32(SYS_MVFR0_EL1),
AARCH32(SYS_MVFR1_EL1),
AARCH32(SYS_MVFR2_EL1),
- ID_UNALLOCATED(3,3),
+ PVM_ID_UNALLOCATED(3, 3),
AARCH32(SYS_ID_PFR2_EL1),
AARCH32(SYS_ID_DFR1_EL1),
AARCH32(SYS_ID_MMFR5_EL1),
- ID_UNALLOCATED(3,7),
+ PVM_ID_UNALLOCATED(3, 7),
/* AArch64 ID registers */
/* CRm=4 */
AARCH64(SYS_ID_AA64PFR0_EL1),
AARCH64(SYS_ID_AA64PFR1_EL1),
AARCH64(SYS_ID_AA64PFR2_EL1),
- ID_UNALLOCATED(4,3),
+ PVM_ID_UNALLOCATED(4, 3),
AARCH64(SYS_ID_AA64ZFR0_EL1),
- ID_UNALLOCATED(4,5),
- ID_UNALLOCATED(4,6),
- ID_UNALLOCATED(4,7),
+ PVM_ID_UNALLOCATED(4, 5),
+ PVM_ID_UNALLOCATED(4, 6),
+ PVM_ID_UNALLOCATED(4, 7),
AARCH64(SYS_ID_AA64DFR0_EL1),
AARCH64(SYS_ID_AA64DFR1_EL1),
- ID_UNALLOCATED(5,2),
- ID_UNALLOCATED(5,3),
+ PVM_ID_UNALLOCATED(5, 2),
+ PVM_ID_UNALLOCATED(5, 3),
AARCH64(SYS_ID_AA64AFR0_EL1),
AARCH64(SYS_ID_AA64AFR1_EL1),
- ID_UNALLOCATED(5,6),
- ID_UNALLOCATED(5,7),
+ PVM_ID_UNALLOCATED(5, 6),
+ PVM_ID_UNALLOCATED(5, 7),
AARCH64(SYS_ID_AA64ISAR0_EL1),
AARCH64(SYS_ID_AA64ISAR1_EL1),
AARCH64(SYS_ID_AA64ISAR2_EL1),
- ID_UNALLOCATED(6,3),
- ID_UNALLOCATED(6,4),
- ID_UNALLOCATED(6,5),
- ID_UNALLOCATED(6,6),
- ID_UNALLOCATED(6,7),
+ PVM_ID_UNALLOCATED(6, 3),
+ PVM_ID_UNALLOCATED(6, 4),
+ PVM_ID_UNALLOCATED(6, 5),
+ PVM_ID_UNALLOCATED(6, 6),
+ PVM_ID_UNALLOCATED(6, 7),
AARCH64(SYS_ID_AA64MMFR0_EL1),
AARCH64(SYS_ID_AA64MMFR1_EL1),
AARCH64(SYS_ID_AA64MMFR2_EL1),
- ID_UNALLOCATED(7,3),
- ID_UNALLOCATED(7,4),
- ID_UNALLOCATED(7,5),
- ID_UNALLOCATED(7,6),
- ID_UNALLOCATED(7,7),
+ PVM_ID_UNALLOCATED(7, 3),
+ PVM_ID_UNALLOCATED(7, 4),
+ PVM_ID_UNALLOCATED(7, 5),
+ PVM_ID_UNALLOCATED(7, 6),
+ PVM_ID_UNALLOCATED(7, 7),
/* Scalable Vector Registers are restricted. */
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 13/26] s390: Introduce read/write ARM sysreg instructions
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (11 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 12/26] KVM: arm64: Add PVM_ prefix to avoid name collisions Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 14/26] s390: Introduce Query Available Arm features Steffen Eiden
` (12 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Introduce Extract Arm System Register and Store Arm System Register to
enable s390 hosts to read and write system registers for arm64 guests.
The new instructions use the new RIE_H instruction format. Add assembler
macros to create instructions in RIE_H format manually. Add Support for
disassembling the new instructions.
Co-developed-by: Andreas Grapentin <gra@linux.ibm.com>
Signed-off-by: Andreas Grapentin <gra@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/include/asm/sae-asm.h | 48 +++++++++++++++++++++++++++
arch/s390/include/asm/sae.h | 58 +++++++++++++++++++++++++++++++++
arch/s390/kernel/dis.c | 1 +
arch/s390/tools/opcodes.txt | 2 ++
4 files changed, 109 insertions(+)
create mode 100644 arch/s390/include/asm/sae-asm.h
diff --git a/arch/s390/include/asm/sae-asm.h b/arch/s390/include/asm/sae-asm.h
new file mode 100644
index 000000000000..d81ed89eb4ed
--- /dev/null
+++ b/arch/s390/include/asm/sae-asm.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_S390_SAE_ASM_H
+#define __ASM_S390_SAE_ASM_H
+
+#ifdef __ASSEMBLER__
+
+.macro GPR_NUM opd gr
+ \opd = 255
+ .irp rs,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+ .ifc \gr,%r\rs
+ \opd = \rs
+ .endif
+ .endr
+ .if \opd == 255
+ \opd = \gr
+ .endif
+.endm
+
+/*
+ * RIE_H - RIE-h instruction format
+ *
+ * RIE-h format: <insn> R1, R3, I2, M4
+ * +--------+----+----+----+-----------------+----+--------+
+ * | OpCode | R1 |////| R3 | I2 | M4 | Opcode |
+ * +--------+----+----+----+-----------------+----+--------+
+ * 0 8 12 16 20 36 40 47
+ */
+.macro RIE_H opc, gr1, gr3, imm2, m4
+ GPR_NUM r1, \gr1
+ GPR_NUM r3, \gr3
+ .byte (\opc & 0xff00) >> 8
+ .byte r1 << 4
+ .byte (r3 << 4) | ((\imm2 & 0xf000) >> 12)
+ .byte ((\imm2 & 0x0ff0) >> 4)
+ .byte ((\imm2 & 0x000f) << 4) | (\m4 & 0xf)
+ .byte \opc & 0xff
+.endm
+
+.macro SASR r1, r3, i2, m4
+ RIE_H 0xed99, \r1, \r3, \i2, \m4,
+.endm
+
+.macro EASR r1, r3, i2, m4
+ RIE_H 0xed9b, \r1, \r3, \i2, \m4,
+.endm
+
+#endif /* __ASSEMBLER__ */
+#endif /* __ASM_S390_SAE_ASM_H */
diff --git a/arch/s390/include/asm/sae.h b/arch/s390/include/asm/sae.h
index fe010a1a7729..1d9a16b91b23 100644
--- a/arch/s390/include/asm/sae.h
+++ b/arch/s390/include/asm/sae.h
@@ -4,6 +4,7 @@
#include "linux/linkage.h"
#include <linux/types.h>
+#include <asm/sae-asm.h>
/* defined in arch/s390/kernel/entry.S */
asmlinkage int __sae64a(phys_addr_t sae_block_phys);
@@ -12,6 +13,12 @@ asmlinkage int __sae64a(phys_addr_t sae_block_phys);
#include <linux/io.h>
#include <asm/kvm_host_arm64_types.h>
+asm(".include \"asm/sae-asm.h\"\n");
+
+#define _SAE_ASR_REG_SHIFT 5
+#define SASR_FLAG_INITIALIZED 0x8
+#define EASR_FLAG_SA 0x8
+
/**
* __sae64a() - Start Arm Execution
*/
@@ -20,6 +27,57 @@ static inline void sae64a(struct kvm_sae_block *sae_block)
__sae64a(virt_to_phys(sae_block));
}
+/**
+ * sasr() - Set Arm System Register
+ * @arm_reg: ARM system register identifier; compile-time constant
+ * @val: Value to set
+ * @save_area: Pointer to SAE save area
+ * @flags: Operation flags; compile-time constant
+ *
+ * Sets an ARM system register value.
+ */
+static __always_inline void sasr(unsigned int arm_reg, u64 val,
+ struct kvm_sae_save_area *save_area,
+ u64 flags)
+{
+ struct kvm_sae_save_area *sdo = (void *)save_area->sdo;
+ u16 reg = arm_reg >> _SAE_ASR_REG_SHIFT;
+
+ asm volatile (
+ " SASR %[r1],%[r3],%[i2],%[m4]\n"
+ : "+m" (*save_area), "+m" (*sdo)
+ : [r1] "d" (val),
+ [r3] "a" (save_area), [i2] "K" (reg), [m4] "I" (flags)
+ );
+}
+
+/**
+ * easr() - Extract Arm System Register
+ * @arm_reg: ARM system register identifier; compile-time constant
+ * @save_area: Pointer to SAE save area
+ * @flags: Operation flags; compile-time constant
+ *
+ * Reads an ARM system register value.
+ *
+ * Return: Register value
+ */
+static __always_inline u64 easr(unsigned int arm_reg,
+ const struct kvm_sae_save_area *save_area,
+ u64 flags)
+{
+ struct kvm_sae_save_area *sdo = (void *)save_area->sdo;
+ u16 reg = arm_reg >> _SAE_ASR_REG_SHIFT;
+ u64 val;
+
+ asm volatile(
+ " EASR %[r1],%[r3],%[i2],%[m4]\n"
+ : [r1] "=d"(val)
+ : "m"(*save_area),
+ "m"(*sdo), [r3] "a"(save_area), [i2] "K"(reg), [m4] "I"(flags)
+ );
+ return val;
+}
+
/**
* stiasrm() - STore and Invalidate Arm System Register Multiple
* @save_area: Pointer to SAE save area
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index 1cec93895b3a..6ff8fd09d5bc 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -208,6 +208,7 @@ static const unsigned char formats[][6] = {
[INSTR_RIE_RUI0] = { R_8, I16_16, U4_12, 0, 0, 0 },
[INSTR_RIE_RUPI] = { R_8, I8_32, U4_12, J16_16, 0, 0 },
[INSTR_RIE_RUPU] = { R_8, U8_32, U4_12, J16_16, 0, 0 },
+ [INSTR_RIE_R0RIU] = { R_8, R_16, U16_20, U4_36, 0, 0 },
[INSTR_RIL_RI] = { R_8, I32_16, 0, 0, 0, 0 },
[INSTR_RIL_RP] = { R_8, J32_16, 0, 0, 0, 0 },
[INSTR_RIL_RU] = { R_8, U32_16, 0, 0, 0, 0 },
diff --git a/arch/s390/tools/opcodes.txt b/arch/s390/tools/opcodes.txt
index 0e4773c94af0..18af14071290 100644
--- a/arch/s390/tools/opcodes.txt
+++ b/arch/s390/tools/opcodes.txt
@@ -1255,6 +1255,8 @@ ed64 ley RXY_FRRD
ed65 ldy RXY_FRRD
ed66 stey RXY_FRRD
ed67 stdy RXY_FRRD
+ed99 sasr RIE_R0RIU
+ed9b easr RIE_R0RIU
eda8 czdt RSL_LRDFU
eda9 czxt RSL_LRDFU
edaa cdzt RSL_LRDFU
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 14/26] s390: Introduce Query Available Arm features
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (12 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 13/26] s390: Introduce read/write ARM sysreg instructions Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 15/26] s390: Add functions to query arm guest time Steffen Eiden
` (11 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
QAAF enables s390 hosts to gain information about the support
and handling of various arm features supported by the machine.
Function code 1 provides general information about available formats,
machine defined content of system/id register, and other various
information for running arm guests.
Co-developed-by: Andreas Grapentin <gra@linux.ibm.com>
Signed-off-by: Andreas Grapentin <gra@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/include/asm/kvm_host_arm64_types.h | 96 ++++++++++++++++++++
arch/s390/include/asm/sae.h | 28 ++++++
arch/s390/tools/opcodes.txt | 1 +
3 files changed, 125 insertions(+)
diff --git a/arch/s390/include/asm/kvm_host_arm64_types.h b/arch/s390/include/asm/kvm_host_arm64_types.h
index 3882d5462a05..16f7018a1714 100644
--- a/arch/s390/include/asm/kvm_host_arm64_types.h
+++ b/arch/s390/include/asm/kvm_host_arm64_types.h
@@ -126,4 +126,100 @@ struct kvm_sae_save_area {
} __packed __aligned(PAGE_SIZE);
static_assert(sizeof(struct kvm_sae_save_area) == PAGE_SIZE);
+#define QAAF_FC_QMC 1
+
+/* QAAF Query Model Capabilities */
+struct qaaf_qmc_block {
+ u64 _0000; /* 0x0000 */
+ u8 ssdf; /* 0x0008 */
+ u8 _0009; /* 0x0009 */
+ u8 ssaf; /* 0x000a */
+ u8 _000b[3]; /* 0x000b */
+ u16 maxncpu; /* 0x000e */
+ u64 regs[0x1fe]; /* 0x0010 */
+} __aligned(PAGE_SIZE);
+static_assert(sizeof(struct qaaf_qmc_block) == PAGE_SIZE);
+
+union qaaf_block {
+ struct qaaf_qmc_block qmc;
+} __aligned(PAGE_SIZE);
+static_assert(sizeof(union qaaf_block) == PAGE_SIZE);
+
+/*
+ * Keep in sync with mapping from SYS_* to QAAF_* in feature.c!
+ */
+enum {
+ QAAF_REG_MIDR_EL1 = 0x02,
+ /* 0x03 -0x06 reserved */
+ QAAF_REG_MPIDR_EL1 = 0x07,
+ QAAF_REG_REVIDR_EL1 = 0x08,
+ /* 0x09 reserved */
+ QAAF_REG_ID_PFR0_EL1 = 0x0a,
+ QAAF_REG_ID_PFR1_EL1 = 0x0b,
+ QAAF_REG_ID_DFR0_EL1 = 0x0c,
+ QAAF_REG_ID_AFR0_EL1 = 0x0d,
+ QAAF_REG_ID_MMFR0_EL1 = 0x0e,
+ QAAF_REG_ID_MMFR1_EL1 = 0x0f,
+ QAAF_REG_ID_MMFR2_EL1 = 0x10,
+ QAAF_REG_ID_MMFR3_EL1 = 0x11,
+ QAAF_REG_ID_ISAR0_EL1 = 0x12,
+ QAAF_REG_ID_ISAR1_EL1 = 0x13,
+ QAAF_REG_ID_ISAR2_EL1 = 0x14,
+ QAAF_REG_ID_ISAR3_EL1 = 0x15,
+ QAAF_REG_ID_ISAR4_EL1 = 0x16,
+ QAAF_REG_ID_ISAR5_EL1 = 0x17,
+ QAAF_REG_ID_MMFR4_EL1 = 0x18,
+ QAAF_REG_ID_ISAR6_EL1 = 0x19,
+ QAAF_REG_MVFR0_EL1 = 0x1a,
+ QAAF_REG_MVFR1_EL1 = 0x1b,
+ QAAF_REG_MVFR2_EL1 = 0x1c,
+ /* 0x1d reserved */
+ QAAF_REG_ID_PFR2_EL1 = 0x1e,
+ QAAF_REG_ID_DFR1_EL1 = 0x1f,
+ QAAF_REG_ID_MMFR5_EL1 = 0x20,
+ /* 0x21 reserved */
+ QAAF_REG_ID_AA64PFR0_EL1 = 0x22,
+ QAAF_REG_ID_AA64PFR1_EL1 = 0x23,
+ QAAF_REG_ID_AA64PFR2_EL1 = 0x24,
+ /* 0x25 reserved */
+ QAAF_REG_ID_AA64ZFR0_EL1 = 0x26,
+ QAAF_REG_ID_AA64SMFR0_EL1 = 0x27,
+ /* 0x28 reserved */
+ QAAF_REG_ID_AA64FPFR0_EL1 = 0x29,
+ QAAF_REG_ID_AA64DFR0_EL1 = 0x2a,
+ QAAF_REG_ID_AA64DFR1_EL1 = 0x2b,
+ QAAF_REG_ID_AA64DFR2_EL1 = 0x2c,
+ /* 0x2d reserved */
+ QAAF_REG_ID_AA64AFR0_EL1 = 0x2e,
+ QAAF_REG_ID_AA64AFR1_EL1 = 0x2f,
+ /* 0x30,0x31 reserved */
+ QAAF_REG_ID_AA64ISAR0_EL1 = 0x32,
+ QAAF_REG_ID_AA64ISAR1_EL1 = 0x33,
+ QAAF_REG_ID_AA64ISAR2_EL1 = 0x34,
+ QAAF_REG_ID_AA64ISAR3_EL1 = 0x35,
+ /* 0x36-0x39 reserved */
+ QAAF_REG_ID_AA64MMFR0_EL1 = 0x3a,
+ QAAF_REG_ID_AA64MMFR1_EL1 = 0x3b,
+ QAAF_REG_ID_AA64MMFR2_EL1 = 0x3c,
+ QAAF_REG_ID_AA64MMFR3_EL1 = 0x3d,
+ QAAF_REG_ID_AA64MMFR4_EL1 = 0x3e,
+ /* 0x3f-0x41 reserved */
+ QAAF_REG_CNTFRQ_EL0 = 0x42,
+ QAAF_REG_CTR_EL0 = 0x43,
+ /* 0x44-0x49 reserved */
+ QAAF_IRPTC = 0x4a,
+ /* 0x4b reserved */
+ QAAF_REG_ICH_VTR_EL2 = 0x4c,
+ QAAF_GIC_ATTR = 0x4d,
+ /* 0x4E-0x51 reserved */
+ QAAF_REG_PMMIR_EL1 = 0x52,
+ QAAF_REG_PMCR_EL0 = 0x53,
+ QAAF_REG_PMCEID0_EL0 = 0x54,
+ QAAF_REG_PMCEID1_EL0 = 0x55,
+ /* 0x56-0x1ff reserved */
+ _QAAF_MAX
+};
+
+static_assert(sizeof(struct qaaf_qmc_block) / 8 + 1 >= _QAAF_MAX);
+
#endif /* ASM_KVM_HOST_ARM64_TYPES_H */
diff --git a/arch/s390/include/asm/sae.h b/arch/s390/include/asm/sae.h
index 1d9a16b91b23..f6f79443d6ce 100644
--- a/arch/s390/include/asm/sae.h
+++ b/arch/s390/include/asm/sae.h
@@ -110,5 +110,33 @@ static __always_inline void lasrm(struct kvm_sae_save_area *save_area)
);
}
+/**
+ * qaaf() - Query Available Arm Features
+ * @gr0: QAAF function code, placed in greg 0
+ * @qaaf_block: Pointer to the page for the output
+ *
+ * Perform QAAF. The result ins written to qaaf_block.
+ */
+static __always_inline void qaaf(u64 gr0, union qaaf_block *qaaf_block)
+{
+ asm volatile(
+ " lgr 0,%[r0]\n"
+ " .insn rre,0xb9ad0000,%[r1],0"
+ : "=m"(*qaaf_block)
+ : [r1] "a"(qaaf_block), [r0] "d"(gr0)
+ : "r0"
+ );
+}
+
+/**
+ * qaaf_qmc() - Query Available Arm Features for Model Capabilities
+ * @qmc: Pointer to qaaf_qmc_block structure to receive model capabilities
+ *
+ */
+static __always_inline void qaaf_qmc(struct qaaf_qmc_block *qmc)
+{
+ qaaf(QAAF_FC_QMC, (union qaaf_block *)qmc);
+}
+
#endif /* !__ASSEMBLER__ */
#endif /* __ASM_S390_SAE_H */
diff --git a/arch/s390/tools/opcodes.txt b/arch/s390/tools/opcodes.txt
index 18af14071290..fd5483107961 100644
--- a/arch/s390/tools/opcodes.txt
+++ b/arch/s390/tools/opcodes.txt
@@ -600,6 +600,7 @@ b9a7 stiasrm RRE_R0
b9aa lptea RRF_RURR2
b9ab essa RRF_U0RR
b9ac irbm RRE_RR
+b9ad qaaf RRE_R0
b9ae rrbm RRE_RR
b9af pfmf RRE_RR
b9b0 cu14 RRF_U0RR
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 15/26] s390: Add functions to query arm guest time
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (13 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 14/26] s390: Introduce Query Available Arm features Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-06-01 22:25 ` Oliver Upton
2026-05-29 15:55 ` [PATCH v1 16/26] KVM: s390: arm64: Add sysreg related functions and definitions Steffen Eiden
` (10 subsequent siblings)
25 siblings, 1 reply; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Add functions to convert between ARM guest time (LSB0) and s390 host
time (MSB0) using new ptff function codes.
Co-developed-by: Nico Boehr <nrb@linux.ibm.com>
Signed-off-by: Nico Boehr <nrb@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/include/asm/timex.h | 49 +++++++++++++++++++++++++++++++++++
arch/s390/kernel/time.c | 1 +
arch/s390/kvm/arm64/arm.c | 9 ++++++-
3 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h
index 49447b40f038..9ec22a28bbda 100644
--- a/arch/s390/include/asm/timex.h
+++ b/arch/s390/include/asm/timex.h
@@ -99,6 +99,8 @@ extern unsigned char ptff_function_mask[16];
#define PTFF_QSI 0x02 /* query steering information */
#define PTFF_QPT 0x03 /* query physical clock */
#define PTFF_QUI 0x04 /* query UTC information */
+#define PTFF_QAGTO 0x10 /* query arm guest time offset */
+#define PTFF_QAGPT 0x11 /* query arm guest physical time offset */
#define PTFF_ATO 0x40 /* adjust tod offset */
#define PTFF_STO 0x41 /* set tod offset */
#define PTFF_SFS 0x42 /* set fine steering rate */
@@ -136,6 +138,17 @@ struct ptff_qui {
unsigned int pad_0x5c[41];
} __packed;
+/*
+ * Query Arm Guest Time
+ * used for:
+ * - Query Arm Guest Time Offset
+ * - Query Arm Guest Physical Time
+ */
+struct ptff_qagt {
+ u64 in;
+ u64 out;
+};
+
/*
* ptff - Perform timing facility function
* @ptff_block: Pointer to ptff parameter block
@@ -286,4 +299,40 @@ static inline int tod_after_eq(unsigned long a, unsigned long b)
return a >= b;
}
+/*
+ * ptff_qagto() - Query Arm Guest Time Offset
+ *
+ * @physical_time: Arm guest physical time in MSb 0
+ *
+ * Converts Arm guest physical time in MSb 0 bit ordering
+ * into the Arm guest offset in LSb 0 bit ordering.
+ *
+ * Return: Arm guest time offset in LSb 0
+ */
+static inline u64 ptff_qagto(u64 physical_time)
+{
+ struct ptff_qagt qagto = { .in = physical_time };
+
+ ptff(&qagto, sizeof(qagto), PTFF_QAGTO);
+ return qagto.out;
+}
+
+/*
+ * ptff_qagpt() - Query Arm Guest Physical Time
+ *
+ * @guest_time_offset: Arm guest time offset in MSb 0
+ *
+ * Converts Arm guest offset in MSb 0 bit ordering
+ * into the Arm guest physical time in LSb 0 bit ordering.
+ *
+ * Return: Arm guest physical time in LSb 0
+ * */
+static inline u64 ptff_qagpt(u64 guest_time_offset)
+{
+ struct ptff_qagt qagpt = { .in = guest_time_offset };
+
+ ptff(&qagpt, sizeof(qagpt), PTFF_QAGPT);
+ return qagpt.out;
+}
+
#endif
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index bd0df61d1907..2b989bebd220 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -65,6 +65,7 @@ ATOMIC_NOTIFIER_HEAD(s390_epoch_delta_notifier);
EXPORT_SYMBOL(s390_epoch_delta_notifier);
unsigned char ptff_function_mask[16];
+EXPORT_SYMBOL(ptff_function_mask);
static unsigned long lpar_offset;
static unsigned long initial_leap_seconds;
diff --git a/arch/s390/kvm/arm64/arm.c b/arch/s390/kvm/arm64/arm.c
index bf0866659421..636bbeda98a8 100644
--- a/arch/s390/kvm/arm64/arm.c
+++ b/arch/s390/kvm/arm64/arm.c
@@ -692,8 +692,15 @@ long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,
static int __init kvm_s390_arm64_init(void)
{
- if (!sclp.has_aef)
+ if (!sclp.has_aef) {
+ pr_info("SAE is not available\n");
return -ENXIO;
+ }
+
+ if (!(ptff_query(PTFF_QAGTO) && ptff_query(PTFF_QAGPT))) {
+ pr_info("PTFF for arm on s390 is not available\n");
+ return -ENXIO;
+ }
return kvm_init_with_dev(sizeof(struct kvm_vcpu), 0, THIS_MODULE,
KVM_DEV_NAME, MISC_DYNAMIC_MINOR);
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 16/26] KVM: s390: arm64: Add sysreg related functions and definitions
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (14 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 15/26] s390: Add functions to query arm guest time Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 17/26] arm64: Extract cputype definitions Steffen Eiden
` (9 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Add guest sysreg access macros in asm/kvm_host_arm64.h using
easr()/sasr()-based helpers for sysregs that map to the SAE save area.
Also add the guest-visible sysreg enum and per-vCPU/per-VM storage for
state that is not directly covered by the save area, such as CLIDR_EL1,
CSSELR_EL1, MPIDR_EL1, and VM-wide ID register state.
This lays out the header-side definitions needed to ensure compilation
success during for the share-code-patches and later sysreg handling
during vCPU setup and runtime.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/include/asm/kvm_host_arm64.h | 165 +++++++++++++++++++++++++
1 file changed, 165 insertions(+)
diff --git a/arch/s390/include/asm/kvm_host_arm64.h b/arch/s390/include/asm/kvm_host_arm64.h
index 8c3214c5b004..d6d9e3ad7a8e 100644
--- a/arch/s390/include/asm/kvm_host_arm64.h
+++ b/arch/s390/include/asm/kvm_host_arm64.h
@@ -44,10 +44,19 @@ struct kvm_vcpu_arch {
struct kvm_sae_save_area save_area;
struct kvm_cpu_context ctxt;
+ /* Guest system registers not part of save area or ID registers */
+ u64 sys_reg_clidr_el1;
+ u64 sys_reg_csselr_el1;
+ /* Per-vcpu CCSIDR override or NULL */
+ u32 *ccsidr;
+
u32 host_acrs[NUM_ACRS];
/* Hypervisor Configuration Register */
u64 hcr_elz;
+ u64 hcrx_elz;
+
+ u64 mpidr;
/* Configuration flags, set once and for all before the vcpu can run */
u8 cflags;
@@ -209,4 +218,160 @@ static inline void kvm_arch_async_page_present_queued(struct kvm_vcpu *vcpu)
#define kvm_supports_32bit_el0() false
+#define vcpu_read_sys_reg(_v, _r) 0xbad1234bad
+#define vcpu_write_sys_reg(_v, _p, _r) ((void)0)
+
+#define __vcpu_sys_reg(__vcpu, __reg) \
+ vcpu_read_sys_reg(__vcpu, __reg)
+
+#define __vcpu_assign_sys_reg(__vcpu, __reg, __val) \
+ vcpu_write_sys_reg(__vcpu, __val, __reg)
+
+/* Read, modify and write system register
+ *
+ */
+#define _vcpu_rmw_sys_reg(C, V, OP, R) \
+({ \
+ u64 __val = vcpu_read_sys_reg(C, R); \
+ __val OP V; \
+ vcpu_write_sys_reg(C, __val, R); \
+})
+
+/**
+ * _vcpu_read_sys_reg() - read a guest sysreg with easr
+ * - R - sysreg id; must be readable by easr; must be compile time constant
+ *
+ * if SYSREGS_ON_CPU: proceed with flags = 0
+ * otherwise: proceed with either
+ * read: flags = EASR_FLAG_SA
+ * write: flags = SASR_FLAG_INITIALIZED
+ *
+ */
+#define _vcpu_read_sys_reg(C, R) \
+ ({ BUILD_BUG_ON(!__builtin_constant_p((R))); \
+ BUG_ON(vcpu_is_loaded(C) && smp_processor_id() != (C)->cpu); \
+ (vcpu_is_loaded(C)) \
+ ? __vcpu_read_sr((C), (R), 0) \
+ : __vcpu_read_sr((C), (R), EASR_FLAG_SA); })
+
+/**
+ * _vcpu_write_sys_reg() - write a guest sysreg with sasr
+ * - R - sysreg id; must be readable by sasr; must be compile time constant
+
+ * if SYSREGS_ON_CPU: proceed with flags = 0
+ * otherwise: proceed with either
+ * read: flags = EASR_FLAG_SA
+ * write: flags = SASR_FLAG_INITIALIZED
+ */
+#define _vcpu_write_sys_reg(C, V, R) \
+ ({ BUILD_BUG_ON(!__builtin_constant_p((R))); \
+ BUG_ON(vcpu_is_loaded(C) && smp_processor_id() != (C)->cpu); \
+ (vcpu_is_loaded(C)) \
+ ? __vcpu_write_sr((C), (V), (R), 0) \
+ : __vcpu_write_sr((C), (V), (R), SASR_FLAG_INITIALIZED); })
+
+/* Forward to easr / sasr
+ * assert that F and R are constant
+ */
+#define __vcpu_read_sr(C, R, F) \
+ ({ BUILD_BUG_ON(!__builtin_constant_p((R))); \
+ BUILD_BUG_ON(!__builtin_constant_p((F))); \
+ easr((R), &(C)->arch.save_area, (F)); })
+
+#define __vcpu_write_sr(C, V, R, F) \
+ ({ BUILD_BUG_ON(!__builtin_constant_p((R))); \
+ BUILD_BUG_ON(!__builtin_constant_p((F))); \
+ sasr((R), (V), &(C)->arch.save_area, (F)); })
+
+#define SR_GROUP(NAME, ...) \
+ __##NAME##_BEGIN__, \
+ __VA_ARGS__ \
+ __##NAME##_END__
+
+/** enum vcpu_sysreg - available guest sysregs
+ *
+ * Contains all arm64 guest-syregs supported by s390.
+ */
+enum vcpu_sysreg {
+ __INVALID_SYSREG__, /* 0 is reserved as an invalid value */
+
+ /* EL 0,1 Register from state description in order of appearance */
+ SR_GROUP(STATE_DESC,
+ CNTP_CTL_EL0,
+ CNTV_CTL_EL0,
+ CONTEXTIDR_EL1,
+ SP_EL1,
+ ),
+
+ /* EL 0,1 Register requiring special handling. */
+ SR_GROUP(SPECIAL,
+ CSSELR_EL1,
+ CLIDR_EL1,
+ MPIDR_EL1,
+ ),
+
+ /* EL 0,1 register from save area in order of appearance */
+ SR_GROUP(SAVE_AREA,
+ ACTLR_EL1,
+ AFSR0_EL1,
+ AFSR1_EL1,
+ CNTFRQ_EL0,
+ CNTP_CVAL_EL0,
+ CNTV_CVAL_EL0,
+ DISR_EL1,
+ MIDR_EL1,
+ OSLSR_EL1,
+ PAR_EL1,
+ OSLAR_EL1,
+ SCTLR_EL1,
+ CPACR_EL1,
+ VBAR_EL1,
+ SPSR_EL1,
+ ELR_EL1,
+ ESR_EL1,
+ TCR_EL1,
+ MAIR_EL1,
+ TTBR0_EL1,
+ TTBR1_EL1,
+ FAR_EL1,
+ TPIDR_EL0,
+ TPIDR_EL1,
+ TPIDRRO_EL0,
+ CNTKCTL_EL1,
+ ZCR_EL1,
+ SCXTNUM_EL0,
+ SCXTNUM_EL1,
+ APIBKEYLO_EL1,
+ APIBKEYHI_EL1,
+ APIAKEYLO_EL1,
+ APIAKEYHI_EL1,
+ APGAKEYLO_EL1,
+ APGAKEYHI_EL1,
+ APDBKEYLO_EL1,
+ APDBKEYHI_EL1,
+ APDAKEYLO_EL1,
+ APDAKEYHI_EL1,
+ MDSCR_EL1,
+ ),
+
+ NR_SYS_REGS /* Nothing after this line! */
+};
+
+void vcpu_write_host_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg);
+u64 vcpu_read_host_sys_reg(const struct kvm_vcpu *vcpu, int reg);
+
+#define kvm_debug_handle_oslar(_v, _val) /* debug not implemented yet*/
+
+static inline u8 kvm_arm_pmu_get_pmuver_limit(void)
+{
+ return 0;
+}
+
+int __init kvm_sys_reg_table_init(void);
+
+static inline u64 kvm_sanitised_host_ftr_reg(u32 id)
+{
+ return 0xbad1234bad;
+}
+
#endif /* ASM_KVM_HOST_ARM64_H */
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 17/26] arm64: Extract cputype definitions.
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (15 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 16/26] KVM: s390: arm64: Add sysreg related functions and definitions Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 18/26] arm64: Extract cache definitions Steffen Eiden
` (8 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Move CPU type definitions from arch/arm64/include/asm/cputype.h to
include/arch/arm64/asm/cputype-defs.h to prepare sharing with other
architectures. No functional changes.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/cputype.h | 246 +-----------------
.../arch/arm64/asm/cputype-defs.h | 92 +------
2 files changed, 6 insertions(+), 332 deletions(-)
copy arch/arm64/include/asm/cputype.h => include/arch/arm64/asm/cputype-defs.h (85%)
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 7b518e81dd15..67765cdbce84 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -5,251 +5,7 @@
#ifndef __ASM_CPUTYPE_H
#define __ASM_CPUTYPE_H
-#define INVALID_HWID ULONG_MAX
-
-#define MPIDR_UP_BITMASK (0x1 << 30)
-#define MPIDR_MT_BITMASK (0x1 << 24)
-#define MPIDR_HWID_BITMASK UL(0xff00ffffff)
-
-#define MPIDR_LEVEL_BITS_SHIFT 3
-#define MPIDR_LEVEL_BITS (1 << MPIDR_LEVEL_BITS_SHIFT)
-#define MPIDR_LEVEL_MASK ((1 << MPIDR_LEVEL_BITS) - 1)
-
-#define MPIDR_LEVEL_SHIFT(level) \
- (((1 << level) >> 1) << MPIDR_LEVEL_BITS_SHIFT)
-
-#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
- ((mpidr >> MPIDR_LEVEL_SHIFT(level)) & MPIDR_LEVEL_MASK)
-
-#define MIDR_REVISION_MASK 0xf
-#define MIDR_REVISION(midr) ((midr) & MIDR_REVISION_MASK)
-#define MIDR_PARTNUM_SHIFT 4
-#define MIDR_PARTNUM_MASK (0xfff << MIDR_PARTNUM_SHIFT)
-#define MIDR_PARTNUM(midr) \
- (((midr) & MIDR_PARTNUM_MASK) >> MIDR_PARTNUM_SHIFT)
-#define MIDR_ARCHITECTURE_SHIFT 16
-#define MIDR_ARCHITECTURE_MASK (0xf << MIDR_ARCHITECTURE_SHIFT)
-#define MIDR_ARCHITECTURE(midr) \
- (((midr) & MIDR_ARCHITECTURE_MASK) >> MIDR_ARCHITECTURE_SHIFT)
-#define MIDR_VARIANT_SHIFT 20
-#define MIDR_VARIANT_MASK (0xf << MIDR_VARIANT_SHIFT)
-#define MIDR_VARIANT(midr) \
- (((midr) & MIDR_VARIANT_MASK) >> MIDR_VARIANT_SHIFT)
-#define MIDR_IMPLEMENTOR_SHIFT 24
-#define MIDR_IMPLEMENTOR_MASK (0xffU << MIDR_IMPLEMENTOR_SHIFT)
-#define MIDR_IMPLEMENTOR(midr) \
- (((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT)
-
-#define MIDR_CPU_MODEL(imp, partnum) \
- ((_AT(u32, imp) << MIDR_IMPLEMENTOR_SHIFT) | \
- (0xf << MIDR_ARCHITECTURE_SHIFT) | \
- ((partnum) << MIDR_PARTNUM_SHIFT))
-
-#define MIDR_CPU_VAR_REV(var, rev) \
- (((var) << MIDR_VARIANT_SHIFT) | (rev))
-
-#define MIDR_CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \
- MIDR_ARCHITECTURE_MASK)
-
-#define ARM_CPU_IMP_ARM 0x41
-#define ARM_CPU_IMP_APM 0x50
-#define ARM_CPU_IMP_CAVIUM 0x43
-#define ARM_CPU_IMP_BRCM 0x42
-#define ARM_CPU_IMP_QCOM 0x51
-#define ARM_CPU_IMP_NVIDIA 0x4E
-#define ARM_CPU_IMP_FUJITSU 0x46
-#define ARM_CPU_IMP_HISI 0x48
-#define ARM_CPU_IMP_APPLE 0x61
-#define ARM_CPU_IMP_AMPERE 0xC0
-#define ARM_CPU_IMP_MICROSOFT 0x6D
-
-#define ARM_CPU_PART_AEM_V8 0xD0F
-#define ARM_CPU_PART_FOUNDATION 0xD00
-#define ARM_CPU_PART_CORTEX_A57 0xD07
-#define ARM_CPU_PART_CORTEX_A72 0xD08
-#define ARM_CPU_PART_CORTEX_A53 0xD03
-#define ARM_CPU_PART_CORTEX_A73 0xD09
-#define ARM_CPU_PART_CORTEX_A75 0xD0A
-#define ARM_CPU_PART_CORTEX_A35 0xD04
-#define ARM_CPU_PART_CORTEX_A55 0xD05
-#define ARM_CPU_PART_CORTEX_A76 0xD0B
-#define ARM_CPU_PART_NEOVERSE_N1 0xD0C
-#define ARM_CPU_PART_CORTEX_A77 0xD0D
-#define ARM_CPU_PART_CORTEX_A76AE 0xD0E
-#define ARM_CPU_PART_NEOVERSE_V1 0xD40
-#define ARM_CPU_PART_CORTEX_A78 0xD41
-#define ARM_CPU_PART_CORTEX_A78AE 0xD42
-#define ARM_CPU_PART_CORTEX_X1 0xD44
-#define ARM_CPU_PART_CORTEX_A510 0xD46
-#define ARM_CPU_PART_CORTEX_A520 0xD80
-#define ARM_CPU_PART_CORTEX_A710 0xD47
-#define ARM_CPU_PART_CORTEX_A715 0xD4D
-#define ARM_CPU_PART_CORTEX_X2 0xD48
-#define ARM_CPU_PART_NEOVERSE_N2 0xD49
-#define ARM_CPU_PART_CORTEX_A78C 0xD4B
-#define ARM_CPU_PART_CORTEX_X1C 0xD4C
-#define ARM_CPU_PART_CORTEX_X3 0xD4E
-#define ARM_CPU_PART_NEOVERSE_V2 0xD4F
-#define ARM_CPU_PART_CORTEX_A720 0xD81
-#define ARM_CPU_PART_CORTEX_X4 0xD82
-#define ARM_CPU_PART_NEOVERSE_V3AE 0xD83
-#define ARM_CPU_PART_NEOVERSE_V3 0xD84
-#define ARM_CPU_PART_CORTEX_X925 0xD85
-#define ARM_CPU_PART_CORTEX_A725 0xD87
-#define ARM_CPU_PART_CORTEX_A720AE 0xD89
-#define ARM_CPU_PART_NEOVERSE_N3 0xD8E
-#define ARM_CPU_PART_C1_PRO 0xD8B
-
-#define APM_CPU_PART_XGENE 0x000
-#define APM_CPU_VAR_POTENZA 0x00
-
-#define CAVIUM_CPU_PART_THUNDERX 0x0A1
-#define CAVIUM_CPU_PART_THUNDERX_81XX 0x0A2
-#define CAVIUM_CPU_PART_THUNDERX_83XX 0x0A3
-#define CAVIUM_CPU_PART_THUNDERX2 0x0AF
-/* OcteonTx2 series */
-#define CAVIUM_CPU_PART_OCTX2_98XX 0x0B1
-#define CAVIUM_CPU_PART_OCTX2_96XX 0x0B2
-#define CAVIUM_CPU_PART_OCTX2_95XX 0x0B3
-#define CAVIUM_CPU_PART_OCTX2_95XXN 0x0B4
-#define CAVIUM_CPU_PART_OCTX2_95XXMM 0x0B5
-#define CAVIUM_CPU_PART_OCTX2_95XXO 0x0B6
-
-#define BRCM_CPU_PART_BRAHMA_B53 0x100
-#define BRCM_CPU_PART_VULCAN 0x516
-
-#define QCOM_CPU_PART_FALKOR_V1 0x800
-#define QCOM_CPU_PART_FALKOR 0xC00
-#define QCOM_CPU_PART_KRYO 0x200
-#define QCOM_CPU_PART_KRYO_2XX_GOLD 0x800
-#define QCOM_CPU_PART_KRYO_2XX_SILVER 0x801
-#define QCOM_CPU_PART_KRYO_3XX_GOLD 0x802
-#define QCOM_CPU_PART_KRYO_3XX_SILVER 0x803
-#define QCOM_CPU_PART_KRYO_4XX_GOLD 0x804
-#define QCOM_CPU_PART_KRYO_4XX_SILVER 0x805
-#define QCOM_CPU_PART_ORYON_X1 0x001
-
-#define NVIDIA_CPU_PART_DENVER 0x003
-#define NVIDIA_CPU_PART_CARMEL 0x004
-#define NVIDIA_CPU_PART_OLYMPUS 0x010
-
-#define FUJITSU_CPU_PART_A64FX 0x001
-
-#define HISI_CPU_PART_TSV110 0xD01
-#define HISI_CPU_PART_HIP09 0xD02
-#define HISI_CPU_PART_HIP12 0xD06
-
-#define APPLE_CPU_PART_M1_ICESTORM 0x022
-#define APPLE_CPU_PART_M1_FIRESTORM 0x023
-#define APPLE_CPU_PART_M1_ICESTORM_PRO 0x024
-#define APPLE_CPU_PART_M1_FIRESTORM_PRO 0x025
-#define APPLE_CPU_PART_M1_ICESTORM_MAX 0x028
-#define APPLE_CPU_PART_M1_FIRESTORM_MAX 0x029
-#define APPLE_CPU_PART_M2_BLIZZARD 0x032
-#define APPLE_CPU_PART_M2_AVALANCHE 0x033
-#define APPLE_CPU_PART_M2_BLIZZARD_PRO 0x034
-#define APPLE_CPU_PART_M2_AVALANCHE_PRO 0x035
-#define APPLE_CPU_PART_M2_BLIZZARD_MAX 0x038
-#define APPLE_CPU_PART_M2_AVALANCHE_MAX 0x039
-
-#define AMPERE_CPU_PART_AMPERE1 0xAC3
-#define AMPERE_CPU_PART_AMPERE1A 0xAC4
-
-#define MICROSOFT_CPU_PART_AZURE_COBALT_100 0xD49 /* Based on r0p0 of ARM Neoverse N2 */
-
-#define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
-#define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
-#define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72)
-#define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73)
-#define MIDR_CORTEX_A75 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A75)
-#define MIDR_CORTEX_A35 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A35)
-#define MIDR_CORTEX_A55 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A55)
-#define MIDR_CORTEX_A76 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76)
-#define MIDR_NEOVERSE_N1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1)
-#define MIDR_CORTEX_A77 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77)
-#define MIDR_CORTEX_A76AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76AE)
-#define MIDR_NEOVERSE_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V1)
-#define MIDR_CORTEX_A78 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78)
-#define MIDR_CORTEX_A78AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78AE)
-#define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1)
-#define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510)
-#define MIDR_CORTEX_A520 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A520)
-#define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
-#define MIDR_CORTEX_A715 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A715)
-#define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
-#define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
-#define MIDR_CORTEX_A78C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C)
-#define MIDR_CORTEX_X1C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1C)
-#define MIDR_CORTEX_X3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X3)
-#define MIDR_NEOVERSE_V2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V2)
-#define MIDR_CORTEX_A720 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A720)
-#define MIDR_CORTEX_X4 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X4)
-#define MIDR_NEOVERSE_V3AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3AE)
-#define MIDR_NEOVERSE_V3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3)
-#define MIDR_CORTEX_X925 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X925)
-#define MIDR_CORTEX_A725 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A725)
-#define MIDR_CORTEX_A720AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A720AE)
-#define MIDR_NEOVERSE_N3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N3)
-#define MIDR_C1_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_C1_PRO)
-#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
-#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
-#define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
-#define MIDR_OCTX2_98XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_OCTX2_98XX)
-#define MIDR_OCTX2_96XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_OCTX2_96XX)
-#define MIDR_OCTX2_95XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_OCTX2_95XX)
-#define MIDR_OCTX2_95XXN MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_OCTX2_95XXN)
-#define MIDR_OCTX2_95XXMM MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_OCTX2_95XXMM)
-#define MIDR_OCTX2_95XXO MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_OCTX2_95XXO)
-#define MIDR_CAVIUM_THUNDERX2 MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX2)
-#define MIDR_BRAHMA_B53 MIDR_CPU_MODEL(ARM_CPU_IMP_BRCM, BRCM_CPU_PART_BRAHMA_B53)
-#define MIDR_BRCM_VULCAN MIDR_CPU_MODEL(ARM_CPU_IMP_BRCM, BRCM_CPU_PART_VULCAN)
-#define MIDR_QCOM_FALKOR_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR_V1)
-#define MIDR_QCOM_FALKOR MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR)
-#define MIDR_QCOM_KRYO MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO)
-#define MIDR_QCOM_KRYO_2XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_2XX_GOLD)
-#define MIDR_QCOM_KRYO_2XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_2XX_SILVER)
-#define MIDR_QCOM_KRYO_3XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_3XX_GOLD)
-#define MIDR_QCOM_KRYO_3XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_3XX_SILVER)
-#define MIDR_QCOM_KRYO_4XX_GOLD MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_4XX_GOLD)
-#define MIDR_QCOM_KRYO_4XX_SILVER MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO_4XX_SILVER)
-#define MIDR_QCOM_ORYON_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_ORYON_X1)
-
-/*
- * NOTES:
- * - Qualcomm Kryo 5XX Prime / Gold ID themselves as MIDR_CORTEX_A77
- * - Qualcomm Kryo 5XX Silver IDs itself as MIDR_QCOM_KRYO_4XX_SILVER
- * - Qualcomm Kryo 6XX Prime IDs itself as MIDR_CORTEX_X1
- * - Qualcomm Kryo 6XX Gold IDs itself as ARM_CPU_PART_CORTEX_A78
- * - Qualcomm Kryo 6XX Silver IDs itself as MIDR_CORTEX_A55
- */
-
-#define MIDR_NVIDIA_DENVER MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_DENVER)
-#define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL)
-#define MIDR_NVIDIA_OLYMPUS MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_OLYMPUS)
-#define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX)
-#define MIDR_HISI_TSV110 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110)
-#define MIDR_HISI_HIP09 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_HIP09)
-#define MIDR_HISI_HIP12 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_HIP12)
-#define MIDR_APPLE_M1_ICESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM)
-#define MIDR_APPLE_M1_FIRESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM)
-#define MIDR_APPLE_M1_ICESTORM_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_PRO)
-#define MIDR_APPLE_M1_FIRESTORM_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_PRO)
-#define MIDR_APPLE_M1_ICESTORM_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_MAX)
-#define MIDR_APPLE_M1_FIRESTORM_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_MAX)
-#define MIDR_APPLE_M2_BLIZZARD MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD)
-#define MIDR_APPLE_M2_AVALANCHE MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE)
-#define MIDR_APPLE_M2_BLIZZARD_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_PRO)
-#define MIDR_APPLE_M2_AVALANCHE_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_PRO)
-#define MIDR_APPLE_M2_BLIZZARD_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_MAX)
-#define MIDR_APPLE_M2_AVALANCHE_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_MAX)
-#define MIDR_AMPERE1 MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1)
-#define MIDR_AMPERE1A MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1A)
-#define MIDR_MICROSOFT_AZURE_COBALT_100 MIDR_CPU_MODEL(ARM_CPU_IMP_MICROSOFT, MICROSOFT_CPU_PART_AZURE_COBALT_100)
-
-/* Fujitsu Erratum 010001 affects A64FX 1.0 and 1.1, (v0r0 and v1r0) */
-#define MIDR_FUJITSU_ERRATUM_010001 MIDR_FUJITSU_A64FX
-#define MIDR_FUJITSU_ERRATUM_010001_MASK (~MIDR_CPU_VAR_REV(1, 0))
-#define TCR_CLEAR_FUJITSU_ERRATUM_010001 (TCR_EL1_NFD1 | TCR_EL1_NFD0)
+#include <asm/cputype-defs.h>
#ifndef __ASSEMBLER__
diff --git a/arch/arm64/include/asm/cputype.h b/include/arch/arm64/asm/cputype-defs.h
similarity index 85%
copy from arch/arm64/include/asm/cputype.h
copy to include/arch/arm64/asm/cputype-defs.h
index 7b518e81dd15..6f5279aaaa19 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/include/arch/arm64/asm/cputype-defs.h
@@ -1,9 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2012 ARM Ltd.
- */
-#ifndef __ASM_CPUTYPE_H
-#define __ASM_CPUTYPE_H
+#ifndef __ASM_CPUTYPE_DEFS_H
+#define __ASM_CPUTYPE_DEFS_H
+
+#include <linux/types.h>
#define INVALID_HWID ULONG_MAX
@@ -251,85 +250,4 @@
#define MIDR_FUJITSU_ERRATUM_010001_MASK (~MIDR_CPU_VAR_REV(1, 0))
#define TCR_CLEAR_FUJITSU_ERRATUM_010001 (TCR_EL1_NFD1 | TCR_EL1_NFD0)
-#ifndef __ASSEMBLER__
-
-#include <asm/sysreg.h>
-
-#define read_cpuid(reg) read_sysreg_s(SYS_ ## reg)
-
-/*
- * The CPU ID never changes at run time, so we might as well tell the
- * compiler that it's constant. Use this function to read the CPU ID
- * rather than directly reading processor_id or read_cpuid() directly.
- */
-static inline u32 __attribute_const__ read_cpuid_id(void)
-{
- return read_cpuid(MIDR_EL1);
-}
-
-/*
- * Represent a range of MIDR values for a given CPU model and a
- * range of variant/revision values.
- *
- * @model - CPU model as defined by MIDR_CPU_MODEL
- * @rv_min - Minimum value for the revision/variant as defined by
- * MIDR_CPU_VAR_REV
- * @rv_max - Maximum value for the variant/revision for the range.
- */
-struct midr_range {
- u32 model;
- u32 rv_min;
- u32 rv_max;
-};
-
-#define MIDR_RANGE(m, v_min, r_min, v_max, r_max) \
- { \
- .model = m, \
- .rv_min = MIDR_CPU_VAR_REV(v_min, r_min), \
- .rv_max = MIDR_CPU_VAR_REV(v_max, r_max), \
- }
-
-#define MIDR_REV_RANGE(m, v, r_min, r_max) MIDR_RANGE(m, v, r_min, v, r_max)
-#define MIDR_REV(m, v, r) MIDR_RANGE(m, v, r, v, r)
-#define MIDR_ALL_VERSIONS(m) MIDR_RANGE(m, 0, 0, 0xf, 0xf)
-
-static inline bool midr_is_cpu_model_range(u32 midr, u32 model, u32 rv_min,
- u32 rv_max)
-{
- u32 _model = midr & MIDR_CPU_MODEL_MASK;
- u32 rv = midr & (MIDR_REVISION_MASK | MIDR_VARIANT_MASK);
-
- return _model == model && rv >= rv_min && rv <= rv_max;
-}
-
-struct target_impl_cpu {
- u64 midr;
- u64 revidr;
- u64 aidr;
-};
-
-bool cpu_errata_set_target_impl(u64 num, void *impl_cpus);
-bool is_midr_in_range_list(struct midr_range const *ranges);
-
-static inline u64 __attribute_const__ read_cpuid_mpidr(void)
-{
- return read_cpuid(MPIDR_EL1);
-}
-
-static inline unsigned int __attribute_const__ read_cpuid_implementor(void)
-{
- return MIDR_IMPLEMENTOR(read_cpuid_id());
-}
-
-static inline unsigned int __attribute_const__ read_cpuid_part_number(void)
-{
- return MIDR_PARTNUM(read_cpuid_id());
-}
-
-static inline u32 __attribute_const__ read_cpuid_cachetype(void)
-{
- return read_cpuid(CTR_EL0);
-}
-#endif /* __ASSEMBLER__ */
-
-#endif
+#endif /* __ASM_CPUTYPE_DEFS_H */
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 18/26] arm64: Extract cache definitions
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (16 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 17/26] arm64: Extract cputype definitions Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 19/26] KVM: arm64: Share KVM feature detection macros Steffen Eiden
` (7 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Move CPU type definitions from arch/arm64/include/asm/cache.h.h to
include/arch/arm64/asm/cache-defs.h to prepare sharing with other
architectures. No functional changes.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/cache.h | 19 ++-----------------
include/arch/arm64/asm/cache-defs.h | 22 ++++++++++++++++++++++
2 files changed, 24 insertions(+), 17 deletions(-)
create mode 100644 include/arch/arm64/asm/cache-defs.h
diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
index 10a7ffadee3d..0f67fe470c29 100644
--- a/arch/arm64/include/asm/cache.h
+++ b/arch/arm64/include/asm/cache.h
@@ -5,26 +5,11 @@
#ifndef __ASM_CACHE_H
#define __ASM_CACHE_H
+#include <asm/cache-defs.h>
+
#define L1_CACHE_SHIFT (6)
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
-#define CLIDR_LOUU_SHIFT 27
-#define CLIDR_LOC_SHIFT 24
-#define CLIDR_LOUIS_SHIFT 21
-
-#define CLIDR_LOUU(clidr) (((clidr) >> CLIDR_LOUU_SHIFT) & 0x7)
-#define CLIDR_LOC(clidr) (((clidr) >> CLIDR_LOC_SHIFT) & 0x7)
-#define CLIDR_LOUIS(clidr) (((clidr) >> CLIDR_LOUIS_SHIFT) & 0x7)
-
-/* Ctypen, bits[3(n - 1) + 2 : 3(n - 1)], for n = 1 to 7 */
-#define CLIDR_CTYPE_SHIFT(level) (3 * (level - 1))
-#define CLIDR_CTYPE_MASK(level) (7 << CLIDR_CTYPE_SHIFT(level))
-#define CLIDR_CTYPE(clidr, level) \
- (((clidr) & CLIDR_CTYPE_MASK(level)) >> CLIDR_CTYPE_SHIFT(level))
-
-/* Ttypen, bits [2(n - 1) + 34 : 2(n - 1) + 33], for n = 1 to 7 */
-#define CLIDR_TTYPE_SHIFT(level) (2 * ((level) - 1) + CLIDR_EL1_Ttypen_SHIFT)
-
/*
* Memory returned by kmalloc() may be used for DMA, so we must make
* sure that all such allocations are cache aligned. Otherwise,
diff --git a/include/arch/arm64/asm/cache-defs.h b/include/arch/arm64/asm/cache-defs.h
new file mode 100644
index 000000000000..bb0ab69a9cd6
--- /dev/null
+++ b/include/arch/arm64/asm/cache-defs.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_CACHE_DEFS_H
+#define __ASM_CACHE_DEFS_H
+
+#define CLIDR_LOUU_SHIFT 27
+#define CLIDR_LOC_SHIFT 24
+#define CLIDR_LOUIS_SHIFT 21
+
+#define CLIDR_LOUU(clidr) (((clidr) >> CLIDR_LOUU_SHIFT) & 0x7)
+#define CLIDR_LOC(clidr) (((clidr) >> CLIDR_LOC_SHIFT) & 0x7)
+#define CLIDR_LOUIS(clidr) (((clidr) >> CLIDR_LOUIS_SHIFT) & 0x7)
+
+/* Ctypen, bits[3(n - 1) + 2 : 3(n - 1)], for n = 1 to 7 */
+#define CLIDR_CTYPE_SHIFT(level) (3 * (level - 1))
+#define CLIDR_CTYPE_MASK(level) (7 << CLIDR_CTYPE_SHIFT(level))
+#define CLIDR_CTYPE(clidr, level) \
+ (((clidr) & CLIDR_CTYPE_MASK(level)) >> CLIDR_CTYPE_SHIFT(level))
+
+/* Ttypen, bits [2(n - 1) + 34 : 2(n - 1) + 33], for n = 1 to 7 */
+#define CLIDR_TTYPE_SHIFT(level) (2 * ((level) - 1) + CLIDR_EL1_Ttypen_SHIFT)
+
+#endif /* __ASM_CACHE_DEFS_H */
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 19/26] KVM: arm64: Share KVM feature detection macros
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (17 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 18/26] arm64: Extract cache definitions Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 20/26] KVM: arm64: Share ID reg handling Steffen Eiden
` (6 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Move kvm feature definitions from arch/arm64/include to a shared location
(include/kvm/arm64) to enable reuse by e.g. s390 for KVM/arm64 on s390
support.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/kvm_feature.h | 60 +------------------
.../asm => include/kvm/arm64}/kvm_feature.h | 28 ++-------
2 files changed, 5 insertions(+), 83 deletions(-)
copy {arch/arm64/include/asm => include/kvm/arm64}/kvm_feature.h (76%)
diff --git a/arch/arm64/include/asm/kvm_feature.h b/arch/arm64/include/asm/kvm_feature.h
index 27a472d2343e..e1fb8b9f5ce2 100644
--- a/arch/arm64/include/asm/kvm_feature.h
+++ b/arch/arm64/include/asm/kvm_feature.h
@@ -2,65 +2,7 @@
#ifndef __ARM64_KVM_FEATURE_H__
#define __ARM64_KVM_FEATURE_H__
-#include <linux/types.h>
-#include <linux/bitfield.h>
-#include <asm/sysreg-defs.h>
-
-#define extract_id_field_unsigned(val, id, fld) \
- (FIELD_GET(id##_##fld##_MASK, (val)))
-
-#define extract_id_field_signed(val, id, fld) \
- ({ \
- u64 __val = extract_id_field_unsigned((val), id, fld); \
- sign_extend64(__val, id##_##fld##_WIDTH - 1); \
- })
-
-#define cmp_id_feat_signed(val, id, fld, op, limit) \
- (extract_id_field_signed((val), id, fld) op S64_SYS_FIELD_VALUE(id, fld, limit))
-
-#define cmp_id_feat_unsigned(val, id, fld, op, limit) \
- (extract_id_field_unsigned((val), id, fld) op (u64)SYS_FIELD_VALUE(id, fld, limit))
-
-#define cmp_id_feat(val, id, fld, op, limit) \
- (id##_##fld##_SIGNED ? \
- cmp_id_feat_signed(val, id, fld, op, limit) : \
- cmp_id_feat_unsigned(val, id, fld, op, limit))
-
-#define id_has_feat(val, id, fld, limit) \
- cmp_id_feat(val, id, fld, >=, limit)
-
-#define id_has_feat_enum(val, id, fld, variant) \
- cmp_id_feat_unsigned(val, id, fld, ==, variant)
-
-#define id_has_feat_range(val, id, fld, min, max) \
- (cmp_id_feat(val, id, fld, >=, min) && \
- cmp_id_feat(val, id, fld, <=, max))
-
-#define __kvm_has_feat(kvm, id, fld, limit) \
- id_has_feat(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, limit)
-
-#define kvm_has_feat(kvm, ...) __kvm_has_feat(kvm, __VA_ARGS__)
-
-#define __kvm_has_feat_enum(kvm, id, fld, val) \
- id_has_feat_enum(kvm_read_vm_id_reg((kvm), SYS_##id), id, fld, val)
-
-#define kvm_has_feat_enum(kvm, ...) __kvm_has_feat_enum(kvm, __VA_ARGS__)
-
-
-/* Check for a given level of PAuth support */
-#define kvm_has_pauth(k, l) \
- ({ \
- bool pa, pi, pa3; \
- \
- pa = kvm_has_feat((k), ID_AA64ISAR1_EL1, APA, l); \
- pa &= kvm_has_feat((k), ID_AA64ISAR1_EL1, GPA, IMP); \
- pi = kvm_has_feat((k), ID_AA64ISAR1_EL1, API, l); \
- pi &= kvm_has_feat((k), ID_AA64ISAR1_EL1, GPI, IMP); \
- pa3 = kvm_has_feat((k), ID_AA64ISAR2_EL1, APA3, l); \
- pa3 &= kvm_has_feat((k), ID_AA64ISAR2_EL1, GPA3, IMP); \
- \
- (pa + pi + pa3) == 1; \
- })
+#include <kvm/arm64/kvm_feature.h>
#define kvm_has_fpmr(k) \
(system_supports_fpmr() && \
diff --git a/arch/arm64/include/asm/kvm_feature.h b/include/kvm/arm64/kvm_feature.h
similarity index 76%
copy from arch/arm64/include/asm/kvm_feature.h
copy to include/kvm/arm64/kvm_feature.h
index 27a472d2343e..945abbbf1aa8 100644
--- a/arch/arm64/include/asm/kvm_feature.h
+++ b/include/kvm/arm64/kvm_feature.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-#ifndef __ARM64_KVM_FEATURE_H__
-#define __ARM64_KVM_FEATURE_H__
+
+#ifndef __KVM_ARM64_FEATURE_H__
+#define __KVM_ARM64_FEATURE_H__
#include <linux/types.h>
#include <linux/bitfield.h>
@@ -46,7 +47,6 @@
#define kvm_has_feat_enum(kvm, ...) __kvm_has_feat_enum(kvm, __VA_ARGS__)
-
/* Check for a given level of PAuth support */
#define kvm_has_pauth(k, l) \
({ \
@@ -62,24 +62,4 @@
(pa + pi + pa3) == 1; \
})
-#define kvm_has_fpmr(k) \
- (system_supports_fpmr() && \
- kvm_has_feat((k), ID_AA64PFR2_EL1, FPMR, IMP))
-
-#define kvm_has_tcr2(k) \
- (kvm_has_feat((k), ID_AA64MMFR3_EL1, TCRX, IMP))
-
-#define kvm_has_s1pie(k) \
- (kvm_has_feat((k), ID_AA64MMFR3_EL1, S1PIE, IMP))
-
-#define kvm_has_s1poe(k) \
- (system_supports_poe() && \
- kvm_has_feat((k), ID_AA64MMFR3_EL1, S1POE, IMP))
-
-#define kvm_has_ras(k) \
- (kvm_has_feat((k), ID_AA64PFR0_EL1, RAS, IMP))
-
-#define kvm_has_sctlr2(k) \
- (kvm_has_feat((k), ID_AA64MMFR3_EL1, SCTLRX, IMP))
-
-#endif /* __ARM64_KVM_FEATURE_H__*/
+#endif /* __KVM_ARM64_FEATURE_H__*/
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 20/26] KVM: arm64: Share ID reg handling
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (18 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 19/26] KVM: arm64: Share KVM feature detection macros Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 22/26] KVM: arm64: Refactor core " Steffen Eiden
` (5 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Move ID register definitions from arch/arm64/include to a shared
location (include/kvm/arm64) to enable reuse by e.g. s390 for KVM/arm64
on s390 support.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/kvm_host.h | 41 ------------------------------
include/kvm/arm64/kvm_host.h | 42 +++++++++++++++++++++++++++++++
2 files changed, 42 insertions(+), 41 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 5734e93cad57..a5fca468cc4a 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1385,47 +1385,6 @@ static inline void kvm_hyp_reserve(void) { }
void kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu);
bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu);
-struct kvm_vm_id_regs {
- /*
- * Emulated CPU ID registers per VM
- * (Op0, Op1, CRn, CRm, Op2) of the ID registers to be saved in it
- * is (3, 0, 0, crm, op2), where 1<=crm<8, 0<=op2<8.
- *
- * These emulated idregs are VM-wide, but accessed from the context of a vCPU.
- * Atomic access to multiple idregs are guarded by kvm_arch.config_lock.
- */
-#define IDREG_IDX(id) (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))
-#define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
- u64 normal[KVM_ARM_ID_REG_NUM];
-
- u64 midr_el1;
- u64 revidr_el1;
- u64 aidr_el1;
- u64 ctr_el0;
-};
-
-static inline u64 *__vm_id_reg(struct kvm_vm_id_regs *id_regs, u32 reg)
-{
- switch (reg) {
- case sys_reg(3, 0, 0, 1, 0) ... sys_reg(3, 0, 0, 7, 7):
- return &id_regs->normal[IDREG_IDX(reg)];
- case SYS_CTR_EL0:
- return &id_regs->ctr_el0;
- case SYS_MIDR_EL1:
- return &id_regs->midr_el1;
- case SYS_REVIDR_EL1:
- return &id_regs->revidr_el1;
- case SYS_AIDR_EL1:
- return &id_regs->aidr_el1;
- default:
- WARN_ON_ONCE(1);
- return NULL;
- }
-}
-
-#define kvm_read_vm_id_reg(kvm, reg) \
- ({ u64 __val = *__vm_id_reg(&(kvm)->arch.id_regs, reg); __val; })
-
void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);
static inline bool kvm_arch_has_irq_bypass(void)
diff --git a/include/kvm/arm64/kvm_host.h b/include/kvm/arm64/kvm_host.h
index 8bf399508757..379942225d5f 100644
--- a/include/kvm/arm64/kvm_host.h
+++ b/include/kvm/arm64/kvm_host.h
@@ -4,6 +4,7 @@
#define __KVM_ARM64_KVM_HOST_H
#include <linux/types.h>
+#include <asm/sysreg-defs.h>
#define KVM_VCPU_MAX_FEATURES 9
@@ -21,6 +22,47 @@
#define KVM_REQ_MAP_L1_VNCR_EL2 KVM_ARCH_REQ(10)
#define KVM_REQ_VGIC_PROCESS_UPDATE KVM_ARCH_REQ(11)
+struct kvm_vm_id_regs {
+ /*
+ * Emulated CPU ID registers per VM
+ * (Op0, Op1, CRn, CRm, Op2) of the ID registers to be saved in it
+ * is (3, 0, 0, crm, op2), where 1<=crm<8, 0<=op2<8.
+ *
+ * These emulated idregs are VM-wide, but accessed from the context of a vCPU.
+ * Atomic access to multiple idregs are guarded by kvm_arch.config_lock.
+ */
+#define IDREG_IDX(id) (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))
+#define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
+ u64 normal[KVM_ARM_ID_REG_NUM];
+
+ u64 midr_el1;
+ u64 revidr_el1;
+ u64 aidr_el1;
+ u64 ctr_el0;
+};
+
+static inline u64 *__vm_id_reg(struct kvm_vm_id_regs *id_regs, u32 reg)
+{
+ switch (reg) {
+ case sys_reg(3, 0, 0, 1, 0) ... sys_reg(3, 0, 0, 7, 7):
+ return &id_regs->normal[IDREG_IDX(reg)];
+ case SYS_CTR_EL0:
+ return &id_regs->ctr_el0;
+ case SYS_MIDR_EL1:
+ return &id_regs->midr_el1;
+ case SYS_REVIDR_EL1:
+ return &id_regs->revidr_el1;
+ case SYS_AIDR_EL1:
+ return &id_regs->aidr_el1;
+ default:
+ WARN_ON_ONCE(1);
+ return NULL;
+ }
+}
+
+#define kvm_read_vm_id_reg(kvm, reg) \
+ ({ u64 __val = *__vm_id_reg(&(kvm)->arch.id_regs, reg); __val; })
+
struct vcpu_reset_state {
unsigned long pc;
unsigned long r0;
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 22/26] KVM: arm64: Refactor core reg handling
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (19 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 20/26] KVM: arm64: Share ID reg handling Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 23/26] KVM: s390: arm64: Implement feature sanitisation Steffen Eiden
` (4 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Refactor sysreg core handling. Before this all core regs are identified
with a memory address and reading/writing happened through accessing the
data at this address. However, for arm64 on s390 not all core registers
have a dedicated memory address.
Refactor such that the address function does not return an address but
actually does the read/write request. ELR_EL1 and SPSR_EL1 now use
vcpu_read_sys_reg/vcpu_write_sys_reg accessor functions, allowing s390
to provide custom implementations.
Co-developed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
virt/kvm/arm64/guest.c | 100 ++++++++++++++++++++++++++---------------
1 file changed, 64 insertions(+), 36 deletions(-)
diff --git a/virt/kvm/arm64/guest.c b/virt/kvm/arm64/guest.c
index 35ba03033b4c..11509382d594 100644
--- a/virt/kvm/arm64/guest.c
+++ b/virt/kvm/arm64/guest.c
@@ -65,69 +65,96 @@ static int core_reg_size_from_offset(const struct kvm_vcpu *vcpu, u64 off)
return size;
}
-static void *core_reg_addr(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+static int core_reg_rw(struct kvm_vcpu *vcpu, u64 reg_id, void *valp, bool read)
{
- u64 off = core_reg_offset_from_id(reg->id);
+ u64 off = core_reg_offset_from_id(reg_id);
int size = core_reg_size_from_offset(vcpu, off);
+ void *addr;
- if (size < 0)
- return NULL;
+ if (size < 0 || (KVM_REG_SIZE(reg_id) != size))
+ return -EINVAL;
- if (KVM_REG_SIZE(reg->id) != size)
- return NULL;
+ switch (off) {
+ case KVM_REG_ARM_CORE_REG(elr_el1):
+ if (read)
+ *(u64 *)valp = vcpu_read_sys_reg(vcpu, ELR_EL1);
+ else
+ vcpu_write_sys_reg(vcpu, *(u64 *)valp, ELR_EL1);
+ return 0;
+
+ case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_EL1]):
+ if (read)
+ *(u64 *)valp = vcpu_read_sys_reg(vcpu, SPSR_EL1);
+ else
+ vcpu_write_sys_reg(vcpu, *(u64 *)valp, SPSR_EL1);
+ return 0;
+ }
switch (off) {
case KVM_REG_ARM_CORE_REG(regs.regs[0]) ...
KVM_REG_ARM_CORE_REG(regs.regs[30]):
off -= KVM_REG_ARM_CORE_REG(regs.regs[0]);
off /= 2;
- return &vcpu_gp_regs(vcpu)[off];
+ addr = &vcpu_gp_regs(vcpu)[off];
+ break;
case KVM_REG_ARM_CORE_REG(regs.sp):
- return vcpu_sp_el0(vcpu);
+ addr = vcpu_sp_el0(vcpu);
+ break;
case KVM_REG_ARM_CORE_REG(regs.pc):
- return vcpu_pc(vcpu);
+ addr = vcpu_pc(vcpu);
+ break;
case KVM_REG_ARM_CORE_REG(regs.pstate):
- return vcpu_cpsr(vcpu);
+ addr = vcpu_cpsr(vcpu);
+ break;
case KVM_REG_ARM_CORE_REG(sp_el1):
- return kvm_vcpu_get_sp_el1(vcpu);
-
- case KVM_REG_ARM_CORE_REG(elr_el1):
- return __ctxt_sys_reg(&vcpu->arch.ctxt, ELR_EL1);
-
- case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_EL1]):
- return __ctxt_sys_reg(&vcpu->arch.ctxt, SPSR_EL1);
+ addr = kvm_vcpu_get_sp_el1(vcpu);
+ break;
case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_ABT]):
- return &vcpu->arch.ctxt.spsr_abt;
+ addr = &vcpu->arch.ctxt.spsr_abt;
+ break;
case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_UND]):
- return &vcpu->arch.ctxt.spsr_und;
+ addr = &vcpu->arch.ctxt.spsr_und;
+ break;
case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_IRQ]):
- return &vcpu->arch.ctxt.spsr_irq;
+ addr = &vcpu->arch.ctxt.spsr_irq;
+ break;
case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_FIQ]):
- return &vcpu->arch.ctxt.spsr_fiq;
+ addr = &vcpu->arch.ctxt.spsr_fiq;
+ break;
case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ...
KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]):
off -= KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]);
off /= 4;
- return kvm_vcpu_get_vreg(vcpu, off);
+ addr = kvm_vcpu_get_vreg(vcpu, off);
+ break;
case KVM_REG_ARM_CORE_REG(fp_regs.fpsr):
- return kvm_vcpu_get_fpsr(vcpu);
+ addr = kvm_vcpu_get_fpsr(vcpu);
+ break;
case KVM_REG_ARM_CORE_REG(fp_regs.fpcr):
- return kvm_vcpu_get_fpcr(vcpu);
+ addr = kvm_vcpu_get_fpcr(vcpu);
+ break;
default:
- return NULL;
+ return -EINVAL;
}
+
+ if (read)
+ memcpy(valp, addr, size);
+ else
+ memcpy(addr, valp, size);
+
+ return 0;
}
int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
@@ -140,7 +167,9 @@ int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
*/
__u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr;
int nr_regs = sizeof(struct kvm_regs) / sizeof(__u32);
- void *addr;
+ __uint128_t tmp;
+ void *valp = &tmp;
+ int ret;
u32 off;
/* Our ID is an index into the kvm_regs struct. */
@@ -149,11 +178,12 @@ int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
(off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
return -ENOENT;
- addr = core_reg_addr(vcpu, reg);
- if (!addr)
- return -EINVAL;
- if (copy_to_user(uaddr, addr, KVM_REG_SIZE(reg->id)))
+ ret = core_reg_rw(vcpu, reg->id, valp, true);
+ if (ret)
+ return ret;
+
+ if (copy_to_user(uaddr, valp, KVM_REG_SIZE(reg->id)))
return -EFAULT;
return 0;
@@ -164,7 +194,7 @@ int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
__u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr;
int nr_regs = sizeof(struct kvm_regs) / sizeof(__u32);
__uint128_t tmp;
- void *valp = &tmp, *addr;
+ void *valp = &tmp;
u64 off;
int err = 0;
@@ -174,10 +204,6 @@ int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
(off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
return -ENOENT;
- addr = core_reg_addr(vcpu, reg);
- if (!addr)
- return -EINVAL;
-
if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
return -EINVAL;
@@ -220,7 +246,9 @@ int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
}
}
- memcpy(addr, valp, KVM_REG_SIZE(reg->id));
+ err = core_reg_rw(vcpu, reg->id, valp, false);
+ if (err)
+ goto out;
if (*vcpu_cpsr(vcpu) & PSR_MODE32_BIT) {
int i, nr_reg;
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 23/26] KVM: s390: arm64: Implement feature sanitisation
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (20 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 22/26] KVM: arm64: Refactor core " Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 24/26] KVM: s390: arm64: Implement sysreg handling Steffen Eiden
` (3 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Implement feature detection and sanitization for arm64 KVM guests on
s390.
Query hardware capabilities using QAAF instruction and sanitize arm64 ID
registers. Provide accessor functions for queried capabilities and
integrate feature detection into module initialization sequence.
Co-developed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/include/asm/kvm_feature.h | 111 ++++++++++++
arch/s390/include/asm/kvm_host_arm64.h | 2 +-
arch/s390/include/asm/kvm_host_arm64_types.h | 3 +-
arch/s390/include/asm/kvm_nested.h | 5 +
arch/s390/kvm/arm64/Makefile | 1 +
arch/s390/kvm/arm64/arm.c | 6 +
arch/s390/kvm/arm64/feature.c | 170 +++++++++++++++++++
7 files changed, 296 insertions(+), 2 deletions(-)
create mode 100644 arch/s390/include/asm/kvm_feature.h
create mode 100644 arch/s390/kvm/arm64/feature.c
diff --git a/arch/s390/include/asm/kvm_feature.h b/arch/s390/include/asm/kvm_feature.h
new file mode 100644
index 000000000000..dda99c3b09af
--- /dev/null
+++ b/arch/s390/include/asm/kvm_feature.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __S390_KVM_ARM64_FEATURE_H__
+#define __S390_KVM_ARM64_FEATURE_H__
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <asm/kvm_host_arm64_types.h>
+
+#include <kvm/arm64/kvm_feature.h>
+
+int __init kvm_arm_host_detect_features(void);
+
+/**
+ * kvm_sae_supported_sd_formats() - Retrieve supported SAE SD formats
+ *
+ * Return: Bitmap of supported SAE state description formats.
+ */
+static inline u32 kvm_sae_supported_sd_formats(void)
+{
+ extern struct qaaf_qmc_block __qaaf_qmp;
+
+ return __qaaf_qmp.ssdf;
+}
+
+/**
+ * kvm_sae_supported_sa_formats() - Retrieve supported SAE SA formats
+ *
+ * Return: Bitmap of supported SAE save area formats.
+ */
+static inline u32 kvm_sae_supported_sa_formats(void)
+{
+ extern struct qaaf_qmc_block __qaaf_qmp;
+
+ return __qaaf_qmp.ssaf;
+}
+
+/**
+ * kvm_sae_max_vcpus() - Retrieve maximum supported vcpus
+ *
+ * Return: Max number of vCPUs supported by the SAE instruction/the machine
+ * as indicated by QAAF, not necessarily that supported by the host software.
+ */
+static inline u16 kvm_sae_max_vcpus(void)
+{
+ extern struct qaaf_qmc_block __qaaf_qmp;
+
+ /* QAAF QMP reports the max id not the max num */
+ return __qaaf_qmp.maxncpu + 1;
+}
+
+/**
+ * kvm_sae_irptc() - Retrieve supported SAE IRPTCs
+ *
+ * Return: Bitmap of supported SAE IRPTCs.
+ */
+static inline u64 kvm_sae_irptc(void)
+{
+ extern struct qaaf_qmc_block __qaaf_qmp;
+
+ return __qaaf_qmp.regs[QAAF_IRPTC];
+}
+
+/**
+ * kvm_arm_host_sys_reg_by_name() - Get the value of a sys register
+ *
+ * @id - ARM (ID-)register name
+ *
+ * Get the value of a sys register describing the host configuration.
+ * The returned value indicates support by the machine (HW/FW)
+ * after some sanitisation. Equivalent to arm64's read_sanitised_ftr_reg,
+ * See `enum qaaf_regs` for supported registers. Use the ARM register name
+ * without the QAAF_REG_ prefix as defined in the qaaf_regs enum.
+ *
+ * Example:
+ * kvm_arm_host_sys_reg_by_name(ID_AA64PFR0_EL1)
+ *
+ * Return: Sanitised HW value of the specified register
+ */
+#define kvm_arm_host_sys_reg_by_name(id) kvm_arm_host_sys_reg_by_id(SYS_##id)
+
+/**
+ * kvm_arm_host_sys_reg_by_id() - Get the value of a sys register
+ *
+ * @id - ARM sysreg id
+ *
+ * Get the value of a sys register describing the host configuration.
+ * The returned value indicates support by the machine (HW/FW)
+ * after some sanitisation. Equivalent to arm64's read_sanitised_ftr_reg,
+ * See `enum qaaf_regs` for supported registers.
+ *
+ * Example:
+ * kvm_arm_host_sys_reg_by_id(SYS_ID_AA64PFR0_EL1)
+ *
+ * Return: Sanitised HW value of the specified register
+ */
+u64 kvm_arm_host_sys_reg_by_id(u32 id);
+
+#define kvm_arm_host_has_feat(id, fld, limit) \
+ id_has_feat(kvm_arm_host_sys_reg_by_name(id), id, fld, limit)
+
+#define kvm_has_fpmr(k) \
+ (kvm_has_feat((k), ID_AA64PFR2_EL1, FPMR, IMP))
+
+#define kvm_has_s1poe(k) \
+ (kvm_has_feat((k), ID_AA64MMFR3_EL1, S1POE, IMP))
+
+#define kvm_vcpu_has_pmu(_v) false
+#define kvm_has_mte(_k) false
+
+#endif /* __S390_KVM_ARM64_FEATURE_H__*/
diff --git a/arch/s390/include/asm/kvm_host_arm64.h b/arch/s390/include/asm/kvm_host_arm64.h
index fcbe510cb868..f62daff3303b 100644
--- a/arch/s390/include/asm/kvm_host_arm64.h
+++ b/arch/s390/include/asm/kvm_host_arm64.h
@@ -6,6 +6,7 @@
#include <asm/kvm_host_arm64_types.h>
#include <asm/debug.h>
+#include <asm/kvm_feature.h>
#define vcpu_gp_regs(v) ((v)->arch.sae_block.gpr)
@@ -123,7 +124,6 @@ struct kvm_vcpu_stat {
#define _vcpu_test_and_clear_flag(v, flagset, ...) \
__vcpu_test_and_clear_flag(&(v)->arch.flagset, __VA_ARGS__)
-#define kvm_has_mte(_kvm) false
#define vcpu_has_sve(_vcpu) false
#define vcpu_has_ptrauth(_vcpu) false
diff --git a/arch/s390/include/asm/kvm_host_arm64_types.h b/arch/s390/include/asm/kvm_host_arm64_types.h
index 16f7018a1714..45fa360601fb 100644
--- a/arch/s390/include/asm/kvm_host_arm64_types.h
+++ b/arch/s390/include/asm/kvm_host_arm64_types.h
@@ -206,7 +206,8 @@ enum {
/* 0x3f-0x41 reserved */
QAAF_REG_CNTFRQ_EL0 = 0x42,
QAAF_REG_CTR_EL0 = 0x43,
- /* 0x44-0x49 reserved */
+ QAAF_REG_AIDR_EL1 = 0x44,
+ /* 0x43-0x49 reserved */
QAAF_IRPTC = 0x4a,
/* 0x4b reserved */
QAAF_REG_ICH_VTR_EL2 = 0x4c,
diff --git a/arch/s390/include/asm/kvm_nested.h b/arch/s390/include/asm/kvm_nested.h
index 7158932e718b..f075df33277f 100644
--- a/arch/s390/include/asm/kvm_nested.h
+++ b/arch/s390/include/asm/kvm_nested.h
@@ -10,4 +10,9 @@ static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu)
return false;
}
+static inline u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val)
+{
+ BUILD_BUG();
+}
+
#endif /* ASM_KVM_NESTED_H */
diff --git a/arch/s390/kvm/arm64/Makefile b/arch/s390/kvm/arm64/Makefile
index d0aac34b8d2f..28deeb90efa9 100644
--- a/arch/s390/kvm/arm64/Makefile
+++ b/arch/s390/kvm/arm64/Makefile
@@ -9,6 +9,7 @@ ccflags-y += -I $(src) -I$(srctree)/arch/s390/kvm/gmap -DKVM_S390_ARM64
kvm-arm64-obj := \
arm.o \
+ feature.o \
guest.o \
handle_exit.o \
inject_fault.o \
diff --git a/arch/s390/kvm/arm64/arm.c b/arch/s390/kvm/arm64/arm.c
index 48418c46e451..dc0e070f8a62 100644
--- a/arch/s390/kvm/arm64/arm.c
+++ b/arch/s390/kvm/arm64/arm.c
@@ -701,6 +701,8 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg)
static int __init kvm_s390_arm64_init(void)
{
+ int err = 0;
+
if (!sclp.has_aef) {
pr_info("SAE is not available\n");
return -ENXIO;
@@ -711,6 +713,10 @@ static int __init kvm_s390_arm64_init(void)
return -ENXIO;
}
+ err = kvm_arm_host_detect_features();
+ if (err)
+ return err;
+
return kvm_init_with_dev(sizeof(struct kvm_vcpu), 0, THIS_MODULE,
KVM_DEV_NAME, MISC_DYNAMIC_MINOR);
}
diff --git a/arch/s390/kvm/arm64/feature.c b/arch/s390/kvm/arm64/feature.c
new file mode 100644
index 000000000000..9a34c0866a2b
--- /dev/null
+++ b/arch/s390/kvm/arm64/feature.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kvm_host.h>
+#include <asm/kvm_host_arm64_types.h>
+#include <asm/kvm_feature.h>
+
+struct qaaf_qmc_block __qaaf_qmc;
+
+#define MASK_RESERVED(_qaafp, _id) \
+ ({ \
+ u64 *_reg = &((_qaafp)->regs[QAAF_REG_##_id]); \
+ *_reg = (*_reg & ~_id##_RES0) | _id##_RES1; \
+ })
+
+#define QAAF_FIELD_MODIFY(_idp, _id_field, _val) \
+ FIELD_MODIFY(_id_field##_MASK, _idp, _id_field##_##_val)
+
+#define MODIFY(_qaafp, _id, _field, _val) \
+ QAAF_FIELD_MODIFY(&((_qaafp)->regs[QAAF_REG_##_id]), _id##_##_field, _val)
+
+int __init kvm_arm_host_detect_features(void)
+{
+ qaaf_qmc(&__qaaf_qmc);
+
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64ISAR0_EL1);
+
+ MODIFY(&__qaaf_qmc, ID_AA64ISAR1_EL1, LS64, NI);
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64ISAR1_EL1);
+
+ MODIFY(&__qaaf_qmc, ID_AA64ISAR2_EL1, SYSINSTR_128, NI);
+ MODIFY(&__qaaf_qmc, ID_AA64ISAR2_EL1, SYSREG_128, NI);
+ MODIFY(&__qaaf_qmc, ID_AA64ISAR2_EL1, PAC_frac, NI);
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64ISAR2_EL1);
+
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64ISAR3_EL1);
+
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64MMFR0_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64MMFR1_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64MMFR2_EL1);
+
+ MODIFY(&__qaaf_qmc, ID_AA64MMFR3_EL1, Spec_FPACC, NI);
+ MODIFY(&__qaaf_qmc, ID_AA64MMFR3_EL1, ADERR, NI);
+ MODIFY(&__qaaf_qmc, ID_AA64MMFR3_EL1, SDERR, NI);
+ MODIFY(&__qaaf_qmc, ID_AA64MMFR3_EL1, ANERR, NI);
+ MODIFY(&__qaaf_qmc, ID_AA64MMFR3_EL1, SNERR, NI);
+ MODIFY(&__qaaf_qmc, ID_AA64MMFR3_EL1, MEC, NI);
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64MMFR3_EL1);
+
+ MODIFY(&__qaaf_qmc, ID_AA64MMFR4_EL1, SRMASK, NI);
+ MODIFY(&__qaaf_qmc, ID_AA64MMFR4_EL1, E3DSE, NI);
+ MODIFY(&__qaaf_qmc, ID_AA64MMFR4_EL1, RMEGDI, NI);
+ MODIFY(&__qaaf_qmc, ID_AA64MMFR4_EL1, FGWTE3, NI);
+ MODIFY(&__qaaf_qmc, ID_AA64MMFR4_EL1, ASID2, NI);
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64MMFR4_EL1);
+
+ MODIFY(&__qaaf_qmc, ID_AA64PFR0_EL1, SEL2, NI);
+ MODIFY(&__qaaf_qmc, ID_AA64PFR0_EL1, SVE, NI);
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64PFR0_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64PFR1_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64PFR2_EL1);
+
+ MODIFY(&__qaaf_qmc, ID_AA64DFR0_EL1, PMUVer, NI);
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64DFR0_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64DFR1_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64DFR2_EL1);
+
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64AFR0_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64AFR1_EL1);
+
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64ZFR0_EL1);
+
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64SMFR0_EL1);
+
+ MASK_RESERVED(&__qaaf_qmc, ID_AA64FPFR0_EL1);
+
+ MASK_RESERVED(&__qaaf_qmc, ID_PFR0_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_PFR1_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_PFR2_EL1);
+
+ MASK_RESERVED(&__qaaf_qmc, ID_DFR0_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_DFR1_EL1);
+
+ MASK_RESERVED(&__qaaf_qmc, ID_MMFR0_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_MMFR1_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_MMFR2_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_MMFR3_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_MMFR4_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_MMFR5_EL1);
+
+ MASK_RESERVED(&__qaaf_qmc, ID_ISAR0_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_ISAR1_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_ISAR2_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_ISAR3_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_ISAR4_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_ISAR5_EL1);
+ MASK_RESERVED(&__qaaf_qmc, ID_ISAR6_EL1);
+
+ MASK_RESERVED(&__qaaf_qmc, MVFR0_EL1);
+ MASK_RESERVED(&__qaaf_qmc, MVFR1_EL1);
+ MASK_RESERVED(&__qaaf_qmc, MVFR2_EL1);
+
+ MASK_RESERVED(&__qaaf_qmc, CTR_EL0);
+
+ MASK_RESERVED(&__qaaf_qmc, ICH_VTR_EL2);
+
+ return 0;
+}
+
+#define _qaaf_reg_case(id) case SYS_##id: return __qaaf_qmc.regs[QAAF_REG_##id]
+
+u64 kvm_arm_host_sys_reg_by_id(u32 id)
+{
+ switch (id) {
+ _qaaf_reg_case(MIDR_EL1);
+ _qaaf_reg_case(MPIDR_EL1);
+ _qaaf_reg_case(REVIDR_EL1);
+ _qaaf_reg_case(ID_PFR0_EL1);
+ _qaaf_reg_case(ID_PFR1_EL1);
+ _qaaf_reg_case(ID_DFR0_EL1);
+ _qaaf_reg_case(ID_AFR0_EL1);
+ _qaaf_reg_case(ID_MMFR0_EL1);
+ _qaaf_reg_case(ID_MMFR1_EL1);
+ _qaaf_reg_case(ID_MMFR2_EL1);
+ _qaaf_reg_case(ID_MMFR3_EL1);
+ _qaaf_reg_case(ID_ISAR0_EL1);
+ _qaaf_reg_case(ID_ISAR1_EL1);
+ _qaaf_reg_case(ID_ISAR2_EL1);
+ _qaaf_reg_case(ID_ISAR3_EL1);
+ _qaaf_reg_case(ID_ISAR4_EL1);
+ _qaaf_reg_case(ID_ISAR5_EL1);
+ _qaaf_reg_case(ID_MMFR4_EL1);
+ _qaaf_reg_case(ID_ISAR6_EL1);
+ _qaaf_reg_case(MVFR0_EL1);
+ _qaaf_reg_case(MVFR1_EL1);
+ _qaaf_reg_case(MVFR2_EL1);
+ _qaaf_reg_case(ID_PFR2_EL1);
+ _qaaf_reg_case(ID_DFR1_EL1);
+ _qaaf_reg_case(ID_MMFR5_EL1);
+ _qaaf_reg_case(ID_AA64PFR0_EL1);
+ _qaaf_reg_case(ID_AA64PFR1_EL1);
+ _qaaf_reg_case(ID_AA64PFR2_EL1);
+ _qaaf_reg_case(ID_AA64ZFR0_EL1);
+ _qaaf_reg_case(ID_AA64SMFR0_EL1);
+ _qaaf_reg_case(ID_AA64FPFR0_EL1);
+ _qaaf_reg_case(ID_AA64DFR0_EL1);
+ _qaaf_reg_case(ID_AA64DFR1_EL1);
+ _qaaf_reg_case(ID_AA64DFR2_EL1);
+ _qaaf_reg_case(ID_AA64AFR0_EL1);
+ _qaaf_reg_case(ID_AA64AFR1_EL1);
+ _qaaf_reg_case(ID_AA64ISAR0_EL1);
+ _qaaf_reg_case(ID_AA64ISAR1_EL1);
+ _qaaf_reg_case(ID_AA64ISAR2_EL1);
+ _qaaf_reg_case(ID_AA64ISAR3_EL1);
+ _qaaf_reg_case(ID_AA64MMFR0_EL1);
+ _qaaf_reg_case(ID_AA64MMFR1_EL1);
+ _qaaf_reg_case(ID_AA64MMFR2_EL1);
+ _qaaf_reg_case(ID_AA64MMFR3_EL1);
+ _qaaf_reg_case(ID_AA64MMFR4_EL1);
+ _qaaf_reg_case(CNTFRQ_EL0);
+ _qaaf_reg_case(CTR_EL0);
+ _qaaf_reg_case(AIDR_EL1);
+ _qaaf_reg_case(ICH_VTR_EL2);
+ _qaaf_reg_case(PMMIR_EL1);
+ _qaaf_reg_case(PMCR_EL0);
+ _qaaf_reg_case(PMCEID0_EL0);
+ _qaaf_reg_case(PMCEID1_EL0);
+ default:
+ WARN(true, "Unknown system register 0x%x\n", id);
+ return 0xbad1234bad;
+ }
+}
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 24/26] KVM: s390: arm64: Implement sysreg handling
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (21 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 23/26] KVM: s390: arm64: Implement feature sanitisation Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 25/26] KVM: s390: arm64: Implement exception injection Steffen Eiden
` (2 subsequent siblings)
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Add arm64 system register support for the s390 KVM backend, including
register enumeration, userspace get/set handling, reset/finalization
hooks, and vCPU run integration for trapped sysreg accesses.
Co-developed-by: Andreas Grapentin <gra@linux.ibm.com>
Signed-off-by: Andreas Grapentin <gra@linux.ibm.com>
Co-developed-by: Nico Boehr <nrb@linux.ibm.com>
Signed-off-by: Nico Boehr <nrb@linux.ibm.com>
Co-developed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/kvm/Makefile | 1 -
arch/s390/include/asm/kvm_emulate.h | 34 ++
arch/s390/include/asm/kvm_host_arm64.h | 2 +-
arch/s390/kvm/arm64/Makefile | 1 +
arch/s390/kvm/arm64/arm.c | 23 +-
arch/s390/kvm/arm64/guest.c | 20 +-
arch/s390/kvm/arm64/handle_exit.c | 1 +
arch/s390/kvm/arm64/reset.c | 5 +
arch/s390/kvm/arm64/sys_regs.c | 769 +++++++++++++++++++++++++
arch/s390/kvm/arm64/trace.h | 33 ++
virt/kvm/arm64/Makefile.kvm | 1 +
11 files changed, 875 insertions(+), 15 deletions(-)
create mode 100644 arch/s390/kvm/arm64/sys_regs.c
create mode 100644 arch/s390/kvm/arm64/trace.h
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index d55c7245aad9..5b4a8d002fc9 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -19,7 +19,6 @@ kvm-y += arm.o mmu.o psci.o hypercalls.o pvtime.o \
guest.o debug.o reset.o sys_regs.o stacktrace.o \
vgic-sys-reg-v3.o fpsimd.o pkvm.o \
arch_timer.o trng.o vmid.o emulate-nested.o nested.o at.o \
- $(KVM_ARM64)/sys_regs.o \
vgic/vgic.o vgic/vgic-init.o \
vgic/vgic-irqfd.o vgic/vgic-v2.o \
vgic/vgic-v3.o vgic/vgic-v4.o \
diff --git a/arch/s390/include/asm/kvm_emulate.h b/arch/s390/include/asm/kvm_emulate.h
index 93b9e777b51e..5549d44fda18 100644
--- a/arch/s390/include/asm/kvm_emulate.h
+++ b/arch/s390/include/asm/kvm_emulate.h
@@ -12,6 +12,7 @@
#include <kvm/arm64/kvm_arm.h>
#include <kvm/arm64/kvm_emulate.h>
+#include <clocksource/arm_arch_timer.h>
static __always_inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
{
@@ -84,6 +85,39 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
HCR_TID4 | HCR_TID5 | HCR_TIDCP;
}
+static inline void vcpu_reset_hcrx(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.hcrx_elz = 0;
+ if (kvm_has_feat(vcpu->kvm, ID_AA64ISAR2_EL1, MOPS, IMP))
+ vcpu->arch.hcrx_elz |= HCRX_EL2_MSCEn ;
+}
+
+static inline void vcpu_reset_cptr(struct kvm_vcpu *vcpu)
+{
+ u64 cptr;
+
+ /* we unconditionally have E2H, so disable traps to EL2 for FP and SVE, if enabled */
+ cptr = CPACR_EL1_FPEN;
+ if (vcpu_has_sve(vcpu))
+ cptr |= CPACR_EL1_ZEN;
+ vcpu_write_host_sys_reg(vcpu, cptr, SYS_CPTR_EL2);
+}
+
+static inline void vcpu_reset_cnthctl(struct kvm_vcpu *vcpu)
+{
+ u64 cnthctl;
+
+ /* we unconditionally have E2H, so disable traps to EL2 for physical timer registers */
+ cnthctl = (CNTHCTL_EL1PCEN | CNTHCTL_EL1PCTEN) << 10;
+ vcpu_write_host_sys_reg(vcpu, cnthctl, SYS_CNTHCTL_EL2);
+}
+
+static inline void vcpu_reset_icc(struct kvm_vcpu *vcpu)
+{
+ /* ensure ICC_SRE_EL2.Enable = 1 so ICC_SRE_EL1 is handled in hardware */
+ vcpu_write_host_sys_reg(vcpu, 0xf, SYS_ICC_SRE_EL2);
+}
+
static inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu)
{
WARN(true, "not implemented, just feat RAS");
diff --git a/arch/s390/include/asm/kvm_host_arm64.h b/arch/s390/include/asm/kvm_host_arm64.h
index f62daff3303b..cc457d69621c 100644
--- a/arch/s390/include/asm/kvm_host_arm64.h
+++ b/arch/s390/include/asm/kvm_host_arm64.h
@@ -370,7 +370,7 @@ int __init kvm_sys_reg_table_init(void);
static inline u64 kvm_sanitised_host_ftr_reg(u32 id)
{
- return 0xbad1234bad;
+ return kvm_arm_host_sys_reg_by_id(id);
}
#endif /* ASM_KVM_HOST_ARM64_H */
diff --git a/arch/s390/kvm/arm64/Makefile b/arch/s390/kvm/arm64/Makefile
index 28deeb90efa9..bec24b60a071 100644
--- a/arch/s390/kvm/arm64/Makefile
+++ b/arch/s390/kvm/arm64/Makefile
@@ -15,6 +15,7 @@ kvm-arm64-obj := \
inject_fault.o \
mmu.o \
reset.o \
+ sys_regs.o \
kvm-arm64-obj += $(patsubst %.o,%-arm64.o,$(shared-arm64-obj))
kvm-arm64-obj += $(patsubst %.o,%-arm64.o,$(kvm-y))
diff --git a/arch/s390/kvm/arm64/arm.c b/arch/s390/kvm/arm64/arm.c
index dc0e070f8a62..88b66552cff0 100644
--- a/arch/s390/kvm/arm64/arm.c
+++ b/arch/s390/kvm/arm64/arm.c
@@ -14,6 +14,7 @@
#include <kvm/arm64/handle_exit.h>
#include <kvm/arm64/kvm_emulate.h>
+#include <kvm/arm64/sys_regs.h>
#include <gmap.h>
@@ -227,6 +228,7 @@ bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
{
struct kvm *kvm = vcpu->kvm;
+ int ret;
if (!kvm_vcpu_initialized(vcpu))
return -ENOEXEC;
@@ -237,6 +239,9 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
if (likely(READ_ONCE(vcpu->pid)))
return 0;
+ ret = kvm_finalize_sys_regs(vcpu);
+ if (ret)
+ return ret;
mutex_lock(&kvm->arch.config_lock);
set_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags);
@@ -363,6 +368,9 @@ static void arm_vcpu_run(struct kvm_vcpu *vcpu)
guest_enter_irqoff();
local_irq_enable();
+ vcpu_write_host_sys_reg(vcpu, vcpu->arch.hcr_elz, SYS_HCR_EL2);
+ vcpu_write_host_sys_reg(vcpu, vcpu->arch.hcrx_elz, SYS_HCRX_EL2);
+ vcpu_write_host_sys_reg(vcpu, vcpu->arch.mpidr, SYS_VMPIDR_EL2); //TODO implement mpidr plumbing
sae_block->icptr = 0;
sae64a(sae_block);
@@ -690,15 +698,6 @@ long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,
return -ENOIOCTLCMD;
}
-void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, enum vcpu_sysreg reg)
-{
-}
-
-u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg)
-{
- return 0xbad12324bad;
-}
-
static int __init kvm_s390_arm64_init(void)
{
int err = 0;
@@ -717,6 +716,12 @@ static int __init kvm_s390_arm64_init(void)
if (err)
return err;
+ err = kvm_sys_reg_table_init();
+ if (err) {
+ kvm_info("Error initializing system register tables");
+ return err;
+ }
+
return kvm_init_with_dev(sizeof(struct kvm_vcpu), 0, THIS_MODULE,
KVM_DEV_NAME, MISC_DYNAMIC_MINOR);
}
diff --git a/arch/s390/kvm/arm64/guest.c b/arch/s390/kvm/arm64/guest.c
index 893d48037292..3287059f89c7 100644
--- a/arch/s390/kvm/arm64/guest.c
+++ b/arch/s390/kvm/arm64/guest.c
@@ -2,6 +2,8 @@
#include <linux/kvm_host.h>
#include <linux/kvm.h>
+#include <kvm/arm64/sys_regs.h>
+
#include "guest.h"
const struct kvm_stats_desc kvm_vm_stats_desc[] = {
@@ -42,12 +44,22 @@ const struct kvm_stats_header kvm_vcpu_stats_header = {
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
{
- return copy_core_reg_indices(vcpu, uindices);
+ int ret;
+
+ ret = copy_core_reg_indices(vcpu, uindices);
+ if (ret < 0)
+ return ret;
+ uindices += ret;
+
+ return kvm_arm_copy_sys_reg_indices(vcpu, uindices);
}
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
{
- return num_core_regs(vcpu);
+ unsigned long num = num_core_regs(vcpu);
+
+ num += kvm_arm_num_sys_reg_descs(vcpu);
+ return num;
}
int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
@@ -60,7 +72,7 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
case KVM_REG_ARM_CORE:
return get_core_reg(vcpu, reg);
default:
- return -EINVAL;
+ return kvm_arm_sys_reg_get_reg(vcpu, reg);
}
}
@@ -74,7 +86,7 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
case KVM_REG_ARM_CORE:
return set_core_reg(vcpu, reg);
default:
- return -EINVAL;
+ return kvm_arm_sys_reg_set_reg(vcpu, reg);
}
}
diff --git a/arch/s390/kvm/arm64/handle_exit.c b/arch/s390/kvm/arm64/handle_exit.c
index bccd644fb07c..53aa7f6c4745 100644
--- a/arch/s390/kvm/arm64/handle_exit.c
+++ b/arch/s390/kvm/arm64/handle_exit.c
@@ -47,6 +47,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu)
exit_handle_fn arm_exit_handlers[] = {
[0 ... ESR_ELx_EC_MAX] = kvm_handle_unknown_ec,
[ESR_ELx_EC_HVC64] = handle_hvc,
+ [ESR_ELx_EC_SYS64] = kvm_handle_sys_reg,
[ESR_ELx_EC_IABT_LOW] = kvm_handle_guest_abort,
[ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort,
};
diff --git a/arch/s390/kvm/arm64/reset.c b/arch/s390/kvm/arm64/reset.c
index b38b36c72c72..19404bfb85b6 100644
--- a/arch/s390/kvm/arm64/reset.c
+++ b/arch/s390/kvm/arm64/reset.c
@@ -33,9 +33,14 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu)
vcpu_put(vcpu);
kvm_reset_vcpu_core_regs(vcpu);
+ kvm_reset_sys_regs(vcpu);
/* Reset special registers */
vcpu_reset_hcr(vcpu);
+ vcpu_reset_hcrx(vcpu);
+ vcpu_reset_cptr(vcpu);
+ vcpu_reset_cnthctl(vcpu);
+ vcpu_reset_icc(vcpu);
if (reset_state.reset) {
*vcpu_pc(vcpu) = reset_state.pc;
diff --git a/arch/s390/kvm/arm64/sys_regs.c b/arch/s390/kvm/arm64/sys_regs.c
new file mode 100644
index 000000000000..0bcfdade8509
--- /dev/null
+++ b/arch/s390/kvm/arm64/sys_regs.c
@@ -0,0 +1,769 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/cpumask.h>
+#include <linux/cacheinfo.h>
+#include <linux/kvm_host.h>
+#include <linux/log2.h>
+#include <asm/sysreg-defs.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_feature.h>
+#include <asm/kvm_nested.h>
+
+#include <kvm/arm64/sys_regs.h>
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+#define SR_INVALID 0x8badf00d8badf00d
+
+enum sr_loc_attr {
+ SR_LOC_SAVE_AREA, /* Register on SA, loaded (on cpu) */
+ SR_LOC_SPECIAL, /* Register in state description or Special care register*/
+ SR_LOC_INVALID, /* Register is unknown */
+};
+
+struct sr_loc {
+ enum sr_loc_attr loc;
+};
+
+#define SREG_RANGE(NAME) __##NAME##_BEGIN__ + 1 ... __##NAME##_END__ - 1
+static __always_inline void locate_register(const struct kvm_vcpu *vcpu,
+ enum vcpu_sysreg reg,
+ struct sr_loc *loc)
+{
+ switch (reg) {
+ case SREG_RANGE(STATE_DESC):
+ case SREG_RANGE(SPECIAL):
+ loc->loc = SR_LOC_SPECIAL;
+ break;
+ case SREG_RANGE(SAVE_AREA):
+ loc->loc = SR_LOC_SAVE_AREA;
+ break;
+ default:
+ WARN(true, "%s wants to read invalid register %x", __func__, reg);
+ loc->loc = SR_LOC_INVALID;
+ }
+}
+
+static __always_inline u64 read_special_sr(const struct kvm_vcpu *vcpu,
+ enum vcpu_sysreg reg)
+{
+ switch (reg) {
+ case CLIDR_EL1: return vcpu->arch.sys_reg_clidr_el1;
+ case CSSELR_EL1: return vcpu->arch.sys_reg_csselr_el1;
+ case MPIDR_EL1: return vcpu->arch.mpidr;
+ case CNTP_CTL_EL0: return vcpu->arch.sae_block.cntp_ctl;
+ case CNTV_CTL_EL0: return vcpu->arch.sae_block.cntv_ctl;
+ case CONTEXTIDR_EL1: return vcpu->arch.sae_block.contextidr_el1;
+ case SP_EL1: return vcpu->arch.sae_block.sp_el1;
+ default:
+ WARN(true, "%s wants to read non-special register %x", __func__, reg);
+ return SR_INVALID;
+ }
+}
+
+static __always_inline u64 read_sr_from_vcpu(const struct kvm_vcpu *vcpu,
+ enum vcpu_sysreg reg)
+{
+ switch (reg) {
+ case ACTLR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_ACTLR_EL1);
+ case AFSR0_EL1: return _vcpu_read_sys_reg(vcpu, SYS_AFSR0_EL1);
+ case AFSR1_EL1: return _vcpu_read_sys_reg(vcpu, SYS_AFSR1_EL1);
+ case CNTFRQ_EL0: return _vcpu_read_sys_reg(vcpu, SYS_CNTFRQ_EL0);
+ case CNTP_CVAL_EL0: return _vcpu_read_sys_reg(vcpu, SYS_CNTP_CVAL_EL0);
+ case CNTV_CVAL_EL0: return _vcpu_read_sys_reg(vcpu, SYS_CNTV_CVAL_EL0);
+ case DISR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_DISR_EL1);
+ case MIDR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_MIDR_EL1);
+ case OSLSR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_OSLSR_EL1);
+ case PAR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_PAR_EL1);
+ case SCTLR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_SCTLR_EL1);
+ case CPACR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_CPACR_EL1);
+ case VBAR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_VBAR_EL1);
+ case SPSR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_SPSR_EL1);
+ case ELR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_ELR_EL1);
+ case ESR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_ESR_EL1);
+ case TCR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_TCR_EL1);
+ case MAIR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_MAIR_EL1);
+ case TTBR0_EL1: return _vcpu_read_sys_reg(vcpu, SYS_TTBR0_EL1);
+ case TTBR1_EL1: return _vcpu_read_sys_reg(vcpu, SYS_TTBR1_EL1);
+ case FAR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_FAR_EL1);
+ case TPIDR_EL0: return _vcpu_read_sys_reg(vcpu, SYS_TPIDR_EL0);
+ case TPIDR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_TPIDR_EL1);
+ case TPIDRRO_EL0: return _vcpu_read_sys_reg(vcpu, SYS_TPIDRRO_EL0);
+ case CNTKCTL_EL1: return _vcpu_read_sys_reg(vcpu, SYS_CNTKCTL_EL1);
+ case ZCR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_ZCR_EL1);
+ case SCXTNUM_EL0: return _vcpu_read_sys_reg(vcpu, SYS_SCXTNUM_EL0);
+ case SCXTNUM_EL1: return _vcpu_read_sys_reg(vcpu, SYS_SCXTNUM_EL1);
+ case APIBKEYLO_EL1: return _vcpu_read_sys_reg(vcpu, SYS_APIBKEYLO_EL1);
+ case APIBKEYHI_EL1: return _vcpu_read_sys_reg(vcpu, SYS_APIBKEYHI_EL1);
+ case APIAKEYLO_EL1: return _vcpu_read_sys_reg(vcpu, SYS_APIAKEYLO_EL1);
+ case APIAKEYHI_EL1: return _vcpu_read_sys_reg(vcpu, SYS_APIAKEYHI_EL1);
+ case APGAKEYLO_EL1: return _vcpu_read_sys_reg(vcpu, SYS_APGAKEYLO_EL1);
+ case APGAKEYHI_EL1: return _vcpu_read_sys_reg(vcpu, SYS_APGAKEYHI_EL1);
+ case APDBKEYLO_EL1: return _vcpu_read_sys_reg(vcpu, SYS_APDBKEYLO_EL1);
+ case APDBKEYHI_EL1: return _vcpu_read_sys_reg(vcpu, SYS_APDBKEYHI_EL1);
+ case APDAKEYLO_EL1: return _vcpu_read_sys_reg(vcpu, SYS_APDAKEYLO_EL1);
+ case APDAKEYHI_EL1: return _vcpu_read_sys_reg(vcpu, SYS_APDAKEYHI_EL1);
+ case MDSCR_EL1: return _vcpu_read_sys_reg(vcpu, SYS_MDSCR_EL1);
+ default:
+ WARN(true, "%s: failed to resolve %x", __func__, reg);
+ return SR_INVALID;
+ }
+}
+
+u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg reg)
+{
+ struct sr_loc loc = {};
+
+ locate_register(vcpu, reg, &loc);
+
+ if (unlikely(loc.loc == SR_LOC_INVALID)) {
+ WARN(true, "%s: failed to locate %u", __func__, reg);
+ return SR_INVALID;
+ }
+
+ if (loc.loc == SR_LOC_SPECIAL)
+ return read_special_sr(vcpu, reg);
+
+ return read_sr_from_vcpu(vcpu, reg);
+}
+
+static __always_inline void write_special_sr(struct kvm_vcpu *vcpu, u64 val,
+ enum vcpu_sysreg reg)
+{
+ switch (reg) {
+ case CLIDR_EL1: vcpu->arch.sys_reg_clidr_el1 = val; break;
+ case CSSELR_EL1: vcpu->arch.sys_reg_csselr_el1 = val; break;
+ case MPIDR_EL1: vcpu->arch.mpidr = val; break;
+ case CNTP_CTL_EL0: vcpu->arch.sae_block.cntp_ctl = val; break;
+ case CNTV_CTL_EL0: vcpu->arch.sae_block.cntv_ctl = val; break;
+ case CONTEXTIDR_EL1: vcpu->arch.sae_block.contextidr_el1 = val; break;
+ case SP_EL1: vcpu->arch.sae_block.sp_el1 = val; break;
+ default:
+ WARN(true, "%s wants to write non-special register %x", __func__, reg);
+ }
+}
+
+static __always_inline void write_sr_to_vcpu(struct kvm_vcpu *vcpu, u64 val,
+ enum vcpu_sysreg reg)
+{
+ switch (reg) {
+ case ACTLR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_ACTLR_EL1); break;
+ case AFSR0_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_AFSR0_EL1); break;
+ case AFSR1_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_AFSR1_EL1); break;
+ case CNTFRQ_EL0: _vcpu_write_sys_reg(vcpu, val, SYS_CNTFRQ_EL0); break;
+ case CNTP_CVAL_EL0: _vcpu_write_sys_reg(vcpu, val, SYS_CNTP_CVAL_EL0); break;
+ case CNTV_CVAL_EL0: _vcpu_write_sys_reg(vcpu, val, SYS_CNTV_CVAL_EL0); break;
+ case DISR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_DISR_EL1); break;
+ case MIDR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_MIDR_EL1); break;
+ case PAR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_PAR_EL1); break;
+ case OSLAR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_OSLAR_EL1); break;
+ case SCTLR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_SCTLR_EL1); break;
+ case CPACR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_CPACR_EL1); break;
+ case VBAR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_VBAR_EL1); break;
+ case SPSR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_SPSR_EL1); break;
+ case ELR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_ELR_EL1); break;
+ case ESR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_ESR_EL1); break;
+ case TCR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_TCR_EL1); break;
+ case MAIR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_MAIR_EL1); break;
+ case TTBR0_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_TTBR0_EL1); break;
+ case TTBR1_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_TTBR1_EL1); break;
+ case FAR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_FAR_EL1); break;
+ case TPIDR_EL0: _vcpu_write_sys_reg(vcpu, val, SYS_TPIDR_EL0); break;
+ case TPIDR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_TPIDR_EL1); break;
+ case TPIDRRO_EL0: _vcpu_write_sys_reg(vcpu, val, SYS_TPIDRRO_EL0); break;
+ case CNTKCTL_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_CNTKCTL_EL1); break;
+ case ZCR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_ZCR_EL1); break;
+ case SCXTNUM_EL0: _vcpu_write_sys_reg(vcpu, val, SYS_SCXTNUM_EL0); break;
+ case SCXTNUM_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_SCXTNUM_EL1); break;
+ case APIBKEYLO_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_APIBKEYLO_EL1); break;
+ case APIBKEYHI_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_APIBKEYHI_EL1); break;
+ case APIAKEYLO_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_APIAKEYLO_EL1); break;
+ case APIAKEYHI_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_APIAKEYHI_EL1); break;
+ case APGAKEYLO_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_APGAKEYLO_EL1); break;
+ case APGAKEYHI_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_APGAKEYHI_EL1); break;
+ case APDBKEYLO_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_APDBKEYLO_EL1); break;
+ case APDBKEYHI_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_APDBKEYHI_EL1); break;
+ case APDAKEYLO_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_APDAKEYLO_EL1); break;
+ case APDAKEYHI_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_APDAKEYHI_EL1); break;
+ case MDSCR_EL1: _vcpu_write_sys_reg(vcpu, val, SYS_MDSCR_EL1); break;
+ default:
+ WARN(true, "%s: failed to resolve %x", __func__, reg);
+ }
+}
+
+void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, enum vcpu_sysreg reg)
+{
+ struct sr_loc loc = {};
+
+ locate_register(vcpu, reg, &loc);
+
+ if (unlikely(loc.loc == SR_LOC_INVALID)) {
+ WARN(true, "%s: failed to locate %u", __func__, reg);
+ return;
+ }
+
+ if (loc.loc == SR_LOC_SPECIAL) {
+ write_special_sr(vcpu, val, reg);
+ return;
+ }
+
+ write_sr_to_vcpu(vcpu, val, reg);
+}
+
+u64 vcpu_read_host_sys_reg(const struct kvm_vcpu *vcpu, int reg)
+{
+ switch (reg) {
+ case SYS_ICH_LR0_EL2: return vcpu->arch.sae_block.ic_regs.ich_lrn_el2[0];
+ case SYS_ICH_LR1_EL2: return vcpu->arch.sae_block.ic_regs.ich_lrn_el2[1];
+ case SYS_ICH_LR2_EL2: return vcpu->arch.sae_block.ic_regs.ich_lrn_el2[2];
+ case SYS_ICH_LR3_EL2: return vcpu->arch.sae_block.ic_regs.ich_lrn_el2[3];
+ case SYS_ICH_HCR_EL2: return vcpu->arch.sae_block.ic_regs.ich_hcr_el2;
+ case SYS_ICH_AP0R0_EL2: return vcpu->arch.sae_block.ic_regs.ich_ap0r0_el2;
+ case SYS_ICH_AP1R0_EL2: return vcpu->arch.sae_block.ic_regs.ich_ap1r0_el2;
+ case SYS_ICH_VMCR_EL2: return vcpu->arch.sae_block.ic_regs.ich_vmcr_el2;
+ case SYS_VSESR_EL2: return _vcpu_read_sys_reg(vcpu, SYS_VSESR_EL2);
+ case SYS_HCR_EL2: return _vcpu_read_sys_reg(vcpu, SYS_HCR_EL2);
+ case SYS_CPTR_EL2: return _vcpu_read_sys_reg(vcpu, SYS_CPTR_EL2);
+ case SYS_MDCR_EL2: return _vcpu_read_sys_reg(vcpu, SYS_MDCR_EL2);
+ case SYS_HCRX_EL2: return _vcpu_read_sys_reg(vcpu, SYS_HCRX_EL2);
+ case SYS_HFGRTR_EL2: return _vcpu_read_sys_reg(vcpu, SYS_HFGRTR_EL2);
+ case SYS_HFGWTR_EL2: return _vcpu_read_sys_reg(vcpu, SYS_HFGWTR_EL2);
+ case SYS_HDFGWTR_EL2: return _vcpu_read_sys_reg(vcpu, SYS_HDFGWTR_EL2);
+ case SYS_HDFGRTR_EL2: return _vcpu_read_sys_reg(vcpu, SYS_HDFGRTR_EL2);
+ case SYS_HFGITR_EL2: return _vcpu_read_sys_reg(vcpu, SYS_HFGITR_EL2);
+ case SYS_CNTHCTL_EL2: return _vcpu_read_sys_reg(vcpu, SYS_CNTHCTL_EL2);
+ case SYS_ICC_SRE_EL2: return _vcpu_read_sys_reg(vcpu, SYS_ICC_SRE_EL2);
+ case SYS_VMPIDR_EL2: return _vcpu_read_sys_reg(vcpu, SYS_VMPIDR_EL2);
+ default:
+ WARN(true, "%s wants to read non-host register %x", __func__, reg);
+ return SR_INVALID;
+ }
+}
+
+void vcpu_write_host_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
+{
+ switch (reg) {
+ case SYS_ICH_LR0_EL2: vcpu->arch.sae_block.ic_regs.ich_lrn_el2[0] = val; break;
+ case SYS_ICH_LR1_EL2: vcpu->arch.sae_block.ic_regs.ich_lrn_el2[1] = val; break;
+ case SYS_ICH_LR2_EL2: vcpu->arch.sae_block.ic_regs.ich_lrn_el2[2] = val; break;
+ case SYS_ICH_LR3_EL2: vcpu->arch.sae_block.ic_regs.ich_lrn_el2[3] = val; break;
+ case SYS_ICH_HCR_EL2: vcpu->arch.sae_block.ic_regs.ich_hcr_el2 = val; break;
+ case SYS_ICH_AP0R0_EL2: vcpu->arch.sae_block.ic_regs.ich_ap0r0_el2 = val; break;
+ case SYS_ICH_AP1R0_EL2: vcpu->arch.sae_block.ic_regs.ich_ap1r0_el2 = val; break;
+ case SYS_ICH_VMCR_EL2: vcpu->arch.sae_block.ic_regs.ich_vmcr_el2 = val; break;
+ case SYS_VSESR_EL2: _vcpu_write_sys_reg(vcpu, val, SYS_VSESR_EL2); break;
+ case SYS_HCR_EL2: _vcpu_write_sys_reg(vcpu, val, SYS_HCR_EL2); break;
+ case SYS_CPTR_EL2: _vcpu_write_sys_reg(vcpu, val, SYS_CPTR_EL2); break;
+ case SYS_MDCR_EL2: _vcpu_write_sys_reg(vcpu, val, SYS_MDCR_EL2); break;
+ case SYS_HCRX_EL2: _vcpu_write_sys_reg(vcpu, val, SYS_HCRX_EL2); break;
+ case SYS_HFGRTR_EL2: _vcpu_write_sys_reg(vcpu, val, SYS_HFGRTR_EL2); break;
+ case SYS_HFGWTR_EL2: _vcpu_write_sys_reg(vcpu, val, SYS_HFGWTR_EL2); break;
+ case SYS_HDFGWTR_EL2: _vcpu_write_sys_reg(vcpu, val, SYS_HDFGWTR_EL2); break;
+ case SYS_HDFGRTR_EL2: _vcpu_write_sys_reg(vcpu, val, SYS_HDFGRTR_EL2); break;
+ case SYS_HFGITR_EL2: _vcpu_write_sys_reg(vcpu, val, SYS_HFGITR_EL2); break;
+ case SYS_CNTHCTL_EL2: _vcpu_write_sys_reg(vcpu, val, SYS_CNTHCTL_EL2); break;
+ case SYS_ICC_SRE_EL2: _vcpu_write_sys_reg(vcpu, val, SYS_ICC_SRE_EL2); break;
+ case SYS_VMPIDR_EL2: _vcpu_write_sys_reg(vcpu, val, SYS_VMPIDR_EL2); break;
+ default:
+ WARN(true, "%s wants to write non-host register %x", __func__, reg);
+ }
+}
+
+static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd,
+ u64 val)
+{
+ u8 debugver = SYS_FIELD_GET(ID_AA64DFR0_EL1, DebugVer, val);
+ u8 pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, val);
+
+ if (pmuver == ID_AA64DFR0_EL1_PMUVer_IMP_DEF)
+ return -EINVAL;
+
+ /*
+ * ID_AA64DFR0_EL1.DebugVer is one of those awkward fields with a
+ * nonzero minimum safe value.
+ */
+ if (debugver < ID_AA64DFR0_EL1_DebugVer_IMP)
+ return -EINVAL;
+
+ return set_id_reg(vcpu, rd, val);
+}
+
+static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd, u64 user_val)
+{
+ /* Fail the guest's request to disable the AA64 ISA at EL{0,1,2} */
+ if (!FIELD_GET(ID_AA64PFR0_EL1_EL0, user_val) ||
+ !FIELD_GET(ID_AA64PFR0_EL1_EL1, user_val) ||
+ (vcpu_has_nv(vcpu) && !FIELD_GET(ID_AA64PFR0_EL1_EL2, user_val)))
+ return -EINVAL;
+
+ return set_id_reg(vcpu, rd, user_val);
+}
+
+int arm64_check_features(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd,
+ u64 val)
+{
+ u32 id = reg_to_encoding(rd);
+ u64 host_val;
+ u64 old_val;
+
+ /*
+ * This is a very minimal implementation to sanitise only the craziest
+ * shenanigans we could get from userspace. The final goal is to share
+ * the sanitisation with arm as well but this needs access to arm
+ * (core) kernel code for which there is no suitable solution yet. TODO
+ */
+
+ /*
+ * If the register is RAZ we know the only safe value is 0.
+ */
+ if (sysreg_visible_as_raz(vcpu, rd))
+ return val ? -E2BIG : 0;
+
+ host_val = kvm_arm_host_sys_reg_by_id(id);
+
+ switch (id) {
+ case SYS_ID_AA64MMFR0_EL1:
+ /* Forbid PRANGE values we do not know about */
+ if (SYS_FIELD_GET(ID_AA64MMFR0_EL1, PARANGE, host_val) >
+ ID_AA64MMFR0_EL1_PARANGE_56)
+ return -E2BIG;
+ break;
+ case SYS_CTR_EL0:
+ /* forbid upgrading from VIPT to PIPT */
+ old_val = read_id_reg(vcpu, rd);
+ if (SYS_FIELD_GET(CTR_EL0, L1Ip, old_val) == CTR_EL0_L1Ip_VIPT &&
+ SYS_FIELD_GET(CTR_EL0, L1Ip, val) == CTR_EL0_L1Ip_PIPT)
+ return -E2BIG;
+ break;
+ }
+ return 0;
+}
+
+static u64 __ro_after_init boot_cpu_midr_val;
+static u64 __ro_after_init boot_cpu_revidr_val;
+static u64 __ro_after_init boot_cpu_aidr_val;
+
+static void init_imp_id_regs(void)
+{
+ boot_cpu_midr_val = kvm_arm_host_sys_reg_by_name(MIDR_EL1);
+ boot_cpu_revidr_val = kvm_arm_host_sys_reg_by_name(REVIDR_EL1);
+ boot_cpu_aidr_val = 0xC0FFEE; // TODO qaaf support needed.
+}
+
+u64 reset_imp_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+ switch (reg_to_encoding(r)) {
+ case SYS_MIDR_EL1:
+ return boot_cpu_midr_val;
+ case SYS_REVIDR_EL1:
+ return boot_cpu_revidr_val;
+ case SYS_AIDR_EL1:
+ return boot_cpu_aidr_val;
+ default:
+ KVM_BUG_ON(1, vcpu->kvm);
+ return 0;
+ }
+}
+
+bool access_imp_id_reg(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ if (p->is_write)
+ return write_to_read_only(vcpu, p, r);
+
+ /*
+ * Return the VM-scoped implementation ID register values if userspace
+ * has made them writable.
+ */
+ if (test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &vcpu->kvm->arch.flags))
+ return access_id_reg(vcpu, p, r);
+
+ switch (reg_to_encoding(r)) {
+ case SYS_REVIDR_EL1:
+ p->regval = boot_cpu_revidr_val; //no old api to conform to?
+ break;
+ case SYS_AIDR_EL1:
+ p->regval = boot_cpu_aidr_val;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ }
+
+ return true;
+}
+
+static int get_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, u64 *val)
+{
+ *val = vcpu->arch.mpidr;
+ return 0;
+}
+
+static int set_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, u64 val)
+{
+ vcpu->arch.mpidr = val;
+ return 0;
+}
+
+static u64 reset_midr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+ _vcpu_write_sys_reg(vcpu, boot_cpu_midr_val, SYS_MIDR_EL1);
+ return boot_cpu_midr_val;
+}
+
+static u64 reset_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+ u64 oslsr = r->val;
+
+ set_oslsr_el1(vcpu, r, oslsr);
+ return oslsr;
+}
+
+static int arch_timer_set_user(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd,
+ u64 val)
+{
+ switch (reg_to_encoding(rd)) {
+ case SYS_CNTVCT_EL0:
+ vcpu->arch.sae_block.gpto = ptff_qagto(val);
+ return 0;
+ case SYS_CNTPCT_EL0:
+ return 0;
+ }
+
+ __vcpu_assign_sys_reg(vcpu, rd->reg, val);
+ return 0;
+}
+
+static int arch_timer_get_user(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd,
+ u64 *val)
+{
+ switch (reg_to_encoding(rd)) {
+ case SYS_CNTVCT_EL0:
+ *val = ptff_qagpt(vcpu->arch.sae_block.gpto);
+ break;
+ case SYS_CNTPCT_EL0:
+ *val = ptff_qagpt(vcpu->arch.sae_block.gpto);
+ break;
+ default:
+ *val = __vcpu_sys_reg(vcpu, rd->reg);
+ }
+
+ return 0;
+}
+
+#define TIMER_REG(name) { \
+ SYS_DESC(SYS_##name), \
+ .reset = reset_val, \
+ .reg = name, \
+ .get_user = arch_timer_get_user, \
+ .set_user = arch_timer_set_user, \
+}
+
+/*
+ * Architected system registers.
+ * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
+ */
+static const struct sys_reg_desc sys_reg_descs[] = {
+ /* Op0 = 2 */
+ { SYS_DESC(SYS_OSLAR_EL1), trap_oslar_el1 },
+ { SYS_DESC(SYS_OSLSR_EL1), trap_oslsr_el1, reset_oslsr_el1, OSLSR_EL1,
+ OSLSR_EL1_OSLM_IMPLEMENTED, NULL, set_oslsr_el1 },
+
+ /* Op0 = 3 */
+ /* Op1 = 0 */
+ /* CRn = 0 */
+ /* CRm = 0 */
+
+ //should not trap, right?
+ { SYS_DESC(SYS_MIDR_EL1), NULL, reset_midr, 0, GENMASK_ULL(31, 0),
+ get_id_reg, set_imp_id_reg },
+ { SYS_DESC(SYS_MPIDR_EL1), NULL, reset_mpidr, MPIDR_EL1, 0, get_mpidr,
+ set_mpidr },
+ IMPLEMENTATION_ID(REVIDR_EL1, GENMASK_ULL(63, 0)),
+
+ /*
+ * ID regs: all ID_SANITISED() entries here must have corresponding
+ * entries in arm64_ftr_regs[].
+ */
+
+ /* AArch64 mappings of the AArch32 ID registers */
+ /* CRm=1 */
+ ID_HIDDEN(ID_PFR0_EL1),
+ ID_HIDDEN(ID_PFR1_EL1),
+ ID_HIDDEN(ID_DFR0_EL1),
+ ID_HIDDEN(ID_AFR0_EL1),
+ ID_HIDDEN(ID_MMFR0_EL1),
+ ID_HIDDEN(ID_MMFR1_EL1),
+ ID_HIDDEN(ID_MMFR2_EL1),
+ ID_HIDDEN(ID_MMFR3_EL1),
+
+ /* CRm=2 */
+ ID_HIDDEN(ID_ISAR0_EL1),
+ ID_HIDDEN(ID_ISAR1_EL1),
+ ID_HIDDEN(ID_ISAR2_EL1),
+ ID_HIDDEN(ID_ISAR3_EL1),
+ ID_HIDDEN(ID_ISAR4_EL1),
+ ID_HIDDEN(ID_ISAR5_EL1),
+ ID_HIDDEN(ID_MMFR4_EL1),
+ ID_HIDDEN(ID_ISAR6_EL1),
+
+ /* CRm=3 */
+ ID_HIDDEN(MVFR0_EL1),
+ ID_HIDDEN(MVFR1_EL1),
+ ID_HIDDEN(MVFR2_EL1),
+ ID_UNALLOCATED(3, 3),
+ ID_HIDDEN(ID_PFR2_EL1),
+ ID_HIDDEN(ID_DFR1_EL1),
+ ID_HIDDEN(ID_MMFR5_EL1),
+ ID_UNALLOCATED(3, 7),
+
+ /* AArch64 ID registers */
+ /* CRm=4 */
+ ID_FILTERED(ID_AA64PFR0_EL1, id_aa64pfr0_el1,
+ ~(ID_AA64PFR0_EL1_AMU | ID_AA64PFR0_EL1_MPAM |
+ ID_AA64PFR0_EL1_SVE | ID_AA64PFR0_EL1_RAS |
+ ID_AA64PFR0_EL1_GIC | ID_AA64PFR0_EL1_AdvSIMD |
+ ID_AA64PFR0_EL1_FP)),
+ ID_WRITABLE(ID_AA64PFR1_EL1,
+ ~(ID_AA64PFR1_EL1_PFAR | ID_AA64PFR1_EL1_DF2 |
+ ID_AA64PFR1_EL1_MTEX | ID_AA64PFR1_EL1_THE |
+ ID_AA64PFR1_EL1_GCS | ID_AA64PFR1_EL1_MTE_frac |
+ ID_AA64PFR1_EL1_NMI | ID_AA64PFR1_EL1_RNDR_trap |
+ ID_AA64PFR1_EL1_SME | ID_AA64PFR1_EL1_RES0 |
+ ID_AA64PFR1_EL1_MPAM_frac | ID_AA64PFR1_EL1_RAS_frac |
+ ID_AA64PFR1_EL1_MTE)),
+ ID_WRITABLE(ID_AA64PFR2_EL1, ID_AA64PFR2_EL1_FPMR),
+ ID_UNALLOCATED(4, 3),
+ ID_WRITABLE(ID_AA64ZFR0_EL1, ~ID_AA64ZFR0_EL1_RES0),
+ ID_HIDDEN(ID_AA64SMFR0_EL1),
+ ID_UNALLOCATED(4, 6),
+ ID_WRITABLE(ID_AA64FPFR0_EL1, ~ID_AA64FPFR0_EL1_RES0),
+
+ /* CRm=5 */
+ /*
+ * Prior to FEAT_Debugv8.9, the architecture defines context-aware
+ * breakpoints (CTX_CMPs) as the highest numbered breakpoints (BRPs).
+ * KVM does not trap + emulate the breakpoint registers, and as such
+ * cannot support a layout that misaligns with the underlying hardware.
+ * While it may be possible to describe a subset that aligns with
+ * hardware, just prevent changes to BRPs and CTX_CMPs altogether for
+ * simplicity.
+ *
+ * See DDI0487K.a, section D2.8.3 Breakpoint types and linking
+ * of breakpoints for more details.
+ */
+ ID_FILTERED(ID_AA64DFR0_EL1, id_aa64dfr0_el1,
+ ID_AA64DFR0_EL1_DoubleLock_MASK |
+ ID_AA64DFR0_EL1_WRPs_MASK |
+ ID_AA64DFR0_EL1_PMUVer_MASK |
+ ID_AA64DFR0_EL1_DebugVer_MASK),
+ ID_SANITISED(ID_AA64DFR1_EL1),
+ ID_UNALLOCATED(5, 2),
+ ID_UNALLOCATED(5, 3),
+ ID_HIDDEN(ID_AA64AFR0_EL1),
+ ID_HIDDEN(ID_AA64AFR1_EL1),
+ ID_UNALLOCATED(5, 6),
+ ID_UNALLOCATED(5, 7),
+
+ /* CRm=6 */
+ ID_WRITABLE(ID_AA64ISAR0_EL1, ~ID_AA64ISAR0_EL1_RES0),
+ ID_WRITABLE(ID_AA64ISAR1_EL1,
+ ~(ID_AA64ISAR1_EL1_GPI | ID_AA64ISAR1_EL1_GPA |
+ ID_AA64ISAR1_EL1_API | ID_AA64ISAR1_EL1_APA)),
+ ID_WRITABLE(ID_AA64ISAR2_EL1,
+ ~(ID_AA64ISAR2_EL1_RES0 | ID_AA64ISAR2_EL1_APA3 |
+ ID_AA64ISAR2_EL1_GPA3)),
+ ID_WRITABLE(ID_AA64ISAR3_EL1,
+ (ID_AA64ISAR3_EL1_FPRCVT | ID_AA64ISAR3_EL1_FAMINMAX)),
+ ID_UNALLOCATED(6, 4),
+ ID_UNALLOCATED(6, 5),
+ ID_UNALLOCATED(6, 6),
+ ID_UNALLOCATED(6, 7),
+
+ /* CRm=7 */
+ ID_FILTERED(ID_AA64MMFR0_EL1, id_aa64mmfr0_el1,
+ ~(ID_AA64MMFR0_EL1_RES0 | ID_AA64MMFR0_EL1_ASIDBITS)),
+ ID_WRITABLE(ID_AA64MMFR1_EL1,
+ ~(ID_AA64MMFR1_EL1_RES0 | ID_AA64MMFR1_EL1_HCX |
+ ID_AA64MMFR1_EL1_TWED | ID_AA64MMFR1_EL1_XNX |
+ ID_AA64MMFR1_EL1_VH | ID_AA64MMFR1_EL1_VMIDBits)),
+ ID_WRITABLE(ID_AA64MMFR2_EL1,
+ ~(ID_AA64MMFR2_EL1_RES0 | ID_AA64MMFR2_EL1_EVT |
+ ID_AA64MMFR2_EL1_FWB | ID_AA64MMFR2_EL1_IDS |
+ ID_AA64MMFR2_EL1_NV | ID_AA64MMFR2_EL1_CCIDX)),
+ ID_WRITABLE(ID_AA64MMFR3_EL1,
+ (ID_AA64MMFR3_EL1_TCRX | ID_AA64MMFR3_EL1_S1PIE |
+ ID_AA64MMFR3_EL1_S1POE)),
+ ID_WRITABLE(ID_AA64MMFR4_EL1, ID_AA64MMFR4_EL1_NV_frac),
+ ID_UNALLOCATED(7, 5),
+ ID_UNALLOCATED(7, 6),
+ ID_UNALLOCATED(7, 7),
+
+ /* CRn = 1 */
+ { SYS_DESC(SYS_SCTLR_EL1), NULL, reset_val, SCTLR_EL1, 0x00C50078 },
+ { SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
+
+ /* CRn = 2 */
+ { SYS_DESC(SYS_TTBR0_EL1), access_rw, reset_val, TTBR0_EL1, 0 },
+ { SYS_DESC(SYS_TTBR1_EL1), access_rw, reset_val, TTBR1_EL1, 0 },
+ { SYS_DESC(SYS_TCR_EL1), access_rw, reset_val, TCR_EL1, 0 },
+
+ { SYS_DESC(SYS_PMMIR_EL1), trap_raz_wi },
+ /* CRn = 10 */
+ { SYS_DESC(SYS_MAIR_EL1), NULL, reset_unknown, MAIR_EL1 },
+
+ /* CRn = 12 */
+ { SYS_DESC(SYS_VBAR_EL1), access_rw, reset_val, VBAR_EL1, 0 },
+
+ /* CRn = 13 */
+ { SYS_DESC(SYS_TPIDR_EL1), NULL, reset_unknown, TPIDR_EL1 },
+
+ /* Op1 = 1 */
+ /* CRn = 0 */
+ /* CRm = 0 */
+ { SYS_DESC(SYS_CCSIDR_EL1), access_ccsidr },
+ { SYS_DESC(SYS_CLIDR_EL1), access_clidr, reset_clidr, CLIDR_EL1,
+ ~CLIDR_EL1_RES0, .set_user = set_clidr },
+ IMPLEMENTATION_ID(AIDR_EL1, GENMASK_ULL(63, 0)),
+ { SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
+ ID_FILTERED(CTR_EL0, ctr_el0,
+ CTR_EL0_DIC_MASK | CTR_EL0_IDC_MASK |
+ CTR_EL0_DminLine_MASK | CTR_EL0_L1Ip_MASK |
+ CTR_EL0_IminLine_MASK),
+
+ { SYS_DESC(SYS_CNTFRQ_EL0), NULL, reset_val, CNTFRQ_EL0, 0x3B9ACA00 },
+ { SYS_DESC(SYS_CNTVCT_EL0), .get_user = arch_timer_get_user,
+ .set_user = arch_timer_set_user },
+ TIMER_REG(CNTP_CTL_EL0),
+ TIMER_REG(CNTP_CVAL_EL0),
+ TIMER_REG(CNTV_CTL_EL0),
+ TIMER_REG(CNTV_CVAL_EL0),
+
+};
+
+/*
+ * kvm_handle_sys_reg -- handles a system instruction or mrs/msr instruction
+ * trap on a guest execution
+ * @vcpu: The VCPU pointer
+ */
+int kvm_handle_sys_reg(struct kvm_vcpu *vcpu)
+{
+ const struct sys_reg_desc *desc = NULL;
+ struct sys_reg_params params;
+ unsigned long esr = kvm_vcpu_get_esr(vcpu);
+ int Rt = kvm_vcpu_sys_get_rt(vcpu);
+
+ trace_kvm_handle_sys_reg(esr);
+
+ params = esr_sys64_to_params(esr);
+ params.regval = vcpu_get_reg(vcpu, Rt);
+
+ /* System registers have Op0=={2,3}, as per DDI487 J.a C5.1.2 */
+ if (params.Op0 == 2 || params.Op0 == 3)
+ desc = find_reg(¶ms, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
+ else
+ WARN(true, "system instruction handling not supported");
+
+ if (!desc) {
+ if (!(params.Op0 == 3 && (params.CRn & 0b1011) == 0b1011))
+ print_sys_reg_msg(¶ms,
+ "Unsupported guest access at: %lx\n",
+ *vcpu_pc(vcpu));
+ kvm_inject_undefined(vcpu);
+ return 1;
+ } else {
+ perform_access(vcpu, ¶ms, desc);
+ }
+
+ /* Read from system register? */
+ if (!params.is_write &&
+ (params.Op0 == 2 || params.Op0 == 3))
+ vcpu_set_reg(vcpu, Rt, params.regval);
+
+ return 1;
+}
+
+void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
+{
+ struct kvm *kvm = vcpu->kvm;
+ unsigned long i;
+
+ for (i = 0; i < ARRAY_SIZE(sys_reg_descs); i++) {
+ const struct sys_reg_desc *r = &sys_reg_descs[i];
+
+ if (!r->reset)
+ continue;
+
+ if (is_vm_ftr_id_reg(reg_to_encoding(r))) {
+ reset_vm_ftr_id_reg(vcpu, r);
+ /*
+ * Even VM only regs are stored in the save area of the vcpu
+ * and need a meaningful initial value. Call reset because of this.
+ */
+ r->reset(vcpu, r);
+ } else if (is_vcpu_ftr_id_reg(reg_to_encoding(r))) {
+ reset_vcpu_ftr_id_reg(vcpu, r);
+ } else {
+ r->reset(vcpu, r);
+ }
+ }
+ set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags);
+}
+
+int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu,
+ const struct kvm_one_reg *reg)
+{
+ return __kvm_arm_sys_reg_get_reg(vcpu, reg, ARRAY_SIZE(sys_reg_descs),
+ sys_reg_descs);
+}
+
+int __init kvm_sys_reg_table_init(void)
+{
+ init_imp_id_regs();
+
+ bool valid = check_sysreg_table(sys_reg_descs,
+ ARRAY_SIZE(sys_reg_descs), false);
+
+ if (!valid)
+ return -EINVAL;
+
+ return 0;
+}
+
+unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu)
+{
+ return __kvm_arm_num_sys_reg_descs(vcpu, ARRAY_SIZE(sys_reg_descs),
+ sys_reg_descs);
+}
+
+int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+ return __kvm_arm_copy_sys_reg_indices(vcpu, uindices,
+ ARRAY_SIZE(sys_reg_descs),
+ sys_reg_descs);
+}
+
+int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu,
+ const struct kvm_one_reg *reg)
+{
+ return __kvm_arm_sys_reg_set_reg(vcpu, reg, ARRAY_SIZE(sys_reg_descs),
+ sys_reg_descs);
+}
+
+/*
+ * Perform last adjustments to the ID registers that are implied by the
+ * configuration outside of the ID regs themselves, as well as any
+ * initialisation that directly depend on these ID registers (such as
+ * RES0/RES1 behaviours). This is not the place to configure traps though.
+ *
+ * Because this can be called once per CPU, changes must be idempotent.
+ */
+int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu)
+{
+ /* TODO GIC finalization */
+ return 0;
+}
diff --git a/arch/s390/kvm/arm64/trace.h b/arch/s390/kvm/arm64/trace.h
new file mode 100644
index 000000000000..015f380207ab
--- /dev/null
+++ b/arch/s390/kvm/arm64/trace.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if !defined(_TRACE_ARM64_KVM_S390_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ARM64_KVM_S390_H
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvm
+
+TRACE_EVENT(kvm_handle_sys_reg,
+ TP_PROTO(unsigned long esr),
+ TP_ARGS(esr),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, esr)
+ ),
+
+ TP_fast_assign(
+ __entry->esr = esr;
+ ),
+
+ TP_printk("ESR 0x%08lx", __entry->esr)
+);
+
+#endif /* _TRACE_ARM64_KVM_S390_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../arch/s390/kvm/arm64
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/virt/kvm/arm64/Makefile.kvm b/virt/kvm/arm64/Makefile.kvm
index c5e1db570a09..9a3df2446b8b 100644
--- a/virt/kvm/arm64/Makefile.kvm
+++ b/virt/kvm/arm64/Makefile.kvm
@@ -10,4 +10,5 @@ shared-arm64-obj := \
$(KVM_ARM64)/handle_exit.o \
$(KVM_ARM64)/mmio.o \
$(KVM_ARM64)/reset.o \
+ $(KVM_ARM64)/sys_regs.o \
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 25/26] KVM: s390: arm64: Implement exception injection
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (22 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 24/26] KVM: s390: arm64: Implement sysreg handling Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 26/26] KVM: s390: arm64: Finalize page fault handling Steffen Eiden
2026-06-01 15:52 ` [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Claudio Imbrenda
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Add exception injection support for s390 KVM arm64 architecture. This
implements the core exception entry mechanism and fault injection
functions needed for proper guest exception handling.
Co-developed-by: Andreas Grapentin <gra@linux.ibm.com>
Signed-off-by: Andreas Grapentin <gra@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/include/asm/kvm_host_arm64.h | 2 +
arch/s390/kvm/arm64/Makefile | 1 +
arch/s390/kvm/arm64/arm.c | 15 +---
arch/s390/kvm/arm64/exception.c | 105 +++++++++++++++++++++++++
arch/s390/kvm/arm64/inject_fault.c | 72 ++++++++++++++++-
5 files changed, 182 insertions(+), 13 deletions(-)
create mode 100644 arch/s390/kvm/arm64/exception.c
diff --git a/arch/s390/include/asm/kvm_host_arm64.h b/arch/s390/include/asm/kvm_host_arm64.h
index cc457d69621c..34d131b36e70 100644
--- a/arch/s390/include/asm/kvm_host_arm64.h
+++ b/arch/s390/include/asm/kvm_host_arm64.h
@@ -373,4 +373,6 @@ static inline u64 kvm_sanitised_host_ftr_reg(u32 id)
return kvm_arm_host_sys_reg_by_id(id);
}
+void kvm_adjust_pc(struct kvm_vcpu *vcpu);
+
#endif /* ASM_KVM_HOST_ARM64_H */
diff --git a/arch/s390/kvm/arm64/Makefile b/arch/s390/kvm/arm64/Makefile
index bec24b60a071..9d6b7d5bf588 100644
--- a/arch/s390/kvm/arm64/Makefile
+++ b/arch/s390/kvm/arm64/Makefile
@@ -9,6 +9,7 @@ ccflags-y += -I $(src) -I$(srctree)/arch/s390/kvm/gmap -DKVM_S390_ARM64
kvm-arm64-obj := \
arm.o \
+ exception.o \
feature.o \
guest.o \
handle_exit.o \
diff --git a/arch/s390/kvm/arm64/arm.c b/arch/s390/kvm/arm64/arm.c
index 88b66552cff0..c62e50002628 100644
--- a/arch/s390/kvm/arm64/arm.c
+++ b/arch/s390/kvm/arm64/arm.c
@@ -350,19 +350,11 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
return 0;
}
-static void adjust_pc(struct kvm_vcpu *vcpu)
-{
- if (vcpu_get_flag(vcpu, INCREMENT_PC)) {
- kvm_skip_instr(vcpu);
- vcpu_clear_flag(vcpu, INCREMENT_PC);
- }
-}
-
static void arm_vcpu_run(struct kvm_vcpu *vcpu)
{
struct kvm_sae_block *sae_block = &vcpu->arch.sae_block;
- adjust_pc(vcpu);
+ kvm_adjust_pc(vcpu);
local_irq_disable();
guest_enter_irqoff();
@@ -457,8 +449,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
kvm_sigset_deactivate(vcpu);
out:
- if (unlikely(vcpu_get_flag(vcpu, INCREMENT_PC)))
- adjust_pc(vcpu);
+ if (unlikely(vcpu_get_flag(vcpu, PENDING_EXCEPTION) ||
+ vcpu_get_flag(vcpu, INCREMENT_PC)))
+ kvm_adjust_pc(vcpu);
save_vx_regs(vcpu->arch.ctxt.vregs);
kernel_fpu_end(&fpu_save, KERNEL_FPC | KERNEL_VXR);
diff --git a/arch/s390/kvm/arm64/exception.c b/arch/s390/kvm/arm64/exception.c
new file mode 100644
index 000000000000..871e4e2c710a
--- /dev/null
+++ b/arch/s390/kvm/arm64/exception.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include <asm/sysreg-defs.h>
+
+#include <asm/pstate.h>
+
+/*
+ * This performs the exception entry at a given EL (@target_mode), stashing PC
+ * and PSTATE into ELR and SPSR respectively, and compute the new PC/PSTATE.
+ * The EL passed to this function *must* be a non-secure, privileged mode with
+ * bit 0 being set (PSTATE.SP == 1).
+ *
+ * When an exception is taken, most PSTATE fields are left unchanged in the
+ * handler. However, some are explicitly overridden (e.g. M[4:0]). Luckily all
+ * of the inherited bits have the same position in the AArch64/AArch32 SPSR_ELx
+ * layouts, so we don't need to shuffle these for exceptions from AArch32 EL0.
+ *
+ * For the SPSR_ELx layout for AArch64, see ARM DDI 0487E.a page C5-429.
+ * For the SPSR_ELx layout for AArch32, see ARM DDI 0487E.a page C5-426.
+ *
+ * Here we manipulate the fields in order of the AArch64 SPSR_ELx layout, from
+ * MSB to LSB.
+ */
+static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode,
+ enum exception_type type)
+{
+ unsigned long sctlr, vbar, old_pstate, new, mode;
+ u64 exc_offset;
+
+ old_pstate = *vcpu_cpsr(vcpu);
+ mode = old_pstate & (PSR_MODE_MASK | PSR_MODE32_BIT);
+
+ if (mode == target_mode)
+ exc_offset = CURRENT_EL_SP_ELx_VECTOR;
+ else if ((mode | PSR_MODE_THREAD_BIT) == target_mode)
+ exc_offset = CURRENT_EL_SP_EL0_VECTOR;
+ else if (!(mode & PSR_MODE32_BIT))
+ exc_offset = LOWER_EL_AArch64_VECTOR;
+ else
+ exc_offset = LOWER_EL_AArch32_VECTOR;
+
+ switch (target_mode) {
+ case PSR_MODE_EL1h:
+ vbar = vcpu_read_sys_reg(vcpu, VBAR_EL1);
+ sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
+ vcpu_write_sys_reg(vcpu, *vcpu_pc(vcpu), ELR_EL1);
+ vcpu_write_sys_reg(vcpu, old_pstate, SPSR_EL1);
+ break;
+ default:
+ panic("Unknown PSR Mode: 0x%lx.", target_mode);
+ }
+
+ *vcpu_pc(vcpu) = vbar + exc_offset + type;
+
+ new = 0;
+
+ new |= (old_pstate & PSR_N_BIT);
+ new |= (old_pstate & PSR_Z_BIT);
+ new |= (old_pstate & PSR_C_BIT);
+ new |= (old_pstate & PSR_V_BIT);
+ new |= (old_pstate & PSR_DIT_BIT);
+ new |= (old_pstate & PSR_PAN_BIT);
+
+ if (!(sctlr & SCTLR_EL1_SPAN))
+ new |= PSR_PAN_BIT;
+
+ if (sctlr & SCTLR_ELx_DSSBS)
+ new |= PSR_SSBS_BIT;
+
+ new |= PSR_D_BIT;
+ new |= PSR_A_BIT;
+ new |= PSR_I_BIT;
+ new |= PSR_F_BIT;
+
+ new |= target_mode;
+
+ *vcpu_cpsr(vcpu) = new;
+}
+
+static void kvm_inject_exception(struct kvm_vcpu *vcpu)
+{
+ switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) {
+ case unpack_vcpu_flag(EXCEPT_AA64_EL1_SYNC):
+ enter_exception64(vcpu, PSR_MODE_EL1h, except_type_sync);
+ break;
+ }
+}
+
+/*
+ * Adjust the guest PC (and potentially exception state) depending on
+ * flags provided by the emulation code.
+ */
+void kvm_adjust_pc(struct kvm_vcpu *vcpu)
+{
+ if (vcpu_get_flag(vcpu, PENDING_EXCEPTION)) {
+ kvm_inject_exception(vcpu);
+ vcpu_clear_flag(vcpu, PENDING_EXCEPTION);
+ vcpu_clear_flag(vcpu, EXCEPT_MASK);
+ } else if (vcpu_get_flag(vcpu, INCREMENT_PC)) {
+ kvm_skip_instr(vcpu);
+ vcpu_clear_flag(vcpu, INCREMENT_PC);
+ }
+}
diff --git a/arch/s390/kvm/arm64/inject_fault.c b/arch/s390/kvm/arm64/inject_fault.c
index 650c041efde2..0216ffbd62ab 100644
--- a/arch/s390/kvm/arm64/inject_fault.c
+++ b/arch/s390/kvm/arm64/inject_fault.c
@@ -2,6 +2,42 @@
#include <asm/kvm_emulate.h>
+#define exception_esr_elx(__vcpu) ESR_EL1
+#define exception_far_elx(__vcpu) FAR_EL1
+
+static void pend_sync_exception(struct kvm_vcpu *vcpu)
+{
+ kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SYNC);
+}
+
+static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
+{
+ unsigned long cpsr = *vcpu_cpsr(vcpu);
+ bool is_aarch32 = vcpu_mode_is_32bit(vcpu);
+ u64 esr = 0;
+
+ if (kvm_vcpu_abt_iss1tw(vcpu))
+ esr |= ESR_ELx_FSC_SEA_TTW(kvm_vcpu_abt_gltl(vcpu));
+ else
+ esr |= ESR_ELx_FSC_EXTABT;
+
+ pend_sync_exception(vcpu);
+
+ if (kvm_vcpu_trap_il_is32bit(vcpu))
+ esr |= ESR_ELx_IL;
+
+ if (is_aarch32 || (cpsr & PSR_MODE_MASK) == PSR_MODE_EL0t)
+ esr |= (ESR_ELx_EC_IABT_LOW << ESR_ELx_EC_SHIFT);
+ else
+ esr |= (ESR_ELx_EC_IABT_CUR << ESR_ELx_EC_SHIFT);
+
+ if (!is_iabt)
+ esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT;
+
+ vcpu_write_sys_reg(vcpu, addr, ESR_EL1);
+ vcpu_write_sys_reg(vcpu, esr, FAR_EL1);
+}
+
/**
* kvm_inject_undefined - inject an undefined instruction into the guest
* @vcpu: The vCPU in which to inject the exception
@@ -11,11 +47,43 @@
*/
void kvm_inject_undefined(struct kvm_vcpu *vcpu)
{
- /* Stub until s390 supports arm64 sysregs TODO sysregs*/
+ u64 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT);
+
+ pend_sync_exception(vcpu);
+
+ /*
+ * Build an unknown exception, depending on the instruction
+ * set.
+ */
+ if (kvm_vcpu_trap_il_is32bit(vcpu))
+ esr |= ESR_ELx_IL;
+
+ vcpu_write_sys_reg(vcpu, esr, exception_esr_elx(vcpu));
+}
+
+static void __kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr)
+{
+ inject_abt64(vcpu, iabt, addr);
}
int kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr)
{
- /* Stub until s390 supports arm64 sysregs TODO sysregs*/
+ lockdep_assert_held(&vcpu->mutex);
+
+ __kvm_inject_sea(vcpu, iabt, addr);
return 1;
}
+
+void kvm_inject_size_fault(struct kvm_vcpu *vcpu)
+{
+ unsigned long addr, esr;
+
+ addr = kvm_vcpu_get_fault_ipa(vcpu);
+ addr |= FAR_TO_FIPA_OFFSET(kvm_vcpu_get_hfar(vcpu));
+
+ __kvm_inject_sea(vcpu, kvm_vcpu_trap_is_iabt(vcpu), addr);
+
+ esr = vcpu_read_sys_reg(vcpu, exception_esr_elx(vcpu));
+ esr &= ~GENMASK_ULL(5, 0);
+ vcpu_write_sys_reg(vcpu, esr, exception_esr_elx(vcpu));
+}
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v1 26/26] KVM: s390: arm64: Finalize page fault handling
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (23 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 25/26] KVM: s390: arm64: Implement exception injection Steffen Eiden
@ 2026-05-29 15:55 ` Steffen Eiden
2026-06-01 15:52 ` [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Claudio Imbrenda
25 siblings, 0 replies; 31+ messages in thread
From: Steffen Eiden @ 2026-05-29 15:55 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Oliver Upton, Paolo Bonzini,
Suzuki K Poulose, Sven Schnelle, Ulrich Weigand, Vasily Gorbik,
Will Deacon, Zenghui Yu
Complete the page fault handling implementation by replacing temporary
error returns with proper ARM64 exception injection.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/kvm/arm64/mmu.c | 62 ++++++++++++++++++++++-----------
include/kvm/arm64/kvm_feature.h | 3 ++
2 files changed, 44 insertions(+), 21 deletions(-)
diff --git a/arch/s390/kvm/arm64/mmu.c b/arch/s390/kvm/arm64/mmu.c
index 8759cbafbaff..4224503276fb 100644
--- a/arch/s390/kvm/arm64/mmu.c
+++ b/arch/s390/kvm/arm64/mmu.c
@@ -31,12 +31,14 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, gpa_t fault_ipa,
ret = kvm_s390_faultin_gfn(vcpu, NULL, &f);
if (ret <= 0)
return ret;
- if (ret == PGM_ADDRESSING)
+ if (ret == PGM_ADDRESSING) {
/*
- * Without the relevant sysregs we cannot do anything for now.
- * Go back to userspace with an error. TODO sysreg handling
+ * There is no page with the requested address. Inject size fault
+ * which is the closest arm match to PGM-addressing
*/
- return -ENOEXEC;
+ kvm_inject_size_fault(vcpu);
+ return 1;
+ }
KVM_BUG_ON(ret, vcpu->kvm);
return -EINVAL;
}
@@ -69,6 +71,27 @@ static int kvm_handle_pic(struct kvm_vcpu *vcpu, bool *translation)
return 0;
}
+static u32 kvm_get_pa_bits(struct kvm *kvm)
+{
+ u32 id_parange = get_idreg_field_enum(kvm, ID_AA64MMFR0_EL1, PARANGE);
+
+ switch (id_parange) {
+ case ID_AA64MMFR0_EL1_PARANGE_32: return 32;
+ case ID_AA64MMFR0_EL1_PARANGE_36: return 36;
+ case ID_AA64MMFR0_EL1_PARANGE_40: return 40;
+ case ID_AA64MMFR0_EL1_PARANGE_42: return 42;
+ case ID_AA64MMFR0_EL1_PARANGE_44: return 44;
+ case ID_AA64MMFR0_EL1_PARANGE_48: return 48;
+ case ID_AA64MMFR0_EL1_PARANGE_52: return 52;
+ case ID_AA64MMFR0_EL1_PARANGE_56: return 56;
+ }
+ /*
+ * Future values must be higher than we know already.
+ * See ARM DDI 0487C.a. Return a safe limit.
+ */
+ return ID_AA64MMFR0_EL1_PARANGE_48;
+}
+
int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
{
struct kvm_memory_slot *memslot;
@@ -98,16 +121,17 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
}
if (translation) {
- /*
- * For both cases:
- * Without the relevant sysregs we cannot do anything for now.
- * Go back to userspace with an error. TODO sysreg handling
- */
- if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit()))
- return -ENOEXEC;
+ /* Beyond sanitised PA range (which is the IPA limit) */
+ if (fault_ipa >= BIT_ULL(kvm_get_pa_bits(vcpu->kvm))) {
+ kvm_inject_size_fault(vcpu);
+ return 1;
+ }
- if (fault_ipa >= kvm_phys_size(vcpu->kvm))
- return -ENOEXEC;
+ /* Falls between the IPA range and the PA range? */
+ if (fault_ipa >= kvm_phys_size(vcpu->kvm)) {
+ fault_ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
+ return kvm_inject_sea(vcpu, is_iabt, fault_ipa);
+ }
}
idx = srcu_read_lock(&vcpu->kvm->srcu);
@@ -123,18 +147,14 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
* The guest has put either its instructions or its page-tables
* somewhere it shouldn't have. Userspace won't be able to do
* anything about this (there's no syndrome for a start).
- *
- * Without the relevant sysregs we cannot do anything for now.
- * Go back to userspace with an error. TODO sysreg handling
*/
- if (is_iabt)
+ if (is_iabt) {
+ ret = kvm_inject_sea_iabt(vcpu, kvm_vcpu_get_hfar(vcpu));
goto out_unlock;
+ }
if (kvm_vcpu_abt_iss1tw(vcpu)) {
- /*
- * Without the relevant sysregs we cannot do anything for now.
- * Go back to userspace with an error. TODO sysreg handling
- */
+ ret = kvm_inject_sea_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
goto out_unlock;
}
diff --git a/include/kvm/arm64/kvm_feature.h b/include/kvm/arm64/kvm_feature.h
index 945abbbf1aa8..193c9ca7045f 100644
--- a/include/kvm/arm64/kvm_feature.h
+++ b/include/kvm/arm64/kvm_feature.h
@@ -47,6 +47,9 @@
#define kvm_has_feat_enum(kvm, ...) __kvm_has_feat_enum(kvm, __VA_ARGS__)
+#define get_idreg_field_enum(kvm, id, fld) \
+ SYS_FIELD_GET(id, fld, kvm_read_vm_id_reg((kvm), SYS_##id))
+
/* Check for a given level of PAuth support */
#define kvm_has_pauth(k, l) \
({ \
--
2.53.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
` (24 preceding siblings ...)
2026-05-29 15:55 ` [PATCH v1 26/26] KVM: s390: arm64: Finalize page fault handling Steffen Eiden
@ 2026-06-01 15:52 ` Claudio Imbrenda
25 siblings, 0 replies; 31+ messages in thread
From: Claudio Imbrenda @ 2026-06-01 15:52 UTC (permalink / raw)
To: Steffen Eiden
Cc: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390,
Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, David Hildenbrand,
Friedrich Welter, Gautam Gala, Hariharan Mari, Heiko Carstens,
Hendrik Brueckner, Ilya Leoshkevich, Janosch Frank, Joey Gouly,
Marc Zyngier, Nico Boehr, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Sven Schnelle, Ulrich Weigand,
Vasily Gorbik, Will Deacon, Zenghui Yu
On Fri, 29 May 2026 17:55:33 +0200
Steffen Eiden <seiden@linux.ibm.com> wrote:
> Add system register handling for KVM/arm64 on s390. Restructure and share
> KVM/arm64 code, introduce ARM guest management functions for s390 hosts,
> and implement host sysreg & exception handling.
>
> Changes in detail:
>
> arm64:
>
> Refactor arm64 feature detection and ID register handling to make it
> generic and reusable across architectures.
>
> Restructure ID register storage and core register handling. Refactor core
> registers to use functions instead of direct memory access.
>
> Move arm64-specific definitions (CPU types, cache, KVM features, ID
> registers, system registers) to shared locations for reuse by other
> architectures.
>
> s390:
>
> Add s390 instruction support for ARM guest management: easr/sasr for
> system register access, QAAF for feature queries, and ptff extensions
> for guest time handling.
>
> Implement complete sysreg handling for s390 including feature
> sanitisation, register enumeration and access, exception injection,
> and finalized page fault handling.
>
> The series builds upon the foundation established in the first series and
> requires the first series v3[1] as base.
the series is now conveniently available on the sae branch on
https://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git
>
> Steffen
>
> [1] https://lore.kernel.org/lkml/20260529155050.2902245-1-seiden@linux.ibm.com/
>
> Andreas Grapentin (1):
> KVM: arm64: Fix set_oslsr_el1 to write to OSLAR_EL1
>
> Steffen Eiden (25):
> KVM: arm64: Extract some feature related changes to kvm_feature.h
> KVM: arm64: Remove __expand_field_sign_(un)signed
> KVM: arm64: Generalize get_idreg_field_*()
> KVM: arm64: Generalize kvm_cmp_feat_*()
> KVM: arm64: Generalize kvm_has_feat_*
> KVM: arm64: Remove get_idreg_field_*() and kvm_cmp_feat_*()
> KVM: arm64: Remove kvm_has_feat_range
> KVM: arm64: Split up feature sysreg sanitisation
> KVM: arm64: Refactor idreg caching into dedicated structure
> KVM: arm64: Move definitions from sys_regs.c to sys_regs.h
> KVM: arm64: Add PVM_ prefix to avoid name collisions
> s390: Introduce read/write ARM sysreg instructions
> s390: Introduce Query Available Arm features
> s390: Add functions to query arm guest time
> KVM: s390: arm64: Add sysreg related functions and definitions
> arm64: Extract cputype definitions.
> arm64: Extract cache definitions
> KVM: arm64: Share KVM feature detection macros
> KVM: arm64: Share ID reg handling
> KVM: arm64: Share sys-reg handling
> KVM: arm64: Refactor core reg handling
> KVM: s390: arm64: Implement feature sanitisation
> KVM: s390: arm64: Implement sysreg handling
> KVM: s390: arm64: Implement exception injection
> KVM: s390: arm64: Finalize page fault handling
>
> arch/arm64/include/asm/cache.h | 19 +-
> arch/arm64/include/asm/cputype.h | 246 +---
> arch/arm64/include/asm/kvm_emulate.h | 1 +
> arch/arm64/include/asm/kvm_feature.h | 27 +
> arch/arm64/include/asm/kvm_host.h | 137 +-
> arch/arm64/include/asm/kvm_nested.h | 1 +
> arch/arm64/kvm/arm.c | 2 +-
> arch/arm64/kvm/at.c | 1 +
> arch/arm64/kvm/config.c | 3 +-
> arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 1 +
> arch/arm64/kvm/hyp/nvhe/hyp-main.c | 1 +
> arch/arm64/kvm/hyp/nvhe/pkvm.c | 7 +-
> arch/arm64/kvm/hyp/nvhe/sys_regs.c | 55 +-
> arch/arm64/kvm/nested.c | 2 +-
> arch/arm64/kvm/sys_regs.c | 1307 +----------------
> arch/arm64/kvm/sys_regs.h | 276 ----
> arch/arm64/kvm/trace_handle_exit.h | 36 +-
> arch/arm64/kvm/vgic-sys-reg-v3.c | 2 +-
> arch/arm64/kvm/vgic/vgic-init.c | 1 +
> arch/arm64/kvm/vgic/vgic.h | 1 +
> arch/s390/include/asm/kvm_emulate.h | 34 +
> arch/s390/include/asm/kvm_feature.h | 111 ++
> arch/s390/include/asm/kvm_host_arm64.h | 168 ++-
> arch/s390/include/asm/kvm_host_arm64_types.h | 97 ++
> arch/s390/include/asm/kvm_nested.h | 5 +
> arch/s390/include/asm/sae-asm.h | 48 +
> arch/s390/include/asm/sae.h | 86 ++
> arch/s390/include/asm/timex.h | 49 +
> arch/s390/kernel/dis.c | 1 +
> arch/s390/kernel/time.c | 1 +
> arch/s390/kvm/arm64/Makefile | 3 +
> arch/s390/kvm/arm64/arm.c | 44 +-
> arch/s390/kvm/arm64/exception.c | 105 ++
> arch/s390/kvm/arm64/feature.c | 170 +++
> arch/s390/kvm/arm64/guest.c | 20 +-
> arch/s390/kvm/arm64/handle_exit.c | 1 +
> arch/s390/kvm/arm64/inject_fault.c | 72 +-
> arch/s390/kvm/arm64/mmu.c | 62 +-
> arch/s390/kvm/arm64/reset.c | 5 +
> arch/s390/kvm/arm64/sys_regs.c | 769 ++++++++++
> arch/s390/kvm/arm64/trace.h | 33 +
> arch/s390/tools/opcodes.txt | 3 +
> include/arch/arm64/asm/cache-defs.h | 22 +
> .../arch/arm64/asm/cputype-defs.h | 92 +-
> include/arch/arm64/asm/sysreg-defs.h | 9 +
> include/kvm/arm64/kvm_feature.h | 68 +
> include/kvm/arm64/kvm_host.h | 52 +
> include/kvm/arm64/sys_regs.h | 548 +++++++
> virt/kvm/arm64/Makefile.kvm | 1 +
> virt/kvm/arm64/guest.c | 100 +-
> virt/kvm/arm64/mmio.c | 1 +
> virt/kvm/arm64/sys_regs.c | 1039 +++++++++++++
> virt/kvm/arm64/trace.h | 34 +
> 53 files changed, 3838 insertions(+), 2141 deletions(-)
> create mode 100644 arch/arm64/include/asm/kvm_feature.h
> delete mode 100644 arch/arm64/kvm/sys_regs.h
> create mode 100644 arch/s390/include/asm/kvm_feature.h
> create mode 100644 arch/s390/include/asm/sae-asm.h
> create mode 100644 arch/s390/kvm/arm64/exception.c
> create mode 100644 arch/s390/kvm/arm64/feature.c
> create mode 100644 arch/s390/kvm/arm64/sys_regs.c
> create mode 100644 arch/s390/kvm/arm64/trace.h
> create mode 100644 include/arch/arm64/asm/cache-defs.h
> copy arch/arm64/include/asm/cputype.h => include/arch/arm64/asm/cputype-defs.h (85%)
> create mode 100644 include/kvm/arm64/kvm_feature.h
> create mode 100644 include/kvm/arm64/sys_regs.h
> create mode 100644 virt/kvm/arm64/sys_regs.c
>
>
> base-commit: 4095afb932d1a98a6fcb3f4f490964949d0de338
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v1 10/26] KVM: arm64: Fix set_oslsr_el1 to write to OSLAR_EL1
2026-05-29 15:55 ` [PATCH v1 10/26] KVM: arm64: Fix set_oslsr_el1 to write to OSLAR_EL1 Steffen Eiden
@ 2026-06-01 22:21 ` Oliver Upton
0 siblings, 0 replies; 31+ messages in thread
From: Oliver Upton @ 2026-06-01 22:21 UTC (permalink / raw)
To: Steffen Eiden
Cc: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390,
Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Paolo Bonzini, Suzuki K Poulose,
Sven Schnelle, Ulrich Weigand, Vasily Gorbik, Will Deacon,
Zenghui Yu
Hi,
On Fri, May 29, 2026 at 05:55:43PM +0200, Steffen Eiden wrote:
> From: Andreas Grapentin <gra@linux.ibm.com>
>
> The set_oslsr_el1() function was incorrectly writing directly to the
> OSLSR_EL1 register, which is architecturally a read-only status register
> that reflects the state of the OS Lock.
>
> Fix this by extracting the OSLK bit from the user-provided value and
> writing it to OSLAR_EL1 (OS Lock Access Register) instead, which is the
> proper control register for managing the OS Lock state. OSLSR_EL1 will
> then reflect this state when read.
>
> This ensures the implementation follows the ARM architecture
> specification where OSLAR_EL1 controls the lock and OSLSR_EL1 provides
> status information.
>
> Signed-off-by: Andreas Grapentin <gra@linux.ibm.com>
> Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
The current behavior of KVM is correct. KVM treats OSLSR_EL1 as the
stateful representation of the OS lock and is RO from the guest POV.
We keep the UAPI straightforward by making this register RW from
userspace, such that the VMM can directly write back the value returned
from KVM_GET_ONE_REG.
Do you have another reason for using OSLAR_EL1 as the canonical
representation?
Thanks,
Oliver
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v1 12/26] KVM: arm64: Add PVM_ prefix to avoid name collisions
2026-05-29 15:55 ` [PATCH v1 12/26] KVM: arm64: Add PVM_ prefix to avoid name collisions Steffen Eiden
@ 2026-06-01 22:23 ` Oliver Upton
0 siblings, 0 replies; 31+ messages in thread
From: Oliver Upton @ 2026-06-01 22:23 UTC (permalink / raw)
To: Steffen Eiden
Cc: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390,
Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Paolo Bonzini, Suzuki K Poulose,
Sven Schnelle, Ulrich Weigand, Vasily Gorbik, Will Deacon,
Zenghui Yu
On Fri, May 29, 2026 at 05:55:45PM +0200, Steffen Eiden wrote:
> Rename ID_UNALLOCATED to PVM_ID_UNALLOCATED and read_id_reg to
> pvm_read_id_reg to prevent future name collisions with other subsystems.
> While at it, fix whitespace issues in the macro invocations
>
> Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
No issues with the rename but do you even need the nVHE object at all
for s390?
Thanks,
Oliver
> ---
> arch/arm64/kvm/hyp/nvhe/sys_regs.c | 48 +++++++++++++++---------------
> 1 file changed, 24 insertions(+), 24 deletions(-)
>
> diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> index e8d773d38905..08b14053568b 100644
> --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> @@ -282,8 +282,8 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
> inject_sync64(vcpu, (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT));
> }
>
> -static u64 read_id_reg(const struct kvm_vcpu *vcpu,
> - struct sys_reg_desc const *r)
> +static u64 pvm_read_id_reg(const struct kvm_vcpu *vcpu,
> + struct sys_reg_desc const *r)
> {
> struct kvm *kvm = vcpu->kvm;
> u32 reg = reg_to_encoding(r);
> @@ -341,7 +341,7 @@ static bool pvm_access_id_aarch64(struct kvm_vcpu *vcpu,
> return false;
> }
>
> - p->regval = read_id_reg(vcpu, r);
> + p->regval = pvm_read_id_reg(vcpu, r);
> return true;
> }
>
> @@ -379,7 +379,7 @@ static bool pvm_idst_access(struct kvm_vcpu *vcpu,
> * register with encoding Op0=3, Op1=0, CRn=0, CRm=crm, Op2=op2
> * (1 <= crm < 8, 0 <= Op2 < 8).
> */
> -#define ID_UNALLOCATED(crm, op2) { \
> +#define PVM_ID_UNALLOCATED(crm, op2) { \
> Op0(3), Op1(0), CRn(0), CRm(crm), Op2(op2), \
> .access = pvm_access_id_aarch64, \
> }
> @@ -438,46 +438,46 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {
> AARCH32(SYS_MVFR0_EL1),
> AARCH32(SYS_MVFR1_EL1),
> AARCH32(SYS_MVFR2_EL1),
> - ID_UNALLOCATED(3,3),
> + PVM_ID_UNALLOCATED(3, 3),
> AARCH32(SYS_ID_PFR2_EL1),
> AARCH32(SYS_ID_DFR1_EL1),
> AARCH32(SYS_ID_MMFR5_EL1),
> - ID_UNALLOCATED(3,7),
> + PVM_ID_UNALLOCATED(3, 7),
>
> /* AArch64 ID registers */
> /* CRm=4 */
> AARCH64(SYS_ID_AA64PFR0_EL1),
> AARCH64(SYS_ID_AA64PFR1_EL1),
> AARCH64(SYS_ID_AA64PFR2_EL1),
> - ID_UNALLOCATED(4,3),
> + PVM_ID_UNALLOCATED(4, 3),
> AARCH64(SYS_ID_AA64ZFR0_EL1),
> - ID_UNALLOCATED(4,5),
> - ID_UNALLOCATED(4,6),
> - ID_UNALLOCATED(4,7),
> + PVM_ID_UNALLOCATED(4, 5),
> + PVM_ID_UNALLOCATED(4, 6),
> + PVM_ID_UNALLOCATED(4, 7),
> AARCH64(SYS_ID_AA64DFR0_EL1),
> AARCH64(SYS_ID_AA64DFR1_EL1),
> - ID_UNALLOCATED(5,2),
> - ID_UNALLOCATED(5,3),
> + PVM_ID_UNALLOCATED(5, 2),
> + PVM_ID_UNALLOCATED(5, 3),
> AARCH64(SYS_ID_AA64AFR0_EL1),
> AARCH64(SYS_ID_AA64AFR1_EL1),
> - ID_UNALLOCATED(5,6),
> - ID_UNALLOCATED(5,7),
> + PVM_ID_UNALLOCATED(5, 6),
> + PVM_ID_UNALLOCATED(5, 7),
> AARCH64(SYS_ID_AA64ISAR0_EL1),
> AARCH64(SYS_ID_AA64ISAR1_EL1),
> AARCH64(SYS_ID_AA64ISAR2_EL1),
> - ID_UNALLOCATED(6,3),
> - ID_UNALLOCATED(6,4),
> - ID_UNALLOCATED(6,5),
> - ID_UNALLOCATED(6,6),
> - ID_UNALLOCATED(6,7),
> + PVM_ID_UNALLOCATED(6, 3),
> + PVM_ID_UNALLOCATED(6, 4),
> + PVM_ID_UNALLOCATED(6, 5),
> + PVM_ID_UNALLOCATED(6, 6),
> + PVM_ID_UNALLOCATED(6, 7),
> AARCH64(SYS_ID_AA64MMFR0_EL1),
> AARCH64(SYS_ID_AA64MMFR1_EL1),
> AARCH64(SYS_ID_AA64MMFR2_EL1),
> - ID_UNALLOCATED(7,3),
> - ID_UNALLOCATED(7,4),
> - ID_UNALLOCATED(7,5),
> - ID_UNALLOCATED(7,6),
> - ID_UNALLOCATED(7,7),
> + PVM_ID_UNALLOCATED(7, 3),
> + PVM_ID_UNALLOCATED(7, 4),
> + PVM_ID_UNALLOCATED(7, 5),
> + PVM_ID_UNALLOCATED(7, 6),
> + PVM_ID_UNALLOCATED(7, 7),
>
> /* Scalable Vector Registers are restricted. */
>
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v1 15/26] s390: Add functions to query arm guest time
2026-05-29 15:55 ` [PATCH v1 15/26] s390: Add functions to query arm guest time Steffen Eiden
@ 2026-06-01 22:25 ` Oliver Upton
0 siblings, 0 replies; 31+ messages in thread
From: Oliver Upton @ 2026-06-01 22:25 UTC (permalink / raw)
To: Steffen Eiden
Cc: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390,
Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Paolo Bonzini, Suzuki K Poulose,
Sven Schnelle, Ulrich Weigand, Vasily Gorbik, Will Deacon,
Zenghui Yu
On Fri, May 29, 2026 at 05:55:48PM +0200, Steffen Eiden wrote:
> Add functions to convert between ARM guest time (LSB0) and s390 host
> time (MSB0) using new ptff function codes.
>
> Co-developed-by: Nico Boehr <nrb@linux.ibm.com>
> Signed-off-by: Nico Boehr <nrb@linux.ibm.com>
> Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
> ---
> arch/s390/include/asm/timex.h | 49 +++++++++++++++++++++++++++++++++++
> arch/s390/kernel/time.c | 1 +
> arch/s390/kvm/arm64/arm.c | 9 ++++++-
> 3 files changed, 58 insertions(+), 1 deletion(-)
>
> diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h
> index 49447b40f038..9ec22a28bbda 100644
> --- a/arch/s390/include/asm/timex.h
> +++ b/arch/s390/include/asm/timex.h
> @@ -99,6 +99,8 @@ extern unsigned char ptff_function_mask[16];
> #define PTFF_QSI 0x02 /* query steering information */
> #define PTFF_QPT 0x03 /* query physical clock */
> #define PTFF_QUI 0x04 /* query UTC information */
> +#define PTFF_QAGTO 0x10 /* query arm guest time offset */
> +#define PTFF_QAGPT 0x11 /* query arm guest physical time offset */
Are these analogous to CNTVOFF_EL2 and CNTPOFF_EL2?
Thanks,
Oliver
> #define PTFF_ATO 0x40 /* adjust tod offset */
> #define PTFF_STO 0x41 /* set tod offset */
> #define PTFF_SFS 0x42 /* set fine steering rate */
> @@ -136,6 +138,17 @@ struct ptff_qui {
> unsigned int pad_0x5c[41];
> } __packed;
>
> +/*
> + * Query Arm Guest Time
> + * used for:
> + * - Query Arm Guest Time Offset
> + * - Query Arm Guest Physical Time
> + */
> +struct ptff_qagt {
> + u64 in;
> + u64 out;
> +};
> +
> /*
> * ptff - Perform timing facility function
> * @ptff_block: Pointer to ptff parameter block
> @@ -286,4 +299,40 @@ static inline int tod_after_eq(unsigned long a, unsigned long b)
> return a >= b;
> }
>
> +/*
> + * ptff_qagto() - Query Arm Guest Time Offset
> + *
> + * @physical_time: Arm guest physical time in MSb 0
> + *
> + * Converts Arm guest physical time in MSb 0 bit ordering
> + * into the Arm guest offset in LSb 0 bit ordering.
> + *
> + * Return: Arm guest time offset in LSb 0
> + */
> +static inline u64 ptff_qagto(u64 physical_time)
> +{
> + struct ptff_qagt qagto = { .in = physical_time };
> +
> + ptff(&qagto, sizeof(qagto), PTFF_QAGTO);
> + return qagto.out;
> +}
> +
> +/*
> + * ptff_qagpt() - Query Arm Guest Physical Time
> + *
> + * @guest_time_offset: Arm guest time offset in MSb 0
> + *
> + * Converts Arm guest offset in MSb 0 bit ordering
> + * into the Arm guest physical time in LSb 0 bit ordering.
> + *
> + * Return: Arm guest physical time in LSb 0
> + * */
> +static inline u64 ptff_qagpt(u64 guest_time_offset)
> +{
> + struct ptff_qagt qagpt = { .in = guest_time_offset };
> +
> + ptff(&qagpt, sizeof(qagpt), PTFF_QAGPT);
> + return qagpt.out;
> +}
> +
> #endif
> diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
> index bd0df61d1907..2b989bebd220 100644
> --- a/arch/s390/kernel/time.c
> +++ b/arch/s390/kernel/time.c
> @@ -65,6 +65,7 @@ ATOMIC_NOTIFIER_HEAD(s390_epoch_delta_notifier);
> EXPORT_SYMBOL(s390_epoch_delta_notifier);
>
> unsigned char ptff_function_mask[16];
> +EXPORT_SYMBOL(ptff_function_mask);
>
> static unsigned long lpar_offset;
> static unsigned long initial_leap_seconds;
> diff --git a/arch/s390/kvm/arm64/arm.c b/arch/s390/kvm/arm64/arm.c
> index bf0866659421..636bbeda98a8 100644
> --- a/arch/s390/kvm/arm64/arm.c
> +++ b/arch/s390/kvm/arm64/arm.c
> @@ -692,8 +692,15 @@ long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,
>
> static int __init kvm_s390_arm64_init(void)
> {
> - if (!sclp.has_aef)
> + if (!sclp.has_aef) {
> + pr_info("SAE is not available\n");
> return -ENXIO;
> + }
> +
> + if (!(ptff_query(PTFF_QAGTO) && ptff_query(PTFF_QAGPT))) {
> + pr_info("PTFF for arm on s390 is not available\n");
> + return -ENXIO;
> + }
>
> return kvm_init_with_dev(sizeof(struct kvm_vcpu), 0, THIS_MODULE,
> KVM_DEV_NAME, MISC_DYNAMIC_MINOR);
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v1 09/26] KVM: arm64: Refactor idreg caching into dedicated structure
2026-05-29 15:55 ` [PATCH v1 09/26] KVM: arm64: Refactor idreg caching into dedicated structure Steffen Eiden
@ 2026-06-01 22:28 ` Oliver Upton
0 siblings, 0 replies; 31+ messages in thread
From: Oliver Upton @ 2026-06-01 22:28 UTC (permalink / raw)
To: Steffen Eiden
Cc: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390,
Alexander Gordeev, Andreas Grapentin, Arnd Bergmann,
Catalin Marinas, Christian Borntraeger, Claudio Imbrenda,
David Hildenbrand, Friedrich Welter, Gautam Gala, Hariharan Mari,
Heiko Carstens, Hendrik Brueckner, Ilya Leoshkevich,
Janosch Frank, Joey Gouly, Marc Zyngier, Nico Boehr,
Nina Schoetterl-Glausch, Paolo Bonzini, Suzuki K Poulose,
Sven Schnelle, Ulrich Weigand, Vasily Gorbik, Will Deacon,
Zenghui Yu
On Fri, May 29, 2026 at 05:55:42PM +0200, Steffen Eiden wrote:
> +struct kvm_vm_id_regs {
> + /*
> + * Emulated CPU ID registers per VM
> + * (Op0, Op1, CRn, CRm, Op2) of the ID registers to be saved in it
> + * is (3, 0, 0, crm, op2), where 1<=crm<8, 0<=op2<8.
> + *
> + * These emulated idregs are VM-wide, but accessed from the context of a vCPU.
> + * Atomic access to multiple idregs are guarded by kvm_arch.config_lock.
> + */
> +#define IDREG_IDX(id) (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))
> +#define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
> + u64 normal[KVM_ARM_ID_REG_NUM];
nit: ftr_reg would be slightly more clear.
Thanks,
Oliver
> + u64 midr_el1;
> + u64 revidr_el1;
> + u64 aidr_el1;
> + u64 ctr_el0;
> +};
> +
> +static inline u64 *__vm_id_reg(struct kvm_vm_id_regs *id_regs, u32 reg)
> {
> switch (reg) {
> case sys_reg(3, 0, 0, 1, 0) ... sys_reg(3, 0, 0, 7, 7):
> - return &ka->id_regs[IDREG_IDX(reg)];
> + return &id_regs->normal[IDREG_IDX(reg)];
> case SYS_CTR_EL0:
> - return &ka->ctr_el0;
> + return &id_regs->ctr_el0;
> case SYS_MIDR_EL1:
> - return &ka->midr_el1;
> + return &id_regs->midr_el1;
> case SYS_REVIDR_EL1:
> - return &ka->revidr_el1;
> + return &id_regs->revidr_el1;
> case SYS_AIDR_EL1:
> - return &ka->aidr_el1;
> + return &id_regs->aidr_el1;
> default:
> WARN_ON_ONCE(1);
> return NULL;
> @@ -1419,7 +1423,7 @@ static inline u64 *__vm_id_reg(struct kvm_arch *ka, u32 reg)
> }
>
> #define kvm_read_vm_id_reg(kvm, reg) \
> - ({ u64 __val = *__vm_id_reg(&(kvm)->arch, reg); __val; })
> + ({ u64 __val = *__vm_id_reg(&(kvm)->arch.id_regs, reg); __val; })
>
> void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);
>
> diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> index 014fe04daabf..58a439c3ab9c 100644
> --- a/arch/arm64/kvm/config.c
> +++ b/arch/arm64/kvm/config.c
> @@ -1398,7 +1398,7 @@ void __init check_feature_map(void)
>
> static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map)
> {
> - u64 regval = kvm->arch.id_regs[map->regidx];
> + u64 regval = kvm->arch.id_regs.normal[map->regidx];
> u64 regfld = (regval >> map->shift) & GENMASK(map->width - 1, 0);
>
> if (map->sign) {
> diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> index eb1c10120f9f..94620f142f42 100644
> --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
> +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> @@ -343,7 +343,7 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
> DECLARE_BITMAP(allowed_features, KVM_VCPU_MAX_FEATURES);
>
> /* CTR_EL0 is always under host control, even for protected VMs. */
> - hyp_vm->kvm.arch.ctr_el0 = host_kvm->arch.ctr_el0;
> + hyp_vm->kvm.arch.id_regs.ctr_el0 = host_kvm->arch.id_regs.ctr_el0;
>
> /* Preserve the vgic model so that GICv3 emulation works */
> hyp_vm->kvm.arch.vgic.vgic_model = host_kvm->arch.vgic.vgic_model;
> @@ -358,7 +358,7 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
> KVM_VCPU_MAX_FEATURES);
>
> if (test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &host_arch_flags))
> - hyp_vm->kvm.arch.midr_el1 = host_kvm->arch.midr_el1;
> + hyp_vm->kvm.arch.id_regs.midr_el1 = host_kvm->arch.id_regs.midr_el1;
>
> return;
> }
> @@ -493,7 +493,8 @@ static int vm_copy_id_regs(struct pkvm_hyp_vcpu *hyp_vcpu)
> if (test_and_set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags))
> return 0;
>
> - memcpy(kvm->arch.id_regs, host_kvm->arch.id_regs, sizeof(kvm->arch.id_regs));
> + memcpy(kvm->arch.id_regs.normal, host_kvm->arch.id_regs.normal,
> + sizeof(kvm->arch.id_regs.normal));
>
> return 0;
> }
> diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> index b5a0de84ce01..e8d773d38905 100644
> --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c
> @@ -292,7 +292,7 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
> return 0;
>
> if (reg >= sys_reg(3, 0, 0, 1, 0) && reg <= sys_reg(3, 0, 0, 7, 7))
> - return kvm->arch.id_regs[IDREG_IDX(reg)];
> + return kvm->arch.id_regs.normal[IDREG_IDX(reg)];
>
> return 0;
> }
> @@ -543,7 +543,7 @@ void kvm_init_pvm_id_regs(struct kvm_vcpu *vcpu)
> * for protected VMs.
> */
> for (r = sys_reg(3, 0, 0, 4, 0); r <= sys_reg(3, 0, 0, 7, 7); r += sys_reg(0, 0, 0, 0, 1))
> - ka->id_regs[IDREG_IDX(r)] = pvm_calc_id_reg(vcpu, r);
> + ka->id_regs.normal[IDREG_IDX(r)] = pvm_calc_id_reg(vcpu, r);
>
> set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags);
> }
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b9aa892616ab..195ecdac7bd6 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -2477,7 +2477,7 @@ static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
>
> void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val)
> {
> - u64 *p = __vm_id_reg(&kvm->arch, reg);
> + u64 *p = __vm_id_reg(&kvm->arch.id_regs, reg);
>
> lockdep_assert_held(&kvm->arch.config_lock);
>
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2026-06-01 22:28 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-29 15:55 [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 01/26] KVM: arm64: Extract some feature related changes to kvm_feature.h Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 02/26] KVM: arm64: Remove __expand_field_sign_(un)signed Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 03/26] KVM: arm64: Generalize get_idreg_field_*() Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 04/26] KVM: arm64: Generalize kvm_cmp_feat_*() Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 05/26] KVM: arm64: Generalize kvm_has_feat_* Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 06/26] KVM: arm64: Remove get_idreg_field_*() and kvm_cmp_feat_*() Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 07/26] KVM: arm64: Remove kvm_has_feat_range Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 08/26] KVM: arm64: Split up feature sysreg sanitisation Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 09/26] KVM: arm64: Refactor idreg caching into dedicated structure Steffen Eiden
2026-06-01 22:28 ` Oliver Upton
2026-05-29 15:55 ` [PATCH v1 10/26] KVM: arm64: Fix set_oslsr_el1 to write to OSLAR_EL1 Steffen Eiden
2026-06-01 22:21 ` Oliver Upton
2026-05-29 15:55 ` [PATCH v1 11/26] KVM: arm64: Move definitions from sys_regs.c to sys_regs.h Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 12/26] KVM: arm64: Add PVM_ prefix to avoid name collisions Steffen Eiden
2026-06-01 22:23 ` Oliver Upton
2026-05-29 15:55 ` [PATCH v1 13/26] s390: Introduce read/write ARM sysreg instructions Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 14/26] s390: Introduce Query Available Arm features Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 15/26] s390: Add functions to query arm guest time Steffen Eiden
2026-06-01 22:25 ` Oliver Upton
2026-05-29 15:55 ` [PATCH v1 16/26] KVM: s390: arm64: Add sysreg related functions and definitions Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 17/26] arm64: Extract cputype definitions Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 18/26] arm64: Extract cache definitions Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 19/26] KVM: arm64: Share KVM feature detection macros Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 20/26] KVM: arm64: Share ID reg handling Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 22/26] KVM: arm64: Refactor core " Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 23/26] KVM: s390: arm64: Implement feature sanitisation Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 24/26] KVM: s390: arm64: Implement sysreg handling Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 25/26] KVM: s390: arm64: Implement exception injection Steffen Eiden
2026-05-29 15:55 ` [PATCH v1 26/26] KVM: s390: arm64: Finalize page fault handling Steffen Eiden
2026-06-01 15:52 ` [PATCH v1 00/26] KVM: arm64 on s390 System Register Handling Claudio Imbrenda
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox