From: Steffen Eiden <seiden@linux.ibm.com>
To: kvm@vger.kernel.org, kvmarm@lists.linux.dev,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-s390@vger.kernel.org
Cc: Alexander Gordeev <agordeev@linux.ibm.com>,
Andreas Grapentin <gra@linux.ibm.com>,
Arnd Bergmann <arnd@arndb.de>,
Catalin Marinas <catalin.marinas@arm.com>,
Christian Borntraeger <borntraeger@linux.ibm.com>,
Claudio Imbrenda <imbrenda@linux.ibm.com>,
David Hildenbrand <david@kernel.org>,
Friedrich Welter <fritz@linux.ibm.com>,
Fuad Tabba <tabba@google.com>, Gautam Gala <ggala@linux.ibm.com>,
Hariharan Mari <hari55@linux.ibm.com>,
Heiko Carstens <hca@linux.ibm.com>,
Hendrik Brueckner <brueckner@linux.ibm.com>,
Ilya Leoshkevich <iii@linux.ibm.com>,
Janosch Frank <frankja@linux.ibm.com>,
Joey Gouly <joey.gouly@arm.com>, Marc Zyngier <maz@kernel.org>,
Nico Boehr <nrb@linux.ibm.com>,
Nina Schoetterl-Glausch <oss@nina.schoetterlglausch.eu>,
Oliver Upton <oupton@kernel.org>,
Paolo Bonzini <pbonzini@redhat.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Sven Schnelle <svens@linux.ibm.com>,
Ulrich Weigand <Ulrich.Weigand@de.ibm.com>,
Vasily Gorbik <gor@linux.ibm.com>, Will Deacon <will@kernel.org>,
Zenghui Yu <yuzenghui@huawei.com>
Subject: [PATCH v2 16/20] KVM: s390: arm64: Implement exception injection
Date: Mon, 31 Aug 2026 16:55:31 +0200 [thread overview]
Message-ID: <20260831145536.913567-17-seiden@linux.ibm.com> (raw)
In-Reply-To: <20260831145536.913567-1-seiden@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 | 105 +++++++++++++++++++++++++
arch/s390/kvm/arm64/inject_fault.c | 73 ++++++++++++++++-
5 files changed, 183 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 0bf396ef54c2..16a378b68c8a 100644
--- a/arch/s390/include/asm/kvm_host_arm64.h
+++ b/arch/s390/include/asm/kvm_host_arm64.h
@@ -426,4 +426,6 @@ static inline bool has_broken_cntvoff(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 e19040cdc27d..cb3bf6da6d63 100644
--- a/arch/s390/kvm/arm64/Makefile
+++ b/arch/s390/kvm/arm64/Makefile
@@ -9,6 +9,7 @@ ccflags-y += -I $(src) -I $(objtree)/$(obj) -I$(srctree)/arch/s390/kvm/gmap -DKV
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 ab6e7d135435..89984c6a5b64 100644
--- a/arch/s390/kvm/arm64/arm.c
+++ b/arch/s390/kvm/arm64/arm.c
@@ -379,19 +379,11 @@ 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 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_timing_enter_irqoff();
@@ -496,8 +488,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..b2d016740488
--- /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 <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;
+ }
+}
+
+/*
+ * 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..7ecf91f86d90 100644
--- a/arch/s390/kvm/arm64/inject_fault.c
+++ b/arch/s390/kvm/arm64/inject_fault.c
@@ -2,6 +2,39 @@
#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);
+
+ 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, 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 +44,47 @@
*/
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);
+
+ /*
+ * Build an unknown exception, depending on the instruction
+ * set.
+ */
+ if (kvm_vcpu_trap_il_is32bit(vcpu))
+ esr |= 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.53.0
next prev parent reply other threads:[~2026-08-31 15:01 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-31 14:55 [PATCH v2 00/20] KVM: arm64 on s390 System Register Handling Steffen Eiden
2026-08-31 14:55 ` [PATCH v2 01/20] KVM: arm64: Refactor idreg caching into dedicated structure Steffen Eiden
2026-08-31 18:06 ` sashiko-bot
2026-08-31 14:55 ` [PATCH v2 02/20] KVM: arm64: Extract number of sys_reg_desc into a constant Steffen Eiden
2026-08-31 18:08 ` sashiko-bot
2026-08-31 14:55 ` [PATCH v2 03/20] arm64: sysreg: Define OSLSR_EL1_OSLK_MASK Steffen Eiden
2026-08-31 18:18 ` sashiko-bot
2026-08-31 14:55 ` [PATCH v2 04/20] arm64: Share more arm64 headers with s390 Steffen Eiden
2026-08-31 18:31 ` sashiko-bot
2026-08-31 14:55 ` [PATCH v2 05/20] KVM: s390: arm64: Prepare for sharing more arm64 code Steffen Eiden
2026-08-31 18:42 ` sashiko-bot
2026-08-31 14:55 ` [PATCH v2 06/20] KVM: arm64: Prepare sys_regs.c for sharing with s390 Steffen Eiden
2026-08-31 18:45 ` sashiko-bot
2026-08-31 14:55 ` [PATCH v2 07/20] KVM: arm64: Share more arm64 code " Steffen Eiden
2026-08-31 19:01 ` sashiko-bot
2026-08-31 14:55 ` [PATCH v2 08/20] s390: tools: Allow sharing arm64/kvm headers Steffen Eiden
2026-08-31 19:03 ` sashiko-bot
2026-08-31 14:55 ` [PATCH v2 09/20] s390: Introduce read/write ARM sysreg instructions Steffen Eiden
2026-08-31 19:16 ` sashiko-bot
2026-08-31 14:55 ` [PATCH v2 10/20] s390: Add functions to query arm guest time Steffen Eiden
2026-08-31 19:24 ` sashiko-bot
2026-08-31 14:55 ` [PATCH v2 11/20] KVM: s390: arm64: Query Available Arm features Steffen Eiden
2026-08-31 19:46 ` sashiko-bot
2026-08-31 14:55 ` [PATCH v2 12/20] KVM: s390: arm64: Implement feature sanitisation Steffen Eiden
2026-08-31 20:11 ` sashiko-bot
2026-08-31 14:55 ` [PATCH v2 13/20] KVM: s390: arm64: Implement arm sysreg managing infrastructure Steffen Eiden
2026-08-31 20:33 ` sashiko-bot
2026-08-31 14:55 ` [PATCH v2 14/20] KVM: s390: arm64: Integrate sysreg into the host Steffen Eiden
2026-08-31 14:55 ` [PATCH v2 15/20] KVM: s390: arm64: Use QAAF init save area Steffen Eiden
2026-08-31 14:55 ` Steffen Eiden [this message]
2026-08-31 14:55 ` [PATCH v2 17/20] KVM: s390: arm64: Finalize page fault handling Steffen Eiden
2026-08-31 14:55 ` [PATCH v2 18/20] KVM: s390: arm64: Implement SVE for arm guests Steffen Eiden
2026-08-31 14:55 ` [PATCH v2 19/20] KVM: s390: arm64: Promote PTRAUTH capability Steffen Eiden
2026-08-31 14:55 ` [PATCH v2 20/20] s390: Report AEF features to sysfs Steffen Eiden
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=20260831145536.913567-17-seiden@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=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=iii@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=maz@kernel.org \
--cc=nrb@linux.ibm.com \
--cc=oss@nina.schoetterlglausch.eu \
--cc=oupton@kernel.org \
--cc=pbonzini@redhat.com \
--cc=suzuki.poulose@arm.com \
--cc=svens@linux.ibm.com \
--cc=tabba@google.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox