* [PATCH v2 28/28] KVM: s390: arm64: Enable KVM_ARM64 config and Kbuild
From: Steffen Eiden @ 2026-04-28 15:56 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: <20260428155622.1361364-1-seiden@linux.ibm.com>
Add all Kbuild/Makefile configurations to build a second KVM module on
s390 implementing the arm64-KVM API. To prevent symbol conflicts with
kvm-s390 all internal symbols in kvm-arm64 are mangled if compiled as
built-in. The new module ins named kvm-arm64.
As in this case the build does not go through the normal build process
the module parameter handling would be messed up. By forcing
KBUILD_MODNAME to kvm-arm64 all parameters are at the same location and
not at object/basename of the object file the parameter is introduced.
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>
Co-developed-by: Gautam Gala <ggala@linux.ibm.com>
Signed-off-by: Gautam Gala <ggala@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/configs/defconfig | 1 +
arch/s390/include/asm/Kbuild | 3 +
arch/s390/kvm/Kconfig | 1 +
arch/s390/kvm/Makefile | 1 +
arch/s390/kvm/arm64/Kconfig | 21 +++++++
arch/s390/kvm/arm64/Makefile | 108 +++++++++++++++++++++++++++++++++++
arch/s390/kvm/s390/Kconfig | 1 -
arch/s390/tools/Makefile | 2 +
8 files changed, 137 insertions(+), 1 deletion(-)
create mode 100644 arch/s390/kvm/arm64/Kconfig
create mode 100644 arch/s390/kvm/arm64/Makefile
diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
index bbbb4d0df9dd..e10e9e1ad94d 100644
--- a/arch/s390/configs/defconfig
+++ b/arch/s390/configs/defconfig
@@ -58,6 +58,7 @@ CONFIG_CMM=m
CONFIG_APPLDATA_BASE=y
CONFIG_S390_HYPFS_FS=y
CONFIG_KVM_S390=m
+CONFIG_KVM_ARM64=m
CONFIG_S390_UNWIND_SELFTEST=m
CONFIG_S390_KPROBES_SANITY_TEST=m
CONFIG_S390_MODULES_SANITY_TEST=m
diff --git a/arch/s390/include/asm/Kbuild b/arch/s390/include/asm/Kbuild
index 80bad7de7a04..c2c238f418c6 100644
--- a/arch/s390/include/asm/Kbuild
+++ b/arch/s390/include/asm/Kbuild
@@ -7,3 +7,6 @@ generated-y += unistd_nr.h
generic-y += asm-offsets.h
generic-y += mcs_spinlock.h
generic-y += mmzone.h
+
+generated-y += sysreg-gen-defs.h
+generated-y += kvm_arm64_modname.h
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index f8d4a9a38dae..bbae58aa8bc4 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -20,5 +20,6 @@ config KVM
tristate
source "arch/s390/kvm/s390/Kconfig"
+source "arch/s390/kvm/arm64/Kconfig"
endif # VIRTUALIZATION
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile
index c43d7dffca13..38bdd7c9b42d 100644
--- a/arch/s390/kvm/Makefile
+++ b/arch/s390/kvm/Makefile
@@ -4,3 +4,4 @@
# Copyright IBM Corp. 2008
obj-$(CONFIG_KVM_S390) += s390/
+obj-$(CONFIG_KVM_ARM64) += arm64/
diff --git a/arch/s390/kvm/arm64/Kconfig b/arch/s390/kvm/arm64/Kconfig
new file mode 100644
index 000000000000..42a1be50f6e1
--- /dev/null
+++ b/arch/s390/kvm/arm64/Kconfig
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config KVM_ARM64
+ def_tristate y
+ prompt "Kernel-based Virtual Machine (KVM) support for arm64 guests"
+ select KVM
+ select KVM_VFIO
+ select IRQ_BYPASS_MANAGER
+ select SCHED_INFO
+ select XARRAY_MULTI
+ select KVM_COMMON
+ select HAVE_KVM_CPU_RELAX_INTERCEPT
+ select HAVE_KVM_MSI
+ select HAVE_KVM_IRQCHIP
+ select HAVE_KVM_IRQ_ROUTING
+ select HAVE_KVM_VCPU_RUN_PID_CHANGE
+ select GUEST_PERF_EVENTS if PERF_EVENTS
+ help
+ Support hosting virtualized arm64 guest machines on s390 host machines.
+
+ If unsure, say N.
diff --git a/arch/s390/kvm/arm64/Makefile b/arch/s390/kvm/arm64/Makefile
new file mode 100644
index 000000000000..d0aac34b8d2f
--- /dev/null
+++ b/arch/s390/kvm/arm64/Makefile
@@ -0,0 +1,108 @@
+# SPDX-License-Identifier: GPL-2.0
+
+KVM := ../../../../virt/kvm
+include $(srctree)/virt/kvm/Makefile.kvm
+include $(srctree)/virt/kvm/arm64/Makefile.kvm
+include $(srctree)/arch/s390/kvm/gmap/Makefile
+
+ccflags-y += -I $(src) -I$(srctree)/arch/s390/kvm/gmap -DKVM_S390_ARM64
+
+kvm-arm64-obj := \
+ arm.o \
+ guest.o \
+ handle_exit.o \
+ inject_fault.o \
+ mmu.o \
+ reset.o \
+
+kvm-arm64-obj += $(patsubst %.o,%-arm64.o,$(shared-arm64-obj))
+kvm-arm64-obj += $(patsubst %.o,%-arm64.o,$(kvm-y))
+
+targets += $(kvm-arm64-obj)
+
+$(obj)/%-arm64.o: $(src)/%.c FORCE
+ @mkdir -p $(dir $@)
+ $(call if_changed_rule,cc_o_c)
+
+ifeq ($(CONFIG_KVM_ARM64),m)
+
+kvm-arm64-y = $(kvm-arm64-obj)
+
+else ifeq ($(CONFIG_KVM_ARM64),y)
+
+KVM_ARM64_GEN_DIR :=$(objtree)/arch/${SRCARCH}/include/generated/asm
+KVM_ARM64_MODNAME_H := $(KVM_ARM64_GEN_DIR)/kvm_arm64_modname.h
+ccflags-y += -include $(KVM_ARM64_MODNAME_H)
+
+targets += $(KVM_ARM64_MODNAME_H)
+
+quiet_cmd_kvm_arm64_modname_h = GEN $@
+ cmd_kvm_arm64_modname_h = { \
+ echo '/* Automatically generated; do not edit. */'; \
+ echo '\#ifndef _KVM_ARM64_MODNAME_H'; \
+ echo '\#define _KVM_ARM64_MODNAME_H'; \
+ echo '\#undef KBUILD_MODNAME'; \
+ echo '\#define KBUILD_MODNAME "kvm_arm64"'; \
+ echo '\#endif /* _KVM_ARM64_MODNAME_H */'; \
+ } > $@
+
+$(addprefix $(obj)/,$(kvm-arm64-obj)): $(KVM_ARM64_MODNAME_H)
+
+$(KVM_ARM64_MODNAME_H):
+ @mkdir -p $(KVM_ARM64_GEN_DIR)
+ $(call cmd,kvm_arm64_modname_h)
+
+prereq-o-cmd = $(foreach o, $(filter %.o, $^), $(dir $(o)).$(notdir $(o)).cmd)
+cmd_gen_symversions_o = \
+ grep --no-filename "^\#SYMVER" $(prereq-o-cmd) >> $(dot-target).cmd || true
+
+define rule_ld_o_o
+ $(call cmd_and_savecmd,ld)
+ $(call cmd,gen_symversions_o)
+endef
+
+LDFLAGS_kvm-unnamespaced.o := -r
+$(obj)/kvm-unnamespaced.o: $(addprefix $(obj)/,$(kvm-arm64-obj)) FORCE
+ $(call if_changed_rule,ld_o_o)
+
+# Make list of symbols to localize.
+# Collect normal/exported symbols. Use dict as set for deduplication.
+quiet_cmd_nm_filter = NMFLTR $@
+ cmd_nm_filter = \
+$(NM) -jU $< | awk ' \
+{ if (match($$0, /^__export_symbol_(.*)$$/, exp_sym)) { \
+ exp_syms[exp_sym[1]] = 1; \
+ } else { \
+ normal_syms[$$0] = 1; \
+ } \
+} \
+END { \
+ for (sym in normal_syms) { \
+ if (!(sym in exp_syms)) { \
+ print sym; \
+ } \
+ } \
+}' > $@
+
+$(obj)/kvm_symbol_list: $(obj)/kvm-unnamespaced.o FORCE
+ $(call if_changed,nm_filter)
+
+define rule_oc_o_o
+ $(call cmd_and_savecmd,objcopy)
+ $(call cmd,gen_objtooldep)
+ $(call cmd,gen_symversions_o)
+endef
+
+OBJCOPYFLAGS_kvm-namespaced.o := -O default --localize-symbols=$(obj)/kvm_symbol_list
+$(obj)/kvm-namespaced.o: $(obj)/kvm-unnamespaced.o $(obj)/kvm_symbol_list FORCE
+ $(call if_changed_rule,oc_o_o)
+
+kvm-arm64-y = kvm-namespaced.o
+
+targets += kvm-unnamespaced.o kvm_symbol_list kvm-namespaced.o
+
+endif
+
+obj-$(CONFIG_KVM_ARM64) += kvm-arm64.o
+
+LINUXINCLUDE := -I$(srctree)/include/arch/arm64/ $(LINUXINCLUDE)
diff --git a/arch/s390/kvm/s390/Kconfig b/arch/s390/kvm/s390/Kconfig
index f9853e61fd58..263ff29b9c9c 100644
--- a/arch/s390/kvm/s390/Kconfig
+++ b/arch/s390/kvm/s390/Kconfig
@@ -2,7 +2,6 @@
#
# KVM_S390 configuration
#
-source "virt/kvm/Kconfig"
config KVM_S390
def_tristate y
diff --git a/arch/s390/tools/Makefile b/arch/s390/tools/Makefile
index f2862364fb42..921261dcde28 100644
--- a/arch/s390/tools/Makefile
+++ b/arch/s390/tools/Makefile
@@ -6,6 +6,8 @@
kapi := arch/$(ARCH)/include/generated/asm
kapi-hdrs-y := $(kapi)/facility-defs.h $(kapi)/dis-defs.h
+include $(srctree)/arch/arm64/tools/Makefile.sysreg
+
PHONY += kapi
kapi: $(kapi-hdrs-y)
--
2.51.0
^ permalink raw reply related
* [PATCH v2 25/28] KVM: s390: arm64: Implement vm/vcpu create destroy.
From: Steffen Eiden @ 2026-04-28 15:56 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: <20260428155622.1361364-1-seiden@linux.ibm.com>
Implement init and destroy IOCTLS for vcpu and vm.
Implement arch vm IOCTL. Use s390 gmap.
Co-developed-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
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/kvm/arm64/arm.c | 161 ++++++++++++++++++++++++++++++++++++++
arch/s390/kvm/arm64/arm.h | 54 +++++++++++++
2 files changed, 215 insertions(+)
diff --git a/arch/s390/kvm/arm64/arm.c b/arch/s390/kvm/arm64/arm.c
index 8f94eb8fe288..77bc4a8841df 100644
--- a/arch/s390/kvm/arm64/arm.c
+++ b/arch/s390/kvm/arm64/arm.c
@@ -8,7 +8,10 @@
#include <linux/kvm_types.h>
#include <linux/kvm_host.h>
+#include <gmap.h>
+
#include "arm.h"
+#include "reset.h"
int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
{
@@ -41,6 +44,61 @@ static u64 kvm_max_guest_address(void)
return ALIGN_DOWN(max_addr + 1, 1 << 30) - 1;
}
+static int kvm_gmap_init(struct kvm *kvm)
+{
+ struct crst_table *table;
+
+ kvm->arch.gmap = gmap_new(kvm, gpa_to_gfn(kvm->arch.guest_phys_size));
+
+ if (!kvm->arch.gmap)
+ return -ENOMEM;
+
+ /* arm64 (on s390) do not have pfault */
+ clear_bit(GMAP_FLAG_PFAULT_ENABLED, &kvm->arch.gmap->flags);
+ set_bit(GMAP_FLAG_ALLOW_HPAGE_1M, &kvm->arch.gmap->flags);
+
+ table = dereference_asce(kvm->arch.gmap->asce);
+ crst_table_init((void *)table, _CRSTE_HOLE(table->crstes[0].h.tt).val);
+
+ return 0;
+}
+
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
+{
+ char debug_name[32];
+ int ret;
+
+ if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
+ return -EINVAL;
+
+ ret = kvm_vm_type_ipa_size_shift(type);
+ if (ret < 0)
+ return ret;
+ kvm->arch.guest_phys_size = 1UL << ret;
+
+ mutex_init(&kvm->arch.config_lock);
+ bitmap_zero(kvm->arch.vcpu_features, KVM_VCPU_MAX_FEATURES);
+
+ snprintf(debug_name, sizeof(debug_name), "kvm-arm64-%u", current->pid);
+ kvm->arch.dbf = debug_register(debug_name, 32, 1, 7 * sizeof(long));
+ if (!kvm->arch.dbf)
+ return -ENOMEM;
+ debug_register_view(kvm->arch.dbf, &debug_sprintf_view);
+
+ ret = kvm_gmap_init(kvm);
+ if (ret)
+ goto out_err;
+ kvm->arch.mem_limit = kvm_max_guest_address();
+
+ VM_EVENT(kvm, 3, "vm created with type %lu", type);
+ return 0;
+
+out_err:
+ debug_unregister(kvm->arch.dbf);
+
+ return ret;
+}
+
vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
{
return VM_FAULT_SIGBUS;
@@ -52,6 +110,13 @@ long kvm_arch_dev_ioctl(struct file *filp,
return -EINVAL;
}
+void kvm_arch_destroy_vm(struct kvm *kvm)
+{
+ kvm_destroy_vcpus(kvm);
+ debug_unregister(kvm->arch.dbf);
+ kvm->arch.gmap = gmap_put(kvm->arch.gmap);
+}
+
u32 get_kvm_ipa_limit(void)
{
return fls64(kvm_max_guest_address() + 1) - 1;
@@ -62,10 +127,39 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
return 0;
}
+int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
+{
+ struct kvm_sae_block *sae_block = &vcpu->arch.sae_block;
+
+ spin_lock_init(&vcpu->arch.mp_state_lock);
+
+ /* Force users to call KVM_ARM_VCPU_INIT */
+ vcpu_clear_flag(vcpu, VCPU_INITIALIZED);
+
+ vcpu->arch.mc = kvm_s390_new_mmu_cache();
+ if (!vcpu->arch.mc)
+ return -ENOMEM;
+
+ sae_block->hbasce = vcpu->kvm->arch.gmap->asce.val;
+ sae_block->mso = 0L;
+ sae_block->msl = kvm_max_guest_address();
+
+ VM_EVENT(vcpu->kvm, 3, "create cpu %d at 0x%p, sae block at 0x%p, satellite at 0x%p",
+ vcpu->vcpu_id, vcpu, &vcpu->arch.sae_block, &vcpu->arch.save_area);
+ return 0;
+}
+
void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
{
}
+void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+ kvm_s390_free_mmu_cache(vcpu->arch.mc);
+
+ VCPU_EVENT(vcpu, 3, "%s", "free cpu");
+}
+
void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
{
}
@@ -103,6 +197,52 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
return 0;
}
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
+ struct kvm_dirty_log *log)
+{
+ return gmap_get_dirty_log(kvm, log);
+}
+
+bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
+{
+ scoped_guard(read_lock, &kvm->mmu_lock)
+ return gmap_age_gfn(kvm->arch.gmap, range->start, range->end);
+}
+
+void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
+{
+ gfn_t last_gfn = memslot->base_gfn + memslot->npages;
+
+ scoped_guard(read_lock, &kvm->mmu_lock)
+ gmap_sync_dirty_log(kvm->arch.gmap, memslot->base_gfn, last_gfn);
+}
+
+int kvm_arch_prepare_memory_region(struct kvm *kvm,
+ const struct kvm_memory_slot *old,
+ struct kvm_memory_slot *new,
+ enum kvm_mr_change change)
+{
+ return gmap_prepare_memory_region(kvm, old, new, change);
+}
+
+void kvm_arch_commit_memory_region(struct kvm *kvm,
+ struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new,
+ enum kvm_mr_change change)
+{
+ gmap_commit_memory_region(kvm, old, new, change);
+}
+
+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);
+}
+
+bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
+{
+ return gmap_test_age_gfn(kvm, range);
+}
+
void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
struct kvm_memory_slot *slot,
gfn_t gfn_offset,
@@ -110,6 +250,27 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
{
}
+int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+
+ switch (ioctl) {
+ case KVM_ARM_PREFERRED_TARGET: {
+ struct kvm_vcpu_init init = {
+ .target = KVM_ARM_TARGET_GENERIC_V8,
+ };
+
+ if (copy_to_user(argp, &init, sizeof(init)))
+ return -EFAULT;
+
+ return 0;
+ }
+
+ default:
+ return -EINVAL;
+ }
+}
+
bool kvm_arch_irqchip_in_kernel(struct kvm *kvm)
{
return false;
diff --git a/arch/s390/kvm/arm64/arm.h b/arch/s390/kvm/arm64/arm.h
index a3db254462c0..df6a9099a864 100644
--- a/arch/s390/kvm/arm64/arm.h
+++ b/arch/s390/kvm/arm64/arm.h
@@ -4,4 +4,58 @@
#define KVM_DEV_NAME "kvm-arm64"
+#define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\
+do { \
+ debug_sprintf_event((d_kvm)->arch.dbf, d_loglevel, KVM_DEV_NAME ": " d_string "\n", d_args); \
+} while (0)
+
+#define VCPU_EVENT(d_vcpu, d_loglevel, d_string, d_args...) \
+ do { \
+ debug_sprintf_event( \
+ (d_vcpu)->kvm->arch.dbf, d_loglevel, \
+ KVM_DEV_NAME " %02d[%016llx-%016llx]: " d_string "\n", \
+ (d_vcpu)->vcpu_id, (d_vcpu)->arch.sae_block.pstate, \
+ (d_vcpu)->arch.sae_block.pc, d_args); \
+ } while (0)
+
+static __always_inline bool kvm_s390_is_in_sie(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+
+static __always_inline int kvm_is_ucontrol(struct kvm *kvm)
+{
+ return 0;
+}
+
+static __always_inline int __kvm_s390_pv_destroy_page(struct page *page)
+{
+ return 0;
+}
+
+static __always_inline void kvm_s390_vsie_gmap_notifier(struct gmap *gmap, gpa_t start, gpa_t end)
+{
+}
+
+static __always_inline int kvm_s390_pv_get_handle(struct kvm *kvm)
+{
+ return 0;
+}
+
+static __always_inline int kvm_s390_is_migration_mode(struct kvm *kvm)
+{
+ return false;
+}
+
+static __always_inline bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+
+/* should never be called */
+static __always_inline int kvm_s390_vm_stop_migration(struct kvm *kvm)
+{
+ return -EINVAL;
+}
+
#endif /* ARCH_S390_KVM_ARM64_H */
--
2.51.0
^ permalink raw reply related
* [PATCH v2 17/28] KVM: Make device name configurable
From: Steffen Eiden @ 2026-04-28 15:56 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: <20260428155622.1361364-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 6a74dceb1f9a..44e6fe3d2d80 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1061,7 +1061,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 27a718a0bc01..60a5bb778993 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -5548,9 +5548,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
@@ -6322,13 +6320,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];
@@ -6464,11 +6462,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);
@@ -6506,7 +6513,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 v2 04/28] arm64: Provide arm64 UAPI for other host architectures
From: Steffen Eiden @ 2026-04-28 15:55 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: <20260428155622.1361364-1-seiden@linux.ibm.com>
Enable the ARM64 userspace API to be used on non-arm64 host
architectures, with initial support for s390.
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.
To achieve architecture independence, some type aliases are introduced,
which conditionally resolve to native arm64 types when building on arm64
or to fallback to ABI compatible inline struct definitions on other
architectures.
The build system is updated to install the moved UAPI headers to their
original location but in and conditionally export arm64 architecture
headers for s390. This infrastructure enables s390 systems to host arm64
virtual machines while maintaining full compatibility with the existing
arm64 KVM-UAPI, requiring only minimal, compatible changes to the arm64
UAPI-headers itself.
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>
---
MAINTAINERS | 2 +
arch/arm64/include/uapi/asm/Kbuild | 3 +
include/uapi/Kbuild | 6 +
.../uapi/arch/arm64}/asm/kvm.h | 24 +-
.../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 +----------------
| 14 +-
usr/include/Makefile | 1 +
10 files changed, 61 insertions(+), 1657 deletions(-)
rename {arch/arm64/include/uapi => include/uapi/arch/arm64}/asm/kvm.h (97%)
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%)
diff --git a/MAINTAINERS b/MAINTAINERS
index c3fe46d7c4bc..0752e340e569 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/uapi/arch/arm64/
F: drivers/virt/coco/arm-cca-guest/
F: drivers/virt/coco/pkvm-guest/
F: tools/testing/selftests/arm64/
@@ -14002,6 +14003,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/uapi/arch/arm64/asm/kvm*
F: arch/arm64/kvm/
F: include/kvm/arm_*
F: tools/testing/selftests/kvm/*/arm64/
diff --git a/arch/arm64/include/uapi/asm/Kbuild b/arch/arm64/include/uapi/asm/Kbuild
index c6d141d7b7d7..b45584e83448 100644
--- a/arch/arm64/include/uapi/asm/Kbuild
+++ b/arch/arm64/include/uapi/asm/Kbuild
@@ -2,3 +2,6 @@
syscall-y += unistd_64.h
generic-y += kvm_para.h
+
+shared-uapi-y += kvm.h
+shared-uapi-y += sve_context.h
diff --git a/include/uapi/Kbuild b/include/uapi/Kbuild
index 61ee6e59c930..497cc73308e7 100644
--- a/include/uapi/Kbuild
+++ b/include/uapi/Kbuild
@@ -4,11 +4,17 @@ no-export-headers += linux/a.out.h
endif
ifeq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/uapi/asm/kvm.h),)
+ifeq ($(wildcard $(srctree)/include/uapi/arch/$(SRCARCH)/asm/kvm.h),)
no-export-headers += linux/kvm.h
endif
+endif
ifeq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/uapi/asm/kvm_para.h),)
ifeq ($(wildcard $(objtree)/arch/$(SRCARCH)/include/generated/uapi/asm/kvm_para.h),)
no-export-headers += linux/kvm_para.h
endif
endif
+
+ifneq ($(ARCH),s390)
+no-export-headers += arch/%
+endif
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/include/uapi/arch/arm64/asm/kvm.h
similarity index 97%
rename from arch/arm64/include/uapi/asm/kvm.h
rename to include/uapi/arch/arm64/asm/kvm.h
index a792a599b9d6..469d90e3aa0d 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/include/uapi/arch/arm64/asm/kvm.h
@@ -34,8 +34,26 @@
#ifndef __ASSEMBLER__
#include <linux/psci.h>
#include <linux/types.h>
+#include "sve_context.h"
+
+#ifdef __aarch64__
#include <asm/ptrace.h>
-#include <asm/sve_context.h>
+typedef struct user_pt_regs user_pt_regs_arm64;
+typedef struct user_fpsimd_state user_fpsimd_state_arm64;
+#else
+typedef struct {
+ __u64 regs[31];
+ __u64 sp;
+ __u64 pc;
+ __u64 pstate;
+} user_pt_regs_arm64;
+typedef struct {
+ __uint128_t vregs[32];
+ __u32 fpsr;
+ __u32 fpcr;
+ __u32 __reserved[2];
+} __attribute__((aligned(16))) user_fpsimd_state_arm64;
+#endif /* __aarch64__ */
#define __KVM_HAVE_IRQ_LINE
#define __KVM_HAVE_VCPU_EVENTS
@@ -44,14 +62,14 @@
#define KVM_DIRTY_LOG_PAGE_OFFSET 64
struct kvm_regs {
- struct user_pt_regs regs; /* sp = sp_el0 */
+ user_pt_regs_arm64 regs; /* sp = sp_el0 */
__u64 sp_el1;
__u64 elr_el1;
__u64 spsr[KVM_NR_SPSR];
- struct user_fpsimd_state fp_regs;
+ user_fpsimd_state_arm64 fp_regs;
};
/*
diff --git a/arch/arm64/include/uapi/asm/sve_context.h b/include/uapi/arch/arm64/asm/sve_context.h
similarity index 100%
rename from arch/arm64/include/uapi/asm/sve_context.h
rename to include/uapi/arch/arm64/asm/sve_context.h
diff --git a/include/uapi/arch/arm64/linux/kvm.h b/include/uapi/arch/arm64/linux/kvm.h
new file mode 100644
index 000000000000..21528a146b4d
--- /dev/null
+++ b/include/uapi/arch/arm64/linux/kvm.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_KVM_H
+#define __LINUX_KVM_H
+
+#include <arch/arm64/asm/kvm.h>
+#include <linux/kvm-generic.h>
+
+#endif /*__LINUX_KVM_H */
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm-generic.h
similarity index 99%
copy from include/uapi/linux/kvm.h
copy to include/uapi/linux/kvm-generic.h
index 80364d4dbebb..78507dcaacb4 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm-generic.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef __LINUX_KVM_H
-#define __LINUX_KVM_H
+#ifndef __LINUX_GENERIC_KVM_H
+#define __LINUX_GENERIC_KVM_H
/*
* Userspace interface for /dev/kvm - kernel based virtual machine
@@ -8,11 +8,14 @@
* Note: you must update KVM_API_VERSION if you change this interface.
*/
+#ifndef __LINUX_KVM_H
+#error "Error: Do not directly include <linux/kvm-generic.h> include <linux/kvm.h>"
+#endif /* __LINUX_KVM_H */
+
#include <linux/const.h>
#include <linux/types.h>
#include <linux/compiler.h>
#include <linux/ioctl.h>
-#include <asm/kvm.h>
#ifdef __KERNEL__
#include <linux/kvm_types.h>
@@ -1658,4 +1661,4 @@ struct kvm_pre_fault_memory {
__u64 padding[5];
};
-#endif /* __LINUX_KVM_H */
+#endif /* __LINUX_KVM_GENERIC_H */
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 80364d4dbebb..d7362e7519b7 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -8,1654 +8,7 @@
* Note: you must update KVM_API_VERSION if you change this interface.
*/
-#include <linux/const.h>
-#include <linux/types.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
#include <asm/kvm.h>
-
-#ifdef __KERNEL__
-#include <linux/kvm_types.h>
-#endif
-
-#define KVM_API_VERSION 12
-
-/*
- * Backwards-compatible definitions.
- */
-#define __KVM_HAVE_GUEST_DEBUG
-
-/* for KVM_SET_USER_MEMORY_REGION */
-struct kvm_userspace_memory_region {
- __u32 slot;
- __u32 flags;
- __u64 guest_phys_addr;
- __u64 memory_size; /* bytes */
- __u64 userspace_addr; /* start of the userspace allocated memory */
-};
-
-/* for KVM_SET_USER_MEMORY_REGION2 */
-struct kvm_userspace_memory_region2 {
- __u32 slot;
- __u32 flags;
- __u64 guest_phys_addr;
- __u64 memory_size;
- __u64 userspace_addr;
- __u64 guest_memfd_offset;
- __u32 guest_memfd;
- __u32 pad1;
- __u64 pad2[14];
-};
-
-/*
- * The bit 0 ~ bit 15 of kvm_userspace_memory_region::flags are visible for
- * userspace, other bits are reserved for kvm internal use which are defined
- * in include/linux/kvm_host.h.
- */
-#define KVM_MEM_LOG_DIRTY_PAGES (1UL << 0)
-#define KVM_MEM_READONLY (1UL << 1)
-#define KVM_MEM_GUEST_MEMFD (1UL << 2)
-
-/* for KVM_IRQ_LINE */
-struct kvm_irq_level {
- /*
- * ACPI gsi notion of irq.
- * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
- * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
- * For ARM: See Documentation/virt/kvm/api.rst
- */
- union {
- __u32 irq;
- __s32 status;
- };
- __u32 level;
-};
-
-
-struct kvm_irqchip {
- __u32 chip_id;
- __u32 pad;
- union {
- char dummy[512]; /* reserving space */
-#ifdef __KVM_HAVE_PIT
- struct kvm_pic_state pic;
-#endif
-#ifdef __KVM_HAVE_IOAPIC
- struct kvm_ioapic_state ioapic;
-#endif
- } chip;
-};
-
-/* for KVM_CREATE_PIT2 */
-struct kvm_pit_config {
- __u32 flags;
- __u32 pad[15];
-};
-
-#define KVM_PIT_SPEAKER_DUMMY 1
-
-struct kvm_hyperv_exit {
-#define KVM_EXIT_HYPERV_SYNIC 1
-#define KVM_EXIT_HYPERV_HCALL 2
-#define KVM_EXIT_HYPERV_SYNDBG 3
- __u32 type;
- __u32 pad1;
- union {
- struct {
- __u32 msr;
- __u32 pad2;
- __u64 control;
- __u64 evt_page;
- __u64 msg_page;
- } synic;
- struct {
- __u64 input;
- __u64 result;
- __u64 params[2];
- } hcall;
- struct {
- __u32 msr;
- __u32 pad2;
- __u64 control;
- __u64 status;
- __u64 send_page;
- __u64 recv_page;
- __u64 pending_page;
- } syndbg;
- } u;
-};
-
-struct kvm_xen_exit {
-#define KVM_EXIT_XEN_HCALL 1
- __u32 type;
- union {
- struct {
- __u32 longmode;
- __u32 cpl;
- __u64 input;
- __u64 result;
- __u64 params[6];
- } hcall;
- } u;
-};
-
-struct kvm_exit_snp_req_certs {
- __u64 gpa;
- __u64 npages;
- __u64 ret;
-};
-
-#define KVM_S390_GET_SKEYS_NONE 1
-#define KVM_S390_SKEYS_MAX 1048576
-
-#define KVM_EXIT_UNKNOWN 0
-#define KVM_EXIT_EXCEPTION 1
-#define KVM_EXIT_IO 2
-#define KVM_EXIT_HYPERCALL 3
-#define KVM_EXIT_DEBUG 4
-#define KVM_EXIT_HLT 5
-#define KVM_EXIT_MMIO 6
-#define KVM_EXIT_IRQ_WINDOW_OPEN 7
-#define KVM_EXIT_SHUTDOWN 8
-#define KVM_EXIT_FAIL_ENTRY 9
-#define KVM_EXIT_INTR 10
-#define KVM_EXIT_SET_TPR 11
-#define KVM_EXIT_TPR_ACCESS 12
-#define KVM_EXIT_S390_SIEIC 13
-#define KVM_EXIT_S390_RESET 14
-#define KVM_EXIT_DCR 15 /* deprecated */
-#define KVM_EXIT_NMI 16
-#define KVM_EXIT_INTERNAL_ERROR 17
-#define KVM_EXIT_OSI 18
-#define KVM_EXIT_PAPR_HCALL 19
-#define KVM_EXIT_S390_UCONTROL 20
-#define KVM_EXIT_WATCHDOG 21
-#define KVM_EXIT_S390_TSCH 22
-#define KVM_EXIT_EPR 23
-#define KVM_EXIT_SYSTEM_EVENT 24
-#define KVM_EXIT_S390_STSI 25
-#define KVM_EXIT_IOAPIC_EOI 26
-#define KVM_EXIT_HYPERV 27
-#define KVM_EXIT_ARM_NISV 28
-#define KVM_EXIT_X86_RDMSR 29
-#define KVM_EXIT_X86_WRMSR 30
-#define KVM_EXIT_DIRTY_RING_FULL 31
-#define KVM_EXIT_AP_RESET_HOLD 32
-#define KVM_EXIT_X86_BUS_LOCK 33
-#define KVM_EXIT_XEN 34
-#define KVM_EXIT_RISCV_SBI 35
-#define KVM_EXIT_RISCV_CSR 36
-#define KVM_EXIT_NOTIFY 37
-#define KVM_EXIT_LOONGARCH_IOCSR 38
-#define KVM_EXIT_MEMORY_FAULT 39
-#define KVM_EXIT_TDX 40
-#define KVM_EXIT_ARM_SEA 41
-#define KVM_EXIT_ARM_LDST64B 42
-#define KVM_EXIT_SNP_REQ_CERTS 43
-
-/* For KVM_EXIT_INTERNAL_ERROR */
-/* Emulate instruction failed. */
-#define KVM_INTERNAL_ERROR_EMULATION 1
-/* Encounter unexpected simultaneous exceptions. */
-#define KVM_INTERNAL_ERROR_SIMUL_EX 2
-/* Encounter unexpected vm-exit due to delivery event. */
-#define KVM_INTERNAL_ERROR_DELIVERY_EV 3
-/* Encounter unexpected vm-exit reason */
-#define KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON 4
-
-/* Flags that describe what fields in emulation_failure hold valid data. */
-#define KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES (1ULL << 0)
-
-/*
- * struct kvm_run can be modified by userspace at any time, so KVM must be
- * careful to avoid TOCTOU bugs. In order to protect KVM, HINT_UNSAFE_IN_KVM()
- * renames fields in struct kvm_run from <symbol> to <symbol>__unsafe when
- * compiled into the kernel, ensuring that any use within KVM is obvious and
- * gets extra scrutiny.
- */
-#ifdef __KERNEL__
-#define HINT_UNSAFE_IN_KVM(_symbol) _symbol##__unsafe
-#else
-#define HINT_UNSAFE_IN_KVM(_symbol) _symbol
-#endif
-
-/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
-struct kvm_run {
- /* in */
- __u8 request_interrupt_window;
- __u8 HINT_UNSAFE_IN_KVM(immediate_exit);
- __u8 padding1[6];
-
- /* out */
- __u32 exit_reason;
- __u8 ready_for_interrupt_injection;
- __u8 if_flag;
- __u16 flags;
-
- /* in (pre_kvm_run), out (post_kvm_run) */
- __u64 cr8;
- __u64 apic_base;
-
-#ifdef __KVM_S390
- /* the processor status word for s390 */
- __u64 psw_mask; /* psw upper half */
- __u64 psw_addr; /* psw lower half */
-#endif
- union {
- /* KVM_EXIT_UNKNOWN */
- struct {
- __u64 hardware_exit_reason;
- } hw;
- /* KVM_EXIT_FAIL_ENTRY */
- struct {
- __u64 hardware_entry_failure_reason;
- __u32 cpu;
- } fail_entry;
- /* KVM_EXIT_EXCEPTION */
- struct {
- __u32 exception;
- __u32 error_code;
- } ex;
- /* KVM_EXIT_IO */
- struct {
-#define KVM_EXIT_IO_IN 0
-#define KVM_EXIT_IO_OUT 1
- __u8 direction;
- __u8 size; /* bytes */
- __u16 port;
- __u32 count;
- __u64 data_offset; /* relative to kvm_run start */
- } io;
- /* KVM_EXIT_DEBUG */
- struct {
- struct kvm_debug_exit_arch arch;
- } debug;
- /* KVM_EXIT_MMIO */
- struct {
- __u64 phys_addr;
- __u8 data[8];
- __u32 len;
- __u8 is_write;
- } mmio;
- /* KVM_EXIT_LOONGARCH_IOCSR */
- struct {
- __u64 phys_addr;
- __u8 data[8];
- __u32 len;
- __u8 is_write;
- } iocsr_io;
- /* KVM_EXIT_HYPERCALL */
- struct {
- __u64 nr;
- __u64 args[6];
- __u64 ret;
-
- union {
-#ifndef __KERNEL__
- __u32 longmode;
-#endif
- __u64 flags;
- };
- } hypercall;
- /* KVM_EXIT_TPR_ACCESS */
- struct {
- __u64 rip;
- __u32 is_write;
- __u32 pad;
- } tpr_access;
- /* KVM_EXIT_S390_SIEIC */
- struct {
- __u8 icptcode;
- __u16 ipa;
- __u32 ipb;
- } s390_sieic;
- /* KVM_EXIT_S390_RESET */
- __u64 s390_reset_flags;
- /* KVM_EXIT_S390_UCONTROL */
- struct {
- __u64 trans_exc_code;
- __u32 pgm_code;
- } s390_ucontrol;
- /* KVM_EXIT_DCR (deprecated) */
- struct {
- __u32 dcrn;
- __u32 data;
- __u8 is_write;
- } dcr;
- /* KVM_EXIT_INTERNAL_ERROR */
- struct {
- __u32 suberror;
- /* Available with KVM_CAP_INTERNAL_ERROR_DATA: */
- __u32 ndata;
- __u64 data[16];
- } internal;
- /*
- * KVM_INTERNAL_ERROR_EMULATION
- *
- * "struct emulation_failure" is an overlay of "struct internal"
- * that is used for the KVM_INTERNAL_ERROR_EMULATION sub-type of
- * KVM_EXIT_INTERNAL_ERROR. Note, unlike other internal error
- * sub-types, this struct is ABI! It also needs to be backwards
- * compatible with "struct internal". Take special care that
- * "ndata" is correct, that new fields are enumerated in "flags",
- * and that each flag enumerates fields that are 64-bit aligned
- * and sized (so that ndata+internal.data[] is valid/accurate).
- *
- * Space beyond the defined fields may be used to store arbitrary
- * debug information relating to the emulation failure. It is
- * accounted for in "ndata" but the format is unspecified and is
- * not represented in "flags". Any such information is *not* ABI!
- */
- struct {
- __u32 suberror;
- __u32 ndata;
- __u64 flags;
- union {
- struct {
- __u8 insn_size;
- __u8 insn_bytes[15];
- };
- };
- /* Arbitrary debug data may follow. */
- } emulation_failure;
- /* KVM_EXIT_OSI */
- struct {
- __u64 gprs[32];
- } osi;
- /* KVM_EXIT_PAPR_HCALL */
- struct {
- __u64 nr;
- __u64 ret;
- __u64 args[9];
- } papr_hcall;
- /* KVM_EXIT_S390_TSCH */
- struct {
- __u16 subchannel_id;
- __u16 subchannel_nr;
- __u32 io_int_parm;
- __u32 io_int_word;
- __u32 ipb;
- __u8 dequeued;
- } s390_tsch;
- /* KVM_EXIT_EPR */
- struct {
- __u32 epr;
- } epr;
- /* KVM_EXIT_SYSTEM_EVENT */
- struct {
-#define KVM_SYSTEM_EVENT_SHUTDOWN 1
-#define KVM_SYSTEM_EVENT_RESET 2
-#define KVM_SYSTEM_EVENT_CRASH 3
-#define KVM_SYSTEM_EVENT_WAKEUP 4
-#define KVM_SYSTEM_EVENT_SUSPEND 5
-#define KVM_SYSTEM_EVENT_SEV_TERM 6
-#define KVM_SYSTEM_EVENT_TDX_FATAL 7
- __u32 type;
- __u32 ndata;
- union {
-#ifndef __KERNEL__
- __u64 flags;
-#endif
- __u64 data[16];
- };
- } system_event;
- /* KVM_EXIT_S390_STSI */
- struct {
- __u64 addr;
- __u8 ar;
- __u8 reserved;
- __u8 fc;
- __u8 sel1;
- __u16 sel2;
- } s390_stsi;
- /* KVM_EXIT_IOAPIC_EOI */
- struct {
- __u8 vector;
- } eoi;
- /* KVM_EXIT_HYPERV */
- struct kvm_hyperv_exit hyperv;
- /* KVM_EXIT_ARM_NISV / KVM_EXIT_ARM_LDST64B */
- struct {
- __u64 esr_iss;
- __u64 fault_ipa;
- } arm_nisv;
- /* KVM_EXIT_X86_RDMSR / KVM_EXIT_X86_WRMSR */
- struct {
- __u8 error; /* user -> kernel */
- __u8 pad[7];
-#define KVM_MSR_EXIT_REASON_INVAL (1 << 0)
-#define KVM_MSR_EXIT_REASON_UNKNOWN (1 << 1)
-#define KVM_MSR_EXIT_REASON_FILTER (1 << 2)
-#define KVM_MSR_EXIT_REASON_VALID_MASK (KVM_MSR_EXIT_REASON_INVAL | \
- KVM_MSR_EXIT_REASON_UNKNOWN | \
- KVM_MSR_EXIT_REASON_FILTER)
- __u32 reason; /* kernel -> user */
- __u32 index; /* kernel -> user */
- __u64 data; /* kernel <-> user */
- } msr;
- /* KVM_EXIT_XEN */
- struct kvm_xen_exit xen;
- /* KVM_EXIT_RISCV_SBI */
- struct {
- unsigned long extension_id;
- unsigned long function_id;
- unsigned long args[6];
- unsigned long ret[2];
- } riscv_sbi;
- /* KVM_EXIT_RISCV_CSR */
- struct {
- unsigned long csr_num;
- unsigned long new_value;
- unsigned long write_mask;
- unsigned long ret_value;
- } riscv_csr;
- /* KVM_EXIT_NOTIFY */
- struct {
-#define KVM_NOTIFY_CONTEXT_INVALID (1 << 0)
- __u32 flags;
- } notify;
- /* KVM_EXIT_MEMORY_FAULT */
- struct {
-#define KVM_MEMORY_EXIT_FLAG_PRIVATE (1ULL << 3)
- __u64 flags;
- __u64 gpa;
- __u64 size;
- } memory_fault;
- /* KVM_EXIT_TDX */
- struct {
- __u64 flags;
- __u64 nr;
- union {
- struct {
- __u64 ret;
- __u64 data[5];
- } unknown;
- struct {
- __u64 ret;
- __u64 gpa;
- __u64 size;
- } get_quote;
- struct {
- __u64 ret;
- __u64 leaf;
- __u64 r11, r12, r13, r14;
- } get_tdvmcall_info;
- struct {
- __u64 ret;
- __u64 vector;
- } setup_event_notify;
- };
- } tdx;
- /* KVM_EXIT_ARM_SEA */
- struct {
-#define KVM_EXIT_ARM_SEA_FLAG_GPA_VALID (1ULL << 0)
- __u64 flags;
- __u64 esr;
- __u64 gva;
- __u64 gpa;
- } arm_sea;
- /* KVM_EXIT_SNP_REQ_CERTS */
- struct kvm_exit_snp_req_certs snp_req_certs;
- /* Fix the size of the union. */
- char padding[256];
- };
-
- /* 2048 is the size of the char array used to bound/pad the size
- * of the union that holds sync regs.
- */
- #define SYNC_REGS_SIZE_BYTES 2048
- /*
- * shared registers between kvm and userspace.
- * kvm_valid_regs specifies the register classes set by the host
- * kvm_dirty_regs specified the register classes dirtied by userspace
- * struct kvm_sync_regs is architecture specific, as well as the
- * bits for kvm_valid_regs and kvm_dirty_regs
- */
- __u64 kvm_valid_regs;
- __u64 kvm_dirty_regs;
- union {
- struct kvm_sync_regs regs;
- char padding[SYNC_REGS_SIZE_BYTES];
- } s;
-};
-
-/* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */
-
-struct kvm_coalesced_mmio_zone {
- __u64 addr;
- __u32 size;
- union {
- __u32 pad;
- __u32 pio;
- };
-};
-
-struct kvm_coalesced_mmio {
- __u64 phys_addr;
- __u32 len;
- union {
- __u32 pad;
- __u32 pio;
- };
- __u8 data[8];
-};
-
-struct kvm_coalesced_mmio_ring {
- __u32 first, last;
- struct kvm_coalesced_mmio coalesced_mmio[];
-};
-
-#define KVM_COALESCED_MMIO_MAX \
- ((PAGE_SIZE - sizeof(struct kvm_coalesced_mmio_ring)) / \
- sizeof(struct kvm_coalesced_mmio))
-
-/* for KVM_TRANSLATE */
-struct kvm_translation {
- /* in */
- __u64 linear_address;
-
- /* out */
- __u64 physical_address;
- __u8 valid;
- __u8 writeable;
- __u8 usermode;
- __u8 pad[5];
-};
-
-/* for KVM_INTERRUPT */
-struct kvm_interrupt {
- /* in */
- __u32 irq;
-};
-
-/* for KVM_GET_DIRTY_LOG */
-struct kvm_dirty_log {
- __u32 slot;
- __u32 padding1;
- union {
- void __user *dirty_bitmap; /* one bit per page */
- __u64 padding2;
- };
-};
-
-/* for KVM_CLEAR_DIRTY_LOG */
-struct kvm_clear_dirty_log {
- __u32 slot;
- __u32 num_pages;
- __u64 first_page;
- union {
- void __user *dirty_bitmap; /* one bit per page */
- __u64 padding2;
- };
-};
-
-/* for KVM_SET_SIGNAL_MASK */
-struct kvm_signal_mask {
- __u32 len;
- __u8 sigset[];
-};
-
-/* for KVM_TPR_ACCESS_REPORTING */
-struct kvm_tpr_access_ctl {
- __u32 enabled;
- __u32 flags;
- __u32 reserved[8];
-};
-
-/* for KVM_SET_VAPIC_ADDR */
-struct kvm_vapic_addr {
- __u64 vapic_addr;
-};
-
-/* for KVM_SET_MP_STATE */
-
-/* not all states are valid on all architectures */
-#define KVM_MP_STATE_RUNNABLE 0
-#define KVM_MP_STATE_UNINITIALIZED 1
-#define KVM_MP_STATE_INIT_RECEIVED 2
-#define KVM_MP_STATE_HALTED 3
-#define KVM_MP_STATE_SIPI_RECEIVED 4
-#define KVM_MP_STATE_STOPPED 5
-#define KVM_MP_STATE_CHECK_STOP 6
-#define KVM_MP_STATE_OPERATING 7
-#define KVM_MP_STATE_LOAD 8
-#define KVM_MP_STATE_AP_RESET_HOLD 9
-#define KVM_MP_STATE_SUSPENDED 10
-
-struct kvm_mp_state {
- __u32 mp_state;
-};
-
-/* for KVM_SET_GUEST_DEBUG */
-
-#define KVM_GUESTDBG_ENABLE 0x00000001
-#define KVM_GUESTDBG_SINGLESTEP 0x00000002
-
-struct kvm_guest_debug {
- __u32 control;
- __u32 pad;
- struct kvm_guest_debug_arch arch;
-};
-
-enum {
- kvm_ioeventfd_flag_nr_datamatch,
- kvm_ioeventfd_flag_nr_pio,
- kvm_ioeventfd_flag_nr_deassign,
- kvm_ioeventfd_flag_nr_virtio_ccw_notify,
- kvm_ioeventfd_flag_nr_fast_mmio,
- kvm_ioeventfd_flag_nr_max,
-};
-
-#define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch)
-#define KVM_IOEVENTFD_FLAG_PIO (1 << kvm_ioeventfd_flag_nr_pio)
-#define KVM_IOEVENTFD_FLAG_DEASSIGN (1 << kvm_ioeventfd_flag_nr_deassign)
-#define KVM_IOEVENTFD_FLAG_VIRTIO_CCW_NOTIFY \
- (1 << kvm_ioeventfd_flag_nr_virtio_ccw_notify)
-
-#define KVM_IOEVENTFD_VALID_FLAG_MASK ((1 << kvm_ioeventfd_flag_nr_max) - 1)
-
-struct kvm_ioeventfd {
- __u64 datamatch;
- __u64 addr; /* legal pio/mmio address */
- __u32 len; /* 1, 2, 4, or 8 bytes; or 0 to ignore length */
- __s32 fd;
- __u32 flags;
- __u8 pad[36];
-};
-
-#define KVM_X86_DISABLE_EXITS_MWAIT (1 << 0)
-#define KVM_X86_DISABLE_EXITS_HLT (1 << 1)
-#define KVM_X86_DISABLE_EXITS_PAUSE (1 << 2)
-#define KVM_X86_DISABLE_EXITS_CSTATE (1 << 3)
-#define KVM_X86_DISABLE_EXITS_APERFMPERF (1 << 4)
-
-/* for KVM_ENABLE_CAP */
-struct kvm_enable_cap {
- /* in */
- __u32 cap;
- __u32 flags;
- __u64 args[4];
- __u8 pad[64];
-};
-
-#define KVMIO 0xAE
-
-/* machine type bits, to be used as argument to KVM_CREATE_VM */
-#define KVM_VM_S390_UCONTROL 1
-
-/* on ppc, 0 indicate default, 1 should force HV and 2 PR */
-#define KVM_VM_PPC_HV 1
-#define KVM_VM_PPC_PR 2
-
-/* on MIPS, 0 indicates auto, 1 forces VZ ASE, 2 forces trap & emulate */
-#define KVM_VM_MIPS_AUTO 0
-#define KVM_VM_MIPS_VZ 1
-#define KVM_VM_MIPS_TE 2
-
-#define KVM_S390_SIE_PAGE_OFFSET 1
-
-/*
- * On arm64, machine type can be used to request the physical
- * address size for the VM. Bits[7-0] are reserved for the guest
- * PA size shift (i.e, log2(PA_Size)). For backward compatibility,
- * value 0 implies the default IPA size, 40bits.
- */
-#define KVM_VM_TYPE_ARM_IPA_SIZE_MASK 0xffULL
-#define KVM_VM_TYPE_ARM_IPA_SIZE(x) \
- ((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
-/*
- * ioctls for /dev/kvm fds:
- */
-#define KVM_GET_API_VERSION _IO(KVMIO, 0x00)
-#define KVM_CREATE_VM _IO(KVMIO, 0x01) /* returns a VM fd */
-#define KVM_GET_MSR_INDEX_LIST _IOWR(KVMIO, 0x02, struct kvm_msr_list)
-
-#define KVM_S390_ENABLE_SIE _IO(KVMIO, 0x06)
-/*
- * Check if a kvm extension is available. Argument is extension number,
- * return is 1 (yes) or 0 (no, sorry).
- */
-#define KVM_CHECK_EXTENSION _IO(KVMIO, 0x03)
-/*
- * Get size for mmap(vcpu_fd)
- */
-#define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */
-#define KVM_GET_SUPPORTED_CPUID _IOWR(KVMIO, 0x05, struct kvm_cpuid2)
-#define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2)
-#define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list)
-
-/*
- * Extension capability list.
- */
-#define KVM_CAP_IRQCHIP 0
-#define KVM_CAP_HLT 1
-#define KVM_CAP_MMU_SHADOW_CACHE_CONTROL 2
-#define KVM_CAP_USER_MEMORY 3
-#define KVM_CAP_SET_TSS_ADDR 4
-#define KVM_CAP_VAPIC 6
-#define KVM_CAP_EXT_CPUID 7
-#define KVM_CAP_CLOCKSOURCE 8
-#define KVM_CAP_NR_VCPUS 9 /* returns recommended max vcpus per vm */
-#define KVM_CAP_NR_MEMSLOTS 10 /* returns max memory slots per vm */
-#define KVM_CAP_PIT 11
-#define KVM_CAP_NOP_IO_DELAY 12
-#define KVM_CAP_PV_MMU 13
-#define KVM_CAP_MP_STATE 14
-#define KVM_CAP_COALESCED_MMIO 15
-#define KVM_CAP_SYNC_MMU 16 /* Changes to host mmap are reflected in guest */
-#define KVM_CAP_IOMMU 18
-/* Bug in KVM_SET_USER_MEMORY_REGION fixed: */
-#define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21
-#define KVM_CAP_USER_NMI 22
-#define KVM_CAP_SET_GUEST_DEBUG 23
-#ifdef __KVM_HAVE_PIT
-#define KVM_CAP_REINJECT_CONTROL 24
-#endif
-#define KVM_CAP_IRQ_ROUTING 25
-#define KVM_CAP_IRQ_INJECT_STATUS 26
-#define KVM_CAP_ASSIGN_DEV_IRQ 29
-/* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
-#define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
-#ifdef __KVM_HAVE_MCE
-#define KVM_CAP_MCE 31
-#endif
-#define KVM_CAP_IRQFD 32
-#ifdef __KVM_HAVE_PIT
-#define KVM_CAP_PIT2 33
-#endif
-#define KVM_CAP_SET_BOOT_CPU_ID 34
-#ifdef __KVM_HAVE_PIT_STATE2
-#define KVM_CAP_PIT_STATE2 35
-#endif
-#define KVM_CAP_IOEVENTFD 36
-#define KVM_CAP_SET_IDENTITY_MAP_ADDR 37
-#ifdef __KVM_HAVE_XEN_HVM
-#define KVM_CAP_XEN_HVM 38
-#endif
-#define KVM_CAP_ADJUST_CLOCK 39
-#define KVM_CAP_INTERNAL_ERROR_DATA 40
-#ifdef __KVM_HAVE_VCPU_EVENTS
-#define KVM_CAP_VCPU_EVENTS 41
-#endif
-#define KVM_CAP_S390_PSW 42
-#define KVM_CAP_PPC_SEGSTATE 43
-#define KVM_CAP_HYPERV 44
-#define KVM_CAP_HYPERV_VAPIC 45
-#define KVM_CAP_HYPERV_SPIN 46
-#define KVM_CAP_PCI_SEGMENT 47
-#define KVM_CAP_PPC_PAIRED_SINGLES 48
-#define KVM_CAP_INTR_SHADOW 49
-#ifdef __KVM_HAVE_DEBUGREGS
-#define KVM_CAP_DEBUGREGS 50
-#endif
-#define KVM_CAP_X86_ROBUST_SINGLESTEP 51
-#define KVM_CAP_PPC_OSI 52
-#define KVM_CAP_PPC_UNSET_IRQ 53
-#define KVM_CAP_ENABLE_CAP 54
-#ifdef __KVM_HAVE_XSAVE
-#define KVM_CAP_XSAVE 55
-#endif
-#ifdef __KVM_HAVE_XCRS
-#define KVM_CAP_XCRS 56
-#endif
-#define KVM_CAP_PPC_GET_PVINFO 57
-#define KVM_CAP_PPC_IRQ_LEVEL 58
-#define KVM_CAP_ASYNC_PF 59
-#define KVM_CAP_TSC_CONTROL 60
-#define KVM_CAP_GET_TSC_KHZ 61
-#define KVM_CAP_PPC_BOOKE_SREGS 62
-#define KVM_CAP_SPAPR_TCE 63
-#define KVM_CAP_PPC_SMT 64
-#define KVM_CAP_PPC_RMA 65
-#define KVM_CAP_MAX_VCPUS 66 /* returns max vcpus per vm */
-#define KVM_CAP_PPC_HIOR 67
-#define KVM_CAP_PPC_PAPR 68
-#define KVM_CAP_SW_TLB 69
-#define KVM_CAP_ONE_REG 70
-#define KVM_CAP_S390_GMAP 71
-#define KVM_CAP_TSC_DEADLINE_TIMER 72
-#define KVM_CAP_S390_UCONTROL 73
-#define KVM_CAP_SYNC_REGS 74
-#define KVM_CAP_PCI_2_3 75
-#define KVM_CAP_KVMCLOCK_CTRL 76
-#define KVM_CAP_SIGNAL_MSI 77
-#define KVM_CAP_PPC_GET_SMMU_INFO 78
-#define KVM_CAP_S390_COW 79
-#define KVM_CAP_PPC_ALLOC_HTAB 80
-#define KVM_CAP_READONLY_MEM 81
-#define KVM_CAP_IRQFD_RESAMPLE 82
-#define KVM_CAP_PPC_BOOKE_WATCHDOG 83
-#define KVM_CAP_PPC_HTAB_FD 84
-#define KVM_CAP_S390_CSS_SUPPORT 85
-#define KVM_CAP_PPC_EPR 86
-#define KVM_CAP_ARM_PSCI 87
-#define KVM_CAP_ARM_SET_DEVICE_ADDR 88
-#define KVM_CAP_DEVICE_CTRL 89
-#define KVM_CAP_IRQ_MPIC 90
-#define KVM_CAP_PPC_RTAS 91
-#define KVM_CAP_IRQ_XICS 92
-#define KVM_CAP_ARM_EL1_32BIT 93
-#define KVM_CAP_SPAPR_MULTITCE 94
-#define KVM_CAP_EXT_EMUL_CPUID 95
-#define KVM_CAP_HYPERV_TIME 96
-#define KVM_CAP_IOAPIC_POLARITY_IGNORED 97
-#define KVM_CAP_ENABLE_CAP_VM 98
-#define KVM_CAP_S390_IRQCHIP 99
-#define KVM_CAP_IOEVENTFD_NO_LENGTH 100
-#define KVM_CAP_VM_ATTRIBUTES 101
-#define KVM_CAP_ARM_PSCI_0_2 102
-#define KVM_CAP_PPC_FIXUP_HCALL 103
-#define KVM_CAP_PPC_ENABLE_HCALL 104
-#define KVM_CAP_CHECK_EXTENSION_VM 105
-#define KVM_CAP_S390_USER_SIGP 106
-#define KVM_CAP_S390_VECTOR_REGISTERS 107
-#define KVM_CAP_S390_MEM_OP 108
-#define KVM_CAP_S390_USER_STSI 109
-#define KVM_CAP_S390_SKEYS 110
-#define KVM_CAP_MIPS_FPU 111
-#define KVM_CAP_MIPS_MSA 112
-#define KVM_CAP_S390_INJECT_IRQ 113
-#define KVM_CAP_S390_IRQ_STATE 114
-#define KVM_CAP_PPC_HWRNG 115
-#define KVM_CAP_DISABLE_QUIRKS 116
-#define KVM_CAP_X86_SMM 117
-#define KVM_CAP_MULTI_ADDRESS_SPACE 118
-#define KVM_CAP_GUEST_DEBUG_HW_BPS 119
-#define KVM_CAP_GUEST_DEBUG_HW_WPS 120
-#define KVM_CAP_SPLIT_IRQCHIP 121
-#define KVM_CAP_IOEVENTFD_ANY_LENGTH 122
-#define KVM_CAP_HYPERV_SYNIC 123
-#define KVM_CAP_S390_RI 124
-#define KVM_CAP_SPAPR_TCE_64 125
-#define KVM_CAP_ARM_PMU_V3 126
-#define KVM_CAP_VCPU_ATTRIBUTES 127
-#define KVM_CAP_MAX_VCPU_ID 128
-#define KVM_CAP_X2APIC_API 129
-#define KVM_CAP_S390_USER_INSTR0 130
-#define KVM_CAP_MSI_DEVID 131
-#define KVM_CAP_PPC_HTM 132
-#define KVM_CAP_SPAPR_RESIZE_HPT 133
-#define KVM_CAP_PPC_MMU_RADIX 134
-#define KVM_CAP_PPC_MMU_HASH_V3 135
-#define KVM_CAP_IMMEDIATE_EXIT 136
-#define KVM_CAP_MIPS_VZ 137
-#define KVM_CAP_MIPS_TE 138
-#define KVM_CAP_MIPS_64BIT 139
-#define KVM_CAP_S390_GS 140
-#define KVM_CAP_S390_AIS 141
-#define KVM_CAP_SPAPR_TCE_VFIO 142
-#define KVM_CAP_X86_DISABLE_EXITS 143
-#define KVM_CAP_ARM_USER_IRQ 144
-#define KVM_CAP_S390_CMMA_MIGRATION 145
-#define KVM_CAP_PPC_FWNMI 146
-#define KVM_CAP_PPC_SMT_POSSIBLE 147
-#define KVM_CAP_HYPERV_SYNIC2 148
-#define KVM_CAP_HYPERV_VP_INDEX 149
-#define KVM_CAP_S390_AIS_MIGRATION 150
-#define KVM_CAP_PPC_GET_CPU_CHAR 151
-#define KVM_CAP_S390_BPB 152
-#define KVM_CAP_GET_MSR_FEATURES 153
-#define KVM_CAP_HYPERV_EVENTFD 154
-#define KVM_CAP_HYPERV_TLBFLUSH 155
-#define KVM_CAP_S390_HPAGE_1M 156
-#define KVM_CAP_NESTED_STATE 157
-#define KVM_CAP_ARM_INJECT_SERROR_ESR 158
-#define KVM_CAP_MSR_PLATFORM_INFO 159
-#define KVM_CAP_PPC_NESTED_HV 160
-#define KVM_CAP_HYPERV_SEND_IPI 161
-#define KVM_CAP_COALESCED_PIO 162
-#define KVM_CAP_HYPERV_ENLIGHTENED_VMCS 163
-#define KVM_CAP_EXCEPTION_PAYLOAD 164
-#define KVM_CAP_ARM_VM_IPA_SIZE 165
-#define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 166 /* Obsolete */
-#define KVM_CAP_HYPERV_CPUID 167
-#define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 168
-#define KVM_CAP_PPC_IRQ_XIVE 169
-#define KVM_CAP_ARM_SVE 170
-#define KVM_CAP_ARM_PTRAUTH_ADDRESS 171
-#define KVM_CAP_ARM_PTRAUTH_GENERIC 172
-#define KVM_CAP_PMU_EVENT_FILTER 173
-#define KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 174
-#define KVM_CAP_HYPERV_DIRECT_TLBFLUSH 175
-#define KVM_CAP_PPC_GUEST_DEBUG_SSTEP 176
-#define KVM_CAP_ARM_NISV_TO_USER 177
-#define KVM_CAP_ARM_INJECT_EXT_DABT 178
-#define KVM_CAP_S390_VCPU_RESETS 179
-#define KVM_CAP_S390_PROTECTED 180
-#define KVM_CAP_PPC_SECURE_GUEST 181
-#define KVM_CAP_HALT_POLL 182
-#define KVM_CAP_ASYNC_PF_INT 183
-#define KVM_CAP_LAST_CPU 184
-#define KVM_CAP_SMALLER_MAXPHYADDR 185
-#define KVM_CAP_S390_DIAG318 186
-#define KVM_CAP_STEAL_TIME 187
-#define KVM_CAP_X86_USER_SPACE_MSR 188
-#define KVM_CAP_X86_MSR_FILTER 189
-#define KVM_CAP_ENFORCE_PV_FEATURE_CPUID 190
-#define KVM_CAP_SYS_HYPERV_CPUID 191
-#define KVM_CAP_DIRTY_LOG_RING 192
-#define KVM_CAP_X86_BUS_LOCK_EXIT 193
-#define KVM_CAP_PPC_DAWR1 194
-#define KVM_CAP_SET_GUEST_DEBUG2 195
-#define KVM_CAP_SGX_ATTRIBUTE 196
-#define KVM_CAP_VM_COPY_ENC_CONTEXT_FROM 197
-#define KVM_CAP_PTP_KVM 198
-#define KVM_CAP_HYPERV_ENFORCE_CPUID 199
-#define KVM_CAP_SREGS2 200
-#define KVM_CAP_EXIT_HYPERCALL 201
-#define KVM_CAP_PPC_RPT_INVALIDATE 202
-#define KVM_CAP_BINARY_STATS_FD 203
-#define KVM_CAP_EXIT_ON_EMULATION_FAILURE 204
-#define KVM_CAP_ARM_MTE 205
-#define KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM 206
-#define KVM_CAP_VM_GPA_BITS 207
-#define KVM_CAP_XSAVE2 208
-#define KVM_CAP_SYS_ATTRIBUTES 209
-#define KVM_CAP_PPC_AIL_MODE_3 210
-#define KVM_CAP_S390_MEM_OP_EXTENSION 211
-#define KVM_CAP_PMU_CAPABILITY 212
-#define KVM_CAP_DISABLE_QUIRKS2 213
-#define KVM_CAP_VM_TSC_CONTROL 214
-#define KVM_CAP_SYSTEM_EVENT_DATA 215
-#define KVM_CAP_ARM_SYSTEM_SUSPEND 216
-#define KVM_CAP_S390_PROTECTED_DUMP 217
-#define KVM_CAP_X86_TRIPLE_FAULT_EVENT 218
-#define KVM_CAP_X86_NOTIFY_VMEXIT 219
-#define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220
-#define KVM_CAP_S390_ZPCI_OP 221
-#define KVM_CAP_S390_CPU_TOPOLOGY 222
-#define KVM_CAP_DIRTY_LOG_RING_ACQ_REL 223
-#define KVM_CAP_S390_PROTECTED_ASYNC_DISABLE 224
-#define KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP 225
-#define KVM_CAP_PMU_EVENT_MASKED_EVENTS 226
-#define KVM_CAP_COUNTER_OFFSET 227
-#define KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE 228
-#define KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES 229
-#define KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES 230
-#define KVM_CAP_USER_MEMORY2 231
-#define KVM_CAP_MEMORY_FAULT_INFO 232
-#define KVM_CAP_MEMORY_ATTRIBUTES 233
-#define KVM_CAP_GUEST_MEMFD 234
-#define KVM_CAP_VM_TYPES 235
-#define KVM_CAP_PRE_FAULT_MEMORY 236
-#define KVM_CAP_X86_APIC_BUS_CYCLES_NS 237
-#define KVM_CAP_X86_GUEST_MODE 238
-#define KVM_CAP_ARM_WRITABLE_IMP_ID_REGS 239
-#define KVM_CAP_ARM_EL2 240
-#define KVM_CAP_ARM_EL2_E2H0 241
-#define KVM_CAP_RISCV_MP_STATE_RESET 242
-#define KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED 243
-#define KVM_CAP_GUEST_MEMFD_FLAGS 244
-#define KVM_CAP_ARM_SEA_TO_USER 245
-#define KVM_CAP_S390_USER_OPEREXEC 246
-#define KVM_CAP_S390_KEYOP 247
-
-struct kvm_irq_routing_irqchip {
- __u32 irqchip;
- __u32 pin;
-};
-
-struct kvm_irq_routing_msi {
- __u32 address_lo;
- __u32 address_hi;
- __u32 data;
- union {
- __u32 pad;
- __u32 devid;
- };
-};
-
-struct kvm_irq_routing_s390_adapter {
- __u64 ind_addr;
- __u64 summary_addr;
- __u64 ind_offset;
- __u32 summary_offset;
- __u32 adapter_id;
-};
-
-struct kvm_irq_routing_hv_sint {
- __u32 vcpu;
- __u32 sint;
-};
-
-struct kvm_irq_routing_xen_evtchn {
- __u32 port;
- __u32 vcpu;
- __u32 priority;
-};
-
-#define KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL ((__u32)(-1))
-
-/* gsi routing entry types */
-#define KVM_IRQ_ROUTING_IRQCHIP 1
-#define KVM_IRQ_ROUTING_MSI 2
-#define KVM_IRQ_ROUTING_S390_ADAPTER 3
-#define KVM_IRQ_ROUTING_HV_SINT 4
-#define KVM_IRQ_ROUTING_XEN_EVTCHN 5
-
-struct kvm_irq_routing_entry {
- __u32 gsi;
- __u32 type;
- __u32 flags;
- __u32 pad;
- union {
- struct kvm_irq_routing_irqchip irqchip;
- struct kvm_irq_routing_msi msi;
- struct kvm_irq_routing_s390_adapter adapter;
- struct kvm_irq_routing_hv_sint hv_sint;
- struct kvm_irq_routing_xen_evtchn xen_evtchn;
- __u32 pad[8];
- } u;
-};
-
-struct kvm_irq_routing {
- __u32 nr;
- __u32 flags;
- struct kvm_irq_routing_entry entries[];
-};
-
-#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
-/*
- * Available with KVM_CAP_IRQFD_RESAMPLE
- *
- * KVM_IRQFD_FLAG_RESAMPLE indicates resamplefd is valid and specifies
- * the irqfd to operate in resampling mode for level triggered interrupt
- * emulation. See Documentation/virt/kvm/api.rst.
- */
-#define KVM_IRQFD_FLAG_RESAMPLE (1 << 1)
-
-struct kvm_irqfd {
- __u32 fd;
- __u32 gsi;
- __u32 flags;
- __u32 resamplefd;
- __u8 pad[16];
-};
-
-/* For KVM_CAP_ADJUST_CLOCK */
-
-/* Do not use 1, KVM_CHECK_EXTENSION returned it before we had flags. */
-#define KVM_CLOCK_TSC_STABLE 2
-#define KVM_CLOCK_REALTIME (1 << 2)
-#define KVM_CLOCK_HOST_TSC (1 << 3)
-
-struct kvm_clock_data {
- __u64 clock;
- __u32 flags;
- __u32 pad0;
- __u64 realtime;
- __u64 host_tsc;
- __u32 pad[4];
-};
-
-/* For KVM_CAP_SW_TLB */
-
-#define KVM_MMU_FSL_BOOKE_NOHV 0
-#define KVM_MMU_FSL_BOOKE_HV 1
-
-struct kvm_config_tlb {
- __u64 params;
- __u64 array;
- __u32 mmu_type;
- __u32 array_len;
-};
-
-struct kvm_dirty_tlb {
- __u64 bitmap;
- __u32 num_dirty;
-};
-
-/* Available with KVM_CAP_ONE_REG */
-
-#define KVM_REG_ARCH_MASK 0xff00000000000000ULL
-#define KVM_REG_GENERIC 0x0000000000000000ULL
-
-/*
- * Architecture specific registers are to be defined in arch headers and
- * ORed with the arch identifier.
- */
-#define KVM_REG_PPC 0x1000000000000000ULL
-#define KVM_REG_X86 0x2000000000000000ULL
-#define KVM_REG_IA64 0x3000000000000000ULL
-#define KVM_REG_ARM 0x4000000000000000ULL
-#define KVM_REG_S390 0x5000000000000000ULL
-#define KVM_REG_ARM64 0x6000000000000000ULL
-#define KVM_REG_MIPS 0x7000000000000000ULL
-#define KVM_REG_RISCV 0x8000000000000000ULL
-#define KVM_REG_LOONGARCH 0x9000000000000000ULL
-
-#define KVM_REG_SIZE_SHIFT 52
-#define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
-
-#define KVM_REG_SIZE(id) \
- (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
-
-#define KVM_REG_SIZE_U8 0x0000000000000000ULL
-#define KVM_REG_SIZE_U16 0x0010000000000000ULL
-#define KVM_REG_SIZE_U32 0x0020000000000000ULL
-#define KVM_REG_SIZE_U64 0x0030000000000000ULL
-#define KVM_REG_SIZE_U128 0x0040000000000000ULL
-#define KVM_REG_SIZE_U256 0x0050000000000000ULL
-#define KVM_REG_SIZE_U512 0x0060000000000000ULL
-#define KVM_REG_SIZE_U1024 0x0070000000000000ULL
-#define KVM_REG_SIZE_U2048 0x0080000000000000ULL
-
-struct kvm_reg_list {
- __u64 n; /* number of regs */
- __u64 reg[];
-};
-
-struct kvm_one_reg {
- __u64 id;
- __u64 addr;
-};
-
-#define KVM_MSI_VALID_DEVID (1U << 0)
-struct kvm_msi {
- __u32 address_lo;
- __u32 address_hi;
- __u32 data;
- __u32 flags;
- __u32 devid;
- __u8 pad[12];
-};
-
-struct kvm_arm_device_addr {
- __u64 id;
- __u64 addr;
-};
-
-/*
- * Device control API, available with KVM_CAP_DEVICE_CTRL
- */
-#define KVM_CREATE_DEVICE_TEST 1
-
-struct kvm_create_device {
- __u32 type; /* in: KVM_DEV_TYPE_xxx */
- __u32 fd; /* out: device handle */
- __u32 flags; /* in: KVM_CREATE_DEVICE_xxx */
-};
-
-struct kvm_device_attr {
- __u32 flags; /* no flags currently defined */
- __u32 group; /* device-defined */
- __u64 attr; /* group-defined */
- __u64 addr; /* userspace address of attr data */
-};
-
-#define KVM_DEV_VFIO_FILE 1
-
-#define KVM_DEV_VFIO_FILE_ADD 1
-#define KVM_DEV_VFIO_FILE_DEL 2
-
-/* KVM_DEV_VFIO_GROUP aliases are for compile time uapi compatibility */
-#define KVM_DEV_VFIO_GROUP KVM_DEV_VFIO_FILE
-
-#define KVM_DEV_VFIO_GROUP_ADD KVM_DEV_VFIO_FILE_ADD
-#define KVM_DEV_VFIO_GROUP_DEL KVM_DEV_VFIO_FILE_DEL
-#define KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE 3
-
-enum kvm_device_type {
- KVM_DEV_TYPE_FSL_MPIC_20 = 1,
-#define KVM_DEV_TYPE_FSL_MPIC_20 KVM_DEV_TYPE_FSL_MPIC_20
- KVM_DEV_TYPE_FSL_MPIC_42,
-#define KVM_DEV_TYPE_FSL_MPIC_42 KVM_DEV_TYPE_FSL_MPIC_42
- KVM_DEV_TYPE_XICS,
-#define KVM_DEV_TYPE_XICS KVM_DEV_TYPE_XICS
- KVM_DEV_TYPE_VFIO,
-#define KVM_DEV_TYPE_VFIO KVM_DEV_TYPE_VFIO
- KVM_DEV_TYPE_ARM_VGIC_V2,
-#define KVM_DEV_TYPE_ARM_VGIC_V2 KVM_DEV_TYPE_ARM_VGIC_V2
- KVM_DEV_TYPE_FLIC,
-#define KVM_DEV_TYPE_FLIC KVM_DEV_TYPE_FLIC
- KVM_DEV_TYPE_ARM_VGIC_V3,
-#define KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_V3
- KVM_DEV_TYPE_ARM_VGIC_ITS,
-#define KVM_DEV_TYPE_ARM_VGIC_ITS KVM_DEV_TYPE_ARM_VGIC_ITS
- KVM_DEV_TYPE_XIVE,
-#define KVM_DEV_TYPE_XIVE KVM_DEV_TYPE_XIVE
- KVM_DEV_TYPE_ARM_PV_TIME,
-#define KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_ARM_PV_TIME
- KVM_DEV_TYPE_RISCV_AIA,
-#define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA
- KVM_DEV_TYPE_LOONGARCH_IPI,
-#define KVM_DEV_TYPE_LOONGARCH_IPI KVM_DEV_TYPE_LOONGARCH_IPI
- KVM_DEV_TYPE_LOONGARCH_EIOINTC,
-#define KVM_DEV_TYPE_LOONGARCH_EIOINTC KVM_DEV_TYPE_LOONGARCH_EIOINTC
- KVM_DEV_TYPE_LOONGARCH_PCHPIC,
-#define KVM_DEV_TYPE_LOONGARCH_PCHPIC KVM_DEV_TYPE_LOONGARCH_PCHPIC
-
- KVM_DEV_TYPE_MAX,
-
-};
-
-struct kvm_vfio_spapr_tce {
- __s32 groupfd;
- __s32 tablefd;
-};
-
-#define KVM_S390_KEYOP_ISKE 0x01
-#define KVM_S390_KEYOP_RRBE 0x02
-#define KVM_S390_KEYOP_SSKE 0x03
-struct kvm_s390_keyop {
- __u64 guest_addr;
- __u8 key;
- __u8 operation;
- __u8 pad[6];
-};
-
-/*
- * KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns
- * a vcpu fd.
- */
-#define KVM_CREATE_VCPU _IO(KVMIO, 0x41)
-#define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log)
-#define KVM_SET_NR_MMU_PAGES _IO(KVMIO, 0x44)
-#define KVM_GET_NR_MMU_PAGES _IO(KVMIO, 0x45) /* deprecated */
-#define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46, \
- struct kvm_userspace_memory_region)
-#define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47)
-#define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO, 0x48, __u64)
-#define KVM_SET_USER_MEMORY_REGION2 _IOW(KVMIO, 0x49, \
- struct kvm_userspace_memory_region2)
-
-/* enable ucontrol for s390 */
-#define KVM_S390_UCAS_MAP _IOW(KVMIO, 0x50, struct kvm_s390_ucas_mapping)
-#define KVM_S390_UCAS_UNMAP _IOW(KVMIO, 0x51, struct kvm_s390_ucas_mapping)
-#define KVM_S390_VCPU_FAULT _IOW(KVMIO, 0x52, unsigned long)
-#define KVM_S390_KEYOP _IOWR(KVMIO, 0x53, struct kvm_s390_keyop)
-
-/* Device model IOC */
-#define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60)
-#define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level)
-#define KVM_GET_IRQCHIP _IOWR(KVMIO, 0x62, struct kvm_irqchip)
-#define KVM_SET_IRQCHIP _IOR(KVMIO, 0x63, struct kvm_irqchip)
-#define KVM_CREATE_PIT _IO(KVMIO, 0x64)
-#define KVM_GET_PIT _IOWR(KVMIO, 0x65, struct kvm_pit_state)
-#define KVM_SET_PIT _IOR(KVMIO, 0x66, struct kvm_pit_state)
-#define KVM_IRQ_LINE_STATUS _IOWR(KVMIO, 0x67, struct kvm_irq_level)
-#define KVM_REGISTER_COALESCED_MMIO \
- _IOW(KVMIO, 0x67, struct kvm_coalesced_mmio_zone)
-#define KVM_UNREGISTER_COALESCED_MMIO \
- _IOW(KVMIO, 0x68, struct kvm_coalesced_mmio_zone)
-#define KVM_SET_GSI_ROUTING _IOW(KVMIO, 0x6a, struct kvm_irq_routing)
-#define KVM_REINJECT_CONTROL _IO(KVMIO, 0x71)
-#define KVM_IRQFD _IOW(KVMIO, 0x76, struct kvm_irqfd)
-#define KVM_CREATE_PIT2 _IOW(KVMIO, 0x77, struct kvm_pit_config)
-#define KVM_SET_BOOT_CPU_ID _IO(KVMIO, 0x78)
-#define KVM_IOEVENTFD _IOW(KVMIO, 0x79, struct kvm_ioeventfd)
-#define KVM_XEN_HVM_CONFIG _IOW(KVMIO, 0x7a, struct kvm_xen_hvm_config)
-#define KVM_SET_CLOCK _IOW(KVMIO, 0x7b, struct kvm_clock_data)
-#define KVM_GET_CLOCK _IOR(KVMIO, 0x7c, struct kvm_clock_data)
-/* Available with KVM_CAP_PIT_STATE2 */
-#define KVM_GET_PIT2 _IOR(KVMIO, 0x9f, struct kvm_pit_state2)
-#define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2)
-/* Available with KVM_CAP_PPC_GET_PVINFO */
-#define KVM_PPC_GET_PVINFO _IOW(KVMIO, 0xa1, struct kvm_ppc_pvinfo)
-/* Available with KVM_CAP_TSC_CONTROL for a vCPU, or with
-* KVM_CAP_VM_TSC_CONTROL to set defaults for a VM */
-#define KVM_SET_TSC_KHZ _IO(KVMIO, 0xa2)
-#define KVM_GET_TSC_KHZ _IO(KVMIO, 0xa3)
-/* Available with KVM_CAP_SIGNAL_MSI */
-#define KVM_SIGNAL_MSI _IOW(KVMIO, 0xa5, struct kvm_msi)
-/* Available with KVM_CAP_PPC_GET_SMMU_INFO */
-#define KVM_PPC_GET_SMMU_INFO _IOR(KVMIO, 0xa6, struct kvm_ppc_smmu_info)
-/* Available with KVM_CAP_PPC_ALLOC_HTAB */
-#define KVM_PPC_ALLOCATE_HTAB _IOWR(KVMIO, 0xa7, __u32)
-#define KVM_CREATE_SPAPR_TCE _IOW(KVMIO, 0xa8, struct kvm_create_spapr_tce)
-#define KVM_CREATE_SPAPR_TCE_64 _IOW(KVMIO, 0xa8, \
- struct kvm_create_spapr_tce_64)
-/* Available with KVM_CAP_RMA */
-#define KVM_ALLOCATE_RMA _IOR(KVMIO, 0xa9, struct kvm_allocate_rma)
-/* Available with KVM_CAP_PPC_HTAB_FD */
-#define KVM_PPC_GET_HTAB_FD _IOW(KVMIO, 0xaa, struct kvm_get_htab_fd)
-/* Available with KVM_CAP_ARM_SET_DEVICE_ADDR */
-#define KVM_ARM_SET_DEVICE_ADDR _IOW(KVMIO, 0xab, struct kvm_arm_device_addr)
-/* Available with KVM_CAP_PPC_RTAS */
-#define KVM_PPC_RTAS_DEFINE_TOKEN _IOW(KVMIO, 0xac, struct kvm_rtas_token_args)
-/* Available with KVM_CAP_SPAPR_RESIZE_HPT */
-#define KVM_PPC_RESIZE_HPT_PREPARE _IOR(KVMIO, 0xad, struct kvm_ppc_resize_hpt)
-#define KVM_PPC_RESIZE_HPT_COMMIT _IOR(KVMIO, 0xae, struct kvm_ppc_resize_hpt)
-/* Available with KVM_CAP_PPC_MMU_RADIX or KVM_CAP_PPC_MMU_HASH_V3 */
-#define KVM_PPC_CONFIGURE_V3_MMU _IOW(KVMIO, 0xaf, struct kvm_ppc_mmuv3_cfg)
-/* Available with KVM_CAP_PPC_MMU_RADIX */
-#define KVM_PPC_GET_RMMU_INFO _IOW(KVMIO, 0xb0, struct kvm_ppc_rmmu_info)
-/* Available with KVM_CAP_PPC_GET_CPU_CHAR */
-#define KVM_PPC_GET_CPU_CHAR _IOR(KVMIO, 0xb1, struct kvm_ppc_cpu_char)
-/* Available with KVM_CAP_PMU_EVENT_FILTER */
-#define KVM_SET_PMU_EVENT_FILTER _IOW(KVMIO, 0xb2, struct kvm_pmu_event_filter)
-#define KVM_PPC_SVM_OFF _IO(KVMIO, 0xb3)
-#define KVM_ARM_MTE_COPY_TAGS _IOR(KVMIO, 0xb4, struct kvm_arm_copy_mte_tags)
-/* Available with KVM_CAP_COUNTER_OFFSET */
-#define KVM_ARM_SET_COUNTER_OFFSET _IOW(KVMIO, 0xb5, struct kvm_arm_counter_offset)
-#define KVM_ARM_GET_REG_WRITABLE_MASKS _IOR(KVMIO, 0xb6, struct reg_mask_range)
-
-/* ioctl for vm fd */
-#define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device)
-
-/* ioctls for fds returned by KVM_CREATE_DEVICE */
-#define KVM_SET_DEVICE_ATTR _IOW(KVMIO, 0xe1, struct kvm_device_attr)
-#define KVM_GET_DEVICE_ATTR _IOW(KVMIO, 0xe2, struct kvm_device_attr)
-#define KVM_HAS_DEVICE_ATTR _IOW(KVMIO, 0xe3, struct kvm_device_attr)
-
-/*
- * ioctls for vcpu fds
- */
-#define KVM_RUN _IO(KVMIO, 0x80)
-#define KVM_GET_REGS _IOR(KVMIO, 0x81, struct kvm_regs)
-#define KVM_SET_REGS _IOW(KVMIO, 0x82, struct kvm_regs)
-#define KVM_GET_SREGS _IOR(KVMIO, 0x83, struct kvm_sregs)
-#define KVM_SET_SREGS _IOW(KVMIO, 0x84, struct kvm_sregs)
-#define KVM_TRANSLATE _IOWR(KVMIO, 0x85, struct kvm_translation)
-#define KVM_INTERRUPT _IOW(KVMIO, 0x86, struct kvm_interrupt)
-#define KVM_GET_MSRS _IOWR(KVMIO, 0x88, struct kvm_msrs)
-#define KVM_SET_MSRS _IOW(KVMIO, 0x89, struct kvm_msrs)
-#define KVM_SET_CPUID _IOW(KVMIO, 0x8a, struct kvm_cpuid)
-#define KVM_SET_SIGNAL_MASK _IOW(KVMIO, 0x8b, struct kvm_signal_mask)
-#define KVM_GET_FPU _IOR(KVMIO, 0x8c, struct kvm_fpu)
-#define KVM_SET_FPU _IOW(KVMIO, 0x8d, struct kvm_fpu)
-#define KVM_GET_LAPIC _IOR(KVMIO, 0x8e, struct kvm_lapic_state)
-#define KVM_SET_LAPIC _IOW(KVMIO, 0x8f, struct kvm_lapic_state)
-#define KVM_SET_CPUID2 _IOW(KVMIO, 0x90, struct kvm_cpuid2)
-#define KVM_GET_CPUID2 _IOWR(KVMIO, 0x91, struct kvm_cpuid2)
-/* Available with KVM_CAP_VAPIC */
-#define KVM_TPR_ACCESS_REPORTING _IOWR(KVMIO, 0x92, struct kvm_tpr_access_ctl)
-/* Available with KVM_CAP_VAPIC */
-#define KVM_SET_VAPIC_ADDR _IOW(KVMIO, 0x93, struct kvm_vapic_addr)
-/* valid for virtual machine (for floating interrupt)_and_ vcpu */
-#define KVM_S390_INTERRUPT _IOW(KVMIO, 0x94, struct kvm_s390_interrupt)
-/* store status for s390 */
-#define KVM_S390_STORE_STATUS_NOADDR (-1ul)
-#define KVM_S390_STORE_STATUS_PREFIXED (-2ul)
-#define KVM_S390_STORE_STATUS _IOW(KVMIO, 0x95, unsigned long)
-/* initial ipl psw for s390 */
-#define KVM_S390_SET_INITIAL_PSW _IOW(KVMIO, 0x96, struct kvm_s390_psw)
-/* initial reset for s390 */
-#define KVM_S390_INITIAL_RESET _IO(KVMIO, 0x97)
-#define KVM_GET_MP_STATE _IOR(KVMIO, 0x98, struct kvm_mp_state)
-#define KVM_SET_MP_STATE _IOW(KVMIO, 0x99, struct kvm_mp_state)
-/* Available with KVM_CAP_USER_NMI */
-#define KVM_NMI _IO(KVMIO, 0x9a)
-/* Available with KVM_CAP_SET_GUEST_DEBUG */
-#define KVM_SET_GUEST_DEBUG _IOW(KVMIO, 0x9b, struct kvm_guest_debug)
-/* MCE for x86 */
-#define KVM_X86_SETUP_MCE _IOW(KVMIO, 0x9c, __u64)
-#define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO, 0x9d, __u64)
-#define KVM_X86_SET_MCE _IOW(KVMIO, 0x9e, struct kvm_x86_mce)
-/* Available with KVM_CAP_VCPU_EVENTS */
-#define KVM_GET_VCPU_EVENTS _IOR(KVMIO, 0x9f, struct kvm_vcpu_events)
-#define KVM_SET_VCPU_EVENTS _IOW(KVMIO, 0xa0, struct kvm_vcpu_events)
-/* Available with KVM_CAP_DEBUGREGS */
-#define KVM_GET_DEBUGREGS _IOR(KVMIO, 0xa1, struct kvm_debugregs)
-#define KVM_SET_DEBUGREGS _IOW(KVMIO, 0xa2, struct kvm_debugregs)
-/*
- * vcpu version available with KVM_CAP_ENABLE_CAP
- * vm version available with KVM_CAP_ENABLE_CAP_VM
- */
-#define KVM_ENABLE_CAP _IOW(KVMIO, 0xa3, struct kvm_enable_cap)
-/* Available with KVM_CAP_XSAVE */
-#define KVM_GET_XSAVE _IOR(KVMIO, 0xa4, struct kvm_xsave)
-#define KVM_SET_XSAVE _IOW(KVMIO, 0xa5, struct kvm_xsave)
-/* Available with KVM_CAP_XCRS */
-#define KVM_GET_XCRS _IOR(KVMIO, 0xa6, struct kvm_xcrs)
-#define KVM_SET_XCRS _IOW(KVMIO, 0xa7, struct kvm_xcrs)
-/* Available with KVM_CAP_SW_TLB */
-#define KVM_DIRTY_TLB _IOW(KVMIO, 0xaa, struct kvm_dirty_tlb)
-/* Available with KVM_CAP_ONE_REG */
-#define KVM_GET_ONE_REG _IOW(KVMIO, 0xab, struct kvm_one_reg)
-#define KVM_SET_ONE_REG _IOW(KVMIO, 0xac, struct kvm_one_reg)
-/* VM is being stopped by host */
-#define KVM_KVMCLOCK_CTRL _IO(KVMIO, 0xad)
-#define KVM_ARM_VCPU_INIT _IOW(KVMIO, 0xae, struct kvm_vcpu_init)
-#define KVM_ARM_PREFERRED_TARGET _IOR(KVMIO, 0xaf, struct kvm_vcpu_init)
-#define KVM_GET_REG_LIST _IOWR(KVMIO, 0xb0, struct kvm_reg_list)
-/* Available with KVM_CAP_S390_MEM_OP */
-#define KVM_S390_MEM_OP _IOW(KVMIO, 0xb1, struct kvm_s390_mem_op)
-/* Available with KVM_CAP_S390_SKEYS */
-#define KVM_S390_GET_SKEYS _IOW(KVMIO, 0xb2, struct kvm_s390_skeys)
-#define KVM_S390_SET_SKEYS _IOW(KVMIO, 0xb3, struct kvm_s390_skeys)
-/* Available with KVM_CAP_S390_INJECT_IRQ */
-#define KVM_S390_IRQ _IOW(KVMIO, 0xb4, struct kvm_s390_irq)
-/* Available with KVM_CAP_S390_IRQ_STATE */
-#define KVM_S390_SET_IRQ_STATE _IOW(KVMIO, 0xb5, struct kvm_s390_irq_state)
-#define KVM_S390_GET_IRQ_STATE _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state)
-/* Available with KVM_CAP_X86_SMM */
-#define KVM_SMI _IO(KVMIO, 0xb7)
-/* Available with KVM_CAP_S390_CMMA_MIGRATION */
-#define KVM_S390_GET_CMMA_BITS _IOWR(KVMIO, 0xb8, struct kvm_s390_cmma_log)
-#define KVM_S390_SET_CMMA_BITS _IOW(KVMIO, 0xb9, struct kvm_s390_cmma_log)
-/* Memory Encryption Commands */
-#define KVM_MEMORY_ENCRYPT_OP _IOWR(KVMIO, 0xba, unsigned long)
-
-struct kvm_enc_region {
- __u64 addr;
- __u64 size;
-};
-
-#define KVM_MEMORY_ENCRYPT_REG_REGION _IOR(KVMIO, 0xbb, struct kvm_enc_region)
-#define KVM_MEMORY_ENCRYPT_UNREG_REGION _IOR(KVMIO, 0xbc, struct kvm_enc_region)
-
-/* Available with KVM_CAP_HYPERV_EVENTFD */
-#define KVM_HYPERV_EVENTFD _IOW(KVMIO, 0xbd, struct kvm_hyperv_eventfd)
-
-/* Available with KVM_CAP_NESTED_STATE */
-#define KVM_GET_NESTED_STATE _IOWR(KVMIO, 0xbe, struct kvm_nested_state)
-#define KVM_SET_NESTED_STATE _IOW(KVMIO, 0xbf, struct kvm_nested_state)
-
-/* Available with KVM_CAP_MANUAL_DIRTY_LOG_PROTECT_2 */
-#define KVM_CLEAR_DIRTY_LOG _IOWR(KVMIO, 0xc0, struct kvm_clear_dirty_log)
-
-/* Available with KVM_CAP_HYPERV_CPUID (vcpu) / KVM_CAP_SYS_HYPERV_CPUID (system) */
-#define KVM_GET_SUPPORTED_HV_CPUID _IOWR(KVMIO, 0xc1, struct kvm_cpuid2)
-
-/* Available with KVM_CAP_ARM_SVE */
-#define KVM_ARM_VCPU_FINALIZE _IOW(KVMIO, 0xc2, int)
-
-/* Available with KVM_CAP_S390_VCPU_RESETS */
-#define KVM_S390_NORMAL_RESET _IO(KVMIO, 0xc3)
-#define KVM_S390_CLEAR_RESET _IO(KVMIO, 0xc4)
-
-/* Available with KVM_CAP_S390_PROTECTED */
-#define KVM_S390_PV_COMMAND _IOWR(KVMIO, 0xc5, struct kvm_pv_cmd)
-
-/* Available with KVM_CAP_X86_MSR_FILTER */
-#define KVM_X86_SET_MSR_FILTER _IOW(KVMIO, 0xc6, struct kvm_msr_filter)
-
-/* Available with KVM_CAP_DIRTY_LOG_RING */
-#define KVM_RESET_DIRTY_RINGS _IO(KVMIO, 0xc7)
-
-/* Per-VM Xen attributes */
-#define KVM_XEN_HVM_GET_ATTR _IOWR(KVMIO, 0xc8, struct kvm_xen_hvm_attr)
-#define KVM_XEN_HVM_SET_ATTR _IOW(KVMIO, 0xc9, struct kvm_xen_hvm_attr)
-
-/* Per-vCPU Xen attributes */
-#define KVM_XEN_VCPU_GET_ATTR _IOWR(KVMIO, 0xca, struct kvm_xen_vcpu_attr)
-#define KVM_XEN_VCPU_SET_ATTR _IOW(KVMIO, 0xcb, struct kvm_xen_vcpu_attr)
-
-/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
-#define KVM_XEN_HVM_EVTCHN_SEND _IOW(KVMIO, 0xd0, struct kvm_irq_routing_xen_evtchn)
-
-#define KVM_GET_SREGS2 _IOR(KVMIO, 0xcc, struct kvm_sregs2)
-#define KVM_SET_SREGS2 _IOW(KVMIO, 0xcd, struct kvm_sregs2)
-
-#define KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE (1 << 0)
-#define KVM_DIRTY_LOG_INITIALLY_SET (1 << 1)
-
-/*
- * Arch needs to define the macro after implementing the dirty ring
- * feature. KVM_DIRTY_LOG_PAGE_OFFSET should be defined as the
- * starting page offset of the dirty ring structures.
- */
-#ifndef KVM_DIRTY_LOG_PAGE_OFFSET
-#define KVM_DIRTY_LOG_PAGE_OFFSET 0
-#endif
-
-/*
- * KVM dirty GFN flags, defined as:
- *
- * |---------------+---------------+--------------|
- * | bit 1 (reset) | bit 0 (dirty) | Status |
- * |---------------+---------------+--------------|
- * | 0 | 0 | Invalid GFN |
- * | 0 | 1 | Dirty GFN |
- * | 1 | X | GFN to reset |
- * |---------------+---------------+--------------|
- *
- * Lifecycle of a dirty GFN goes like:
- *
- * dirtied harvested reset
- * 00 -----------> 01 -------------> 1X -------+
- * ^ |
- * | |
- * +------------------------------------------+
- *
- * The userspace program is only responsible for the 01->1X state
- * conversion after harvesting an entry. Also, it must not skip any
- * dirty bits, so that dirty bits are always harvested in sequence.
- */
-#define KVM_DIRTY_GFN_F_DIRTY _BITUL(0)
-#define KVM_DIRTY_GFN_F_RESET _BITUL(1)
-#define KVM_DIRTY_GFN_F_MASK 0x3
-
-/*
- * KVM dirty rings should be mapped at KVM_DIRTY_LOG_PAGE_OFFSET of
- * per-vcpu mmaped regions as an array of struct kvm_dirty_gfn. The
- * size of the gfn buffer is decided by the first argument when
- * enabling KVM_CAP_DIRTY_LOG_RING.
- */
-struct kvm_dirty_gfn {
- __u32 flags;
- __u32 slot;
- __u64 offset;
-};
-
-#define KVM_BUS_LOCK_DETECTION_OFF (1 << 0)
-#define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1)
-
-#define KVM_PMU_CAP_DISABLE (1 << 0)
-
-/**
- * struct kvm_stats_header - Header of per vm/vcpu binary statistics data.
- * @flags: Some extra information for header, always 0 for now.
- * @name_size: The size in bytes of the memory which contains statistics
- * name string including trailing '\0'. The memory is allocated
- * at the send of statistics descriptor.
- * @num_desc: The number of statistics the vm or vcpu has.
- * @id_offset: The offset of the vm/vcpu stats' id string in the file pointed
- * by vm/vcpu stats fd.
- * @desc_offset: The offset of the vm/vcpu stats' descriptor block in the file
- * pointd by vm/vcpu stats fd.
- * @data_offset: The offset of the vm/vcpu stats' data block in the file
- * pointed by vm/vcpu stats fd.
- *
- * This is the header userspace needs to read from stats fd before any other
- * readings. It is used by userspace to discover all the information about the
- * vm/vcpu's binary statistics.
- * Userspace reads this header from the start of the vm/vcpu's stats fd.
- */
-struct kvm_stats_header {
- __u32 flags;
- __u32 name_size;
- __u32 num_desc;
- __u32 id_offset;
- __u32 desc_offset;
- __u32 data_offset;
-};
-
-#define KVM_STATS_TYPE_SHIFT 0
-#define KVM_STATS_TYPE_MASK (0xF << KVM_STATS_TYPE_SHIFT)
-#define KVM_STATS_TYPE_CUMULATIVE (0x0 << KVM_STATS_TYPE_SHIFT)
-#define KVM_STATS_TYPE_INSTANT (0x1 << KVM_STATS_TYPE_SHIFT)
-#define KVM_STATS_TYPE_PEAK (0x2 << KVM_STATS_TYPE_SHIFT)
-#define KVM_STATS_TYPE_LINEAR_HIST (0x3 << KVM_STATS_TYPE_SHIFT)
-#define KVM_STATS_TYPE_LOG_HIST (0x4 << KVM_STATS_TYPE_SHIFT)
-#define KVM_STATS_TYPE_MAX KVM_STATS_TYPE_LOG_HIST
-
-#define KVM_STATS_UNIT_SHIFT 4
-#define KVM_STATS_UNIT_MASK (0xF << KVM_STATS_UNIT_SHIFT)
-#define KVM_STATS_UNIT_NONE (0x0 << KVM_STATS_UNIT_SHIFT)
-#define KVM_STATS_UNIT_BYTES (0x1 << KVM_STATS_UNIT_SHIFT)
-#define KVM_STATS_UNIT_SECONDS (0x2 << KVM_STATS_UNIT_SHIFT)
-#define KVM_STATS_UNIT_CYCLES (0x3 << KVM_STATS_UNIT_SHIFT)
-#define KVM_STATS_UNIT_BOOLEAN (0x4 << KVM_STATS_UNIT_SHIFT)
-#define KVM_STATS_UNIT_MAX KVM_STATS_UNIT_BOOLEAN
-
-#define KVM_STATS_BASE_SHIFT 8
-#define KVM_STATS_BASE_MASK (0xF << KVM_STATS_BASE_SHIFT)
-#define KVM_STATS_BASE_POW10 (0x0 << KVM_STATS_BASE_SHIFT)
-#define KVM_STATS_BASE_POW2 (0x1 << KVM_STATS_BASE_SHIFT)
-#define KVM_STATS_BASE_MAX KVM_STATS_BASE_POW2
-
-/**
- * struct kvm_stats_desc - Descriptor of a KVM statistics.
- * @flags: Annotations of the stats, like type, unit, etc.
- * @exponent: Used together with @flags to determine the unit.
- * @size: The number of data items for this stats.
- * Every data item is of type __u64.
- * @offset: The offset of the stats to the start of stat structure in
- * structure kvm or kvm_vcpu.
- * @bucket_size: A parameter value used for histogram stats. It is only used
- * for linear histogram stats, specifying the size of the bucket;
- * @name: The name string for the stats. Its size is indicated by the
- * &kvm_stats_header->name_size.
- */
-struct kvm_stats_desc {
- __u32 flags;
- __s16 exponent;
- __u16 size;
- __u32 offset;
- __u32 bucket_size;
-#ifdef __KERNEL__
- char name[KVM_STATS_NAME_SIZE];
-#else
- char name[];
-#endif
-};
-
-#define KVM_GET_STATS_FD _IO(KVMIO, 0xce)
-
-/* Available with KVM_CAP_XSAVE2 */
-#define KVM_GET_XSAVE2 _IOR(KVMIO, 0xcf, struct kvm_xsave)
-
-/* Available with KVM_CAP_S390_PROTECTED_DUMP */
-#define KVM_S390_PV_CPU_COMMAND _IOWR(KVMIO, 0xd0, struct kvm_pv_cmd)
-
-/* Available with KVM_CAP_X86_NOTIFY_VMEXIT */
-#define KVM_X86_NOTIFY_VMEXIT_ENABLED (1ULL << 0)
-#define KVM_X86_NOTIFY_VMEXIT_USER (1ULL << 1)
-
-/* Available with KVM_CAP_S390_ZPCI_OP */
-#define KVM_S390_ZPCI_OP _IOW(KVMIO, 0xd1, struct kvm_s390_zpci_op)
-
-/* Available with KVM_CAP_MEMORY_ATTRIBUTES */
-#define KVM_SET_MEMORY_ATTRIBUTES _IOW(KVMIO, 0xd2, struct kvm_memory_attributes)
-
-struct kvm_memory_attributes {
- __u64 address;
- __u64 size;
- __u64 attributes;
- __u64 flags;
-};
-
-#define KVM_MEMORY_ATTRIBUTE_PRIVATE (1ULL << 3)
-
-#define KVM_CREATE_GUEST_MEMFD _IOWR(KVMIO, 0xd4, struct kvm_create_guest_memfd)
-#define GUEST_MEMFD_FLAG_MMAP (1ULL << 0)
-#define GUEST_MEMFD_FLAG_INIT_SHARED (1ULL << 1)
-
-struct kvm_create_guest_memfd {
- __u64 size;
- __u64 flags;
- __u64 reserved[6];
-};
-
-#define KVM_PRE_FAULT_MEMORY _IOWR(KVMIO, 0xd5, struct kvm_pre_fault_memory)
-
-struct kvm_pre_fault_memory {
- __u64 gpa;
- __u64 size;
- __u64 flags;
- __u64 padding[5];
-};
+#include <linux/kvm-generic.h>
#endif /* __LINUX_KVM_H */
--git a/scripts/Makefile.asm-headers b/scripts/Makefile.asm-headers
index 8a4856e74180..6482028624e4 100644
--- a/scripts/Makefile.asm-headers
+++ b/scripts/Makefile.asm-headers
@@ -46,14 +46,18 @@ generic-y += $(foreach f, $(mandatory-y), $(if $(wildcard $(src)/$(f)),,$(f)))
generic-y := $(addprefix $(obj)/, $(generic-y))
syscall-y := $(addprefix $(obj)/, $(syscall-y))
generated-y := $(addprefix $(obj)/, $(generated-y))
+shared-uapi-y := $(addprefix $(obj)/, $(shared-uapi-y))
# Remove stale wrappers when the corresponding files are removed from generic-y
old-headers := $(wildcard $(obj)/*.h)
-unwanted := $(filter-out $(generic-y) $(generated-y) $(syscall-y),$(old-headers))
+unwanted := $(filter-out $(generic-y) $(generated-y) $(syscall-y) $(shared-uapi-y),$(old-headers))
quiet_cmd_wrap = WRAP $@
cmd_wrap = echo "\#include <asm-generic/$*.h>" > $@
+quiet_cmd_share_hdr = SHARE $@
+ cmd_share_hdr = cp $< $@
+
quiet_cmd_remove = REMOVE $(unwanted)
cmd_remove = rm -f $(unwanted)
@@ -70,13 +74,19 @@ quiet_cmd_systbl = SYSTBL $@
--abis $(subst $(space),$(comma),$(strip $(syscall_abis_$*))) \
$< $@
-all: $(generic-y) $(syscall-y)
+all: $(generic-y) $(syscall-y) $(shared-uapi-y)
$(if $(unwanted),$(call cmd,remove))
@:
$(obj)/%.h: $(srctree)/$(generic)/%.h
$(call cmd,wrap)
+# Let architectures define architecture specific headers that can be shared
+# with other architectures to enable single-system cross architecture communication
+shared-uapi-dest := $(srctree)/include/uapi/arch/$(SRCARCH)/asm
+$(shared-uapi-y): $(obj)/%.h: $(shared-uapi-dest)/%.h FORCE
+ $(call if_changed,share_hdr)
+
$(obj)/unistd_%.h: $(syscalltbl) $(syshdr) FORCE
$(call if_changed,syshdr)
diff --git a/usr/include/Makefile b/usr/include/Makefile
index 6d86a53c6f0a..c080447f8126 100644
--- a/usr/include/Makefile
+++ b/usr/include/Makefile
@@ -24,6 +24,7 @@ no-header-test += linux/cyclades.h
no-header-test += linux/errqueue.h
no-header-test += linux/hdlc/ioctl.h
no-header-test += linux/ivtv.h
+no-header-test += linux/kvm-generic.h
no-header-test += linux/matroxfb.h
no-header-test += linux/omap3isp.h
no-header-test += linux/omapfb.h
--
2.51.0
^ permalink raw reply related
* [PATCH v2 24/28] KVM: s390: arm64: Implement required functions
From: Steffen Eiden @ 2026-04-28 15:56 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: <20260428155622.1361364-1-seiden@linux.ibm.com>
Implement the mostly trivial functions that the shared arm64 (kvm)
headers oblige s390 to implement.
Implement a very basic smccc handler that (non-compliantly) is just able
to stop a vcpu.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/include/asm/kvm_emulate.h | 135 ++++++++++++++++++++++++++++
arch/s390/include/asm/kvm_mmu.h | 12 +++
arch/s390/include/asm/kvm_nested.h | 13 +++
arch/s390/kvm/arm64/handle_exit.c | 50 +++++++++++
arch/s390/kvm/arm64/inject_fault.c | 21 +++++
5 files changed, 231 insertions(+)
create mode 100644 arch/s390/include/asm/kvm_emulate.h
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/kvm/arm64/handle_exit.c
create mode 100644 arch/s390/kvm/arm64/inject_fault.c
diff --git a/arch/s390/include/asm/kvm_emulate.h b/arch/s390/include/asm/kvm_emulate.h
new file mode 100644
index 000000000000..bf019005e137
--- /dev/null
+++ b/arch/s390/include/asm/kvm_emulate.h
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Emulation functionality for arm64 guests.
+ */
+
+#ifndef __S390_ARM64_KVM_EMULATE_H__
+#define __S390_ARM64_KVM_EMULATE_H__
+
+#include <asm/fault.h>
+#include <asm/ptrace.h>
+#include <linux/kvm_host.h>
+
+#include <kvm/arm64/kvm_arm.h>
+#include <kvm/arm64/kvm_emulate.h>
+
+static __always_inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
+{
+ return (unsigned long *)&vcpu->arch.sae_block.pc;
+}
+
+static __always_inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
+{
+ return (unsigned long *)&vcpu->arch.sae_block.pstate;
+}
+
+static __always_inline unsigned long *vcpu_sp_el0(const struct kvm_vcpu *vcpu)
+{
+ return (unsigned long *)&vcpu->arch.sae_block.sp_el0;
+}
+
+static __always_inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+
+static __always_inline u64 kvm_vcpu_get_esr(const struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.sae_block.hai.esr_elz;
+}
+
+static __always_inline unsigned long kvm_vcpu_get_hfar(const struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.sae_block.hai.far_elz;
+}
+
+static __always_inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.sae_block.hai.teid.addr * PAGE_SIZE;
+}
+
+static inline u16 kvm_vcpu_fault_pic(const struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.sae_block.hai.pic & PGM_INT_CODE_MASK;
+}
+
+/* Should be unreachable, arm64 on s390 does not claim KVM_CAP_ARM_NISV_TO_USER*/
+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);
+}
+
+static __always_inline
+bool kvm_vcpu_trap_is_permission_fault(const struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_fault_pic(vcpu) == PGM_PROTECTION;
+}
+
+static __always_inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)
+{
+ return true;
+}
+
+static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+
+static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.hcr_elz = HCR_E2H | HCR_RW | HCR_PTW;
+ /* traps */
+ vcpu->arch.hcr_elz |= HCR_TSC | HCR_TID1 | HCR_TID2 | HCR_TID3 |
+ HCR_TID4 | HCR_TID5 | HCR_TIDCP;
+}
+
+static inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu)
+{
+ WARN(true, "not implemented, just feat RAS");
+
+ return 0L;
+}
+
+static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
+{
+ WARN(true, "not implemented, just feat RAS");
+}
+
+static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
+{
+ return (unsigned long *)&vcpu->arch.hcr_elz;
+}
+
+static inline bool vcpu_el2_tge_is_set(const struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+
+static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+
+static inline int kvm_vcpu_abt_gltl(struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.sae_block.hai.gltl;
+}
+
+static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+
+static inline bool is_nested_ctxt(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+
+static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
+{
+ u32 mode = *vcpu_cpsr(vcpu) & PSR_MODE_MASK;
+
+ return mode != PSR_MODE_EL0t;
+}
+
+#endif /* __S390_ARM64_KVM_EMULATE_H__ */
diff --git a/arch/s390/include/asm/kvm_mmu.h b/arch/s390/include/asm/kvm_mmu.h
new file mode 100644
index 000000000000..ac354fd5bac9
--- /dev/null
+++ b/arch/s390/include/asm/kvm_mmu.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * KVM MMU for arm64 guests.
+ */
+#ifndef __S390_ARM64_KVM_MMU_H__
+#define __S390_ARM64_KVM_MMU_H__
+
+#include <linux/kvm_host.h>
+
+#include <kvm/arm64/kvm_mmu.h>
+
+#endif /* __S390_ARM64_KVM_MMU_H__ */
diff --git a/arch/s390/include/asm/kvm_nested.h b/arch/s390/include/asm/kvm_nested.h
new file mode 100644
index 000000000000..7158932e718b
--- /dev/null
+++ b/arch/s390/include/asm/kvm_nested.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Nested KVM for arm64 guests. (Not supported by s390)
+ */
+#ifndef ASM_KVM_NESTED_H
+#define ASM_KVM_NESTED_H
+
+static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+
+#endif /* ASM_KVM_NESTED_H */
diff --git a/arch/s390/kvm/arm64/handle_exit.c b/arch/s390/kvm/arm64/handle_exit.c
new file mode 100644
index 000000000000..89933a604876
--- /dev/null
+++ b/arch/s390/kvm/arm64/handle_exit.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kvm_host.h>
+
+#include <asm/esr.h>
+#include <asm/kvm_emulate.h>
+
+#include <kvm/arm64/handle_exit.h>
+
+#define PSCI_0_2_FN_SYSTEM_OFF 0x84000008
+#define PSCI_RET_NOT_SUPPORTED -1
+#define PSCI_RET_INTERNAL_FAILURE -6
+/*
+ * Temporary smc/hvc handler. Non-compliant implementation (features missing).
+ * Implements only system off so that test programs are able to end their execution
+ */
+static int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
+{
+ u32 func_id = vcpu_get_reg(vcpu, 0);
+ u64 val = PSCI_RET_NOT_SUPPORTED;
+ int ret = 1;
+
+ if (func_id == PSCI_0_2_FN_SYSTEM_OFF) {
+ spin_lock(&vcpu->arch.mp_state_lock);
+ WRITE_ONCE(vcpu->arch.mp_state.mp_state, KVM_MP_STATE_STOPPED);
+ spin_unlock(&vcpu->arch.mp_state_lock);
+ kvm_make_all_cpus_request(vcpu->kvm, KVM_REQ_SLEEP);
+ memset(&vcpu->run->system_event, 0,
+ sizeof(vcpu->run->system_event));
+ vcpu->run->system_event.type = KVM_SYSTEM_EVENT_SHUTDOWN;
+ vcpu->run->system_event.ndata = 1;
+ vcpu->run->system_event.data[0] = 0;
+ vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
+ val = PSCI_RET_INTERNAL_FAILURE;
+ ret = 0;
+ }
+ vcpu_set_reg(vcpu, 0, val);
+
+ return ret;
+}
+
+static int handle_hvc(struct kvm_vcpu *vcpu)
+{
+ vcpu->stat.hvc_exit_stat++;
+ return kvm_smccc_call_handler(vcpu);
+}
+
+exit_handle_fn arm_exit_handlers[] = {
+ [0 ... ESR_ELx_EC_MAX] = kvm_handle_unknown_ec,
+ [ESR_ELx_EC_HVC64] = handle_hvc,
+};
diff --git a/arch/s390/kvm/arm64/inject_fault.c b/arch/s390/kvm/arm64/inject_fault.c
new file mode 100644
index 000000000000..650c041efde2
--- /dev/null
+++ b/arch/s390/kvm/arm64/inject_fault.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <asm/kvm_emulate.h>
+
+/**
+ * kvm_inject_undefined - inject an undefined instruction into the guest
+ * @vcpu: The vCPU in which to inject the exception
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+void kvm_inject_undefined(struct kvm_vcpu *vcpu)
+{
+ /* Stub until s390 supports arm64 sysregs TODO sysregs*/
+}
+
+int kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr)
+{
+ /* Stub until s390 supports arm64 sysregs TODO sysregs*/
+ return 1;
+}
--
2.51.0
^ permalink raw reply related
* [PATCH v2 13/28] KVM: arm64: Extract & share ipa size shift calculation
From: Steffen Eiden @ 2026-04-28 15:56 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: <20260428155622.1361364-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 | 19 ++++++-------------
include/kvm/arm64/kvm_host.h | 1 +
virt/kvm/arm64/arm.c | 21 +++++++++++++++++++++
3 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index e19ff77b3cd5..bec52291bc0c 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -874,27 +874,20 @@ 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 d36ebea4d60f..8bf399508757 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 v2 23/28] KVM: s390: Add basic arm64 kvm module
From: Steffen Eiden @ 2026-04-28 15:56 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: <20260428155622.1361364-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 v2 27/28] KVM: s390: arm64: Implement basic page fault handler
From: Steffen Eiden @ 2026-04-28 15:56 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: <20260428155622.1361364-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 | 178 ++++++++++++++++++++++++++++++
3 files changed, 181 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 b629bef84eda..e15dad763847 100644
--- a/arch/s390/kvm/arm64/arm.c
+++ b/arch/s390/kvm/arm64/arm.c
@@ -429,6 +429,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..8759cbafbaff
--- /dev/null
+++ b/arch/s390/kvm/arm64/mmu.c
@@ -0,0 +1,178 @@
+// 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;
+}
+
+static int kvm_handle_pic(struct kvm_vcpu *vcpu, bool *translation)
+{
+ 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;
+ }
+
+ return 0;
+}
+
+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 guest_size_err;
+ 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);
+ guest_size_err = vcpu->arch.sae_block.icptr == SAE_ICPTR_GUEST_ADDRESS_SIZE;
+
+ if (guest_size_err) {
+ translation = true;
+ } else {
+ ret = kvm_handle_pic(vcpu, &translation);
+ if (ret)
+ return ret;
+ }
+
+ 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;
+ }
+
+ /* Userspace should not be able to register out-of-bounds IPAs */
+ VM_BUG_ON(fault_ipa >= kvm_phys_size(vcpu->kvm));
+ /*
+ * Proper guest size faults have been injected.
+ * In theory it's fine to have device memory higher than MSL,
+ * even if not currently possible, but that would have been handled above.
+ * So if we get here with a guest size intercept, we have a bug somewhere.
+ */
+ VM_BUG_ON(guest_size_err);
+
+ 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 v2 00/28] KVM: s390: Introduce arm64 KVM
From: Steffen Eiden @ 2026-04-28 15:55 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
since v1:
- moved mispositioned kvm_supports_32bit_el0 from shared to s390 (thanks Marc)
- various small issues fixed (non exhaustive)
- un-move macros creating arm instructions from sysreg-defs.h back to sysreg.h
- reset sp register
- use 'a' inline asm modifier for address registers in stiasrm and lasrm
- clear x2 after SAE exit
- fix unnecessary recompilations of the kvm-arm64 module
- Add Steffen to KVM/arm64 reviewer
- Rebased onto & included Paolos latest vfio series
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 (21):
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
MAINTAINERS: Add Steffen as reviewer for KVM/arm64
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 | 6 +
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 | 960 +---------
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 | 21 +-
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/debug_defconfig | 2 +-
arch/s390/configs/defconfig | 3 +-
arch/s390/include/asm/Kbuild | 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 | 202 ++
arch/s390/include/asm/kvm_host_arm64_types.h | 129 ++
.../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 | 35 +-
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 | 21 +
arch/s390/kvm/arm64/Makefile | 108 ++
arch/s390/kvm/arm64/arm.c | 698 +++++++
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 | 21 +
arch/s390/kvm/arm64/mmu.c | 178 ++
arch/s390/kvm/arm64/reset.c | 45 +
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 | 26 +-
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 | 51 +-
.../arch/arm64}/asm/brk-imm.h | 6 +-
.../include => include/arch/arm64}/asm/esr.h | 62 +-
include/arch/arm64/asm/pstate.h | 46 +
.../arch/arm64/asm/sysreg-defs.h | 351 +---
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 | 197 ++
include/kvm/arm64/kvm_mmu.h | 47 +
include/kvm/arm64/reset.h | 8 +
include/linux/kvm_host.h | 17 +-
include/linux/kvm_types.h | 30 +
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 | 43 +
virt/kvm/arm64/trace.h | 42 +
virt/kvm/coalesced_mmio.c | 3 +
virt/kvm/coalesced_mmio.h | 2 +-
virt/kvm/kvm_main.c | 63 +-
virt/kvm/vfio.c | 4 +-
159 files changed, 3879 insertions(+), 5125 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 (61%)
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 (92%)
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 (79%)
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: 7f87a5ea75f011d2c9bc8ac0167e5e2d1adb1594
--
2.51.0
^ permalink raw reply
* [PATCH v2 09/28] KVM: arm64: Share kvm_emulate definitions
From: Steffen Eiden @ 2026-04-28 15:56 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: <20260428155622.1361364-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 v2 12/28] KVM: arm64: Share reset general register code
From: Steffen Eiden @ 2026-04-28 15:56 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: <20260428155622.1361364-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 | 34 +----------
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 | 43 ++++++++++++++
7 files changed, 155 insertions(+), 118 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 e952dec01d74..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,23 +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;
- *vcpu_sp_el0(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 d1eccbe44c50..d36ebea4d60f 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)
+
#define vcpu_is_protected(vcpu) kvm_vm_is_protected((vcpu)->kvm)
/*
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..257f28373566
--- /dev/null
+++ b/virt/kvm/arm64/reset.c
@@ -0,0 +1,43 @@
+// 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;
+ *vcpu_sp_el0(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 v2 14/28] MAINTAINERS: Add Steffen as reviewer for KVM/arm64
From: Steffen Eiden @ 2026-04-28 15:56 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: <20260428155622.1361364-1-seiden@linux.ibm.com>
KVM/arm64 and KVM/s390 now share some code.Add me as a cross-reviewer
from the s390 team to arm64 to help to keep both architectures in sync.
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 9cb2b50d24b7..9cb4942c7d7b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13994,6 +13994,7 @@ KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
M: Marc Zyngier <maz@kernel.org>
M: Oliver Upton <oupton@kernel.org>
R: Joey Gouly <joey.gouly@arm.com>
+R: Steffen Eiden <seiden@linux.ibm.com>
R: Suzuki K Poulose <suzuki.poulose@arm.com>
R: Zenghui Yu <yuzenghui@huawei.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
--
2.51.0
^ permalink raw reply related
* [PATCH v2 11/28] KVM: arm64: Access elements of vcpu_gp_regs individually
From: Steffen Eiden @ 2026-04-28 15:56 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: <20260428155622.1361364-1-seiden@linux.ibm.com>
While for arm64 the members of vcpu_gp_regs are allocated continuous
this is not necessarily true for other architectures implementing ARM.
Let vcpu_gp_regs() no longer return the address of the user_pt_regs in
the vcpu context but the address of the gp-register array field in the
user_pt_reg struct.
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 | 9 +++++++--
arch/arm64/include/asm/kvm_host.h | 2 +-
arch/arm64/kvm/hyp/exception.c | 7 +++++--
arch/arm64/kvm/hyp/include/hyp/adjust_pc.h | 4 ++--
arch/arm64/kvm/hyp/include/hyp/switch.h | 6 +++---
arch/arm64/kvm/reset.c | 6 ++++--
include/kvm/arm64/kvm_emulate.h | 4 ++--
virt/kvm/arm64/guest.c | 6 +++---
8 files changed, 27 insertions(+), 17 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 39fa3a12730c..41eac2b5de14 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -95,12 +95,17 @@ static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
static __always_inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
{
- return (unsigned long *)&vcpu_gp_regs(vcpu)->pc;
+ return (unsigned long *)&vcpu->arch.ctxt.regs.pc;
}
static __always_inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
{
- return (unsigned long *)&vcpu_gp_regs(vcpu)->pstate;
+ return (unsigned long *)&vcpu->arch.ctxt.regs.pstate;
+}
+
+static __always_inline unsigned long *vcpu_sp_el0(const struct kvm_vcpu *vcpu)
+{
+ return (unsigned long *)&vcpu->arch.ctxt.regs.sp;
}
static __always_inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ae9e507f2c7c..7e473b895740 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1050,7 +1050,7 @@ struct kvm_vcpu_arch {
#define vcpu_clear_on_unsupported_cpu(vcpu) \
vcpu_clear_flag(vcpu, ON_UNSUPPORTED_CPU)
-#define vcpu_gp_regs(v) (&(v)->arch.ctxt.regs)
+#define vcpu_gp_regs(v) ((v)->arch.ctxt.regs.regs)
/*
* Only use __vcpu_sys_reg/ctxt_sys_reg if you know you want the
diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c
index bef40ddb16db..82611442a2d1 100644
--- a/arch/arm64/kvm/hyp/exception.c
+++ b/arch/arm64/kvm/hyp/exception.c
@@ -277,6 +277,9 @@ static const u8 return_offsets[8][2] = {
[7] = { 4, 4 }, /* FIQ, unused */
};
+#define OFFSETOF_PT_REG(__r) offsetof(struct user_pt_regs, __r)
+#define COMPAT_IDX(__c) ((OFFSETOF_PT_REG(__c) - OFFSETOF_PT_REG(regs[0])) / sizeof(u64))
+
static void enter_exception32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
{
unsigned long spsr = *vcpu_cpsr(vcpu);
@@ -292,12 +295,12 @@ static void enter_exception32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
switch(mode) {
case PSR_AA32_MODE_ABT:
__vcpu_write_spsr_abt(vcpu, host_spsr_to_spsr32(spsr));
- vcpu_gp_regs(vcpu)->compat_lr_abt = return_address;
+ vcpu_gp_regs(vcpu)[COMPAT_IDX(compat_lr_abt)] = return_address;
break;
case PSR_AA32_MODE_UND:
__vcpu_write_spsr_und(vcpu, host_spsr_to_spsr32(spsr));
- vcpu_gp_regs(vcpu)->compat_lr_und = return_address;
+ vcpu_gp_regs(vcpu)[COMPAT_IDX(compat_lr_und)] = return_address;
break;
}
diff --git a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
index 15e1e5db73e1..4e4cb67824c0 100644
--- a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
+++ b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
@@ -20,11 +20,11 @@
static inline void __kvm_skip_instr(struct kvm_vcpu *vcpu)
{
*vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);
- vcpu_gp_regs(vcpu)->pstate = read_sysreg_el2(SYS_SPSR);
+ *vcpu_cpsr(vcpu) = read_sysreg_el2(SYS_SPSR);
kvm_skip_instr(vcpu);
- write_sysreg_el2(vcpu_gp_regs(vcpu)->pstate, SYS_SPSR);
+ write_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);
write_sysreg_el2(*vcpu_pc(vcpu), SYS_ELR);
}
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 2597e8bda867..6250b50e1841 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -416,7 +416,7 @@ static inline bool __populate_fault_info(struct kvm_vcpu *vcpu)
static inline bool kvm_hyp_handle_mops(struct kvm_vcpu *vcpu, u64 *exit_code)
{
*vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);
- arm64_mops_reset_regs(vcpu_gp_regs(vcpu), vcpu->arch.fault.esr_el2);
+ arm64_mops_reset_regs(&vcpu->arch.ctxt.regs, vcpu->arch.fault.esr_el2);
write_sysreg_el2(*vcpu_pc(vcpu), SYS_ELR);
/*
@@ -857,7 +857,7 @@ static inline void synchronize_vcpu_pstate(struct kvm_vcpu *vcpu)
/*
* Check for the conditions of Cortex-A510's #2077057. When these occur
* SPSR_EL2 can't be trusted, but isn't needed either as it is
- * unchanged from the value in vcpu_gp_regs(vcpu)->pstate.
+ * unchanged from the value in vcpu_cpsr(vcpu).
* Are we single-stepping the guest, and took a PAC exception from the
* active-not-pending state?
*/
@@ -867,7 +867,7 @@ static inline void synchronize_vcpu_pstate(struct kvm_vcpu *vcpu)
ESR_ELx_EC(read_sysreg_el2(SYS_ESR)) == ESR_ELx_EC_PAC)
write_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);
- vcpu->arch.ctxt.regs.pstate = read_sysreg_el2(SYS_SPSR);
+ *vcpu_cpsr(vcpu) = read_sysreg_el2(SYS_SPSR);
}
/*
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 036bf2dff976..e952dec01d74 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -218,13 +218,15 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu)
pstate = VCPU_RESET_PSTATE_EL1;
/* Reset core registers */
- memset(vcpu_gp_regs(vcpu), 0, sizeof(*vcpu_gp_regs(vcpu)));
+ memset(vcpu_gp_regs(vcpu), 0, sizeof(vcpu_gp_regs(vcpu)));
+ *vcpu_pc(vcpu) = 0;
+ *vcpu_sp_el0(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_gp_regs(vcpu)->pstate = pstate;
+ *vcpu_cpsr(vcpu) = pstate;
/* Reset system registers */
kvm_reset_sys_regs(vcpu);
diff --git a/include/kvm/arm64/kvm_emulate.h b/include/kvm/arm64/kvm_emulate.h
index 25322b95af21..0e16d18e53d2 100644
--- a/include/kvm/arm64/kvm_emulate.h
+++ b/include/kvm/arm64/kvm_emulate.h
@@ -77,14 +77,14 @@ static inline void kvm_skip_instr(struct kvm_vcpu *vcpu)
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];
+ return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)[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;
+ vcpu_gp_regs(vcpu)[reg_num] = val;
}
static inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm64/guest.c b/virt/kvm/arm64/guest.c
index 83e33e0143b9..e283a4456df8 100644
--- a/virt/kvm/arm64/guest.c
+++ b/virt/kvm/arm64/guest.c
@@ -81,16 +81,16 @@ static void *core_reg_addr(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
KVM_REG_ARM_CORE_REG(regs.regs[30]):
off -= KVM_REG_ARM_CORE_REG(regs.regs[0]);
off /= 2;
- return &vcpu_gp_regs(vcpu)->regs[off];
+ return &vcpu_gp_regs(vcpu)[off];
case KVM_REG_ARM_CORE_REG(regs.sp):
- return &vcpu_gp_regs(vcpu)->sp;
+ return vcpu_sp_el0(vcpu);
case KVM_REG_ARM_CORE_REG(regs.pc):
return vcpu_pc(vcpu);
case KVM_REG_ARM_CORE_REG(regs.pstate):
- return &vcpu_gp_regs(vcpu)->pstate;
+ return vcpu_cpsr(vcpu);
case KVM_REG_ARM_CORE_REG(sp_el1):
return __ctxt_sys_reg(&vcpu->arch.ctxt, SP_EL1);
--
2.51.0
^ permalink raw reply related
* [PATCH v2 19/28] KVM: s390: Prepare kvm-s390 for a second kvm module
From: Steffen Eiden @ 2026-04-28 15:56 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: <20260428155622.1361364-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 0e325b47d40e..5373b2347651 100644
--- a/arch/s390/kvm/s390/s390.c
+++ b/arch/s390/kvm/s390/s390.c
@@ -5677,6 +5677,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 v2 06/28] arm64: Provide arm64 API for non-native architectures
From: Steffen Eiden @ 2026-04-28 15:55 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: <20260428155622.1361364-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 | 6 +-
.../include => include/arch/arm64}/asm/esr.h | 62 +++++++++++++++++--
.../arch/arm64}/asm/sysreg-defs.h | 6 +-
6 files changed, 65 insertions(+), 65 deletions(-)
rename {arch/arm64/include => include/arch/arm64}/asm/brk-imm.h (92%)
rename {arch/arm64/include => include/arch/arm64}/asm/esr.h (88%)
rename {arch/arm64/include => include/arch/arm64}/asm/sysreg-defs.h (99%)
diff --git a/MAINTAINERS b/MAINTAINERS
index 0752e340e569..b58399be11f7 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 92%
rename from arch/arm64/include/asm/brk-imm.h
rename to include/arch/arm64/asm/brk-imm.h
index beb42c62b6ac..c311085886f5 100644
--- a/arch/arm64/include/asm/brk-imm.h
+++ b/include/arch/arm64/asm/brk-imm.h
@@ -3,8 +3,8 @@
* Copyright (C) 2012 ARM Ltd.
*/
-#ifndef __ASM_BRK_IMM_H
-#define __ASM_BRK_IMM_H
+#ifndef __ARM64_ASM_BRK_IMM_H
+#define __ARM64_ASM_BRK_IMM_H
/*
* #imm16 values used for BRK instruction generation
@@ -39,4 +39,4 @@
#define CFI_BRK_IMM_BASE 0x8000
#define CFI_BRK_IMM_MASK (CFI_BRK_IMM_TARGET | CFI_BRK_IMM_TYPE)
-#endif
+#endif /* __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..a7421cc966f9 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/include/arch/arm64/asm/esr.h
@@ -4,11 +4,12 @@
* Author: Marc Zyngier <marc.zyngier@arm.com>
*/
-#ifndef __ASM_ESR_H
-#define __ASM_ESR_H
+#ifndef __ARM64_ASM_ESR_H
+#define __ARM64_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 */
+#endif /* __ARM64_ASM_ESR_H */
diff --git a/arch/arm64/include/asm/sysreg-defs.h b/include/arch/arm64/asm/sysreg-defs.h
similarity index 99%
rename from arch/arm64/include/asm/sysreg-defs.h
rename to include/arch/arm64/asm/sysreg-defs.h
index 311f882a992b..399ff6897c1b 100644
--- a/arch/arm64/include/asm/sysreg-defs.h
+++ b/include/arch/arm64/asm/sysreg-defs.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-#ifndef __ASM_SYSREG_DEFS_H
-#define __ASM_SYSREG_DEFS_H
+#ifndef __ARM64_ASM_SYSREG_DEFS_H
+#define __ARM64_ASM_SYSREG_DEFS_H
#include <linux/bits.h>
@@ -968,4 +968,4 @@
FIELD_PREP(reg##_##field##_MASK, \
SYS_FIELD_VALUE(reg, field, val))
#endif /* __ASSEMBLER__ */
-#endif /* __ASM_SYSREG_DEFS_H */
+#endif /* __ARM64_ASM_SYSREG_DEFS_H */
--
2.51.0
^ permalink raw reply related
* [PATCH v2 18/28] KVM: Remove KVM_MMIO as config option
From: Steffen Eiden @ 2026-04-28 15:56 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: <20260428155622.1361364-1-seiden@linux.ibm.com>
Defining KVM_MMIO is not flexible enough for multi-KVM systems with
different Kconfig options regarding KVM_MMIO. Therefore, remove KVM_MMIO
from the config space and use the macro HAVE_KVM_MMIO instead.
Suggested-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/arm64/include/asm/kvm_host.h | 2 ++
arch/arm64/kvm/Kconfig | 1 -
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/x86/include/asm/kvm_host.h | 2 ++
arch/x86/kvm/Kconfig | 1 -
include/linux/kvm_host.h | 2 +-
virt/kvm/Kconfig | 3 ---
virt/kvm/Makefile.kvm | 3 +--
virt/kvm/coalesced_mmio.c | 3 +++
virt/kvm/coalesced_mmio.h | 2 +-
virt/kvm/kvm_main.c | 8 ++++----
18 files changed, 27 insertions(+), 20 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index e3a2ac3979ac..39630e235a36 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -33,6 +33,8 @@
#define KVM_HALT_POLL_NS_DEFAULT 500000
+#define HAVE_KVM_MMIO
+
#include <kvm/arm_vgic.h>
#include <kvm/arm_arch_timer.h>
#include <kvm/arm_pmu.h>
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 7d1f22fd490b..4761b5e7e75b 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -22,7 +22,6 @@ menuconfig KVM
select KVM_COMMON
select KVM_GENERIC_HARDWARE_ENABLING
select HAVE_KVM_CPU_RELAX_INTERCEPT
- select KVM_MMIO
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
select VIRT_XFER_TO_GUEST_WORK
select KVM_VFIO
diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index 19eb5e5c3984..392e14302453 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -26,6 +26,8 @@
#define __KVM_HAVE_ARCH_INTC_INITIALIZED
+#define HAVE_KVM_MMIO
+
/* Loongarch KVM register ids */
#define KVM_GET_IOC_CSR_IDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
diff --git a/arch/loongarch/kvm/Kconfig b/arch/loongarch/kvm/Kconfig
index 8e5213609975..a244f2aea7ff 100644
--- a/arch/loongarch/kvm/Kconfig
+++ b/arch/loongarch/kvm/Kconfig
@@ -28,7 +28,6 @@ config KVM
select KVM_COMMON
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
select KVM_GENERIC_HARDWARE_ENABLING
- select KVM_MMIO
select VIRT_XFER_TO_GUEST_WORK
select SCHED_INFO
select GUEST_PERF_EVENTS if PERF_EVENTS
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index c14b10821817..e3cb7c8c9461 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -26,6 +26,8 @@
#include <kvm/iodev.h>
+#define HAVE_KVM_MMIO
+
/* MIPS KVM register ids */
#define MIPS_CP0_32(_R, _S) \
(KVM_REG_MIPS_CP0 | KVM_REG_SIZE_U32 | (8 * (_R) + (_S)))
diff --git a/arch/mips/kvm/Kconfig b/arch/mips/kvm/Kconfig
index b1b9a1d67758..c65596fdf54f 100644
--- a/arch/mips/kvm/Kconfig
+++ b/arch/mips/kvm/Kconfig
@@ -22,7 +22,6 @@ config KVM
select EXPORT_UASM
select KVM_COMMON
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
- select KVM_MMIO
select KVM_GENERIC_HARDWARE_ENABLING
select HAVE_KVM_READONLY_MEM
help
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 2d139c807577..92d14438e31b 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -29,6 +29,13 @@
#define __KVM_HAVE_ARCH_VCPU_DEBUGFS
+#if defined(CONFIG_KVM_BOOK3S_32_HANDLER) || \
+ defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE) || \
+ defined(CONFIG_KVM_E500V2) || \
+ defined(CONFIG_KVM_E500MC)
+#define HAVE_KVM_MMIO
+#endif
+
#define KVM_MAX_VCPUS NR_CPUS
#define KVM_MAX_VCORES NR_CPUS
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index 9a0d1c1aca6c..d97a4a51ec55 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -29,7 +29,6 @@ config KVM_BOOK3S_HANDLER
config KVM_BOOK3S_32_HANDLER
bool
select KVM_BOOK3S_HANDLER
- select KVM_MMIO
config KVM_BOOK3S_64_HANDLER
bool
@@ -37,7 +36,6 @@ config KVM_BOOK3S_64_HANDLER
config KVM_BOOK3S_PR_POSSIBLE
bool
- select KVM_MMIO
config KVM_BOOK3S_HV_POSSIBLE
bool
@@ -200,7 +198,6 @@ config KVM_E500V2
depends on PPC_E500 && !PPC_E500MC
depends on !CONTEXT_TRACKING_USER
select KVM
- select KVM_MMIO
help
Support running unmodified E500 guest kernels in virtual machines on
E500v2 host processors.
@@ -215,7 +212,6 @@ config KVM_E500MC
depends on PPC_E500MC
depends on !CONTEXT_TRACKING_USER
select KVM
- select KVM_MMIO
select KVM_BOOKE_HV
help
Support running unmodified E500MC/E5500/E6500 guest kernels in
diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
index 24585304c02b..a405cd30c6fa 100644
--- a/arch/riscv/include/asm/kvm_host.h
+++ b/arch/riscv/include/asm/kvm_host.h
@@ -25,6 +25,8 @@
#include <asm/kvm_vcpu_timer.h>
#include <asm/kvm_vcpu_pmu.h>
+#define HAVE_KVM_MMIO
+
#define KVM_MAX_VCPUS 1024
#define KVM_HALT_POLL_NS_DEFAULT 500000
diff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig
index ec2cee0a39e0..3aea8d4939d2 100644
--- a/arch/riscv/kvm/Kconfig
+++ b/arch/riscv/kvm/Kconfig
@@ -28,7 +28,6 @@ config KVM
select KVM_COMMON
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
select KVM_GENERIC_HARDWARE_ENABLING
- select KVM_MMIO
select VIRT_XFER_TO_GUEST_WORK
select SCHED_INFO
select GUEST_PERF_EVENTS if PERF_EVENTS
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 6e4e3ef9b8c7..4cdaf60c9217 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -45,6 +45,8 @@
#define __KVM_HAVE_ARCH_VCPU_DEBUGFS
+#define HAVE_KVM_MMIO
+
/*
* CONFIG_KVM_MAX_NR_VCPUS is defined iff CONFIG_KVM!=n, provide a dummy max if
* KVM is disabled (arbitrarily use the default from CONFIG_KVM_MAX_NR_VCPUS).
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index 801bf9e520db..da5d9fa8a11c 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -32,7 +32,6 @@ config KVM_X86
select VHOST_TASK
select KVM_ASYNC_PF
select USER_RETURN_NOTIFIER
- select KVM_MMIO
select SCHED_INFO
select PERF_EVENTS
select GUEST_PERF_EVENTS
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 44e6fe3d2d80..2aeda4c6af14 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -833,7 +833,7 @@ struct kvm {
struct list_head ioeventfds;
struct kvm_vm_stat stat;
struct kvm_arch arch;
-#ifdef CONFIG_KVM_MMIO
+#ifdef HAVE_KVM_MMIO
struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
spinlock_t ring_lock;
struct list_head coalesced_zones;
diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig
index 794976b88c6f..c4a983e41765 100644
--- a/virt/kvm/Kconfig
+++ b/virt/kvm/Kconfig
@@ -40,9 +40,6 @@ config NEED_KVM_DIRTY_RING_WITH_BITMAP
bool
depends on HAVE_KVM_DIRTY_RING
-config KVM_MMIO
- bool
-
config KVM_ASYNC_PF
bool
diff --git a/virt/kvm/Makefile.kvm b/virt/kvm/Makefile.kvm
index d047d4cf58c9..3c27c18b49a0 100644
--- a/virt/kvm/Makefile.kvm
+++ b/virt/kvm/Makefile.kvm
@@ -5,9 +5,8 @@
KVM ?= ../../../virt/kvm
-kvm-y := $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/binary_stats.o
+kvm-y := $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/binary_stats.o $(KVM)/coalesced_mmio.o
kvm-$(CONFIG_KVM_VFIO) += $(KVM)/vfio.o
-kvm-$(CONFIG_KVM_MMIO) += $(KVM)/coalesced_mmio.o
kvm-$(CONFIG_KVM_ASYNC_PF) += $(KVM)/async_pf.o
kvm-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(KVM)/irqchip.o
kvm-$(CONFIG_HAVE_KVM_DIRTY_RING) += $(KVM)/dirty_ring.o
diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c
index 6b1d90161099..070eba3c6534 100644
--- a/virt/kvm/coalesced_mmio.c
+++ b/virt/kvm/coalesced_mmio.c
@@ -12,6 +12,8 @@
#include <kvm/iodev.h>
#include <linux/kvm_host.h>
+
+#ifdef HAVE_KVM_MMIO
#include <linux/slab.h>
#include <linux/kvm.h>
@@ -188,3 +190,4 @@ int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,
*/
return 0;
}
+#endif /* ifdef HAVE_KVM_MMIO */
diff --git a/virt/kvm/coalesced_mmio.h b/virt/kvm/coalesced_mmio.h
index 36f84264ed25..a8430d41945b 100644
--- a/virt/kvm/coalesced_mmio.h
+++ b/virt/kvm/coalesced_mmio.h
@@ -11,7 +11,7 @@
*
*/
-#ifdef CONFIG_KVM_MMIO
+#ifdef HAVE_KVM_MMIO
#include <linux/list.h>
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 60a5bb778993..ab3a0347bdd3 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -4041,7 +4041,7 @@ static vm_fault_t kvm_vcpu_fault(struct vm_fault *vmf)
else if (vmf->pgoff == KVM_PIO_PAGE_OFFSET)
page = virt_to_page(vcpu->arch.pio_data);
#endif
-#ifdef CONFIG_KVM_MMIO
+#ifdef HAVE_KVM_MMIO
else if (vmf->pgoff == KVM_COALESCED_MMIO_PAGE_OFFSET)
page = virt_to_page(vcpu->kvm->coalesced_mmio_ring);
#endif
@@ -4867,7 +4867,7 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
case KVM_CAP_ENABLE_CAP_VM:
case KVM_CAP_HALT_POLL:
return 1;
-#ifdef CONFIG_KVM_MMIO
+#ifdef HAVE_KVM_MMIO
case KVM_CAP_COALESCED_MMIO:
return KVM_COALESCED_MMIO_PAGE_OFFSET;
case KVM_CAP_COALESCED_PIO:
@@ -5208,7 +5208,7 @@ static long kvm_vm_ioctl(struct file *filp,
break;
}
#endif
-#ifdef CONFIG_KVM_MMIO
+#ifdef HAVE_KVM_MMIO
case KVM_REGISTER_COALESCED_MMIO: {
struct kvm_coalesced_mmio_zone zone;
@@ -5530,7 +5530,7 @@ static long kvm_dev_ioctl(struct file *filp,
#ifdef CONFIG_X86
r += PAGE_SIZE; /* pio data page */
#endif
-#ifdef CONFIG_KVM_MMIO
+#ifdef HAVE_KVM_MMIO
r += PAGE_SIZE; /* coalesced mmio ring page */
#endif
break;
--
2.51.0
^ permalink raw reply related
* Re: [PATCH 07/43] KVM: arm64: gic-v5: Create & manage VM and VPE tables
From: Joey Gouly @ 2026-04-28 15:55 UTC (permalink / raw)
To: Sascha Bischoff
Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
kvm@vger.kernel.org, nd, maz@kernel.org, oliver.upton@linux.dev,
Suzuki Poulose, yuzenghui@huawei.com, peter.maydell@linaro.org,
lpieralisi@kernel.org, Timothy Hayes
In-Reply-To: <20260427160547.3129448-8-sascha.bischoff@arm.com>
A lot to look into here, just some first read through nits.
On Mon, Apr 27, 2026 at 04:08:25PM +0000, Sascha Bischoff wrote:
> GICv5 uses a set of in-memory tables to track and manage VM
> state. These must be allocated by the hypervisor, and provided to the
> IRS to use.
>
> The VMT (Virtual Machine Table) is a linear or two level table
> comprising VMT Entries (VMTE). Each VMTE describes the state for a
> single VM. This state includes things such as the SPI and LPI IST
> configuration (coming in a future commit), an implementation-defined
> VM Descriptor, and a VPE Table (VPET).
>
> The VPET contains one entry per VPE belonging to a VM, and is used to
> mark a VPE as valid, as well as providing the address of an
> implementation-defined VPE Descriptor, which is used by the hardware
> to track and manage VPE state.
>
> This commit adds support for allocating the VMT, and managing the
> VMTEs. The VMTEs can be initialised or released for re-use. Allocation
> and tracking of unused VMTEs is handled with an IDA.
>
> Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
> ---
> arch/arm64/kvm/vgic/vgic-v5-tables.c | 628 +++++++++++++++++++++++++++
> arch/arm64/kvm/vgic/vgic-v5-tables.h | 108 +++++
> include/kvm/arm_vgic.h | 2 +
> include/linux/irqchip/arm-gic-v5.h | 13 +
> 4 files changed, 751 insertions(+)
>
> diff --git a/arch/arm64/kvm/vgic/vgic-v5-tables.c b/arch/arm64/kvm/vgic/vgic-v5-tables.c
> index 30e2b108b1aa3..502d05d46cccf 100644
> --- a/arch/arm64/kvm/vgic/vgic-v5-tables.c
> +++ b/arch/arm64/kvm/vgic/vgic-v5-tables.c
> @@ -3,6 +3,634 @@
> * Copyright (C) 2025, 2026 Arm Ltd.
> */
>
> +#include <kvm/arm_vgic.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/sizes.h>
> +#include <linux/slab.h>
> +#include <linux/xarray.h>
> +#include <asm/kvm_mmu.h>
> +
> +#include "vgic.h"
> #include "vgic-v5-tables.h"
>
> struct vgic_v5_host_ist_caps gicv5_host_ist_caps;
> +
> +static struct vgic_v5_vmt *vmt_info;
> +DEFINE_XARRAY(vm_info);
> +
> +static bool vgic_v5_vmt_allocated(void)
> +{
> + return vmt_info != NULL;
> +}
> +
> +static int vgic_v5_check_vm_id(u16 vm_id)
> +{
> + if (vm_id >= vmt_info->num_entries)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +/*
> + * Our IRS might be coherent or non-coherent. If coherent, we can just emit a
> + * DSB to ensure that we're in sync. However, when non-coherent, we need to
> + * manage our cached data explicitly.
> + *
> + * This helper is used to handle both coherent and non-coherent IRSes, and
> + * handles all combinations of cleaning and invalidating to the PoC.
> + */
> +static void vgic_v5_clean_inval(void *va, size_t size, bool clean, bool inval)
> +{
> + unsigned long base = (unsigned long)va;
> +
> + /* Catch any accidental NOPs */
> + BUILD_BUG_ON(!(clean || inval));
> +
> + /* Coherent; emit DSB. */
> + if (!gicv5_host_ist_caps.irs_non_coherent) {
> + dsb(ishst);
> + return;
> + }
> +
> + if (clean && inval)
> + dcache_clean_inval_poc(base, base + size);
> + else if (clean)
> + dcache_clean_poc(base, base + size);
> + else if (inval)
> + dcache_inval_poc(base, base + size);
> +}
> +
> +/*
> + * Create a linear VM table, rounding up the number of entries to at least one
> + * whole page to give us nicer alignment.
> + *
> + * Note: We don't update the number of entries tracked in our tracking structure
> + * as this might be higher than the number of bits supported by the HW.
> + */
> +static int vgic_v5_alloc_vmt_linear(unsigned int num_entries)
> +{
> + unsigned int l2_entries_per_page;
> + size_t alloc_size;
> +
> + /* Potentially throw away a bit of memory for the sake of alignment! */
> + l2_entries_per_page = PAGE_SIZE / GICV5_VMTEL2E_SIZE;
> + if (num_entries < l2_entries_per_page)
> + num_entries = l2_entries_per_page;
> +
> + alloc_size = num_entries * sizeof(struct vmtl2_entry);
> +
> + vmt_info->linear.vmt_base = kzalloc(alloc_size, GFP_KERNEL);
> + if (vmt_info->linear.vmt_base == NULL)
> + return -ENOMEM;
> +
> + vgic_v5_clean_inval(vmt_info->linear.vmt_base, alloc_size, true, true);
> +
> + return 0;
> +}
> +
> +/*
> + * Allocate the first level of a two-level VM table. The second-level VM tables
> + * are allocated on demand (by vgic_v5_alloc_l2_vmt()).
> + *
> + * Note: If there are too few entries, these are rounded up to the size of an L2
> + * table (4k) to ensure sane alignment. As with the linear table, the tracked
> + * number of entries is not increased to avoid the case of going above what the
> + * hardware supports.
> + */
> +static int vgic_v5_alloc_vmt_two_level(unsigned int num_entries)
> +{
> + size_t alloc_size;
> +
> + /* Potentially throw away a bit of memory for the sake of alignment! */
> + if (num_entries < GICV5_VMT_L2_TABLE_ENTRIES)
> + num_entries = GICV5_VMT_L2_TABLE_ENTRIES;
> +
> + /*
> + * Let's make sure that we always allocate a whole power of 2
> + * of entries. Note that we need to subtract 1 from the fls()
> + * result in order to give the correct number of bits as we
> + * are operating on a whole power of 2.
This fls() seems unrelated? There is an fls() - 1 in vgic_v5_vmte_init().
> + */
> + num_entries = roundup_pow_of_two(num_entries);
> +
> + vmt_info->l2.num_l1_ents = (num_entries / GICV5_VMT_L2_TABLE_ENTRIES);
> + alloc_size = vmt_info->l2.num_l1_ents * sizeof(vmtl1_entry);
> +
> + vmt_info->l2.vmt_base = kzalloc(alloc_size, GFP_KERNEL);
> + if (vmt_info->l2.vmt_base == NULL)
> + return -ENOMEM;
> +
> + vgic_v5_clean_inval(vmt_info->l2.vmt_base, alloc_size, true, true);
> +
> + vmt_info->l2.l2ptrs = kzalloc_objs(*vmt_info->l2.l2ptrs,
> + vmt_info->l2.num_l1_ents,
> + GFP_KERNEL);
> + if (vmt_info->l2.l2ptrs == NULL) {
> + kfree(vmt_info->l2.vmt_base);
> + return -ENOMEM;
> + }
> +
> + return 0;
> +}
> +
> +
> +/*
> + * Allocate a second level VMT, if required. This can be called eagerly, and
> + * will only perform the allocation if required.
> + */
> +static int vgic_v5_alloc_l2_vmt(struct kvm *kvm)
> +{
> + unsigned int l1_index;
> + struct vmtl2_entry *l2_table;
> + vmtl1_entry tmp;
> + u16 vm_id = vgic_v5_vm_id(kvm);
> + struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
> + struct gicv5_cmd_info cmd_info;
> + int ret;
> +
> + if (!vgic_v5_vmt_allocated())
> + return -ENXIO;
> +
> + /* Nothing to do if we have linear tables! */
> + if (!vmt_info->two_level)
> + return 0;
> +
> + ret = vgic_v5_check_vm_id(vm_id);
> + if (ret)
> + return ret;
> +
> + /*
> + * We have 4k-sized L2 tables - this is mandated by the spec for
> + * two-level VMTs. This means that we have 128 entries per L1 VMTE.
> + */
> + l1_index = vm_id / GICV5_VMT_L2_TABLE_ENTRIES;
> +
> + if (l1_index > vmt_info->l2.num_l1_ents)
> + return -E2BIG;
> +
> + /* Already valid? Great! */
> + if (vmt_info->l2.l2ptrs[l1_index] != NULL)
> + return 0;
> +
> + l2_table = kzalloc(GICV5_VMT_L2_TABLE_SIZE, GFP_KERNEL);
> + if (l2_table == NULL)
> + return -ENOMEM;
> +
> + if (virt_to_phys(l2_table) & ~GICV5_VMTEL1E_L2_ADDR) {
> + kfree(l2_table);
> + return -EINVAL;
> + }
Duplicated code below this. I guess move the comment up and delete the same checks below.
> +
> + vmt_info->l2.l2ptrs[l1_index] = l2_table;
> +
> + /* Alignment issue! */
> + if (virt_to_phys(l2_table) & ~GICV5_VMTEL1E_L2_ADDR) {
> + kfree(l2_table);
> + return -EFAULT;
> + }
> +
> + tmp = virt_to_phys(l2_table) & GICV5_VMTEL1E_L2_ADDR;
Can we rename tmp to vmte_l2_addr or something? (Although reading on I see tmp
is used more often.. so maybe it's consistent here)
> + WRITE_ONCE(vmt_info->l2.vmt_base[l1_index], cpu_to_le64(tmp));
> +
> + vgic_v5_clean_inval(l2_table, GICV5_VMT_L2_TABLE_SIZE, true, true);
> + /* Skip inval for now - wait until table is made valid by HW */
> + vgic_v5_clean_inval(vmt_info->l2.vmt_base + l1_index,
> + sizeof(vmtl1_entry), true, false);
> +
> + /* VMAP in the L2 VMT via the IRS */
> + cmd_info.cmd_type = VMT_L2_MAP;
> + ret = irq_set_vcpu_affinity(vgic_v5_vpe_db(vcpu0), &cmd_info);
> +
> + /* We've failed to make the L2 VMT valid - things are very broken! */
> + if (ret) {
> + /* Remove the pointer from L1 table */
> + WRITE_ONCE(vmt_info->l2.vmt_base[l1_index], 0);
> +
> + kfree(l2_table);
> + vmt_info->l2.l2ptrs[l1_index] = NULL;
> +
> + return ret;
> + }
> +
> + /* Table updated; inval our copy */
> + vgic_v5_clean_inval(vmt_info->l2.vmt_base + l1_index,
> + sizeof(vmtl1_entry), false, true);
> +
> + return ret;
> +}
> +
> +/*
> + * Allocate the top-level VMT. This can either be linear or two-level.
> + */
> +int vgic_v5_vmt_allocate(bool two_level, unsigned int num_entries,
> + size_t vmd_size, size_t vped_size,
> + unsigned int max_vpes)
> +{
> + int ret = 0;
> +
> + if (vgic_v5_vmt_allocated())
> + return -EBUSY;
> +
> + /* VMD is optional; using 0 to signal that it not needed. */
> + if (vmd_size != 0 &&
> + (vmd_size < VMD_MIN_SIZE || vmd_size > VMD_MAX_SIZE))
> + return -EINVAL;
> +
> + if (vped_size < VPED_MIN_SIZE || vped_size > VPED_MAX_SIZE)
> + return -EINVAL;
> +
> + /* Allocate the tracking structure */
> + vmt_info = kzalloc_obj(*vmt_info, GFP_KERNEL);
> + if (vmt_info == NULL)
> + return -ENOMEM;
> +
> + ida_init(&vmt_info->vm_id_ida);
> + vmt_info->max_vpes = max_vpes;
> + vmt_info->vmd_size = vmd_size;
> + vmt_info->vped_size = vped_size;
> + vmt_info->two_level = two_level;
> + vmt_info->num_entries = num_entries;
> +
> + if (!two_level)
> + ret = vgic_v5_alloc_vmt_linear(num_entries);
> + else
> + ret = vgic_v5_alloc_vmt_two_level(num_entries);
> +
> + /* If anything failed, free our tracking structure before returning */
> + if (ret) {
> + kfree(vmt_info);
> + vmt_info = NULL;
> + }
> +
> + return ret;
> +}
> +
> +/*
> + * Free the VMT and associated tracking structures. This isn't strictly expected
> + * to be called in general operation, but instead exists for completeness.
> + */
> +int vgic_v5_vmt_free(void)
> +{
> + if (!vgic_v5_vmt_allocated())
> + return -EINVAL;
> +
> + if (!vmt_info->two_level) {
> + kfree(vmt_info->linear.vmt_base);
> + } else {
> + /* Free the L2 tables; kfree(NULL) is safe */
> + for (int i = 0; i < vmt_info->l2.num_l1_ents; ++i)
> + kfree(vmt_info->l2.l2ptrs[i]);
> + kfree(vmt_info->l2.l2ptrs);
> +
> + /* And now free the L1 table */
> + kfree(vmt_info->l2.vmt_base);
> + }
> +
> + ida_destroy(&vmt_info->vm_id_ida);
> + kfree(vmt_info);
> + vmt_info = NULL;
> +
> + return 0;
> +}
> +
> +/*
> + * Look up a VMT Entry by VM ID.
> + */
> +static int vgic_v5_get_l2_vmte(u16 vm_id, struct vmtl2_entry **vmte)
> +{
> + unsigned int l1_index, l2_index;
> + struct vmtl2_entry *l2_table;
> + int ret;
> +
> + ret = vgic_v5_check_vm_id(vm_id);
> + if (ret)
> + return ret;
> +
> + if (!vmt_info->two_level) {
> + /* All entries always valid for Linear table */
> + *vmte = &vmt_info->linear.vmt_base[vm_id];
> + } else {
> + l1_index = vm_id / GICV5_VMT_L2_TABLE_ENTRIES;
> + l2_index = vm_id % GICV5_VMT_L2_TABLE_ENTRIES;
> +
> + if (l1_index > vmt_info->l2.num_l1_ents)
> + return -E2BIG;
> +
> + if (vmt_info->l2.l2ptrs[l1_index] == NULL)
> + return -EINVAL;
> +
> + l2_table = vmt_info->l2.l2ptrs[l1_index];
> + *vmte = &l2_table[l2_index];
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * Zero a VMT Entry, and flush & invalidate to the PoC, if required.
> + */
> +static int vgic_v5_reset_vmte(struct kvm *kvm)
> +{
> + u16 vm_id = vgic_v5_vm_id(kvm);
> + struct vmtl2_entry *vmte;
> + int ret;
> +
> + ret = vgic_v5_get_l2_vmte(vm_id, &vmte);
> + if (ret)
> + return ret;
> +
> + WRITE_ONCE(vmte->val[0], 0ULL);
> + WRITE_ONCE(vmte->val[1], 0ULL);
> + WRITE_ONCE(vmte->val[2], 0ULL);
> + WRITE_ONCE(vmte->val[3], 0ULL);
> +
> + vgic_v5_clean_inval(vmte, sizeof(*vmte), true, true);
> +
> + return 0;
> +}
> +
> +/*
> + * Use the IDA to allocate a new VM ID, and track it in the gicv5_vm data
> + * structure. If we're out of VM IDs, the IDA catches that, and we return the
> + * error (-ENOSPC).
> + */
> +int vgic_v5_allocate_vm_id(struct kvm *kvm)
> +{
> + int id;
> +
> + id = ida_alloc_max(&vmt_info->vm_id_ida, vmt_info->num_entries - 1u,
> + GFP_KERNEL);
> + if (id < 0)
> + return id;
> +
> + kvm->arch.vgic.gicv5_vm.vm_id = id;
> + kvm->arch.vgic.gicv5_vm.vm_id_valid = true;
> +
> + return 0;
> +}
> +
> +/*
> + * Release the VM ID to allow it to be reallocated in the future.
> + */
> +void vgic_v5_release_vm_id(struct kvm *kvm)
> +{
> + ida_free(&vmt_info->vm_id_ida, kvm->arch.vgic.gicv5_vm.vm_id);
> + kvm->arch.vgic.gicv5_vm.vm_id_valid = false;
> +}
> +
> +/*
> + * Initialise an entry in the VMT based on the index of the VM.
> + *
> + * Note: We don't mark the VMTE as valid as this needs to be done by
> + * the hardware.
> + */
> +int vgic_v5_vmte_init(struct kvm *kvm)
> +{
> + int nr_cpus = atomic_read(&kvm->online_vcpus);
> + struct vgic_v5_vm_info *vmi = NULL;
> + u16 vm_id = vgic_v5_vm_id(kvm);
> + void *vmd = NULL, *vpet = NULL;
> + struct vmtl2_entry *vmte;
> + void **vped_ptrs = NULL;
> + size_t vpet_alloc_size;
> + int ret;
> + u64 tmp;
> +
> + if (nr_cpus > vmt_info->max_vpes)
> + return -E2BIG;
> +
> + /*
> + * If we're using two-level VMTs, L2 is allocated on demand. For linear
> + * VMTs, this is a NOP.
> + */
> + if (vgic_v5_alloc_l2_vmt(kvm))
> + return -EIO;
> +
> + ret = vgic_v5_get_l2_vmte(vm_id, &vmte);
> + if (ret)
> + return ret;
> +
> + /* If the entry is already valid, something went wrong */
> + if (FIELD_GET(GICV5_VMTEL2E_VALID, le64_to_cpu(READ_ONCE(vmte->val[0])))) {
> + vgic_v5_clean_inval(vmte, sizeof(*vmte), true, true);
> + return -EINVAL;
> + }
> +
> + ret = vgic_v5_reset_vmte(kvm);
> + if (ret)
> + return ret;
> +
> + vmi = kzalloc_objs(*vmi, GFP_KERNEL);
> + if (vmi == NULL) {
> + ret = -ENOMEM;
> + goto out_fail;
> + }
> +
> + ret = xa_insert(&vm_info, vm_id, vmi, GFP_KERNEL);
> + if (ret)
> + goto out_fail;
> +
> + /* Allocate and assign the VM Descriptor, if required. */
> + if (vmt_info->vmd_size != 0) {
> + vmd = kzalloc(vmt_info->vmd_size, GFP_KERNEL);
> + if (!vmd) {
> + ret = -ENOMEM;
> + goto out_fail;
> + }
> +
> + /* Stash the VA so we can free it later */
> + vmi->vmd_base = vmd;
> +
> + tmp = FIELD_PREP(GICV5_VMTEL2E_VMD_ADDR,
> + virt_to_phys(vmd) >>
> + GICV5_VMTEL2E_VMD_ADDR_SHIFT);
> + WRITE_ONCE(vmte->val[0], cpu_to_le64(tmp));
> + }
> +
> + /*
> + * Allocate and assign the VPE Table. We can only describe the number of
> + * VPE ID Bits in the VMTE, and therefore we round up the number of CPUs
> + * to a whole power of two.
This comment is a bit confusing, would try reword it somewhere along the lines of:
Round up the number of CPUs to a whole power of two, as the VMTE describes the ID bits as log2()
Something like that. "We can only describe the number of VPE ID Bits in the
VMTE", the emphasis on 'Bits' is hard to make out.
> + */
> + nr_cpus = roundup_pow_of_two(nr_cpus);
> + vmi->vpe_id_bits = fls(nr_cpus) - 1;
> +
> + vpet_alloc_size = sizeof(vpe_entry) * nr_cpus;
> + vpet = kzalloc(vpet_alloc_size, GFP_KERNEL);
kzalloc_objs()? Or is there some alignment thing here?
> + if (!vpet) {
> + ret = -ENOMEM;
> + goto out_fail;
> + }
> +
> + /* Stash the VA so we can free it later */
> + vmi->vpet_base = vpet;
> +
> + tmp = FIELD_PREP(GICV5_VMTEL2E_VPET_ADDR,
> + virt_to_phys(vpet) >> GICV5_VMTEL2E_VPET_ADDR_SHIFT);
> + tmp |= FIELD_PREP(GICV5_VMTEL2E_VPE_ID_BITS, vmi->vpe_id_bits);
> + WRITE_ONCE(vmte->val[1], cpu_to_le64(tmp));
> +
> + vped_ptrs = kzalloc_objs(*vped_ptrs, nr_cpus, GFP_KERNEL);
> + if (vped_ptrs == NULL) {
> + ret = -ENOMEM;
> + goto out_fail;
> + }
> + vmi->vped_ptrs = vped_ptrs;
> +
> + if (vmd)
> + vgic_v5_clean_inval(vmd, vmt_info->vmd_size, true, true);
> + vgic_v5_clean_inval(vpet, vpet_alloc_size, true, true);
> + vgic_v5_clean_inval(vmte, sizeof(*vmte), true, true);
> +
> + kvm->arch.vgic.gicv5_vm.vmte_allocated = true;
> +
> + return 0;
> +
> +out_fail:
> + /* kfree(NULL) is safe so we can just kfree() at leisure */
> + kfree(vmd);
> + kfree(vpet);
> + kfree(vped_ptrs);
> + if (vmi)
> + xa_erase(&vm_info, vm_id);
> + kfree(vmi);
> +
> + vgic_v5_reset_vmte(kvm);
> +
> + return ret;
> +}
> +
> +/*
> + * Release the VMT Entry, freeing up any allocated data structures before
> + * zeroing the VMTE.
> + *
> + * The VMTE must be marked as invalid before it is released.
> + */
> +int vgic_v5_vmte_release(struct kvm *kvm)
> +{
> + u16 vm_id = vgic_v5_vm_id(kvm);
> + struct vgic_v5_vm_info *vmi;
> + struct vmtl2_entry *vmte;
> + int ret;
> +
> + ret = vgic_v5_get_l2_vmte(vm_id, &vmte);
> + if (ret)
> + return ret;
> +
> + /* Reject if the VMTE has not been marked as invalid! */
> + if (FIELD_GET(GICV5_VMTEL2E_VALID, le64_to_cpu(READ_ONCE(vmte->val[0])))) {
> + vgic_v5_clean_inval(vmte, sizeof(*vmte), true, true);
> + return -EINVAL;
> + }
> +
> + vmi = xa_load(&vm_info, vm_id);
> + if (WARN_ON_ONCE(!vmi))
> + goto no_vmi;
> +
> + kfree(vmi->vmd_base);
> + kfree(vmi->vpet_base);
> +
> + xa_erase(&vm_info, vm_id);
> + kfree(vmi);
> +
> +no_vmi:
> + /*
> + * If we didn't get far enough into allocating a VMTE to create the VM
> + * info structure, then we just zero the VMTE and move on. There's
> + * nothing else we can realistically do here.
> + */
> + ret = vgic_v5_reset_vmte(kvm);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +/*
> + * Allocate a VPE descriptor and provide it to the hardware via the VPE Table.
> + */
> +int vgic_v5_vmte_alloc_vpe(struct kvm_vcpu *vcpu)
> +{
> + u16 vm_id = vgic_v5_vm_id(vcpu->kvm);
> + u16 vpe_id = vgic_v5_vpe_id(vcpu);
> + struct vgic_v5_vm_info *vmi;
> + vpe_entry tmp, *vpet_base;
> + void *vped;
> +
> + /* Make sure we're not over what the hardware supports */
> + if (vpe_id >= vmt_info->max_vpes)
> + return -E2BIG;
> +
> + vmi = xa_load(&vm_info, vm_id);
> + if (WARN_ON_ONCE(!vmi))
> + return -EINVAL;
> +
> + if (vpe_id >= 1 << vmi->vpe_id_bits)
> + return -E2BIG;
> +
> + vpet_base = vmi->vpet_base;
> +
> + /* If the VPETE for this CPU is already valid we've gone wrong */
> + if (FIELD_GET(GICV5_VPE_VALID, le64_to_cpu(READ_ONCE(vpet_base[vpe_id])))) {
> + vgic_v5_clean_inval(&vpet_base[vpe_id], sizeof(*vpet_base), true, true);
> + return -EBUSY;
> + }
> +
> + /* Alloc VPE Descriptor. Only used by IRS. */
> + vped = kzalloc(vmt_info->vped_size, GFP_KERNEL);
> + if (vped == NULL)
> + return -ENOMEM;
> +
> + vmi->vped_ptrs[vpe_id] = vped;
> +
> + tmp = FIELD_PREP(GICV5_VPED_ADDR, virt_to_phys(vped) >> GICV5_VPED_ADDR_SHIFT);
> + WRITE_ONCE(vpet_base[vpe_id], cpu_to_le64(tmp));
> +
> + vgic_v5_clean_inval(vped, vmt_info->vped_size, true, true);
> + vgic_v5_clean_inval(vpet_base + vpe_id, sizeof(vpe_entry), true, true);
> +
> + return 0;
> +}
> +
> +/*
> + * Free the memory allocated for the VPE descriptor.
> + */
> +int vgic_v5_vmte_free_vpe(struct kvm_vcpu *vcpu)
> +{
> + u16 vm_id = vgic_v5_vm_id(vcpu->kvm);
> + u16 vpe_id = vgic_v5_vpe_id(vcpu);
> + struct vgic_v5_vm_info *vmi;
> + struct vmtl2_entry *vmte;
> + vpe_entry *vpet_base;
> + void *vped;
> + int ret;
> +
> + ret = vgic_v5_get_l2_vmte(vm_id, &vmte);
> + if (ret)
> + return ret;
> +
> + if (FIELD_GET(GICV5_VMTEL2E_VALID, le64_to_cpu(READ_ONCE(vmte->val[0])))) {
> + vgic_v5_clean_inval(vmte, sizeof(*vmte), true, true);
> + return -EBUSY;
> + }
> +
> + vmi = xa_load(&vm_info, vm_id);
> + if (!vmi)
> + return -EINVAL;
> +
> + if (vpe_id >= 1 << vmi->vpe_id_bits)
> + return -E2BIG;
> +
> + vpet_base = vmi->vpet_base;
> + WRITE_ONCE(vpet_base[vpe_id], 0ULL);
> +
> + vgic_v5_clean_inval(vpet_base + vpe_id, sizeof(vpe_entry), true, true);
> +
> + /* Free VPE Descriptor. Only used by IRS. */
> + vped = vmi->vped_ptrs[vpe_id];
> + vmi->vped_ptrs[vpe_id] = NULL;
> + kfree(vped);
> +
> + return 0;
> +}
> diff --git a/arch/arm64/kvm/vgic/vgic-v5-tables.h b/arch/arm64/kvm/vgic/vgic-v5-tables.h
> index cf00a248eabd5..5501a44308362 100644
> --- a/arch/arm64/kvm/vgic/vgic-v5-tables.h
> +++ b/arch/arm64/kvm/vgic/vgic-v5-tables.h
> @@ -8,6 +8,86 @@
>
> #include <linux/irqchip/arm-gic-v5.h>
>
> +#define VM_ID_BITS_MIN 8
> +#define VM_ID_BITS_MAX 16
> +#define VMD_MIN_SIZE 8
> +#define VMD_MAX_SIZE 4096
> +#define VPED_MIN_SIZE 8
> +#define VPED_MAX_SIZE 4096
> +#define VPE_ID_BITS_MIN 8
> +#define VPE_ID_BITS_MAX 16
> +
> +/* Level 1 Virtual Machine Table Entry */
> +typedef __le64 vmtl1_entry;
> +#define GICV5_VMTEL1E_VALID BIT_ULL(0)
> +/* Note that there is no shift for the address by design */
> +#define GICV5_VMTEL1E_L2_ADDR GENMASK(51, 12)
> +
> +#define GICV5_VMTEL2E_SIZE 32ULL
> +/* An L2 table (two-level VMT) is ALWAYS 4kB! */
> +#define GICV5_VMT_L2_TABLE_SIZE 4096ULL
> +#define GICV5_VMT_L2_TABLE_ENTRIES (GICV5_VMT_L2_TABLE_SIZE / GICV5_VMTEL2E_SIZE)
> +
> +/* Level 2 Virtual Machine Table Entry */
> +struct vmtl2_entry {
> + __le64 val[4];
> +};
> +
> +/*
> + * As the L2 VMTE is a large data structure, we are splitting it into 4 parts.
> + * We only mask and shift WITHIN each part for simplicity.
> + */
> +/* First 64-bit chunk */
> +#define GICV5_VMTEL2E_VALID BIT_ULL(0)
> +#define GICV5_VMTEL2E_VMD_ADDR_SHIFT 3ULL
> +#define GICV5_VMTEL2E_VMD_ADDR GENMASK_ULL(55, 3)
> +/* Second 64-bit chunk */
> +#define GICV5_VMTEL2E_VPET_ADDR_SHIFT 3ULL
> +#define GICV5_VMTEL2E_VPET_ADDR GENMASK_ULL(55, 3)
> +#define GICV5_VMTEL2E_VPE_ID_BITS GENMASK_ULL(63, 59)
> +/* Third & fourth 64-bit chunks (the encodings are the same for each) */
> +#define GICV5_VMTEL2E_IST_VALID BIT_ULL(0)
> +#define GICV5_VMTEL2E_IST_L2SZ GENMASK_ULL(2, 1)
> +#define GICV5_VMTEL2E_IST_ADDR_SHIFT 6ULL
> +#define GICV5_VMTEL2E_IST_ADDR GENMASK_ULL(55, 6)
> +#define GICV5_VMTEL2E_IST_ISTSZ GENMASK_ULL(57, 56)
> +#define GICV5_VMTEL2E_IST_STRUCTURE BIT_ULL(58)
> +#define GICV5_VMTEL2E_IST_ID_BITS GENMASK_ULL(63, 59)
> +
> +/* Virtual PE Table Entry */
> +typedef __le64 vpe_entry;
> +#define GICV5_VPE_VALID BIT_ULL(0)
> +/* Note that there is no shift for the address by design. */
> +#define GICV5_VPED_ADDR_SHIFT 3ULL
> +#define GICV5_VPED_ADDR GENMASK_ULL(55, 3)
> +
> +struct vgic_v5_vm_info {
> + void __iomem *vmd_base;
> + vpe_entry __iomem *vpet_base;
> + void __iomem **vped_ptrs;
> + u8 vpe_id_bits;
> +};
> +
> +struct vgic_v5_vmt {
> + union {
> + struct {
> + struct vmtl2_entry *vmt_base;
> + unsigned int num_ents;
> + } linear;
> + struct {
> + vmtl1_entry *vmt_base;
> + struct vmtl2_entry **l2ptrs;
> + unsigned int num_l1_ents;
> + } l2;
> + };
> + bool two_level;
> + unsigned int num_entries;
> + unsigned int max_vpes;
> + size_t vmd_size;
> + size_t vped_size;
> + struct ida vm_id_ida;
> +};
> +
> struct vgic_v5_host_ist_caps {
> /* IST Capabilities */
>
> @@ -38,4 +118,32 @@ static inline struct vgic_v5_host_ist_caps *vgic_v5_host_caps(void)
> return &gicv5_host_ist_caps;
> }
>
> +static inline u16 vgic_v5_vm_id(struct kvm *kvm)
> +{
> + return kvm->arch.vgic.gicv5_vm.vm_id;
> +}
> +
> +static inline u16 vgic_v5_vpe_id(struct kvm_vcpu *vcpu)
> +{
> + return vcpu->vcpu_id;
> +}
> +
> +static inline int vgic_v5_vpe_db(struct kvm_vcpu *vcpu)
> +{
> + return vcpu->arch.vgic_cpu.vgic_v5.gicv5_vpe.db;
> +}
> +
> +int vgic_v5_vmt_allocate(bool two_level, unsigned int num_entries,
> + size_t vmd_size, size_t vped_size,
> + unsigned int vpe_id_bits);
> +int vgic_v5_vmt_free(void);
> +
> +int vgic_v5_allocate_vm_id(struct kvm *kvm);
> +void vgic_v5_release_vm_id(struct kvm *kvm);
> +
> +int vgic_v5_vmte_init(struct kvm *kvm);
> +int vgic_v5_vmte_release(struct kvm *kvm);
> +int vgic_v5_vmte_alloc_vpe(struct kvm_vcpu *vcpu);
> +int vgic_v5_vmte_free_vpe(struct kvm_vcpu *vcpu);
> +
> #endif
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 05dbd01f6fd21..0bcbc751593cc 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -372,6 +372,8 @@ struct vgic_v5_vm {
> int vpe_db_base;
> int nr_vpes;
> u16 vm_id;
> + bool vm_id_valid;
> + bool vmte_allocated;
> };
>
> struct vgic_dist {
> diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
> index 087d94f739672..89579ee04f5d1 100644
> --- a/include/linux/irqchip/arm-gic-v5.h
> +++ b/include/linux/irqchip/arm-gic-v5.h
> @@ -182,6 +182,7 @@
> #define GICV5_IRS_MAP_L2_ISTR_ID GENMASK(23, 0)
>
> #define GICV5_ISTL1E_VALID BIT_ULL(0)
> +#define GICV5_IRS_ISTL1E_SIZE 8UL
>
> #define GICV5_ISTL1E_L2_ADDR_MASK GENMASK_ULL(55, 12)
>
> @@ -444,4 +445,16 @@ void gicv5_free_lpi(u32 lpi);
>
> void __init gicv5_its_of_probe(struct device_node *parent);
> void __init gicv5_its_acpi_probe(void);
> +
> +enum gicv5_vcpu_info_cmd_type {
> + VMT_L2_MAP, /* Map in a L2 VMT - *may* happen on VM init */
> + VMTE_MAKE_VALID, /* Make the VMTE valid */
> + VMTE_MAKE_INVALID, /* Make the VMTE (et al.) invalid */
> +};
> +
> +struct gicv5_cmd_info {
> + enum gicv5_vcpu_info_cmd_type cmd_type;
> + u64 data;
> +};
> +
> #endif
Thanks,
Joey
^ permalink raw reply
* Re: [PATCH v13 3/4] gpio: rpmsg: add generic rpmsg GPIO driver
From: Padhi, Beleswar @ 2026-04-28 15:52 UTC (permalink / raw)
To: Shenwei Wang, Linus Walleij, Bartosz Golaszewski, Jonathan Corbet,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Mathieu Poirier, Frank Li, Sascha Hauer
Cc: Shuah Khan, linux-gpio@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, Pengutronix Kernel Team,
Fabio Estevam, Peng Fan, devicetree@vger.kernel.org,
linux-remoteproc@vger.kernel.org, imx@lists.linux.dev,
linux-arm-kernel@lists.infradead.org, dl-linux-imx,
Bartosz Golaszewski, Andrew Lunn
In-Reply-To: <PAXPR04MB9185C7741DCC422212F952CD89372@PAXPR04MB9185.eurprd04.prod.outlook.com>
On 4/28/2026 9:01 PM, Shenwei Wang wrote:
>
>> -----Original Message-----
>> From: Padhi, Beleswar <b-padhi@ti.com>
>> Sent: Tuesday, April 28, 2026 10:11 AM
>> To: Shenwei Wang <shenwei.wang@nxp.com>; Linus Walleij
>> <linusw@kernel.org>; Bartosz Golaszewski <brgl@kernel.org>; Jonathan Corbet
>> <corbet@lwn.net>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski
>> <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Bjorn Andersson
>> <andersson@kernel.org>; Mathieu Poirier <mathieu.poirier@linaro.org>; Frank Li
>> <frank.li@nxp.com>; Sascha Hauer <s.hauer@pengutronix.de>
>> Cc: Shuah Khan <skhan@linuxfoundation.org>; linux-gpio@vger.kernel.org; linux-
>> doc@vger.kernel.org; linux-kernel@vger.kernel.org; Pengutronix Kernel Team
>> <kernel@pengutronix.de>; Fabio Estevam <festevam@gmail.com>; Peng Fan
>> <peng.fan@nxp.com>; devicetree@vger.kernel.org; linux-
>> remoteproc@vger.kernel.org; imx@lists.linux.dev; linux-arm-
>> kernel@lists.infradead.org; dl-linux-imx <linux-imx@nxp.com>; Bartosz
>> Golaszewski <brgl@bgdev.pl>; Andrew Lunn <andrew@lunn.ch>
>> Subject: Re: [EXT] Re: [PATCH v13 3/4] gpio: rpmsg: add generic rpmsg GPIO
>> driver
>>
>> Caution: This is an external email. Please take care when clicking links or opening
>> attachments. When in doubt, report the message using the 'Report this email'
>> button
>>
>>
>> On 4/28/2026 8:13 PM, Shenwei Wang wrote:
>>>> -----Original Message-----
>>>> From: Beleswar Prasad Padhi <b-padhi@ti.com>
>>>> Sent: Tuesday, April 28, 2026 2:25 AM
>>>> To: Shenwei Wang <shenwei.wang@nxp.com>; Linus Walleij
>>>> <linusw@kernel.org>; Bartosz Golaszewski <brgl@kernel.org>; Jonathan
>>>> Corbet <corbet@lwn.net>; Rob Herring <robh@kernel.org>; Krzysztof
>>>> Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>;
>>>> Bjorn Andersson <andersson@kernel.org>; Mathieu Poirier
>>>> <mathieu.poirier@linaro.org>; Frank Li <frank.li@nxp.com>; Sascha
>>>> Hauer <s.hauer@pengutronix.de>
>>>> Cc: Shuah Khan <skhan@linuxfoundation.org>;
>>>> linux-gpio@vger.kernel.org; linux- doc@vger.kernel.org;
>>>> linux-kernel@vger.kernel.org; Pengutronix Kernel Team
>>>> <kernel@pengutronix.de>; Fabio Estevam <festevam@gmail.com>; Peng Fan
>>>> <peng.fan@nxp.com>; devicetree@vger.kernel.org; linux-
>>>> remoteproc@vger.kernel.org; imx@lists.linux.dev; linux-arm-
>>>> kernel@lists.infradead.org; dl-linux-imx <linux-imx@nxp.com>; Bartosz
>>>> Golaszewski <brgl@bgdev.pl>; Andrew Lunn <andrew@lunn.ch>
>>>> Subject: [EXT] Re: [PATCH v13 3/4] gpio: rpmsg: add generic rpmsg
>>>> GPIO driver On 28/04/26 00:53, Shenwei Wang wrote:
>>>> [...]
>>>>
>>>>>>> + void *channel_devices[MAX_PORT_PER_CHANNEL];
>>>>>> So this is technically a rpmsg endpoint (struct rpmsg_endpoint)
>>>>>> without naming it "endpoint". Every rpmsg endpoint has a reference
>>>>>> to its parent rpmsg channel (struct rpmsg_device) which represents
>>>>>> the same information here. So we should use the framework standard here.
>>>>>>
>>>>> Yes, agree to use "endpoint_devices".
>>>> I did not mean to say to just change the variable name from
>>>> "channel_devices" to "endpoint_devices". Infact you would not need to
>>>> have this field & struct anymore.
>>>>
>>>> Pseudo-code:
>>>> 1. Add a 'struct rpmsg_endpoint *ept' field to struct rpmsg_gpio_port
>>>> to maintain the ept to port idx map.
>>>>
>>>> 2. Call port->ept = rpmsg_create_ept(rpdev,
>>>> rpmsg_gpio_channel_callback,
>>>> port, {rpdev.id.name,
>>>> RPMSG_ADDR_ANY,
>>>> RPMSG_ADDR_ANY})
>>>> from rpmsg_gpiochip_register().
>>>>
>>> On the Linux side, we invoke rpmsg_create_ept. What is expected from the
>> remote system in this case?
>>
>>
>> Nothing extra in my opinion. rpmsg_create_ept() just creates a dynamic local
>> endpoint address for Linux's usage. The firmware just has to make sure to reply
>> to the same endpoint address where it received the message. This should already
>> be in place IMO, because currently you are sending all messages in the default
> Since rpmsg_create_ept creates a new local endpoint address on the Linux side, how is
> the remote system expected to learn and use this new address for communication if no
> additional logic is added on the remote side?
Remote side learns the endpoint when it receives any message from Linux
from the dynamic endpoint.
Lets say rpmsg_create_ept() allocates a dynamic local ept of 1026. When
you send the message from this endpoint, the standard rpmsg header
would have:
85 struct rpmsg_hdr {
86 __rpmsg32 src; // 1026
87 __rpmsg32 dst; // rpdev->dst (e.g. 400)
88 __rpmsg32 reserved;
89 __rpmsg16 len;
90 __rpmsg16 flags;
91 u8 data[];
92 } __packed;
Remote side tracks the dynamic endpoint by reading src = 1026. And while
sending the response it fills the header as:
85 struct rpmsg_hdr {
86 __rpmsg32 src; // 400
87 __rpmsg32 dst; // 1026
88 __rpmsg32 reserved;
89 __rpmsg16 len;
90 __rpmsg16 flags;
91 u8 data[];
92 } __packed;
Note: Remote firmware can also send messages from dynamically created
endpoints on its side, and Linux can learn those in the same manner. The
dynamic endpoint address is passed to the callback as 'u32 src'. So you
could pass on the 'src' from rpmsg_gpio_channel_callback() to
rpmsg_gpio_send_message() as 'dst' and call
rpmsg_sendto(port->ept, msg, sizeof(*msg), dst) to reply to the dynamic
endpoint on firmware's side.
Thanks,
Beleswar
>
> Is this handled automatically by the rpmsg stack software, or does it require explicit support
> on the remote system to exchange and track endpoint addresses?
>
> Thanks,
> Shenwei
>
>> endpoint (rpdev->ept) which is also dynamic[1] and is created when the channel
>> is created. And you receive the responses correctly. (Unless you have hard-coded
>> the default ept address in the firmware)
>>
>> [1]:
>> https://github.co/
>> m%2Ftorvalds%2Flinux%2Fblob%2Fmaster%2Fdrivers%2Frpmsg%2Frpmsg_core.
>> c%23L480&data=05%7C02%7Cshenwei.wang%40nxp.com%7C4ec06bf01bb14dd
>> 2625708dea5387471%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C6
>> 39129859078622527%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRyd
>> WUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%
>> 3D%7C0%7C%7C%7C&sdata=OUmjqOdWqiXSTjPDv1TUvrjKP1YTx9ji44SdGlIR2n
>> Q%3D&reserved=0
>> (chinfo.src is RPMSG_ADDR_ANY)
>>
>> Thanks,
>> Beleswar
>>
>>> If the remote side does not need any extra support, this would be an excellent
>> solution.
>>> Thanks,
>>> Shenwei
>>>
>>>> 3. Send msgs from local ept in rpmsg_gpio_send_message() by:
>>>> rpmsg_send(port->ept, msg, sizeof(*msg));
>>>>
>>>> 4. Get the port info in rpmsg_gpio_channel_callback() by:
>>>> struct rpmsg_gpio_port *port = priv;
>>>>
>>>> Which also eliminates the need for struct rpdev_drvdata as you can
>>>> just do
>>>> rpmsg_get_rproc_node_name(rpdev) from rpmsg_gpiochip_register().
>>>>
^ permalink raw reply
* Re: [REGRESSION] rseq: refactoring in v6.19 broke everyone on arm64 and tcmalloc everywhere
From: Thomas Gleixner @ 2026-04-28 15:46 UTC (permalink / raw)
To: Mathias Stearn, Dmitry Vyukov
Cc: Peter Zijlstra, Jinjie Ruan, linux-man, Mark Rutland,
Mathieu Desnoyers, Catalin Marinas, Will Deacon, Boqun Feng,
Paul E. McKenney, Chris Kennelly, regressions, linux-kernel,
linux-arm-kernel, Ingo Molnar, Blake Oler, Florian Weimer,
Rich Felker, Matthew Wilcox, Greg Kroah-Hartman, Linus Torvalds
In-Reply-To: <CAHnCjA2sCwOumOjWm=wW=Kj0C83KVW5zS+51=9=YSeAzuEaVQA@mail.gmail.com>
On Tue, Apr 28 2026 at 15:31, Mathias Stearn wrote:
> On Tue, Apr 28, 2026 at 11:54 AM Dmitry Vyukov <dvyukov@google.com> wrote:
>>
>> On Tue, 28 Apr 2026 at 10:18, Thomas Gleixner <tglx@kernel.org> wrote:
>> >
>> > Is there a pre-compiled version of those tcmalloc tests somewhere?
>>
>> I've attached an archive with 2 tests that I used.
>
> Here is an additional test. It is the stress test I used to show that
> it could result in two live allocations getting the same address. It
> will run for up to a minute or until the first double allocation gets
> detected (usually within 30ms on 6.19).
Thanks to both of you for providing those binaries.
I've run all three binaries now on my latest version in parallel for
quite same time and it seems to hold up. Mark just told me privately
that these plus the arm64 fix he's working on survive that double
allocation test.
Let me go and write a cover letter and post the pile.
Thanks,
tglx
^ permalink raw reply
* RE: [PATCH v3 08/11] drm/bridge: adv7511: switch to of_drm_get_bridge_by_endpoint()
From: Biju Das @ 2026-04-28 15:41 UTC (permalink / raw)
To: Luca Ceresoli, Andrzej Hajda, Neil Armstrong, Robert Foss,
laurent.pinchart, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, Xinliang Liu,
Sumit Semwal, Yongqin Liu, John Stultz, tomi.valkeinen,
Michal Simek
Cc: Hui Pu, Ian Ray, Thomas Petazzoni,
dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
linux-arm-msm@vger.kernel.org, freedreno@lists.freedesktop.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20260428-drm-bridge-alloc-getput-panel_or_bridge-v3-8-a537b5567add@bootlin.com>
Hi Luca,
Thanks for the patch.
> -----Original Message-----
> From: dri-devel <dri-devel-bounces@lists.freedesktop.org> On Behalf Of Luca Ceresoli
> Sent: 28 April 2026 16:31
> Subject: [PATCH v3 08/11] drm/bridge: adv7511: switch to of_drm_get_bridge_by_endpoint()
>
> This driver calls drm_of_find_panel_or_bridge() with a NULL pointer in the @panel parameter, thus using
> a reduced feature set of that function.
> Replace this call with the simpler of_drm_get_bridge_by_endpoint().
>
> Since of_drm_get_bridge_by_endpoint() increases the refcount of the returned bridge, ensure it is put
> on removal. To achieve this, instead of adding an explicit drm_bridge_put(), migrate to the
> bridge::next_bridge pointer which is automatically put when the bridge is eventually freed.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Tested on RZ/G3L SMARC EVK connected to ADV7535.
Tested-by: Biju Das <biju.das.jz@bp.renesas.com>
Cheers,
Biju
>
> ---
>
> Changes in v3:
> - fix ERR_PTR deref when -ENODEV is returned
> ---
> drivers/gpu/drm/bridge/adv7511/adv7511.h | 1 -
> drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 15 +++++++++------
> 2 files changed, 9 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
> index 8be7266fd4f4..12c95198d9a4 100644
> --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
> @@ -354,7 +354,6 @@ struct adv7511 {
> enum drm_connector_status status;
> bool powered;
>
> - struct drm_bridge *next_bridge;
> struct drm_display_mode curr_mode;
>
> unsigned int f_tmds;
> diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> index 6bd76c1fb007..3c516551e482 100644
> --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> @@ -851,8 +851,8 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge,
> struct adv7511 *adv = bridge_to_adv7511(bridge);
> int ret = 0;
>
> - if (adv->next_bridge) {
> - ret = drm_bridge_attach(encoder, adv->next_bridge, bridge,
> + if (adv->bridge.next_bridge) {
> + ret = drm_bridge_attach(encoder, adv->bridge.next_bridge, bridge,
> flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> if (ret)
> return ret;
> @@ -1251,10 +1251,13 @@ static int adv7511_probe(struct i2c_client *i2c)
>
> memset(&link_config, 0, sizeof(link_config));
>
> - ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL,
> - &adv7511->next_bridge);
> - if (ret && ret != -ENODEV)
> - return ret;
> + adv7511->bridge.next_bridge = of_drm_get_bridge_by_endpoint(dev->of_node, 1, -1);
> + if (IS_ERR(adv7511->bridge.next_bridge)) {
> + if (PTR_ERR(adv7511->bridge.next_bridge) == -ENODEV)
> + adv7511->bridge.next_bridge = NULL;
> + else
> + return PTR_ERR(adv7511->bridge.next_bridge);
> + }
>
> if (adv7511->info->link_config)
> ret = adv7511_parse_dt(dev->of_node, &link_config);
>
> --
> 2.53.0
^ permalink raw reply
* [arm-platforms:kvm-arm64/no-lazy-vgic-init 22/26] include/kvm/arm_pmu.h:134:46: warning: no return statement in function returning non-void
From: kernel test robot @ 2026-04-28 15:40 UTC (permalink / raw)
To: Marc Zyngier; +Cc: oe-kbuild-all, linux-arm-kernel
tree: https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/no-lazy-vgic-init
head: 3bba2d1179c5198c5788cd387feeeba2070e7cd9
commit: 4c12b5742e18dbd00b0b59f3882478219d73b463 [22/26] KVM: arm64: Simplify userspace notification of interrupt state
config: arm64-allnoconfig (https://download.01.org/0day-ci/archive/20260428/202604282305.uZdSNvk7-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260428/202604282305.uZdSNvk7-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604282305.uZdSNvk7-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from arch/arm64/include/asm/kvm_host.h:38,
from include/linux/kvm_host.h:45,
from arch/arm64/kernel/asm-offsets.c:16:
include/kvm/arm_pmu.h: In function 'kvm_pmu_update_run':
>> include/kvm/arm_pmu.h:134:46: warning: no return statement in function returning non-void [-Wreturn-type]
134 | static inline bool kvm_pmu_update_run(struct kvm_vcpu *vcpu) {}
| ^~~~~~~~
--
In file included from arch/arm64/include/asm/kvm_host.h:38,
from include/linux/kvm_host.h:45,
from arch/arm64/kernel/asm-offsets.c:16:
include/kvm/arm_pmu.h: In function 'kvm_pmu_update_run':
>> include/kvm/arm_pmu.h:134:46: warning: no return statement in function returning non-void [-Wreturn-type]
134 | static inline bool kvm_pmu_update_run(struct kvm_vcpu *vcpu) {}
| ^~~~~~~~
vim +134 include/kvm/arm_pmu.h
106
107 #define kvm_arm_pmu_irq_initialized(v) (false)
108 static inline u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu,
109 u64 select_idx)
110 {
111 return 0;
112 }
113 static inline void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu,
114 u64 select_idx, u64 val) {}
115 static inline void kvm_pmu_set_counter_value_user(struct kvm_vcpu *vcpu,
116 u64 select_idx, u64 val) {}
117 static inline u64 kvm_pmu_implemented_counter_mask(struct kvm_vcpu *vcpu)
118 {
119 return 0;
120 }
121 static inline u64 kvm_pmu_accessible_counter_mask(struct kvm_vcpu *vcpu)
122 {
123 return 0;
124 }
125 static inline void kvm_pmu_vcpu_init(struct kvm_vcpu *vcpu) {}
126 static inline void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu) {}
127 static inline void kvm_pmu_reprogram_counter_mask(struct kvm_vcpu *vcpu, u64 val) {}
128 static inline void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
129 static inline void kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu) {}
130 static inline bool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu)
131 {
132 return false;
133 }
> 134 static inline bool kvm_pmu_update_run(struct kvm_vcpu *vcpu) {}
135 static inline void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
136 static inline void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val) {}
137 static inline void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu,
138 u64 data, u64 select_idx) {}
139 static inline int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu,
140 struct kvm_device_attr *attr)
141 {
142 return -ENXIO;
143 }
144 static inline int kvm_arm_pmu_v3_get_attr(struct kvm_vcpu *vcpu,
145 struct kvm_device_attr *attr)
146 {
147 return -ENXIO;
148 }
149 static inline int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu,
150 struct kvm_device_attr *attr)
151 {
152 return -ENXIO;
153 }
154 static inline int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
155 {
156 return 0;
157 }
158 static inline u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
159 {
160 return 0;
161 }
162
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* RE: [PATCH v3 10/11] drm: zynqmp_dp: switch to of_drm_get_bridge_by_endpoint()
From: Biju Das @ 2026-04-28 15:37 UTC (permalink / raw)
To: Luca Ceresoli, Andrzej Hajda, Neil Armstrong, Robert Foss,
laurent.pinchart, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, Xinliang Liu,
Sumit Semwal, Yongqin Liu, John Stultz, tomi.valkeinen,
Michal Simek
Cc: Hui Pu, Ian Ray, Thomas Petazzoni,
dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
linux-arm-msm@vger.kernel.org, freedreno@lists.freedesktop.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20260428-drm-bridge-alloc-getput-panel_or_bridge-v3-10-a537b5567add@bootlin.com>
Hi Luca,
> -----Original Message-----
> From: dri-devel <dri-devel-bounces@lists.freedesktop.org> On Behalf Of Luca Ceresoli
> Sent: 28 April 2026 16:31
> Subject: [PATCH v3 10/11] drm: zynqmp_dp: switch to of_drm_get_bridge_by_endpoint()
>
> This driver calls drm_of_find_panel_or_bridge() with a NULL pointer in the @panel parameter, thus using
> a reduced feature set of that function.
> Replace this call with the simpler of_drm_get_bridge_by_endpoint().
>
> Since of_drm_get_bridge_by_endpoint() increases the refcount of the returned bridge, ensure it is put
> on removal. To achieve this, instead of adding an explicit drm_bridge_put(), migrate to the
> bridge::next_bridge pointer which is automatically put when the bridge is eventually freed.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
>
> ---
>
> Changes in v3:
> - fix ERR_PTR deref when -ENODEV is returned
> ---
> drivers/gpu/drm/xlnx/zynqmp_dp.c | 19 +++++++++++--------
> 1 file changed, 11 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
> index 379180fb3004..c5aa236d6b74 100644
> --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
> +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
> @@ -353,7 +353,6 @@ struct zynqmp_dp_train_set_priv {
> * @lock: Mutex protecting this struct and register access (but not AUX)
> * @irq: irq
> * @bridge: DRM bridge for the DP encoder
> - * @next_bridge: The downstream bridge
> * @test: Configuration for test mode
> * @config: IP core configuration from DTS
> * @aux: aux channel
> @@ -385,7 +384,6 @@ struct zynqmp_dp {
> struct completion aux_done;
> struct mutex lock;
>
> - struct drm_bridge *next_bridge;
> struct device *dev;
> struct zynqmp_dpsub *dpsub;
> void __iomem *iomem;
> @@ -1494,8 +1492,8 @@ static int zynqmp_dp_bridge_attach(struct drm_bridge *bridge,
> return ret;
> }
>
> - if (dp->next_bridge) {
> - ret = drm_bridge_attach(encoder, dp->next_bridge,
> + if (dp->bridge.next_bridge) {
> + ret = drm_bridge_attach(encoder, dp->bridge.next_bridge,
> bridge, flags);
> if (ret < 0)
> goto error;
> @@ -2461,10 +2459,15 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub)
> * Acquire the next bridge in the chain. Ignore errors caused by port@5
> * not being connected for backward-compatibility with older DTs.
> */
> - ret = drm_of_find_panel_or_bridge(dp->dev->of_node, 5, 0, NULL,
> - &dp->next_bridge);
> - if (ret < 0 && ret != -ENODEV)
> - goto err_reset;
> + dp->bridge.next_bridge = of_drm_get_bridge_by_endpoint(dp->dev->of_node, 5, 0);
> + if (IS_ERR(dp->bridge.next_bridge)) {
> + if (PTR_ERR(dp->bridge.next_bridge) == -ENODEV) {
> + dp->bridge.next_bridge;
A warning on this patch
drivers/gpu/drm/xlnx/zynqmp_dp.c: In function ‘zynqmp_dp_probe’:
drivers/gpu/drm/xlnx/zynqmp_dp.c:2465:35: warning: statement with no effect [-Wunused-value]
2465 | dp->bridge.next_bridge;
| ~~~~~~~~~~^~~~~~~~~~~~
Cheers,
Biju
> + } else {
> + ret = PTR_ERR(dp->bridge.next_bridge);
> + goto err_reset;
> + }
> + }
>
> /* Initialize the hardware. */
> dp->config.misc0 &= ~ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK;
>
> --
> 2.53.0
^ permalink raw reply
* Re: [PATCH v3 2/3] crypto: atmel-sha204a - fix truncated 32-byte blocking read
From: Thorsten Blum @ 2026-04-28 15:35 UTC (permalink / raw)
To: Lothar Rubusch
Cc: herbert, davem, nicolas.ferre, alexandre.belloni, claudiu.beznea,
ardb, linusw, linux-crypto, linux-arm-kernel, linux-kernel
In-Reply-To: <20260422210936.20095-3-l.rubusch@gmail.com>
On Wed, Apr 22, 2026 at 09:09:35PM +0000, Lothar Rubusch wrote:
> The ATSHA204A returns a 35-byte packet consisting of a 1-byte count,
> 32 bytes of entropy, and a 2-byte CRC. The current blocking read
> implementation was incorrectly copying data starting from the
> count byte, leading to offset data and truncated entropy.
>
> Additionally, the chip requires significant execution time to
> generate random numbers, going by the datasheet. Reading the I2C bus
> too early results in the chip NACK-ing or returning a partial buffer
> followed by zeros.
>
> Verification:
> Tests before showed repeadetly reading only 8 bytes of entropy:
> $ head -c 32 /dev/hwrng | hexdump -C
> 00000000 02 28 85 b3 47 40 f2 ee 00 00 00 00 00 00 00 00 |.(..G@..........|
> 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
> 00000020
>
> After this patch applied, the result will be as follows:
> $ head -c 32 /dev/hwrng | hexdump -C
> 00000000 5a fc 3f 13 14 68 fe 06 68 0a bd 04 83 6e 09 69 |Z.?..h..h....n.i|
> 00000010 75 ff cf 87 10 84 3b c9 c1 df ae eb 45 53 4c c3 |u.....;.....ESL.|
> 00000020
>
> Fix these issues by:
> Increase cmd.msecs to 30ms to provide sufficient execution time. Then
> set cmd.rxsize to RANDOM_RSP_SIZE (35 bytes) to capture the entire
> hardware response. Eventually, correct the memcpy() offset to index 1 of
> the data buffer to skip the count byte and retrieve exactly 32 bytes of
> entropy.
>
> Fixes: da001fb651b0 ("crypto: atmel-i2c - add support for SHA204A random number generator")
> Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
> ---
> drivers/crypto/atmel-sha204a.c | 9 +++++++--
> 1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
> index 19720bdd446d..f7dc00d0f4cd 100644
> --- a/drivers/crypto/atmel-sha204a.c
> +++ b/drivers/crypto/atmel-sha204a.c
> @@ -19,6 +19,9 @@
> #include <linux/workqueue.h>
> #include "atmel-i2c.h"
>
> +#define ATMEL_RNG_BLOCK_SIZE 32
> +#define ATMEL_RNG_EXEC_TIME 30
Maybe I missed it, but how did you arrive at 30 ms from the datasheet?
Thanks,
Thorsten
^ permalink raw reply
* [PATCH v3 11/11] drm: of: forbid bridge-only calls to drm_of_find_panel_or_bridge()
From: Luca Ceresoli @ 2026-04-28 15:31 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Clark,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Sean Paul,
Marijn Suijten, Xinliang Liu, Sumit Semwal, Yongqin Liu,
John Stultz, Tomi Valkeinen, Michal Simek
Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel,
linux-arm-msm, freedreno, linux-arm-kernel, Luca Ceresoli,
Dmitry Baryshkov
In-Reply-To: <20260428-drm-bridge-alloc-getput-panel_or_bridge-v3-0-a537b5567add@bootlin.com>
Up to now drm_of_find_panel_or_bridge() can be called with a bridge pointer
only, a panel pointer only, or both a bridge and a panel pointers. The
logic to handle all the three cases is somewhat complex to read however.
Now all bridge-only callers have been converted to
of_drm_get_bridge_by_endpoint(), which is simpler and handles bridge
refcounting. So forbid new bridge-only users by mandating a non-NULL panel
pointer in the docs and in the sanity checks along with a warning.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/drm_of.c | 26 ++++++++++++--------------
1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index ef6b09316963..d03ada82eac9 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -225,15 +225,15 @@ EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint);
* @np: device tree node containing encoder output ports
* @port: port in the device tree node
* @endpoint: endpoint in the device tree node
- * @panel: pointer to hold returned drm_panel
+ * @panel: pointer to hold returned drm_panel, must not be NULL
* @bridge: pointer to hold returned drm_bridge
*
* Given a DT node's port and endpoint number, find the connected node and
- * return either the associated struct drm_panel or drm_bridge device. Either
- * @panel or @bridge must not be NULL.
+ * return either the associated struct drm_panel or drm_bridge device.
*
* This function is deprecated and should not be used in new drivers. Use
- * devm_drm_of_get_bridge() instead.
+ * of_drm_get_bridge_by_endpoint() instead when not looking for a panel, or
+ * devm_drm_of_get_bridge() otherwise.
*
* Returns zero if successful, or one of the standard error codes if it fails.
*/
@@ -245,10 +245,10 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
int ret = -EPROBE_DEFER;
struct device_node *remote;
- if (!panel && !bridge)
+ if (WARN_ON(!panel))
return -EINVAL;
- if (panel)
- *panel = NULL;
+
+ *panel = NULL;
/*
* of_graph_get_remote_node() produces a noisy error message if port
@@ -263,13 +263,11 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
if (!remote)
return -ENODEV;
- if (panel) {
- *panel = of_drm_find_panel(remote);
- if (!IS_ERR(*panel))
- ret = 0;
- else
- *panel = NULL;
- }
+ *panel = of_drm_find_panel(remote);
+ if (!IS_ERR(*panel))
+ ret = 0;
+ else
+ *panel = NULL;
if (bridge) {
if (ret) {
--
2.53.0
^ permalink raw reply related
* [PATCH v3 09/11] drm/bridge: lt8713sx: switch to of_drm_get_bridge_by_endpoint()
From: Luca Ceresoli @ 2026-04-28 15:30 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Clark,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Sean Paul,
Marijn Suijten, Xinliang Liu, Sumit Semwal, Yongqin Liu,
John Stultz, Tomi Valkeinen, Michal Simek
Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel,
linux-arm-msm, freedreno, linux-arm-kernel, Luca Ceresoli,
Dmitry Baryshkov
In-Reply-To: <20260428-drm-bridge-alloc-getput-panel_or_bridge-v3-0-a537b5567add@bootlin.com>
This driver calls drm_of_find_panel_or_bridge() with a NULL pointer in the
@panel parameter, thus using a reduced feature set of that function.
Replace this call with the simpler of_drm_get_bridge_by_endpoint().
Since of_drm_get_bridge_by_endpoint() increases the refcount of the
returned bridge, ensure it is put on removal. To achieve this, instead of
adding an explicit drm_bridge_put(), migrate to the bridge::next_bridge
pointer which is automatically put when the bridge is eventually freed.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/lontium-lt8713sx.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/bridge/lontium-lt8713sx.c b/drivers/gpu/drm/bridge/lontium-lt8713sx.c
index 18fac6a46db4..cee485adf5e5 100644
--- a/drivers/gpu/drm/bridge/lontium-lt8713sx.c
+++ b/drivers/gpu/drm/bridge/lontium-lt8713sx.c
@@ -32,7 +32,6 @@ DECLARE_CRC8_TABLE(lt8713sx_crc_table);
struct lt8713sx {
struct device *dev;
struct drm_bridge bridge;
- struct drm_bridge *next_bridge;
struct regmap *regmap;
/* Protects all accesses to registers by stopping the on-chip MCU */
@@ -458,7 +457,7 @@ static int lt8713sx_bridge_attach(struct drm_bridge *bridge,
struct lt8713sx *lt8713sx = container_of(bridge, struct lt8713sx, bridge);
return drm_bridge_attach(encoder,
- lt8713sx->next_bridge,
+ lt8713sx->bridge.next_bridge,
bridge, flags);
}
@@ -537,10 +536,9 @@ static int lt8713sx_probe(struct i2c_client *client)
if (IS_ERR(lt8713sx->regmap))
return dev_err_probe(dev, PTR_ERR(lt8713sx->regmap), "regmap i2c init failed\n");
- ret = drm_of_find_panel_or_bridge(lt8713sx->dev->of_node, 1, -1, NULL,
- <8713sx->next_bridge);
- if (ret < 0)
- return ret;
+ lt8713sx->bridge.next_bridge = of_drm_get_bridge_by_endpoint(lt8713sx->dev->of_node, 1, -1);
+ if (IS_ERR(lt8713sx->bridge.next_bridge))
+ return PTR_ERR(lt8713sx->bridge.next_bridge);
ret = lt8713sx_gpio_init(lt8713sx);
if (ret < 0)
--
2.53.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