* [PATCH v1 22/27] KVM: s390: Add basic arm64 kvm module
From: Steffen Eiden @ 2026-04-02 4:21 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
Add basic code for the new arm64 on s390 KVM implementation.
Add kernel module boilerplate code and trivial functions.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/kvm/arm64/arm.c | 182 ++++++++++++++++++++++++++++++++++++
arch/s390/kvm/arm64/arm.h | 7 ++
arch/s390/kvm/arm64/guest.c | 95 +++++++++++++++++++
arch/s390/kvm/arm64/guest.h | 10 ++
4 files changed, 294 insertions(+)
create mode 100644 arch/s390/kvm/arm64/arm.c
create mode 100644 arch/s390/kvm/arm64/arm.h
create mode 100644 arch/s390/kvm/arm64/guest.c
create mode 100644 arch/s390/kvm/arm64/guest.h
diff --git a/arch/s390/kvm/arm64/arm.c b/arch/s390/kvm/arm64/arm.c
new file mode 100644
index 000000000000..8f94eb8fe288
--- /dev/null
+++ b/arch/s390/kvm/arm64/arm.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define KMSG_COMPONENT "kvm-s390-arm64"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/miscdevice.h>
+#include <linux/kvm.h>
+#include <linux/kvm_types.h>
+#include <linux/kvm_host.h>
+
+#include "arm.h"
+
+int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
+{
+ int ret;
+
+ switch (ext) {
+ case KVM_CAP_NR_VCPUS:
+ case KVM_CAP_MAX_VCPUS:
+ case KVM_CAP_MAX_VCPU_ID:
+ ret = KVM_MAX_VCPUS;
+ break;
+ case KVM_CAP_ARM_VM_IPA_SIZE:
+ ret = get_kvm_ipa_limit();
+ break;
+ default:
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static u64 kvm_max_guest_address(void)
+{
+ u64 max_addr;
+
+ if (sclp.hamax == U64_MAX)
+ max_addr = TASK_SIZE_MAX;
+ else
+ max_addr = min_t(u64, TASK_SIZE_MAX, sclp.hamax);
+ return ALIGN_DOWN(max_addr + 1, 1 << 30) - 1;
+}
+
+vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
+{
+ return VM_FAULT_SIGBUS;
+}
+
+long kvm_arch_dev_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ return -EINVAL;
+}
+
+u32 get_kvm_ipa_limit(void)
+{
+ return fls64(kvm_max_guest_address() + 1) - 1;
+}
+
+int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
+{
+ return 0;
+}
+
+void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
+{
+}
+
+void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
+{
+}
+
+void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu)
+{
+}
+
+int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ *mp_state = READ_ONCE(vcpu->arch.mp_state);
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
+{
+ return 0;
+}
+
+unsigned long system_supported_vcpu_features(void)
+{
+ return KVM_VCPU_VALID_FEATURES;
+}
+
+int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
+ bool line_status)
+{
+ return 0;
+}
+
+void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
+ struct kvm_memory_slot *slot,
+ gfn_t gfn_offset,
+ unsigned long mask)
+{
+}
+
+bool kvm_arch_irqchip_in_kernel(struct kvm *kvm)
+{
+ return false;
+}
+
+void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
+{
+}
+
+void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen)
+{
+}
+
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
+ struct kvm *kvm, int irq_source_id,
+ int level, bool line_status)
+{
+ return -EINVAL;
+}
+
+int kvm_set_routing_entry(struct kvm *kvm,
+ struct kvm_kernel_irq_routing_entry *e,
+ const struct kvm_irq_routing_entry *ue)
+{
+ return -EINVAL;
+}
+
+void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
+ struct kvm_memory_slot *slot)
+{
+}
+
+void kvm_arch_flush_shadow_all(struct kvm *kvm)
+{
+}
+
+int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+
+#ifdef CONFIG_HAVE_KVM_NO_POLL
+__weak bool kvm_arch_no_poll(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+#endif
+
+long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,
+ unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+static __init int kvm_s390_arm64_init(void)
+{
+ if (!sclp.has_aef)
+ return -ENXIO;
+
+ return kvm_init_with_dev(sizeof(struct kvm_vcpu), 0, THIS_MODULE,
+ KVM_DEV_NAME, MISC_DYNAMIC_MINOR);
+}
+
+static __exit void kvm_s390_arm64_exit(void)
+{
+ kvm_exit();
+}
+
+module_init(kvm_s390_arm64_init);
+module_exit(kvm_s390_arm64_exit);
diff --git a/arch/s390/kvm/arm64/arm.h b/arch/s390/kvm/arm64/arm.h
new file mode 100644
index 000000000000..a3db254462c0
--- /dev/null
+++ b/arch/s390/kvm/arm64/arm.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ARCH_S390_KVM_ARM64_H
+#define ARCH_S390_KVM_ARM64_H
+
+#define KVM_DEV_NAME "kvm-arm64"
+
+#endif /* ARCH_S390_KVM_ARM64_H */
diff --git a/arch/s390/kvm/arm64/guest.c b/arch/s390/kvm/arm64/guest.c
new file mode 100644
index 000000000000..00886755accf
--- /dev/null
+++ b/arch/s390/kvm/arm64/guest.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+
+#include "guest.h"
+
+const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+ KVM_GENERIC_VM_STATS()
+};
+
+const struct kvm_stats_header kvm_vm_stats_header = {
+ .name_size = KVM_STATS_NAME_SIZE,
+ .num_desc = ARRAY_SIZE(kvm_vm_stats_desc),
+ .id_offset = sizeof(struct kvm_stats_header),
+ .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+ .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+ sizeof(kvm_vm_stats_desc),
+};
+
+const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+ KVM_GENERIC_VCPU_STATS(),
+ /* ARM64 stats */
+ STATS_DESC_COUNTER(VCPU, hvc_exit_stat),
+ STATS_DESC_COUNTER(VCPU, wfe_exit_stat),
+ STATS_DESC_COUNTER(VCPU, wfi_exit_stat),
+ STATS_DESC_COUNTER(VCPU, mmio_exit_user),
+ STATS_DESC_COUNTER(VCPU, mmio_exit_kernel),
+ STATS_DESC_COUNTER(VCPU, signal_exits),
+ STATS_DESC_COUNTER(VCPU, exits),
+ /* GMAP stats */
+ STATS_DESC_COUNTER(VCPU, pfault_sync),
+};
+
+const struct kvm_stats_header kvm_vcpu_stats_header = {
+ .name_size = KVM_STATS_NAME_SIZE,
+ .num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc),
+ .id_offset = sizeof(struct kvm_stats_header),
+ .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+ .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+ sizeof(kvm_vcpu_stats_desc),
+};
+
+int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+ return copy_core_reg_indices(vcpu, uindices);
+}
+
+unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
+{
+ return num_core_regs(vcpu);
+}
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
+ struct kvm_translation *tr)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+ struct kvm_guest_debug *dbg)
+{
+ return -EINVAL;
+}
diff --git a/arch/s390/kvm/arm64/guest.h b/arch/s390/kvm/arm64/guest.h
new file mode 100644
index 000000000000..db635d513c2c
--- /dev/null
+++ b/arch/s390/kvm/arm64/guest.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef KVM_ARM_GUEST_H
+#define KVM_ARM_GUEST_H
+
+#include <linux/kvm_host.h>
+#include <kvm/arm64/guest.h>
+
+unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
+
+#endif /* KVM_ARM_GUEST_H */
--
2.51.0
^ permalink raw reply related
* [PATCH v1 26/27] KVM: s390: arm64: Implement basic page fault handler
From: Steffen Eiden @ 2026-04-02 4:21 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
Add host functionality to page in guest memory. If the guest does
something unexpected or illegal exit to userspace which very likely has
to stop guest execution. This behaviour will be changed to guest error
injects once all sysregs are accessible for the host.
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/kvm/arm64/arm.c | 1 +
arch/s390/kvm/arm64/handle_exit.c | 2 +
arch/s390/kvm/arm64/mmu.c | 153 ++++++++++++++++++++++++++++++
3 files changed, 156 insertions(+)
create mode 100644 arch/s390/kvm/arm64/mmu.c
diff --git a/arch/s390/kvm/arm64/arm.c b/arch/s390/kvm/arm64/arm.c
index 71562a0c438c..5bd6914b484d 100644
--- a/arch/s390/kvm/arm64/arm.c
+++ b/arch/s390/kvm/arm64/arm.c
@@ -435,6 +435,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
vcpu->arch.sae_block.vir);
ret = -EINVAL;
break;
+ case SAE_ICPTR_HOST_ACCESS_EXCEPTION:
case SAE_ICPTR_SYNCHRONOUS_EXCEPTION:
ret = handle_trap_exceptions(vcpu);
break;
diff --git a/arch/s390/kvm/arm64/handle_exit.c b/arch/s390/kvm/arm64/handle_exit.c
index 89933a604876..debe8aa12c7c 100644
--- a/arch/s390/kvm/arm64/handle_exit.c
+++ b/arch/s390/kvm/arm64/handle_exit.c
@@ -46,5 +46,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_IABT_LOW] = kvm_handle_guest_abort,
+ [ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort,
[ESR_ELx_EC_HVC64] = handle_hvc,
};
diff --git a/arch/s390/kvm/arm64/mmu.c b/arch/s390/kvm/arm64/mmu.c
new file mode 100644
index 000000000000..6499d82a5d5c
--- /dev/null
+++ b/arch/s390/kvm/arm64/mmu.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_mmu.h>
+
+#include "faultin.h"
+
+static inline bool kvm_s390_cur_gmap_fault_is_write(struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.sae_block.hai.pic == PGM_PROTECTION ||
+ vcpu->arch.sae_block.hai.teid.fsi == TEID_FSI_STORE;
+}
+
+/*
+ * user_mem_abort() - handle a dat fault for the gmap of a vcpu
+ *
+ * Return: 0 on success, < 0 in case of error.
+ * Context: The mm lock must not be held before calling. May sleep.
+ */
+static int user_mem_abort(struct kvm_vcpu *vcpu, gpa_t fault_ipa,
+ struct kvm_memory_slot *slot, hva_t hva)
+{
+ struct guest_fault f = { };
+ int ret;
+
+ if (kvm_s390_cur_gmap_fault_is_write(vcpu))
+ f.write_attempt = FOLL_WRITE;
+ f.gfn = gpa_to_gfn(fault_ipa);
+
+ ret = kvm_s390_faultin_gfn(vcpu, NULL, &f);
+ if (ret <= 0)
+ return ret;
+ if (ret == PGM_ADDRESSING)
+ /*
+ * Without the relevant sysregs we cannot do anything for now.
+ * Go back to userspace with an error. TODO sysreg handling
+ */
+ return -ENOEXEC;
+ KVM_BUG_ON(ret, vcpu->kvm);
+ return -EINVAL;
+}
+
+int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
+{
+ struct kvm_memory_slot *memslot;
+ bool translation = false;
+ phys_addr_t fault_ipa;
+ unsigned long esr;
+ unsigned long hva;
+ bool write_fault;
+ bool writable;
+ bool is_iabt;
+ int ret;
+ gfn_t gfn;
+ int idx;
+
+ esr = kvm_vcpu_get_esr(vcpu);
+ fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
+ is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
+
+ switch (kvm_vcpu_fault_pic(vcpu)) {
+ /* expected cases: */
+ case PGM_ASCE_TYPE:
+ case PGM_REGION_FIRST_TRANS:
+ case PGM_REGION_SECOND_TRANS:
+ case PGM_REGION_THIRD_TRANS:
+ case PGM_SEGMENT_TRANSLATION:
+ case PGM_PAGE_TRANSLATION:
+ translation = true;
+ break;
+ case PGM_PROTECTION:
+ break;
+ /* unexpected cases: */
+ case 0:
+ KVM_BUG(1, vcpu->kvm, "On MMU fault path but no fault occurred");
+ return -EFAULT;
+ default:
+ KVM_BUG(1, vcpu->kvm, "Unexpected program interrupt 0x%x, TEID 0x%016lx",
+ vcpu->arch.sae_block.hai.pic, vcpu->arch.sae_block.hai.teid.val);
+ send_sig(SIGSEGV, current, 0);
+ return -EFAULT;
+ }
+
+ 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;
+
+ if (fault_ipa >= kvm_phys_size(vcpu->kvm))
+ return -ENOEXEC;
+ }
+
+ idx = srcu_read_lock(&vcpu->kvm->srcu);
+
+ gfn = fault_ipa >> PAGE_SHIFT;
+
+ memslot = gfn_to_memslot(vcpu->kvm, gfn);
+ hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable);
+ write_fault = kvm_is_write_fault(vcpu);
+ if (kvm_is_error_hva(hva) || (write_fault && !writable)) {
+ ret = -ENOEXEC;
+ /*
+ * 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)
+ 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
+ */
+ goto out_unlock;
+ }
+
+ /*
+ * Check for a cache maintenance operation. Assume the guest is
+ * cautious and skip instruction
+ */
+ if (kvm_is_error_hva(hva) && kvm_vcpu_dabt_is_cm(vcpu)) {
+ kvm_incr_pc(vcpu);
+ ret = 1;
+ goto out_unlock;
+ }
+
+ /*
+ * The IPA is reported as [MAX:12], so we need to
+ * complement it with the bottom 12 bits from the
+ * faulting VA. This is always 12 bits, irrespective
+ * of the page size.
+ */
+ fault_ipa |= kvm_vcpu_get_hfar(vcpu) & ((1 << 12) - 1);
+ ret = io_mem_abort(vcpu, fault_ipa);
+ goto out_unlock;
+ }
+
+ ret = user_mem_abort(vcpu, fault_ipa, memslot, hva);
+ if (!ret)
+ ret = 1;
+out_unlock:
+ srcu_read_unlock(&vcpu->kvm->srcu, idx);
+ return ret;
+}
--
2.51.0
^ permalink raw reply related
* [PATCH v1 06/27] arm64: Provide arm64 API for non-native architectures
From: Steffen Eiden @ 2026-04-02 4:21 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
Enable the usage of arm64 asm headers independent of the CPU
architecture. Introduce a new directory, include/arch/arm64/asm to store
(host) architecture- agnostic headers for arm64 implementors.
The new path is added to the include patch of native arm64. Therefore,
arm64 will continue to reference to those headers via include
<asm/header.h> without any code change. This means that the header names
should be unique for arm64 asm headers. For native arm64, headers at the
new path take precedence over any other include path.
For other architectures to use the esr string names, move *esr_class_str
from traps.c to esr.h.
For a seamless integration non-native architectures must also include the
new path to the include path.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
MAINTAINERS | 1 +
arch/arm64/Makefile | 2 +
arch/arm64/kernel/traps.c | 53 ------------------
.../arch/arm64}/asm/brk-imm.h | 0
.../include => include/arch/arm64}/asm/esr.h | 56 ++++++++++++++++++-
.../arch/arm64}/asm/sysreg-defs.h | 0
6 files changed, 56 insertions(+), 56 deletions(-)
rename {arch/arm64/include => include/arch/arm64}/asm/brk-imm.h (100%)
rename {arch/arm64/include => include/arch/arm64}/asm/esr.h (88%)
rename {arch/arm64/include => include/arch/arm64}/asm/sysreg-defs.h (100%)
diff --git a/MAINTAINERS b/MAINTAINERS
index 3f03ef9ee2bd..e0a101fe05ce 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3817,6 +3817,7 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git
F: Documentation/arch/arm64/
F: arch/arm64/
+F: include/arch/arm64/
F: include/uapi/arch/arm64/
F: drivers/virt/coco/arm-cca-guest/
F: drivers/virt/coco/pkvm-guest/
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 73a10f65ce8b..b244e837cedd 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -221,6 +221,8 @@ PHONY += virtconfig
virtconfig:
$(call merge_into_defconfig_override,defconfig,virt)
+LINUXINCLUDE := -I$(srctree)/include/arch/arm64/ $(LINUXINCLUDE)
+
define archhelp
echo '* Image.gz - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)'
echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 914282016069..ca679dcdf1c8 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -829,59 +829,6 @@ void do_el0_sys(unsigned long esr, struct pt_regs *regs)
do_el0_undef(regs, esr);
}
-static const char *esr_class_str[] = {
- [0 ... ESR_ELx_EC_MAX] = "UNRECOGNIZED EC",
- [ESR_ELx_EC_UNKNOWN] = "Unknown/Uncategorized",
- [ESR_ELx_EC_WFx] = "WFI/WFE",
- [ESR_ELx_EC_CP15_32] = "CP15 MCR/MRC",
- [ESR_ELx_EC_CP15_64] = "CP15 MCRR/MRRC",
- [ESR_ELx_EC_CP14_MR] = "CP14 MCR/MRC",
- [ESR_ELx_EC_CP14_LS] = "CP14 LDC/STC",
- [ESR_ELx_EC_FP_ASIMD] = "ASIMD",
- [ESR_ELx_EC_CP10_ID] = "CP10 MRC/VMRS",
- [ESR_ELx_EC_PAC] = "PAC",
- [ESR_ELx_EC_CP14_64] = "CP14 MCRR/MRRC",
- [ESR_ELx_EC_BTI] = "BTI",
- [ESR_ELx_EC_ILL] = "PSTATE.IL",
- [ESR_ELx_EC_SVC32] = "SVC (AArch32)",
- [ESR_ELx_EC_HVC32] = "HVC (AArch32)",
- [ESR_ELx_EC_SMC32] = "SMC (AArch32)",
- [ESR_ELx_EC_SVC64] = "SVC (AArch64)",
- [ESR_ELx_EC_HVC64] = "HVC (AArch64)",
- [ESR_ELx_EC_SMC64] = "SMC (AArch64)",
- [ESR_ELx_EC_SYS64] = "MSR/MRS (AArch64)",
- [ESR_ELx_EC_SVE] = "SVE",
- [ESR_ELx_EC_ERET] = "ERET/ERETAA/ERETAB",
- [ESR_ELx_EC_FPAC] = "FPAC",
- [ESR_ELx_EC_SME] = "SME",
- [ESR_ELx_EC_IMP_DEF] = "EL3 IMP DEF",
- [ESR_ELx_EC_IABT_LOW] = "IABT (lower EL)",
- [ESR_ELx_EC_IABT_CUR] = "IABT (current EL)",
- [ESR_ELx_EC_PC_ALIGN] = "PC Alignment",
- [ESR_ELx_EC_DABT_LOW] = "DABT (lower EL)",
- [ESR_ELx_EC_DABT_CUR] = "DABT (current EL)",
- [ESR_ELx_EC_SP_ALIGN] = "SP Alignment",
- [ESR_ELx_EC_MOPS] = "MOPS",
- [ESR_ELx_EC_FP_EXC32] = "FP (AArch32)",
- [ESR_ELx_EC_FP_EXC64] = "FP (AArch64)",
- [ESR_ELx_EC_GCS] = "Guarded Control Stack",
- [ESR_ELx_EC_SERROR] = "SError",
- [ESR_ELx_EC_BREAKPT_LOW] = "Breakpoint (lower EL)",
- [ESR_ELx_EC_BREAKPT_CUR] = "Breakpoint (current EL)",
- [ESR_ELx_EC_SOFTSTP_LOW] = "Software Step (lower EL)",
- [ESR_ELx_EC_SOFTSTP_CUR] = "Software Step (current EL)",
- [ESR_ELx_EC_WATCHPT_LOW] = "Watchpoint (lower EL)",
- [ESR_ELx_EC_WATCHPT_CUR] = "Watchpoint (current EL)",
- [ESR_ELx_EC_BKPT32] = "BKPT (AArch32)",
- [ESR_ELx_EC_VECTOR32] = "Vector catch (AArch32)",
- [ESR_ELx_EC_BRK64] = "BRK (AArch64)",
-};
-
-const char *esr_get_class_string(unsigned long esr)
-{
- return esr_class_str[ESR_ELx_EC(esr)];
-}
-
/*
* bad_el0_sync handles unexpected, but potentially recoverable synchronous
* exceptions taken from EL0.
diff --git a/arch/arm64/include/asm/brk-imm.h b/include/arch/arm64/asm/brk-imm.h
similarity index 100%
rename from arch/arm64/include/asm/brk-imm.h
rename to include/arch/arm64/asm/brk-imm.h
diff --git a/arch/arm64/include/asm/esr.h b/include/arch/arm64/asm/esr.h
similarity index 88%
rename from arch/arm64/include/asm/esr.h
rename to include/arch/arm64/asm/esr.h
index 7e86d400864e..1c86202c1be4 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/include/arch/arm64/asm/esr.h
@@ -7,8 +7,9 @@
#ifndef __ASM_ESR_H
#define __ASM_ESR_H
-#include <asm/memory.h>
-#include <asm/sysreg.h>
+#include <linux/const.h>
+#include <asm/sysreg-defs.h>
+#include <asm/brk-imm.h>
#define ESR_ELx_EC_UNKNOWN UL(0x00)
#define ESR_ELx_EC_WFx UL(0x01)
@@ -541,7 +542,56 @@ static inline bool esr_iss_is_eretab(unsigned long esr)
return esr & ESR_ELx_ERET_ISS_ERETA;
}
-const char *esr_get_class_string(unsigned long esr);
+static inline const char *esr_get_class_string(unsigned long esr)
+{
+ switch (ESR_ELx_EC(esr)) {
+ case ESR_ELx_EC_UNKNOWN: return "Unknown/Uncategorized";
+ case ESR_ELx_EC_WFx: return "WFI/WFE";
+ case ESR_ELx_EC_CP15_32: return "CP15 MCR/MRC";
+ case ESR_ELx_EC_CP15_64: return "CP15 MCRR/MRRC";
+ case ESR_ELx_EC_CP14_MR: return "CP14 MCR/MRC";
+ case ESR_ELx_EC_CP14_LS: return "CP14 LDC/STC";
+ case ESR_ELx_EC_FP_ASIMD: return "ASIMD";
+ case ESR_ELx_EC_CP10_ID: return "CP10 MRC/VMRS";
+ case ESR_ELx_EC_PAC: return "PAC";
+ case ESR_ELx_EC_CP14_64: return "CP14 MCRR/MRRC";
+ case ESR_ELx_EC_BTI: return "BTI";
+ case ESR_ELx_EC_ILL: return "PSTATE.IL";
+ case ESR_ELx_EC_SVC32: return "SVC (AArch32)";
+ case ESR_ELx_EC_HVC32: return "HVC (AArch32)";
+ case ESR_ELx_EC_SMC32: return "SMC (AArch32)";
+ case ESR_ELx_EC_SVC64: return "SVC (AArch64)";
+ case ESR_ELx_EC_HVC64: return "HVC (AArch64)";
+ case ESR_ELx_EC_SMC64: return "SMC (AArch64)";
+ case ESR_ELx_EC_SYS64: return "MSR/MRS (AArch64)";
+ case ESR_ELx_EC_SVE: return "SVE";
+ case ESR_ELx_EC_ERET: return "ERET/ERETAA/ERETAB";
+ case ESR_ELx_EC_FPAC: return "FPAC";
+ case ESR_ELx_EC_SME: return "SME";
+ case ESR_ELx_EC_IMP_DEF: return "EL3 IMP DEF";
+ case ESR_ELx_EC_IABT_LOW: return "IABT (lower EL)";
+ case ESR_ELx_EC_IABT_CUR: return "IABT (current EL)";
+ case ESR_ELx_EC_PC_ALIGN: return "PC Alignment";
+ case ESR_ELx_EC_DABT_LOW: return "DABT (lower EL)";
+ case ESR_ELx_EC_DABT_CUR: return "DABT (current EL)";
+ case ESR_ELx_EC_SP_ALIGN: return "SP Alignment";
+ case ESR_ELx_EC_MOPS: return "MOPS";
+ case ESR_ELx_EC_FP_EXC32: return "FP (AArch32)";
+ case ESR_ELx_EC_FP_EXC64: return "FP (AArch64)";
+ case ESR_ELx_EC_GCS: return "Guarded Control Stack";
+ case ESR_ELx_EC_SERROR: return "SError";
+ case ESR_ELx_EC_BREAKPT_LOW: return "Breakpoint (lower EL)";
+ case ESR_ELx_EC_BREAKPT_CUR: return "Breakpoint (current EL)";
+ case ESR_ELx_EC_SOFTSTP_LOW: return "Software Step (lower EL)";
+ case ESR_ELx_EC_SOFTSTP_CUR: return "Software Step (current EL)";
+ case ESR_ELx_EC_WATCHPT_LOW: return "Watchpoint (lower EL)";
+ case ESR_ELx_EC_WATCHPT_CUR: return "Watchpoint (current EL)";
+ case ESR_ELx_EC_BKPT32: return "BKPT (AArch32)";
+ case ESR_ELx_EC_VECTOR32: return "Vector catch (AArch32)";
+ case ESR_ELx_EC_BRK64: return "BRK (AArch64)";
+ default: return "UNRECOGNIZED EC";
+ }
+}
#endif /* __ASSEMBLER__ */
#endif /* __ASM_ESR_H */
diff --git a/arch/arm64/include/asm/sysreg-defs.h b/include/arch/arm64/asm/sysreg-defs.h
similarity index 100%
rename from arch/arm64/include/asm/sysreg-defs.h
rename to include/arch/arm64/asm/sysreg-defs.h
--
2.51.0
^ permalink raw reply related
* [PATCH v1 20/27] KVM: s390: arm64: Introduce host definitions
From: Steffen Eiden @ 2026-04-02 4:21 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
Add all basic definitions the arm on s390 KVM host requires.
Including, but not limited to:
- struct kvm*arch definitions
- various functions (to be implemented in the following patches)
- various defines required to run arm64 guests
Co-developed-by: Andreas Grapentin <gra@linux.ibm.com>
Signed-off-by: Andreas Grapentin <gra@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/s390/include/asm/kvm.h | 6 +
arch/s390/include/asm/kvm_host.h | 9 ++
arch/s390/include/asm/kvm_host_arm64.h | 199 +++++++++++++++++++++++++
3 files changed, 214 insertions(+)
create mode 100644 arch/s390/include/asm/kvm.h
create mode 100644 arch/s390/include/asm/kvm_host_arm64.h
diff --git a/arch/s390/include/asm/kvm.h b/arch/s390/include/asm/kvm.h
new file mode 100644
index 000000000000..d9e727d2378c
--- /dev/null
+++ b/arch/s390/include/asm/kvm.h
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifdef KVM_S390_ARM64
+#include <uapi/arch/arm64/asm/kvm.h>
+#else
+#include <uapi/asm/kvm.h>
+#endif
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 1c20168a3ef5..0330d3e503d8 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -3,7 +3,16 @@
#ifndef ASM_KVM_HOST_H
#define ASM_KVM_HOST_H
+#ifdef KVM_S390_ARM64
+#include <asm/kvm_host_arm64.h>
+#else
#include <asm/kvm_host_s390.h>
+#endif
+
+static inline bool kvm_arch_pmi_in_guest(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
#define PGM_PROTECTION 0x04
#define PGM_ADDRESSING 0x05
diff --git a/arch/s390/include/asm/kvm_host_arm64.h b/arch/s390/include/asm/kvm_host_arm64.h
new file mode 100644
index 000000000000..5a694c835dbb
--- /dev/null
+++ b/arch/s390/include/asm/kvm_host_arm64.h
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ASM_KVM_HOST_ARM64_H
+#define ASM_KVM_HOST_ARM64_H
+
+#include <linux/bug.h>
+
+#include <asm/kvm_host_arm64_types.h>
+#include "asm/debug.h"
+
+#include <kvm/arm_vgic.h>
+
+#define vcpu_gp_regs(v) ((v)->arch.sae_block.gpr)
+
+#define HAVE_KVM_MMIO
+
+#include <kvm/arm64/kvm_host.h>
+#include <asm/sae.h>
+
+#define KVM_HAVE_MMU_RWLOCK
+#define KVM_MAX_VCPUS 1
+
+#define KVM_VCPU_VALID_FEATURES 0
+
+#define KVM_HALT_POLL_NS_DEFAULT 50000
+
+#define __ctxt_sys_reg(ctx, reg) NULL
+struct kvm_cpu_context {
+ /*
+ * These are just for 32 bit, which we don't have, making them RES0.
+ * They are exposed to user space.
+ * Arm KVM seemingly does not enforce RES0.
+ */
+ u64 spsr_abt;
+ u64 spsr_und;
+ u64 spsr_irq;
+ u64 spsr_fiq;
+
+ __vector128 __aligned(16) vregs[32];
+};
+
+struct kvm_vcpu_arch {
+ struct kvm_sae_block sae_block;
+ struct kvm_sae_save_area save_area;
+ struct kvm_cpu_context ctxt;
+
+ u32 host_acrs[NUM_ACRS];
+
+ /* Hypervisor Configuration Register */
+ u64 hcr_elz;
+
+ /* Configuration flags, set once and for all before the vcpu can run */
+ u8 cflags;
+
+ /* Input flags to the hypervisor code, potentially cleared after use */
+ u8 iflags;
+
+ /* State flags for kernel bookkeeping, unused by the hypervisor code */
+ u8 sflags;
+
+ /*
+ * Don't run the guest (internal implementation need).
+ *
+ * Contrary to the flags above, this is set/cleared outside of
+ * a vcpu context, and thus cannot be mixed with the flags
+ * themselves (or the flag accesses need to be made atomic).
+ */
+ bool pause;
+
+ /* vcpu power state */
+ struct kvm_mp_state mp_state;
+ /* lock for mp_state & reset_state.reset */
+ spinlock_t mp_state_lock;
+
+ /* vcpu reset state */
+ struct vcpu_reset_state reset_state;
+
+ /* GMAP */
+ struct gmap *gmap;
+ struct kvm_s390_mmu_cache *mc;
+
+ void *debugfs_state_data;
+};
+
+struct kvm_vcpu_stat {
+ struct kvm_vcpu_stat_generic generic;
+ /* ARM64 stats */
+ u64 hvc_exit_stat;
+ u64 wfe_exit_stat;
+ u64 wfi_exit_stat;
+ u64 mmio_exit_user;
+ u64 mmio_exit_kernel;
+ u64 signal_exits;
+ u64 exits;
+ /* GMAP stats */
+ u64 pfault_sync;
+};
+
+#define kvm_vcpu_get_sp_el1(__vcpu) (&((__vcpu)->arch.sae_block.sp_el1))
+#define kvm_vcpu_get_vreg(__vcpu, _off) (&(__vcpu)->arch.ctxt.vregs[_off])
+#define kvm_vcpu_get_vregs(__vcpu) (&(__vcpu)->arch.ctxt.vregs)
+#define kvm_vcpu_get_fpsr(__vcpu) (&(__vcpu)->arch.sae_block.fpsr)
+#define kvm_vcpu_get_fpcr(__vcpu) (&(__vcpu)->arch.sae_block.fpcr)
+
+#define __vcpu_flags_preempt_disable() preempt_disable()
+#define __vcpu_flags_preempt_enable() preempt_enable()
+
+#define _vcpu_get_flag(v, flagset, ...) \
+ __vcpu_get_flag(&(v)->arch.flagset, __VA_ARGS__)
+#define _vcpu_set_flag(v, flagset, ...) \
+ __vcpu_set_flag(&(v)->arch.flagset, __VA_ARGS__)
+#define _vcpu_clear_flag(v, flagset, ...) \
+ __vcpu_clear_flag(&(v)->arch.flagset, __VA_ARGS__)
+#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
+
+struct kvm_arch_memory_slot {
+};
+
+struct kvm_arch {
+ struct gmap *gmap;
+ u64 guest_phys_size;
+
+ /* VM-wide vCPU feature set */
+ unsigned long flags;
+
+ /* Protects VM-scoped configuration data */
+ struct mutex config_lock;
+
+ debug_info_t *dbf;
+
+ DECLARE_BITMAP(vcpu_features, KVM_VCPU_MAX_FEATURES);
+
+ unsigned long mem_limit;
+};
+
+struct kvm_vm_stat {
+ struct kvm_vm_stat_generic generic;
+};
+
+#define kvm_vm_is_protected(_kvm) false
+
+#define KVM_HVA_ERR_BAD -1UL
+#define KVM_HVA_ERR_RO_BAD -2UL
+
+#define kvm_phys_size(__kvm) ((__kvm)->arch.guest_phys_size)
+static inline bool kvm_is_error_hva(unsigned long addr)
+{
+ return IS_ERR_VALUE(addr);
+}
+
+u32 get_kvm_ipa_limit(void);
+
+static inline void kvm_arch_sync_events(struct kvm *kvm) {}
+static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
+
+int kvm_handle_guest_abort(struct kvm_vcpu *vcpu);
+
+/* arm64 guests do not use async-pf. Defined because Kbuild requires it as s390 kvm turns it on. */
+#define ASYNC_PF_PER_VCPU 0
+struct kvm_arch_async_pf {
+ unsigned long pfault_token;
+};
+
+#define __unsupp_async_call(fn) WARN_ONCE(true, "async not supported on kvm-arm64 %s", fn)
+
+static inline bool kvm_arch_can_dequeue_async_page_present(struct kvm_vcpu *vcpu)
+{
+ __unsupp_async_call(__func__);
+ return false;
+};
+
+static inline void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+ __unsupp_async_call(__func__);
+};
+
+static inline bool kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+ __unsupp_async_call(__func__);
+ return false;
+};
+
+static inline void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+ __unsupp_async_call(__func__);
+};
+
+static inline void kvm_arch_async_page_present_queued(struct kvm_vcpu *vcpu)
+{
+ __unsupp_async_call(__func__);
+};
+
+#endif /* ASM_KVM_HOST_ARM64_H */
--
2.51.0
^ permalink raw reply related
* [PATCH v1 07/27] KVM: arm64: Provide arm64 KVM API for non-native architectures
From: Steffen Eiden @ 2026-04-02 4:21 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
The KVM‑related headers are moved to include/kvm/arm64/, decoupling them from
the arm64 architecture directory. The design convention is that
architecture‑specific headers under <arch>/include/asm/ include from this
shared location, allowing non‑native hosts to consume the arm64 KVM
infrastructure without duplicating code.
This refactoring enables non-native hosts to include and utilize arm64
KVM infrastructure without duplicating code or creating architecture
specific dependencies.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
MAINTAINERS | 1 +
arch/arm64/include/asm/el2_setup.h | 2 +-
arch/arm64/include/asm/hardirq.h | 2 +-
arch/arm64/include/asm/kvm_emulate.h | 3 +-
arch/arm64/include/asm/kvm_host.h | 99 +--------------
arch/arm64/include/asm/kvm_mmu.h | 41 +------
arch/arm64/kernel/head.S | 2 +-
arch/arm64/kernel/hyp-stub.S | 2 +-
arch/arm64/kvm/arm.c | 6 +-
arch/arm64/kvm/debug.c | 2 +-
arch/arm64/kvm/guest.c | 2 +
arch/arm64/kvm/hyp/entry.S | 2 +-
arch/arm64/kvm/hyp/hyp-entry.S | 2 +-
arch/arm64/kvm/hyp/nvhe/host.S | 2 +-
arch/arm64/kvm/hyp/nvhe/hyp-init.S | 2 +-
arch/arm64/kvm/mmu.c | 2 +-
arch/arm64/kvm/nested.c | 2 +-
arch/arm64/kvm/reset.c | 2 +-
arch/arm64/kvm/sys_regs.c | 2 +-
arch/arm64/kvm/vgic/vgic-its.c | 2 +-
arch/arm64/kvm/vgic/vgic-mmio-v3.c | 2 +-
arch/arm64/kvm/vgic/vgic-v3-nested.c | 2 +-
include/kvm/arm64/guest.h | 10 ++
.../asm => include/kvm/arm64}/kvm_arm.h | 5 +-
include/kvm/arm64/kvm_host.h | 113 ++++++++++++++++++
include/kvm/arm64/kvm_mmu.h | 47 ++++++++
26 files changed, 203 insertions(+), 156 deletions(-)
create mode 100644 include/kvm/arm64/guest.h
rename {arch/arm64/include/asm => include/kvm/arm64}/kvm_arm.h (99%)
create mode 100644 include/kvm/arm64/kvm_host.h
create mode 100644 include/kvm/arm64/kvm_mmu.h
diff --git a/MAINTAINERS b/MAINTAINERS
index e0a101fe05ce..075463117c2b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13995,6 +13995,7 @@ F: Documentation/virt/kvm/arm/
F: Documentation/virt/kvm/devices/arm*
F: arch/arm64/include/asm/kvm*
F: arch/arm64/include/uapi/asm/kvm*
+F: include/kvm/arm64/
F: include/uapi/arch/arm64/asm/kvm*
F: arch/arm64/kvm/
F: include/kvm/arm_*
diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
index 85f4c1615472..dfe3e85759f6 100644
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@ -11,7 +11,7 @@
#error Assembly-only header
#endif
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/ptrace.h>
#include <asm/sysreg.h>
#include <linux/irqchip/arm-gic-v3.h>
diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h
index 77d6b8c63d4e..0eceb8ab6abb 100644
--- a/arch/arm64/include/asm/hardirq.h
+++ b/arch/arm64/include/asm/hardirq.h
@@ -10,7 +10,7 @@
#include <linux/threads.h>
#include <asm/barrier.h>
#include <asm/irq.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/sysreg.h>
#define ack_bad_irq ack_bad_irq
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 5bf3d7e1d92c..822f6077b107 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -16,13 +16,14 @@
#include <asm/debug-monitors.h>
#include <asm/esr.h>
-#include <asm/kvm_arm.h>
#include <asm/kvm_hyp.h>
#include <asm/kvm_nested.h>
#include <asm/ptrace.h>
#include <asm/cputype.h>
#include <asm/virt.h>
+#include <kvm/arm64/kvm_arm.h>
+
#define CURRENT_EL_SP_EL0_VECTOR 0x0
#define CURRENT_EL_SP_ELx_VECTOR 0x200
#define LOWER_EL_AArch64_VECTOR 0x400
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 70cb9cfd760a..ae9e507f2c7c 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -37,25 +37,12 @@
#include <kvm/arm_arch_timer.h>
#include <kvm/arm_pmu.h>
+#include <kvm/arm64/kvm_host.h>
+
#define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
-#define KVM_VCPU_MAX_FEATURES 9
#define KVM_VCPU_VALID_FEATURES (BIT(KVM_VCPU_MAX_FEATURES) - 1)
-#define KVM_REQ_SLEEP \
- KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
-#define KVM_REQ_IRQ_PENDING KVM_ARCH_REQ(1)
-#define KVM_REQ_VCPU_RESET KVM_ARCH_REQ(2)
-#define KVM_REQ_RECORD_STEAL KVM_ARCH_REQ(3)
-#define KVM_REQ_RELOAD_GICv4 KVM_ARCH_REQ(4)
-#define KVM_REQ_RELOAD_PMU KVM_ARCH_REQ(5)
-#define KVM_REQ_SUSPEND KVM_ARCH_REQ(6)
-#define KVM_REQ_RESYNC_PMU_EL0 KVM_ARCH_REQ(7)
-#define KVM_REQ_NESTED_S2_UNMAP KVM_ARCH_REQ(8)
-#define KVM_REQ_GUEST_HYP_IRQ_PENDING KVM_ARCH_REQ(9)
-#define KVM_REQ_MAP_L1_VNCR_EL2 KVM_ARCH_REQ(10)
-#define KVM_REQ_VGIC_PROCESS_UPDATE KVM_ARCH_REQ(11)
-
#define KVM_DIRTY_LOG_MANUAL_CAPS (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \
KVM_DIRTY_LOG_INITIALLY_SET)
@@ -324,35 +311,7 @@ struct kvm_arch {
/* Protects VM-scoped configuration data */
struct mutex config_lock;
- /*
- * If we encounter a data abort without valid instruction syndrome
- * information, report this to user space. User space can (and
- * should) opt in to this feature if KVM_CAP_ARM_NISV_TO_USER is
- * supported.
- */
-#define KVM_ARCH_FLAG_RETURN_NISV_IO_ABORT_TO_USER 0
- /* Memory Tagging Extension enabled for the guest */
-#define KVM_ARCH_FLAG_MTE_ENABLED 1
- /* At least one vCPU has ran in the VM */
-#define KVM_ARCH_FLAG_HAS_RAN_ONCE 2
- /* The vCPU feature set for the VM is configured */
-#define KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED 3
- /* PSCI SYSTEM_SUSPEND enabled for the guest */
-#define KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED 4
- /* VM counter offset */
-#define KVM_ARCH_FLAG_VM_COUNTER_OFFSET 5
- /* Timer PPIs made immutable */
-#define KVM_ARCH_FLAG_TIMER_PPIS_IMMUTABLE 6
- /* Initial ID reg values loaded */
-#define KVM_ARCH_FLAG_ID_REGS_INITIALIZED 7
- /* Fine-Grained UNDEF initialised */
-#define KVM_ARCH_FLAG_FGU_INITIALIZED 8
- /* SVE exposed to guest */
-#define KVM_ARCH_FLAG_GUEST_HAS_SVE 9
- /* MIDR_EL1, REVIDR_EL1, and AIDR_EL1 are writable from userspace */
-#define KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS 10
- /* Unhandled SEAs are taken to userspace */
-#define KVM_ARCH_FLAG_EXIT_SEA 11
+ /* VM-wide vCPU feature set */
unsigned long flags;
/* VM-wide vCPU feature set */
@@ -812,13 +771,6 @@ extern s64 kvm_nvhe_sym(hyp_physvirt_offset);
extern u64 kvm_nvhe_sym(hyp_cpu_logical_map)[NR_CPUS];
#define hyp_cpu_logical_map CHOOSE_NVHE_SYM(hyp_cpu_logical_map)
-struct vcpu_reset_state {
- unsigned long pc;
- unsigned long r0;
- bool be;
- bool reset;
-};
-
struct vncr_tlb;
struct kvm_vcpu_arch {
@@ -1020,41 +972,6 @@ struct kvm_vcpu_arch {
/* pKVM VCPU setup completed */
#define VCPU_PKVM_FINALIZED __vcpu_single_flag(cflags, BIT(2))
-/* Exception pending */
-#define PENDING_EXCEPTION __vcpu_single_flag(iflags, BIT(0))
-/*
- * PC increment. Overlaps with EXCEPT_MASK on purpose so that it can't
- * be set together with an exception...
- */
-#define INCREMENT_PC __vcpu_single_flag(iflags, BIT(1))
-/* Target EL/MODE (not a single flag, but let's abuse the macro) */
-#define EXCEPT_MASK __vcpu_single_flag(iflags, GENMASK(3, 1))
-
-/* Helpers to encode exceptions with minimum fuss */
-#define __EXCEPT_MASK_VAL unpack_vcpu_flag(EXCEPT_MASK)
-#define __EXCEPT_SHIFT __builtin_ctzl(__EXCEPT_MASK_VAL)
-#define __vcpu_except_flags(_f) iflags, (_f << __EXCEPT_SHIFT), __EXCEPT_MASK_VAL
-
-/*
- * When PENDING_EXCEPTION is set, EXCEPT_MASK can take the following
- * values:
- *
- * For AArch32 EL1:
- */
-#define EXCEPT_AA32_UND __vcpu_except_flags(0)
-#define EXCEPT_AA32_IABT __vcpu_except_flags(1)
-#define EXCEPT_AA32_DABT __vcpu_except_flags(2)
-/* For AArch64: */
-#define EXCEPT_AA64_EL1_SYNC __vcpu_except_flags(0)
-#define EXCEPT_AA64_EL1_IRQ __vcpu_except_flags(1)
-#define EXCEPT_AA64_EL1_FIQ __vcpu_except_flags(2)
-#define EXCEPT_AA64_EL1_SERR __vcpu_except_flags(3)
-/* For AArch64 with NV: */
-#define EXCEPT_AA64_EL2_SYNC __vcpu_except_flags(4)
-#define EXCEPT_AA64_EL2_IRQ __vcpu_except_flags(5)
-#define EXCEPT_AA64_EL2_FIQ __vcpu_except_flags(6)
-#define EXCEPT_AA64_EL2_SERR __vcpu_except_flags(7)
-
/* Physical CPU not in supported_cpus */
#define ON_UNSUPPORTED_CPU __vcpu_single_flag(sflags, BIT(0))
/* WFIT instruction trapped */
@@ -1215,7 +1132,6 @@ struct kvm_vcpu_stat {
};
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
-int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
@@ -1299,13 +1215,6 @@ int __init populate_nv_trap_config(void);
void kvm_calculate_traps(struct kvm_vcpu *vcpu);
-/* MMIO helpers */
-void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
-unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
-
-int kvm_handle_mmio_return(struct kvm_vcpu *vcpu);
-int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa);
-
/*
* Returns true if a Performance Monitoring Interrupt (PMI), a.k.a. perf event,
* arrived in guest context. For arm64, any event that arrives while a vCPU is
@@ -1480,8 +1389,6 @@ struct kvm *kvm_arch_alloc_vm(void);
#define kvm_vm_is_protected(kvm) (is_protected_kvm_enabled() && (kvm)->arch.pkvm.is_protected)
-#define vcpu_is_protected(vcpu) kvm_vm_is_protected((vcpu)->kvm)
-
int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature);
bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index d968aca0461a..6a990aa63622 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -100,6 +100,8 @@ alternative_cb_end
#include <asm/kvm_host.h>
#include <asm/kvm_nested.h>
+#include <kvm/arm64/kvm_mmu.h>
+
void kvm_update_va_mask(struct alt_instr *alt,
__le32 *origptr, __le32 *updptr, int nr_inst);
void kvm_compute_layout(void);
@@ -142,12 +144,6 @@ static __always_inline unsigned long __kern_hyp_va(unsigned long v)
extern u32 __hyp_va_bits;
-/*
- * We currently support using a VM-specified IPA size. For backward
- * compatibility, the default IPA size is fixed to 40bits.
- */
-#define KVM_PHYS_SHIFT (40)
-
#define kvm_phys_shift(mmu) VTCR_EL2_IPA((mmu)->vtcr)
#define kvm_phys_size(mmu) (_AC(1, ULL) << kvm_phys_shift(mmu))
#define kvm_phys_mask(mmu) (kvm_phys_size(mmu) - _AC(1, ULL))
@@ -161,9 +157,6 @@ int create_hyp_mappings(void *from, void *to, enum kvm_pgtable_prot prot);
int __create_hyp_mappings(unsigned long start, unsigned long size,
unsigned long phys, enum kvm_pgtable_prot prot);
int hyp_alloc_private_va_range(size_t size, unsigned long *haddr);
-int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
- void __iomem **kaddr,
- void __iomem **haddr);
int create_hyp_exec_mappings(phys_addr_t phys_addr, size_t size,
void **haddr);
int create_hyp_stack(phys_addr_t phys_addr, unsigned long *haddr);
@@ -178,8 +171,6 @@ void stage2_unmap_vm(struct kvm *kvm);
int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long type);
void kvm_uninit_stage2_mmu(struct kvm *kvm);
void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu);
-int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
- phys_addr_t pa, unsigned long size, bool writable);
int kvm_handle_guest_sea(struct kvm_vcpu *vcpu);
int kvm_handle_guest_abort(struct kvm_vcpu *vcpu);
@@ -267,34 +258,6 @@ static inline unsigned int kvm_get_vmid_bits(void)
return get_vmid_bits(reg);
}
-
-/*
- * We are not in the kvm->srcu critical section most of the time, so we take
- * the SRCU read lock here. Since we copy the data from the user page, we
- * can immediately drop the lock again.
- */
-static inline int kvm_read_guest_lock(struct kvm *kvm,
- gpa_t gpa, void *data, unsigned long len)
-{
- int srcu_idx = srcu_read_lock(&kvm->srcu);
- int ret = kvm_read_guest(kvm, gpa, data, len);
-
- srcu_read_unlock(&kvm->srcu, srcu_idx);
-
- return ret;
-}
-
-static inline int kvm_write_guest_lock(struct kvm *kvm, gpa_t gpa,
- const void *data, unsigned long len)
-{
- int srcu_idx = srcu_read_lock(&kvm->srcu);
- int ret = kvm_write_guest(kvm, gpa, data, len);
-
- srcu_read_unlock(&kvm->srcu, srcu_idx);
-
- return ret;
-}
-
#define kvm_phys_to_vttbr(addr) phys_to_ttbr(addr)
/*
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 87a822e5c4ca..853952be8021 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -25,7 +25,7 @@
#include <asm/elf.h>
#include <asm/image.h>
#include <asm/kernel-pgtable.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/memory.h>
#include <asm/pgtable-hwdef.h>
#include <asm/page.h>
diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
index 085bc9972f6b..bf3a541fc076 100644
--- a/arch/arm64/kernel/hyp-stub.S
+++ b/arch/arm64/kernel/hyp-stub.S
@@ -11,7 +11,7 @@
#include <asm/assembler.h>
#include <asm/el2_setup.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_asm.h>
#include <asm/ptrace.h>
#include <asm/virt.h>
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 410ffd41fd73..47630730260f 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -32,7 +32,7 @@
#include <asm/cacheflush.h>
#include <asm/cpufeature.h>
#include <asm/virt.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_mmu.h>
@@ -46,6 +46,8 @@
#include <kvm/arm_pmu.h>
#include <kvm/arm_psci.h>
+#include <kvm/arm64/guest.h>
+
#include "sys_regs.h"
static enum kvm_mode kvm_mode = KVM_MODE_DEFAULT;
@@ -1489,7 +1491,7 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
return -EINVAL;
}
-static unsigned long system_supported_vcpu_features(void)
+unsigned long system_supported_vcpu_features(void)
{
unsigned long features = KVM_VCPU_VALID_FEATURES;
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index 3ad6b7c6e4ba..349fea6e3e51 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -12,7 +12,7 @@
#include <asm/debug-monitors.h>
#include <asm/kvm_asm.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_emulate.h>
static int cpu_has_spe(u64 dfr0)
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 332c453b87cf..557c380ffa37 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -27,6 +27,8 @@
#include <asm/kvm_nested.h>
#include <asm/sigcontext.h>
+#include <kvm/arm64/guest.h>
+
#include "trace.h"
const struct kvm_stats_desc kvm_vm_stats_desc[] = {
diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
index 11a10d8f5beb..b1694f738208 100644
--- a/arch/arm64/kvm/hyp/entry.S
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -10,7 +10,7 @@
#include <asm/assembler.h>
#include <asm/fpsimdmacros.h>
#include <asm/kvm.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_mmu.h>
#include <asm/kvm_mte.h>
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index 03f97d71984c..dfec4e6e5d62 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -10,7 +10,7 @@
#include <asm/alternative.h>
#include <asm/assembler.h>
#include <asm/cpufeature.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_asm.h>
#include <asm/mmu.h>
#include <asm/spectre.h>
diff --git a/arch/arm64/kvm/hyp/nvhe/host.S b/arch/arm64/kvm/hyp/nvhe/host.S
index eef15b374abb..3f5093387f5a 100644
--- a/arch/arm64/kvm/hyp/nvhe/host.S
+++ b/arch/arm64/kvm/hyp/nvhe/host.S
@@ -7,7 +7,7 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_mmu.h>
#include <asm/kvm_ptrauth.h>
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
index 0d42eedc7167..8677f4da7a2f 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
@@ -11,7 +11,7 @@
#include <asm/alternative.h>
#include <asm/assembler.h>
#include <asm/el2_setup.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_mmu.h>
#include <asm/pgtable-hwdef.h>
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 17d64a1e11e5..e19ff77b3cd5 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -14,7 +14,7 @@
#include <asm/acpi.h>
#include <asm/pgalloc.h>
#include <asm/cacheflush.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_mmu.h>
#include <asm/kvm_pgtable.h>
#include <asm/kvm_pkvm.h>
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index 2c43097248b2..1a3bd7bf6bf4 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -9,7 +9,7 @@
#include <linux/kvm_host.h>
#include <asm/fixmap.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_mmu.h>
#include <asm/kvm_nested.h>
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index b963fd975aac..036bf2dff976 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -23,7 +23,7 @@
#include <asm/cputype.h>
#include <asm/fpsimd.h>
#include <asm/ptrace.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_mmu.h>
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 1b4cacb6e918..a7564ee0fd15 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -24,7 +24,7 @@
#include <asm/cputype.h>
#include <asm/debug-monitors.h>
#include <asm/esr.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_hyp.h>
#include <asm/kvm_mmu.h>
diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
index 2ea9f1c7ebcd..076877db9243 100644
--- a/arch/arm64/kvm/vgic/vgic-its.c
+++ b/arch/arm64/kvm/vgic/vgic-its.c
@@ -17,7 +17,7 @@
#include <linux/irqchip/arm-gic-v3.h>
#include <asm/kvm_emulate.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_mmu.h>
#include "vgic.h"
diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
index 89edb84d1ac6..009e52a16c25 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
@@ -12,7 +12,7 @@
#include <kvm/arm_vgic.h>
#include <asm/kvm_emulate.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_mmu.h>
#include "vgic.h"
diff --git a/arch/arm64/kvm/vgic/vgic-v3-nested.c b/arch/arm64/kvm/vgic/vgic-v3-nested.c
index 5c69fa615823..a2070a637f51 100644
--- a/arch/arm64/kvm/vgic/vgic-v3-nested.c
+++ b/arch/arm64/kvm/vgic/vgic-v3-nested.c
@@ -9,7 +9,7 @@
#include <kvm/arm_vgic.h>
-#include <asm/kvm_arm.h>
+#include <kvm/arm64/kvm_arm.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_nested.h>
diff --git a/include/kvm/arm64/guest.h b/include/kvm/arm64/guest.h
new file mode 100644
index 000000000000..fa67d992e8fd
--- /dev/null
+++ b/include/kvm/arm64/guest.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __KVM_ARM64_GUEST_H__
+#define __KVM_ARM64_GUEST_H__
+
+/* Implemented by virt/kvm/arm64/guest.c */
+unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
+int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
+
+#endif /* __KVM_ARM64_GUEST_H__ */
diff --git a/arch/arm64/include/asm/kvm_arm.h b/include/kvm/arm64/kvm_arm.h
similarity index 99%
rename from arch/arm64/include/asm/kvm_arm.h
rename to include/kvm/arm64/kvm_arm.h
index 3f9233b5a130..b9c45e4dad72 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/include/kvm/arm64/kvm_arm.h
@@ -8,8 +8,9 @@
#define __ARM64_KVM_ARM_H__
#include <asm/esr.h>
-#include <asm/memory.h>
-#include <asm/sysreg.h>
+#include <linux/const.h>
+#include <linux/bits.h>
+#include <asm/sysreg-defs.h>
#include <asm/types.h>
/*
diff --git a/include/kvm/arm64/kvm_host.h b/include/kvm/arm64/kvm_host.h
new file mode 100644
index 000000000000..3a434f47497b
--- /dev/null
+++ b/include/kvm/arm64/kvm_host.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __KVM_ARM64_KVM_HOST_H
+#define __KVM_ARM64_KVM_HOST_H
+
+#include <linux/types.h>
+
+#define KVM_VCPU_MAX_FEATURES 9
+
+#define KVM_REQ_SLEEP \
+ KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
+#define KVM_REQ_IRQ_PENDING KVM_ARCH_REQ(1)
+#define KVM_REQ_VCPU_RESET KVM_ARCH_REQ(2)
+#define KVM_REQ_RECORD_STEAL KVM_ARCH_REQ(3)
+#define KVM_REQ_RELOAD_GICv4 KVM_ARCH_REQ(4)
+#define KVM_REQ_RELOAD_PMU KVM_ARCH_REQ(5)
+#define KVM_REQ_SUSPEND KVM_ARCH_REQ(6)
+#define KVM_REQ_RESYNC_PMU_EL0 KVM_ARCH_REQ(7)
+#define KVM_REQ_NESTED_S2_UNMAP KVM_ARCH_REQ(8)
+#define KVM_REQ_GUEST_HYP_IRQ_PENDING KVM_ARCH_REQ(9)
+#define KVM_REQ_MAP_L1_VNCR_EL2 KVM_ARCH_REQ(10)
+#define KVM_REQ_VGIC_PROCESS_UPDATE KVM_ARCH_REQ(11)
+
+struct vcpu_reset_state {
+ unsigned long pc;
+ unsigned long r0;
+ bool be;
+ bool reset;
+};
+
+/* MMIO helpers */
+void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
+unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
+
+int kvm_handle_mmio_return(struct kvm_vcpu *vcpu);
+int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa);
+
+/* Exception pending */
+#define PENDING_EXCEPTION __vcpu_single_flag(iflags, BIT(0))
+/*
+ * PC increment. Overlaps with EXCEPT_MASK on purpose so that it can't
+ * be set together with an exception...
+ */
+#define INCREMENT_PC __vcpu_single_flag(iflags, BIT(1))
+/* Target EL/MODE (not a single flag, but let's abuse the macro) */
+#define EXCEPT_MASK __vcpu_single_flag(iflags, GENMASK(3, 1))
+
+/* Helpers to encode exceptions with minimum fuss */
+#define __EXCEPT_MASK_VAL unpack_vcpu_flag(EXCEPT_MASK)
+#define __EXCEPT_SHIFT __builtin_ctzl(__EXCEPT_MASK_VAL)
+#define __vcpu_except_flags(_f) iflags, (_f << __EXCEPT_SHIFT), __EXCEPT_MASK_VAL
+
+/*
+ * When PENDING_EXCEPTION is set, EXCEPT_MASK can take the following
+ * values:
+ *
+ * For AArch32 EL1:
+ */
+#define EXCEPT_AA32_UND __vcpu_except_flags(0)
+#define EXCEPT_AA32_IABT __vcpu_except_flags(1)
+#define EXCEPT_AA32_DABT __vcpu_except_flags(2)
+/* For AArch64: */
+#define EXCEPT_AA64_EL1_SYNC __vcpu_except_flags(0)
+#define EXCEPT_AA64_EL1_IRQ __vcpu_except_flags(1)
+#define EXCEPT_AA64_EL1_FIQ __vcpu_except_flags(2)
+#define EXCEPT_AA64_EL1_SERR __vcpu_except_flags(3)
+/* For AArch64 with NV: */
+#define EXCEPT_AA64_EL2_SYNC __vcpu_except_flags(4)
+#define EXCEPT_AA64_EL2_IRQ __vcpu_except_flags(5)
+#define EXCEPT_AA64_EL2_FIQ __vcpu_except_flags(6)
+#define EXCEPT_AA64_EL2_SERR __vcpu_except_flags(7)
+
+static inline bool kvm_supports_32bit_el0(void)
+{
+ return false;
+}
+
+#define vcpu_is_protected(vcpu) kvm_vm_is_protected((vcpu)->kvm)
+
+/*
+ * If we encounter a data abort without valid instruction syndrome
+ * information, report this to user space. User space can (and
+ * should) opt in to this feature if KVM_CAP_ARM_NISV_TO_USER is
+ * supported.
+ */
+#define KVM_ARCH_FLAG_RETURN_NISV_IO_ABORT_TO_USER 0
+/* Memory Tagging Extension enabled for the guest */
+#define KVM_ARCH_FLAG_MTE_ENABLED 1
+/* At least one vCPU has ran in the VM */
+#define KVM_ARCH_FLAG_HAS_RAN_ONCE 2
+/* The vCPU feature set for the VM is configured */
+#define KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED 3
+/* PSCI SYSTEM_SUSPEND enabled for the guest */
+#define KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED 4
+/* VM counter offset */
+#define KVM_ARCH_FLAG_VM_COUNTER_OFFSET 5
+/* Timer PPIs made immutable */
+#define KVM_ARCH_FLAG_TIMER_PPIS_IMMUTABLE 6
+/* Initial ID reg values loaded */
+#define KVM_ARCH_FLAG_ID_REGS_INITIALIZED 7
+/* Fine-Grained UNDEF initialised */
+#define KVM_ARCH_FLAG_FGU_INITIALIZED 8
+/* SVE exposed to guest */
+#define KVM_ARCH_FLAG_GUEST_HAS_SVE 9
+/* MIDR_EL1, REVIDR_EL1, and AIDR_EL1 are writable from userspace */
+#define KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS 10
+/* Unhandled SEAs are taken to userspace */
+#define KVM_ARCH_FLAG_EXIT_SEA 11
+
+/* Implemented in architecture specific code */
+unsigned long system_supported_vcpu_features(void);
+
+#endif /* __KVM_ARM64_KVM_HOST_H */
diff --git a/include/kvm/arm64/kvm_mmu.h b/include/kvm/arm64/kvm_mmu.h
new file mode 100644
index 000000000000..91607105eaf6
--- /dev/null
+++ b/include/kvm/arm64/kvm_mmu.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef KVM_ARM64_KVM_MMU_H__
+#define KVM_ARM64_KVM_MMU_H__
+
+/*
+ * We currently support using a VM-specified IPA size. For backward
+ * compatibility, the default IPA size is fixed to 40bits.
+ */
+#define KVM_PHYS_SHIFT (40)
+
+/*
+ * We are not in the kvm->srcu critical section most of the time, so we take
+ * the SRCU read lock here. Since we copy the data from the user page, we
+ * can immediately drop the lock again.
+ */
+static inline int kvm_read_guest_lock(struct kvm *kvm,
+ gpa_t gpa, void *data, unsigned long len)
+{
+ int srcu_idx = srcu_read_lock(&kvm->srcu);
+ int ret = kvm_read_guest(kvm, gpa, data, len);
+
+ srcu_read_unlock(&kvm->srcu, srcu_idx);
+
+ return ret;
+}
+
+static inline int kvm_write_guest_lock(struct kvm *kvm, gpa_t gpa,
+ const void *data, unsigned long len)
+{
+ int srcu_idx = srcu_read_lock(&kvm->srcu);
+ int ret = kvm_write_guest(kvm, gpa, data, len);
+
+ srcu_read_unlock(&kvm->srcu, srcu_idx);
+
+ return ret;
+}
+
+/* Implemented by each architecture */
+int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
+ phys_addr_t pa, unsigned long size, bool writable);
+
+int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
+ void __iomem **kaddr,
+ void __iomem **haddr);
+
+#endif /* KVM_ARM64_KVM_MMU_H__ */
--
2.51.0
^ permalink raw reply related
* [PATCH v1 12/27] KVM: arm64: Share reset general register code
From: Steffen Eiden @ 2026-04-02 4:21 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
From: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Move code and required definitions to reset general registers into the
shared location. Additionally, add defines to arch/arm64 such that
accessing general registers becomes architecture agnostic.
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 | 97 +++++--------------------------
arch/arm64/kvm/reset.c | 33 +----------
include/kvm/arm64/kvm_host.h | 82 ++++++++++++++++++++++++++
include/kvm/arm64/reset.h | 8 +++
virt/kvm/arm64/Makefile.kvm | 1 +
virt/kvm/arm64/guest.c | 8 +--
virt/kvm/arm64/reset.c | 42 +++++++++++++
7 files changed, 154 insertions(+), 117 deletions(-)
create mode 100644 include/kvm/arm64/reset.h
create mode 100644 virt/kvm/arm64/reset.c
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 7e473b895740..e3a2ac3979ac 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -877,39 +877,6 @@ struct kvm_vcpu_arch {
struct vncr_tlb *vncr_tlb;
};
-/*
- * Each 'flag' is composed of a comma-separated triplet:
- *
- * - the flag-set it belongs to in the vcpu->arch structure
- * - the value for that flag
- * - the mask for that flag
- *
- * __vcpu_single_flag() builds such a triplet for a single-bit flag.
- * unpack_vcpu_flag() extract the flag value from the triplet for
- * direct use outside of the flag accessors.
- */
-#define __vcpu_single_flag(_set, _f) _set, (_f), (_f)
-
-#define __unpack_flag(_set, _f, _m) _f
-#define unpack_vcpu_flag(...) __unpack_flag(__VA_ARGS__)
-
-#define __build_check_flag(v, flagset, f, m) \
- do { \
- typeof(v->arch.flagset) *_fset; \
- \
- /* Check that the flags fit in the mask */ \
- BUILD_BUG_ON(HWEIGHT(m) != HWEIGHT((f) | (m))); \
- /* Check that the flags fit in the type */ \
- BUILD_BUG_ON((sizeof(*_fset) * 8) <= __fls(m)); \
- } while (0)
-
-#define __vcpu_get_flag(v, flagset, f, m) \
- ({ \
- __build_check_flag(v, flagset, f, m); \
- \
- READ_ONCE(v->arch.flagset) & (m); \
- })
-
/*
* Note that the set/clear accessors must be preempt-safe in order to
* avoid nesting them with load/put which also manipulate flags...
@@ -923,54 +890,14 @@ struct kvm_vcpu_arch {
#define __vcpu_flags_preempt_enable() preempt_enable()
#endif
-#define __vcpu_set_flag(v, flagset, f, m) \
- do { \
- typeof(v->arch.flagset) *fset; \
- \
- __build_check_flag(v, flagset, f, m); \
- \
- fset = &v->arch.flagset; \
- __vcpu_flags_preempt_disable(); \
- if (HWEIGHT(m) > 1) \
- *fset &= ~(m); \
- *fset |= (f); \
- __vcpu_flags_preempt_enable(); \
- } while (0)
-
-#define __vcpu_clear_flag(v, flagset, f, m) \
- do { \
- typeof(v->arch.flagset) *fset; \
- \
- __build_check_flag(v, flagset, f, m); \
- \
- fset = &v->arch.flagset; \
- __vcpu_flags_preempt_disable(); \
- *fset &= ~(m); \
- __vcpu_flags_preempt_enable(); \
- } while (0)
-
-#define __vcpu_test_and_clear_flag(v, flagset, f, m) \
- ({ \
- typeof(v->arch.flagset) set; \
- \
- set = __vcpu_get_flag(v, flagset, f, m); \
- __vcpu_clear_flag(v, flagset, f, m); \
- \
- set; \
- })
-
-#define vcpu_get_flag(v, ...) __vcpu_get_flag((v), __VA_ARGS__)
-#define vcpu_set_flag(v, ...) __vcpu_set_flag((v), __VA_ARGS__)
-#define vcpu_clear_flag(v, ...) __vcpu_clear_flag((v), __VA_ARGS__)
-#define vcpu_test_and_clear_flag(v, ...) \
- __vcpu_test_and_clear_flag((v), __VA_ARGS__)
-
-/* KVM_ARM_VCPU_INIT completed */
-#define VCPU_INITIALIZED __vcpu_single_flag(cflags, BIT(0))
-/* SVE config completed */
-#define VCPU_SVE_FINALIZED __vcpu_single_flag(cflags, BIT(1))
-/* pKVM VCPU setup completed */
-#define VCPU_PKVM_FINALIZED __vcpu_single_flag(cflags, BIT(2))
+#define _vcpu_get_flag(v, flagset, ...) \
+ __vcpu_get_flag(&(v)->arch.flagset, __VA_ARGS__)
+#define _vcpu_set_flag(v, flagset, ...) \
+ __vcpu_set_flag(&(v)->arch.flagset, __VA_ARGS__)
+#define _vcpu_clear_flag(v, flagset, ...) \
+ __vcpu_clear_flag(&(v)->arch.flagset, __VA_ARGS__)
+#define _vcpu_test_and_clear_flag(v, flagset, ...) \
+ __vcpu_test_and_clear_flag(&(v)->arch.flagset, __VA_ARGS__)
/* Physical CPU not in supported_cpus */
#define ON_UNSUPPORTED_CPU __vcpu_single_flag(sflags, BIT(0))
@@ -1081,6 +1008,12 @@ static inline u64 *___ctxt_sys_reg(const struct kvm_cpu_context *ctxt, int r)
#define ctxt_sys_reg(c,r) (*__ctxt_sys_reg(c,r))
+#define kvm_vcpu_get_sp_el1(__vcpu) (__ctxt_sys_reg(&(__vcpu)->arch.ctxt, SP_EL1))
+#define kvm_vcpu_get_vreg(__vcpu, _n) (&(__vcpu)->arch.ctxt.fp_regs.vregs[_n])
+#define kvm_vcpu_get_vregs(__vcpu) (&(__vcpu)->arch.ctxt.fp_regs.vregs)
+#define kvm_vcpu_get_fpsr(__vcpu) (&(__vcpu)->arch.ctxt.fp_regs.fpsr)
+#define kvm_vcpu_get_fpcr(__vcpu) (&(__vcpu)->arch.ctxt.fp_regs.fpcr)
+
u64 kvm_vcpu_apply_reg_masks(const struct kvm_vcpu *, enum vcpu_sysreg, u64);
#define __vcpu_assign_sys_reg(v, r, val) \
@@ -1413,8 +1346,6 @@ static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature)
#define kvm_vcpu_has_feature(k, f) __vcpu_has_feature(&(k)->arch, (f))
#define vcpu_has_feature(v, f) __vcpu_has_feature(&(v)->kvm->arch, (f))
-#define kvm_vcpu_initialized(v) vcpu_get_flag(vcpu, VCPU_INITIALIZED)
-
int kvm_trng_call(struct kvm_vcpu *vcpu);
#ifdef CONFIG_KVM
extern phys_addr_t hyp_mem_base;
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index d039f1d7116a..b4f579df0beb 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -30,22 +30,11 @@
#include <asm/kvm_nested.h>
#include <asm/virt.h>
+#include <kvm/arm64/reset.h>
+
/* Maximum phys_shift supported for any VM on this host */
static u32 __ro_after_init kvm_ipa_limit;
unsigned int __ro_after_init kvm_host_sve_max_vl;
-
-/*
- * ARMv8 Reset Values
- */
-#define VCPU_RESET_PSTATE_EL1 (PSR_MODE_EL1h | PSR_A_BIT | PSR_I_BIT | \
- PSR_F_BIT | PSR_D_BIT)
-
-#define VCPU_RESET_PSTATE_EL2 (PSR_MODE_EL2h | PSR_A_BIT | PSR_I_BIT | \
- PSR_F_BIT | PSR_D_BIT)
-
-#define VCPU_RESET_PSTATE_SVC (PSR_AA32_MODE_SVC | PSR_AA32_A_BIT | \
- PSR_AA32_I_BIT | PSR_AA32_F_BIT)
-
unsigned int __ro_after_init kvm_sve_max_vl;
int __init kvm_arm_init_sve(void)
@@ -191,7 +180,6 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu)
{
struct vcpu_reset_state reset_state;
bool loaded;
- u32 pstate;
spin_lock(&vcpu->arch.mp_state_lock);
reset_state = vcpu->arch.reset_state;
@@ -210,22 +198,7 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu)
kvm_vcpu_reset_sve(vcpu);
}
- if (vcpu_el1_is_32bit(vcpu))
- pstate = VCPU_RESET_PSTATE_SVC;
- else if (vcpu_has_nv(vcpu))
- pstate = VCPU_RESET_PSTATE_EL2;
- else
- pstate = VCPU_RESET_PSTATE_EL1;
-
- /* Reset core registers */
- memset(vcpu_gp_regs(vcpu), 0, sizeof(*vcpu_gp_regs(vcpu)));
- *vcpu_pc(vcpu) = 0;
- memset(&vcpu->arch.ctxt.fp_regs, 0, sizeof(vcpu->arch.ctxt.fp_regs));
- vcpu->arch.ctxt.spsr_abt = 0;
- vcpu->arch.ctxt.spsr_und = 0;
- vcpu->arch.ctxt.spsr_irq = 0;
- vcpu->arch.ctxt.spsr_fiq = 0;
- *vcpu_cpsr(vcpu) = pstate;
+ kvm_reset_vcpu_core_regs(vcpu);
/* Reset system registers */
kvm_reset_sys_regs(vcpu);
diff --git a/include/kvm/arm64/kvm_host.h b/include/kvm/arm64/kvm_host.h
index 21117e4fd546..20b824ecf16e 100644
--- a/include/kvm/arm64/kvm_host.h
+++ b/include/kvm/arm64/kvm_host.h
@@ -41,6 +41,86 @@ unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
int kvm_handle_mmio_return(struct kvm_vcpu *vcpu);
int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa);
+/*
+ * Each 'flag' is composed of a comma-separated triplet:
+ *
+ * - the flag-set it belongs to in the vcpu->arch structure
+ * - the value for that flag
+ * - the mask for that flag
+ *
+ * __vcpu_single_flag() builds such a triplet for a single-bit flag.
+ * unpack_vcpu_flag() extract the flag value from the triplet for
+ * direct use outside of the flag accessors.
+ */
+#define __vcpu_single_flag(_set, _f) _set, (_f), (_f)
+
+#define __unpack_flag(_set, _f, _m) _f
+#define unpack_vcpu_flag(...) __unpack_flag(__VA_ARGS__)
+
+#define __build_check_flag(flagset, f, m) \
+ do { \
+ /* Check that the flags fit in the mask */ \
+ BUILD_BUG_ON(HWEIGHT(m) != HWEIGHT((f) | (m))); \
+ /* Check that the flags fit in the type */ \
+ BUILD_BUG_ON((sizeof(*(flagset)) * 8) <= __fls(m)); \
+ } while (0)
+
+#define __vcpu_get_flag(flagset, f, m) \
+ ({ \
+ __build_check_flag((flagset), f, m); \
+ \
+ READ_ONCE(*(flagset)) & (m); \
+ })
+
+#define __vcpu_set_flag(flagset, f, m) \
+ do { \
+ typeof(*flagset) *fset; \
+ \
+ __build_check_flag((flagset), f, m); \
+ \
+ fset = (flagset); \
+ __vcpu_flags_preempt_disable(); \
+ if (HWEIGHT(m) > 1) \
+ *fset &= ~(m); \
+ *fset |= (f); \
+ __vcpu_flags_preempt_enable(); \
+ } while (0)
+
+#define __vcpu_clear_flag(flagset, f, m) \
+ do { \
+ typeof(*flagset) *fset; \
+ \
+ __build_check_flag(flagset, f, m); \
+ \
+ fset = (flagset); \
+ __vcpu_flags_preempt_disable(); \
+ *fset &= ~(m); \
+ __vcpu_flags_preempt_enable(); \
+ } while (0)
+
+#define __vcpu_test_and_clear_flag(flagset, f, m) \
+ ({ \
+ typeof(*flagset) set; \
+ \
+ set = __vcpu_get_flag((flagset), f, m); \
+ __vcpu_clear_flag((flagset), f, m); \
+ \
+ set; \
+ })
+
+#define vcpu_get_flag(v, ...) _vcpu_get_flag((v), __VA_ARGS__)
+#define vcpu_set_flag(v, ...) _vcpu_set_flag((v), __VA_ARGS__)
+#define vcpu_clear_flag(v, ...) _vcpu_clear_flag((v), __VA_ARGS__)
+#define vcpu_test_and_clear_flag(v, ...) \
+ _vcpu_test_and_clear_flag((v), __VA_ARGS__)
+
+/* KVM_ARM_VCPU_INIT completed */
+#define VCPU_INITIALIZED __vcpu_single_flag(cflags, BIT(0))
+/* SVE config completed */
+#define VCPU_SVE_FINALIZED __vcpu_single_flag(cflags, BIT(1))
+/* pKVM VCPU setup completed */
+#define VCPU_PKVM_FINALIZED __vcpu_single_flag(cflags, BIT(2))
+
/* Exception pending */
#define PENDING_EXCEPTION __vcpu_single_flag(iflags, BIT(0))
/*
@@ -76,6 +156,8 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa);
#define EXCEPT_AA64_EL2_FIQ __vcpu_except_flags(6)
#define EXCEPT_AA64_EL2_SERR __vcpu_except_flags(7)
+#define kvm_vcpu_initialized(v) vcpu_get_flag(v, VCPU_INITIALIZED)
+
static inline bool kvm_supports_32bit_el0(void)
{
return false;
diff --git a/include/kvm/arm64/reset.h b/include/kvm/arm64/reset.h
new file mode 100644
index 000000000000..a0bca4769b13
--- /dev/null
+++ b/include/kvm/arm64/reset.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __KVM_ARM64_RESET_H__
+#define __KVM_ARM64_RESET_H__
+
+void kvm_reset_vcpu_core_regs(struct kvm_vcpu *vcpu);
+
+#endif /* __KVM_ARM64_RESET_H__ */
diff --git a/virt/kvm/arm64/Makefile.kvm b/virt/kvm/arm64/Makefile.kvm
index ac969bf1c016..c5e1db570a09 100644
--- a/virt/kvm/arm64/Makefile.kvm
+++ b/virt/kvm/arm64/Makefile.kvm
@@ -9,4 +9,5 @@ shared-arm64-obj := \
$(KVM_ARM64)/guest.o \
$(KVM_ARM64)/handle_exit.o \
$(KVM_ARM64)/mmio.o \
+ $(KVM_ARM64)/reset.o \
diff --git a/virt/kvm/arm64/guest.c b/virt/kvm/arm64/guest.c
index e283a4456df8..35ba03033b4c 100644
--- a/virt/kvm/arm64/guest.c
+++ b/virt/kvm/arm64/guest.c
@@ -93,7 +93,7 @@ static void *core_reg_addr(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
return vcpu_cpsr(vcpu);
case KVM_REG_ARM_CORE_REG(sp_el1):
- return __ctxt_sys_reg(&vcpu->arch.ctxt, 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);
@@ -117,13 +117,13 @@ static void *core_reg_addr(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]):
off -= KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]);
off /= 4;
- return &vcpu->arch.ctxt.fp_regs.vregs[off];
+ return kvm_vcpu_get_vreg(vcpu, off);
case KVM_REG_ARM_CORE_REG(fp_regs.fpsr):
- return &vcpu->arch.ctxt.fp_regs.fpsr;
+ return kvm_vcpu_get_fpsr(vcpu);
case KVM_REG_ARM_CORE_REG(fp_regs.fpcr):
- return &vcpu->arch.ctxt.fp_regs.fpcr;
+ return kvm_vcpu_get_fpcr(vcpu);
default:
return NULL;
diff --git a/virt/kvm/arm64/reset.c b/virt/kvm/arm64/reset.c
new file mode 100644
index 000000000000..5a8be5233f76
--- /dev/null
+++ b/virt/kvm/arm64/reset.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/kvm_host.h>
+#include <asm/pstate.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_nested.h>
+#include <kvm/arm64/reset.h>
+
+/*
+ * ARMv8 Reset Values
+ */
+#define VCPU_RESET_PSTATE_EL1 (PSR_MODE_EL1h | PSR_A_BIT | PSR_I_BIT | \
+ PSR_F_BIT | PSR_D_BIT)
+
+#define VCPU_RESET_PSTATE_EL2 (PSR_MODE_EL2h | PSR_A_BIT | PSR_I_BIT | \
+ PSR_F_BIT | PSR_D_BIT)
+
+#define VCPU_RESET_PSTATE_SVC (PSR_AA32_MODE_SVC | PSR_AA32_A_BIT | \
+ PSR_AA32_I_BIT | PSR_AA32_F_BIT)
+
+void kvm_reset_vcpu_core_regs(struct kvm_vcpu *vcpu)
+{
+ u64 pstate;
+
+ if (vcpu_el1_is_32bit(vcpu))
+ pstate = VCPU_RESET_PSTATE_SVC;
+ else if (vcpu_has_nv(vcpu))
+ pstate = VCPU_RESET_PSTATE_EL2;
+ else
+ pstate = VCPU_RESET_PSTATE_EL1;
+
+ /* Reset core registers */
+ memset(vcpu_gp_regs(vcpu), 0, sizeof(vcpu_gp_regs(vcpu)));
+ *vcpu_pc(vcpu) = 0;
+ memset(kvm_vcpu_get_vregs(vcpu), 0, sizeof(*kvm_vcpu_get_vregs(vcpu)));
+ memset(kvm_vcpu_get_fpsr(vcpu), 0, sizeof(*kvm_vcpu_get_fpsr(vcpu)));
+ memset(kvm_vcpu_get_fpcr(vcpu), 0, sizeof(*kvm_vcpu_get_fpcr(vcpu)));
+ vcpu->arch.ctxt.spsr_abt = 0;
+ vcpu->arch.ctxt.spsr_und = 0;
+ vcpu->arch.ctxt.spsr_irq = 0;
+ vcpu->arch.ctxt.spsr_fiq = 0;
+ *vcpu_cpsr(vcpu) = pstate;
+}
--
2.51.0
^ permalink raw reply related
* [PATCH v1 09/27] KVM: arm64: Share kvm_emulate definitions
From: Steffen Eiden @ 2026-04-02 4:21 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
Move functions and definitions useful for emulating arm64 instructions
to include/kvm/arm64.
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 | 235 +-----------------
arch/arm64/kvm/hyp/include/hyp/adjust_pc.h | 13 -
include/kvm/arm64/kvm_emulate.h | 268 +++++++++++++++++++++
3 files changed, 269 insertions(+), 247 deletions(-)
create mode 100644 include/kvm/arm64/kvm_emulate.h
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 822f6077b107..39fa3a12730c 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -23,18 +23,7 @@
#include <asm/virt.h>
#include <kvm/arm64/kvm_arm.h>
-
-#define CURRENT_EL_SP_EL0_VECTOR 0x0
-#define CURRENT_EL_SP_ELx_VECTOR 0x200
-#define LOWER_EL_AArch64_VECTOR 0x400
-#define LOWER_EL_AArch32_VECTOR 0x600
-
-enum exception_type {
- except_type_sync = 0,
- except_type_irq = 0x80,
- except_type_fiq = 0x100,
- except_type_serror = 0x180,
-};
+#include <kvm/arm64/kvm_emulate.h>
#define kvm_exception_type_names \
{ except_type_sync, "SYNC" }, \
@@ -45,36 +34,8 @@ enum exception_type {
bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
void kvm_skip_instr32(struct kvm_vcpu *vcpu);
-void kvm_inject_undefined(struct kvm_vcpu *vcpu);
void kvm_inject_sync(struct kvm_vcpu *vcpu, u64 esr);
-int kvm_inject_serror_esr(struct kvm_vcpu *vcpu, u64 esr);
-int kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr);
int kvm_inject_dabt_excl_atomic(struct kvm_vcpu *vcpu, u64 addr);
-void kvm_inject_size_fault(struct kvm_vcpu *vcpu);
-
-static inline int kvm_inject_sea_dabt(struct kvm_vcpu *vcpu, u64 addr)
-{
- return kvm_inject_sea(vcpu, false, addr);
-}
-
-static inline int kvm_inject_sea_iabt(struct kvm_vcpu *vcpu, u64 addr)
-{
- return kvm_inject_sea(vcpu, true, addr);
-}
-
-static inline int kvm_inject_serror(struct kvm_vcpu *vcpu)
-{
- /*
- * ESR_ELx.ISV (later renamed to IDS) indicates whether or not
- * ESR_ELx.ISS contains IMPLEMENTATION DEFINED syndrome information.
- *
- * Set the bit when injecting an SError w/o an ESR to indicate ISS
- * does not follow the architected format.
- */
- return kvm_inject_serror_esr(vcpu, ESR_ELx_ISV);
-}
-
-void kvm_vcpu_wfi(struct kvm_vcpu *vcpu);
void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu);
int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2);
@@ -160,24 +121,6 @@ static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
*vcpu_cpsr(vcpu) |= PSR_AA32_T_BIT;
}
-/*
- * vcpu_get_reg and vcpu_set_reg should always be passed a register number
- * coming from a read of ESR_EL2. Otherwise, it may give the wrong result on
- * AArch32 with banked registers.
- */
-static __always_inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,
- u8 reg_num)
-{
- return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs[reg_num];
-}
-
-static __always_inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
- unsigned long val)
-{
- if (reg_num != 31)
- vcpu_gp_regs(vcpu)->regs[reg_num] = val;
-}
-
static inline bool vcpu_is_el2_ctxt(const struct kvm_cpu_context *ctxt)
{
switch (ctxt->regs.pstate & (PSR_MODE32_BIT | PSR_MODE_MASK)) {
@@ -361,82 +304,11 @@ static inline u64 kvm_vcpu_get_disr(const struct kvm_vcpu *vcpu)
return vcpu->arch.fault.disr_el1;
}
-static inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu)
-{
- return kvm_vcpu_get_esr(vcpu) & ESR_ELx_xVC_IMM_MASK;
-}
-
-static __always_inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
-{
- return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_ISV);
-}
-
static inline unsigned long kvm_vcpu_dabt_iss_nisv_sanitized(const struct kvm_vcpu *vcpu)
{
return kvm_vcpu_get_esr(vcpu) & (ESR_ELx_CM | ESR_ELx_WNR | ESR_ELx_FSC);
}
-static inline bool kvm_vcpu_dabt_issext(const struct kvm_vcpu *vcpu)
-{
- return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_SSE);
-}
-
-static inline bool kvm_vcpu_dabt_issf(const struct kvm_vcpu *vcpu)
-{
- return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_SF);
-}
-
-static __always_inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
-{
- return (kvm_vcpu_get_esr(vcpu) & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT;
-}
-
-static __always_inline bool kvm_vcpu_abt_iss1tw(const struct kvm_vcpu *vcpu)
-{
- return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_S1PTW);
-}
-
-/* Always check for S1PTW *before* using this. */
-static __always_inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
-{
- return kvm_vcpu_get_esr(vcpu) & ESR_ELx_WNR;
-}
-
-static inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu)
-{
- return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_CM);
-}
-
-static __always_inline unsigned int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu)
-{
- return 1 << ((kvm_vcpu_get_esr(vcpu) & ESR_ELx_SAS) >> ESR_ELx_SAS_SHIFT);
-}
-
-/* This one is not specific to Data Abort */
-static __always_inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu)
-{
- return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_IL);
-}
-
-static __always_inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
-{
- return ESR_ELx_EC(kvm_vcpu_get_esr(vcpu));
-}
-
-static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
-{
- return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW;
-}
-
-static inline bool kvm_vcpu_trap_is_exec_fault(const struct kvm_vcpu *vcpu)
-{
- return kvm_vcpu_trap_is_iabt(vcpu) && !kvm_vcpu_abt_iss1tw(vcpu);
-}
-
-static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
-{
- return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC;
-}
static inline
bool kvm_vcpu_trap_is_permission_fault(const struct kvm_vcpu *vcpu)
@@ -472,36 +344,6 @@ static __always_inline bool kvm_vcpu_abt_issea(const struct kvm_vcpu *vcpu)
}
}
-static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
-{
- u64 esr = kvm_vcpu_get_esr(vcpu);
- return ESR_ELx_SYS64_ISS_RT(esr);
-}
-
-static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
-{
- if (kvm_vcpu_abt_iss1tw(vcpu)) {
- /*
- * Only a permission fault on a S1PTW should be
- * considered as a write. Otherwise, page tables baked
- * in a read-only memslot will result in an exception
- * being delivered in the guest.
- *
- * The drawback is that we end-up faulting twice if the
- * guest is using any of HW AF/DB: a translation fault
- * to map the page containing the PT (read only at
- * first), then a permission fault to allow the flags
- * to be set.
- */
- return kvm_vcpu_trap_is_permission_fault(vcpu);
- }
-
- if (kvm_vcpu_trap_is_iabt(vcpu))
- return false;
-
- return kvm_vcpu_dabt_iswrite(vcpu);
-}
-
static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
{
return __vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
@@ -537,81 +379,6 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
return vcpu_read_sys_reg(vcpu, r) & bit;
}
-static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
- unsigned long data,
- unsigned int len)
-{
- if (kvm_vcpu_is_be(vcpu)) {
- switch (len) {
- case 1:
- return data & 0xff;
- case 2:
- return be16_to_cpu(data & 0xffff);
- case 4:
- return be32_to_cpu(data & 0xffffffff);
- default:
- return be64_to_cpu(data);
- }
- } else {
- switch (len) {
- case 1:
- return data & 0xff;
- case 2:
- return le16_to_cpu(data & 0xffff);
- case 4:
- return le32_to_cpu(data & 0xffffffff);
- default:
- return le64_to_cpu(data);
- }
- }
-
- return data; /* Leave LE untouched */
-}
-
-static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,
- unsigned long data,
- unsigned int len)
-{
- if (kvm_vcpu_is_be(vcpu)) {
- switch (len) {
- case 1:
- return data & 0xff;
- case 2:
- return cpu_to_be16(data & 0xffff);
- case 4:
- return cpu_to_be32(data & 0xffffffff);
- default:
- return cpu_to_be64(data);
- }
- } else {
- switch (len) {
- case 1:
- return data & 0xff;
- case 2:
- return cpu_to_le16(data & 0xffff);
- case 4:
- return cpu_to_le32(data & 0xffffffff);
- default:
- return cpu_to_le64(data);
- }
- }
-
- return data; /* Leave LE untouched */
-}
-
-static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
-{
- WARN_ON(vcpu_get_flag(vcpu, PENDING_EXCEPTION));
- vcpu_set_flag(vcpu, INCREMENT_PC);
-}
-
-#define kvm_pend_exception(v, e) \
- do { \
- WARN_ON(vcpu_get_flag((v), INCREMENT_PC)); \
- vcpu_set_flag((v), PENDING_EXCEPTION); \
- vcpu_set_flag((v), e); \
- } while (0)
-
/*
* Returns a 'sanitised' view of CPTR_EL2, translating from nVHE to the VHE
* format if E2H isn't set.
diff --git a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
index 4fdfeabefeb4..15e1e5db73e1 100644
--- a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
+++ b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
@@ -13,19 +13,6 @@
#include <asm/kvm_emulate.h>
#include <asm/kvm_host.h>
-static inline void kvm_skip_instr(struct kvm_vcpu *vcpu)
-{
- if (vcpu_mode_is_32bit(vcpu)) {
- kvm_skip_instr32(vcpu);
- } else {
- *vcpu_pc(vcpu) += 4;
- *vcpu_cpsr(vcpu) &= ~PSR_BTYPE_MASK;
- }
-
- /* advance the singlestep state machine */
- *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
-}
-
/*
* Skip an instruction which has been emulated at hyp while most guest sysregs
* are live.
diff --git a/include/kvm/arm64/kvm_emulate.h b/include/kvm/arm64/kvm_emulate.h
new file mode 100644
index 000000000000..25322b95af21
--- /dev/null
+++ b/include/kvm/arm64/kvm_emulate.h
@@ -0,0 +1,268 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef KVM_ARM64_KVM_EMULATE_H
+#define KVM_ARM64_KVM_EMULATE_H
+
+#include <asm/esr.h>
+#include <asm/pstate.h>
+#include <asm/sysreg-defs.h>
+
+static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu);
+static __always_inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu);
+static __always_inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu);
+static inline bool kvm_vcpu_trap_is_permission_fault(const struct kvm_vcpu *vcpu);
+static u64 kvm_vcpu_get_esr(const struct kvm_vcpu *vcpu);
+static __always_inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu);
+
+#define CURRENT_EL_SP_EL0_VECTOR 0x0
+#define CURRENT_EL_SP_ELx_VECTOR 0x200
+#define LOWER_EL_AArch64_VECTOR 0x400
+#define LOWER_EL_AArch32_VECTOR 0x600
+
+enum exception_type {
+ except_type_sync = 0,
+ except_type_irq = 0x80,
+ except_type_fiq = 0x100,
+ except_type_serror = 0x180,
+};
+
+void kvm_skip_instr32(struct kvm_vcpu *vcpu);
+
+void kvm_inject_undefined(struct kvm_vcpu *vcpu);
+int kvm_inject_serror_esr(struct kvm_vcpu *vcpu, u64 esr);
+int kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr);
+void kvm_inject_size_fault(struct kvm_vcpu *vcpu);
+
+static inline int kvm_inject_sea_dabt(struct kvm_vcpu *vcpu, u64 addr)
+{
+ return kvm_inject_sea(vcpu, false, addr);
+}
+
+static inline int kvm_inject_sea_iabt(struct kvm_vcpu *vcpu, u64 addr)
+{
+ return kvm_inject_sea(vcpu, true, addr);
+}
+
+static inline int kvm_inject_serror(struct kvm_vcpu *vcpu)
+{
+ /*
+ * ESR_ELx.ISV (later renamed to IDS) indicates whether or not
+ * ESR_ELx.ISS contains IMPLEMENTATION DEFINED syndrome information.
+ *
+ * Set the bit when injecting an SError w/o an ESR to indicate ISS
+ * does not follow the architected format.
+ */
+ return kvm_inject_serror_esr(vcpu, ESR_ELx_ISV);
+}
+
+void kvm_vcpu_wfi(struct kvm_vcpu *vcpu);
+
+static inline void kvm_skip_instr(struct kvm_vcpu *vcpu)
+{
+ if (vcpu_mode_is_32bit(vcpu)) {
+ kvm_skip_instr32(vcpu);
+ } else {
+ *vcpu_pc(vcpu) += 4;
+ *vcpu_cpsr(vcpu) &= ~SPSR64_BTYPE_MASK;
+ }
+
+ /* advance the singlestep state machine */
+ *vcpu_cpsr(vcpu) &= ~SPSR_SS;
+}
+
+/*
+ * vcpu_get_reg and vcpu_set_reg should always be passed a register number
+ * coming from a read of ESR_EL2. Otherwise, it may give the wrong result on
+ * AArch32 with banked registers.
+ */
+static __always_inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,
+ u8 reg_num)
+{
+ return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs[reg_num];
+}
+
+static __always_inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
+ unsigned long val)
+{
+ if (reg_num != 31)
+ vcpu_gp_regs(vcpu)->regs[reg_num] = val;
+}
+
+static inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_get_esr(vcpu) & ESR_ELx_xVC_IMM_MASK;
+}
+
+static __always_inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
+{
+ return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_ISV);
+}
+
+static inline bool kvm_vcpu_dabt_issext(const struct kvm_vcpu *vcpu)
+{
+ return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_SSE);
+}
+
+static inline bool kvm_vcpu_dabt_issf(const struct kvm_vcpu *vcpu)
+{
+ return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_SF);
+}
+
+static __always_inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
+{
+ return (kvm_vcpu_get_esr(vcpu) & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT;
+}
+
+static __always_inline bool kvm_vcpu_abt_iss1tw(const struct kvm_vcpu *vcpu)
+{
+ return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_S1PTW);
+}
+
+/* Always check for S1PTW *before* using this. */
+static __always_inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_get_esr(vcpu) & ESR_ELx_WNR;
+}
+
+static inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu)
+{
+ return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_CM);
+}
+
+static __always_inline unsigned int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu)
+{
+ return 1 << ((kvm_vcpu_get_esr(vcpu) & ESR_ELx_SAS) >> ESR_ELx_SAS_SHIFT);
+}
+
+/* This one is not specific to Data Abort */
+static __always_inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu)
+{
+ return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_IL);
+}
+
+static __always_inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
+{
+ return ESR_ELx_EC(kvm_vcpu_get_esr(vcpu));
+}
+
+static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW;
+}
+
+static inline bool kvm_vcpu_trap_is_exec_fault(const struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_trap_is_iabt(vcpu) && !kvm_vcpu_abt_iss1tw(vcpu);
+}
+
+static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
+{
+ u64 esr = kvm_vcpu_get_esr(vcpu);
+
+ return ESR_ELx_SYS64_ISS_RT(esr);
+}
+
+static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC;
+}
+
+static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
+{
+ if (kvm_vcpu_abt_iss1tw(vcpu)) {
+ /*
+ * Only a permission fault on a S1PTW should be
+ * considered as a write. Otherwise, page tables baked
+ * in a read-only memslot will result in an exception
+ * being delivered in the guest.
+ *
+ * The drawback is that we end-up faulting twice if the
+ * guest is using any of HW AF/DB: a translation fault
+ * to map the page containing the PT (read only at
+ * first), then a permission fault to allow the flags
+ * to be set.
+ */
+ return kvm_vcpu_trap_is_permission_fault(vcpu);
+ }
+
+ if (kvm_vcpu_trap_is_iabt(vcpu))
+ return false;
+
+ return kvm_vcpu_dabt_iswrite(vcpu);
+}
+
+static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
+ unsigned long data,
+ unsigned int len)
+{
+ if (kvm_vcpu_is_be(vcpu)) {
+ switch (len) {
+ case 1:
+ return data & 0xff;
+ case 2:
+ return be16_to_cpu(data & 0xffff);
+ case 4:
+ return be32_to_cpu(data & 0xffffffff);
+ default:
+ return be64_to_cpu(data);
+ }
+ } else {
+ switch (len) {
+ case 1:
+ return data & 0xff;
+ case 2:
+ return le16_to_cpu(data & 0xffff);
+ case 4:
+ return le32_to_cpu(data & 0xffffffff);
+ default:
+ return le64_to_cpu(data);
+ }
+ }
+
+ return data; /* Leave LE untouched */
+}
+
+static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,
+ unsigned long data,
+ unsigned int len)
+{
+ if (kvm_vcpu_is_be(vcpu)) {
+ switch (len) {
+ case 1:
+ return data & 0xff;
+ case 2:
+ return cpu_to_be16(data & 0xffff);
+ case 4:
+ return cpu_to_be32(data & 0xffffffff);
+ default:
+ return cpu_to_be64(data);
+ }
+ } else {
+ switch (len) {
+ case 1:
+ return data & 0xff;
+ case 2:
+ return cpu_to_le16(data & 0xffff);
+ case 4:
+ return cpu_to_le32(data & 0xffffffff);
+ default:
+ return cpu_to_le64(data);
+ }
+ }
+
+ return data; /* Leave LE untouched */
+}
+
+static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
+{
+ WARN_ON(vcpu_get_flag(vcpu, PENDING_EXCEPTION));
+ vcpu_set_flag(vcpu, INCREMENT_PC);
+}
+
+#define kvm_pend_exception(v, e) \
+ do { \
+ WARN_ON(vcpu_get_flag((v), INCREMENT_PC)); \
+ vcpu_set_flag((v), PENDING_EXCEPTION); \
+ vcpu_set_flag((v), e); \
+ } while (0)
+
+#endif /* KVM_ARM64_KVM_EMULATE_H */
--
2.51.0
^ permalink raw reply related
* [PATCH v1 08/27] arm64: Extract pstate definitions from ptrace
From: Steffen Eiden @ 2026-04-02 4:21 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
From: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Split all definitions that can be used by non-native architectures into a
separate file pstate.h. This allows other architectures using
the pstate definitions. While at it refactor SPSR related definitions
to use the BIT(n) macro and move them into sysreg-defs.h
Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/ptrace.h | 34 +-----------------
arch/arm64/include/uapi/asm/Kbuild | 1 +
arch/arm64/include/uapi/asm/ptrace.h | 49 +------------------------
include/arch/arm64/asm/pstate.h | 46 ++++++++++++++++++++++++
include/arch/arm64/asm/sysreg-defs.h | 42 ++++++++++++++++++++++
include/uapi/arch/arm64/asm/pstate.h | 53 ++++++++++++++++++++++++++++
6 files changed, 144 insertions(+), 81 deletions(-)
create mode 100644 include/arch/arm64/asm/pstate.h
create mode 100644 include/uapi/arch/arm64/asm/pstate.h
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 39582511ad72..72ea0a8af960 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -9,6 +9,7 @@
#define __ASM_PTRACE_H
#include <asm/cpufeature.h>
+#include <asm/pstate.h>
#include <uapi/asm/ptrace.h>
@@ -28,10 +29,6 @@
#define GIC_PRIO_PSR_I_SET GICV3_PRIO_PSR_I_SET
-/* Additional SPSR bits not exposed in the UABI */
-#define PSR_MODE_THREAD_BIT (1 << 0)
-#define PSR_IL_BIT (1 << 20)
-
/* AArch32-specific ptrace requests */
#define COMPAT_PTRACE_GETREGS 12
#define COMPAT_PTRACE_SETREGS 13
@@ -42,41 +39,12 @@
#define COMPAT_PTRACE_GETHBPREGS 29
#define COMPAT_PTRACE_SETHBPREGS 30
-/* SPSR_ELx bits for exceptions taken from AArch32 */
-#define PSR_AA32_MODE_MASK 0x0000001f
-#define PSR_AA32_MODE_USR 0x00000010
-#define PSR_AA32_MODE_FIQ 0x00000011
-#define PSR_AA32_MODE_IRQ 0x00000012
-#define PSR_AA32_MODE_SVC 0x00000013
-#define PSR_AA32_MODE_ABT 0x00000017
-#define PSR_AA32_MODE_HYP 0x0000001a
-#define PSR_AA32_MODE_UND 0x0000001b
-#define PSR_AA32_MODE_SYS 0x0000001f
-#define PSR_AA32_T_BIT 0x00000020
-#define PSR_AA32_F_BIT 0x00000040
-#define PSR_AA32_I_BIT 0x00000080
-#define PSR_AA32_A_BIT 0x00000100
-#define PSR_AA32_E_BIT 0x00000200
-#define PSR_AA32_PAN_BIT 0x00400000
-#define PSR_AA32_SSBS_BIT 0x00800000
-#define PSR_AA32_DIT_BIT 0x01000000
-#define PSR_AA32_Q_BIT 0x08000000
-#define PSR_AA32_V_BIT 0x10000000
-#define PSR_AA32_C_BIT 0x20000000
-#define PSR_AA32_Z_BIT 0x40000000
-#define PSR_AA32_N_BIT 0x80000000
-#define PSR_AA32_IT_MASK 0x0600fc00 /* If-Then execution state mask */
-#define PSR_AA32_GE_MASK 0x000f0000
-
#ifdef CONFIG_CPU_BIG_ENDIAN
#define PSR_AA32_ENDSTATE PSR_AA32_E_BIT
#else
#define PSR_AA32_ENDSTATE 0
#endif
-/* AArch32 CPSR bits, as seen in AArch32 */
-#define COMPAT_PSR_DIT_BIT 0x00200000
-
/*
* These are 'magic' values for PTRACE_PEEKUSR that return info about where a
* process is located in memory.
diff --git a/arch/arm64/include/uapi/asm/Kbuild b/arch/arm64/include/uapi/asm/Kbuild
index b45584e83448..43d1a8ab98e1 100644
--- a/arch/arm64/include/uapi/asm/Kbuild
+++ b/arch/arm64/include/uapi/asm/Kbuild
@@ -5,3 +5,4 @@ generic-y += kvm_para.h
shared-uapi-y += kvm.h
shared-uapi-y += sve_context.h
+shared-uapi-y += pstate.h
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index 6fed93fb2536..6e743eb021e8 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -24,54 +24,7 @@
#include <asm/hwcap.h>
#include <asm/sve_context.h>
-
-
-/*
- * PSR bits
- */
-#define PSR_MODE_EL0t 0x00000000
-#define PSR_MODE_EL1t 0x00000004
-#define PSR_MODE_EL1h 0x00000005
-#define PSR_MODE_EL2t 0x00000008
-#define PSR_MODE_EL2h 0x00000009
-#define PSR_MODE_EL3t 0x0000000c
-#define PSR_MODE_EL3h 0x0000000d
-#define PSR_MODE_MASK 0x0000000f
-
-/* AArch32 CPSR bits */
-#define PSR_MODE32_BIT 0x00000010
-
-/* AArch64 SPSR bits */
-#define PSR_F_BIT 0x00000040
-#define PSR_I_BIT 0x00000080
-#define PSR_A_BIT 0x00000100
-#define PSR_D_BIT 0x00000200
-#define PSR_BTYPE_MASK 0x00000c00
-#define PSR_SSBS_BIT 0x00001000
-#define PSR_PAN_BIT 0x00400000
-#define PSR_UAO_BIT 0x00800000
-#define PSR_DIT_BIT 0x01000000
-#define PSR_TCO_BIT 0x02000000
-#define PSR_V_BIT 0x10000000
-#define PSR_C_BIT 0x20000000
-#define PSR_Z_BIT 0x40000000
-#define PSR_N_BIT 0x80000000
-
-#define PSR_BTYPE_SHIFT 10
-
-/*
- * Groups of PSR bits
- */
-#define PSR_f 0xff000000 /* Flags */
-#define PSR_s 0x00ff0000 /* Status */
-#define PSR_x 0x0000ff00 /* Extension */
-#define PSR_c 0x000000ff /* Control */
-
-/* Convenience names for the values of PSTATE.BTYPE */
-#define PSR_BTYPE_NONE (0b00 << PSR_BTYPE_SHIFT)
-#define PSR_BTYPE_JC (0b01 << PSR_BTYPE_SHIFT)
-#define PSR_BTYPE_C (0b10 << PSR_BTYPE_SHIFT)
-#define PSR_BTYPE_J (0b11 << PSR_BTYPE_SHIFT)
+#include <asm/pstate.h>
/* syscall emulation path in ptrace */
#define PTRACE_SYSEMU 31
diff --git a/include/arch/arm64/asm/pstate.h b/include/arch/arm64/asm/pstate.h
new file mode 100644
index 000000000000..3ff6073a0eaa
--- /dev/null
+++ b/include/arch/arm64/asm/pstate.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ASM_PSTATE_H
+#define __ASM_PSTATE_H
+
+#include <asm/sysreg-defs.h>
+#ifdef __arm64__
+#include <uapi/asm/pstate.h>
+#else
+#include <uapi/arch/arm64/asm/pstate.h>
+#endif // __arm64__
+
+/* Additional SPSR bits not exposed in the UABI */
+#define PSR_MODE_THREAD_BIT BIT(0)
+#define PSR_IL_BIT SPSR_IL
+
+/* SPSR_ELx bits for exceptions taken from AArch32 */
+#define PSR_AA32_MODE_MASK SPSR_MODE_MASK
+#define PSR_AA32_MODE_USR (SPSR_MODE_32BIT | SPSR32_MODE_USR)
+#define PSR_AA32_MODE_FIQ (SPSR_MODE_32BIT | SPSR32_MODE_FIQ)
+#define PSR_AA32_MODE_IRQ (SPSR_MODE_32BIT | SPSR32_MODE_IRQ)
+#define PSR_AA32_MODE_SVC (SPSR_MODE_32BIT | SPSR32_MODE_SVC)
+#define PSR_AA32_MODE_ABT (SPSR_MODE_32BIT | SPSR32_MODE_ABT)
+#define PSR_AA32_MODE_HYP (SPSR_MODE_32BIT | SPSR32_MODE_HYP)
+#define PSR_AA32_MODE_UND (SPSR_MODE_32BIT | SPSR32_MODE_UND)
+#define PSR_AA32_MODE_SYS (SPSR_MODE_32BIT | SPSR32_MODE_SYS)
+#define PSR_AA32_T_BIT SPSR32_T
+#define PSR_AA32_F_BIT SPSR_F
+#define PSR_AA32_I_BIT SPSR_I
+#define PSR_AA32_A_BIT SPSR_A
+#define PSR_AA32_E_BIT SPSR32_E
+#define PSR_AA32_PAN_BIT SPSR_PAN
+#define PSR_AA32_SSBS_BIT SPSR32_SSBS
+#define PSR_AA32_DIT_BIT SPSR_DIT
+#define PSR_AA32_Q_BIT SPSR32_Q
+#define PSR_AA32_V_BIT SPSR_V
+#define PSR_AA32_C_BIT SPSR_C
+#define PSR_AA32_Z_BIT SPSR_Z
+#define PSR_AA32_N_BIT SPSR_N
+#define PSR_AA32_IT_MASK SPSR32_IT_MASK /* If-Then execution state mask */
+#define PSR_AA32_GE_MASK SPSR32_GE_MASK
+
+/* AArch32 CPSR bits, as seen in AArch32 */
+#define COMPAT_PSR_DIT_BIT 0x00200000
+
+#endif /* __ASM_PSTATE_H */
diff --git a/include/arch/arm64/asm/sysreg-defs.h b/include/arch/arm64/asm/sysreg-defs.h
index d5196f293e19..4460fae38623 100644
--- a/include/arch/arm64/asm/sysreg-defs.h
+++ b/include/arch/arm64/asm/sysreg-defs.h
@@ -470,6 +470,48 @@
#define SYS_FPEXC32_EL2 sys_reg(3, 4, 5, 3, 0)
#define SYS_TFSR_EL2 sys_reg(3, 4, 5, 6, 0)
+#define SPSR_PPEND BIT(33)
+#define SPSR_N BIT(31)
+#define SPSR_Z BIT(30)
+#define SPSR_C BIT(29)
+#define SPSR_V BIT(28)
+#define SPSR32_Q BIT(27)
+#define SPSR32_IT_MASK (GENMASK(26, 25) | GENMASK(15, 10))
+#define SPSR64_TCO BIT(25)
+#define SPSR_DIT BIT(24)
+#define SPSR64_UAO BIT(23)
+#define SPSR32_SSBS BIT(23)
+#define SPSR_PAN BIT(22)
+#define SPSR_SS BIT(21)
+#define SPSR_IL BIT(20)
+#define SPSR32_GE_MASK GENMASK(19, 16)
+#define SPSR64_SSBS BIT(12)
+#define SPSR64_BTYPE_SHIFT 10
+#define SPSR64_BTYPE_MASK (UL(3) << SPSR64_BTYPE_SHIFT)
+#define SPSR64_D BIT(9)
+#define SPSR32_E BIT(9)
+#define SPSR_A BIT(8)
+#define SPSR_I BIT(7)
+#define SPSR_F BIT(6)
+#define SPSR32_T BIT(5)
+#define SPSR_MODE_MASK UL(0x1f)
+#define SPSR_MODE_32BIT BIT(4)
+#define SPSR64_MODE_EL0 UL(0x0)
+#define SPSR64_MODE_EL1t UL(0x4)
+#define SPSR64_MODE_EL1h UL(0x5)
+#define SPSR64_MODE_EL2t UL(0x8)
+#define SPSR64_MODE_EL2h UL(0x9)
+#define SPSR64_MODE_EL3t UL(0xc)
+#define SPSR64_MODE_EL3h UL(0xd)
+#define SPSR32_MODE_USR UL(0x0)
+#define SPSR32_MODE_FIQ UL(0x1)
+#define SPSR32_MODE_IRQ UL(0x2)
+#define SPSR32_MODE_SVC UL(0x3)
+#define SPSR32_MODE_ABT UL(0x7)
+#define SPSR32_MODE_HYP UL(0xa)
+#define SPSR32_MODE_UND UL(0xb)
+#define SPSR32_MODE_SYS UL(0xf)
+
#define SYS_FAR_EL2 sys_reg(3, 4, 6, 0, 0)
#define SYS_HPFAR_EL2 sys_reg(3, 4, 6, 0, 4)
diff --git a/include/uapi/arch/arm64/asm/pstate.h b/include/uapi/arch/arm64/asm/pstate.h
new file mode 100644
index 000000000000..87b2acec9ac2
--- /dev/null
+++ b/include/uapi/arch/arm64/asm/pstate.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef _UAPI__ASM_PSTATE_H
+#define _UAPI__ASM_PSTATE_H
+
+/*
+ * PSR bits
+ */
+#define PSR_MODE_EL0t 0x00000000
+#define PSR_MODE_EL1t 0x00000004
+#define PSR_MODE_EL1h 0x00000005
+#define PSR_MODE_EL2t 0x00000008
+#define PSR_MODE_EL2h 0x00000009
+#define PSR_MODE_EL3t 0x0000000c
+#define PSR_MODE_EL3h 0x0000000d
+#define PSR_MODE_MASK 0x0000000f
+
+/* AArch32 CPSR bits */
+#define PSR_MODE32_BIT 0x00000010
+
+/* AArch64 SPSR bits */
+#define PSR_F_BIT 0x00000040
+#define PSR_I_BIT 0x00000080
+#define PSR_A_BIT 0x00000100
+#define PSR_D_BIT 0x00000200
+#define PSR_BTYPE_MASK 0x00000c00
+#define PSR_SSBS_BIT 0x00001000
+#define PSR_PAN_BIT 0x00400000
+#define PSR_UAO_BIT 0x00800000
+#define PSR_DIT_BIT 0x01000000
+#define PSR_TCO_BIT 0x02000000
+#define PSR_V_BIT 0x10000000
+#define PSR_C_BIT 0x20000000
+#define PSR_Z_BIT 0x40000000
+#define PSR_N_BIT 0x80000000
+
+#define PSR_BTYPE_SHIFT 10
+
+/*
+ * Groups of PSR bits
+ */
+#define PSR_f 0xff000000 /* Flags */
+#define PSR_s 0x00ff0000 /* Status */
+#define PSR_x 0x0000ff00 /* Extension */
+#define PSR_c 0x000000ff /* Control */
+
+/* Convenience names for the values of PSTATE.BTYPE */
+#define PSR_BTYPE_NONE (0b00 << PSR_BTYPE_SHIFT)
+#define PSR_BTYPE_JC (0b01 << PSR_BTYPE_SHIFT)
+#define PSR_BTYPE_C (0b10 << PSR_BTYPE_SHIFT)
+#define PSR_BTYPE_J (0b11 << PSR_BTYPE_SHIFT)
+
+#endif /* _UAPI__ASM_PSTATE_H */
--
2.51.0
^ permalink raw reply related
* [PATCH v1 16/27] KVM: Make device name configurable
From: Steffen Eiden @ 2026-04-02 4:21 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
Allow KVM implementations to choose alternative device names. This is
especially useful for architectures providing multiple KVM
implementations simultaneously.
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>
---
include/linux/kvm_host.h | 4 +++-
virt/kvm/kvm_main.c | 21 ++++++++++++++-------
2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index ff2aff71e207..d5d9757e40ca 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1062,7 +1062,9 @@ static inline void kvm_irqfd_exit(void)
{
}
#endif
-int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module);
+int kvm_init(unsigned int vcpu_size, unsigned int vcpu_align, struct module *module);
+int kvm_init_with_dev(unsigned int vcpu_size, unsigned int vcpu_align,
+ struct module *module, const char *dev_name, int minor);
void kvm_exit(void);
bool file_is_kvm(struct file *file);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 642f9e9638cc..d05e2c1e6fb0 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -5547,9 +5547,7 @@ static struct file_operations kvm_chardev_ops = {
};
static struct miscdevice kvm_dev = {
- KVM_MINOR,
- "kvm",
- &kvm_chardev_ops,
+ .fops = &kvm_chardev_ops,
};
#ifdef CONFIG_KVM_GENERIC_HARDWARE_ENABLING
@@ -6321,13 +6319,13 @@ static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm)
kfree(env);
}
-static void kvm_init_debug(void)
+static void kvm_init_debug(const char *dev_name)
{
const struct file_operations *fops;
const struct kvm_stats_desc *pdesc;
int i;
- kvm_debugfs_dir = debugfs_create_dir("kvm", NULL);
+ kvm_debugfs_dir = debugfs_create_dir(dev_name, NULL);
for (i = 0; i < kvm_vm_stats_header.num_desc; ++i) {
pdesc = &kvm_vm_stats_desc[i];
@@ -6463,11 +6461,20 @@ void kvm_unregister_perf_callbacks(void)
}
#endif
-int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)
+int kvm_init(unsigned int vcpu_size, unsigned int vcpu_align, struct module *module)
+{
+ return kvm_init_with_dev(vcpu_size, vcpu_align, module, "kvm", KVM_MINOR);
+}
+
+int kvm_init_with_dev(unsigned int vcpu_size, unsigned int vcpu_align,
+ struct module *module, const char *dev_name, int minor)
{
int r;
int cpu;
+ kvm_dev.name = dev_name;
+ kvm_dev.minor = minor;
+
/* A kmem cache lets us meet the alignment requirements of fx_save. */
if (!vcpu_align)
vcpu_align = __alignof__(struct kvm_vcpu);
@@ -6505,7 +6512,7 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)
kvm_preempt_ops.sched_in = kvm_sched_in;
kvm_preempt_ops.sched_out = kvm_sched_out;
- kvm_init_debug();
+ kvm_init_debug(kvm_dev.name);
r = kvm_vfio_ops_init();
if (WARN_ON_ONCE(r))
--
2.51.0
^ permalink raw reply related
* [PATCH v1 01/27] VFIO: take reference to the KVM module
From: Steffen Eiden @ 2026-04-02 4:20 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
From: Paolo Bonzini <pbonzini@redhat.com>
VFIO is implicitly taking a reference to the KVM module between
vfio_device_get_kvm_safe and vfio_device_put_kvm, thanks to
symbol_get and symbol_put.
In preparation for removing symbol_get and symbol_put themselves
from VFIO, actually store a pointer to the KVM module and use
module_get()/module_put() to keep KVM alive.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
drivers/vfio/device_cdev.c | 2 +-
drivers/vfio/group.c | 5 +++--
drivers/vfio/vfio.h | 15 ++++++++++-----
drivers/vfio/vfio_main.c | 18 +++++++++++++-----
include/linux/vfio.h | 3 ++-
virt/kvm/vfio.c | 14 ++++++++------
6 files changed, 37 insertions(+), 20 deletions(-)
diff --git a/drivers/vfio/device_cdev.c b/drivers/vfio/device_cdev.c
index 8ceca24ac136..a67d7215c239 100644
--- a/drivers/vfio/device_cdev.c
+++ b/drivers/vfio/device_cdev.c
@@ -56,7 +56,7 @@ int vfio_device_fops_cdev_open(struct inode *inode, struct file *filep)
static void vfio_df_get_kvm_safe(struct vfio_device_file *df)
{
spin_lock(&df->kvm_ref_lock);
- vfio_device_get_kvm_safe(df->device, df->kvm);
+ vfio_device_get_kvm_safe(df->device, df->kvm, df->kvm_module);
spin_unlock(&df->kvm_ref_lock);
}
diff --git a/drivers/vfio/group.c b/drivers/vfio/group.c
index 4f15016d2a5f..7d28f45fefaa 100644
--- a/drivers/vfio/group.c
+++ b/drivers/vfio/group.c
@@ -158,7 +158,7 @@ static int vfio_group_ioctl_set_container(struct vfio_group *group,
static void vfio_device_group_get_kvm_safe(struct vfio_device *device)
{
spin_lock(&device->group->kvm_ref_lock);
- vfio_device_get_kvm_safe(device, device->group->kvm);
+ vfio_device_get_kvm_safe(device, device->group->kvm, device->group->kvm_module);
spin_unlock(&device->group->kvm_ref_lock);
}
@@ -858,10 +858,11 @@ bool vfio_group_enforced_coherent(struct vfio_group *group)
return ret;
}
-void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm)
+void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm, struct module *kvm_module)
{
spin_lock(&group->kvm_ref_lock);
group->kvm = kvm;
+ group->kvm_module = kvm_module;
spin_unlock(&group->kvm_ref_lock);
}
diff --git a/drivers/vfio/vfio.h b/drivers/vfio/vfio.h
index 50128da18bca..a0c38f89b30a 100644
--- a/drivers/vfio/vfio.h
+++ b/drivers/vfio/vfio.h
@@ -22,8 +22,9 @@ struct vfio_device_file {
u8 access_granted;
u32 devid; /* only valid when iommufd is valid */
- spinlock_t kvm_ref_lock; /* protect kvm field */
+ spinlock_t kvm_ref_lock; /* protect kvm and kvm_module fields */
struct kvm *kvm;
+ struct module *kvm_module;
struct iommufd_ctx *iommufd; /* protected by struct vfio_device_set::lock */
};
@@ -89,6 +90,7 @@ struct vfio_group {
enum vfio_group_type type;
struct mutex group_lock;
struct kvm *kvm;
+ struct module *kvm_module;
struct file *opened_file;
struct blocking_notifier_head notifier;
struct iommufd_ctx *iommufd;
@@ -108,7 +110,7 @@ void vfio_device_group_unuse_iommu(struct vfio_device *device);
void vfio_df_group_close(struct vfio_device_file *df);
struct vfio_group *vfio_group_from_file(struct file *file);
bool vfio_group_enforced_coherent(struct vfio_group *group);
-void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm);
+void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm, struct module *kvm_module);
bool vfio_device_has_container(struct vfio_device *device);
int __init vfio_group_init(void);
void vfio_group_cleanup(void);
@@ -171,7 +173,8 @@ static inline bool vfio_group_enforced_coherent(struct vfio_group *group)
return true;
}
-static inline void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm)
+static inline void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm,
+ struct module *kvm_module)
{
}
@@ -435,11 +438,13 @@ static inline void vfio_virqfd_exit(void)
#endif
#if IS_ENABLED(CONFIG_KVM)
-void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm);
+void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,
+ struct module *kvm_module);
void vfio_device_put_kvm(struct vfio_device *device);
#else
static inline void vfio_device_get_kvm_safe(struct vfio_device *device,
- struct kvm *kvm)
+ struct kvm *kvm,
+ struct module *kvm_module)
{
}
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 742477546b15..b1b753889a77 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -433,7 +433,8 @@ void vfio_unregister_group_dev(struct vfio_device *device)
EXPORT_SYMBOL_GPL(vfio_unregister_group_dev);
#if IS_ENABLED(CONFIG_KVM)
-void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm)
+void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,
+ struct module *kvm_module)
{
void (*pfn)(struct kvm *kvm);
bool (*fn)(struct kvm *kvm);
@@ -444,6 +445,9 @@ void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm)
if (!kvm)
return;
+ if (!try_module_get(kvm_module))
+ return;
+
pfn = symbol_get(kvm_put_kvm);
if (WARN_ON(!pfn))
return;
@@ -463,6 +467,7 @@ void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm)
device->put_kvm = pfn;
device->kvm = kvm;
+ device->kvm_module = kvm_module;
}
void vfio_device_put_kvm(struct vfio_device *device)
@@ -480,6 +485,8 @@ void vfio_device_put_kvm(struct vfio_device *device)
symbol_put(kvm_put_kvm);
clear:
+ module_put(device->kvm_module);
+ device->kvm_module = NULL;
device->kvm = NULL;
}
#endif
@@ -1483,7 +1490,7 @@ bool vfio_file_enforced_coherent(struct file *file)
}
EXPORT_SYMBOL_GPL(vfio_file_enforced_coherent);
-static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm)
+static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module)
{
struct vfio_device_file *df = file->private_data;
@@ -1494,6 +1501,7 @@ static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm)
*/
spin_lock(&df->kvm_ref_lock);
df->kvm = kvm;
+ df->kvm_module = kvm_module;
spin_unlock(&df->kvm_ref_lock);
}
@@ -1505,16 +1513,16 @@ static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm)
* When a VFIO device is first opened the KVM will be available in
* device->kvm if one was associated with the file.
*/
-void vfio_file_set_kvm(struct file *file, struct kvm *kvm)
+void vfio_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module)
{
struct vfio_group *group;
group = vfio_group_from_file(file);
if (group)
- vfio_group_set_kvm(group, kvm);
+ vfio_group_set_kvm(group, kvm, kvm_module);
if (vfio_device_from_file(file))
- vfio_device_file_set_kvm(file, kvm);
+ vfio_device_file_set_kvm(file, kvm, kvm_module);
}
EXPORT_SYMBOL_GPL(vfio_file_set_kvm);
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index e90859956514..69a8d527b0e8 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -53,6 +53,7 @@ struct vfio_device {
struct list_head dev_set_list;
unsigned int migration_flags;
struct kvm *kvm;
+ struct module *kvm_module;
/* Members below here are private, not for driver use */
unsigned int index;
@@ -339,7 +340,7 @@ static inline bool vfio_file_has_dev(struct file *file, struct vfio_device *devi
#endif
bool vfio_file_is_valid(struct file *file);
bool vfio_file_enforced_coherent(struct file *file);
-void vfio_file_set_kvm(struct file *file, struct kvm *kvm);
+void vfio_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module);
#define VFIO_PIN_PAGES_MAX_ENTRIES (PAGE_SIZE/sizeof(unsigned long))
diff --git a/virt/kvm/vfio.c b/virt/kvm/vfio.c
index 9f9acb66cc1e..8161229f4b86 100644
--- a/virt/kvm/vfio.c
+++ b/virt/kvm/vfio.c
@@ -35,15 +35,15 @@ struct kvm_vfio {
bool noncoherent;
};
-static void kvm_vfio_file_set_kvm(struct file *file, struct kvm *kvm)
+static void kvm_vfio_file_set_kvm(struct file *file, struct kvm *kvm, struct module *module)
{
- void (*fn)(struct file *file, struct kvm *kvm);
+ void (*fn)(struct file *file, struct kvm *kvm, struct module *kvm_module);
fn = symbol_get(vfio_file_set_kvm);
if (!fn)
return;
- fn(file, kvm);
+ fn(file, kvm, module);
symbol_put(vfio_file_set_kvm);
}
@@ -142,6 +142,7 @@ static void kvm_vfio_update_coherency(struct kvm_device *dev)
static int kvm_vfio_file_add(struct kvm_device *dev, unsigned int fd)
{
+ struct module *module;
struct kvm_vfio *kv = dev->private;
struct kvm_vfio_file *kvf;
struct file *filp;
@@ -157,6 +158,7 @@ static int kvm_vfio_file_add(struct kvm_device *dev, unsigned int fd)
goto out_fput;
}
+ module = filp->f_op->owner;
mutex_lock(&kv->lock);
list_for_each_entry(kvf, &kv->file_list, node) {
@@ -175,7 +177,7 @@ static int kvm_vfio_file_add(struct kvm_device *dev, unsigned int fd)
kvf->file = get_file(filp);
list_add_tail(&kvf->node, &kv->file_list);
- kvm_vfio_file_set_kvm(kvf->file, dev->kvm);
+ kvm_vfio_file_set_kvm(kvf->file, dev->kvm, module);
kvm_vfio_update_coherency(dev);
out_unlock:
@@ -207,7 +209,7 @@ static int kvm_vfio_file_del(struct kvm_device *dev, unsigned int fd)
#ifdef CONFIG_SPAPR_TCE_IOMMU
kvm_spapr_tce_release_vfio_group(dev->kvm, kvf);
#endif
- kvm_vfio_file_set_kvm(kvf->file, NULL);
+ kvm_vfio_file_set_kvm(kvf->file, NULL, NULL);
fput(kvf->file);
kfree(kvf);
ret = 0;
@@ -330,7 +332,7 @@ static void kvm_vfio_release(struct kvm_device *dev)
#ifdef CONFIG_SPAPR_TCE_IOMMU
kvm_spapr_tce_release_vfio_group(dev->kvm, kvf);
#endif
- kvm_vfio_file_set_kvm(kvf->file, NULL);
+ kvm_vfio_file_set_kvm(kvf->file, NULL, NULL);
fput(kvf->file);
list_del(&kvf->node);
kfree(kvf);
--
2.51.0
^ permalink raw reply related
* [PATCH v1 18/27] KVM: s390: Prepare kvm-s390 for a second kvm module
From: Steffen Eiden @ 2026-04-02 4:21 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
The second KVM module will have a different Kconfig set.
When both modules are compiled the Kconfig sets get merged and
the native s390 KVM needs to implement functionality required by
the respective config options. Ensure that s390-KVM will still compile.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/kvm/s390/s390.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/s390/kvm/s390/s390.c b/arch/s390/kvm/s390/s390.c
index 497abe3a83f4..8a99d6e9f7e7 100644
--- a/arch/s390/kvm/s390/s390.c
+++ b/arch/s390/kvm/s390/s390.c
@@ -5665,6 +5665,14 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
return gmap_unmap_gfn_range(kvm->arch.gmap, range->slot, range->start, range->end);
}
+#ifdef CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE
+/* Make s390 compile if arm64-on-s390 is selected */
+int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+#endif /* CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE */
+
static inline unsigned long nonhyp_mask(int i)
{
unsigned int nonhyp_fai = (sclp.hmfai << i * 2) >> 30;
--
2.51.0
^ permalink raw reply related
* [PATCH v1 13/27] KVM: arm64: Extract & share ipa size shift calculation
From: Steffen Eiden @ 2026-04-02 4:21 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
Extract the ipa shift calculation from kvm_init_ipa_range into its own
function kvm_vm_type_ipa_size_shift to be shared across architectures.
User space passes a type parameter to the VM creation ioctl, indicating
the physical size of the VM. Therefore extract the ipa shift calculation
from kvm_init_ipa_range into its own function kvm_vm_type_ipa_size_shift,
so all implementers of arm64 KVM can make use of it for VM creation.
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/mmu.c | 18 ++++++------------
include/kvm/arm64/kvm_host.h | 1 +
virt/kvm/arm64/arm.c | 21 +++++++++++++++++++++
3 files changed, 28 insertions(+), 12 deletions(-)
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index e19ff77b3cd5..9d71bb3627fc 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -874,27 +874,21 @@ static struct kvm_pgtable_mm_ops kvm_s2_mm_ops = {
static int kvm_init_ipa_range(struct kvm_s2_mmu *mmu, unsigned long type)
{
- u32 kvm_ipa_limit = get_kvm_ipa_limit();
u64 mmfr0, mmfr1;
u32 phys_shift;
+ int r;
if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
return -EINVAL;
phys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type);
if (is_protected_kvm_enabled()) {
- phys_shift = kvm_ipa_limit;
- } else if (phys_shift) {
- if (phys_shift > kvm_ipa_limit ||
- phys_shift < ARM64_MIN_PARANGE_BITS)
- return -EINVAL;
+ phys_shift = get_kvm_ipa_limit();
} else {
- phys_shift = KVM_PHYS_SHIFT;
- if (phys_shift > kvm_ipa_limit) {
- pr_warn_once("%s using unsupported default IPA limit, upgrade your VMM\n",
- current->comm);
- return -EINVAL;
- }
+ r = kvm_vm_type_ipa_size_shift(type);
+ if (r < 0)
+ return r;
+ phys_shift = r;
}
mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
diff --git a/include/kvm/arm64/kvm_host.h b/include/kvm/arm64/kvm_host.h
index 20b824ecf16e..8c39ec485730 100644
--- a/include/kvm/arm64/kvm_host.h
+++ b/include/kvm/arm64/kvm_host.h
@@ -33,6 +33,7 @@ int kvm_vcpu_init_check_features(struct kvm_vcpu *vcpu,
const struct kvm_vcpu_init *init);
bool kvm_vcpu_init_changed(struct kvm_vcpu *vcpu,
const struct kvm_vcpu_init *init);
+int kvm_vm_type_ipa_size_shift(unsigned long type);
/* MMIO helpers */
void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
diff --git a/virt/kvm/arm64/arm.c b/virt/kvm/arm64/arm.c
index b47adef65e5f..0bbfbe63e558 100644
--- a/virt/kvm/arm64/arm.c
+++ b/virt/kvm/arm64/arm.c
@@ -52,3 +52,24 @@ bool kvm_vcpu_init_changed(struct kvm_vcpu *vcpu,
return !bitmap_equal(vcpu->kvm->arch.vcpu_features, &features,
KVM_VCPU_MAX_FEATURES);
}
+
+int kvm_vm_type_ipa_size_shift(unsigned long type)
+{
+ int phys_shift;
+
+ phys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type);
+ if (phys_shift) {
+ if (phys_shift > get_kvm_ipa_limit() ||
+ phys_shift < ARM64_MIN_PARANGE_BITS)
+ return -EINVAL;
+ } else {
+ phys_shift = KVM_PHYS_SHIFT;
+ if (phys_shift > get_kvm_ipa_limit()) {
+ pr_warn_once("%s using unsupported default IPA limit, upgrade your VMM\n",
+ current->comm);
+ return -EINVAL;
+ }
+ }
+
+ return phys_shift;
+}
--
2.51.0
^ permalink raw reply related
* [PATCH v1 03/27] KVM, vfio: remove symbol_get(kvm_put_kvm) from vfio
From: Steffen Eiden @ 2026-04-02 4:20 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Right now, KVM and VFIO are using symbol_get to access each other's
symbols because of a circular reference between the modules, as well
as to avoid loading them unnecessarily.
The remaining use in VFIO is for kvm_put_kvm, which is not inline
because it needs to call kvm_destroy_vm. However, storing the
address of kvm_destroy_vm in the "struct kvm" is enough to remove
the dependency from VFIO.
This also makes it possible to direct kvm_put_kvm to different
implementations of kvm_destroy_vm.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
drivers/vfio/vfio_main.c | 29 +++++------------------------
include/linux/kvm_host.h | 1 -
include/linux/kvm_types.h | 9 +++++++++
include/linux/vfio.h | 1 -
virt/kvm/kvm_main.c | 9 ++-------
5 files changed, 16 insertions(+), 33 deletions(-)
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 42f515519d87..e9c6353c74d8 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -17,7 +17,7 @@
#include <linux/idr.h>
#include <linux/iommu.h>
#if IS_ENABLED(CONFIG_KVM)
-#include <linux/kvm_host.h>
+#include <linux/kvm_types.h>
#endif
#include <linux/list.h>
#include <linux/miscdevice.h>
@@ -436,9 +436,6 @@ EXPORT_SYMBOL_GPL(vfio_unregister_group_dev);
void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,
struct module *kvm_module)
{
- void (*pfn)(struct kvm *kvm);
- bool ret;
-
lockdep_assert_held(&device->dev_set->lock);
if (!kvm)
@@ -447,19 +444,10 @@ void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,
if (!try_module_get(kvm_module))
return;
- pfn = symbol_get(kvm_put_kvm);
- if (WARN_ON(!pfn))
- return;
-
- ret = kvm_get_kvm_safe(kvm);
- if (!ret) {
- symbol_put(kvm_put_kvm);
- return;
+ if (kvm_get_kvm_safe(kvm)) {
+ device->kvm = kvm;
+ device->kvm_module = kvm_module;
}
-
- device->put_kvm = pfn;
- device->kvm = kvm;
- device->kvm_module = kvm_module;
}
void vfio_device_put_kvm(struct vfio_device *device)
@@ -469,15 +457,8 @@ void vfio_device_put_kvm(struct vfio_device *device)
if (!device->kvm)
return;
- if (WARN_ON(!device->put_kvm))
- goto clear;
-
- device->put_kvm(device->kvm);
- device->put_kvm = NULL;
- symbol_put(kvm_put_kvm);
-
-clear:
module_put(device->kvm_module);
+ kvm_put_kvm(device->kvm);
device->kvm_module = NULL;
device->kvm = NULL;
}
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index dc18ee99bba4..13f903993ed0 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1065,7 +1065,6 @@ static inline void kvm_irqfd_exit(void)
int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module);
void kvm_exit(void);
-void kvm_put_kvm(struct kvm *kvm);
bool file_is_kvm(struct file *file);
void kvm_put_kvm_no_destroy(struct kvm *kvm);
diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
index add7cc2016e8..aadee536771a 100644
--- a/include/linux/kvm_types.h
+++ b/include/linux/kvm_types.h
@@ -144,6 +144,7 @@ struct kvm_vcpu_stat_generic {
struct kvm_refcount {
refcount_t users_count;
+ void (*destroy)(struct kvm *kvm);
};
static inline void kvm_get_kvm(struct kvm *kvm)
@@ -164,6 +165,14 @@ static inline bool kvm_get_kvm_safe(struct kvm *kvm)
return refcount_inc_not_zero(&rc->users_count);
}
+static inline void kvm_put_kvm(struct kvm *kvm)
+{
+ struct kvm_refcount *rc = (struct kvm_refcount *)kvm;
+
+ if (refcount_dec_and_test(&rc->users_count))
+ rc->destroy(kvm);
+}
+
#endif /* !__ASSEMBLER__ */
#endif /* __KVM_TYPES_H__ */
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index 69a8d527b0e8..5c69532d6127 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -65,7 +65,6 @@ struct vfio_device {
unsigned int open_count;
struct completion comp;
struct iommufd_access *iommufd_access;
- void (*put_kvm)(struct kvm *kvm);
struct inode *inode;
#if IS_ENABLED(CONFIG_IOMMUFD)
struct iommufd_device *iommufd_device;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index cb5e01f92503..642f9e9638cc 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -120,6 +120,7 @@ static struct dentry *kvm_debugfs_dir;
static const struct file_operations stat_fops_per_vm;
+static void kvm_destroy_vm(struct kvm *kvm);
static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
unsigned long arg);
#ifdef CONFIG_KVM_COMPAT
@@ -1154,6 +1155,7 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
goto out_err_no_irq_routing;
refcount_set(&kvm->rc.users_count, 1);
+ kvm->rc.destroy = kvm_destroy_vm;
for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
for (j = 0; j < 2; j++) {
@@ -1316,13 +1318,6 @@ static void kvm_destroy_vm(struct kvm *kvm)
mmdrop(mm);
}
-void kvm_put_kvm(struct kvm *kvm)
-{
- if (refcount_dec_and_test(&kvm->rc.users_count))
- kvm_destroy_vm(kvm);
-}
-EXPORT_SYMBOL_GPL(kvm_put_kvm);
-
/*
* Used to put a reference that was taken on behalf of an object associated
* with a user-visible file descriptor, e.g. a vcpu or device, if installation
--
2.51.0
^ permalink raw reply related
* [PATCH v1 00/27] KVM: s390: Introduce arm64 KVM
From: Steffen Eiden @ 2026-04-02 4:20 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
By introducing a novel virtualization acceleration for the ARM architecture on
s390 architecture, we aim to expand the platform's software ecosystem. This
initial patch series lays the groundwork by enabling KVM-accelerated ARM CPU
virtualization on s390. To achieve this, a common KVM layer between s390 and
arm64 is introduced (see below for more details). Design considerations of
arm64 on the s390 Architecture The s390 virtualization architecture is extended
with a set of new instructions dedicated to supporting ARM-based virtual
machines. The s390 KVM host acts as EL2 (hypervisor) for a EL1/EL0
(OS/application) arm64 guest. To achieve this, the new Start-Arm-Execution
(SAE) instruction enables accelerated execution of arm64 VMs. Additional new
s390 instructions are introduced to query available arm64 features, used to
populate the arm64 ID register contents, as well as, new s390 instructions to
save/restore various arm64 registers in the VM context.
Summary of changes to arm64 KVM
UAPI / KAPI changes
The arm64 KVM UAPI headers are relocated to include/uapi/arch/arm64/,
allowing non‑arm64 hosts (such as s390) to use the arm64 KVM userspace API.
Likewise, the arm64 KVM kernel‑internal headers are relocated to
include/kvm/arm64/, and several arm64 asm headers are relocated to
include/arch/arm64/asm for architecture‑independent consumption.
Refactoring of arm64 headers and shared arm64 KVM functionality
To avoid code duplication, sharing logic between arm64/kvm and s390/kvm/arm64
is maximized while refactoring noise was minimized. IOCTL (arch) entry points
are deliberately kept separate for arm64 and arm64 on s390. This ensures full
control over execution paths for each KVM implementation. The arm64 sysreg
definitions and pstate/SPSR constants are extracted from their native headers
into dedicated, shareable files (sysreg-defs.h, pstate.h). This enables
other architectures to access sysreg name‑to‑ID mappings and pstate definitions
without relying on arm64‑specific, non‑shareable headers.
A new virt/kvm/arm64/ source directory is introduced to hold shared Arm64 KVM
implementation code, including guest register handling, exit handling,
general‑register reset logic, and IPA size/shift
calculations. Several functions are also refactored to improve portability for
non‑arm64 KVM implementations.
Maintainership considerations
Introducing a shared arm64 KVM code base for both native arm64 and s390
implementations may have subtle implications for each architecture,
depending on the context and the contributor’s expertise. We therefore
recognize the importance of clear maintainership guidelines and
well-defined review processes to ensure the stability and correctness of
both implementations. We welcome community feedback on how best to
structure maintainership and the review workflow, and we are open to
suggestions for effective coordination between the arm64 and s390
maintainer teams.
UAPI design
The arm64 KVM UAPI headers are relocated from arch/arm64/include/uapi/
to the new include/uapi/arch/arm64/ directory, and generic KVM definitions are
split into include/uapi/linux/kvm-generic.h for use across all architectures.
To maintain ABI compatibility, type aliases are introduced; they resolve to
native arm64 types on arm64 and to equivalent inline struct definitions on
foreign hosts. The build system installs the headers in their original location
on arm64, while conditionally exporting them to the new location for s390.
KAPI design
The include/arch/arm64/asm/ directory is introduced to host arm64 asm headers
that are independent of the host CPU. On native arm64 systems, this path is
added with the highest precedence so that existing <asm/header.h> includes
continue to work without modification. Foreign architectures can opt in by
adding this path to their include search, enabling them to use these
architecture‑agnostic headers.
The KVM‑related headers are moved to include/kvm/arm64/, decoupling them from
the arm64 architecture directory. The design convention is that
architecture‑specific headers under <arch>/include/asm/ include from this
shared location, allowing non‑arm64 hosts to consume the arm64 KVM
infrastructure without duplicating code.
Series structure
KVM symbol cleanup:
Three preparatory patches clean up KVM module symbol exports, making it
possible to load two KVM modules side by side.
Arm64 header and code sharing:
Selected arm64 UAPI, asm, and KVM kernel headers are
refactored into architecture-agnostic include paths, and shared arm64 KVM code
is relocated accordingly. This enables non-arm64 hosts to use the arm64 KVM
infrastructure without duplication.
s390 & KVM reorganization:
The existing s390 KVM code is moved into a dedicated s390 subdirectory
to make room for a second KVM implementation alongside it. The KVM
core is extended to support a configurable device name (needed for two
KVM devices on one architecture) Arm64
KVM on s390:
The SAE (Start Arm Execution) instruction is introduced as the
s390 mechanism for running Arm64 guests, and a new kvm-arm64 module is
built up incrementally.
Upcoming patch series will introduce system-register handling, interrupt
support, hypercalls, and additional features such as PMU.
We appreciate your feedback and review.
The Linux on s390 team
Hendrik Brueckner (1):
s390/hwcaps: Report SAE support as hwcap
Nina Schoetterl-Glausch (3):
arm64: Extract sysreg definitions
arm64: Extract pstate definitions from ptrace
KVM: arm64: Share reset general register code
Paolo Bonzini (3):
VFIO: take reference to the KVM module
KVM, vfio: remove symbol_get(kvm_get_kvm_safe) from vfio
KVM, vfio: remove symbol_get(kvm_put_kvm) from vfio
Steffen Eiden (20):
arm64: Provide arm64 UAPI for other host architectures
arm64: Provide arm64 API for non-native architectures
KVM: arm64: Provide arm64 KVM API for non-native architectures
KVM: arm64: Share kvm_emulate definitions
KVM: arm64: Make some arm64 KVM code shareable
KVM: arm64: Access elements of vcpu_gp_regs individually
KVM: arm64: Extract & share ipa size shift calculation
KVM: s390: Move s390 kvm code into a subdirectory
KVM: S390: Refactor gmap
KVM: Make device name configurable
KVM: Remove KVM_MMIO as config option
KVM: s390: Prepare kvm-s390 for a second kvm module
s390: Introduce Start Arm Execution instruction
KVM: s390: arm64: Introduce host definitions
KVM: s390: Add basic arm64 kvm module
KVM: s390: arm64: Implement required functions
KVM: s390: arm64: Implement vm/vcpu create destroy.
KVM: s390: arm64: Implement vCPU IOCTLs
KVM: s390: arm64: Implement basic page fault handler
KVM: s390: arm64: Enable KVM_ARM64 config and Kbuild
MAINTAINERS | 5 +
arch/arm64/Makefile | 2 +
arch/arm64/include/asm/Kbuild | 2 +-
arch/arm64/include/asm/el2_setup.h | 2 +-
arch/arm64/include/asm/hardirq.h | 2 +-
arch/arm64/include/asm/kvm_emulate.h | 245 +--
arch/arm64/include/asm/kvm_host.h | 200 +-
arch/arm64/include/asm/kvm_mmu.h | 41 +-
arch/arm64/include/asm/ptrace.h | 34 +-
arch/arm64/include/asm/sysreg.h | 972 +---------
arch/arm64/include/uapi/asm/Kbuild | 4 +
arch/arm64/include/uapi/asm/ptrace.h | 49 +-
arch/arm64/kernel/head.S | 2 +-
arch/arm64/kernel/hyp-stub.S | 2 +-
arch/arm64/kernel/traps.c | 53 -
arch/arm64/kvm/Kconfig | 1 -
arch/arm64/kvm/Makefile | 5 +-
arch/arm64/kvm/arm.c | 54 +-
arch/arm64/kvm/debug.c | 2 +-
arch/arm64/kvm/guest.c | 294 +--
arch/arm64/kvm/handle_exit.c | 52 +-
arch/arm64/kvm/hyp/entry.S | 2 +-
arch/arm64/kvm/hyp/exception.c | 7 +-
arch/arm64/kvm/hyp/hyp-entry.S | 2 +-
arch/arm64/kvm/hyp/include/hyp/adjust_pc.h | 17 +-
arch/arm64/kvm/hyp/include/hyp/switch.h | 6 +-
arch/arm64/kvm/hyp/nvhe/host.S | 2 +-
arch/arm64/kvm/hyp/nvhe/hyp-init.S | 2 +-
arch/arm64/kvm/mmu.c | 20 +-
arch/arm64/kvm/nested.c | 2 +-
arch/arm64/kvm/reset.c | 34 +-
arch/arm64/kvm/sys_regs.c | 2 +-
arch/arm64/kvm/trace_arm.h | 25 -
arch/arm64/kvm/vgic/vgic-its.c | 2 +-
arch/arm64/kvm/vgic/vgic-mmio-v3.c | 2 +-
arch/arm64/kvm/vgic/vgic-v3-nested.c | 2 +-
arch/arm64/tools/Makefile | 14 +-
arch/arm64/tools/Makefile.sysreg | 12 +
arch/arm64/tools/gen-sysreg.awk | 6 +-
arch/loongarch/include/asm/kvm_host.h | 2 +
arch/loongarch/kvm/Kconfig | 1 -
arch/mips/include/asm/kvm_host.h | 2 +
arch/mips/kvm/Kconfig | 1 -
arch/powerpc/include/asm/kvm_host.h | 7 +
arch/powerpc/kvm/Kconfig | 4 -
arch/riscv/include/asm/kvm_host.h | 2 +
arch/riscv/kvm/Kconfig | 1 -
arch/s390/Kconfig | 2 +-
arch/s390/boot/ipl_parm.c | 2 +-
arch/s390/boot/uv.c | 2 +-
arch/s390/configs/defconfig | 3 +-
arch/s390/include/asm/asm-prototypes.h | 1 +
arch/s390/include/asm/elf.h | 2 +
arch/s390/include/asm/kvm.h | 6 +
arch/s390/include/asm/kvm_emulate.h | 135 ++
arch/s390/include/asm/kvm_host.h | 748 +-------
arch/s390/include/asm/kvm_host_arm64.h | 199 ++
arch/s390/include/asm/kvm_host_arm64_types.h | 128 ++
.../asm/{kvm_host.h => kvm_host_s390.h} | 19 +-
...kvm_host_types.h => kvm_host_s390_types.h} | 0
arch/s390/include/asm/kvm_mmu.h | 12 +
arch/s390/include/asm/kvm_nested.h | 13 +
arch/s390/include/asm/sae.h | 39 +
arch/s390/include/asm/sclp.h | 5 +-
arch/s390/include/asm/stacktrace.h | 5 +
arch/s390/kernel/asm-offsets.c | 3 +-
arch/s390/kernel/early.c | 2 +-
arch/s390/kernel/entry.S | 34 +-
arch/s390/kernel/perf_event.c | 2 +-
arch/s390/kernel/processor.c | 3 +
arch/s390/kvm/Kconfig | 36 +-
arch/s390/kvm/Makefile | 12 +-
arch/s390/kvm/arm64/Kconfig | 23 +
arch/s390/kvm/arm64/Makefile | 107 ++
arch/s390/kvm/arm64/arm.c | 704 +++++++
arch/s390/kvm/arm64/arm.h | 61 +
arch/s390/kvm/arm64/guest.c | 162 ++
arch/s390/kvm/arm64/guest.h | 15 +
arch/s390/kvm/arm64/handle_exit.c | 52 +
arch/s390/kvm/arm64/inject_fault.c | 15 +
arch/s390/kvm/arm64/mmu.c | 153 ++
arch/s390/kvm/arm64/reset.c | 42 +
arch/s390/kvm/arm64/reset.h | 11 +
arch/s390/kvm/gmap/Makefile | 5 +
arch/s390/kvm/{ => gmap}/dat.c | 0
arch/s390/kvm/{ => gmap}/dat.h | 6 +-
arch/s390/kvm/{ => gmap}/faultin.c | 11 +-
arch/s390/kvm/{ => gmap}/faultin.h | 6 +-
arch/s390/kvm/{ => gmap}/gmap.c | 13 +-
arch/s390/kvm/{ => gmap}/gmap.h | 17 +-
arch/s390/kvm/gmap/mmu.c | 154 ++
arch/s390/kvm/gmap/trace-gmap.h | 59 +
arch/s390/kvm/{ => s390}/Kconfig | 25 +-
arch/s390/kvm/{ => s390}/Makefile | 10 +-
arch/s390/kvm/{ => s390}/diag.c | 2 +-
arch/s390/kvm/{ => s390}/gaccess.c | 2 +-
arch/s390/kvm/{ => s390}/gaccess.h | 2 +-
arch/s390/kvm/{ => s390}/guestdbg.c | 2 +-
arch/s390/kvm/{ => s390}/intercept.c | 2 +-
arch/s390/kvm/{ => s390}/interrupt.c | 2 +-
arch/s390/kvm/{ => s390}/pci.c | 2 +-
arch/s390/kvm/{ => s390}/pci.h | 0
arch/s390/kvm/{ => s390}/priv.c | 2 +-
arch/s390/kvm/{ => s390}/pv.c | 2 +-
arch/s390/kvm/{kvm-s390.c => s390/s390.c} | 126 +-
arch/s390/kvm/{kvm-s390.h => s390/s390.h} | 18 +-
arch/s390/kvm/{ => s390}/sigp.c | 2 +-
arch/s390/kvm/{ => s390}/trace-s390.h | 0
arch/s390/kvm/{ => s390}/trace.h | 14 -
arch/s390/kvm/{ => s390}/vsie.c | 2 +-
arch/s390/tools/Makefile | 2 +
arch/s390/tools/opcodes.txt | 3 +
arch/x86/include/asm/kvm_host.h | 2 +
arch/x86/kvm/Kconfig | 1 -
arch/x86/kvm/mmu/tdp_mmu.c | 2 +-
arch/x86/kvm/vmx/nested.h | 4 +-
drivers/s390/char/sclp_early.c | 1 +
drivers/vfio/device_cdev.c | 2 +-
drivers/vfio/group.c | 5 +-
drivers/vfio/vfio.h | 15 +-
drivers/vfio/vfio_main.c | 49 +-
.../arch/arm64}/asm/brk-imm.h | 0
.../include => include/arch/arm64}/asm/esr.h | 56 +-
include/arch/arm64/asm/pstate.h | 46 +
.../arch/arm64/asm/sysreg-defs.h | 344 +---
include/kvm/arm64/guest.h | 13 +
include/kvm/arm64/handle_exit.h | 14 +
.../asm => include/kvm/arm64}/kvm_arm.h | 5 +-
include/kvm/arm64/kvm_emulate.h | 268 +++
include/kvm/arm64/kvm_host.h | 205 ++
include/kvm/arm64/kvm_mmu.h | 47 +
include/kvm/arm64/reset.h | 8 +
include/linux/kvm_host.h | 18 +-
include/linux/kvm_types.h | 33 +
include/linux/vfio.h | 4 +-
include/uapi/Kbuild | 6 +
.../uapi/arch/arm64}/asm/kvm.h | 24 +-
include/uapi/arch/arm64/asm/pstate.h | 53 +
.../uapi/arch/arm64}/asm/sve_context.h | 0
include/uapi/arch/arm64/linux/kvm.h | 8 +
include/uapi/linux/{kvm.h => kvm-generic.h} | 11 +-
include/uapi/linux/kvm.h | 1649 +----------------
scripts/Makefile.asm-headers | 14 +-
usr/include/Makefile | 1 +
virt/kvm/Kconfig | 3 -
virt/kvm/Makefile.kvm | 3 +-
virt/kvm/arm64/Makefile.kvm | 13 +
virt/kvm/arm64/arm.c | 75 +
virt/kvm/arm64/guest.c | 302 +++
virt/kvm/arm64/handle_exit.c | 54 +
{arch/arm64/kvm => virt/kvm/arm64}/mmio.c | 1 +
virt/kvm/arm64/reset.c | 42 +
virt/kvm/arm64/trace.h | 42 +
virt/kvm/coalesced_mmio.c | 3 +
virt/kvm/coalesced_mmio.h | 2 +-
virt/kvm/kvm_main.c | 62 +-
virt/kvm/vfio.c | 14 +-
157 files changed, 3855 insertions(+), 5120 deletions(-)
create mode 100644 arch/arm64/tools/Makefile.sysreg
create mode 100644 arch/s390/include/asm/kvm.h
create mode 100644 arch/s390/include/asm/kvm_emulate.h
create mode 100644 arch/s390/include/asm/kvm_host_arm64.h
create mode 100644 arch/s390/include/asm/kvm_host_arm64_types.h
copy arch/s390/include/asm/{kvm_host.h => kvm_host_s390.h} (98%)
rename arch/s390/include/asm/{kvm_host_types.h => kvm_host_s390_types.h} (100%)
create mode 100644 arch/s390/include/asm/kvm_mmu.h
create mode 100644 arch/s390/include/asm/kvm_nested.h
create mode 100644 arch/s390/include/asm/sae.h
create mode 100644 arch/s390/kvm/arm64/Kconfig
create mode 100644 arch/s390/kvm/arm64/Makefile
create mode 100644 arch/s390/kvm/arm64/arm.c
create mode 100644 arch/s390/kvm/arm64/arm.h
create mode 100644 arch/s390/kvm/arm64/guest.c
create mode 100644 arch/s390/kvm/arm64/guest.h
create mode 100644 arch/s390/kvm/arm64/handle_exit.c
create mode 100644 arch/s390/kvm/arm64/inject_fault.c
create mode 100644 arch/s390/kvm/arm64/mmu.c
create mode 100644 arch/s390/kvm/arm64/reset.c
create mode 100644 arch/s390/kvm/arm64/reset.h
create mode 100644 arch/s390/kvm/gmap/Makefile
rename arch/s390/kvm/{ => gmap}/dat.c (100%)
rename arch/s390/kvm/{ => gmap}/dat.h (99%)
rename arch/s390/kvm/{ => gmap}/faultin.c (96%)
rename arch/s390/kvm/{ => gmap}/faultin.h (96%)
rename arch/s390/kvm/{ => gmap}/gmap.c (99%)
rename arch/s390/kvm/{ => gmap}/gmap.h (93%)
create mode 100644 arch/s390/kvm/gmap/mmu.c
create mode 100644 arch/s390/kvm/gmap/trace-gmap.h
copy arch/s390/kvm/{ => s390}/Kconfig (62%)
copy arch/s390/kvm/{ => s390}/Makefile (53%)
rename arch/s390/kvm/{ => s390}/diag.c (99%)
rename arch/s390/kvm/{ => s390}/gaccess.c (99%)
rename arch/s390/kvm/{ => s390}/gaccess.h (99%)
rename arch/s390/kvm/{ => s390}/guestdbg.c (99%)
rename arch/s390/kvm/{ => s390}/intercept.c (99%)
rename arch/s390/kvm/{ => s390}/interrupt.c (99%)
rename arch/s390/kvm/{ => s390}/pci.c (99%)
rename arch/s390/kvm/{ => s390}/pci.h (100%)
rename arch/s390/kvm/{ => s390}/priv.c (99%)
rename arch/s390/kvm/{ => s390}/pv.c (99%)
rename arch/s390/kvm/{kvm-s390.c => s390/s390.c} (98%)
rename arch/s390/kvm/{kvm-s390.h => s390/s390.h} (97%)
rename arch/s390/kvm/{ => s390}/sigp.c (99%)
rename arch/s390/kvm/{ => s390}/trace-s390.h (100%)
rename arch/s390/kvm/{ => s390}/trace.h (97%)
rename arch/s390/kvm/{ => s390}/vsie.c (99%)
rename {arch/arm64/include => include/arch/arm64}/asm/brk-imm.h (100%)
rename {arch/arm64/include => include/arch/arm64}/asm/esr.h (88%)
create mode 100644 include/arch/arm64/asm/pstate.h
copy arch/arm64/include/asm/sysreg.h => include/arch/arm64/asm/sysreg-defs.h (80%)
create mode 100644 include/kvm/arm64/guest.h
create mode 100644 include/kvm/arm64/handle_exit.h
rename {arch/arm64/include/asm => include/kvm/arm64}/kvm_arm.h (99%)
create mode 100644 include/kvm/arm64/kvm_emulate.h
create mode 100644 include/kvm/arm64/kvm_host.h
create mode 100644 include/kvm/arm64/kvm_mmu.h
create mode 100644 include/kvm/arm64/reset.h
rename {arch/arm64/include/uapi => include/uapi/arch/arm64}/asm/kvm.h (97%)
create mode 100644 include/uapi/arch/arm64/asm/pstate.h
rename {arch/arm64/include/uapi => include/uapi/arch/arm64}/asm/sve_context.h (100%)
create mode 100644 include/uapi/arch/arm64/linux/kvm.h
copy include/uapi/linux/{kvm.h => kvm-generic.h} (99%)
create mode 100644 virt/kvm/arm64/Makefile.kvm
create mode 100644 virt/kvm/arm64/arm.c
create mode 100644 virt/kvm/arm64/guest.c
create mode 100644 virt/kvm/arm64/handle_exit.c
rename {arch/arm64/kvm => virt/kvm/arm64}/mmio.c (99%)
create mode 100644 virt/kvm/arm64/reset.c
create mode 100644 virt/kvm/arm64/trace.h
base-commit: 46b513250491a7bfc97d98791dbe6a10bcc8129d
--
2.51.0
^ permalink raw reply
* [PATCH v1 02/27] KVM, vfio: remove symbol_get(kvm_get_kvm_safe) from vfio
From: Steffen Eiden @ 2026-04-02 4:20 UTC (permalink / raw)
To: kvm, kvmarm, linux-arm-kernel, linux-kernel, linux-s390
Cc: Andreas Grapentin, Arnd Bergmann, Catalin Marinas,
Christian Borntraeger, Claudio Imbrenda, David Hildenbrand,
Gautam Gala, Hendrik Brueckner, Janosch Frank, Joey Gouly,
Marc Zyngier, Nina Schoetterl-Glausch, Oliver Upton,
Paolo Bonzini, Suzuki K Poulose, Ulrich Weigand, Will Deacon,
Zenghui Yu
In-Reply-To: <20260402042125.3948963-1-seiden@linux.ibm.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Right now, KVM and VFIO are using symbol_get to access each other's
symbols because of a circular reference between the modules, as well
as to avoid loading them unnecessarily.
However, usage of symbol_get is mostly deprecated and there are just a
handful of users left. In the case of VFIO, in particular, the
functions it calls can be made inline. Start with kvm_get_kvm_safe, for
which it is trivial to do so.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/x86/kvm/mmu/tdp_mmu.c | 2 +-
arch/x86/kvm/vmx/nested.h | 4 ++--
drivers/vfio/vfio_main.c | 10 +---------
include/linux/kvm_host.h | 9 +++++----
include/linux/kvm_types.h | 24 ++++++++++++++++++++++++
virt/kvm/kvm_main.c | 26 +++++---------------------
6 files changed, 38 insertions(+), 37 deletions(-)
diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
index 9c26038f6b77..a88686b5db24 100644
--- a/arch/x86/kvm/mmu/tdp_mmu.c
+++ b/arch/x86/kvm/mmu/tdp_mmu.c
@@ -1136,7 +1136,7 @@ void kvm_tdp_mmu_invalidate_roots(struct kvm *kvm,
* being destroyed in an error path of KVM_CREATE_VM.
*/
if (IS_ENABLED(CONFIG_PROVE_LOCKING) &&
- refcount_read(&kvm->users_count) && kvm->created_vcpus)
+ refcount_read(&kvm->rc.users_count) && kvm->created_vcpus)
lockdep_assert_held_write(&kvm->mmu_lock);
/*
diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h
index 213a448104af..2c83fc905698 100644
--- a/arch/x86/kvm/vmx/nested.h
+++ b/arch/x86/kvm/vmx/nested.h
@@ -58,7 +58,7 @@ bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port,
static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
{
lockdep_assert_once(lockdep_is_held(&vcpu->mutex) ||
- !refcount_read(&vcpu->kvm->users_count));
+ !refcount_read(&vcpu->kvm->rc.users_count));
return to_vmx(vcpu)->nested.cached_vmcs12;
}
@@ -66,7 +66,7 @@ static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
static inline struct vmcs12 *get_shadow_vmcs12(struct kvm_vcpu *vcpu)
{
lockdep_assert_once(lockdep_is_held(&vcpu->mutex) ||
- !refcount_read(&vcpu->kvm->users_count));
+ !refcount_read(&vcpu->kvm->rc.users_count));
return to_vmx(vcpu)->nested.cached_shadow_vmcs12;
}
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index b1b753889a77..42f515519d87 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -437,7 +437,6 @@ void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,
struct module *kvm_module)
{
void (*pfn)(struct kvm *kvm);
- bool (*fn)(struct kvm *kvm);
bool ret;
lockdep_assert_held(&device->dev_set->lock);
@@ -452,14 +451,7 @@ void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,
if (WARN_ON(!pfn))
return;
- fn = symbol_get(kvm_get_kvm_safe);
- if (WARN_ON(!fn)) {
- symbol_put(kvm_put_kvm);
- return;
- }
-
- ret = fn(kvm);
- symbol_put(kvm_get_kvm_safe);
+ ret = kvm_get_kvm_safe(kvm);
if (!ret) {
symbol_put(kvm_put_kvm);
return;
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 6b76e7a6f4c2..dc18ee99bba4 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -767,6 +767,9 @@ struct kvm_memslots {
};
struct kvm {
+ /* Must be the first field, see function definitions in kvm_types.h. */
+ struct kvm_refcount rc;
+
#ifdef KVM_HAVE_MMU_RWLOCK
rwlock_t mmu_lock;
#else
@@ -830,7 +833,6 @@ struct kvm {
struct list_head ioeventfds;
struct kvm_vm_stat stat;
struct kvm_arch arch;
- refcount_t users_count;
#ifdef CONFIG_KVM_MMIO
struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
spinlock_t ring_lock;
@@ -876,6 +878,7 @@ struct kvm {
#endif
char stats_id[KVM_STATS_NAME_SIZE];
};
+static_assert(offsetof(struct kvm, rc) == 0);
#define kvm_err(fmt, ...) \
pr_err("kvm [%i]: " fmt, task_pid_nr(current), ## __VA_ARGS__)
@@ -1062,8 +1065,6 @@ static inline void kvm_irqfd_exit(void)
int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module);
void kvm_exit(void);
-void kvm_get_kvm(struct kvm *kvm);
-bool kvm_get_kvm_safe(struct kvm *kvm);
void kvm_put_kvm(struct kvm *kvm);
bool file_is_kvm(struct file *file);
void kvm_put_kvm_no_destroy(struct kvm *kvm);
@@ -1073,7 +1074,7 @@ static inline struct kvm_memslots *__kvm_memslots(struct kvm *kvm, int as_id)
as_id = array_index_nospec(as_id, KVM_MAX_NR_ADDRESS_SPACES);
return srcu_dereference_check(kvm->memslots[as_id], &kvm->srcu,
lockdep_is_held(&kvm->slots_lock) ||
- !refcount_read(&kvm->users_count));
+ !refcount_read(&kvm->rc.users_count));
}
static inline struct kvm_memslots *kvm_memslots(struct kvm *kvm)
diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
index a568d8e6f4e8..add7cc2016e8 100644
--- a/include/linux/kvm_types.h
+++ b/include/linux/kvm_types.h
@@ -33,6 +33,7 @@
#include <linux/mutex.h>
#include <linux/spinlock_types.h>
+#include <linux/refcount.h>
struct kvm;
struct kvm_async_pf;
@@ -140,6 +141,29 @@ struct kvm_vcpu_stat_generic {
};
#define KVM_STATS_NAME_SIZE 48
+
+struct kvm_refcount {
+ refcount_t users_count;
+};
+
+static inline void kvm_get_kvm(struct kvm *kvm)
+{
+ struct kvm_refcount *rc = (struct kvm_refcount *)kvm;
+
+ refcount_inc(&rc->users_count);
+}
+
+/*
+ * A safe version of kvm_get_kvm(), making sure the vm is not being destroyed.
+ * Return true if kvm referenced successfully, false otherwise.
+ */
+static inline bool kvm_get_kvm_safe(struct kvm *kvm)
+{
+ struct kvm_refcount *rc = (struct kvm_refcount *)kvm;
+
+ return refcount_inc_not_zero(&rc->users_count);
+}
+
#endif /* !__ASSEMBLER__ */
#endif /* __KVM_TYPES_H__ */
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 9093251beb39..cb5e01f92503 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1099,7 +1099,7 @@ static inline struct kvm_io_bus *kvm_get_bus_for_destruction(struct kvm *kvm,
enum kvm_bus idx)
{
return rcu_dereference_protected(kvm->buses[idx],
- !refcount_read(&kvm->users_count));
+ !refcount_read(&kvm->rc.users_count));
}
static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
@@ -1153,7 +1153,7 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
if (r)
goto out_err_no_irq_routing;
- refcount_set(&kvm->users_count, 1);
+ refcount_set(&kvm->rc.users_count, 1);
for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
for (j = 0; j < 2; j++) {
@@ -1223,7 +1223,7 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
out_err_no_disable:
kvm_arch_destroy_vm(kvm);
out_err_no_arch_destroy_vm:
- WARN_ON_ONCE(!refcount_dec_and_test(&kvm->users_count));
+ WARN_ON_ONCE(!refcount_dec_and_test(&kvm->rc.users_count));
for (i = 0; i < KVM_NR_BUSES; i++)
kfree(kvm_get_bus_for_destruction(kvm, i));
kvm_free_irq_routing(kvm);
@@ -1316,25 +1316,9 @@ static void kvm_destroy_vm(struct kvm *kvm)
mmdrop(mm);
}
-void kvm_get_kvm(struct kvm *kvm)
-{
- refcount_inc(&kvm->users_count);
-}
-EXPORT_SYMBOL_GPL(kvm_get_kvm);
-
-/*
- * Make sure the vm is not during destruction, which is a safe version of
- * kvm_get_kvm(). Return true if kvm referenced successfully, false otherwise.
- */
-bool kvm_get_kvm_safe(struct kvm *kvm)
-{
- return refcount_inc_not_zero(&kvm->users_count);
-}
-EXPORT_SYMBOL_GPL(kvm_get_kvm_safe);
-
void kvm_put_kvm(struct kvm *kvm)
{
- if (refcount_dec_and_test(&kvm->users_count))
+ if (refcount_dec_and_test(&kvm->rc.users_count))
kvm_destroy_vm(kvm);
}
EXPORT_SYMBOL_GPL(kvm_put_kvm);
@@ -1348,7 +1332,7 @@ EXPORT_SYMBOL_GPL(kvm_put_kvm);
*/
void kvm_put_kvm_no_destroy(struct kvm *kvm)
{
- WARN_ON(refcount_dec_and_test(&kvm->users_count));
+ WARN_ON(refcount_dec_and_test(&kvm->rc.users_count));
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_put_kvm_no_destroy);
--
2.51.0
^ permalink raw reply related
* Re: [PATCH 00/11] Drivers: hv: Add ARM64 support in mshv_vtl
From: Naman Jain @ 2026-04-02 4:01 UTC (permalink / raw)
To: Michael Kelley, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Catalin Marinas, Will Deacon,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
x86@kernel.org, H . Peter Anvin, Arnd Bergmann, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Marc Zyngier, Timothy Hayes, Lorenzo Pieralisi, mrigendrachaubey,
ssengar@linux.microsoft.com, linux-hyperv@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org,
linux-riscv@lists.infradead.org
In-Reply-To: <SN6PR02MB4157E4E088F39106979BE4EDD450A@SN6PR02MB4157.namprd02.prod.outlook.com>
On 4/1/2026 10:24 PM, Michael Kelley wrote:
> From: Naman Jain <namjain@linux.microsoft.com> Sent: Tuesday, March 17, 2026 9:23 PM
>>
>> On 3/18/2026 3:33 AM, Michael Kelley wrote:
>>> From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, March 16, 2026 5:13 AM
>>>>
>>>> The series intends to add support for ARM64 to mshv_vtl driver.
>
> No need to be tentative. :-) Just write as:
>
> "The series adds support for ARM64 to the mshv_vtl driver."
>
>>>> For this, common Hyper-V code is refactored, necessary support is added,
>>>> mshv_vtl_main.c is refactored and then finally support is added in
>>>> Kconfig.
>>>>
>>>> Based on commit 1f318b96cc84 ("Linux 7.0-rc3")
>>>
>>> There's now an online LLM-based tool that is automatically reviewing
>>> kernel patches. For this patch set, the results are here:
>>>
>>> https://sashiko.dev/#/patchset/20260316121241.910764-1-namjain%40linux.microsoft.com
>>>
>>> It has flagged several things that are worth checking, but I haven't
>>> reviewed them to see if they are actually valid.
>>>
>>> FWIW, the announcement about sashiko.dev is here:
>>>
>>> https://lore.kernel.org/lkml/7ia4o6kmpj5s.fsf@castle.c.googlers.com/
>>>
>>> Michael
>>
>>
>> Thanks for sharing Michael,
>> I'll check it out and do the needful.
>>
>
> I've done a full review of this patch set and provided comments in the
> individual patches. Some of my comments reference the Sashiko AI
> comments, but there are still some Sashiko AI comments to consider
> that I haven't referenced.
>
> FWIW, the Sashiko AI comments are quite good -- it found some things
> here that I missed on my own, and in my earlier reviews of the original VTL
> code. :-(
>
> Michael
Thank you so much Michael for reviewing these. I was also trying to
address review comments from Sashiko, and noticed some of them were
false positives in the sense that these were existing issues and not
introduced by arm64 changes. I thought of keeping them separate from the
scope of this series for future.
I'll review your comments and address them.
Regards,
Naman
^ permalink raw reply
* Re: [RFC PATCH v2 1/5] iommu/arm-smmu-v3: Add basic debugfs framework
From: Qinxin Xia @ 2026-04-02 3:50 UTC (permalink / raw)
To: Nicolin Chen
Cc: robin.murphy, will, jpb, linux-arm-kernel, iommu, wangzhou1,
prime.zeng, fanghao11, jonathan.cameron, wuyifan50, linuxarm
In-Reply-To: <acpUoZ7wx9gdT5BG@nvidia.com>
On 2026/3/30 18:46:57, Nicolin Chen <nicolinc@nvidia.com> wrote:
> On Sat, Mar 28, 2026 at 06:17:02PM +0800, Qinxin Xia wrote:
>> Add basic debugfs framework for ARM SMMUv3 driver.This creates the
>
> Needs a space after "."
>
>> +static int smmu_debugfs_capabilities_show(struct seq_file *seq, void *unused)
>> +{
>> + struct arm_smmu_device *smmu = seq->private;
>> +
>> + if (!smmu) {
>> + seq_puts(seq, "SMMU not available\n");
>> + return 0;
>> + }
>> +
>> + seq_puts(seq, "SMMUv3 Capabilities:\n");
>> + seq_printf(seq, " Stage1 Translation: %s\n",
>> + smmu->features & ARM_SMMU_FEAT_TRANS_S1 ? "Yes" : "No");
>> + seq_printf(seq, " Stage2 Translation: %s\n",
>> + smmu->features & ARM_SMMU_FEAT_TRANS_S2 ? "Yes" : "No");
>> + seq_printf(seq, " Coherent Walk: %s\n",
>> + smmu->features & ARM_SMMU_FEAT_COHERENCY ? "Yes" : "No");
>> + seq_printf(seq, " ATS Support: %s\n",
>> + smmu->features & ARM_SMMU_FEAT_ATS ? "Yes" : "No");
>> + seq_printf(seq, " PRI Support: %s\n",
>> + smmu->features & ARM_SMMU_FEAT_PRI ? "Yes" : "No");
>> + seq_printf(seq, " Stream Table Size: %d\n", 1 << smmu->sid_bits);
>> + seq_printf(seq, " Command Queue Depth: %d\n",
>> + 1 << smmu->cmdq.q.llq.max_n_shift);
>> + seq_printf(seq, " Event Queue Depth: %d\n",
>> + 1 << smmu->evtq.q.llq.max_n_shift);
>
> Nit: should we do all sizes or all depths? Any good reason to mix
> them here?
>
Stream Table is a table, not a queue, so 'Size' is more appropriate;
queues use 'Depth'. But I can change to unify if preferred.
>> +/**
>> + * arm_smmu_debugfs_remove() - Clean up debugfs entries for an SMMU device
>> + * @smmu: SMMU device
>> + *
>> + * This function removes the debugfs directories created by setup.
>> + */
>> +void arm_smmu_debugfs_remove(struct arm_smmu_device *smmu)
>> +{
>> + struct arm_smmu_debugfs *debugfs;
>> +
>> + scoped_guard(mutex, &arm_smmu_debugfs_lock) {
>
> It could be just normal guard().
>
>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> index 4d00d796f078..cbb3fccc501b 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -4904,6 +4904,15 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
>> /* Check for RMRs and install bypass STEs if any */
>> arm_smmu_rmr_install_bypass_ste(smmu);
>>
>> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
>> + char name[32];
>
> This could be moved to the top, as iommu_device_sysfs_add() can use
> it, whether CONFIG_ARM_SMMU_V3_DEBUGFS=y or =n.
>
>> + snprintf(name, sizeof(name), "smmu3.%pa", &ioaddr);
>
> And this could be moved after ioaddr gets a copy from res->start.
>
>>
>> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
>> +struct arm_smmu_debugfs {
>> + struct dentry *smmu_dir;
>
> A personal preference: for new structures, maybe drop those tabs?
>
>> /* An SMMUv3 instance */
>> struct arm_smmu_device {
>> struct device *dev;
>> @@ -803,6 +813,11 @@ struct arm_smmu_device {
>>
>> struct rb_root streams;
>> struct mutex streams_mutex;
>> +
>> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
>> + /* DebugFS Info */
>
> Doesn't seem very useful. I'd drop it.
>
>> + struct arm_smmu_debugfs *debugfs;
>> +#endif
>
> Nicolin
>
--
Thanks,
Qinxin
^ permalink raw reply
* Re: [PATCH v2 02/10] dmaengine: imx-sdma: fix spba-bus handling for i.MX8M
From: Shengjiu Wang @ 2026-04-02 3:33 UTC (permalink / raw)
To: Marco Felsch
Cc: Vinod Koul, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Jiada Wang, dmaengine, imx, linux-arm-kernel,
linux-kernel
In-Reply-To: <20250911-v6-16-topic-sdma-v2-2-d315f56343b5@pengutronix.de>
On Fri, Sep 12, 2025 at 6:05 AM Marco Felsch <m.felsch@pengutronix.de> wrote:
>
> Starting with i.MX8M* devices there are multiple spba-busses so we can't
> just search the whole DT for the first spba-bus match and take it.
> Instead we need to check for each device to which bus it belongs and
> setup the spba_{start,end}_addr accordingly per sdma_channel.
>
> While on it, don't ignore errors from of_address_to_resource() if they
> are valid.
>
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
> drivers/dma/imx-sdma.c | 58 ++++++++++++++++++++++++++++++++++----------------
> 1 file changed, 40 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
> index 3ecb917214b1268b148a29df697b780bc462afa4..56daaeb7df03986850c9c74273d0816700581dc0 100644
> --- a/drivers/dma/imx-sdma.c
> +++ b/drivers/dma/imx-sdma.c
> @@ -429,6 +429,8 @@ struct sdma_desc {
> * @event_mask: event mask used in p_2_p script
> * @watermark_level: value for gReg[7], some script will extend it from
> * basic watermark such as p_2_p
> + * @spba_start_addr: SDMA controller SPBA bus start address
> + * @spba_end_addr: SDMA controller SPBA bus end address
> * @shp_addr: value for gReg[6]
> * @per_addr: value for gReg[2]
> * @status: status of dma channel
> @@ -461,6 +463,8 @@ struct sdma_channel {
> dma_addr_t per_address, per_address2;
> unsigned long event_mask[2];
> unsigned long watermark_level;
> + u32 spba_start_addr;
> + u32 spba_end_addr;
> u32 shp_addr, per_addr;
> enum dma_status status;
> struct imx_dma_data data;
> @@ -534,8 +538,6 @@ struct sdma_engine {
> u32 script_number;
> struct sdma_script_start_addrs *script_addrs;
> const struct sdma_driver_data *drvdata;
> - u32 spba_start_addr;
> - u32 spba_end_addr;
> unsigned int irq;
> dma_addr_t bd0_phys;
> struct sdma_buffer_descriptor *bd0;
> @@ -1236,8 +1238,6 @@ static void sdma_channel_synchronize(struct dma_chan *chan)
>
> static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac)
> {
> - struct sdma_engine *sdma = sdmac->sdma;
> -
> int lwml = sdmac->watermark_level & SDMA_WATERMARK_LEVEL_LWML;
> int hwml = (sdmac->watermark_level & SDMA_WATERMARK_LEVEL_HWML) >> 16;
>
> @@ -1263,12 +1263,12 @@ static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac)
> swap(sdmac->event_mask[0], sdmac->event_mask[1]);
> }
>
> - if (sdmac->per_address2 >= sdma->spba_start_addr &&
> - sdmac->per_address2 <= sdma->spba_end_addr)
> + if (sdmac->per_address2 >= sdmac->spba_start_addr &&
> + sdmac->per_address2 <= sdmac->spba_end_addr)
> sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SP;
>
> - if (sdmac->per_address >= sdma->spba_start_addr &&
> - sdmac->per_address <= sdma->spba_end_addr)
> + if (sdmac->per_address >= sdmac->spba_start_addr &&
> + sdmac->per_address <= sdmac->spba_end_addr)
> sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_DP;
>
> sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_CONT;
> @@ -1447,6 +1447,31 @@ static void sdma_desc_free(struct virt_dma_desc *vd)
> kfree(desc);
> }
>
> +static int sdma_config_spba_slave(struct dma_chan *chan)
> +{
> + struct sdma_channel *sdmac = to_sdma_chan(chan);
> + struct device_node *spba_bus;
> + struct resource spba_res;
> + int ret;
> +
> + spba_bus = of_get_parent(chan->slave->of_node);
if the chan is requested by __dma_request_channel(), the chan->slave = NULL
Then there will be an issue here.
Best regards
Shengjiu Wang
> + /* Device doesn't belong to the spba-bus */
> + if (!of_device_is_compatible(spba_bus, "fsl,spba-bus"))
> + return 0;
> +
> + ret = of_address_to_resource(spba_bus, 0, &spba_res);
> + of_node_put(spba_bus);
> + if (ret) {
> + dev_err(sdmac->sdma->dev, "Failed to get spba-bus resources\n");
> + return -EINVAL;
> + }
> +
> + sdmac->spba_start_addr = spba_res.start;
> + sdmac->spba_end_addr = spba_res.end;
> +
> + return 0;
> +}
> +
> static int sdma_alloc_chan_resources(struct dma_chan *chan)
> {
> struct sdma_channel *sdmac = to_sdma_chan(chan);
> @@ -1527,6 +1552,8 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
>
> sdmac->event_id0 = 0;
> sdmac->event_id1 = 0;
> + sdmac->spba_start_addr = 0;
> + sdmac->spba_end_addr = 0;
>
> sdma_set_channel_priority(sdmac, 0);
>
> @@ -1837,6 +1864,7 @@ static int sdma_config(struct dma_chan *chan,
> {
> struct sdma_channel *sdmac = to_sdma_chan(chan);
> struct sdma_engine *sdma = sdmac->sdma;
> + int ret;
>
> memcpy(&sdmac->slave_config, dmaengine_cfg, sizeof(*dmaengine_cfg));
>
> @@ -1867,6 +1895,10 @@ static int sdma_config(struct dma_chan *chan,
> sdma_event_enable(sdmac, sdmac->event_id1);
> }
>
> + ret = sdma_config_spba_slave(chan);
> + if (ret)
> + return ret;
> +
> return 0;
> }
>
> @@ -2235,11 +2267,9 @@ static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec,
> static int sdma_probe(struct platform_device *pdev)
> {
> struct device_node *np = pdev->dev.of_node;
> - struct device_node *spba_bus;
> const char *fw_name;
> int ret;
> int irq;
> - struct resource spba_res;
> int i;
> struct sdma_engine *sdma;
> s32 *saddr_arr;
> @@ -2375,14 +2405,6 @@ static int sdma_probe(struct platform_device *pdev)
> dev_err(&pdev->dev, "failed to register controller\n");
> goto err_register;
> }
> -
> - spba_bus = of_find_compatible_node(NULL, NULL, "fsl,spba-bus");
> - ret = of_address_to_resource(spba_bus, 0, &spba_res);
> - if (!ret) {
> - sdma->spba_start_addr = spba_res.start;
> - sdma->spba_end_addr = spba_res.end;
> - }
> - of_node_put(spba_bus);
> }
>
> /*
>
> --
> 2.47.3
>
>
^ permalink raw reply
* Re: [RFC PATCH 1/7] media: v4l2-ctrls: Add V4L2_CID_MEMORY_USAGE control
From: Ming Qian(OSS) @ 2026-04-02 3:14 UTC (permalink / raw)
To: Nicolas Dufresne, Frank Li
Cc: linux-media, mchehab, hverkuil-cisco, sebastian.fricke, shawnguo,
s.hauer, kernel, festevam, linux-imx, xiahong.bao, eagle.zhou,
imx, linux-kernel, linux-arm-kernel
In-Reply-To: <d8c12ba1-5004-4a51-8a2b-3d500184778b@oss.nxp.com>
Hi Nicolas,
On 4/1/2026 10:23 AM, Ming Qian(OSS) wrote:
> Hi Nicolas,
>
> On 3/31/2026 10:54 PM, Nicolas Dufresne wrote:
>> Le mardi 31 mars 2026 à 10:33 -0400, Frank Li a écrit :
>>> On Tue, Mar 31, 2026 at 03:23:11PM +0800, ming.qian@oss.nxp.com wrote:
>>>> From: Ming Qian <ming.qian@oss.nxp.com>
>>>>
>>>> Add a new read-only control V4L2_CID_MEMORY_USAGE that allows
>>>> applications to query the total amount of memory currently used
>>>> by a device instance.
>>>>
>>>> This control reports the memory consumption in bytes, including
>>>> internal buffers, intermediate processing data, and other
>>>> driver-managed allocations. Applications can use this information
>>>> for debugging, resource monitoring, or making informed decisions
>>>> about buffer allocation strategies.
>>>>
>>>> Signed-off-by: Ming Qian <ming.qian@oss.nxp.com>
>>>> ---
>>>
>>> Not sure why not export these information by debugfs, or any benefit vs
>>> debugfs?
>>
>> There is also a on-going proposal that uses fdinfo.
>>
>> Nicolas
>>
>
> Thanks for the reminder about the ongoing fdinfo proposal.
>
> Just to confirm, you are referring to Detlev’s ongoing fdinfo proposal,
> specifically this series:
> https://lore.kernel.org/lkml/20260212162328.192217-1-
> detlev.casanova@collabora.com/
>
> I will align my work with it and switch to using fdinfo.
> Once the show_fdinfo support from that series is merged, I will prepare
> the next revision of my patch accordingly.
>
> Regards,
> Ming
>
Regarding the discussion about using fdinfo instead of a V4L2 control, I
have two questions:
1. Key consistency in fdinfo
fdinfo uses key–value pairs, which is flexible, but if multiple
drivers want to expose the same “memory usage” information,
they need to agree on a common key name and meaning. Otherwise
user‑space must handle each driver differently. A V4L2 control
naturally provides a unified interface without this coordination
effort.
2. Lack of notification in fdinfo
With a control, user‑space can subscribe to control events and
receive notifications when the memory usage changes. fdinfo does
not have a built‑in event mechanism, so users must either poll
or rely on additional eventfd‑like or custom event mechanisms.
Do you have any suggestions or existing practices to address these two
issues when using fdinfo?
Thanks again for your time and comments.
Regards,
Ming
>>>
>>> Generanlly document should be first patch, then driver change.
>>>
>>> Frank
>>>
>>>> drivers/media/v4l2-core/v4l2-ctrls-defs.c | 8 ++++++++
>>>> include/uapi/linux/v4l2-controls.h | 4 +++-
>>>> 2 files changed, 11 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/
>>>> media/v4l2-core/v4l2-ctrls-defs.c
>>>> index 551426c4cd01..053db78ff661 100644
>>>> --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c
>>>> +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
>>>> @@ -831,6 +831,7 @@ const char *v4l2_ctrl_get_name(u32 id)
>>>> case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component";
>>>> case V4L2_CID_COLORFX_CBCR: return "Color Effects, CbCr";
>>>> case V4L2_CID_COLORFX_RGB: return "Color Effects,
>>>> RGB";
>>>> + case V4L2_CID_MEMORY_USAGE: return "Memory Usage";
>>>>
>>>> /*
>>>> * Codec controls
>>>> @@ -1476,6 +1477,13 @@ void v4l2_ctrl_fill(u32 id, const char
>>>> **name, enum v4l2_ctrl_type *type,
>>>> *min = 0;
>>>> *max = 0xffff;
>>>> break;
>>>> + case V4L2_CID_MEMORY_USAGE:
>>>> + *type = V4L2_CTRL_TYPE_INTEGER64;
>>>> + *flags |= V4L2_CTRL_FLAG_READ_ONLY;
>>>> + *min = 0;
>>>> + *max = S64_MAX;
>>>> + *step = 1;
>>>> + break;
>>>> case V4L2_CID_FLASH_FAULT:
>>>> case V4L2_CID_JPEG_ACTIVE_MARKER:
>>>> case V4L2_CID_3A_LOCK:
>>>> diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/
>>>> linux/v4l2-controls.h
>>>> index 68dd0c4e47b2..02c6f960d38e 100644
>>>> --- a/include/uapi/linux/v4l2-controls.h
>>>> +++ b/include/uapi/linux/v4l2-controls.h
>>>> @@ -110,8 +110,10 @@ enum v4l2_colorfx {
>>>> #define V4L2_CID_COLORFX_CBCR (V4L2_CID_BASE+42)
>>>> #define V4L2_CID_COLORFX_RGB (V4L2_CID_BASE+43)
>>>>
>>>> +#define V4L2_CID_MEMORY_USAGE (V4L2_CID_BASE+44)
>>>> +
>>>> /* last CID + 1 */
>>>> -#define V4L2_CID_LASTP1 (V4L2_CID_BASE+44)
>>>> +#define V4L2_CID_LASTP1 (V4L2_CID_BASE+45)
>>>>
>>>> /* USER-class private control IDs */
>>>>
>>>> --
>>>> 2.53.0
>>>>
>
^ permalink raw reply
* Re: [PATCH v3 0/5] Support the FEAT_HDBSS introduced in Armv9.5
From: Tian Zheng @ 2026-04-02 2:40 UTC (permalink / raw)
To: Leonardo Bras
Cc: maz, oupton, catalin.marinas, corbet, pbonzini, will, yuzenghui,
wangzhou1, liuyonglong, Jonathan.Cameron, yezhenyu2, linuxarm,
joey.gouly, kvmarm, kvm, linux-arm-kernel, linux-doc,
linux-kernel, skhan, suzuki.poulose
In-Reply-To: <acvWnjG0AZBHL21q@devkitleo>
On 3/31/2026 10:13 PM, Leonardo Bras wrote:
> On Wed, Feb 25, 2026 at 12:04:16PM +0800, Tian Zheng wrote:
>> This series of patches add support to the Hardware Dirty state tracking
>> Structure(HDBSS) feature, which is introduced by the ARM architecture
>> in the DDI0601(ID121123) version.
>>
>> The HDBSS feature is an extension to the architecture that enhances
>> tracking translation table descriptors' dirty state, identified as
>> FEAT_HDBSS. This feature utilizes hardware assistance to achieve dirty
>> page tracking, aiming to significantly reduce the overhead of scanning
>> for dirty pages.
>>
>> The purpose of this feature is to make the execution overhead of live
>> migration lower to both the guest and the host, compared to existing
>> approaches (write-protect or search stage 2 tables).
>>
>> After these patches, users(such as qemu) can use the
>> KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl to enable or disable the HDBSS
>> feature before and after the live migration.
>>
>> v2:
>> https://lore.kernel.org/linux-arm-kernel/20251121092342.3393318-1-zhengtian10@huawei.com/
>>
>> v2->v3 changes:
>> - Remove the ARM64_HDBSS configuration option and ensure this feature
>> is only enabled in VHE mode.
>> - Move HDBSS-related variables to the arch-independent portion of the
>> kvm structure.
>> - Remove error messages during HDBSS enable/disable operations
>> - Change HDBSS buffer flushing from handle_exit to vcpu_put,
>> check_vcpu_requests, and kvm_handle_guest_abort.
>> - Add fault handling for HDBSS including buffer full, external abort,
>> and general protection fault (GPF).
>> - Add support for a 4KB HDBSS buffer size, mapped to the value 0b0000.
>> - Add a second argument to the ioctl to turn HDBSS on or off.
>>
>> Tian Zheng (1):
>> KVM: arm64: Document HDBSS ioctl
>>
>> eillon (4):
>> arm64/sysreg: Add HDBSS related register information
>> KVM: arm64: Add support to set the DBM attr during memory abort
>> KVM: arm64: Add support for FEAT_HDBSS
>> KVM: arm64: Enable HDBSS support and handle HDBSSF events
>>
>> Documentation/virt/kvm/api.rst | 16 +++++
>> arch/arm64/include/asm/cpufeature.h | 5 ++
>> arch/arm64/include/asm/esr.h | 7 ++
>> arch/arm64/include/asm/kvm_host.h | 17 +++++
>> arch/arm64/include/asm/kvm_mmu.h | 1 +
>> arch/arm64/include/asm/kvm_pgtable.h | 4 ++
>> arch/arm64/include/asm/sysreg.h | 11 +++
>> arch/arm64/kernel/cpufeature.c | 12 ++++
>> arch/arm64/kvm/arm.c | 102 +++++++++++++++++++++++++++
>> arch/arm64/kvm/hyp/pgtable.c | 6 ++
>> arch/arm64/kvm/hyp/vhe/switch.c | 19 +++++
>> arch/arm64/kvm/mmu.c | 70 ++++++++++++++++++
>> arch/arm64/kvm/reset.c | 3 +
>> arch/arm64/tools/cpucaps | 1 +
>> arch/arm64/tools/sysreg | 29 ++++++++
>> include/uapi/linux/kvm.h | 1 +
>> tools/include/uapi/linux/kvm.h | 1 +
>> 17 files changed, 305 insertions(+)
>>
>> --
>> 2.33.0
>>
>
> Hi Tian,
>
> I was thinking: maybe instead of putting the HDBSS (and HACDBS) stuff
> across a bunch of KVM files, we should try to focus them all on a single
> arch/arm64/kvm/dirty_bit.c file (plus a header such as
> arch/arm64/include/asm/kvm_dirty_bit.h).
>
> What is your opinion on that?
>
> Thanks!
> Leo
Sorry for the late reply. Yes, I had the same thought before. In the
next version, I will
move all the HDBSS-related content into the same file, such as
arch/arm64/kvm/dirty_bit.c
and arch/arm64/include/asm/kvm_dirty_bit.h.
Tian
>
>
^ permalink raw reply
* [PATCH v2 2/2] pwm: meson: Add support for Amlogic S7
From: Xianwei Zhao via B4 Relay @ 2026-04-02 2:40 UTC (permalink / raw)
To: Uwe Kleine-König, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Heiner Kallweit, Neil Armstrong, Kevin Hilman,
Jerome Brunet, Martin Blumenstingl
Cc: linux-pwm, devicetree, linux-kernel, linux-arm-kernel,
linux-amlogic, Xianwei Zhao
In-Reply-To: <20260402-s6-s7-pwm-v2-0-657dce040956@amlogic.com>
From: Xianwei Zhao <xianwei.zhao@amlogic.com>
Add support for Amlogic S7 PWM. Amlogic S7 different from the
previous SoCs, a controller includes one pwm, at the same time,
the controller has only one input clock source.
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
drivers/pwm/pwm-meson.c | 32 +++++++++++++++++++++++++++++---
1 file changed, 29 insertions(+), 3 deletions(-)
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
index 8c6bf3d49753..7a43c42ef3d6 100644
--- a/drivers/pwm/pwm-meson.c
+++ b/drivers/pwm/pwm-meson.c
@@ -113,6 +113,7 @@ struct meson_pwm_data {
int (*channels_init)(struct pwm_chip *chip);
bool has_constant;
bool has_polarity;
+ bool single_pwm;
};
struct meson_pwm {
@@ -503,6 +504,18 @@ static void meson_pwm_s4_put_clk(void *data)
clk_put(clk);
}
+static int meson_pwm_init_channels_s7(struct pwm_chip *chip)
+{
+ struct device *dev = pwmchip_parent(chip);
+ struct meson_pwm *meson = to_meson_pwm(chip);
+
+ meson->channels[0].clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(meson->channels[0].clk))
+ return dev_err_probe(dev, PTR_ERR(meson->channels[0].clk),
+ "Failed to get clk\n");
+ return 0;
+}
+
static int meson_pwm_init_channels_s4(struct pwm_chip *chip)
{
struct device *dev = pwmchip_parent(chip);
@@ -592,6 +605,13 @@ static const struct meson_pwm_data pwm_s4_data = {
.has_polarity = true,
};
+static const struct meson_pwm_data pwm_s7_data = {
+ .channels_init = meson_pwm_init_channels_s7,
+ .has_constant = true,
+ .has_polarity = true,
+ .single_pwm = true,
+};
+
static const struct of_device_id meson_pwm_matches[] = {
{
.compatible = "amlogic,meson8-pwm-v2",
@@ -642,6 +662,10 @@ static const struct of_device_id meson_pwm_matches[] = {
.compatible = "amlogic,meson-s4-pwm",
.data = &pwm_s4_data
},
+ {
+ .compatible = "amlogic,s7-pwm",
+ .data = &pwm_s7_data
+ },
{},
};
MODULE_DEVICE_TABLE(of, meson_pwm_matches);
@@ -650,9 +674,11 @@ static int meson_pwm_probe(struct platform_device *pdev)
{
struct pwm_chip *chip;
struct meson_pwm *meson;
- int err;
+ const struct meson_pwm_data *pdata = of_device_get_match_data(&pdev->dev);
+ int err, npwm;
- chip = devm_pwmchip_alloc(&pdev->dev, MESON_NUM_PWMS, sizeof(*meson));
+ npwm = pdata->single_pwm ? 1 : MESON_NUM_PWMS;
+ chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*meson));
if (IS_ERR(chip))
return PTR_ERR(chip);
meson = to_meson_pwm(chip);
@@ -664,7 +690,7 @@ static int meson_pwm_probe(struct platform_device *pdev)
spin_lock_init(&meson->lock);
chip->ops = &meson_pwm_ops;
- meson->data = of_device_get_match_data(&pdev->dev);
+ meson->data = pdata;
err = meson->data->channels_init(chip);
if (err < 0)
--
2.52.0
^ permalink raw reply related
* [PATCH v2 1/2] dt-bindings: pwm: amlogic: Add new bindings for S6 S7 S7D
From: Xianwei Zhao via B4 Relay @ 2026-04-02 2:40 UTC (permalink / raw)
To: Uwe Kleine-König, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Heiner Kallweit, Neil Armstrong, Kevin Hilman,
Jerome Brunet, Martin Blumenstingl
Cc: linux-pwm, devicetree, linux-kernel, linux-arm-kernel,
linux-amlogic, Xianwei Zhao, Junyi Zhao, Krzysztof Kozlowski
In-Reply-To: <20260402-s6-s7-pwm-v2-0-657dce040956@amlogic.com>
From: Junyi Zhao <junyi.zhao@amlogic.com>
Amlogic S7/S7D/S6 different from the previous SoCs, a controller
includes one pwm, at the same time, the controller has only one
input clock source.
Signed-off-by: Junyi Zhao <junyi.zhao@amlogic.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Reviewed-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
.../devicetree/bindings/pwm/pwm-amlogic.yaml | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml b/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml
index c337d85da40f..93fa97f4011b 100644
--- a/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml
+++ b/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml
@@ -37,6 +37,7 @@ properties:
- enum:
- amlogic,meson8-pwm-v2
- amlogic,meson-s4-pwm
+ - amlogic,s7-pwm
- items:
- enum:
- amlogic,a4-pwm
@@ -45,6 +46,11 @@ properties:
- amlogic,t7-pwm
- amlogic,meson-a1-pwm
- const: amlogic,meson-s4-pwm
+ - items:
+ - enum:
+ - amlogic,s6-pwm
+ - amlogic,s7d-pwm
+ - const: amlogic,s7-pwm
- items:
- enum:
- amlogic,meson8b-pwm-v2
@@ -146,6 +152,19 @@ allOf:
clock-names: false
required:
- clocks
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - amlogic,s7-pwm
+ then:
+ properties:
+ clocks:
+ maxItems: 1
+ clock-names: false
+ required:
+ - clocks
- if:
properties:
--
2.52.0
^ permalink raw reply related
* [PATCH v2 0/2] Add PWM support Amlogic S7 S7D S6
From: Xianwei Zhao via B4 Relay @ 2026-04-02 2:40 UTC (permalink / raw)
To: Uwe Kleine-König, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Heiner Kallweit, Neil Armstrong, Kevin Hilman,
Jerome Brunet, Martin Blumenstingl
Cc: linux-pwm, devicetree, linux-kernel, linux-arm-kernel,
linux-amlogic, Xianwei Zhao, Junyi Zhao, Krzysztof Kozlowski
Add bindings and driver support Amlogic S7/S7D/S6 SoCs.
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
Changes in v2:
- Simpler s7 clock desc, and drop the example in bindings.
- Make minor changes to probe based on Martin's suggestion.
- Link to v1: https://lore.kernel.org/r/20260326-s6-s7-pwm-v1-0-67e2f72b98bc@amlogic.com
---
Junyi Zhao (1):
dt-bindings: pwm: amlogic: Add new bindings for S6 S7 S7D
Xianwei Zhao (1):
pwm: meson: Add support for Amlogic S7
.../devicetree/bindings/pwm/pwm-amlogic.yaml | 19 +++++++++++++
drivers/pwm/pwm-meson.c | 32 ++++++++++++++++++++--
2 files changed, 48 insertions(+), 3 deletions(-)
---
base-commit: 8ab1fc9104158045f68fde2d0ae16f5fbcf8bfbd
change-id: 20260325-s6-s7-pwm-281658b88736
Best regards,
--
Xianwei Zhao <xianwei.zhao@amlogic.com>
^ permalink raw reply
* [PATCH v2 3/3] arm64: dts: exynos850: Add ap2apm mailbox
From: Alexey Klimov @ 2026-04-02 2:20 UTC (permalink / raw)
To: Krzysztof Kozlowski, Sylwester Nawrocki, Chanwoo Choi,
Alim Akhtar, Sam Protsenko, Michael Turquette, Stephen Boyd,
Rob Herring, Conor Dooley, Tudor Ambarus, Jassi Brar
Cc: Krzysztof Kozlowski, Peter Griffin, linux-samsung-soc,
linux-arm-kernel, linux-clk, devicetree, linux-kernel,
Alexey Klimov
In-Reply-To: <20260402-exynos850-ap2apm-mailbox-v2-0-ca5ffdff99d4@linaro.org>
Add mailbox node that describes AP-to-APM mailbox, that can be
used for communicating with APM co-processor on Exynos850 SoCs.
Signed-off-by: Alexey Klimov <alexey.klimov@linaro.org>
---
arch/arm64/boot/dts/exynos/exynos850.dtsi | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm64/boot/dts/exynos/exynos850.dtsi b/arch/arm64/boot/dts/exynos/exynos850.dtsi
index cb55015c8dce..fcb665ccc7ae 100644
--- a/arch/arm64/boot/dts/exynos/exynos850.dtsi
+++ b/arch/arm64/boot/dts/exynos/exynos850.dtsi
@@ -298,6 +298,15 @@ cmu_apm: clock-controller@11800000 {
clock-names = "oscclk", "dout_clkcmu_apm_bus";
};
+ ap2apm_mailbox: mailbox@11900000 {
+ compatible = "samsung,exynos850-mbox";
+ reg = <0x11900000 0x1000>;
+ clocks = <&cmu_apm CLK_GOUT_MAILBOX_APM_AP_PCLK>;
+ clock-names = "pclk";
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ #mbox-cells = <0>;
+ };
+
cmu_cmgp: clock-controller@11c00000 {
compatible = "samsung,exynos850-cmu-cmgp";
reg = <0x11c00000 0x8000>;
--
2.51.0
^ permalink raw reply related
* [PATCH v2 2/3] mailbox: exynos: Add support for Exynos850 mailbox
From: Alexey Klimov @ 2026-04-02 2:20 UTC (permalink / raw)
To: Krzysztof Kozlowski, Sylwester Nawrocki, Chanwoo Choi,
Alim Akhtar, Sam Protsenko, Michael Turquette, Stephen Boyd,
Rob Herring, Conor Dooley, Tudor Ambarus, Jassi Brar
Cc: Krzysztof Kozlowski, Peter Griffin, linux-samsung-soc,
linux-arm-kernel, linux-clk, devicetree, linux-kernel,
Alexey Klimov
In-Reply-To: <20260402-exynos850-ap2apm-mailbox-v2-0-ca5ffdff99d4@linaro.org>
Exynos850-based platforms support ACPM and has similar workflow
of communicating with ACPM via mailbox, however mailbox controller
registers are located at different offsets and writes/reads could be
different. To distinguish between such different behaviours,
the registers offsets for Exynos850 and the platform-specific data
structs are introduced and configuration is described in such structs
for gs101 and exynos850 based SoCs. Probe routine now selects the
corresponding platform-specific data via device_get_match_data().
Signed-off-by: Alexey Klimov <alexey.klimov@linaro.org>
---
drivers/mailbox/exynos-mailbox.c | 67 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 64 insertions(+), 3 deletions(-)
diff --git a/drivers/mailbox/exynos-mailbox.c b/drivers/mailbox/exynos-mailbox.c
index d2355b128ba4..f9c59c07558a 100644
--- a/drivers/mailbox/exynos-mailbox.c
+++ b/drivers/mailbox/exynos-mailbox.c
@@ -31,14 +31,61 @@
#define EXYNOS_MBOX_CHAN_COUNT HWEIGHT32(EXYNOS_MBOX_INTGR1_MASK)
+#define EXYNOS850_MBOX_MCUCTRL 0x0 /* Mailbox Control Register */
+#define EXYNOS850_MBOX_INTGR0 0x8 /* Interrupt Generation Register 0 */
+#define EXYNOS850_MBOX_INTCR0 0x0C /* Interrupt Clear Register 0 */
+#define EXYNOS850_MBOX_INTMR0 0x10 /* Interrupt Mask Register 0 */
+#define EXYNOS850_MBOX_INTSR0 0x14 /* Interrupt Status Register 0 */
+#define EXYNOS850_MBOX_INTMSR0 0x18 /* Interrupt Mask Status Register 0 */
+#define EXYNOS850_MBOX_INTGR1 0x1C /* Interrupt Generation Register 1 */
+#define EXYNOS850_MBOX_INTMR1 0x24 /* Interrupt Mask Register 1 */
+#define EXYNOS850_MBOX_INTSR1 0x28 /* Interrupt Status Register 1 */
+#define EXYNOS850_MBOX_INTMSR1 0x2C /* Interrupt Mask Status Register 1 */
+#define EXYNOS850_MBOX_VERSION 0x70
+
+#define EXYNOS850_MBOX_INTMR1_MASK GENMASK(15, 0)
+
+/**
+ * struct exynos_mbox_driver_data - platform-specific mailbox configuration.
+ * @irq_doorbell_offset: offset to the IRQ generation register, doorbell
+ * to APM co-processor.
+ * @irq_doorbell_shift: shift to apply to the value written to IRQ
+ * generation register.
+ * @irq_mask_offset: offset to the IRQ mask register.
+ * @irq_mask_value: value to right to the mask register to mask out
+ * all interrupts.
+ */
+struct exynos_mbox_driver_data {
+ u16 irq_doorbell_offset;
+ u16 irq_doorbell_shift;
+ u16 irq_mask_offset;
+ u16 irq_mask_value;
+};
+
/**
* struct exynos_mbox - driver's private data.
* @regs: mailbox registers base address.
* @mbox: pointer to the mailbox controller.
+ * @data: pointer to driver platform-specific data.
*/
struct exynos_mbox {
void __iomem *regs;
struct mbox_controller *mbox;
+ const struct exynos_mbox_driver_data *data;
+};
+
+static const struct exynos_mbox_driver_data exynos850_mbox_data = {
+ .irq_doorbell_offset = EXYNOS850_MBOX_INTGR0,
+ .irq_doorbell_shift = 16,
+ .irq_mask_offset = EXYNOS850_MBOX_INTMR1,
+ .irq_mask_value = EXYNOS850_MBOX_INTMR1_MASK,
+};
+
+static const struct exynos_mbox_driver_data exynos_gs101_mbox_data = {
+ .irq_doorbell_offset = EXYNOS_MBOX_INTGR1,
+ .irq_doorbell_shift = 0,
+ .irq_mask_offset = EXYNOS_MBOX_INTMR0,
+ .irq_mask_value = EXYNOS_MBOX_INTMR0_MASK,
};
static int exynos_mbox_send_data(struct mbox_chan *chan, void *data)
@@ -57,7 +104,8 @@ static int exynos_mbox_send_data(struct mbox_chan *chan, void *data)
return -EINVAL;
}
- writel(BIT(msg->chan_id), exynos_mbox->regs + EXYNOS_MBOX_INTGR1);
+ writel(BIT(msg->chan_id) << exynos_mbox->data->irq_doorbell_shift,
+ exynos_mbox->regs + exynos_mbox->data->irq_doorbell_offset);
return 0;
}
@@ -87,13 +135,21 @@ static struct mbox_chan *exynos_mbox_of_xlate(struct mbox_controller *mbox,
}
static const struct of_device_id exynos_mbox_match[] = {
- { .compatible = "google,gs101-mbox" },
+ {
+ .compatible = "google,gs101-mbox",
+ .data = &exynos_gs101_mbox_data
+ },
+ {
+ .compatible = "samsung,exynos850-mbox",
+ .data = &exynos850_mbox_data
+ },
{},
};
MODULE_DEVICE_TABLE(of, exynos_mbox_match);
static int exynos_mbox_probe(struct platform_device *pdev)
{
+ const struct exynos_mbox_driver_data *data;
struct device *dev = &pdev->dev;
struct exynos_mbox *exynos_mbox;
struct mbox_controller *mbox;
@@ -122,6 +178,11 @@ static int exynos_mbox_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(pclk),
"Failed to enable clock.\n");
+ data = device_get_match_data(&pdev->dev);
+ if (!data)
+ return -ENODEV;
+
+ exynos_mbox->data = data;
mbox->num_chans = EXYNOS_MBOX_CHAN_COUNT;
mbox->chans = chans;
mbox->dev = dev;
@@ -133,7 +194,7 @@ static int exynos_mbox_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, exynos_mbox);
/* Mask out all interrupts. We support just polling channels for now. */
- writel(EXYNOS_MBOX_INTMR0_MASK, exynos_mbox->regs + EXYNOS_MBOX_INTMR0);
+ writel(data->irq_mask_value, exynos_mbox->regs + data->irq_mask_offset);
return devm_mbox_controller_register(dev, mbox);
}
--
2.51.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox