From: Steffen Eiden <seiden@linux.ibm.com>
To: Marc Zyngier <maz@kernel.org>, Oliver Upton <oupton@kernel.org>,
Fuad Tabba <fuad.tabba@linux.dev>,
Joey Gouly <joey.gouly@arm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Zenghui Yu <yuzenghui@huawei.com>,
Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Andreas Grapentin <gra@linux.ibm.com>,
Christian Borntraeger <borntraeger@linux.ibm.com>,
Janosch Frank <frankja@linux.ibm.com>,
Claudio Imbrenda <imbrenda@linux.ibm.com>,
David Hildenbrand <david@kernel.org>,
Heiko Carstens <hca@linux.ibm.com>,
Vasily Gorbik <gor@linux.ibm.com>,
Alexander Gordeev <agordeev@linux.ibm.com>,
Sven Schnelle <svens@linux.ibm.com>,
Friedrich Welter <fritz@linux.ibm.com>,
Gautam Gala <ggala@linux.ibm.com>,
Hariharan Mari <hari55@linux.ibm.com>,
Hendrik Brueckner <brueckner@linux.ibm.com>,
Nico Boehr <nrb@linux.ibm.com>,
Ulrich Weigand <Ulrich.Weigand@de.ibm.com>,
Arnd Bergmann <arnd@arndb.de>,
Paolo Bonzini <pbonzini@redhat.com>
Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
linux-kernel@vger.kernel.org, kvm@vger.kernel.org,
linux-s390@vger.kernel.org, Steffen Eiden <seiden@linux.ibm.com>
Subject: [PATCH v3 19/23] KVM: s390: arm64: Implement exception injection
Date: Fri, 06 Nov 2026 17:07:52 +0100 [thread overview]
Message-ID: <20261106-sysreg-v3-19-75e95980fb10@linux.ibm.com> (raw)
In-Reply-To: <20261106-sysreg-v3-0-75e95980fb10@linux.ibm.com>
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 | 109 +++++++++++++++++++++++++++++++++
arch/s390/kvm/arm64/inject_fault.c | 65 +++++++++++++++++++-
5 files changed, 179 insertions(+), 13 deletions(-)
diff --git a/arch/s390/include/asm/kvm_host_arm64.h b/arch/s390/include/asm/kvm_host_arm64.h
index 44deae423ace..79549434a1d6 100644
--- a/arch/s390/include/asm/kvm_host_arm64.h
+++ b/arch/s390/include/asm/kvm_host_arm64.h
@@ -425,4 +425,6 @@ static inline bool vgic_host_has_gicv5(void)
return false;
}
+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 24ac6f6f6278..b0f2da6ac482 100644
--- a/arch/s390/kvm/arm64/Makefile
+++ b/arch/s390/kvm/arm64/Makefile
@@ -11,6 +11,7 @@ ccflags-y += -I $(src) -I $(objtree)/$(obj) -I$(srctree)/arch/$(SRCARCH)/kvm/gma
kvm-arm64-local := \
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 4de0f17052cb..91e9f4a75ce7 100644
--- a/arch/s390/kvm/arm64/arm.c
+++ b/arch/s390/kvm/arm64/arm.c
@@ -390,14 +390,6 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
return -EINVAL;
}
-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 noinstr void arm_vcpu_enter_exit(phys_addr_t sae_block)
{
guest_timing_enter_irqoff();
@@ -488,7 +480,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
trace_kvm_entry(*vcpu_pc(vcpu));
- adjust_pc(vcpu);
+ kvm_adjust_pc(vcpu);
vcpu_write_host_sys_reg(vcpu, vcpu->arch.hcr_el2, SYS_HCR_EL2);
vcpu_write_host_sys_reg(vcpu, vcpu->arch.hcrx_el2, SYS_HCRX_EL2);
vcpu_write_host_sys_reg(vcpu, vcpu->arch.mpidr, SYS_VMPIDR_EL2);
@@ -511,8 +503,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..93a2a2a8bcc8
--- /dev/null
+++ b/arch/s390/kvm/arm64/exception.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/kvm_host.h>
+#include <arm64/kvm_emulate.h>
+#include <arm64/sysreg-defs.h>
+
+#include <arm64/ptrace.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;
+ default:
+ WARN_ONCE(1, "Unsupported pending exception type: 0x%lx\n",
+ vcpu_get_flag(vcpu, EXCEPT_MASK));
+ 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 425dbeaa421c..33f40c5188c9 100644
--- a/arch/s390/kvm/arm64/inject_fault.c
+++ b/arch/s390/kvm/arm64/inject_fault.c
@@ -2,6 +2,38 @@
#include <arm64/kvm_emulate.h>
+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);
+
+ 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, FAR_EL1);
+ vcpu_write_sys_reg(vcpu, esr, ESR_EL1);
+}
+
/**
* kvm_inject_undefined - inject an undefined instruction into the guest
* @vcpu: The vCPU in which to inject the exception
@@ -11,11 +43,40 @@
*/
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) | ESR_ELx_IL;
+
+ kvm_inject_sync(vcpu, esr);
+}
+
+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, ESR_EL1);
+ esr &= ~GENMASK_ULL(5, 0);
+ vcpu_write_sys_reg(vcpu, esr, ESR_EL1);
+}
+
+void kvm_inject_sync(struct kvm_vcpu *vcpu, u64 esr)
+{
+ pend_sync_exception(vcpu);
+ vcpu_write_sys_reg(vcpu, esr, ESR_EL1);
+}
--
2.56.0
next prev parent reply other threads:[~2026-11-06 16:08 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-06 16:07 [PATCH v3 00/23] KVM: arm64 on s390 System Register Handling Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 01/23] KVM: arm64: Refactor idreg caching into dedicated structure Steffen Eiden
2026-11-06 16:23 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 02/23] KVM: arm64: Extract number of sys_reg_desc into a constant Steffen Eiden
2026-11-06 16:25 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 03/23] arm64: sysreg: Convert OSLSR to automatic register generation Steffen Eiden
2026-11-06 16:34 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 04/23] arm64: Prepare headers for sysreg sharing with s390 Steffen Eiden
2026-11-06 16:38 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 05/23] arm64: Share system register related headers and functions " Steffen Eiden
2026-11-06 16:58 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 06/23] KVM: s390: arm64: Prepare for sharing arm64 SVE and ftr-reg code Steffen Eiden
2026-11-06 17:05 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 07/23] KVM: arm64: Prepare sys_regs.c for sharing with s390 Steffen Eiden
2026-11-06 17:06 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 08/23] KVM: arm64: Share system register code " Steffen Eiden
2026-11-06 17:18 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 09/23] s390: tools: Share arm64/kvm headers Steffen Eiden
2026-11-06 17:20 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 10/23] s390: Add range check asm macro Steffen Eiden
2026-11-06 17:23 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 11/23] s390: Read/write ARM system registers Steffen Eiden
2026-11-06 17:34 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 12/23] s390: Query arm guest time Steffen Eiden
2026-11-06 17:37 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 13/23] KVM: s390: arm64: Query Available Arm features Steffen Eiden
2026-11-06 17:45 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 14/23] KVM: s390: arm64: Verify machine feature set before loading Steffen Eiden
2026-11-06 17:49 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 15/23] KVM: s390: arm64: Implement feature sanitisation Steffen Eiden
2026-11-06 18:17 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 16/23] KVM: s390: arm64: Implement arm sysreg managing infrastructure Steffen Eiden
2026-11-06 18:45 ` sashiko-bot
2026-11-07 14:08 ` Andreas Grapentin
2026-11-06 16:07 ` [PATCH v3 17/23] KVM: s390: arm64: Integrate sysreg into the host Steffen Eiden
2026-11-06 19:18 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 18/23] KVM: s390: arm64: Use QAAF init save area Steffen Eiden
2026-11-06 19:23 ` sashiko-bot
2026-11-06 16:07 ` Steffen Eiden [this message]
2026-11-06 19:50 ` [PATCH v3 19/23] KVM: s390: arm64: Implement exception injection sashiko-bot
2026-11-06 16:07 ` [PATCH v3 20/23] KVM: s390: arm64: Finalize page fault handling Steffen Eiden
2026-11-06 20:10 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 21/23] KVM: s390: arm64: Implement SVE for arm guests Steffen Eiden
2026-11-06 20:24 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 22/23] KVM: s390: arm64: Promote PTRAUTH capability Steffen Eiden
2026-11-06 20:33 ` sashiko-bot
2026-11-06 16:07 ` [PATCH v3 23/23] s390: Report AEF features to sysfs Steffen Eiden
2026-11-06 20:43 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261106-sysreg-v3-19-75e95980fb10@linux.ibm.com \
--to=seiden@linux.ibm.com \
--cc=Ulrich.Weigand@de.ibm.com \
--cc=agordeev@linux.ibm.com \
--cc=arnd@arndb.de \
--cc=borntraeger@linux.ibm.com \
--cc=brueckner@linux.ibm.com \
--cc=catalin.marinas@arm.com \
--cc=david@kernel.org \
--cc=frankja@linux.ibm.com \
--cc=fritz@linux.ibm.com \
--cc=fuad.tabba@linux.dev \
--cc=ggala@linux.ibm.com \
--cc=gor@linux.ibm.com \
--cc=gra@linux.ibm.com \
--cc=hari55@linux.ibm.com \
--cc=hca@linux.ibm.com \
--cc=imbrenda@linux.ibm.com \
--cc=joey.gouly@arm.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=maz@kernel.org \
--cc=nrb@linux.ibm.com \
--cc=oupton@kernel.org \
--cc=pbonzini@redhat.com \
--cc=suzuki.poulose@arm.com \
--cc=svens@linux.ibm.com \
--cc=will@kernel.org \
--cc=yuzenghui@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.