| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/06 09:40 | flow | patch-triage |
5mArgs:null Results: {
"EnableConfigs": [
"KVM"
],
"FocusSymbols": [
"kvm_init_with_dev",
"vfio_device_get_kvm_safe",
"vfio_device_put_kvm",
"vfio_file_set_kvm",
"gmap_prepare_memory_region",
"gmap_commit_memory_region",
"gmap_get_dirty_log",
"gmap_test_age_gfn",
"gmap_pre_fault_memory",
"gmap_enable_skeys",
"dat_set_storage_key"
],
"Reasoning": "The patch introduces support for running arm64 guests on s390x hosts. While the actual arm64 execution requires the Arm Execution Facility (AEF) hardware feature which is not available in QEMU, the patch also significantly refactors the existing s390x KVM code (e.g., separating gmap and s390 specific KVM code) and modifies core KVM/VFIO reference counting logic (e.g., kvm_init_with_dev, vfio_device_get_kvm_safe). These core KVM and s390x KVM refactoring changes are reachable and should be fuzzed.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/06 09:40 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit dcc55d0914e18b996dc0d615bfdf95353e70be81\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Jul 6 09:40:50 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/arch/arm64/Makefile b/arch/arm64/Makefile\nindex 6b005c8fef7066..1cd7cd94a8554f 100644\n--- a/arch/arm64/Makefile\n+++ b/arch/arm64/Makefile\n@@ -43,7 +43,9 @@ CC_FLAGS_NO_FPU\t:= -mgeneral-regs-only\n KBUILD_CFLAGS\t+= $(CC_FLAGS_NO_FPU) \\\n \t\t $(compat_vdso) $(cc_has_k_constraint)\n KBUILD_CFLAGS\t+= $(call cc-disable-warning, psabi)\n+KBUILD_CFLAGS\t+= -DARM64_S390_COMMON\n KBUILD_AFLAGS\t+= $(compat_vdso)\n+KBUILD_AFLAGS\t+= -DARM64_S390_COMMON\n \n ifeq ($(call rustc-min-version, 108500),y)\n KBUILD_RUSTFLAGS += --target=aarch64-unknown-none-softfloat\ndiff --git a/arch/arm64/include/asm/brk-imm.h b/arch/arm64/include/asm/brk-imm.h\nindex beb42c62b6acc5..dd2d153dc0d81b 100644\n--- a/arch/arm64/include/asm/brk-imm.h\n+++ b/arch/arm64/include/asm/brk-imm.h\n@@ -2,6 +2,7 @@\n /*\n * Copyright (C) 2012 ARM Ltd.\n */\n+/* Whole file is shared with s390 */\n \n #ifndef __ASM_BRK_IMM_H\n #define __ASM_BRK_IMM_H\ndiff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h\nindex 81c17320a588d9..e25b742b09ac9f 100644\n--- a/arch/arm64/include/asm/esr.h\n+++ b/arch/arm64/include/asm/esr.h\n@@ -3,11 +3,12 @@\n * Copyright (C) 2013 - ARM Ltd\n * Author: Marc Zyngier \u003cmarc.zyngier@arm.com\u003e\n */\n+/* Whole file is shared with s390 */\n \n #ifndef __ASM_ESR_H\n #define __ASM_ESR_H\n \n-#include \u003casm/memory.h\u003e\n+#include \u003casm/brk-imm.h\u003e\n #include \u003casm/sysreg.h\u003e\n \n #define ESR_ELx_EC_UNKNOWN\tUL(0x00)\n@@ -435,7 +436,7 @@\n #define ESR_ELx_IT_GCSPOPX\t\t7\n \n #ifndef __ASSEMBLER__\n-#include \u003casm/types.h\u003e\n+#include \u003clinux/types.h\u003e\n \n static inline unsigned long esr_brk_comment(unsigned long esr)\n {\ndiff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h\nindex 3f9233b5a13081..cc4175176f947a 100644\n--- a/arch/arm64/include/asm/kvm_arm.h\n+++ b/arch/arm64/include/asm/kvm_arm.h\n@@ -3,14 +3,16 @@\n * Copyright (C) 2012,2013 - ARM Ltd\n * Author: Marc Zyngier \u003cmarc.zyngier@arm.com\u003e\n */\n+/* Whole file is shared with s390 */\n \n #ifndef __ARM64_KVM_ARM_H__\n #define __ARM64_KVM_ARM_H__\n \n+#include \u003clinux/const.h\u003e\n+#include \u003clinux/bits.h\u003e\n+#include \u003clinux/types.h\u003e\n #include \u003casm/esr.h\u003e\n-#include \u003casm/memory.h\u003e\n #include \u003casm/sysreg.h\u003e\n-#include \u003casm/types.h\u003e\n \n /*\n * Because I'm terribly lazy and that repainting the whole of the KVM\ndiff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h\nindex 5bf3d7e1d92c77..15d6d6a08d3712 100644\n--- a/arch/arm64/include/asm/kvm_emulate.h\n+++ b/arch/arm64/include/asm/kvm_emulate.h\n@@ -44,13 +44,18 @@ enum exception_type {\n bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);\n void kvm_skip_instr32(struct kvm_vcpu *vcpu);\n \n+#ifdef ARM64_S390_COMMON\n void kvm_inject_undefined(struct kvm_vcpu *vcpu);\n+#endif /* ARM64_S390_COMMON */\n void kvm_inject_sync(struct kvm_vcpu *vcpu, u64 esr);\n int kvm_inject_serror_esr(struct kvm_vcpu *vcpu, u64 esr);\n+#ifdef ARM64_S390_COMMON\n int kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr);\n+#endif /* ARM64_S390_COMMON */\n int kvm_inject_dabt_excl_atomic(struct kvm_vcpu *vcpu, u64 addr);\n void kvm_inject_size_fault(struct kvm_vcpu *vcpu);\n \n+#ifdef ARM64_S390_COMMON\n static inline int kvm_inject_sea_dabt(struct kvm_vcpu *vcpu, u64 addr)\n {\n \treturn kvm_inject_sea(vcpu, false, addr);\n@@ -61,6 +66,8 @@ static inline int kvm_inject_sea_iabt(struct kvm_vcpu *vcpu, u64 addr)\n \treturn kvm_inject_sea(vcpu, true, addr);\n }\n \n+#endif /* ARM64_S390_COMMON */\n+\n static inline int kvm_inject_serror(struct kvm_vcpu *vcpu)\n {\n \t/*\n@@ -133,12 +140,17 @@ static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)\n \n static __always_inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)\n {\n-\treturn (unsigned long *)\u0026vcpu_gp_regs(vcpu)-\u003epc;\n+\treturn (unsigned long *)\u0026vcpu-\u003earch.ctxt.regs.pc;\n }\n \n static __always_inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)\n {\n-\treturn (unsigned long *)\u0026vcpu_gp_regs(vcpu)-\u003epstate;\n+\treturn (unsigned long *)\u0026vcpu-\u003earch.ctxt.regs.pstate;\n+}\n+\n+static __always_inline unsigned long *vcpu_sp_el0(const struct kvm_vcpu *vcpu)\n+{\n+\treturn (unsigned long *)\u0026vcpu-\u003earch.ctxt.regs.sp;\n }\n \n static __always_inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)\n@@ -159,6 +171,7 @@ static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)\n \t*vcpu_cpsr(vcpu) |= PSR_AA32_T_BIT;\n }\n \n+#ifdef ARM64_S390_COMMON\n /*\n * vcpu_get_reg and vcpu_set_reg should always be passed a register number\n * coming from a read of ESR_EL2. Otherwise, it may give the wrong result on\n@@ -167,16 +180,18 @@ static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)\n static __always_inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,\n \t\t\t\t\t u8 reg_num)\n {\n-\treturn (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)-\u003eregs[reg_num];\n+\treturn (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)[reg_num];\n }\n \n static __always_inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,\n \t\t\t\tunsigned long val)\n {\n \tif (reg_num != 31)\n-\t\tvcpu_gp_regs(vcpu)-\u003eregs[reg_num] = val;\n+\t\tvcpu_gp_regs(vcpu)[reg_num] = val;\n }\n \n+#endif /* ARM64_S390_COMMON */\n+\n static inline bool vcpu_is_el2_ctxt(const struct kvm_cpu_context *ctxt)\n {\n \tswitch (ctxt-\u003eregs.pstate \u0026 (PSR_MODE32_BIT | PSR_MODE_MASK)) {\n@@ -360,6 +375,7 @@ static inline u64 kvm_vcpu_get_disr(const struct kvm_vcpu *vcpu)\n \treturn vcpu-\u003earch.fault.disr_el1;\n }\n \n+#ifdef ARM64_S390_COMMON\n static inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu)\n {\n \treturn kvm_vcpu_get_esr(vcpu) \u0026 ESR_ELx_xVC_IMM_MASK;\n@@ -437,6 +453,8 @@ static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)\n \treturn kvm_vcpu_get_esr(vcpu) \u0026 ESR_ELx_FSC;\n }\n \n+#endif /* ARM64_S390_COMMON */\n+\n static inline\n bool kvm_vcpu_trap_is_permission_fault(const struct kvm_vcpu *vcpu)\n {\n@@ -477,6 +495,7 @@ static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)\n \treturn ESR_ELx_SYS64_ISS_RT(esr);\n }\n \n+#ifdef ARM64_S390_COMMON\n static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)\n {\n \tif (kvm_vcpu_abt_iss1tw(vcpu)) {\n@@ -501,6 +520,8 @@ static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)\n \treturn kvm_vcpu_dabt_iswrite(vcpu);\n }\n \n+#endif /* ARM64_S390_COMMON */\n+\n static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)\n {\n \treturn __vcpu_sys_reg(vcpu, MPIDR_EL1) \u0026 MPIDR_HWID_BITMASK;\n@@ -536,6 +557,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)\n \treturn vcpu_read_sys_reg(vcpu, r) \u0026 bit;\n }\n \n+#ifdef ARM64_S390_COMMON\n static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,\n \t\t\t\t\t\t unsigned long data,\n \t\t\t\t\t\t unsigned int len)\n@@ -611,6 +633,8 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)\n \t\tvcpu_set_flag((v), e);\t\t\t\t\t\\\n \t} while (0)\n \n+#endif /* ARM64_S390_COMMON */\n+\n /*\n * Returns a 'sanitised' view of CPTR_EL2, translating from nVHE to the VHE\n * format if E2H isn't set.\ndiff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h\nindex bae2c4f92ef5c0..2fce38fd91529c 100644\n--- a/arch/arm64/include/asm/kvm_host.h\n+++ b/arch/arm64/include/asm/kvm_host.h\n@@ -33,12 +33,15 @@\n \n #define KVM_HALT_POLL_NS_DEFAULT 500000\n \n+#define HAVE_KVM_MMIO\n+\n #include \u003ckvm/arm_vgic.h\u003e\n #include \u003ckvm/arm_arch_timer.h\u003e\n #include \u003ckvm/arm_pmu.h\u003e\n \n #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS\n \n+#ifdef ARM64_S390_COMMON\n #define KVM_VCPU_MAX_FEATURES 9\n #define KVM_VCPU_VALID_FEATURES\t(BIT(KVM_VCPU_MAX_FEATURES) - 1)\n \n@@ -56,6 +59,8 @@\n #define KVM_REQ_MAP_L1_VNCR_EL2\t\tKVM_ARCH_REQ(10)\n #define KVM_REQ_VGIC_PROCESS_UPDATE\tKVM_ARCH_REQ(11)\n \n+#endif /* ARM64_S390_COMMON */\n+\n #define KVM_DIRTY_LOG_MANUAL_CAPS (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \\\n \t\t\t\t KVM_DIRTY_LOG_INITIALLY_SET)\n \n@@ -338,6 +343,7 @@ struct kvm_arch {\n \t/* Protects VM-scoped configuration data */\n \tstruct mutex config_lock;\n \n+#ifdef ARM64_S390_COMMON\n \t/*\n \t * If we encounter a data abort without valid instruction syndrome\n \t * information, report this to user space. User space can (and\n@@ -367,6 +373,8 @@ struct kvm_arch {\n #define KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS\t\t10\n \t/* Unhandled SEAs are taken to userspace */\n #define KVM_ARCH_FLAG_EXIT_SEA\t\t\t\t11\n+\n+#endif /* ARM64_S390_COMMON */\n \tunsigned long flags;\n \n \t/* VM-wide vCPU feature set */\n@@ -831,6 +839,8 @@ extern s64 kvm_nvhe_sym(hyp_physvirt_offset);\n extern u64 kvm_nvhe_sym(hyp_cpu_logical_map)[NR_CPUS];\n #define hyp_cpu_logical_map CHOOSE_NVHE_SYM(hyp_cpu_logical_map)\n \n+#ifdef ARM64_S390_COMMON\n+\n struct vcpu_reset_state {\n \tunsigned long\tpc;\n \tunsigned long\tr0;\n@@ -838,6 +848,8 @@ struct vcpu_reset_state {\n \tbool\t\treset;\n };\n \n+#endif /* ARM64_S390_COMMON */\n+\n struct vncr_tlb;\n \n struct kvm_vcpu_arch {\n@@ -947,6 +959,7 @@ struct kvm_vcpu_arch {\n \tpid_t pid;\n };\n \n+#ifdef ARM64_S390_COMMON\n /*\n * Each 'flag' is composed of a comma-separated triplet:\n *\n@@ -980,6 +993,8 @@ struct kvm_vcpu_arch {\n \t\tREAD_ONCE(v-\u003earch.flagset) \u0026 (m);\t\t\\\n \t})\n \n+#endif /* ARM64_S390_COMMON */\n+\n /*\n * Note that the set/clear accessors must be preempt-safe in order to\n * avoid nesting them with load/put which also manipulate flags...\n@@ -993,6 +1008,7 @@ struct kvm_vcpu_arch {\n #define __vcpu_flags_preempt_enable()\tpreempt_enable()\n #endif\n \n+#ifdef ARM64_S390_COMMON\n #define __vcpu_set_flag(v, flagset, f, m)\t\t\t\\\n \tdo {\t\t\t\t\t\t\t\\\n \t\ttypeof(v-\u003earch.flagset) *fset;\t\t\t\\\n@@ -1077,6 +1093,8 @@ struct kvm_vcpu_arch {\n #define EXCEPT_AA64_EL2_FIQ\t__vcpu_except_flags(6)\n #define EXCEPT_AA64_EL2_SERR\t__vcpu_except_flags(7)\n \n+#endif /* ARM64_S390_COMMON */\n+\n /* Physical CPU not in supported_cpus */\n #define ON_UNSUPPORTED_CPU\t__vcpu_single_flag(sflags, BIT(0))\n /* WFIT instruction trapped */\n@@ -1152,7 +1170,7 @@ struct kvm_vcpu_arch {\n #define vcpu_clear_on_unsupported_cpu(vcpu)\t\t\t\t\\\n \tvcpu_clear_flag(vcpu, ON_UNSUPPORTED_CPU)\n \n-#define vcpu_gp_regs(v)\t\t(\u0026(v)-\u003earch.ctxt.regs)\n+#define vcpu_gp_regs(v)\t\t((v)-\u003earch.ctxt.regs.regs)\n \n /*\n * Only use __vcpu_sys_reg/ctxt_sys_reg if you know you want the\n@@ -1183,6 +1201,12 @@ static inline u64 *___ctxt_sys_reg(const struct kvm_cpu_context *ctxt, int r)\n \n #define ctxt_sys_reg(c,r)\t(*__ctxt_sys_reg(c,r))\n \n+#define kvm_vcpu_get_sp_el1(__vcpu) (__ctxt_sys_reg(\u0026(__vcpu)-\u003earch.ctxt, SP_EL1))\n+#define kvm_vcpu_get_vreg(__vcpu, _n) (\u0026(__vcpu)-\u003earch.ctxt.fp_regs.vregs[_n])\n+#define kvm_vcpu_get_vregs(__vcpu) (\u0026(__vcpu)-\u003earch.ctxt.fp_regs.vregs)\n+#define kvm_vcpu_get_fpsr(__vcpu) (\u0026(__vcpu)-\u003earch.ctxt.fp_regs.fpsr)\n+#define kvm_vcpu_get_fpcr(__vcpu) (\u0026(__vcpu)-\u003earch.ctxt.fp_regs.fpcr)\n+\n u64 kvm_vcpu_apply_reg_masks(const struct kvm_vcpu *, enum vcpu_sysreg, u64);\n \n #define __vcpu_assign_sys_reg(v, r, val)\t\t\t\t\\\n@@ -1234,7 +1258,10 @@ struct kvm_vcpu_stat {\n };\n \n unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);\n+#ifdef ARM64_S390_COMMON\n int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);\n+\n+#endif /* ARM64_S390_COMMON */\n int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);\n int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);\n \n@@ -1319,6 +1346,7 @@ int __init populate_nv_trap_config(void);\n \n void kvm_calculate_traps(struct kvm_vcpu *vcpu);\n \n+#ifdef ARM64_S390_COMMON\n /* MMIO helpers */\n void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);\n unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);\n@@ -1326,6 +1354,8 @@ unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);\n int kvm_handle_mmio_return(struct kvm_vcpu *vcpu);\n int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa);\n \n+#endif /* ARM64_S390_COMMON */\n+\n /*\n * Returns true if a Performance Monitoring Interrupt (PMI), a.k.a. perf event,\n * arrived in guest context. For arm64, any event that arrives while a vCPU is\n@@ -1500,8 +1530,11 @@ struct kvm *kvm_arch_alloc_vm(void);\n \n #define kvm_vm_is_protected(kvm)\t(is_protected_kvm_enabled() \u0026\u0026 (kvm)-\u003earch.pkvm.is_protected)\n \n+#ifdef ARM64_S390_COMMON\n #define vcpu_is_protected(vcpu)\t\tkvm_vm_is_protected((vcpu)-\u003ekvm)\n \n+#endif /* ARM64_S390_COMMON */\n+\n int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature);\n bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);\n \n@@ -1526,8 +1559,11 @@ static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature)\n #define kvm_vcpu_has_feature(k, f)\t__vcpu_has_feature(\u0026(k)-\u003earch, (f))\n #define vcpu_has_feature(v, f)\t__vcpu_has_feature(\u0026(v)-\u003ekvm-\u003earch, (f))\n \n+#ifdef ARM64_S390_COMMON\n #define kvm_vcpu_initialized(v) vcpu_get_flag(v, VCPU_INITIALIZED)\n \n+#endif /* ARM64_S390_COMMON */\n+\n int kvm_trng_call(struct kvm_vcpu *vcpu);\n #ifdef CONFIG_KVM\n extern phys_addr_t hyp_mem_base;\ndiff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h\nindex 6eae7e7e2a6845..b782cae771fe89 100644\n--- a/arch/arm64/include/asm/kvm_mmu.h\n+++ b/arch/arm64/include/asm/kvm_mmu.h\n@@ -142,12 +142,15 @@ static __always_inline unsigned long __kern_hyp_va(unsigned long v)\n \n extern u32 __hyp_va_bits;\n \n+#ifdef ARM64_S390_COMMON\n /*\n * We currently support using a VM-specified IPA size. For backward\n * compatibility, the default IPA size is fixed to 40bits.\n */\n #define KVM_PHYS_SHIFT\t(40)\n \n+#endif /* ARM64_S390_COMMON */\n+\n #define kvm_phys_shift(mmu)\t\tVTCR_EL2_IPA((mmu)-\u003evtcr)\n #define kvm_phys_size(mmu)\t\t(_AC(1, ULL) \u003c\u003c kvm_phys_shift(mmu))\n #define kvm_phys_mask(mmu)\t\t(kvm_phys_size(mmu) - _AC(1, ULL))\n@@ -178,9 +181,12 @@ void stage2_unmap_vm(struct kvm *kvm);\n int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long type);\n void kvm_uninit_stage2_mmu(struct kvm *kvm);\n void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu);\n+#ifdef ARM64_S390_COMMON\n int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,\n \t\t\t phys_addr_t pa, unsigned long size, bool writable);\n \n+#endif /* ARM64_S390_COMMON */\n+\n int kvm_handle_guest_sea(struct kvm_vcpu *vcpu);\n int kvm_handle_guest_abort(struct kvm_vcpu *vcpu);\n \ndiff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h\nindex 39582511ad72f7..6eb122eb5fa62b 100644\n--- a/arch/arm64/include/asm/ptrace.h\n+++ b/arch/arm64/include/asm/ptrace.h\n@@ -10,8 +10,13 @@\n \n #include \u003casm/cpufeature.h\u003e\n \n+#ifdef ARM64_S390_COMMON\n+#include \u003casm/sysreg.h\u003e\n+\n #include \u003cuapi/asm/ptrace.h\u003e\n \n+#endif /* ARM64_S390_COMMON */\n+\n /* Current Exception Level values, as contained in CurrentEL */\n #define CurrentEL_EL1\t\t(1 \u003c\u003c 2)\n #define CurrentEL_EL2\t\t(2 \u003c\u003c 2)\n@@ -28,6 +33,8 @@\n \n #define GIC_PRIO_PSR_I_SET\tGICV3_PRIO_PSR_I_SET\n \n+#ifdef ARM64_S390_COMMON\n+\n /* Additional SPSR bits not exposed in the UABI */\n #define PSR_MODE_THREAD_BIT\t(1 \u003c\u003c 0)\n #define PSR_IL_BIT\t\t(1 \u003c\u003c 20)\n@@ -68,6 +75,8 @@\n #define PSR_AA32_IT_MASK\t0x0600fc00\t/* If-Then execution state mask */\n #define PSR_AA32_GE_MASK\t0x000f0000\n \n+#endif /* ARM64_S390_COMMON */\n+\n #ifdef CONFIG_CPU_BIG_ENDIAN\n #define PSR_AA32_ENDSTATE\tPSR_AA32_E_BIT\n #else\ndiff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h\nindex 7aa08d59d49448..58912a6b6fcd56 100644\n--- a/arch/arm64/include/asm/sysreg.h\n+++ b/arch/arm64/include/asm/sysreg.h\n@@ -9,13 +9,17 @@\n #ifndef __ASM_SYSREG_H\n #define __ASM_SYSREG_H\n \n+#ifdef ARM64_S390_COMMON\n #include \u003clinux/bits.h\u003e\n+#endif /* ARM64_S390_COMMON */\n #include \u003clinux/stringify.h\u003e\n #include \u003clinux/kasan-tags.h\u003e\n #include \u003clinux/kconfig.h\u003e\n \n #include \u003casm/gpr-num.h\u003e\n \n+#ifdef ARM64_S390_COMMON\n+\n /*\n * ARMv8 ARM reserves the following encoding for system registers:\n * (Ref: ARMv8 ARM, Section: \"System instruction class encoding overview\",\n@@ -50,6 +54,8 @@\n #define sys_reg_CRm(id)\t(((id) \u003e\u003e CRm_shift) \u0026 CRm_mask)\n #define sys_reg_Op2(id)\t(((id) \u003e\u003e Op2_shift) \u0026 Op2_mask)\n \n+#endif /* ARM64_S390_COMMON */\n+\n #ifndef CONFIG_BROKEN_GAS_INST\n \n #ifdef __ASSEMBLER__\n@@ -79,6 +85,8 @@\n \n #endif\t/* CONFIG_BROKEN_GAS_INST */\n \n+#ifdef ARM64_S390_COMMON\n+\n /*\n * Instructions for modifying PSTATE fields.\n * As per Arm ARM for v8-A, Section \"C.5.1.3 op0 == 0b00, architectural hints,\n@@ -91,8 +99,6 @@\n */\n #define pstate_field(op1, op2)\t\t((op1) \u003c\u003c Op1_shift | (op2) \u003c\u003c Op2_shift)\n #define PSTATE_Imm_shift\t\tCRm_shift\n-#define ENCODE_PSTATE(x, r)\t\t(0xd500401f | PSTATE_ ## r | ((!!x) \u003c\u003c PSTATE_Imm_shift))\n-#define SET_PSTATE(x, r)\t\t__emit_inst(ENCODE_PSTATE(x, r))\n \n #define PSTATE_PAN\t\t\tpstate_field(0, 4)\n #define PSTATE_UAO\t\t\tpstate_field(0, 3)\n@@ -100,6 +106,11 @@\n #define PSTATE_DIT\t\t\tpstate_field(3, 2)\n #define PSTATE_TCO\t\t\tpstate_field(3, 4)\n \n+#endif /* ARM64_S390_COMMON */\n+\n+#define ENCODE_PSTATE(x, r)\t\t(0xd500401f | PSTATE_ ## r | ((!!x) \u003c\u003c PSTATE_Imm_shift))\n+#define SET_PSTATE(x, r)\t\t__emit_inst(ENCODE_PSTATE(x, r))\n+\n #define SET_PSTATE_PAN(x)\t\tSET_PSTATE((x), PAN)\n #define SET_PSTATE_UAO(x)\t\tSET_PSTATE((x), UAO)\n #define SET_PSTATE_SSBS(x)\t\tSET_PSTATE((x), SSBS)\n@@ -123,6 +134,8 @@\n #define GSB_SYS_BARRIER_INSN\t\t__SYS_BARRIER_INSN(1, 0, 12, 0, 0, 31)\n #define GSB_ACK_BARRIER_INSN\t\t__SYS_BARRIER_INSN(1, 0, 12, 0, 1, 31)\n \n+#ifdef ARM64_S390_COMMON\n+\n /* Data cache zero operations */\n #define SYS_DC_ISW\t\t\tsys_insn(1, 0, 7, 6, 2)\n #define SYS_DC_IGSW\t\t\tsys_insn(1, 0, 7, 6, 4)\n@@ -173,7 +186,7 @@\n * come from here. The header relies on the definition of sys_reg()\n * earlier in this file.\n */\n-#include \"asm/sysreg-defs.h\"\n+#include \u003casm/sysreg-defs.h\u003e\n \n /*\n * System registers, organised loosely by encoding but grouped together\n@@ -835,6 +848,8 @@\n #define SCTLR_ELx_A\t (BIT(1))\n #define SCTLR_ELx_M\t (BIT(0))\n \n+#endif /* ARM64_S390_COMMON */\n+\n #ifdef CONFIG_CPU_BIG_ENDIAN\n #define ENDIAN_SET_EL2\t\tSCTLR_ELx_EE\n #else\n@@ -869,6 +884,8 @@\n \t SCTLR_EL1_LSMAOE | SCTLR_EL1_nTLSMD | SCTLR_EL1_EIS | \\\n \t SCTLR_EL1_TSCXT | SCTLR_EL1_EOS)\n \n+#ifdef ARM64_S390_COMMON\n+\n /* MAIR_ELx memory attributes (used by Linux) */\n #define MAIR_ATTR_DEVICE_nGnRnE\t\tUL(0x00)\n #define MAIR_ATTR_DEVICE_nGnRE\t\tUL(0x04)\n@@ -1105,6 +1122,8 @@\n #define GICV5_GICR_CDNMIA_TYPE_MASK\tGENMASK_ULL(31, 29)\n #define GICV5_GICR_CDNMIA_ID_MASK\tGENMASK_ULL(23, 0)\n \n+#endif /* ARM64_S390_COMMON */\n+\n #define gicr_insn(insn)\t\t\tread_sysreg_s(GICV5_OP_GICR_##insn)\n #define gic_insn(v, insn)\t\twrite_sysreg_s(v, GICV5_OP_GIC_##insn)\n \n@@ -1254,6 +1273,8 @@\n \tpar;\t\t\t\t\t\t\t\t\\\n })\n \n+#ifdef ARM64_S390_COMMON\n+\n #define SYS_FIELD_VALUE(reg, field, val)\treg##_##field##_##val\n \n #define SYS_FIELD_GET(reg, field, val)\t\t\\\n@@ -1266,6 +1287,8 @@\n \t\t FIELD_PREP(reg##_##field##_MASK,\t\\\n \t\t\t SYS_FIELD_VALUE(reg, field, val))\n \n-#endif\n+#endif /* ARM64_S390_COMMON */\n+\n+#endif /* __ASSEMBLER__ */\n \n #endif\t/* __ASM_SYSREG_H */\ndiff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig\nindex 449154f9a4852d..dd138b730217e5 100644\n--- a/arch/arm64/kvm/Kconfig\n+++ b/arch/arm64/kvm/Kconfig\n@@ -22,7 +22,6 @@ menuconfig KVM\n \tselect KVM_COMMON\n \tselect KVM_GENERIC_HARDWARE_ENABLING\n \tselect HAVE_KVM_CPU_RELAX_INTERCEPT\n-\tselect KVM_MMIO\n \tselect KVM_GENERIC_DIRTYLOG_READ_PROTECT\n \tselect VIRT_XFER_TO_GUEST_WORK\n \tselect KVM_VFIO\ndiff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c\nindex 50adfff75be82e..c992308b2dcebc 100644\n--- a/arch/arm64/kvm/arm.c\n+++ b/arch/arm64/kvm/arm.c\n@@ -1580,6 +1580,7 @@ static unsigned long system_supported_vcpu_features(void)\n \treturn features;\n }\n \n+#ifdef ARM64_S390_COMMON\n static int kvm_vcpu_init_check_features(struct kvm_vcpu *vcpu,\n \t\t\t\t\tconst struct kvm_vcpu_init *init)\n {\n@@ -1628,6 +1629,8 @@ static bool kvm_vcpu_init_changed(struct kvm_vcpu *vcpu,\n \t\t\t KVM_VCPU_MAX_FEATURES);\n }\n \n+#endif /* ARM64_S390_COMMON */\n+\n static int kvm_setup_vcpu(struct kvm_vcpu *vcpu)\n {\n \tstruct kvm *kvm = vcpu-\u003ekvm;\ndiff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c\nindex b01d6622b87206..5e1e1faa98c291 100644\n--- a/arch/arm64/kvm/guest.c\n+++ b/arch/arm64/kvm/guest.c\n@@ -62,6 +62,7 @@ const struct kvm_stats_header kvm_vcpu_stats_header = {\n \t\t sizeof(kvm_vcpu_stats_desc),\n };\n \n+#ifdef ARM64_S390_COMMON\n static bool core_reg_offset_is_vreg(u64 off)\n {\n \treturn off \u003e= KVM_REG_ARM_CORE_REG(fp_regs.vregs) \u0026\u0026\n@@ -134,19 +135,19 @@ static void *core_reg_addr(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)\n \t KVM_REG_ARM_CORE_REG(regs.regs[30]):\n \t\toff -= KVM_REG_ARM_CORE_REG(regs.regs[0]);\n \t\toff /= 2;\n-\t\treturn \u0026vcpu-\u003earch.ctxt.regs.regs[off];\n+\t\treturn \u0026vcpu_gp_regs(vcpu)[off];\n \n \tcase KVM_REG_ARM_CORE_REG(regs.sp):\n-\t\treturn \u0026vcpu-\u003earch.ctxt.regs.sp;\n+\t\treturn vcpu_sp_el0(vcpu);\n \n \tcase KVM_REG_ARM_CORE_REG(regs.pc):\n-\t\treturn \u0026vcpu-\u003earch.ctxt.regs.pc;\n+\t\treturn vcpu_pc(vcpu);\n \n \tcase KVM_REG_ARM_CORE_REG(regs.pstate):\n-\t\treturn \u0026vcpu-\u003earch.ctxt.regs.pstate;\n+\t\treturn vcpu_cpsr(vcpu);\n \n \tcase KVM_REG_ARM_CORE_REG(sp_el1):\n-\t\treturn __ctxt_sys_reg(\u0026vcpu-\u003earch.ctxt, SP_EL1);\n+\t\treturn kvm_vcpu_get_sp_el1(vcpu);\n \n \tcase KVM_REG_ARM_CORE_REG(elr_el1):\n \t\treturn __ctxt_sys_reg(\u0026vcpu-\u003earch.ctxt, ELR_EL1);\n@@ -170,13 +171,13 @@ static void *core_reg_addr(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)\n \t KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]):\n \t\toff -= KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]);\n \t\toff /= 4;\n-\t\treturn \u0026vcpu-\u003earch.ctxt.fp_regs.vregs[off];\n+\t\treturn kvm_vcpu_get_vreg(vcpu, off);\n \n \tcase KVM_REG_ARM_CORE_REG(fp_regs.fpsr):\n-\t\treturn \u0026vcpu-\u003earch.ctxt.fp_regs.fpsr;\n+\t\treturn kvm_vcpu_get_fpsr(vcpu);\n \n \tcase KVM_REG_ARM_CORE_REG(fp_regs.fpcr):\n-\t\treturn \u0026vcpu-\u003earch.ctxt.fp_regs.fpcr;\n+\t\treturn kvm_vcpu_get_fpcr(vcpu);\n \n \tdefault:\n \t\treturn NULL;\n@@ -306,6 +307,8 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)\n \treturn err;\n }\n \n+#endif /* ARM64_S390_COMMON */\n+\n #define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)\n #define vq_mask(vq) ((u64)1 \u003c\u003c ((vq) - SVE_VQ_MIN) % 64)\n #define vq_present(vqs, vq) (!!((vqs)[vq_word(vq)] \u0026 vq_mask(vq)))\n@@ -543,6 +546,7 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)\n \treturn -EINVAL;\n }\n \n+#ifdef ARM64_S390_COMMON\n static int copy_core_reg_indices(const struct kvm_vcpu *vcpu,\n \t\t\t\t u64 __user *uindices)\n {\n@@ -591,6 +595,8 @@ static unsigned long num_core_regs(const struct kvm_vcpu *vcpu)\n \treturn copy_core_reg_indices(vcpu, NULL);\n }\n \n+#endif /* ARM64_S390_COMMON */\n+\n static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)\n {\n \tconst unsigned int slices = vcpu_sve_slices(vcpu);\ndiff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c\nindex 54aedf93c78b64..d511af145ee6ab 100644\n--- a/arch/arm64/kvm/handle_exit.c\n+++ b/arch/arm64/kvm/handle_exit.c\n@@ -213,6 +213,7 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)\n \treturn 0;\n }\n \n+#ifdef ARM64_S390_COMMON\n static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu)\n {\n \tu64 esr = kvm_vcpu_get_esr(vcpu);\n@@ -224,6 +225,8 @@ static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu)\n \treturn 1;\n }\n \n+#endif /* ARM64_S390_COMMON */\n+\n /*\n * Guest access to SVE registers should be routed to this handler only\n * when the system doesn't support SVE.\n@@ -404,6 +407,7 @@ static exit_handle_fn arm_exit_handlers[] = {\n \t[ESR_ELx_EC_GCS]\t= kvm_handle_gcs,\n };\n \n+#ifdef ARM64_S390_COMMON\n static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)\n {\n \tu64 esr = kvm_vcpu_get_esr(vcpu);\n@@ -439,6 +443,8 @@ static int handle_trap_exceptions(struct kvm_vcpu *vcpu)\n \treturn handled;\n }\n \n+#endif /* ARM64_S390_COMMON */\n+\n /*\n * Return \u003e 0 to return to guest, \u003c 0 on error, 0 (and set exit_reason) on\n * proper exit to userspace.\ndiff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c\nindex bef40ddb16dbc2..82611442a2d13b 100644\n--- a/arch/arm64/kvm/hyp/exception.c\n+++ b/arch/arm64/kvm/hyp/exception.c\n@@ -277,6 +277,9 @@ static const u8 return_offsets[8][2] = {\n \t[7] = { 4, 4 },\t\t/* FIQ, unused */\n };\n \n+#define OFFSETOF_PT_REG(__r) offsetof(struct user_pt_regs, __r)\n+#define COMPAT_IDX(__c) ((OFFSETOF_PT_REG(__c) - OFFSETOF_PT_REG(regs[0])) / sizeof(u64))\n+\n static void enter_exception32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)\n {\n \tunsigned long spsr = *vcpu_cpsr(vcpu);\n@@ -292,12 +295,12 @@ static void enter_exception32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)\n \tswitch(mode) {\n \tcase PSR_AA32_MODE_ABT:\n \t\t__vcpu_write_spsr_abt(vcpu, host_spsr_to_spsr32(spsr));\n-\t\tvcpu_gp_regs(vcpu)-\u003ecompat_lr_abt = return_address;\n+\t\tvcpu_gp_regs(vcpu)[COMPAT_IDX(compat_lr_abt)] = return_address;\n \t\tbreak;\n \n \tcase PSR_AA32_MODE_UND:\n \t\t__vcpu_write_spsr_und(vcpu, host_spsr_to_spsr32(spsr));\n-\t\tvcpu_gp_regs(vcpu)-\u003ecompat_lr_und = return_address;\n+\t\tvcpu_gp_regs(vcpu)[COMPAT_IDX(compat_lr_und)] = return_address;\n \t\tbreak;\n \t}\n \ndiff --git a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h\nindex 4fdfeabefeb432..a049983bd5c3ac 100644\n--- a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h\n+++ b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h\n@@ -33,11 +33,11 @@ static inline void kvm_skip_instr(struct kvm_vcpu *vcpu)\n static inline void __kvm_skip_instr(struct kvm_vcpu *vcpu)\n {\n \t*vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);\n-\tvcpu_gp_regs(vcpu)-\u003epstate = read_sysreg_el2(SYS_SPSR);\n+\t*vcpu_cpsr(vcpu) = read_sysreg_el2(SYS_SPSR);\n \n \tkvm_skip_instr(vcpu);\n \n-\twrite_sysreg_el2(vcpu_gp_regs(vcpu)-\u003epstate, SYS_SPSR);\n+\twrite_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);\n \twrite_sysreg_el2(*vcpu_pc(vcpu), SYS_ELR);\n }\n \ndiff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h\nindex 18131e395e24c3..a57aec6dd85446 100644\n--- a/arch/arm64/kvm/hyp/include/hyp/switch.h\n+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h\n@@ -449,7 +449,7 @@ static inline bool __populate_fault_info(struct kvm_vcpu *vcpu)\n static inline bool kvm_hyp_handle_mops(struct kvm_vcpu *vcpu, u64 *exit_code)\n {\n \t*vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);\n-\tarm64_mops_reset_regs(vcpu_gp_regs(vcpu), vcpu-\u003earch.fault.esr_el2);\n+\tarm64_mops_reset_regs(\u0026vcpu-\u003earch.ctxt.regs, vcpu-\u003earch.fault.esr_el2);\n \twrite_sysreg_el2(*vcpu_pc(vcpu), SYS_ELR);\n \n \t/*\n@@ -895,7 +895,7 @@ static inline void synchronize_vcpu_pstate(struct kvm_vcpu *vcpu)\n \t/*\n \t * Check for the conditions of Cortex-A510's #2077057. When these occur\n \t * SPSR_EL2 can't be trusted, but isn't needed either as it is\n-\t * unchanged from the value in vcpu_gp_regs(vcpu)-\u003epstate.\n+\t * unchanged from the value in vcpu_cpsr(vcpu).\n \t * Are we single-stepping the guest, and took a PAC exception from the\n \t * active-not-pending state?\n \t */\n@@ -905,7 +905,7 @@ static inline void synchronize_vcpu_pstate(struct kvm_vcpu *vcpu)\n \t ESR_ELx_EC(read_sysreg_el2(SYS_ESR)) == ESR_ELx_EC_PAC)\n \t\twrite_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);\n \n-\tvcpu-\u003earch.ctxt.regs.pstate = read_sysreg_el2(SYS_SPSR);\n+\t*vcpu_cpsr(vcpu) = read_sysreg_el2(SYS_SPSR);\n }\n \n /*\ndiff --git a/arch/arm64/kvm/mmio.c b/arch/arm64/kvm/mmio.c\nindex e2285ed8c91de6..876d56dd5b640a 100644\n--- a/arch/arm64/kvm/mmio.c\n+++ b/arch/arm64/kvm/mmio.c\n@@ -10,6 +10,7 @@\n \n #include \"trace.h\"\n \n+#ifdef ARM64_S390_COMMON\n void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data)\n {\n \tvoid *datap = NULL;\n@@ -135,8 +136,11 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu)\n \t\tif (!kvm_vcpu_dabt_issf(vcpu))\n \t\t\tdata = data \u0026 0xffffffff;\n \n+#endif /* ARM64_S390_COMMON */\n \t\ttrace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run-\u003emmio.phys_addr,\n \t\t\t \u0026data);\n+\t\t//TODO tracing\n+#ifdef ARM64_S390_COMMON\n \t\tdata = vcpu_data_host_to_guest(vcpu, data, len);\n \t\tvcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu), data);\n \t}\n@@ -171,8 +175,11 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)\n \t * though, so directly deliver an exception to the guest.\n \t */\n \tif (!kvm_vcpu_dabt_isvalid(vcpu)) {\n+#endif /* ARM64_S390_COMMON */\n \t\ttrace_kvm_mmio_nisv(*vcpu_pc(vcpu), esr,\n \t\t\t\t kvm_vcpu_get_hfar(vcpu), fault_ipa);\n+\t\t//TODO tracing\n+#ifdef ARM64_S390_COMMON\n \n \t\tif (vcpu_is_protected(vcpu))\n \t\t\treturn kvm_inject_sea_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));\n@@ -223,14 +230,20 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)\n \t\tdata = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt),\n \t\t\t\t\t len);\n \n+#endif /* ARM64_S390_COMMON */\n \t\ttrace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, \u0026data);\n+\t//TODO tracing\n+#ifdef ARM64_S390_COMMON\n \t\tkvm_mmio_write_buf(data_buf, len, data);\n \n \t\tret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,\n \t\t\t\t data_buf);\n \t} else {\n+#endif /* ARM64_S390_COMMON */\n \t\ttrace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len,\n \t\t\t fault_ipa, NULL);\n+\t//TODO tracing\n+#ifdef ARM64_S390_COMMON\n \n \t\tret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_ipa, len,\n \t\t\t\t data_buf);\n@@ -257,3 +270,4 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)\n \trun-\u003eexit_reason\t= KVM_EXIT_MMIO;\n \treturn 0;\n }\n+#endif /* ARM64_S390_COMMON */\ndiff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c\nindex b963fd975aacaf..81d9f0faede2e0 100644\n--- a/arch/arm64/kvm/reset.c\n+++ b/arch/arm64/kvm/reset.c\n@@ -34,6 +34,7 @@\n static u32 __ro_after_init kvm_ipa_limit;\n unsigned int __ro_after_init kvm_host_sve_max_vl;\n \n+#ifdef ARM64_S390_COMMON\n /*\n * ARMv8 Reset Values\n */\n@@ -46,6 +47,8 @@ unsigned int __ro_after_init kvm_host_sve_max_vl;\n #define VCPU_RESET_PSTATE_SVC\t(PSR_AA32_MODE_SVC | PSR_AA32_A_BIT | \\\n \t\t\t\t PSR_AA32_I_BIT | PSR_AA32_F_BIT)\n \n+#endif /* ARM64_S390_COMMON */\n+\n unsigned int __ro_after_init kvm_sve_max_vl;\n \n int __init kvm_arm_init_sve(void)\n@@ -169,6 +172,33 @@ static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)\n \t\tmemset(vcpu-\u003earch.sve_state, 0, vcpu_sve_state_size(vcpu));\n }\n \n+#ifdef ARM64_S390_COMMON\n+static void kvm_reset_vcpu_core_regs(struct kvm_vcpu *vcpu)\n+{\n+\tu32 pstate;\n+\n+\tif (vcpu_el1_is_32bit(vcpu))\n+\t\tpstate = VCPU_RESET_PSTATE_SVC;\n+\telse if (vcpu_has_nv(vcpu))\n+\t\tpstate = VCPU_RESET_PSTATE_EL2;\n+\telse\n+\t\tpstate = VCPU_RESET_PSTATE_EL1;\n+\n+\tmemset(vcpu_gp_regs(vcpu), 0, sizeof(vcpu_gp_regs(vcpu)));\n+\t*vcpu_pc(vcpu) = 0;\n+\t*vcpu_sp_el0(vcpu) = 0;\n+\tmemset(kvm_vcpu_get_vregs(vcpu), 0, sizeof(*kvm_vcpu_get_vregs(vcpu)));\n+\tmemset(kvm_vcpu_get_fpsr(vcpu), 0, sizeof(*kvm_vcpu_get_fpsr(vcpu)));\n+\tmemset(kvm_vcpu_get_fpcr(vcpu), 0, sizeof(*kvm_vcpu_get_fpcr(vcpu)));\n+\tvcpu-\u003earch.ctxt.spsr_abt = 0;\n+\tvcpu-\u003earch.ctxt.spsr_und = 0;\n+\tvcpu-\u003earch.ctxt.spsr_irq = 0;\n+\tvcpu-\u003earch.ctxt.spsr_fiq = 0;\n+\t*vcpu_cpsr(vcpu) = pstate;\n+}\n+\n+#endif /* ARM64_S390_COMMON */\n+\n /**\n * kvm_reset_vcpu - sets core registers and sys_regs to reset value\n * @vcpu: The VCPU pointer\n@@ -191,7 +221,6 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu)\n {\n \tstruct vcpu_reset_state reset_state;\n \tbool loaded;\n-\tu32 pstate;\n \n \tspin_lock(\u0026vcpu-\u003earch.mp_state_lock);\n \treset_state = vcpu-\u003earch.reset_state;\n@@ -210,21 +239,8 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu)\n \t\tkvm_vcpu_reset_sve(vcpu);\n \t}\n \n-\tif (vcpu_el1_is_32bit(vcpu))\n-\t\tpstate = VCPU_RESET_PSTATE_SVC;\n-\telse if (vcpu_has_nv(vcpu))\n-\t\tpstate = VCPU_RESET_PSTATE_EL2;\n-\telse\n-\t\tpstate = VCPU_RESET_PSTATE_EL1;\n-\n \t/* Reset core registers */\n-\tmemset(vcpu_gp_regs(vcpu), 0, sizeof(*vcpu_gp_regs(vcpu)));\n-\tmemset(\u0026vcpu-\u003earch.ctxt.fp_regs, 0, sizeof(vcpu-\u003earch.ctxt.fp_regs));\n-\tvcpu-\u003earch.ctxt.spsr_abt = 0;\n-\tvcpu-\u003earch.ctxt.spsr_und = 0;\n-\tvcpu-\u003earch.ctxt.spsr_irq = 0;\n-\tvcpu-\u003earch.ctxt.spsr_fiq = 0;\n-\tvcpu_gp_regs(vcpu)-\u003epstate = pstate;\n+\tkvm_reset_vcpu_core_regs(vcpu);\n \n \t/* Reset system registers */\n \tkvm_reset_sys_regs(vcpu);\ndiff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h\nindex 23cfbecebbd79a..47003a85b35a3d 100644\n--- a/arch/loongarch/include/asm/kvm_host.h\n+++ b/arch/loongarch/include/asm/kvm_host.h\n@@ -27,6 +27,8 @@\n \n #define __KVM_HAVE_ARCH_INTC_INITIALIZED\n \n+#define HAVE_KVM_MMIO\n+\n /* Loongarch KVM register ids */\n #define KVM_GET_IOC_CSR_IDX(id)\t\t((id \u0026 KVM_CSR_IDX_MASK) \u003e\u003e LOONGARCH_REG_SHIFT)\n #define KVM_GET_IOC_CPUCFG_IDX(id)\t((id \u0026 KVM_CPUCFG_IDX_MASK) \u003e\u003e LOONGARCH_REG_SHIFT)\ndiff --git a/arch/loongarch/kvm/Kconfig b/arch/loongarch/kvm/Kconfig\nindex 15da2d88c0c10c..f03872ba0ba8c6 100644\n--- a/arch/loongarch/kvm/Kconfig\n+++ b/arch/loongarch/kvm/Kconfig\n@@ -28,7 +28,6 @@ config KVM\n \tselect KVM_COMMON\n \tselect KVM_GENERIC_DIRTYLOG_READ_PROTECT\n \tselect KVM_GENERIC_HARDWARE_ENABLING\n-\tselect KVM_MMIO\n \tselect VIRT_XFER_TO_GUEST_WORK\n \tselect SCHED_INFO\n \tselect GUEST_PERF_EVENTS if PERF_EVENTS\ndiff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h\nindex c14b10821817b4..e3cb7c8c9461fd 100644\n--- a/arch/mips/include/asm/kvm_host.h\n+++ b/arch/mips/include/asm/kvm_host.h\n@@ -26,6 +26,8 @@\n \n #include \u003ckvm/iodev.h\u003e\n \n+#define HAVE_KVM_MMIO\n+\n /* MIPS KVM register ids */\n #define MIPS_CP0_32(_R, _S)\t\t\t\t\t\\\n \t(KVM_REG_MIPS_CP0 | KVM_REG_SIZE_U32 | (8 * (_R) + (_S)))\ndiff --git a/arch/mips/kvm/Kconfig b/arch/mips/kvm/Kconfig\nindex b1b9a1d677581e..c65596fdf54f44 100644\n--- a/arch/mips/kvm/Kconfig\n+++ b/arch/mips/kvm/Kconfig\n@@ -22,7 +22,6 @@ config KVM\n \tselect EXPORT_UASM\n \tselect KVM_COMMON\n \tselect KVM_GENERIC_DIRTYLOG_READ_PROTECT\n-\tselect KVM_MMIO\n \tselect KVM_GENERIC_HARDWARE_ENABLING\n \tselect HAVE_KVM_READONLY_MEM\n \thelp\ndiff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h\nindex 2d139c80757732..92d14438e31b16 100644\n--- a/arch/powerpc/include/asm/kvm_host.h\n+++ b/arch/powerpc/include/asm/kvm_host.h\n@@ -29,6 +29,13 @@\n \n #define __KVM_HAVE_ARCH_VCPU_DEBUGFS\n \n+#if defined(CONFIG_KVM_BOOK3S_32_HANDLER) || \\\n+\tdefined(CONFIG_KVM_BOOK3S_PR_POSSIBLE) || \\\n+\tdefined(CONFIG_KVM_E500V2) || \\\n+\tdefined(CONFIG_KVM_E500MC)\n+#define HAVE_KVM_MMIO\n+#endif\n+\n #define KVM_MAX_VCPUS\t\tNR_CPUS\n #define KVM_MAX_VCORES\t\tNR_CPUS\n \ndiff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig\nindex 9a0d1c1aca6c80..d97a4a51ec55e2 100644\n--- a/arch/powerpc/kvm/Kconfig\n+++ b/arch/powerpc/kvm/Kconfig\n@@ -29,7 +29,6 @@ config KVM_BOOK3S_HANDLER\n config KVM_BOOK3S_32_HANDLER\n \tbool\n \tselect KVM_BOOK3S_HANDLER\n-\tselect KVM_MMIO\n \n config KVM_BOOK3S_64_HANDLER\n \tbool\n@@ -37,7 +36,6 @@ config KVM_BOOK3S_64_HANDLER\n \n config KVM_BOOK3S_PR_POSSIBLE\n \tbool\n-\tselect KVM_MMIO\n \n config KVM_BOOK3S_HV_POSSIBLE\n \tbool\n@@ -200,7 +198,6 @@ config KVM_E500V2\n \tdepends on PPC_E500 \u0026\u0026 !PPC_E500MC\n \tdepends on !CONTEXT_TRACKING_USER\n \tselect KVM\n-\tselect KVM_MMIO\n \thelp\n \t Support running unmodified E500 guest kernels in virtual machines on\n \t E500v2 host processors.\n@@ -215,7 +212,6 @@ config KVM_E500MC\n \tdepends on PPC_E500MC\n \tdepends on !CONTEXT_TRACKING_USER\n \tselect KVM\n-\tselect KVM_MMIO\n \tselect KVM_BOOKE_HV\n \thelp\n \t Support running unmodified E500MC/E5500/E6500 guest kernels in\ndiff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h\nindex 60017ceec9d2af..38333a01e5bbeb 100644\n--- a/arch/riscv/include/asm/kvm_host.h\n+++ b/arch/riscv/include/asm/kvm_host.h\n@@ -26,6 +26,8 @@\n #include \u003casm/kvm_vcpu_timer.h\u003e\n #include \u003casm/kvm_vcpu_pmu.h\u003e\n \n+#define HAVE_KVM_MMIO\n+\n #define KVM_MAX_VCPUS\t\t\t1024\n \n #define KVM_HALT_POLL_NS_DEFAULT\t500000\ndiff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig\nindex ec2cee0a39e01c..3aea8d4939d2eb 100644\n--- a/arch/riscv/kvm/Kconfig\n+++ b/arch/riscv/kvm/Kconfig\n@@ -28,7 +28,6 @@ config KVM\n \tselect KVM_COMMON\n \tselect KVM_GENERIC_DIRTYLOG_READ_PROTECT\n \tselect KVM_GENERIC_HARDWARE_ENABLING\n-\tselect KVM_MMIO\n \tselect VIRT_XFER_TO_GUEST_WORK\n \tselect SCHED_INFO\n \tselect GUEST_PERF_EVENTS if PERF_EVENTS\ndiff --git a/arch/s390/Kconfig b/arch/s390/Kconfig\nindex 84404e6778d504..b2eaa2000b101f 100644\n--- a/arch/s390/Kconfig\n+++ b/arch/s390/Kconfig\n@@ -834,7 +834,7 @@ config VFIO_CCW\n config VFIO_AP\n \tdef_tristate n\n \tprompt \"VFIO support for AP devices\"\n-\tdepends on KVM\n+\tdepends on KVM_S390\n \tdepends on VFIO\n \tdepends on AP\n \tselect VFIO_MDEV\ndiff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c\nindex 6bc950b92be766..b8906ba7e5e8ad 100644\n--- a/arch/s390/boot/ipl_parm.c\n+++ b/arch/s390/boot/ipl_parm.c\n@@ -300,7 +300,7 @@ void parse_boot_command_line(void)\n \t\t\tstack_protector_debug = 1;\n #endif\n \n-#if IS_ENABLED(CONFIG_KVM)\n+#if IS_ENABLED(CONFIG_KVM_S390)\n \t\tif (!strcmp(param, \"prot_virt\")) {\n \t\t\trc = kstrtobool(val, \u0026enabled);\n \t\t\tif (!rc \u0026\u0026 enabled)\ndiff --git a/arch/s390/boot/uv.c b/arch/s390/boot/uv.c\nindex 4568e8f81dac1d..f7b68bdcedc132 100644\n--- a/arch/s390/boot/uv.c\n+++ b/arch/s390/boot/uv.c\n@@ -26,7 +26,7 @@ void uv_query_info(void)\n \tif (uv_call(0, (uint64_t)\u0026uvcb) \u0026\u0026 uvcb.header.rc != UVC_RC_MORE_DATA)\n \t\treturn;\n \n-\tif (IS_ENABLED(CONFIG_KVM)) {\n+\tif (IS_ENABLED(CONFIG_KVM_S390)) {\n \t\tmemcpy(uv_info.inst_calls_list, uvcb.inst_calls_list, sizeof(uv_info.inst_calls_list));\n \t\tuv_info.uv_base_stor_len = uvcb.uv_base_stor_len;\n \t\tuv_info.guest_base_stor_len = uvcb.conf_base_phys_stor_len;\ndiff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig\nindex 54637be87fb735..e9ad718a940854 100644\n--- a/arch/s390/configs/debug_defconfig\n+++ b/arch/s390/configs/debug_defconfig\n@@ -63,7 +63,7 @@ CONFIG_IOMMUFD=y\n CONFIG_CMM=m\n CONFIG_APPLDATA_BASE=y\n CONFIG_S390_HYPFS_FS=y\n-CONFIG_KVM=m\n+CONFIG_KVM_S390=m\n CONFIG_KVM_S390_UCONTROL=y\n CONFIG_S390_UNWIND_SELFTEST=m\n CONFIG_S390_KPROBES_SANITY_TEST=m\ndiff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig\nindex 5f5114a253cf7c..20de85c96e9eb3 100644\n--- a/arch/s390/configs/defconfig\n+++ b/arch/s390/configs/defconfig\n@@ -61,7 +61,8 @@ CONFIG_IOMMUFD=y\n CONFIG_CMM=m\n CONFIG_APPLDATA_BASE=y\n CONFIG_S390_HYPFS_FS=y\n-CONFIG_KVM=m\n+CONFIG_KVM_S390=m\n+CONFIG_KVM_ARM64=m\n CONFIG_S390_UNWIND_SELFTEST=m\n CONFIG_S390_KPROBES_SANITY_TEST=m\n CONFIG_S390_MODULES_SANITY_TEST=m\ndiff --git a/arch/s390/include/arm64/kvm_emulate.h b/arch/s390/include/arm64/kvm_emulate.h\nnew file mode 100644\nindex 00000000000000..6ad21398f86f4b\n--- /dev/null\n+++ b/arch/s390/include/arm64/kvm_emulate.h\n@@ -0,0 +1,135 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+\n+#ifndef __S390_ARM64_KVM_EMULATE_H__\n+#define __S390_ARM64_KVM_EMULATE_H__\n+\n+#include \u003casm/fault.h\u003e\n+#include \u003casm/ptrace.h\u003e\n+#include \u003clinux/kvm_host.h\u003e\n+\n+#include \u003carm64/kvm_arm.h\u003e\n+#include \u003carm64/sysreg.h\u003e\n+\n+static __always_inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)\n+{\n+\treturn (unsigned long *)\u0026vcpu-\u003earch.sae_block.pc;\n+}\n+\n+static __always_inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)\n+{\n+\treturn (unsigned long *)\u0026vcpu-\u003earch.sae_block.pstate;\n+}\n+\n+static __always_inline unsigned long *vcpu_sp_el0(const struct kvm_vcpu *vcpu)\n+{\n+\treturn (unsigned long *)\u0026vcpu-\u003earch.sae_block.sp_el0;\n+}\n+\n+static __always_inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)\n+{\n+\treturn false;\n+}\n+\n+static __always_inline u64 kvm_vcpu_get_esr(const struct kvm_vcpu *vcpu)\n+{\n+\treturn vcpu-\u003earch.sae_block.hai.esr_elz;\n+}\n+\n+static __always_inline unsigned long kvm_vcpu_get_hfar(const struct kvm_vcpu *vcpu)\n+{\n+\treturn vcpu-\u003earch.sae_block.hai.far_elz;\n+}\n+\n+static __always_inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu)\n+{\n+\treturn vcpu-\u003earch.sae_block.hai.teid.addr * PAGE_SIZE;\n+}\n+\n+static inline u16 kvm_vcpu_fault_pic(const struct kvm_vcpu *vcpu)\n+{\n+\treturn vcpu-\u003earch.sae_block.hai.pic \u0026 PGM_INT_CODE_MASK;\n+}\n+\n+static __always_inline\n+bool kvm_vcpu_trap_is_permission_fault(const struct kvm_vcpu *vcpu)\n+{\n+\treturn kvm_vcpu_fault_pic(vcpu) == PGM_PROTECTION;\n+}\n+\n+static __always_inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)\n+{\n+\treturn true;\n+}\n+\n+static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)\n+{\n+\treturn false;\n+}\n+\n+static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)\n+{\n+\tvcpu-\u003earch.hcr_elz = HCR_E2H | HCR_RW | HCR_AMO | HCR_IMO | HCR_FMO |\n+\t\t\t HCR_PTW;\n+\t/* traps */\n+\tvcpu-\u003earch.hcr_elz |= HCR_TSC | HCR_TID1 | HCR_TID2 | HCR_TID3 |\n+\t\t\t HCR_TID4 | HCR_TID5 | HCR_TIDCP;\n+}\n+\n+static inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu)\n+{\n+\tWARN(true, \"not implemented, just feat RAS\");\n+\n+\treturn 0L;\n+}\n+\n+static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)\n+{\n+\tWARN(true, \"not implemented, just feat RAS\");\n+}\n+\n+static inline bool vcpu_el2_tge_is_set(const struct kvm_vcpu *vcpu)\n+{\n+\treturn false;\n+}\n+\n+static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)\n+{\n+\treturn false;\n+}\n+\n+static inline int kvm_vcpu_abt_gltl(struct kvm_vcpu *vcpu)\n+{\n+\treturn vcpu-\u003earch.sae_block.hai.gltl;\n+}\n+\n+static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)\n+{\n+\treturn false;\n+}\n+\n+static inline bool is_nested_ctxt(struct kvm_vcpu *vcpu)\n+{\n+\treturn false;\n+}\n+\n+static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)\n+{\n+\tu32 mode = *vcpu_cpsr(vcpu) \u0026 PSR_MODE_MASK;\n+\n+\treturn mode != PSR_MODE_EL0t;\n+}\n+\n+#define SPSR_SS BIT(21)\n+\n+static inline void kvm_skip_instr(struct kvm_vcpu *vcpu)\n+{\n+\t*vcpu_pc(vcpu) += 4;\n+\t*vcpu_cpsr(vcpu) \u0026= ~PSR_BTYPE_MASK;\n+\n+\t/* advance the singlestep state machine */\n+\t*vcpu_cpsr(vcpu) \u0026= ~SPSR_SS;\n+}\n+\n+#include \u003carm64/kvm_emulate-part.h\u003e\n+\n+#endif /* __S390_ARM64_KVM_EMULATE_H__ */\ndiff --git a/arch/s390/include/arm64/kvm_nested.h b/arch/s390/include/arm64/kvm_nested.h\nnew file mode 100644\nindex 00000000000000..e950b1a10c4176\n--- /dev/null\n+++ b/arch/s390/include/arm64/kvm_nested.h\n@@ -0,0 +1,11 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+\n+#ifndef ASM_KVM_NESTED_H\n+#define ASM_KVM_NESTED_H\n+\n+static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu)\n+{\n+\treturn false;\n+}\n+\n+#endif /* ASM_KVM_NESTED_H */\ndiff --git a/arch/s390/include/asm/Kbuild b/arch/s390/include/asm/Kbuild\nindex 0c1fc47c3ba0a4..f6fd67d1c6513c 100644\n--- a/arch/s390/include/asm/Kbuild\n+++ b/arch/s390/include/asm/Kbuild\n@@ -8,3 +8,6 @@ generic-y += asm-offsets.h\n generic-y += mcs_spinlock.h\n generic-y += mmzone.h\n generic-y += ring_buffer.h\n+\n+generated-y += sysreg-gen-defs.h\n+generated-y += kvm_arm64_modname.h\ndiff --git a/arch/s390/include/asm/asm-prototypes.h b/arch/s390/include/asm/asm-prototypes.h\nindex d4da4436d02bee..faa2afb259a1a9 100644\n--- a/arch/s390/include/asm/asm-prototypes.h\n+++ b/arch/s390/include/asm/asm-prototypes.h\n@@ -6,6 +6,7 @@\n #include \u003casm/bug.h\u003e\n #include \u003casm/fpu.h\u003e\n #include \u003casm/nospec-branch.h\u003e\n+#include \u003casm/sae.h\u003e\n #include \u003casm-generic/asm-prototypes.h\u003e\n \n #endif /* _ASM_S390_PROTOTYPES_H */\ndiff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h\nindex bb63fa4d20bb87..ad3108ecfb07be 100644\n--- a/arch/s390/include/asm/elf.h\n+++ b/arch/s390/include/asm/elf.h\n@@ -123,6 +123,7 @@ enum {\n \tHWCAP_NR_NNPA\t\t= 20,\n \tHWCAP_NR_PCI_MIO\t= 21,\n \tHWCAP_NR_SIE\t\t= 22,\n+\tHWCAP_NR_SAE\t\t= 23,\n \tHWCAP_NR_MAX\n };\n \n@@ -150,6 +151,7 @@ enum {\n #define HWCAP_NNPA\t\tBIT(HWCAP_NR_NNPA)\n #define HWCAP_PCI_MIO\t\tBIT(HWCAP_NR_PCI_MIO)\n #define HWCAP_SIE\t\tBIT(HWCAP_NR_SIE)\n+#define HWCAP_SAE\t\tBIT(HWCAP_NR_SAE)\n \n /*\n * These are used to set parameters in the core dumps.\ndiff --git a/arch/s390/include/asm/kvm.h b/arch/s390/include/asm/kvm.h\nnew file mode 100644\nindex 00000000000000..aeb11dc631d5e4\n--- /dev/null\n+++ b/arch/s390/include/asm/kvm.h\n@@ -0,0 +1,6 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#ifdef KVM_S390_ARM64\n+#include \u003cuapi/arm64/kvm.h\u003e\n+#else\n+#include \u003cuapi/asm/kvm.h\u003e\n+#endif\ndiff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h\nindex eaa34c5bd3c110..0c22cc42be7e5d 100644\n--- a/arch/s390/include/asm/kvm_host.h\n+++ b/arch/s390/include/asm/kvm_host.h\n@@ -1,778 +1,26 @@\n /* SPDX-License-Identifier: GPL-2.0 */\n-/*\n- * definition for kernel virtual machines on s390\n- *\n- * Copyright IBM Corp. 2008, 2018\n- *\n- * Author(s): Carsten Otte \u003ccotte@de.ibm.com\u003e\n- */\n-\n \n #ifndef ASM_KVM_HOST_H\n #define ASM_KVM_HOST_H\n \n-#include \u003clinux/types.h\u003e\n-#include \u003clinux/hrtimer.h\u003e\n-#include \u003clinux/interrupt.h\u003e\n-#include \u003clinux/kvm_types.h\u003e\n-#include \u003clinux/kvm.h\u003e\n-#include \u003clinux/seqlock.h\u003e\n-#include \u003clinux/module.h\u003e\n-#include \u003clinux/pci.h\u003e\n-#include \u003clinux/mmu_notifier.h\u003e\n-#include \u003casm/kvm_host_types.h\u003e\n-#include \u003casm/debug.h\u003e\n-#include \u003casm/cpu.h\u003e\n-#include \u003casm/fpu.h\u003e\n-#include \u003casm/isc.h\u003e\n-#include \u003casm/guarded_storage.h\u003e\n-\n-#define KVM_HAVE_MMU_RWLOCK\n-#define KVM_MAX_VCPUS 255\n-\n-#define KVM_INTERNAL_MEM_SLOTS 1\n-\n-/*\n- * These seem to be used for allocating -\u003echip in the routing table, which we\n- * don't use. 1 is as small as we can get to reduce the needed memory. If we\n- * need to look at -\u003echip later on, we'll need to revisit this.\n- */\n-#define KVM_NR_IRQCHIPS 1\n-#define KVM_IRQCHIP_NUM_PINS 1\n-#define KVM_HALT_POLL_NS_DEFAULT 50000\n-\n-/* s390-specific vcpu-\u003erequests bit members */\n-#define KVM_REQ_ENABLE_IBS\tKVM_ARCH_REQ(0)\n-#define KVM_REQ_DISABLE_IBS\tKVM_ARCH_REQ(1)\n-#define KVM_REQ_ICPT_OPEREXC\tKVM_ARCH_REQ(2)\n-#define KVM_REQ_START_MIGRATION KVM_ARCH_REQ(3)\n-#define KVM_REQ_STOP_MIGRATION KVM_ARCH_REQ(4)\n-#define KVM_REQ_VSIE_RESTART\tKVM_ARCH_REQ(5)\n-#define KVM_REQ_REFRESH_GUEST_PREFIX\t\\\n-\tKVM_ARCH_REQ_FLAGS(6, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)\n+#ifdef KVM_S390_ARM64\n+#include \u003casm/kvm_host_arm64.h\u003e\n+#else\n+#include \u003casm/kvm_host_s390.h\u003e\n+#endif\n \n-struct kvm_vcpu_stat {\n-\tstruct kvm_vcpu_stat_generic generic;\n-\tu64 exit_userspace;\n-\tu64 exit_null;\n-\tu64 exit_external_request;\n-\tu64 exit_io_request;\n-\tu64 exit_external_interrupt;\n-\tu64 exit_stop_request;\n-\tu64 exit_validity;\n-\tu64 exit_instruction;\n-\tu64 exit_pei;\n-\tu64 halt_no_poll_steal;\n-\tu64 instruction_lctl;\n-\tu64 instruction_lctlg;\n-\tu64 instruction_stctl;\n-\tu64 instruction_stctg;\n-\tu64 exit_program_interruption;\n-\tu64 exit_instr_and_program;\n-\tu64 exit_operation_exception;\n-\tu64 deliver_ckc;\n-\tu64 deliver_cputm;\n-\tu64 deliver_external_call;\n-\tu64 deliver_emergency_signal;\n-\tu64 deliver_service_signal;\n-\tu64 deliver_virtio;\n-\tu64 deliver_stop_signal;\n-\tu64 deliver_prefix_signal;\n-\tu64 deliver_restart_signal;\n-\tu64 deliver_program;\n-\tu64 deliver_io;\n-\tu64 deliver_machine_check;\n-\tu64 exit_wait_state;\n-\tu64 inject_ckc;\n-\tu64 inject_cputm;\n-\tu64 inject_external_call;\n-\tu64 inject_emergency_signal;\n-\tu64 inject_mchk;\n-\tu64 inject_pfault_init;\n-\tu64 inject_program;\n-\tu64 inject_restart;\n-\tu64 inject_set_prefix;\n-\tu64 inject_stop_signal;\n-\tu64 instruction_epsw;\n-\tu64 instruction_gs;\n-\tu64 instruction_io_other;\n-\tu64 instruction_lpsw;\n-\tu64 instruction_lpswe;\n-\tu64 instruction_lpswey;\n-\tu64 instruction_pfmf;\n-\tu64 instruction_ptff;\n-\tu64 instruction_sck;\n-\tu64 instruction_sckpf;\n-\tu64 instruction_stidp;\n-\tu64 instruction_spx;\n-\tu64 instruction_stpx;\n-\tu64 instruction_stap;\n-\tu64 instruction_iske;\n-\tu64 instruction_ri;\n-\tu64 instruction_rrbe;\n-\tu64 instruction_sske;\n-\tu64 instruction_ipte_interlock;\n-\tu64 instruction_stsi;\n-\tu64 instruction_stfl;\n-\tu64 instruction_tb;\n-\tu64 instruction_tpi;\n-\tu64 instruction_tprot;\n-\tu64 instruction_tsch;\n-\tu64 instruction_sie;\n-\tu64 instruction_essa;\n-\tu64 instruction_sthyi;\n-\tu64 instruction_sigp_sense;\n-\tu64 instruction_sigp_sense_running;\n-\tu64 instruction_sigp_external_call;\n-\tu64 instruction_sigp_emergency;\n-\tu64 instruction_sigp_cond_emergency;\n-\tu64 instruction_sigp_start;\n-\tu64 instruction_sigp_stop;\n-\tu64 instruction_sigp_stop_store_status;\n-\tu64 instruction_sigp_store_status;\n-\tu64 instruction_sigp_store_adtl_status;\n-\tu64 instruction_sigp_arch;\n-\tu64 instruction_sigp_prefix;\n-\tu64 instruction_sigp_restart;\n-\tu64 instruction_sigp_init_cpu_reset;\n-\tu64 instruction_sigp_cpu_reset;\n-\tu64 instruction_sigp_unknown;\n-\tu64 instruction_diagnose_10;\n-\tu64 instruction_diagnose_44;\n-\tu64 instruction_diagnose_9c;\n-\tu64 diag_9c_ignored;\n-\tu64 diag_9c_forward;\n-\tu64 instruction_diagnose_258;\n-\tu64 instruction_diagnose_308;\n-\tu64 instruction_diagnose_500;\n-\tu64 instruction_diagnose_other;\n-\tu64 pfault_sync;\n-\tu64 signal_exits;\n-};\n+static inline bool kvm_arch_pmi_in_guest(struct kvm_vcpu *vcpu)\n+{\n+\treturn false;\n+}\n \n-#define PGM_OPERATION\t\t\t0x01\n-#define PGM_PRIVILEGED_OP\t\t0x02\n-#define PGM_EXECUTE\t\t\t0x03\n #define PGM_PROTECTION\t\t\t0x04\n #define PGM_ADDRESSING\t\t\t0x05\n-#define PGM_SPECIFICATION\t\t0x06\n-#define PGM_DATA\t\t\t0x07\n-#define PGM_FIXED_POINT_OVERFLOW\t0x08\n-#define PGM_FIXED_POINT_DIVIDE\t\t0x09\n-#define PGM_DECIMAL_OVERFLOW\t\t0x0a\n-#define PGM_DECIMAL_DIVIDE\t\t0x0b\n-#define PGM_HFP_EXPONENT_OVERFLOW\t0x0c\n-#define PGM_HFP_EXPONENT_UNDERFLOW\t0x0d\n-#define PGM_HFP_SIGNIFICANCE\t\t0x0e\n-#define PGM_HFP_DIVIDE\t\t\t0x0f\n #define PGM_SEGMENT_TRANSLATION\t\t0x10\n #define PGM_PAGE_TRANSLATION\t\t0x11\n-#define PGM_TRANSLATION_SPEC\t\t0x12\n-#define PGM_SPECIAL_OPERATION\t\t0x13\n-#define PGM_OPERAND\t\t\t0x15\n-#define PGM_TRACE_TABEL\t\t\t0x16\n-#define PGM_VECTOR_PROCESSING\t\t0x1b\n-#define PGM_SPACE_SWITCH\t\t0x1c\n-#define PGM_HFP_SQUARE_ROOT\t\t0x1d\n-#define PGM_PC_TRANSLATION_SPEC\t\t0x1f\n-#define PGM_AFX_TRANSLATION\t\t0x20\n-#define PGM_ASX_TRANSLATION\t\t0x21\n-#define PGM_LX_TRANSLATION\t\t0x22\n-#define PGM_EX_TRANSLATION\t\t0x23\n-#define PGM_PRIMARY_AUTHORITY\t\t0x24\n-#define PGM_SECONDARY_AUTHORITY\t\t0x25\n-#define PGM_LFX_TRANSLATION\t\t0x26\n-#define PGM_LSX_TRANSLATION\t\t0x27\n-#define PGM_ALET_SPECIFICATION\t\t0x28\n-#define PGM_ALEN_TRANSLATION\t\t0x29\n-#define PGM_ALE_SEQUENCE\t\t0x2a\n-#define PGM_ASTE_VALIDITY\t\t0x2b\n-#define PGM_ASTE_SEQUENCE\t\t0x2c\n-#define PGM_EXTENDED_AUTHORITY\t\t0x2d\n-#define PGM_LSTE_SEQUENCE\t\t0x2e\n-#define PGM_ASTE_INSTANCE\t\t0x2f\n-#define PGM_STACK_FULL\t\t\t0x30\n-#define PGM_STACK_EMPTY\t\t\t0x31\n-#define PGM_STACK_SPECIFICATION\t\t0x32\n-#define PGM_STACK_TYPE\t\t\t0x33\n-#define PGM_STACK_OPERATION\t\t0x34\n #define PGM_ASCE_TYPE\t\t\t0x38\n #define PGM_REGION_FIRST_TRANS\t\t0x39\n #define PGM_REGION_SECOND_TRANS\t\t0x3a\n #define PGM_REGION_THIRD_TRANS\t\t0x3b\n-#define PGM_SECURE_STORAGE_ACCESS\t0x3d\n-#define PGM_NON_SECURE_STORAGE_ACCESS\t0x3e\n-#define PGM_SECURE_STORAGE_VIOLATION\t0x3f\n-#define PGM_MONITOR\t\t\t0x40\n-#define PGM_PER\t\t\t\t0x80\n-#define PGM_CRYPTO_OPERATION\t\t0x119\n-\n-/* irq types in ascend order of priorities */\n-enum irq_types {\n-\tIRQ_PEND_SET_PREFIX = 0,\n-\tIRQ_PEND_RESTART,\n-\tIRQ_PEND_SIGP_STOP,\n-\tIRQ_PEND_IO_ISC_7,\n-\tIRQ_PEND_IO_ISC_6,\n-\tIRQ_PEND_IO_ISC_5,\n-\tIRQ_PEND_IO_ISC_4,\n-\tIRQ_PEND_IO_ISC_3,\n-\tIRQ_PEND_IO_ISC_2,\n-\tIRQ_PEND_IO_ISC_1,\n-\tIRQ_PEND_IO_ISC_0,\n-\tIRQ_PEND_VIRTIO,\n-\tIRQ_PEND_PFAULT_DONE,\n-\tIRQ_PEND_PFAULT_INIT,\n-\tIRQ_PEND_EXT_HOST,\n-\tIRQ_PEND_EXT_SERVICE,\n-\tIRQ_PEND_EXT_SERVICE_EV,\n-\tIRQ_PEND_EXT_TIMING,\n-\tIRQ_PEND_EXT_CPU_TIMER,\n-\tIRQ_PEND_EXT_CLOCK_COMP,\n-\tIRQ_PEND_EXT_EXTERNAL,\n-\tIRQ_PEND_EXT_EMERGENCY,\n-\tIRQ_PEND_EXT_MALFUNC,\n-\tIRQ_PEND_EXT_IRQ_KEY,\n-\tIRQ_PEND_MCHK_REP,\n-\tIRQ_PEND_PROG,\n-\tIRQ_PEND_SVC,\n-\tIRQ_PEND_MCHK_EX,\n-\tIRQ_PEND_COUNT\n-};\n-\n-/* We have 2M for virtio device descriptor pages. Smallest amount of\n- * memory per page is 24 bytes (1 queue), so (2048*1024) / 24 = 87381\n- */\n-#define KVM_S390_MAX_VIRTIO_IRQS 87381\n-\n-/*\n- * Repressible (non-floating) machine check interrupts\n- * subclass bits in MCIC\n- */\n-#define MCHK_EXTD_BIT 58\n-#define MCHK_DEGR_BIT 56\n-#define MCHK_WARN_BIT 55\n-#define MCHK_REP_MASK ((1UL \u003c\u003c MCHK_DEGR_BIT) | \\\n-\t\t (1UL \u003c\u003c MCHK_EXTD_BIT) | \\\n-\t\t (1UL \u003c\u003c MCHK_WARN_BIT))\n-\n-/* Exigent machine check interrupts subclass bits in MCIC */\n-#define MCHK_SD_BIT 63\n-#define MCHK_PD_BIT 62\n-#define MCHK_EX_MASK ((1UL \u003c\u003c MCHK_SD_BIT) | (1UL \u003c\u003c MCHK_PD_BIT))\n-\n-#define IRQ_PEND_EXT_MASK ((1UL \u003c\u003c IRQ_PEND_EXT_IRQ_KEY) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_CLOCK_COMP) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_CPU_TIMER) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_MALFUNC) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_EMERGENCY) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_EXTERNAL) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_TIMING) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_HOST) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_SERVICE) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_SERVICE_EV) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_VIRTIO) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_PFAULT_INIT) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_PFAULT_DONE))\n-\n-#define IRQ_PEND_IO_MASK ((1UL \u003c\u003c IRQ_PEND_IO_ISC_0) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_1) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_2) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_3) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_4) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_5) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_6) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_7))\n-\n-#define IRQ_PEND_MCHK_MASK ((1UL \u003c\u003c IRQ_PEND_MCHK_REP) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_MCHK_EX))\n-\n-#define IRQ_PEND_EXT_II_MASK ((1UL \u003c\u003c IRQ_PEND_EXT_CPU_TIMER) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_CLOCK_COMP) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_EMERGENCY) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_EXTERNAL) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_SERVICE) | \\\n-\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_SERVICE_EV))\n-\n-struct kvm_s390_interrupt_info {\n-\tstruct list_head list;\n-\tu64\ttype;\n-\tunion {\n-\t\tstruct kvm_s390_io_info io;\n-\t\tstruct kvm_s390_ext_info ext;\n-\t\tstruct kvm_s390_pgm_info pgm;\n-\t\tstruct kvm_s390_emerg_info emerg;\n-\t\tstruct kvm_s390_extcall_info extcall;\n-\t\tstruct kvm_s390_prefix_info prefix;\n-\t\tstruct kvm_s390_stop_info stop;\n-\t\tstruct kvm_s390_mchk_info mchk;\n-\t};\n-};\n-\n-struct kvm_s390_irq_payload {\n-\tstruct kvm_s390_io_info io;\n-\tstruct kvm_s390_ext_info ext;\n-\tstruct kvm_s390_pgm_info pgm;\n-\tstruct kvm_s390_emerg_info emerg;\n-\tstruct kvm_s390_extcall_info extcall;\n-\tstruct kvm_s390_prefix_info prefix;\n-\tstruct kvm_s390_stop_info stop;\n-\tstruct kvm_s390_mchk_info mchk;\n-};\n-\n-struct kvm_s390_local_interrupt {\n-\tspinlock_t lock;\n-\tDECLARE_BITMAP(sigp_emerg_pending, KVM_MAX_VCPUS);\n-\tstruct kvm_s390_irq_payload irq;\n-\tunsigned long pending_irqs;\n-};\n-\n-#define FIRQ_LIST_IO_ISC_0 0\n-#define FIRQ_LIST_IO_ISC_1 1\n-#define FIRQ_LIST_IO_ISC_2 2\n-#define FIRQ_LIST_IO_ISC_3 3\n-#define FIRQ_LIST_IO_ISC_4 4\n-#define FIRQ_LIST_IO_ISC_5 5\n-#define FIRQ_LIST_IO_ISC_6 6\n-#define FIRQ_LIST_IO_ISC_7 7\n-#define FIRQ_LIST_PFAULT 8\n-#define FIRQ_LIST_VIRTIO 9\n-#define FIRQ_LIST_COUNT 10\n-#define FIRQ_CNTR_IO 0\n-#define FIRQ_CNTR_SERVICE 1\n-#define FIRQ_CNTR_VIRTIO 2\n-#define FIRQ_CNTR_PFAULT 3\n-#define FIRQ_MAX_COUNT 4\n-\n-/* mask the AIS mode for a given ISC */\n-#define AIS_MODE_MASK(isc) (0x80 \u003e\u003e isc)\n-\n-#define KVM_S390_AIS_MODE_ALL 0\n-#define KVM_S390_AIS_MODE_SINGLE 1\n-\n-struct kvm_s390_float_interrupt {\n-\tunsigned long pending_irqs;\n-\tunsigned long masked_irqs;\n-\tspinlock_t lock;\n-\tstruct list_head lists[FIRQ_LIST_COUNT];\n-\tint counters[FIRQ_MAX_COUNT];\n-\tstruct kvm_s390_mchk_info mchk;\n-\tstruct kvm_s390_ext_info srv_signal;\n-\tint last_sleep_cpu;\n-\tspinlock_t ais_lock;\n-\tu8 simm;\n-\tu8 nimm;\n-};\n-\n-struct kvm_hw_wp_info_arch {\n-\tunsigned long addr;\n-\tunsigned long phys_addr;\n-\tint len;\n-\tchar *old_data;\n-};\n-\n-struct kvm_hw_bp_info_arch {\n-\tunsigned long addr;\n-\tint len;\n-};\n-\n-/*\n- * Only the upper 16 bits of kvm_guest_debug-\u003econtrol are arch specific.\n- * Further KVM_GUESTDBG flags which an be used from userspace can be found in\n- * arch/s390/include/uapi/asm/kvm.h\n- */\n-#define KVM_GUESTDBG_EXIT_PENDING 0x10000000\n-\n-#define guestdbg_enabled(vcpu) \\\n-\t\t(vcpu-\u003eguest_debug \u0026 KVM_GUESTDBG_ENABLE)\n-#define guestdbg_sstep_enabled(vcpu) \\\n-\t\t(vcpu-\u003eguest_debug \u0026 KVM_GUESTDBG_SINGLESTEP)\n-#define guestdbg_hw_bp_enabled(vcpu) \\\n-\t\t(vcpu-\u003eguest_debug \u0026 KVM_GUESTDBG_USE_HW_BP)\n-#define guestdbg_exit_pending(vcpu) (guestdbg_enabled(vcpu) \u0026\u0026 \\\n-\t\t(vcpu-\u003eguest_debug \u0026 KVM_GUESTDBG_EXIT_PENDING))\n-\n-#define KVM_GUESTDBG_VALID_MASK \\\n-\t\t(KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP |\\\n-\t\tKVM_GUESTDBG_USE_HW_BP | KVM_GUESTDBG_EXIT_PENDING)\n-\n-struct kvm_guestdbg_info_arch {\n-\tunsigned long cr0;\n-\tunsigned long cr9;\n-\tunsigned long cr10;\n-\tunsigned long cr11;\n-\tstruct kvm_hw_bp_info_arch *hw_bp_info;\n-\tstruct kvm_hw_wp_info_arch *hw_wp_info;\n-\tint nr_hw_bp;\n-\tint nr_hw_wp;\n-\tunsigned long last_bp;\n-};\n-\n-struct kvm_s390_pv_vcpu {\n-\tu64 handle;\n-\tunsigned long stor_base;\n-};\n-\n-struct kvm_vcpu_arch {\n-\tstruct kvm_s390_sie_block *sie_block;\n-\t/* if vsie is active, currently executed shadow sie control block */\n-\tstruct kvm_s390_sie_block *vsie_block;\n-\tunsigned int host_acrs[NUM_ACRS];\n-\tstruct gs_cb *host_gscb;\n-\tstruct kvm_s390_local_interrupt local_int;\n-\tstruct hrtimer ckc_timer;\n-\tstruct kvm_s390_pgm_info pgm;\n-\tstruct gmap *gmap;\n-\tstruct kvm_guestdbg_info_arch guestdbg;\n-\tunsigned long pfault_token;\n-\tunsigned long pfault_select;\n-\tunsigned long pfault_compare;\n-\tbool cputm_enabled;\n-\t/*\n-\t * The seqcount protects updates to cputm_start and sie_block.cputm,\n-\t * this way we can have non-blocking reads with consistent values.\n-\t * Only the owning VCPU thread (vcpu-\u003ecpu) is allowed to change these\n-\t * values and to start/stop/enable/disable cpu timer accounting.\n-\t */\n-\tseqcount_t cputm_seqcount;\n-\t__u64 cputm_start;\n-\tbool gs_enabled;\n-\tbool skey_enabled;\n-\t/* Indicator if the access registers have been loaded from guest */\n-\tbool acrs_loaded;\n-\tstruct kvm_s390_pv_vcpu pv;\n-\tunion diag318_info diag318_info;\n-\tstruct kvm_s390_mmu_cache *mc;\n-};\n-\n-struct kvm_vm_stat {\n-\tstruct kvm_vm_stat_generic generic;\n-\tu64 inject_io;\n-\tu64 io_390_adapter_map;\n-\tu64 io_390_adapter_unmap;\n-\tu64 io_390_inatomic;\n-\tu64 io_flic_inject_airq;\n-\tu64 io_set_adapter_int;\n-\tu64 io_390_inatomic_no_inject;\n-\tu64 inject_float_mchk;\n-\tu64 inject_pfault_done;\n-\tu64 inject_service_signal;\n-\tu64 inject_virtio;\n-\tu64 aen_forward;\n-\tu64 gmap_shadow_create;\n-\tu64 gmap_shadow_reuse;\n-\tu64 gmap_shadow_r1_entry;\n-\tu64 gmap_shadow_r2_entry;\n-\tu64 gmap_shadow_r3_entry;\n-\tu64 gmap_shadow_sg_entry;\n-\tu64 gmap_shadow_pg_entry;\n-};\n-\n-struct kvm_arch_memory_slot {\n-};\n-\n-struct s390_map_info {\n-\tstruct list_head list;\n-\t__u64 guest_addr;\n-\t__u64 addr;\n-\tstruct page *page;\n-};\n-\n-struct s390_io_adapter {\n-\tunsigned int id;\n-\tint isc;\n-\tbool maskable;\n-\tbool masked;\n-\tbool swap;\n-\tbool suppressible;\n-\tspinlock_t maps_lock;\n-\tstruct list_head maps;\n-\tunsigned int nr_maps;\n-};\n-\n-#define MAX_S390_IO_ADAPTERS ((MAX_ISC + 1) * 8)\n-#define MAX_S390_ADAPTER_MAPS 256\n-\n-/* maximum size of facilities and facility mask is 2k bytes */\n-#define S390_ARCH_FAC_LIST_SIZE_BYTE (1\u003c\u003c11)\n-#define S390_ARCH_FAC_LIST_SIZE_U64 \\\n-\t(S390_ARCH_FAC_LIST_SIZE_BYTE / sizeof(u64))\n-#define S390_ARCH_FAC_MASK_SIZE_BYTE S390_ARCH_FAC_LIST_SIZE_BYTE\n-#define S390_ARCH_FAC_MASK_SIZE_U64 \\\n-\t(S390_ARCH_FAC_MASK_SIZE_BYTE / sizeof(u64))\n-\n-struct kvm_s390_cpu_model {\n-\t/* facility mask supported by kvm \u0026 hosting machine */\n-\t__u64 fac_mask[S390_ARCH_FAC_MASK_SIZE_U64];\n-\tstruct kvm_s390_vm_cpu_subfunc subfuncs;\n-\t/* facility list requested by guest (in dma page) */\n-\t__u64 *fac_list;\n-\tu64 cpuid;\n-\tunsigned short ibc;\n-\t/* subset of available UV-features for pv-guests enabled by user space */\n-\tstruct kvm_s390_vm_cpu_uv_feat uv_feat_guest;\n-};\n-\n-#define S390_ARCH_FAC_FORMAT_2 2\n-struct kvm_s390_flcb2 {\n-\tunion {\n-\t\tstruct {\n-\t\t\tu8 reserved0[7];\n-\t\t\tu8 length;\n-\t\t};\n-\t\tu64 header_val;\n-\t};\n-\tu64 facilities[S390_ARCH_FAC_LIST_SIZE_U64];\n-};\n-\n-typedef int (*crypto_hook)(struct kvm_vcpu *vcpu);\n \n-struct kvm_s390_crypto {\n-\tstruct kvm_s390_crypto_cb *crycb;\n-\tstruct rw_semaphore pqap_hook_rwsem;\n-\tcrypto_hook *pqap_hook;\n-\t__u32 crycbd;\n-\t__u8 aes_kw;\n-\t__u8 dea_kw;\n-\t__u8 apie;\n-};\n-\n-#define APCB0_MASK_SIZE 1\n-struct kvm_s390_apcb0 {\n-\t__u64 apm[APCB0_MASK_SIZE];\t\t/* 0x0000 */\n-\t__u64 aqm[APCB0_MASK_SIZE];\t\t/* 0x0008 */\n-\t__u64 adm[APCB0_MASK_SIZE];\t\t/* 0x0010 */\n-\t__u64 reserved18;\t\t\t/* 0x0018 */\n-};\n-\n-#define APCB1_MASK_SIZE 4\n-struct kvm_s390_apcb1 {\n-\t__u64 apm[APCB1_MASK_SIZE];\t\t/* 0x0000 */\n-\t__u64 aqm[APCB1_MASK_SIZE];\t\t/* 0x0020 */\n-\t__u64 adm[APCB1_MASK_SIZE];\t\t/* 0x0040 */\n-\t__u64 reserved60[4];\t\t\t/* 0x0060 */\n-};\n-\n-struct kvm_s390_crypto_cb {\n-\tstruct kvm_s390_apcb0 apcb0;\t\t/* 0x0000 */\n-\t__u8 reserved20[0x0048 - 0x0020];\t/* 0x0020 */\n-\t__u8 dea_wrapping_key_mask[24];\t/* 0x0048 */\n-\t__u8 aes_wrapping_key_mask[32];\t/* 0x0060 */\n-\tstruct kvm_s390_apcb1 apcb1;\t\t/* 0x0080 */\n-};\n-\n-struct kvm_s390_gisa {\n-\tunion {\n-\t\tstruct { /* common to all formats */\n-\t\t\tu32 next_alert;\n-\t\t\tu8 ipm;\n-\t\t\tu8 reserved01[2];\n-\t\t\tu8 iam;\n-\t\t};\n-\t\tstruct { /* format 0 */\n-\t\t\tu32 next_alert;\n-\t\t\tu8 ipm;\n-\t\t\tu8 reserved01;\n-\t\t\tu8 : 6;\n-\t\t\tu8 g : 1;\n-\t\t\tu8 c : 1;\n-\t\t\tu8 iam;\n-\t\t\tu8 reserved02[4];\n-\t\t\tu32 airq_count;\n-\t\t} g0;\n-\t\tstruct { /* format 1 */\n-\t\t\tu32 next_alert;\n-\t\t\tu8 ipm;\n-\t\t\tu8 simm;\n-\t\t\tu8 nimm;\n-\t\t\tu8 iam;\n-\t\t\tu8 aism[8];\n-\t\t\tu8 : 6;\n-\t\t\tu8 g : 1;\n-\t\t\tu8 c : 1;\n-\t\t\tu8 reserved03[11];\n-\t\t\tu32 airq_count;\n-\t\t} g1;\n-\t\tstruct {\n-\t\t\tu64 word[4];\n-\t\t} u64;\n-\t};\n-};\n-\n-struct kvm_s390_gib {\n-\tu32 alert_list_origin;\n-\tu32 reserved01;\n-\tu8:5;\n-\tu8 nisc:3;\n-\tu8 reserved03[3];\n-\tu32 reserved04[5];\n-};\n-\n-/*\n- * sie_page2 has to be allocated as DMA because fac_list, crycb and\n- * gisa need 31bit addresses in the sie control block.\n- */\n-struct sie_page2 {\n-\t__u64 fac_list[S390_ARCH_FAC_LIST_SIZE_U64];\t/* 0x0000 */\n-\tstruct kvm_s390_crypto_cb crycb;\t\t/* 0x0800 */\n-\tstruct kvm_s390_gisa gisa;\t\t\t/* 0x0900 */\n-\tstruct kvm *kvm;\t\t\t\t/* 0x0920 */\n-\tu8 reserved928[0x1000 - 0x928];\t\t\t/* 0x0928 */\n-};\n-\n-struct vsie_page;\n-\n-struct kvm_s390_vsie {\n-\tstruct mutex mutex;\n-\tstruct radix_tree_root addr_to_page;\n-\tint page_count;\n-\tint next;\n-\tstruct vsie_page *pages[KVM_MAX_VCPUS];\n-};\n-\n-struct kvm_s390_gisa_iam {\n-\tu8 mask;\n-\tspinlock_t ref_lock;\n-\tu32 ref_count[MAX_ISC + 1];\n-};\n-\n-struct kvm_s390_gisa_interrupt {\n-\tstruct kvm_s390_gisa *origin;\n-\tstruct kvm_s390_gisa_iam alert;\n-\tstruct hrtimer timer;\n-\tu64 expires;\n-\tDECLARE_BITMAP(kicked_mask, KVM_MAX_VCPUS);\n-};\n-\n-struct kvm_s390_pv {\n-\tu64 handle;\n-\tu64 guest_len;\n-\tunsigned long stor_base;\n-\tvoid *stor_var;\n-\tbool dumping;\n-\tvoid *set_aside;\n-\tstruct list_head need_cleanup;\n-\tstruct mmu_notifier mmu_notifier;\n-\t/* Protects against concurrent import-like operations */\n-\tstruct mutex import_lock;\n-};\n-\n-struct kvm_s390_mmu_cache;\n-\n-struct kvm_arch {\n-\tstruct esca_block *sca;\n-\tdebug_info_t *dbf;\n-\tstruct kvm_s390_float_interrupt float_int;\n-\tstruct kvm_device *flic;\n-\tstruct gmap *gmap;\n-\tunsigned long mem_limit;\n-\tint css_support;\n-\tint use_irqchip;\n-\tint use_cmma;\n-\tint use_pfmfi;\n-\tint use_skf;\n-\tint use_zpci_interp;\n-\tint user_cpu_state_ctrl;\n-\tint user_sigp;\n-\tint user_stsi;\n-\tint user_instr0;\n-\tint user_operexec;\n-\tint allow_vsie_esamode;\n-\tstruct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];\n-\twait_queue_head_t ipte_wq;\n-\tint ipte_lock_count;\n-\tstruct mutex ipte_mutex;\n-\tspinlock_t start_stop_lock;\n-\tstruct sie_page2 *sie_page2;\n-\tstruct kvm_s390_cpu_model model;\n-\tstruct kvm_s390_crypto crypto;\n-\tstruct kvm_s390_vsie vsie;\n-\tu8 epdx;\n-\tu64 epoch;\n-\tint migration_mode;\n-\tatomic64_t cmma_dirty_pages;\n-\t/* subset of available cpu features enabled by user space */\n-\tDECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);\n-\t/* indexed by vcpu_idx */\n-\tDECLARE_BITMAP(idle_mask, KVM_MAX_VCPUS);\n-\tstruct kvm_s390_gisa_interrupt gisa_int;\n-\tstruct kvm_s390_pv pv;\n-\tstruct list_head kzdev_list;\n-\tspinlock_t kzdev_list_lock;\n-\tstruct kvm_s390_mmu_cache *mc;\n-};\n-\n-#define KVM_HVA_ERR_BAD\t\t(-1UL)\n-#define KVM_HVA_ERR_RO_BAD\t(-2UL)\n-\n-static inline bool kvm_is_error_hva(unsigned long addr)\n-{\n-\treturn IS_ERR_VALUE(addr);\n-}\n-\n-#define ASYNC_PF_PER_VCPU\t64\n-struct kvm_arch_async_pf {\n-\tunsigned long pfault_token;\n-};\n-\n-bool kvm_arch_can_dequeue_async_page_present(struct kvm_vcpu *vcpu);\n-\n-void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,\n-\t\t\t struct kvm_async_pf *work);\n-\n-bool kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,\n-\t\t\t\t struct kvm_async_pf *work);\n-\n-void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,\n-\t\t\t\t struct kvm_async_pf *work);\n-\n-static inline void kvm_arch_async_page_present_queued(struct kvm_vcpu *vcpu) {}\n-\n-void kvm_arch_crypto_clear_masks(struct kvm *kvm);\n-void kvm_arch_crypto_set_masks(struct kvm *kvm, unsigned long *apm,\n-\t\t\t unsigned long *aqm, unsigned long *adm);\n-\n-#define SIE64_RETURN_NORMAL\t0\n-#define SIE64_RETURN_MCCK\t1\n-\n-int __sie64a(phys_addr_t sie_block_phys, struct kvm_s390_sie_block *sie_block, u64 *rsa,\n-\t unsigned long gasce);\n-\n-static inline int sie64a(struct kvm_s390_sie_block *sie_block, u64 *rsa, unsigned long gasce)\n-{\n-\treturn __sie64a(virt_to_phys(sie_block), sie_block, rsa, gasce);\n-}\n-\n-extern char sie_exit;\n-\n-bool kvm_s390_pv_is_protected(struct kvm *kvm);\n-bool kvm_s390_pv_cpu_is_protected(struct kvm_vcpu *vcpu);\n-\n-extern int kvm_s390_enter_exit_sie(struct kvm_s390_sie_block *scb,\n-\t\t\t\t u64 *gprs, unsigned long gasce);\n-\n-extern int kvm_s390_gisc_register(struct kvm *kvm, u32 gisc);\n-extern int kvm_s390_gisc_unregister(struct kvm *kvm, u32 gisc);\n-\n-bool kvm_s390_is_gpa_in_memslot(struct kvm *kvm, gpa_t gpa);\n-\n-static inline void kvm_arch_free_memslot(struct kvm *kvm,\n-\t\t\t\t\t struct kvm_memory_slot *slot) {}\n-static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}\n-static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {}\n-static inline void kvm_arch_flush_shadow_memslot(struct kvm *kvm,\n-\t\tstruct kvm_memory_slot *slot) {}\n-static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {}\n-static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {}\n-\n-#define __KVM_HAVE_ARCH_VM_FREE\n-void kvm_arch_free_vm(struct kvm *kvm);\n-\n-struct zpci_kvm_hook {\n-\tint (*kvm_register)(void *opaque, struct kvm *kvm);\n-\tvoid (*kvm_unregister)(void *opaque);\n-};\n-\n-extern struct zpci_kvm_hook zpci_kvm_hook;\n-\n-#endif\n+#endif /* ASM_KVM_HOST_H */\ndiff --git a/arch/s390/include/asm/kvm_host_arm64.h b/arch/s390/include/asm/kvm_host_arm64.h\nnew file mode 100644\nindex 00000000000000..6d08856fe39538\n--- /dev/null\n+++ b/arch/s390/include/asm/kvm_host_arm64.h\n@@ -0,0 +1,210 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#ifndef ASM_KVM_HOST_ARM64_H\n+#define ASM_KVM_HOST_ARM64_H\n+\n+#include \u003clinux/bug.h\u003e\n+\n+#include \u003casm/kvm_host_types.h\u003e\n+#include \u003casm/debug.h\u003e\n+\n+#define vcpu_gp_regs(v)\t\t((v)-\u003earch.sae_block.gpr)\n+\n+#define HAVE_KVM_MMIO\n+\n+#include \u003carm64/kvm_host.h\u003e\n+#include \u003casm/sae.h\u003e\n+\n+#define KVM_HAVE_MMU_RWLOCK\n+#define KVM_MAX_VCPUS 1\n+\n+#define KVM_HALT_POLL_NS_DEFAULT 50000\n+\n+/* Minimal (=no) vgic definitions */\n+#define KVM_IRQCHIP_NUM_PINS 1\n+#define irqchip_in_kernel(_v) false;\n+\n+#define __ctxt_sys_reg(ctx, reg) NULL\n+struct kvm_cpu_context {\n+\t/*\n+\t * These are just for 32 bit, which we don't have, making them RES0.\n+\t * They are exposed to user space.\n+\t */\n+\tu64\tspsr_abt;\n+\tu64\tspsr_und;\n+\tu64\tspsr_irq;\n+\tu64\tspsr_fiq;\n+\n+\t__vector128 __aligned(16) vregs[32];\n+};\n+\n+struct kvm_vcpu_arch {\n+\tstruct kvm_sae_block sae_block;\n+\tstruct kvm_sae_save_area save_area;\n+\tstruct kvm_cpu_context ctxt;\n+\n+\tu32 host_acrs[NUM_ACRS];\n+\n+\t/* Hypervisor Configuration Register */\n+\tu64 hcr_elz;\n+\n+\t/* Configuration flags, set once and for all before the vcpu can run */\n+\tu8 cflags;\n+\n+\t/* Input flags to the hypervisor code, potentially cleared after use */\n+\tu8 iflags;\n+\n+\t/* State flags for kernel bookkeeping, unused by the hypervisor code */\n+\tu8 sflags;\n+\n+\t/*\n+\t * Don't run the guest (internal implementation need).\n+\t *\n+\t * Contrary to the flags above, this is set/cleared outside of\n+\t * a vcpu context, and thus cannot be mixed with the flags\n+\t * themselves (or the flag accesses need to be made atomic).\n+\t */\n+\tbool pause;\n+\n+\t/* vcpu power state */\n+\tstruct kvm_mp_state mp_state;\n+\t/* lock for mp_state \u0026 reset_state.reset */\n+\tspinlock_t mp_state_lock;\n+\n+\t/* vcpu reset state */\n+\tstruct vcpu_reset_state reset_state;\n+\n+\t/* GMAP */\n+\tstruct gmap *gmap;\n+\tstruct kvm_s390_mmu_cache *mc;\n+\n+\tvoid *debugfs_state_data;\n+};\n+\n+struct kvm_vcpu_stat {\n+\tstruct kvm_vcpu_stat_generic generic;\n+\t/* ARM64 stats */\n+\tu64 hvc_exit_stat;\n+\tu64 wfe_exit_stat;\n+\tu64 wfi_exit_stat;\n+\tu64 mmio_exit_user;\n+\tu64 mmio_exit_kernel;\n+\tu64 signal_exits;\n+\tu64 exits;\n+\t/* GMAP stats */\n+\tu64 pfault_sync;\n+};\n+\n+#define kvm_vcpu_get_sp_el1(__vcpu) (\u0026((__vcpu)-\u003earch.sae_block.sp_el1))\n+#define kvm_vcpu_get_vreg(__vcpu, _off) (\u0026(__vcpu)-\u003earch.ctxt.vregs[_off])\n+#define kvm_vcpu_get_vregs(__vcpu) (\u0026(__vcpu)-\u003earch.ctxt.vregs)\n+#define kvm_vcpu_get_fpsr(__vcpu) (\u0026(__vcpu)-\u003earch.sae_block.fpsr)\n+#define kvm_vcpu_get_fpcr(__vcpu) (\u0026(__vcpu)-\u003earch.sae_block.fpcr)\n+\n+#define __vcpu_flags_preempt_disable()\tpreempt_disable()\n+#define __vcpu_flags_preempt_enable()\tpreempt_enable()\n+\n+#define _vcpu_get_flag(v, flagset, ...)\t\\\n+\t__vcpu_get_flag(\u0026(v)-\u003earch.flagset, __VA_ARGS__)\n+#define _vcpu_set_flag(v, flagset, ...)\t\\\n+\t__vcpu_set_flag(\u0026(v)-\u003earch.flagset, __VA_ARGS__)\n+#define _vcpu_clear_flag(v, flagset, ...)\t\\\n+\t__vcpu_clear_flag(\u0026(v)-\u003earch.flagset, __VA_ARGS__)\n+#define _vcpu_test_and_clear_flag(v, flagset, ...)\t\\\n+\t__vcpu_test_and_clear_flag(\u0026(v)-\u003earch.flagset, __VA_ARGS__)\n+\n+#define kvm_has_mte(_kvm) false\n+#define vcpu_has_sve(_vcpu) false\n+#define vcpu_has_ptrauth(_vcpu) false\n+\n+struct kvm_arch_memory_slot {\n+};\n+\n+struct kvm_arch {\n+\tstruct gmap *gmap;\n+\tu64 guest_phys_size;\n+\n+\t/* VM-wide vCPU feature set */\n+\tunsigned long flags;\n+\n+\t/* Protects VM-scoped configuration data */\n+\tstruct mutex config_lock;\n+\n+\tdebug_info_t *dbf;\n+\n+\tDECLARE_BITMAP(vcpu_features, KVM_VCPU_MAX_FEATURES);\n+\n+\tunsigned long mem_limit;\n+};\n+\n+static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature)\n+{\n+\treturn test_bit(feature, ka-\u003evcpu_features);\n+}\n+\n+#define vcpu_has_feature(v, f)\t__vcpu_has_feature(\u0026(v)-\u003ekvm-\u003earch, (f))\n+\n+struct kvm_vm_stat {\n+\tstruct kvm_vm_stat_generic generic;\n+};\n+\n+#define kvm_vm_is_protected(_kvm)\tfalse\n+\n+#define vcpu_is_loaded(_vcpu) ((_vcpu)-\u003ecpu != -1)\n+\n+#define KVM_HVA_ERR_BAD\t\t-1UL\n+#define KVM_HVA_ERR_RO_BAD\t-2UL\n+\n+#define kvm_phys_size(__kvm) ((__kvm)-\u003earch.guest_phys_size)\n+static inline bool kvm_is_error_hva(unsigned long addr)\n+{\n+\treturn IS_ERR_VALUE(addr);\n+}\n+\n+u32 get_kvm_ipa_limit(void);\n+\n+static inline void kvm_arch_sync_events(struct kvm *kvm) {}\n+static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}\n+\n+int kvm_handle_guest_abort(struct kvm_vcpu *vcpu);\n+\n+/* arm64 guests do not use async-pf. Defined because Kbuild requires it as s390 kvm turns it on. */\n+#define ASYNC_PF_PER_VCPU 0\n+struct kvm_arch_async_pf {\n+\tunsigned long pfault_token;\n+};\n+\n+#define __unsupp_async_call(fn) WARN_ONCE(true, \"async not supported on kvm-arm64 %s\", fn)\n+\n+static inline bool kvm_arch_can_dequeue_async_page_present(struct kvm_vcpu *vcpu)\n+{\n+\t__unsupp_async_call(__func__);\n+\treturn false;\n+};\n+\n+static inline void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,\n+\t\t\t\t\t struct kvm_async_pf *work)\n+{\n+\t__unsupp_async_call(__func__);\n+};\n+\n+static inline bool kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,\n+\t\t\t\t\t\t struct kvm_async_pf *work)\n+{\n+\t__unsupp_async_call(__func__);\n+\treturn false;\n+};\n+\n+static inline void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,\n+\t\t\t\t\t struct kvm_async_pf *work)\n+{\n+\t__unsupp_async_call(__func__);\n+};\n+\n+static inline void kvm_arch_async_page_present_queued(struct kvm_vcpu *vcpu)\n+{\n+\t__unsupp_async_call(__func__);\n+};\n+\n+#define kvm_supports_32bit_el0() false\n+\n+#endif /* ASM_KVM_HOST_ARM64_H */\ndiff --git a/arch/s390/include/asm/kvm_host_arm64_types.h b/arch/s390/include/asm/kvm_host_arm64_types.h\nnew file mode 100644\nindex 00000000000000..3882d5462a05a8\n--- /dev/null\n+++ b/arch/s390/include/asm/kvm_host_arm64_types.h\n@@ -0,0 +1,129 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#ifndef ASM_KVM_HOST_ARM64_TYPES_H\n+#define ASM_KVM_HOST_ARM64_TYPES_H\n+\n+#include \u003clinux/types.h\u003e\n+#include \u003clinux/kvm_types.h\u003e\n+#include \u003clinux/compiler_attributes.h\u003e\n+#include \u003casm/page.h\u003e\n+#include \u003casm/fault.h\u003e\n+\n+struct kvm_sae_block {\n+\tu64\t_0000[16];\t\t/* 0x0000 */\n+#define SAE_ICPTR_SPURIOUS\t\t\t0x00\n+#define SAE_ICPTR_VALIDITY\t\t\t0x01\n+#define SAE_ICPTR_HOST_ACCESS_EXCEPTION\t\t0x02\n+#define SAE_ICPTR_SYNCHRONOUS_EXCEPTION\t\t0x03\n+#define SAE_ICPTR_TIMER\t\t\t\t0x04\n+#define SAE_ICPTR_PE_INTERCOMM\t\t\t0x05\n+#define SAE_ICPTR_GUEST_ADDRESS_SIZE\t\t0x06\n+#define SAE_ICPTR_STOP\t\t\t\t0x07\n+#define SAE_ICPTR_SYSTEM_REGISTER\t\t0x08\n+#define SAE_ICPTR_PMU\t\t\t\t0x09\n+#define SAE_ICPTR_MAINTENANCE\t\t\t0x0a\n+\tu8\ticptr;\t\t\t/* 0x0080 */\n+\tu8\t_0081[7];\t\t/* 0x0081 */\n+\tu64\tscad;\t\t\t/* 0x0088 */\n+\tu64\t_0090[16];\t\t/* 0x00b0 */\n+\tu32\tcntp_ctl;\t\t/* 0x0110 */\n+\tu32\tcntv_ctl;\t\t/* 0x0114 */\n+\tu8\tirq_ctl;\t\t/* 0x0118 */\n+\tu8\t_0119[7];\t\t/* 0x0119 */\n+\tstruct {\n+\t\tu64\tich_hcr_el2;\t/* 0x0120 */\n+\t\tu64\tich_vmcr_el2;\t/* 0x0128 */\n+\t\tu64\tich_ap0r0_el2;\t/* 0x0130 */\n+\t\tu64\tich_ap1r0_el2;\t/* 0x0138 */\n+\t\tu64\t_0140[2];\t/* 0x0140 */\n+\t\tu64\tich_lrn_el2[4];\t/* 0x0150 */\n+\t\tu64\t_0170[4];\t/* 0x0170 */\n+\t} ic_regs;\n+\tu64\t_0190[12];\t\t/* 0x0190 */\n+\tu64\tcontextidr_el1;\t\t/* 0x01f0 */\n+\tu32\twip;\t\t\t/* 0x01f8 */\n+\tu32\t_01fc;\t\t\t/* 0x01fc */\n+#define SAE_SD_FORMAT_0 0x00\n+\tu8\tsdf;\t\t\t/* 0x0200 */\n+\tu8\t_0201[7];\t\t/* 0x0201 */\n+\tu64\tmso;\t\t\t/* 0x0208 */\n+\tu64\tmsl;\t\t\t/* 0x0210 */\n+\tu64\thbasce;\t\t\t/* 0x0218 */\n+\tu64\t_0220;\t\t\t/* 0x0220 */\n+\tu64\tgpto;\t\t\t/* 0x0228 */\n+\tu64\tic;\t\t\t/* 0x0230 */\n+\tu64\tec;\t\t\t/* 0x0238 */\n+\tu64\tsave_area;\t\t/* 0x0240 */\n+\tu64\t_0248[7];\t\t/* 0x0248 */\n+\tu8\t_0280[6];\t\t/* 0x0280 */\n+\tu16\tlrcpua;\t\t\t/* 0x0286 */\n+\tu64\tpstate;\t\t\t/* 0x0288 */\n+\tu64\tpc;\t\t\t/* 0x0290 */\n+\tu64\tsp_el0;\t\t\t/* 0x0298 */\n+\tu64\tsp_el1;\t\t\t/* 0x02a0 */\n+\tu64\t_02a8;\t\t\t/* 0x02a8 */\n+\tu64\tfpcr;\t\t\t/* 0x02b0 */\n+\tu64\tfpsr;\t\t\t/* 0x02b8 */\n+\tu16\tsve_pregs[16];\t\t/* 0x02c0 */\n+\tu16\tsve_ffr;\t\t/* 0x02e0 */\n+\tu8\t_02e2[6];\t\t/* 0x02e2 */\n+\tu64\t_02e8[3];\t\t/* 0x02e8 */\n+\n+\tu64\tgpr[31];\t\t/* 0x0300 */\n+\tu64\t_03f8;\t\t\t/* 0x03f8 */\n+\n+\tunion {\n+\t\tu64\ticptd[8];\t\t/* 0x0400 */\n+\t\t/* validity-interception reason; icptr 0x01 */\n+#define SAE_VIR_UNKNOWN\t\t0x00\n+#define SAE_VIR_UNSUPP_FORMAT\t0x01\n+#define SAE_VIR_MSO_BOUNDS\t0x02\n+#define SAE_VIR_MSLA\t\t0x03\n+#define SAE_VIR_MGPAS\t\t0x04\n+#define SAE_VIR_INVAL_SYSREG\t0x05\n+#define SAE_VIR_HOST_CONTROL\t0x06\n+#define SAE_VIR_SCA\t\t0x07\n+#define SAE_VIR_MSO_ALIGN\t0x08\n+#define SAE_VIR_HLC\t\t0x09\n+#define SAE_VIR_IRPTC\t\t0x0a\n+\t\tu16 vir;\t\t\t/* 0x0400 */\n+\t\t/* host access interception details; icptr 0x02 */\n+\t\tstruct {\n+\t\t\tu64\t\tesr_elz;\t/* 0x0400 */\n+\t\t\tu8\t\t_0408[6];\t/* 0x0408 */\n+\t\t\tu16\t\tpic;\t\t/* 0x040e */\n+\t\t\tunion teid\tteid;\t\t/* 0x0410 */\n+\t\t\tgva_t\t\tfar_elz;\t/* 0x0418 */\n+\t\t\tgva_t\t\tvaddr;\t\t/* 0x0420 */\n+\t\t\tu64\t\tsuppl;\t\t/* 0x0428 */\n+\t\t\tu8\t\tgltl;\t\t/* 0x0430 */\n+\t\t\tu8\t\t_0431[7];\t/* 0x0431 */\n+\t\t\tu64\t\t_0438;\t\t/* 0x0438 */\n+\t\t} hai;\n+\t\t/* exception-interception details; icptr 0x03 */\n+\t\tstruct {\n+\t\t\tu64\tesr_elz;\t\t/* 0x0400 */\n+\t\t\tu64\t_0408[2];\t\t/* 0x0408 */\n+\t\t\tgva_t\tfar_elz;\t\t/* 0x0418 */\n+\t\t} trap;\n+\t\t/* timer-interception reason; icptr 0x04 */\n+#define SAE_IR_TIMER_ID_VIRT\t\tBIT(6)\n+#define SAE_IR_TIMER_ID_PHYS\t\tBIT(7)\n+\t\tu8\ttir;\t\t\t/* 0x0400 */\n+\t};\n+\tu64\t_0440[376];\t\t\t/* 0x0440 */\n+} __packed __aligned(PAGE_SIZE);\n+static_assert(sizeof(struct kvm_sae_block) == PAGE_SIZE);\n+\n+struct kvm_sae_save_area {\n+#define SAE_SAVE_AREA_FORMAT_0\t0x00\n+\tu8\tsaf;\t\t/* 0x0000 */\n+\tu8\t_0001[5];\t/* 0x0001 */\n+#define SAE_SAS_VALID\t\tBIT(0)\n+\tu16\tsas;\t\t/* 0x0006 */\n+\tu64\tsdo;\t\t/* 0x0008 */\n+\tu64\t_0010[2];\t/* 0x0010 */\n+\tu64\tregs[508];\t/* 0x0020 */\n+} __packed __aligned(PAGE_SIZE);\n+static_assert(sizeof(struct kvm_sae_save_area) == PAGE_SIZE);\n+\n+#endif /* ASM_KVM_HOST_ARM64_TYPES_H */\ndiff --git a/arch/s390/include/asm/kvm_host_s390.h b/arch/s390/include/asm/kvm_host_s390.h\nnew file mode 100644\nindex 00000000000000..7b7aa166cff730\n--- /dev/null\n+++ b/arch/s390/include/asm/kvm_host_s390.h\n@@ -0,0 +1,773 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/*\n+ * definition for kernel virtual machines on s390\n+ *\n+ * Copyright IBM Corp. 2008, 2018\n+ *\n+ * Author(s): Carsten Otte \u003ccotte@de.ibm.com\u003e\n+ */\n+\n+\n+#ifndef ASM_KVM_HOST_S390_H\n+#define ASM_KVM_HOST_S390_H\n+\n+#include \u003clinux/types.h\u003e\n+#include \u003clinux/hrtimer.h\u003e\n+#include \u003clinux/interrupt.h\u003e\n+#include \u003clinux/kvm_types.h\u003e\n+#include \u003clinux/kvm.h\u003e\n+#include \u003clinux/seqlock.h\u003e\n+#include \u003clinux/module.h\u003e\n+#include \u003clinux/pci.h\u003e\n+#include \u003clinux/mmu_notifier.h\u003e\n+#include \u003casm/kvm_host_types.h\u003e\n+#include \u003casm/debug.h\u003e\n+#include \u003casm/cpu.h\u003e\n+#include \u003casm/fpu.h\u003e\n+#include \u003casm/isc.h\u003e\n+#include \u003casm/guarded_storage.h\u003e\n+\n+#define KVM_HAVE_MMU_RWLOCK\n+#define KVM_MAX_VCPUS 255\n+\n+#define KVM_INTERNAL_MEM_SLOTS 1\n+\n+/*\n+ * These seem to be used for allocating -\u003echip in the routing table, which we\n+ * don't use. 1 is as small as we can get to reduce the needed memory. If we\n+ * need to look at -\u003echip later on, we'll need to revisit this.\n+ */\n+#define KVM_NR_IRQCHIPS 1\n+#define KVM_IRQCHIP_NUM_PINS 1\n+#define KVM_HALT_POLL_NS_DEFAULT 50000\n+\n+/* s390-specific vcpu-\u003erequests bit members */\n+#define KVM_REQ_ENABLE_IBS\tKVM_ARCH_REQ(0)\n+#define KVM_REQ_DISABLE_IBS\tKVM_ARCH_REQ(1)\n+#define KVM_REQ_ICPT_OPEREXC\tKVM_ARCH_REQ(2)\n+#define KVM_REQ_START_MIGRATION KVM_ARCH_REQ(3)\n+#define KVM_REQ_STOP_MIGRATION KVM_ARCH_REQ(4)\n+#define KVM_REQ_VSIE_RESTART\tKVM_ARCH_REQ(5)\n+#define KVM_REQ_REFRESH_GUEST_PREFIX\t\\\n+\tKVM_ARCH_REQ_FLAGS(6, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)\n+\n+struct kvm_vcpu_stat {\n+\tstruct kvm_vcpu_stat_generic generic;\n+\tu64 exit_userspace;\n+\tu64 exit_null;\n+\tu64 exit_external_request;\n+\tu64 exit_io_request;\n+\tu64 exit_external_interrupt;\n+\tu64 exit_stop_request;\n+\tu64 exit_validity;\n+\tu64 exit_instruction;\n+\tu64 exit_pei;\n+\tu64 halt_no_poll_steal;\n+\tu64 instruction_lctl;\n+\tu64 instruction_lctlg;\n+\tu64 instruction_stctl;\n+\tu64 instruction_stctg;\n+\tu64 exit_program_interruption;\n+\tu64 exit_instr_and_program;\n+\tu64 exit_operation_exception;\n+\tu64 deliver_ckc;\n+\tu64 deliver_cputm;\n+\tu64 deliver_external_call;\n+\tu64 deliver_emergency_signal;\n+\tu64 deliver_service_signal;\n+\tu64 deliver_virtio;\n+\tu64 deliver_stop_signal;\n+\tu64 deliver_prefix_signal;\n+\tu64 deliver_restart_signal;\n+\tu64 deliver_program;\n+\tu64 deliver_io;\n+\tu64 deliver_machine_check;\n+\tu64 exit_wait_state;\n+\tu64 inject_ckc;\n+\tu64 inject_cputm;\n+\tu64 inject_external_call;\n+\tu64 inject_emergency_signal;\n+\tu64 inject_mchk;\n+\tu64 inject_pfault_init;\n+\tu64 inject_program;\n+\tu64 inject_restart;\n+\tu64 inject_set_prefix;\n+\tu64 inject_stop_signal;\n+\tu64 instruction_epsw;\n+\tu64 instruction_gs;\n+\tu64 instruction_io_other;\n+\tu64 instruction_lpsw;\n+\tu64 instruction_lpswe;\n+\tu64 instruction_lpswey;\n+\tu64 instruction_pfmf;\n+\tu64 instruction_ptff;\n+\tu64 instruction_sck;\n+\tu64 instruction_sckpf;\n+\tu64 instruction_stidp;\n+\tu64 instruction_spx;\n+\tu64 instruction_stpx;\n+\tu64 instruction_stap;\n+\tu64 instruction_iske;\n+\tu64 instruction_ri;\n+\tu64 instruction_rrbe;\n+\tu64 instruction_sske;\n+\tu64 instruction_ipte_interlock;\n+\tu64 instruction_stsi;\n+\tu64 instruction_stfl;\n+\tu64 instruction_tb;\n+\tu64 instruction_tpi;\n+\tu64 instruction_tprot;\n+\tu64 instruction_tsch;\n+\tu64 instruction_sie;\n+\tu64 instruction_essa;\n+\tu64 instruction_sthyi;\n+\tu64 instruction_sigp_sense;\n+\tu64 instruction_sigp_sense_running;\n+\tu64 instruction_sigp_external_call;\n+\tu64 instruction_sigp_emergency;\n+\tu64 instruction_sigp_cond_emergency;\n+\tu64 instruction_sigp_start;\n+\tu64 instruction_sigp_stop;\n+\tu64 instruction_sigp_stop_store_status;\n+\tu64 instruction_sigp_store_status;\n+\tu64 instruction_sigp_store_adtl_status;\n+\tu64 instruction_sigp_arch;\n+\tu64 instruction_sigp_prefix;\n+\tu64 instruction_sigp_restart;\n+\tu64 instruction_sigp_init_cpu_reset;\n+\tu64 instruction_sigp_cpu_reset;\n+\tu64 instruction_sigp_unknown;\n+\tu64 instruction_diagnose_10;\n+\tu64 instruction_diagnose_44;\n+\tu64 instruction_diagnose_9c;\n+\tu64 diag_9c_ignored;\n+\tu64 diag_9c_forward;\n+\tu64 instruction_diagnose_258;\n+\tu64 instruction_diagnose_308;\n+\tu64 instruction_diagnose_500;\n+\tu64 instruction_diagnose_other;\n+\tu64 pfault_sync;\n+\tu64 signal_exits;\n+};\n+\n+#define PGM_OPERATION\t\t\t0x01\n+#define PGM_PRIVILEGED_OP\t\t0x02\n+#define PGM_EXECUTE\t\t\t0x03\n+/* 0x04 \u0026 0x05 defined in kvm_host.h */\n+#define PGM_SPECIFICATION\t\t0x06\n+#define PGM_DATA\t\t\t0x07\n+#define PGM_FIXED_POINT_OVERFLOW\t0x08\n+#define PGM_FIXED_POINT_DIVIDE\t\t0x09\n+#define PGM_DECIMAL_OVERFLOW\t\t0x0a\n+#define PGM_DECIMAL_DIVIDE\t\t0x0b\n+#define PGM_HFP_EXPONENT_OVERFLOW\t0x0c\n+#define PGM_HFP_EXPONENT_UNDERFLOW\t0x0d\n+#define PGM_HFP_SIGNIFICANCE\t\t0x0e\n+#define PGM_HFP_DIVIDE\t\t\t0x0f\n+/* 0x10 \u0026 0x11 defined in kvm_host.h */\n+#define PGM_TRANSLATION_SPEC\t\t0x12\n+#define PGM_SPECIAL_OPERATION\t\t0x13\n+#define PGM_OPERAND\t\t\t0x15\n+#define PGM_TRACE_TABEL\t\t\t0x16\n+#define PGM_VECTOR_PROCESSING\t\t0x1b\n+#define PGM_SPACE_SWITCH\t\t0x1c\n+#define PGM_HFP_SQUARE_ROOT\t\t0x1d\n+#define PGM_PC_TRANSLATION_SPEC\t\t0x1f\n+#define PGM_AFX_TRANSLATION\t\t0x20\n+#define PGM_ASX_TRANSLATION\t\t0x21\n+#define PGM_LX_TRANSLATION\t\t0x22\n+#define PGM_EX_TRANSLATION\t\t0x23\n+#define PGM_PRIMARY_AUTHORITY\t\t0x24\n+#define PGM_SECONDARY_AUTHORITY\t\t0x25\n+#define PGM_LFX_TRANSLATION\t\t0x26\n+#define PGM_LSX_TRANSLATION\t\t0x27\n+#define PGM_ALET_SPECIFICATION\t\t0x28\n+#define PGM_ALEN_TRANSLATION\t\t0x29\n+#define PGM_ALE_SEQUENCE\t\t0x2a\n+#define PGM_ASTE_VALIDITY\t\t0x2b\n+#define PGM_ASTE_SEQUENCE\t\t0x2c\n+#define PGM_EXTENDED_AUTHORITY\t\t0x2d\n+#define PGM_LSTE_SEQUENCE\t\t0x2e\n+#define PGM_ASTE_INSTANCE\t\t0x2f\n+#define PGM_STACK_FULL\t\t\t0x30\n+#define PGM_STACK_EMPTY\t\t\t0x31\n+#define PGM_STACK_SPECIFICATION\t\t0x32\n+#define PGM_STACK_TYPE\t\t\t0x33\n+#define PGM_STACK_OPERATION\t\t0x34\n+/* 0x38 - 0x3b defined in kvm_host.h */\n+#define PGM_SECURE_STORAGE_ACCESS\t0x3d\n+#define PGM_NON_SECURE_STORAGE_ACCESS\t0x3e\n+#define PGM_SECURE_STORAGE_VIOLATION\t0x3f\n+#define PGM_MONITOR\t\t\t0x40\n+#define PGM_PER\t\t\t\t0x80\n+#define PGM_CRYPTO_OPERATION\t\t0x119\n+\n+/* irq types in ascend order of priorities */\n+enum irq_types {\n+\tIRQ_PEND_SET_PREFIX = 0,\n+\tIRQ_PEND_RESTART,\n+\tIRQ_PEND_SIGP_STOP,\n+\tIRQ_PEND_IO_ISC_7,\n+\tIRQ_PEND_IO_ISC_6,\n+\tIRQ_PEND_IO_ISC_5,\n+\tIRQ_PEND_IO_ISC_4,\n+\tIRQ_PEND_IO_ISC_3,\n+\tIRQ_PEND_IO_ISC_2,\n+\tIRQ_PEND_IO_ISC_1,\n+\tIRQ_PEND_IO_ISC_0,\n+\tIRQ_PEND_VIRTIO,\n+\tIRQ_PEND_PFAULT_DONE,\n+\tIRQ_PEND_PFAULT_INIT,\n+\tIRQ_PEND_EXT_HOST,\n+\tIRQ_PEND_EXT_SERVICE,\n+\tIRQ_PEND_EXT_SERVICE_EV,\n+\tIRQ_PEND_EXT_TIMING,\n+\tIRQ_PEND_EXT_CPU_TIMER,\n+\tIRQ_PEND_EXT_CLOCK_COMP,\n+\tIRQ_PEND_EXT_EXTERNAL,\n+\tIRQ_PEND_EXT_EMERGENCY,\n+\tIRQ_PEND_EXT_MALFUNC,\n+\tIRQ_PEND_EXT_IRQ_KEY,\n+\tIRQ_PEND_MCHK_REP,\n+\tIRQ_PEND_PROG,\n+\tIRQ_PEND_SVC,\n+\tIRQ_PEND_MCHK_EX,\n+\tIRQ_PEND_COUNT\n+};\n+\n+/* We have 2M for virtio device descriptor pages. Smallest amount of\n+ * memory per page is 24 bytes (1 queue), so (2048*1024) / 24 = 87381\n+ */\n+#define KVM_S390_MAX_VIRTIO_IRQS 87381\n+\n+/*\n+ * Repressible (non-floating) machine check interrupts\n+ * subclass bits in MCIC\n+ */\n+#define MCHK_EXTD_BIT 58\n+#define MCHK_DEGR_BIT 56\n+#define MCHK_WARN_BIT 55\n+#define MCHK_REP_MASK ((1UL \u003c\u003c MCHK_DEGR_BIT) | \\\n+\t\t (1UL \u003c\u003c MCHK_EXTD_BIT) | \\\n+\t\t (1UL \u003c\u003c MCHK_WARN_BIT))\n+\n+/* Exigent machine check interrupts subclass bits in MCIC */\n+#define MCHK_SD_BIT 63\n+#define MCHK_PD_BIT 62\n+#define MCHK_EX_MASK ((1UL \u003c\u003c MCHK_SD_BIT) | (1UL \u003c\u003c MCHK_PD_BIT))\n+\n+#define IRQ_PEND_EXT_MASK ((1UL \u003c\u003c IRQ_PEND_EXT_IRQ_KEY) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_CLOCK_COMP) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_CPU_TIMER) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_MALFUNC) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_EMERGENCY) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_EXTERNAL) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_TIMING) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_HOST) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_SERVICE) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_SERVICE_EV) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_VIRTIO) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_PFAULT_INIT) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_PFAULT_DONE))\n+\n+#define IRQ_PEND_IO_MASK ((1UL \u003c\u003c IRQ_PEND_IO_ISC_0) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_1) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_2) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_3) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_4) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_5) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_6) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_IO_ISC_7))\n+\n+#define IRQ_PEND_MCHK_MASK ((1UL \u003c\u003c IRQ_PEND_MCHK_REP) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_MCHK_EX))\n+\n+#define IRQ_PEND_EXT_II_MASK ((1UL \u003c\u003c IRQ_PEND_EXT_CPU_TIMER) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_CLOCK_COMP) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_EMERGENCY) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_EXTERNAL) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_SERVICE) | \\\n+\t\t\t (1UL \u003c\u003c IRQ_PEND_EXT_SERVICE_EV))\n+\n+struct kvm_s390_interrupt_info {\n+\tstruct list_head list;\n+\tu64\ttype;\n+\tunion {\n+\t\tstruct kvm_s390_io_info io;\n+\t\tstruct kvm_s390_ext_info ext;\n+\t\tstruct kvm_s390_pgm_info pgm;\n+\t\tstruct kvm_s390_emerg_info emerg;\n+\t\tstruct kvm_s390_extcall_info extcall;\n+\t\tstruct kvm_s390_prefix_info prefix;\n+\t\tstruct kvm_s390_stop_info stop;\n+\t\tstruct kvm_s390_mchk_info mchk;\n+\t};\n+};\n+\n+struct kvm_s390_irq_payload {\n+\tstruct kvm_s390_io_info io;\n+\tstruct kvm_s390_ext_info ext;\n+\tstruct kvm_s390_pgm_info pgm;\n+\tstruct kvm_s390_emerg_info emerg;\n+\tstruct kvm_s390_extcall_info extcall;\n+\tstruct kvm_s390_prefix_info prefix;\n+\tstruct kvm_s390_stop_info stop;\n+\tstruct kvm_s390_mchk_info mchk;\n+};\n+\n+struct kvm_s390_local_interrupt {\n+\tspinlock_t lock;\n+\tDECLARE_BITMAP(sigp_emerg_pending, KVM_MAX_VCPUS);\n+\tstruct kvm_s390_irq_payload irq;\n+\tunsigned long pending_irqs;\n+};\n+\n+#define FIRQ_LIST_IO_ISC_0 0\n+#define FIRQ_LIST_IO_ISC_1 1\n+#define FIRQ_LIST_IO_ISC_2 2\n+#define FIRQ_LIST_IO_ISC_3 3\n+#define FIRQ_LIST_IO_ISC_4 4\n+#define FIRQ_LIST_IO_ISC_5 5\n+#define FIRQ_LIST_IO_ISC_6 6\n+#define FIRQ_LIST_IO_ISC_7 7\n+#define FIRQ_LIST_PFAULT 8\n+#define FIRQ_LIST_VIRTIO 9\n+#define FIRQ_LIST_COUNT 10\n+#define FIRQ_CNTR_IO 0\n+#define FIRQ_CNTR_SERVICE 1\n+#define FIRQ_CNTR_VIRTIO 2\n+#define FIRQ_CNTR_PFAULT 3\n+#define FIRQ_MAX_COUNT 4\n+\n+/* mask the AIS mode for a given ISC */\n+#define AIS_MODE_MASK(isc) (0x80 \u003e\u003e isc)\n+\n+#define KVM_S390_AIS_MODE_ALL 0\n+#define KVM_S390_AIS_MODE_SINGLE 1\n+\n+struct kvm_s390_float_interrupt {\n+\tunsigned long pending_irqs;\n+\tunsigned long masked_irqs;\n+\tspinlock_t lock;\n+\tstruct list_head lists[FIRQ_LIST_COUNT];\n+\tint counters[FIRQ_MAX_COUNT];\n+\tstruct kvm_s390_mchk_info mchk;\n+\tstruct kvm_s390_ext_info srv_signal;\n+\tint last_sleep_cpu;\n+\tspinlock_t ais_lock;\n+\tu8 simm;\n+\tu8 nimm;\n+};\n+\n+struct kvm_hw_wp_info_arch {\n+\tunsigned long addr;\n+\tunsigned long phys_addr;\n+\tint len;\n+\tchar *old_data;\n+};\n+\n+struct kvm_hw_bp_info_arch {\n+\tunsigned long addr;\n+\tint len;\n+};\n+\n+/*\n+ * Only the upper 16 bits of kvm_guest_debug-\u003econtrol are arch specific.\n+ * Further KVM_GUESTDBG flags which an be used from userspace can be found in\n+ * arch/s390/include/uapi/asm/kvm.h\n+ */\n+#define KVM_GUESTDBG_EXIT_PENDING 0x10000000\n+\n+#define guestdbg_enabled(vcpu) \\\n+\t\t(vcpu-\u003eguest_debug \u0026 KVM_GUESTDBG_ENABLE)\n+#define guestdbg_sstep_enabled(vcpu) \\\n+\t\t(vcpu-\u003eguest_debug \u0026 KVM_GUESTDBG_SINGLESTEP)\n+#define guestdbg_hw_bp_enabled(vcpu) \\\n+\t\t(vcpu-\u003eguest_debug \u0026 KVM_GUESTDBG_USE_HW_BP)\n+#define guestdbg_exit_pending(vcpu) (guestdbg_enabled(vcpu) \u0026\u0026 \\\n+\t\t(vcpu-\u003eguest_debug \u0026 KVM_GUESTDBG_EXIT_PENDING))\n+\n+#define KVM_GUESTDBG_VALID_MASK \\\n+\t\t(KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP |\\\n+\t\tKVM_GUESTDBG_USE_HW_BP | KVM_GUESTDBG_EXIT_PENDING)\n+\n+struct kvm_guestdbg_info_arch {\n+\tunsigned long cr0;\n+\tunsigned long cr9;\n+\tunsigned long cr10;\n+\tunsigned long cr11;\n+\tstruct kvm_hw_bp_info_arch *hw_bp_info;\n+\tstruct kvm_hw_wp_info_arch *hw_wp_info;\n+\tint nr_hw_bp;\n+\tint nr_hw_wp;\n+\tunsigned long last_bp;\n+};\n+\n+struct kvm_s390_pv_vcpu {\n+\tu64 handle;\n+\tunsigned long stor_base;\n+};\n+\n+struct kvm_vcpu_arch {\n+\tstruct kvm_s390_sie_block *sie_block;\n+\t/* if vsie is active, currently executed shadow sie control block */\n+\tstruct kvm_s390_sie_block *vsie_block;\n+\tunsigned int host_acrs[NUM_ACRS];\n+\tstruct gs_cb *host_gscb;\n+\tstruct kvm_s390_local_interrupt local_int;\n+\tstruct hrtimer ckc_timer;\n+\tstruct kvm_s390_pgm_info pgm;\n+\tstruct gmap *gmap;\n+\tstruct kvm_guestdbg_info_arch guestdbg;\n+\tunsigned long pfault_token;\n+\tunsigned long pfault_select;\n+\tunsigned long pfault_compare;\n+\tbool cputm_enabled;\n+\t/*\n+\t * The seqcount protects updates to cputm_start and sie_block.cputm,\n+\t * this way we can have non-blocking reads with consistent values.\n+\t * Only the owning VCPU thread (vcpu-\u003ecpu) is allowed to change these\n+\t * values and to start/stop/enable/disable cpu timer accounting.\n+\t */\n+\tseqcount_t cputm_seqcount;\n+\t__u64 cputm_start;\n+\tbool gs_enabled;\n+\tbool skey_enabled;\n+\t/* Indicator if the access registers have been loaded from guest */\n+\tbool acrs_loaded;\n+\tstruct kvm_s390_pv_vcpu pv;\n+\tunion diag318_info diag318_info;\n+\tstruct kvm_s390_mmu_cache *mc;\n+};\n+\n+struct kvm_vm_stat {\n+\tstruct kvm_vm_stat_generic generic;\n+\tu64 inject_io;\n+\tu64 io_390_adapter_map;\n+\tu64 io_390_adapter_unmap;\n+\tu64 io_390_inatomic;\n+\tu64 io_flic_inject_airq;\n+\tu64 io_set_adapter_int;\n+\tu64 io_390_inatomic_no_inject;\n+\tu64 inject_float_mchk;\n+\tu64 inject_pfault_done;\n+\tu64 inject_service_signal;\n+\tu64 inject_virtio;\n+\tu64 aen_forward;\n+\tu64 gmap_shadow_create;\n+\tu64 gmap_shadow_reuse;\n+\tu64 gmap_shadow_r1_entry;\n+\tu64 gmap_shadow_r2_entry;\n+\tu64 gmap_shadow_r3_entry;\n+\tu64 gmap_shadow_sg_entry;\n+\tu64 gmap_shadow_pg_entry;\n+};\n+\n+struct kvm_arch_memory_slot {\n+};\n+\n+struct s390_map_info {\n+\tstruct list_head list;\n+\t__u64 guest_addr;\n+\t__u64 addr;\n+\tstruct page *page;\n+};\n+\n+struct s390_io_adapter {\n+\tunsigned int id;\n+\tint isc;\n+\tbool maskable;\n+\tbool masked;\n+\tbool swap;\n+\tbool suppressible;\n+\tspinlock_t maps_lock;\n+\tstruct list_head maps;\n+\tunsigned int nr_maps;\n+};\n+\n+#define MAX_S390_IO_ADAPTERS ((MAX_ISC + 1) * 8)\n+#define MAX_S390_ADAPTER_MAPS 256\n+\n+/* maximum size of facilities and facility mask is 2k bytes */\n+#define S390_ARCH_FAC_LIST_SIZE_BYTE (1\u003c\u003c11)\n+#define S390_ARCH_FAC_LIST_SIZE_U64 \\\n+\t(S390_ARCH_FAC_LIST_SIZE_BYTE / sizeof(u64))\n+#define S390_ARCH_FAC_MASK_SIZE_BYTE S390_ARCH_FAC_LIST_SIZE_BYTE\n+#define S390_ARCH_FAC_MASK_SIZE_U64 \\\n+\t(S390_ARCH_FAC_MASK_SIZE_BYTE / sizeof(u64))\n+\n+struct kvm_s390_cpu_model {\n+\t/* facility mask supported by kvm \u0026 hosting machine */\n+\t__u64 fac_mask[S390_ARCH_FAC_MASK_SIZE_U64];\n+\tstruct kvm_s390_vm_cpu_subfunc subfuncs;\n+\t/* facility list requested by guest (in dma page) */\n+\t__u64 *fac_list;\n+\tu64 cpuid;\n+\tunsigned short ibc;\n+\t/* subset of available UV-features for pv-guests enabled by user space */\n+\tstruct kvm_s390_vm_cpu_uv_feat uv_feat_guest;\n+};\n+\n+#define S390_ARCH_FAC_FORMAT_2 2\n+struct kvm_s390_flcb2 {\n+\tunion {\n+\t\tstruct {\n+\t\t\tu8 reserved0[7];\n+\t\t\tu8 length;\n+\t\t};\n+\t\tu64 header_val;\n+\t};\n+\tu64 facilities[S390_ARCH_FAC_LIST_SIZE_U64];\n+};\n+\n+typedef int (*crypto_hook)(struct kvm_vcpu *vcpu);\n+\n+struct kvm_s390_crypto {\n+\tstruct kvm_s390_crypto_cb *crycb;\n+\tstruct rw_semaphore pqap_hook_rwsem;\n+\tcrypto_hook *pqap_hook;\n+\t__u32 crycbd;\n+\t__u8 aes_kw;\n+\t__u8 dea_kw;\n+\t__u8 apie;\n+};\n+\n+#define APCB0_MASK_SIZE 1\n+struct kvm_s390_apcb0 {\n+\t__u64 apm[APCB0_MASK_SIZE];\t\t/* 0x0000 */\n+\t__u64 aqm[APCB0_MASK_SIZE];\t\t/* 0x0008 */\n+\t__u64 adm[APCB0_MASK_SIZE];\t\t/* 0x0010 */\n+\t__u64 reserved18;\t\t\t/* 0x0018 */\n+};\n+\n+#define APCB1_MASK_SIZE 4\n+struct kvm_s390_apcb1 {\n+\t__u64 apm[APCB1_MASK_SIZE];\t\t/* 0x0000 */\n+\t__u64 aqm[APCB1_MASK_SIZE];\t\t/* 0x0020 */\n+\t__u64 adm[APCB1_MASK_SIZE];\t\t/* 0x0040 */\n+\t__u64 reserved60[4];\t\t\t/* 0x0060 */\n+};\n+\n+struct kvm_s390_crypto_cb {\n+\tstruct kvm_s390_apcb0 apcb0;\t\t/* 0x0000 */\n+\t__u8 reserved20[0x0048 - 0x0020];\t/* 0x0020 */\n+\t__u8 dea_wrapping_key_mask[24];\t/* 0x0048 */\n+\t__u8 aes_wrapping_key_mask[32];\t/* 0x0060 */\n+\tstruct kvm_s390_apcb1 apcb1;\t\t/* 0x0080 */\n+};\n+\n+struct kvm_s390_gisa {\n+\tunion {\n+\t\tstruct { /* common to all formats */\n+\t\t\tu32 next_alert;\n+\t\t\tu8 ipm;\n+\t\t\tu8 reserved01[2];\n+\t\t\tu8 iam;\n+\t\t};\n+\t\tstruct { /* format 0 */\n+\t\t\tu32 next_alert;\n+\t\t\tu8 ipm;\n+\t\t\tu8 reserved01;\n+\t\t\tu8 : 6;\n+\t\t\tu8 g : 1;\n+\t\t\tu8 c : 1;\n+\t\t\tu8 iam;\n+\t\t\tu8 reserved02[4];\n+\t\t\tu32 airq_count;\n+\t\t} g0;\n+\t\tstruct { /* format 1 */\n+\t\t\tu32 next_alert;\n+\t\t\tu8 ipm;\n+\t\t\tu8 simm;\n+\t\t\tu8 nimm;\n+\t\t\tu8 iam;\n+\t\t\tu8 aism[8];\n+\t\t\tu8 : 6;\n+\t\t\tu8 g : 1;\n+\t\t\tu8 c : 1;\n+\t\t\tu8 reserved03[11];\n+\t\t\tu32 airq_count;\n+\t\t} g1;\n+\t\tstruct {\n+\t\t\tu64 word[4];\n+\t\t} u64;\n+\t};\n+};\n+\n+struct kvm_s390_gib {\n+\tu32 alert_list_origin;\n+\tu32 reserved01;\n+\tu8:5;\n+\tu8 nisc:3;\n+\tu8 reserved03[3];\n+\tu32 reserved04[5];\n+};\n+\n+/*\n+ * sie_page2 has to be allocated as DMA because fac_list, crycb and\n+ * gisa need 31bit addresses in the sie control block.\n+ */\n+struct sie_page2 {\n+\t__u64 fac_list[S390_ARCH_FAC_LIST_SIZE_U64];\t/* 0x0000 */\n+\tstruct kvm_s390_crypto_cb crycb;\t\t/* 0x0800 */\n+\tstruct kvm_s390_gisa gisa;\t\t\t/* 0x0900 */\n+\tstruct kvm *kvm;\t\t\t\t/* 0x0920 */\n+\tu8 reserved928[0x1000 - 0x928];\t\t\t/* 0x0928 */\n+};\n+\n+struct vsie_page;\n+\n+struct kvm_s390_vsie {\n+\tstruct mutex mutex;\n+\tstruct radix_tree_root addr_to_page;\n+\tint page_count;\n+\tint next;\n+\tstruct vsie_page *pages[KVM_MAX_VCPUS];\n+};\n+\n+struct kvm_s390_gisa_iam {\n+\tu8 mask;\n+\tspinlock_t ref_lock;\n+\tu32 ref_count[MAX_ISC + 1];\n+};\n+\n+struct kvm_s390_gisa_interrupt {\n+\tstruct kvm_s390_gisa *origin;\n+\tstruct kvm_s390_gisa_iam alert;\n+\tstruct hrtimer timer;\n+\tu64 expires;\n+\tDECLARE_BITMAP(kicked_mask, KVM_MAX_VCPUS);\n+};\n+\n+struct kvm_s390_pv {\n+\tu64 handle;\n+\tu64 guest_len;\n+\tunsigned long stor_base;\n+\tvoid *stor_var;\n+\tbool dumping;\n+\tvoid *set_aside;\n+\tstruct list_head need_cleanup;\n+\tstruct mmu_notifier mmu_notifier;\n+\t/* Protects against concurrent import-like operations */\n+\tstruct mutex import_lock;\n+};\n+\n+struct kvm_s390_mmu_cache;\n+\n+struct kvm_arch {\n+\tstruct esca_block *sca;\n+\tdebug_info_t *dbf;\n+\tstruct kvm_s390_float_interrupt float_int;\n+\tstruct kvm_device *flic;\n+\tstruct gmap *gmap;\n+\tunsigned long mem_limit;\n+\tint css_support;\n+\tint use_irqchip;\n+\tint use_cmma;\n+\tint use_pfmfi;\n+\tint use_skf;\n+\tint use_zpci_interp;\n+\tint user_cpu_state_ctrl;\n+\tint user_sigp;\n+\tint user_stsi;\n+\tint user_instr0;\n+\tint user_operexec;\n+\tint allow_vsie_esamode;\n+\tstruct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];\n+\twait_queue_head_t ipte_wq;\n+\tint ipte_lock_count;\n+\tstruct mutex ipte_mutex;\n+\tspinlock_t start_stop_lock;\n+\tstruct sie_page2 *sie_page2;\n+\tstruct kvm_s390_cpu_model model;\n+\tstruct kvm_s390_crypto crypto;\n+\tstruct kvm_s390_vsie vsie;\n+\tu8 epdx;\n+\tu64 epoch;\n+\tint migration_mode;\n+\tatomic64_t cmma_dirty_pages;\n+\t/* subset of available cpu features enabled by user space */\n+\tDECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);\n+\t/* indexed by vcpu_idx */\n+\tDECLARE_BITMAP(idle_mask, KVM_MAX_VCPUS);\n+\tstruct kvm_s390_gisa_interrupt gisa_int;\n+\tstruct kvm_s390_pv pv;\n+\tstruct list_head kzdev_list;\n+\tspinlock_t kzdev_list_lock;\n+\tstruct kvm_s390_mmu_cache *mc;\n+};\n+\n+#define KVM_HVA_ERR_BAD\t\t(-1UL)\n+#define KVM_HVA_ERR_RO_BAD\t(-2UL)\n+\n+static inline bool kvm_is_error_hva(unsigned long addr)\n+{\n+\treturn IS_ERR_VALUE(addr);\n+}\n+\n+#define ASYNC_PF_PER_VCPU\t64\n+struct kvm_arch_async_pf {\n+\tunsigned long pfault_token;\n+};\n+\n+bool kvm_arch_can_dequeue_async_page_present(struct kvm_vcpu *vcpu);\n+\n+void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,\n+\t\t\t struct kvm_async_pf *work);\n+\n+bool kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,\n+\t\t\t\t struct kvm_async_pf *work);\n+\n+void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,\n+\t\t\t\t struct kvm_async_pf *work);\n+\n+static inline void kvm_arch_async_page_present_queued(struct kvm_vcpu *vcpu) {}\n+\n+void kvm_arch_crypto_clear_masks(struct kvm *kvm);\n+void kvm_arch_crypto_set_masks(struct kvm *kvm, unsigned long *apm,\n+\t\t\t unsigned long *aqm, unsigned long *adm);\n+\n+#define SIE64_RETURN_NORMAL\t0\n+#define SIE64_RETURN_MCCK\t1\n+\n+int __sie64a(phys_addr_t sie_block_phys, struct kvm_s390_sie_block *sie_block, u64 *rsa,\n+\t unsigned long gasce);\n+\n+static inline int sie64a(struct kvm_s390_sie_block *sie_block, u64 *rsa, unsigned long gasce)\n+{\n+\treturn __sie64a(virt_to_phys(sie_block), sie_block, rsa, gasce);\n+}\n+\n+extern char sie_exit;\n+\n+bool kvm_s390_pv_is_protected(struct kvm *kvm);\n+bool kvm_s390_pv_cpu_is_protected(struct kvm_vcpu *vcpu);\n+\n+extern int kvm_s390_enter_exit_sie(struct kvm_s390_sie_block *scb,\n+\t\t\t\t u64 *gprs, unsigned long gasce);\n+\n+extern int kvm_s390_gisc_register(struct kvm *kvm, u32 gisc);\n+extern int kvm_s390_gisc_unregister(struct kvm *kvm, u32 gisc);\n+\n+bool kvm_s390_is_gpa_in_memslot(struct kvm *kvm, gpa_t gpa);\n+\n+static inline void kvm_arch_free_memslot(struct kvm *kvm,\n+\t\t\t\t\t struct kvm_memory_slot *slot) {}\n+static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}\n+static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {}\n+static inline void kvm_arch_flush_shadow_memslot(struct kvm *kvm,\n+\t\tstruct kvm_memory_slot *slot) {}\n+static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {}\n+static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {}\n+\n+#define __KVM_HAVE_ARCH_VM_FREE\n+void kvm_arch_free_vm(struct kvm *kvm);\n+\n+struct zpci_kvm_hook {\n+\tint (*kvm_register)(void *opaque, struct kvm *kvm);\n+\tvoid (*kvm_unregister)(void *opaque);\n+};\n+\n+extern struct zpci_kvm_hook zpci_kvm_hook;\n+\n+#endif /* ASM_KVM_HOST_S390_H */\ndiff --git a/arch/s390/include/asm/kvm_host_s390_types.h b/arch/s390/include/asm/kvm_host_s390_types.h\nnew file mode 100644\nindex 00000000000000..5cf746095bfd12\n--- /dev/null\n+++ b/arch/s390/include/asm/kvm_host_s390_types.h\n@@ -0,0 +1,347 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+\n+#ifndef _ASM_KVM_HOST_S390_TYPES_H\n+#define _ASM_KVM_HOST_S390_TYPES_H\n+\n+#include \u003clinux/atomic.h\u003e\n+#include \u003clinux/types.h\u003e\n+\n+#define KVM_S390_BSCA_CPU_SLOTS 64\n+#define KVM_S390_ESCA_CPU_SLOTS 248\n+\n+#define SIGP_CTRL_C\t\t0x80\n+#define SIGP_CTRL_SCN_MASK\t0x3f\n+\n+union bsca_sigp_ctrl {\n+\t__u8 value;\n+\tstruct {\n+\t\t__u8 c : 1;\n+\t\t__u8 r : 1;\n+\t\t__u8 scn : 6;\n+\t};\n+};\n+\n+union esca_sigp_ctrl {\n+\t__u16 value;\n+\tstruct {\n+\t\t__u8 c : 1;\n+\t\t__u8 reserved: 7;\n+\t\t__u8 scn;\n+\t};\n+};\n+\n+struct esca_entry {\n+\tunion esca_sigp_ctrl sigp_ctrl;\n+\t__u16\treserved1[3];\n+\t__u64\tsda;\n+\t__u64\treserved2[6];\n+};\n+\n+struct bsca_entry {\n+\t__u8\treserved0;\n+\tunion bsca_sigp_ctrl\tsigp_ctrl;\n+\t__u16\treserved[3];\n+\t__u64\tsda;\n+\t__u64\treserved2[2];\n+};\n+\n+union ipte_control {\n+\tunsigned long val;\n+\tstruct {\n+\t\tunsigned long k : 1;\n+\t\tunsigned long kh : 31;\n+\t\tunsigned long kg : 32;\n+\t};\n+};\n+\n+/*\n+ * Utility is defined as two bytes but having it four bytes wide\n+ * generates more efficient code. Since the following bytes are\n+ * reserved this makes no functional difference.\n+ */\n+union sca_utility {\n+\t__u32 val;\n+\tstruct {\n+\t\t__u32 mtcr : 1;\n+\t\t__u32\t : 31;\n+\t};\n+};\n+\n+struct bsca_block {\n+\tunion ipte_control ipte_control;\n+\t__u64\treserved[5];\n+\t__u64\tmcn;\n+\tunion sca_utility utility;\n+\t__u8\treserved2[4];\n+\tstruct bsca_entry cpu[KVM_S390_BSCA_CPU_SLOTS];\n+};\n+\n+struct esca_block {\n+\tunion ipte_control ipte_control;\n+\t__u64\treserved1[6];\n+\tunion sca_utility utility;\n+\t__u8\treserved2[4];\n+\t__u64\tmcn[4];\n+\t__u64\treserved3[20];\n+\tstruct esca_entry cpu[KVM_S390_ESCA_CPU_SLOTS];\n+};\n+\n+/*\n+ * This struct is used to store some machine check info from lowcore\n+ * for machine checks that happen while the guest is running.\n+ * This info in host's lowcore might be overwritten by a second machine\n+ * check from host when host is in the machine check's high-level handling.\n+ * The size is 24 bytes.\n+ */\n+struct mcck_volatile_info {\n+\t__u64 mcic;\n+\t__u64 failing_storage_address;\n+\t__u32 ext_damage_code;\n+\t__u32 reserved;\n+};\n+\n+#define CR0_INITIAL_MASK (CR0_UNUSED_56 | CR0_INTERRUPT_KEY_SUBMASK | \\\n+\t\t\t CR0_MEASUREMENT_ALERT_SUBMASK)\n+#define CR14_INITIAL_MASK (CR14_UNUSED_32 | CR14_UNUSED_33 | \\\n+\t\t\t CR14_EXTERNAL_DAMAGE_SUBMASK)\n+\n+#define SIDAD_SIZE_MASK\t\t0xff\n+#define sida_addr(sie_block) phys_to_virt((sie_block)-\u003esidad \u0026 PAGE_MASK)\n+#define sida_size(sie_block) \\\n+\t((((sie_block)-\u003esidad \u0026 SIDAD_SIZE_MASK) + 1) * PAGE_SIZE)\n+\n+#define CPUSTAT_STOPPED 0x80000000\n+#define CPUSTAT_WAIT\t 0x10000000\n+#define CPUSTAT_ECALL_PEND 0x08000000\n+#define CPUSTAT_STOP_INT 0x04000000\n+#define CPUSTAT_IO_INT\t 0x02000000\n+#define CPUSTAT_EXT_INT 0x01000000\n+#define CPUSTAT_RUNNING 0x00800000\n+#define CPUSTAT_RETAINED 0x00400000\n+#define CPUSTAT_TIMING_SUB 0x00020000\n+#define CPUSTAT_SIE_SUB 0x00010000\n+#define CPUSTAT_RRF\t 0x00008000\n+#define CPUSTAT_SLSV\t 0x00004000\n+#define CPUSTAT_SLSR\t 0x00002000\n+#define CPUSTAT_ZARCH\t 0x00000800\n+#define CPUSTAT_MCDS\t 0x00000100\n+#define CPUSTAT_KSS\t 0x00000200\n+#define CPUSTAT_SM\t 0x00000080\n+#define CPUSTAT_IBS\t 0x00000040\n+#define CPUSTAT_GED2\t 0x00000010\n+#define CPUSTAT_G\t 0x00000008\n+#define CPUSTAT_GED\t 0x00000004\n+#define CPUSTAT_J\t 0x00000002\n+#define CPUSTAT_P\t 0x00000001\n+\n+struct kvm_s390_sie_block {\n+\tatomic_t cpuflags;\t\t/* 0x0000 */\n+\t__u32 : 1;\t\t\t/* 0x0004 */\n+\t__u32 prefix : 19;\n+\t__u32 ibc : 12;\n+\t__u8\treserved08[4];\t\t/* 0x0008 */\n+#define PROG_IN_SIE (1\u003c\u003c0)\n+\t__u32\tprog0c;\t\t\t/* 0x000c */\n+\tunion {\n+\t\t__u8\treserved10[16];\t\t/* 0x0010 */\n+\t\tstruct {\n+\t\t\t__u64\tpv_handle_cpu;\n+\t\t\t__u64\tpv_handle_config;\n+\t\t};\n+\t};\n+#define PROG_BLOCK_SIE\t(1\u003c\u003c0)\n+#define PROG_REQUEST\t(1\u003c\u003c1)\n+\tatomic_t prog20;\t\t/* 0x0020 */\n+\t__u8\treserved24[4];\t\t/* 0x0024 */\n+\t__u64\tcputm;\t\t\t/* 0x0028 */\n+\t__u64\tckc;\t\t\t/* 0x0030 */\n+\t__u64\tepoch;\t\t\t/* 0x0038 */\n+\t__u32\tsvcc;\t\t\t/* 0x0040 */\n+#define LCTL_CR0\t0x8000\n+#define LCTL_CR6\t0x0200\n+#define LCTL_CR9\t0x0040\n+#define LCTL_CR10\t0x0020\n+#define LCTL_CR11\t0x0010\n+#define LCTL_CR14\t0x0002\n+\t__u16\tlctl;\t\t\t/* 0x0044 */\n+\t__s16\ticpua;\t\t\t/* 0x0046 */\n+#define ICTL_OPEREXC\t0x80000000\n+#define ICTL_PINT\t0x20000000\n+#define ICTL_LPSW\t0x00400000\n+#define ICTL_STCTL\t0x00040000\n+#define ICTL_ISKE\t0x00004000\n+#define ICTL_SSKE\t0x00002000\n+#define ICTL_RRBE\t0x00001000\n+#define ICTL_TPROT\t0x00000200\n+\t__u32\tictl;\t\t\t/* 0x0048 */\n+#define ECA_CEI\t\t0x80000000\n+#define ECA_IB\t\t0x40000000\n+#define ECA_SIGPI\t0x10000000\n+#define ECA_MVPGI\t0x01000000\n+#define ECA_AIV\t\t0x00200000\n+#define ECA_VX\t\t0x00020000\n+#define ECA_PROTEXCI\t0x00002000\n+#define ECA_APIE\t0x00000008\n+#define ECA_SII\t\t0x00000001\n+\t__u32\teca;\t\t\t/* 0x004c */\n+#define ICPT_INST\t0x04\n+#define ICPT_PROGI\t0x08\n+#define ICPT_INSTPROGI\t0x0C\n+#define ICPT_EXTREQ\t0x10\n+#define ICPT_EXTINT\t0x14\n+#define ICPT_IOREQ\t0x18\n+#define ICPT_WAIT\t0x1c\n+#define ICPT_VALIDITY\t0x20\n+#define ICPT_STOP\t0x28\n+#define ICPT_OPEREXC\t0x2C\n+#define ICPT_PARTEXEC\t0x38\n+#define ICPT_IOINST\t0x40\n+#define ICPT_KSS\t0x5c\n+#define ICPT_MCHKREQ\t0x60\n+#define ICPT_INT_ENABLE\t0x64\n+#define ICPT_PV_INSTR\t0x68\n+#define ICPT_PV_NOTIFY\t0x6c\n+#define ICPT_PV_PREF\t0x70\n+\t__u8\ticptcode;\t\t/* 0x0050 */\n+\t__u8\ticptstatus;\t\t/* 0x0051 */\n+\t__u16\tihcpu;\t\t\t/* 0x0052 */\n+\t__u8\treserved54;\t\t/* 0x0054 */\n+#define IICTL_CODE_NONE\t\t 0x00\n+#define IICTL_CODE_MCHK\t\t 0x01\n+#define IICTL_CODE_EXT\t\t 0x02\n+#define IICTL_CODE_IO\t\t 0x03\n+#define IICTL_CODE_RESTART\t 0x04\n+#define IICTL_CODE_SPECIFICATION 0x10\n+#define IICTL_CODE_OPERAND\t 0x11\n+\t__u8\tiictl;\t\t\t/* 0x0055 */\n+\t__u16\tipa;\t\t\t/* 0x0056 */\n+\t__u32\tipb;\t\t\t/* 0x0058 */\n+\t__u32\tscaoh;\t\t\t/* 0x005c */\n+#define FPF_BPBC\t0x20\n+\t__u8\tfpf;\t\t\t/* 0x0060 */\n+#define ECB_GS\t\t0x40\n+#define ECB_TE\t\t0x10\n+#define ECB_SPECI\t0x08\n+#define ECB_SRSI\t0x04\n+#define ECB_HOSTPROTINT\t0x02\n+#define ECB_PTF\t\t0x01\n+\t__u8\tecb;\t\t\t/* 0x0061 */\n+#define ECB2_CMMA\t0x80\n+#define ECB2_IEP\t0x20\n+#define ECB2_PFMFI\t0x08\n+#define ECB2_ESCA\t0x04\n+#define ECB2_ZPCI_LSI\t0x02\n+\t__u8\tecb2;\t\t\t/* 0x0062 */\n+#define ECB3_AISI\t0x20\n+#define ECB3_AISII\t0x10\n+#define ECB3_DEA 0x08\n+#define ECB3_AES 0x04\n+#define ECB3_RI 0x01\n+\t__u8\tecb3;\t\t\t/* 0x0063 */\n+#define ESCA_SCAOL_MASK ~0x3fU\n+\t__u32\tscaol;\t\t\t/* 0x0064 */\n+\t__u8\tsdf;\t\t\t/* 0x0068 */\n+\t__u8\tepdx;\t\t\t/* 0x0069 */\n+\t__u8\tcpnc;\t\t\t/* 0x006a */\n+\t__u8\treserved6b;\t\t/* 0x006b */\n+\t__u32\ttodpr;\t\t\t/* 0x006c */\n+#define GISA_FORMAT1 0x00000001\n+\t__u32\tgd;\t\t\t/* 0x0070 */\n+\t__u8\treserved74[12];\t\t/* 0x0074 */\n+\t__u64\tmso;\t\t\t/* 0x0080 */\n+\t__u64\tmsl;\t\t\t/* 0x0088 */\n+\tpsw_t\tgpsw;\t\t\t/* 0x0090 */\n+\t__u64\tgg14;\t\t\t/* 0x00a0 */\n+\t__u64\tgg15;\t\t\t/* 0x00a8 */\n+\t__u8\treservedb0[8];\t\t/* 0x00b0 */\n+#define HPID_KVM\t0x4\n+#define HPID_VSIE\t0x5\n+\t__u8\thpid;\t\t\t/* 0x00b8 */\n+\t__u8\treservedb9[7];\t\t/* 0x00b9 */\n+\tunion {\n+\t\tstruct {\n+\t\t\t__u32\teiparams;\t/* 0x00c0 */\n+\t\t\t__u16\textcpuaddr;\t/* 0x00c4 */\n+\t\t\t__u16\teic;\t\t/* 0x00c6 */\n+\t\t};\n+\t\t__u64\tmcic;\t\t\t/* 0x00c0 */\n+\t} __packed;\n+\t__u32\treservedc8;\t\t/* 0x00c8 */\n+\tunion {\n+\t\tstruct {\n+\t\t\t__u16\tpgmilc;\t\t/* 0x00cc */\n+\t\t\t__u16\tiprcc;\t\t/* 0x00ce */\n+\t\t};\n+\t\t__u32\tedc;\t\t\t/* 0x00cc */\n+\t} __packed;\n+\tunion {\n+\t\tstruct {\n+\t\t\t__u32\tdxc;\t\t/* 0x00d0 */\n+\t\t\t__u16\tmcn;\t\t/* 0x00d4 */\n+\t\t\t__u8\tperc;\t\t/* 0x00d6 */\n+\t\t\t__u8\tperatmid;\t/* 0x00d7 */\n+\t\t};\n+\t\t__u64\tfaddr;\t\t\t/* 0x00d0 */\n+\t} __packed;\n+\t__u64\tperaddr;\t\t/* 0x00d8 */\n+\t__u8\teai;\t\t\t/* 0x00e0 */\n+\t__u8\tperaid;\t\t\t/* 0x00e1 */\n+\t__u8\toai;\t\t\t/* 0x00e2 */\n+\t__u8\tarmid;\t\t\t/* 0x00e3 */\n+\t__u8\treservede4[4];\t\t/* 0x00e4 */\n+\tunion {\n+\t\t__u64\ttecmc;\t\t/* 0x00e8 */\n+\t\tstruct {\n+\t\t\t__u16\tsubchannel_id;\t/* 0x00e8 */\n+\t\t\t__u16\tsubchannel_nr;\t/* 0x00ea */\n+\t\t\t__u32\tio_int_parm;\t/* 0x00ec */\n+\t\t\t__u32\tio_int_word;\t/* 0x00f0 */\n+\t\t};\n+\t} __packed;\n+\t__u8\treservedf4[8];\t\t/* 0x00f4 */\n+#define CRYCB_FORMAT_MASK 0x00000003\n+#define CRYCB_FORMAT0 0x00000000\n+#define CRYCB_FORMAT1 0x00000001\n+#define CRYCB_FORMAT2 0x00000003\n+\t__u32\tcrycbd;\t\t\t/* 0x00fc */\n+\t__u64\tgcr[16];\t\t/* 0x0100 */\n+\tunion {\n+\t\t__u64\tgbea;\t\t/* 0x0180 */\n+\t\t__u64\tsidad;\n+\t};\n+\t__u8\treserved188[8];\t\t/* 0x0188 */\n+\t__u64\tsdnxo;\t\t\t/* 0x0190 */\n+\t__u8\treserved198[8];\t\t/* 0x0198 */\n+\t__u32\tfac;\t\t\t/* 0x01a0 */\n+\t__u8\treserved1a4[20];\t/* 0x01a4 */\n+\t__u64\tcbrlo;\t\t\t/* 0x01b8 */\n+\t__u8\treserved1c0[8];\t\t/* 0x01c0 */\n+#define ECD_HOSTREGMGMT\t0x20000000\n+#define ECD_MEF\t\t0x08000000\n+#define ECD_ETOKENF\t0x02000000\n+#define ECD_ECC\t\t0x00200000\n+#define ECD_HMAC\t0x00004000\n+\t__u32\tecd;\t\t\t/* 0x01c8 */\n+\t__u8\treserved1cc[18];\t/* 0x01cc */\n+\t__u64\tpp;\t\t\t/* 0x01de */\n+\t__u8\treserved1e6[2];\t\t/* 0x01e6 */\n+\t__u64\titdba;\t\t\t/* 0x01e8 */\n+\t__u64\triccbd;\t\t\t/* 0x01f0 */\n+\t__u64\tgvrd;\t\t\t/* 0x01f8 */\n+} __packed __aligned(512);\n+\n+struct kvm_s390_itdb {\n+\t__u8\tdata[256];\n+};\n+\n+struct sie_page {\n+\tstruct kvm_s390_sie_block sie_block;\n+\tstruct mcck_volatile_info mcck_info;\t/* 0x0200 */\n+\t__u8 reserved218[360];\t\t/* 0x0218 */\n+\t__u64 pv_grregs[16];\t\t/* 0x0380 */\n+\t__u8 reserved400[512];\t\t/* 0x0400 */\n+\tstruct kvm_s390_itdb itdb;\t/* 0x0600 */\n+\t__u8 reserved700[2304];\t\t/* 0x0700 */\n+};\n+\n+#endif /* _ASM_KVM_HOST_S390_TYPES_H */\ndiff --git a/arch/s390/include/asm/kvm_host_types.h b/arch/s390/include/asm/kvm_host_types.h\nindex 3f50942bdfe6c7..d308739ebcf570 100644\n--- a/arch/s390/include/asm/kvm_host_types.h\n+++ b/arch/s390/include/asm/kvm_host_types.h\n@@ -1,347 +1,12 @@\n /* SPDX-License-Identifier: GPL-2.0 */\n \n-#ifndef _ASM_KVM_HOST_TYPES_H\n-#define _ASM_KVM_HOST_TYPES_H\n+#ifndef ASM_KVM_HOST_TYPES_H\n+#define ASM_KVM_HOST_TYPES_H\n \n-#include \u003clinux/atomic.h\u003e\n-#include \u003clinux/types.h\u003e\n+#ifdef KVM_S390_ARM64\n+#include \u003casm/kvm_host_arm64_types.h\u003e\n+#else\n+#include \u003casm/kvm_host_s390_types.h\u003e\n+#endif /* KVM_S390_ARM64 */\n \n-#define KVM_S390_BSCA_CPU_SLOTS 64\n-#define KVM_S390_ESCA_CPU_SLOTS 248\n-\n-#define SIGP_CTRL_C\t\t0x80\n-#define SIGP_CTRL_SCN_MASK\t0x3f\n-\n-union bsca_sigp_ctrl {\n-\t__u8 value;\n-\tstruct {\n-\t\t__u8 c : 1;\n-\t\t__u8 r : 1;\n-\t\t__u8 scn : 6;\n-\t};\n-};\n-\n-union esca_sigp_ctrl {\n-\t__u16 value;\n-\tstruct {\n-\t\t__u8 c : 1;\n-\t\t__u8 reserved: 7;\n-\t\t__u8 scn;\n-\t};\n-};\n-\n-struct esca_entry {\n-\tunion esca_sigp_ctrl sigp_ctrl;\n-\t__u16\treserved1[3];\n-\t__u64\tsda;\n-\t__u64\treserved2[6];\n-};\n-\n-struct bsca_entry {\n-\t__u8\treserved0;\n-\tunion bsca_sigp_ctrl\tsigp_ctrl;\n-\t__u16\treserved[3];\n-\t__u64\tsda;\n-\t__u64\treserved2[2];\n-};\n-\n-union ipte_control {\n-\tunsigned long val;\n-\tstruct {\n-\t\tunsigned long k : 1;\n-\t\tunsigned long kh : 31;\n-\t\tunsigned long kg : 32;\n-\t};\n-};\n-\n-/*\n- * Utility is defined as two bytes but having it four bytes wide\n- * generates more efficient code. Since the following bytes are\n- * reserved this makes no functional difference.\n- */\n-union sca_utility {\n-\t__u32 val;\n-\tstruct {\n-\t\t__u32 mtcr : 1;\n-\t\t__u32\t : 31;\n-\t};\n-};\n-\n-struct bsca_block {\n-\tunion ipte_control ipte_control;\n-\t__u64\treserved[5];\n-\t__u64\tmcn;\n-\tunion sca_utility utility;\n-\t__u8\treserved2[4];\n-\tstruct bsca_entry cpu[KVM_S390_BSCA_CPU_SLOTS];\n-};\n-\n-struct esca_block {\n-\tunion ipte_control ipte_control;\n-\t__u64\treserved1[6];\n-\tunion sca_utility utility;\n-\t__u8\treserved2[4];\n-\t__u64\tmcn[4];\n-\t__u64\treserved3[20];\n-\tstruct esca_entry cpu[KVM_S390_ESCA_CPU_SLOTS];\n-};\n-\n-/*\n- * This struct is used to store some machine check info from lowcore\n- * for machine checks that happen while the guest is running.\n- * This info in host's lowcore might be overwritten by a second machine\n- * check from host when host is in the machine check's high-level handling.\n- * The size is 24 bytes.\n- */\n-struct mcck_volatile_info {\n-\t__u64 mcic;\n-\t__u64 failing_storage_address;\n-\t__u32 ext_damage_code;\n-\t__u32 reserved;\n-};\n-\n-#define CR0_INITIAL_MASK (CR0_UNUSED_56 | CR0_INTERRUPT_KEY_SUBMASK | \\\n-\t\t\t CR0_MEASUREMENT_ALERT_SUBMASK)\n-#define CR14_INITIAL_MASK (CR14_UNUSED_32 | CR14_UNUSED_33 | \\\n-\t\t\t CR14_EXTERNAL_DAMAGE_SUBMASK)\n-\n-#define SIDAD_SIZE_MASK\t\t0xff\n-#define sida_addr(sie_block) phys_to_virt((sie_block)-\u003esidad \u0026 PAGE_MASK)\n-#define sida_size(sie_block) \\\n-\t((((sie_block)-\u003esidad \u0026 SIDAD_SIZE_MASK) + 1) * PAGE_SIZE)\n-\n-#define CPUSTAT_STOPPED 0x80000000\n-#define CPUSTAT_WAIT\t 0x10000000\n-#define CPUSTAT_ECALL_PEND 0x08000000\n-#define CPUSTAT_STOP_INT 0x04000000\n-#define CPUSTAT_IO_INT\t 0x02000000\n-#define CPUSTAT_EXT_INT 0x01000000\n-#define CPUSTAT_RUNNING 0x00800000\n-#define CPUSTAT_RETAINED 0x00400000\n-#define CPUSTAT_TIMING_SUB 0x00020000\n-#define CPUSTAT_SIE_SUB 0x00010000\n-#define CPUSTAT_RRF\t 0x00008000\n-#define CPUSTAT_SLSV\t 0x00004000\n-#define CPUSTAT_SLSR\t 0x00002000\n-#define CPUSTAT_ZARCH\t 0x00000800\n-#define CPUSTAT_MCDS\t 0x00000100\n-#define CPUSTAT_KSS\t 0x00000200\n-#define CPUSTAT_SM\t 0x00000080\n-#define CPUSTAT_IBS\t 0x00000040\n-#define CPUSTAT_GED2\t 0x00000010\n-#define CPUSTAT_G\t 0x00000008\n-#define CPUSTAT_GED\t 0x00000004\n-#define CPUSTAT_J\t 0x00000002\n-#define CPUSTAT_P\t 0x00000001\n-\n-struct kvm_s390_sie_block {\n-\tatomic_t cpuflags;\t\t/* 0x0000 */\n-\t__u32 : 1;\t\t\t/* 0x0004 */\n-\t__u32 prefix : 19;\n-\t__u32 ibc : 12;\n-\t__u8\treserved08[4];\t\t/* 0x0008 */\n-#define PROG_IN_SIE (1\u003c\u003c0)\n-\t__u32\tprog0c;\t\t\t/* 0x000c */\n-\tunion {\n-\t\t__u8\treserved10[16];\t\t/* 0x0010 */\n-\t\tstruct {\n-\t\t\t__u64\tpv_handle_cpu;\n-\t\t\t__u64\tpv_handle_config;\n-\t\t};\n-\t};\n-#define PROG_BLOCK_SIE\t(1\u003c\u003c0)\n-#define PROG_REQUEST\t(1\u003c\u003c1)\n-\tatomic_t prog20;\t\t/* 0x0020 */\n-\t__u8\treserved24[4];\t\t/* 0x0024 */\n-\t__u64\tcputm;\t\t\t/* 0x0028 */\n-\t__u64\tckc;\t\t\t/* 0x0030 */\n-\t__u64\tepoch;\t\t\t/* 0x0038 */\n-\t__u32\tsvcc;\t\t\t/* 0x0040 */\n-#define LCTL_CR0\t0x8000\n-#define LCTL_CR6\t0x0200\n-#define LCTL_CR9\t0x0040\n-#define LCTL_CR10\t0x0020\n-#define LCTL_CR11\t0x0010\n-#define LCTL_CR14\t0x0002\n-\t__u16\tlctl;\t\t\t/* 0x0044 */\n-\t__s16\ticpua;\t\t\t/* 0x0046 */\n-#define ICTL_OPEREXC\t0x80000000\n-#define ICTL_PINT\t0x20000000\n-#define ICTL_LPSW\t0x00400000\n-#define ICTL_STCTL\t0x00040000\n-#define ICTL_ISKE\t0x00004000\n-#define ICTL_SSKE\t0x00002000\n-#define ICTL_RRBE\t0x00001000\n-#define ICTL_TPROT\t0x00000200\n-\t__u32\tictl;\t\t\t/* 0x0048 */\n-#define ECA_CEI\t\t0x80000000\n-#define ECA_IB\t\t0x40000000\n-#define ECA_SIGPI\t0x10000000\n-#define ECA_MVPGI\t0x01000000\n-#define ECA_AIV\t\t0x00200000\n-#define ECA_VX\t\t0x00020000\n-#define ECA_PROTEXCI\t0x00002000\n-#define ECA_APIE\t0x00000008\n-#define ECA_SII\t\t0x00000001\n-\t__u32\teca;\t\t\t/* 0x004c */\n-#define ICPT_INST\t0x04\n-#define ICPT_PROGI\t0x08\n-#define ICPT_INSTPROGI\t0x0C\n-#define ICPT_EXTREQ\t0x10\n-#define ICPT_EXTINT\t0x14\n-#define ICPT_IOREQ\t0x18\n-#define ICPT_WAIT\t0x1c\n-#define ICPT_VALIDITY\t0x20\n-#define ICPT_STOP\t0x28\n-#define ICPT_OPEREXC\t0x2C\n-#define ICPT_PARTEXEC\t0x38\n-#define ICPT_IOINST\t0x40\n-#define ICPT_KSS\t0x5c\n-#define ICPT_MCHKREQ\t0x60\n-#define ICPT_INT_ENABLE\t0x64\n-#define ICPT_PV_INSTR\t0x68\n-#define ICPT_PV_NOTIFY\t0x6c\n-#define ICPT_PV_PREF\t0x70\n-\t__u8\ticptcode;\t\t/* 0x0050 */\n-\t__u8\ticptstatus;\t\t/* 0x0051 */\n-\t__u16\tihcpu;\t\t\t/* 0x0052 */\n-\t__u8\treserved54;\t\t/* 0x0054 */\n-#define IICTL_CODE_NONE\t\t 0x00\n-#define IICTL_CODE_MCHK\t\t 0x01\n-#define IICTL_CODE_EXT\t\t 0x02\n-#define IICTL_CODE_IO\t\t 0x03\n-#define IICTL_CODE_RESTART\t 0x04\n-#define IICTL_CODE_SPECIFICATION 0x10\n-#define IICTL_CODE_OPERAND\t 0x11\n-\t__u8\tiictl;\t\t\t/* 0x0055 */\n-\t__u16\tipa;\t\t\t/* 0x0056 */\n-\t__u32\tipb;\t\t\t/* 0x0058 */\n-\t__u32\tscaoh;\t\t\t/* 0x005c */\n-#define FPF_BPBC\t0x20\n-\t__u8\tfpf;\t\t\t/* 0x0060 */\n-#define ECB_GS\t\t0x40\n-#define ECB_TE\t\t0x10\n-#define ECB_SPECI\t0x08\n-#define ECB_SRSI\t0x04\n-#define ECB_HOSTPROTINT\t0x02\n-#define ECB_PTF\t\t0x01\n-\t__u8\tecb;\t\t\t/* 0x0061 */\n-#define ECB2_CMMA\t0x80\n-#define ECB2_IEP\t0x20\n-#define ECB2_PFMFI\t0x08\n-#define ECB2_ESCA\t0x04\n-#define ECB2_ZPCI_LSI\t0x02\n-\t__u8\tecb2;\t\t\t/* 0x0062 */\n-#define ECB3_AISI\t0x20\n-#define ECB3_AISII\t0x10\n-#define ECB3_DEA 0x08\n-#define ECB3_AES 0x04\n-#define ECB3_RI 0x01\n-\t__u8\tecb3;\t\t\t/* 0x0063 */\n-#define ESCA_SCAOL_MASK ~0x3fU\n-\t__u32\tscaol;\t\t\t/* 0x0064 */\n-\t__u8\tsdf;\t\t\t/* 0x0068 */\n-\t__u8\tepdx;\t\t\t/* 0x0069 */\n-\t__u8\tcpnc;\t\t\t/* 0x006a */\n-\t__u8\treserved6b;\t\t/* 0x006b */\n-\t__u32\ttodpr;\t\t\t/* 0x006c */\n-#define GISA_FORMAT1 0x00000001\n-\t__u32\tgd;\t\t\t/* 0x0070 */\n-\t__u8\treserved74[12];\t\t/* 0x0074 */\n-\t__u64\tmso;\t\t\t/* 0x0080 */\n-\t__u64\tmsl;\t\t\t/* 0x0088 */\n-\tpsw_t\tgpsw;\t\t\t/* 0x0090 */\n-\t__u64\tgg14;\t\t\t/* 0x00a0 */\n-\t__u64\tgg15;\t\t\t/* 0x00a8 */\n-\t__u8\treservedb0[8];\t\t/* 0x00b0 */\n-#define HPID_KVM\t0x4\n-#define HPID_VSIE\t0x5\n-\t__u8\thpid;\t\t\t/* 0x00b8 */\n-\t__u8\treservedb9[7];\t\t/* 0x00b9 */\n-\tunion {\n-\t\tstruct {\n-\t\t\t__u32\teiparams;\t/* 0x00c0 */\n-\t\t\t__u16\textcpuaddr;\t/* 0x00c4 */\n-\t\t\t__u16\teic;\t\t/* 0x00c6 */\n-\t\t};\n-\t\t__u64\tmcic;\t\t\t/* 0x00c0 */\n-\t} __packed;\n-\t__u32\treservedc8;\t\t/* 0x00c8 */\n-\tunion {\n-\t\tstruct {\n-\t\t\t__u16\tpgmilc;\t\t/* 0x00cc */\n-\t\t\t__u16\tiprcc;\t\t/* 0x00ce */\n-\t\t};\n-\t\t__u32\tedc;\t\t\t/* 0x00cc */\n-\t} __packed;\n-\tunion {\n-\t\tstruct {\n-\t\t\t__u32\tdxc;\t\t/* 0x00d0 */\n-\t\t\t__u16\tmcn;\t\t/* 0x00d4 */\n-\t\t\t__u8\tperc;\t\t/* 0x00d6 */\n-\t\t\t__u8\tperatmid;\t/* 0x00d7 */\n-\t\t};\n-\t\t__u64\tfaddr;\t\t\t/* 0x00d0 */\n-\t} __packed;\n-\t__u64\tperaddr;\t\t/* 0x00d8 */\n-\t__u8\teai;\t\t\t/* 0x00e0 */\n-\t__u8\tperaid;\t\t\t/* 0x00e1 */\n-\t__u8\toai;\t\t\t/* 0x00e2 */\n-\t__u8\tarmid;\t\t\t/* 0x00e3 */\n-\t__u8\treservede4[4];\t\t/* 0x00e4 */\n-\tunion {\n-\t\t__u64\ttecmc;\t\t/* 0x00e8 */\n-\t\tstruct {\n-\t\t\t__u16\tsubchannel_id;\t/* 0x00e8 */\n-\t\t\t__u16\tsubchannel_nr;\t/* 0x00ea */\n-\t\t\t__u32\tio_int_parm;\t/* 0x00ec */\n-\t\t\t__u32\tio_int_word;\t/* 0x00f0 */\n-\t\t};\n-\t} __packed;\n-\t__u8\treservedf4[8];\t\t/* 0x00f4 */\n-#define CRYCB_FORMAT_MASK 0x00000003\n-#define CRYCB_FORMAT0 0x00000000\n-#define CRYCB_FORMAT1 0x00000001\n-#define CRYCB_FORMAT2 0x00000003\n-\t__u32\tcrycbd;\t\t\t/* 0x00fc */\n-\t__u64\tgcr[16];\t\t/* 0x0100 */\n-\tunion {\n-\t\t__u64\tgbea;\t\t/* 0x0180 */\n-\t\t__u64\tsidad;\n-\t};\n-\t__u8\treserved188[8];\t\t/* 0x0188 */\n-\t__u64\tsdnxo;\t\t\t/* 0x0190 */\n-\t__u8\treserved198[8];\t\t/* 0x0198 */\n-\t__u32\tfac;\t\t\t/* 0x01a0 */\n-\t__u8\treserved1a4[20];\t/* 0x01a4 */\n-\t__u64\tcbrlo;\t\t\t/* 0x01b8 */\n-\t__u8\treserved1c0[8];\t\t/* 0x01c0 */\n-#define ECD_HOSTREGMGMT\t0x20000000\n-#define ECD_MEF\t\t0x08000000\n-#define ECD_ETOKENF\t0x02000000\n-#define ECD_ECC\t\t0x00200000\n-#define ECD_HMAC\t0x00004000\n-\t__u32\tecd;\t\t\t/* 0x01c8 */\n-\t__u8\treserved1cc[18];\t/* 0x01cc */\n-\t__u64\tpp;\t\t\t/* 0x01de */\n-\t__u8\treserved1e6[2];\t\t/* 0x01e6 */\n-\t__u64\titdba;\t\t\t/* 0x01e8 */\n-\t__u64\triccbd;\t\t\t/* 0x01f0 */\n-\t__u64\tgvrd;\t\t\t/* 0x01f8 */\n-} __packed __aligned(512);\n-\n-struct kvm_s390_itdb {\n-\t__u8\tdata[256];\n-};\n-\n-struct sie_page {\n-\tstruct kvm_s390_sie_block sie_block;\n-\tstruct mcck_volatile_info mcck_info;\t/* 0x0200 */\n-\t__u8 reserved218[360];\t\t/* 0x0218 */\n-\t__u64 pv_grregs[16];\t\t/* 0x0380 */\n-\t__u8 reserved400[512];\t\t/* 0x0400 */\n-\tstruct kvm_s390_itdb itdb;\t/* 0x0600 */\n-\t__u8 reserved700[2304];\t\t/* 0x0700 */\n-};\n-\n-#endif /* _ASM_KVM_HOST_TYPES_H */\n+#endif /* ASM_KVM_HOST_TYPES_H */\ndiff --git a/arch/s390/include/asm/sae.h b/arch/s390/include/asm/sae.h\nnew file mode 100644\nindex 00000000000000..fe010a1a772975\n--- /dev/null\n+++ b/arch/s390/include/asm/sae.h\n@@ -0,0 +1,56 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#ifndef __ASM_S390_SAE_H\n+#define __ASM_S390_SAE_H\n+\n+#include \"linux/linkage.h\"\n+#include \u003clinux/types.h\u003e\n+\n+/* defined in arch/s390/kernel/entry.S */\n+asmlinkage int __sae64a(phys_addr_t sae_block_phys);\n+\n+#ifndef __ASSEMBLER__\n+#include \u003clinux/io.h\u003e\n+#include \u003casm/kvm_host_arm64_types.h\u003e\n+\n+/**\n+ * __sae64a() - Start Arm Execution\n+ */\n+static inline void sae64a(struct kvm_sae_block *sae_block)\n+{\n+\t__sae64a(virt_to_phys(sae_block));\n+}\n+\n+/**\n+ * stiasrm() - STore and Invalidate Arm System Register Multiple\n+ * @save_area: Pointer to SAE save area\n+ *\n+ * Store the guest system register to the save area.\n+ * The values in the guest are not valid anymore..\n+ */\n+static __always_inline void stiasrm(struct kvm_sae_save_area *save_area)\n+{\n+\tasm volatile(\n+\t\t\"\t.insn\trre,0xb9a70000,%[r1],0\\n\"\n+\t\t: \"+m\"(*save_area)\n+\t\t: [r1] \"a\"(save_area)\n+\t);\n+}\n+\n+/**\n+ * lasrm() - Load Arm System Register Multiple\n+ *\n+ * @save_area: Pointer to SAE save area\n+ *\n+ * Load the system registers from save_area into the guest.\n+ */\n+static __always_inline void lasrm(struct kvm_sae_save_area *save_area)\n+{\n+\tasm volatile(\n+\t\t\"\t.insn\trre,0xb9a60000,%[r1],0\\n\"\n+\t\t:\n+\t\t: \"m\"(*save_area), [r1] \"a\"(save_area)\n+\t);\n+}\n+\n+#endif /* !__ASSEMBLER__ */\n+#endif /* __ASM_S390_SAE_H */\ndiff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h\nindex f2d49055805437..f669569cf78df6 100644\n--- a/arch/s390/include/asm/sclp.h\n+++ b/arch/s390/include/asm/sclp.h\n@@ -53,7 +53,9 @@ struct sclp_core_entry {\n \tu8 siif : 1;\n \tu8 sigpif : 1;\n \tu8 : 3;\n-\tu8 reserved2[3];\n+\tu8 aef: 1;\n+\tu8 : 7;\n+\tu8 reserved2[2];\n \tu8 : 2;\n \tu8 ib : 1;\n \tu8 cei : 1;\n@@ -106,6 +108,7 @@ struct sclp_info {\n \tunsigned char has_aeni : 1;\n \tunsigned char has_aisi : 1;\n \tunsigned char has_astfleie2 : 1;\n+\tunsigned char has_aef : 1;\n \tunsigned int ibc;\n \tunsigned int mtid;\n \tunsigned int mtid_cp;\ndiff --git a/arch/s390/include/asm/stacktrace.h b/arch/s390/include/asm/stacktrace.h\nindex ac3606c3babe49..2d332d7c814594 100644\n--- a/arch/s390/include/asm/stacktrace.h\n+++ b/arch/s390/include/asm/stacktrace.h\n@@ -59,6 +59,7 @@ static inline bool on_stack(struct stack_info *info,\n struct stack_frame {\n \tunion {\n \t\tunsigned long empty[9];\n+\t\t/* SIE stack frame */\n \t\tstruct {\n \t\t\tunsigned long sie_control_block;\n \t\t\tunsigned long sie_savearea;\n@@ -68,6 +69,10 @@ struct stack_frame {\n \t\t\tunsigned long sie_guest_asce;\n \t\t\tunsigned long sie_irq;\n \t\t};\n+\t\t/* SAE stack frame */\n+\t\tstruct {\n+\t\t\tunsigned long sae_bear;\n+\t\t};\n \t};\n \tunsigned long gprs[10];\n \tunsigned long back_chain;\ndiff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c\nindex f6dd2b67dcee74..f9f9c2246074f8 100644\n--- a/arch/s390/kernel/asm-offsets.c\n+++ b/arch/s390/kernel/asm-offsets.c\n@@ -70,6 +70,7 @@ int main(void)\n \tOFFSET(__SF_SIE_CONTROL_PHYS, stack_frame, sie_control_block_phys);\n \tOFFSET(__SF_SIE_GUEST_ASCE, stack_frame, sie_guest_asce);\n \tOFFSET(__SF_SIE_IRQ, stack_frame, sie_irq);\n+\tOFFSET(__SF_SAE_BEAR, stack_frame, sae_bear);\n \tDEFINE(STACK_FRAME_OVERHEAD, sizeof(struct stack_frame));\n \tBLANK();\n \tOFFSET(__SFUSER_BACKCHAIN, stack_frame_user, back_chain);\ndiff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c\nindex b27239c03d7992..464f8918d447fb 100644\n--- a/arch/s390/kernel/early.c\n+++ b/arch/s390/kernel/early.c\n@@ -57,7 +57,7 @@ decompressor_handled_param(cmma);\n decompressor_handled_param(relocate_lowcore);\n decompressor_handled_param(bootdebug);\n __decompressor_handled_param(debug_alternative, debug-alternative);\n-#if IS_ENABLED(CONFIG_KVM)\n+#if IS_ENABLED(CONFIG_KVM_S390)\n decompressor_handled_param(prot_virt);\n #endif\n \ndiff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S\nindex 79a45efae23d06..248bea26921bef 100644\n--- a/arch/s390/kernel/entry.S\n+++ b/arch/s390/kernel/entry.S\n@@ -113,7 +113,7 @@ _LPP_OFFSET\t= __LC_LPP\n \t\t \"jnz .+8; .insn rrf,0xb2e80000,0,0,13,0\", ALT_SPEC(82)\n \t.endm\n \n-#if IS_ENABLED(CONFIG_KVM)\n+#if IS_ENABLED(CONFIG_KVM_S390)\n \t.macro SIEEXIT sie_control,lowcore\n \tlg\t%r9,\\sie_control\t\t\t# get control block pointer\n \tni\t__SIE_PROG0C+3(%r9),0xfe\t\t# no longer in SIE\n@@ -184,7 +184,7 @@ EXPORT_SYMBOL(__WARN_trap)\n \n #endif /* CONFIG_BUG \u0026\u0026 CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */\n \n-#if IS_ENABLED(CONFIG_KVM)\n+#if IS_ENABLED(CONFIG_KVM_S390)\n /*\n * __sie64a calling convention:\n * %r2 pointer to sie control block phys\n@@ -244,6 +244,31 @@ EXPORT_SYMBOL(__sie64a)\n EXPORT_SYMBOL(sie_exit)\n #endif\n \n+#if IS_ENABLED(CONFIG_KVM_ARM64)\n+/*\n+ * __sae64a calling convention:\n+ * %r2 pointer to sae control block physical address\n+ */\n+SYM_FUNC_START(__sae64a)\n+\tstmg\t%r6,%r14,__SF_GPRS(%r15)\t# store kernel registers\n+\tSTBEAR\t__SF_SAE_BEAR(%r15)\t\t# save breaking event address register\n+\t.insn\trre,0xb9a50000,%r2,0\t\t# Start Arm Execution\n+# Let the next instruction be NOP to avoid triggering a machine check\n+# and handling it in a guest as result of the instruction execution.\n+\tnopr\t7\n+\tLBEAR\t__SF_SAE_BEAR(%r15)\t\t# restore breaking event address register\n+\tlmg\t%r6,%r14,__SF_GPRS(%r15)\t# restore kernel registers\n+\txgr\t%r0,%r0\t\t\t\t# clear guest registers to\n+\txgr\t%r1,%r1\t\t\t\t# prevent speculative use\n+\txgr\t%r3,%r3\n+\txgr\t%r2,%r2\n+\txgr\t%r4,%r4\n+\txgr\t%r5,%r5\n+\tBR_EX\t%r14\n+SYM_FUNC_END(__sae64a)\n+EXPORT_SYMBOL(__sae64a)\n+#endif\n+\n /*\n * SVC interrupt handler routine. System calls are synchronous events and\n * are entered with interrupts disabled.\n@@ -315,7 +340,7 @@ SYM_CODE_START(pgm_check_handler)\n \txgr\t%r10,%r10\n \ttmhh\t%r8,0x0001\t\t# coming from user space?\n \tjo\t3f\t\t\t# -\u003e fault in user space\n-#if IS_ENABLED(CONFIG_KVM)\n+#if IS_ENABLED(CONFIG_KVM_S390)\n \tlg\t%r11,__LC_CURRENT(%r13)\n \ttm\t__TI_sie(%r11),0xff\n \tjz\t1f\n@@ -397,7 +422,7 @@ SYM_CODE_START(\\name)\n \tlmg\t%r8,%r9,\\lc_old_psw(%r13)\n \ttmhh\t%r8,0x0001\t\t\t# interrupting from user ?\n \tjnz\t1f\n-#if IS_ENABLED(CONFIG_KVM)\n+#if IS_ENABLED(CONFIG_KVM_S390)\n \tlg\t%r10,__LC_CURRENT(%r13)\n \ttm\t__TI_sie(%r10),0xff\n \tjz\t0f\n@@ -475,7 +500,7 @@ SYM_CODE_START(mcck_int_handler)\n \tjnz\t.Lmcck_user\n \tTSTMSK\t__LC_MCCK_CODE(%r13),MCCK_CODE_PSW_IA_VALID\n \tjno\t.Lmcck_panic\n-#if IS_ENABLED(CONFIG_KVM)\n+#if IS_ENABLED(CONFIG_KVM_S390)\n \tlg\t%r10,__LC_CURRENT(%r13)\n \ttm\t__TI_sie(%r10),0xff\n \tjz\t.Lmcck_user\ndiff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c\nindex 606750bae508df..6441746b8e7209 100644\n--- a/arch/s390/kernel/perf_event.c\n+++ b/arch/s390/kernel/perf_event.c\n@@ -37,7 +37,7 @@ static bool is_in_guest(struct pt_regs *regs)\n {\n \tif (user_mode(regs))\n \t\treturn false;\n-#if IS_ENABLED(CONFIG_KVM)\n+#if IS_ENABLED(CONFIG_KVM_S390)\n \treturn instruction_pointer(regs) == (unsigned long) \u0026sie_exit;\n #else\n \treturn false;\ndiff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c\nindex e33a3eccda5688..6da55a158027eb 100644\n--- a/arch/s390/kernel/processor.c\n+++ b/arch/s390/kernel/processor.c\n@@ -150,6 +150,7 @@ static void show_cpu_summary(struct seq_file *m, void *v)\n \t\t[HWCAP_NR_NNPA]\t\t= \"nnpa\",\n \t\t[HWCAP_NR_PCI_MIO]\t= \"pcimio\",\n \t\t[HWCAP_NR_SIE]\t\t= \"sie\",\n+\t\t[HWCAP_NR_SAE]\t\t= \"sae\",\n \t};\n \tint i, cpu;\n \n@@ -254,6 +255,8 @@ static int __init setup_hwcaps(void)\n \t/* virtualization support */\n \tif (sclp.has_sief2)\n \t\telf_hwcap |= HWCAP_SIE;\n+\tif (sclp.has_aef)\n+\t\telf_hwcap |= HWCAP_SAE;\n \n \treturn 0;\n }\ndiff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig\nindex 8d3ee17a1bcbcf..bbae58aa8bc467 100644\n--- a/arch/s390/kvm/Kconfig\n+++ b/arch/s390/kvm/Kconfig\n@@ -17,40 +17,9 @@ menuconfig VIRTUALIZATION\n if VIRTUALIZATION\n \n config KVM\n-\tdef_tristate y\n-\tprompt \"Kernel-based Virtual Machine (KVM) support\"\n-\tselect HAVE_KVM_CPU_RELAX_INTERCEPT\n-\tselect KVM_ASYNC_PF\n-\tselect KVM_ASYNC_PF_SYNC\n-\tselect KVM_COMMON\n-\tselect HAVE_KVM_IRQCHIP\n-\tselect HAVE_KVM_IRQ_ROUTING\n-\tselect HAVE_KVM_INVALID_WAKEUPS\n-\tselect HAVE_KVM_NO_POLL\n-\tselect KVM_VFIO\n-\tselect VIRT_XFER_TO_GUEST_WORK\n-\tselect KVM_MMU_LOCKLESS_AGING\n-\tselect KVM_GENERIC_PRE_FAULT_MEMORY\n-\thelp\n-\t Support hosting paravirtualized guest machines using the SIE\n-\t virtualization capability on the mainframe. This should work\n-\t on any 64bit machine.\n-\n-\t This module provides access to the hardware capabilities through\n-\t a character device node named /dev/kvm.\n-\n-\t To compile this as a module, choose M here: the module\n-\t will be called kvm.\n-\n-\t If unsure, say N.\n-\n-config KVM_S390_UCONTROL\n-\tbool \"Userspace controlled virtual machines\"\n-\tdepends on KVM\n-\thelp\n-\t Allow CAP_SYS_ADMIN users to create KVM virtual machines that are\n-\t controlled by userspace.\n+\ttristate\n \n-\t If unsure, say N.\n+source \"arch/s390/kvm/s390/Kconfig\"\n+source \"arch/s390/kvm/arm64/Kconfig\"\n \n endif # VIRTUALIZATION\ndiff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile\nindex dac9d53b23d8b7..38bdd7c9b42d25 100644\n--- a/arch/s390/kvm/Makefile\n+++ b/arch/s390/kvm/Makefile\n@@ -3,13 +3,5 @@\n #\n # Copyright IBM Corp. 2008\n \n-include $(srctree)/virt/kvm/Makefile.kvm\n-\n-ccflags-y := -Ivirt/kvm -Iarch/s390/kvm\n-\n-kvm-y += kvm-s390.o intercept.o interrupt.o priv.o sigp.o\n-kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o\n-kvm-y += dat.o gmap.o faultin.o\n-\n-kvm-$(CONFIG_VFIO_PCI_ZDEV_KVM) += pci.o\n-obj-$(CONFIG_KVM) += kvm.o\n+obj-$(CONFIG_KVM_S390) += s390/\n+obj-$(CONFIG_KVM_ARM64) += arm64/\ndiff --git a/arch/s390/kvm/arm64/Kconfig b/arch/s390/kvm/arm64/Kconfig\nnew file mode 100644\nindex 00000000000000..99a7fc3b71c0e1\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/Kconfig\n@@ -0,0 +1,23 @@\n+# SPDX-License-Identifier: GPL-2.0\n+\n+config KVM_ARM64\n+\tdef_tristate y\n+\tprompt \"Kernel-based Virtual Machine (KVM) support for arm64 guests\"\n+\tdepends on HAS_IOMEM\n+\tselect KVM\n+\tselect KVM_VFIO\n+\tselect IRQ_BYPASS_MANAGER\n+\tselect SCHED_INFO\n+\tselect XARRAY_MULTI\n+\tselect KVM_COMMON\n+\tselect HAVE_KVM_CPU_RELAX_INTERCEPT\n+\tselect HAVE_KVM_MSI\n+\tselect HAVE_KVM_IRQCHIP\n+\tselect HAVE_KVM_IRQ_ROUTING\n+\tselect HAVE_KVM_VCPU_RUN_PID_CHANGE\n+\tselect KVM_GENERIC_PRE_FAULT_MEMORY\n+\tselect GUEST_PERF_EVENTS if PERF_EVENTS\n+\thelp\n+\t Support hosting virtualized arm64 guest machines on s390 host machines.\n+\n+\t If unsure, say N.\ndiff --git a/arch/s390/kvm/arm64/Makefile b/arch/s390/kvm/arm64/Makefile\nnew file mode 100644\nindex 00000000000000..566040725ab57a\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/Makefile\n@@ -0,0 +1,94 @@\n+# SPDX-License-Identifier: GPL-2.0\n+\n+KVM := ../../../../virt/kvm\n+include $(srctree)/virt/kvm/Makefile.kvm\n+KVM_MANAGES_S390_GUEST = n\n+include $(srctree)/arch/s390/kvm/gmap/Makefile\n+include $(src)/Makefile.gen\n+\n+ccflags-y += -I $(src) -I $(objtree)/$(obj) -I$(srctree)/arch/s390/kvm/gmap -I$(srctree)/arch/arm64/include -I$(srctree)/arch/arm64/kvm -DKVM_S390_ARM64\n+\n+kvm-arm64-obj := \\\n+\tarm.o \\\n+\tguest.o \\\n+\thandle_exit.o \\\n+\tinject_fault.o \\\n+\tmmu.o \\\n+\tmmio.o \\\n+\treset.o \\\n+\n+kvm-arm64-obj += $(patsubst %.o,%-arm64.o,$(kvm-y))\n+\n+targets += $(kvm-arm64-obj)\n+\n+$(obj)/%-arm64.o: $(src)/%.c FORCE\n+\t@mkdir -p $(dir $@)\n+\t$(call if_changed_rule,cc_o_c)\n+\n+ifeq ($(CONFIG_KVM_ARM64),m)\n+\n+kvm-arm64-y = $(kvm-arm64-obj)\n+\n+else ifeq ($(CONFIG_KVM_ARM64),y)\n+\n+KVM_ARM64_GEN_DIR := $(objtree)/arch/${SRCARCH}/include/generated/asm\n+KVM_ARM64_MODNAME_H := $(KVM_ARM64_GEN_DIR)/kvm_arm64_modname.h\n+ccflags-y += -include $(KVM_ARM64_MODNAME_H)\n+\n+targets += $(KVM_ARM64_MODNAME_H)\n+\n+quiet_cmd_kvm_arm64_modname_h = GEN $@\n+ cmd_kvm_arm64_modname_h = { \\\n+\techo '/* Automatically generated; do not edit. */'; \\\n+\techo '\\#ifndef _KVM_ARM64_MODNAME_H'; \\\n+\techo '\\#define _KVM_ARM64_MODNAME_H'; \\\n+\techo '\\#undef KBUILD_MODNAME'; \\\n+\techo '\\#define KBUILD_MODNAME \"kvm_arm64\"'; \\\n+\techo '\\#endif /* _KVM_ARM64_MODNAME_H */'; \\\n+\t} \u003e $@\n+\n+$(addprefix $(obj)/,$(kvm-arm64-obj)): $(KVM_ARM64_MODNAME_H)\n+\n+$(KVM_ARM64_MODNAME_H):\n+\t@mkdir -p $(KVM_ARM64_GEN_DIR)\n+\t$(call cmd,kvm_arm64_modname_h)\n+\n+prereq-o-cmd = $(foreach o, $(filter %.o, $^), $(dir $(o)).$(notdir $(o)).cmd)\n+cmd_gen_symversions_o = \\\n+\tgrep --no-filename \"^\\#SYMVER\" $(prereq-o-cmd) \u003e\u003e $(dot-target).cmd || true\n+\n+define rule_ld_o_o\n+\t$(call cmd_and_savecmd,ld)\n+\t$(call cmd,gen_symversions_o)\n+endef\n+\n+LDFLAGS_kvm-unnamespaced.o := -r --whole-archive\n+$(obj)/kvm-unnamespaced.o: $(addprefix $(obj)/,$(kvm-arm64-obj)) FORCE\n+\t$(call if_changed_rule,ld_o_o)\n+\n+# Make list of symbols to localize.\n+# Collect normal/exported symbols. Use dict as set for deduplication.\n+# TODO extract do script\n+quiet_cmd_nm_filter = NMFLTR $@\n+\tcmd_nm_filter = $(NM) -jU $\u003c | sort -u \u003e $@\n+\n+$(obj)/kvm_symbol_list: $(obj)/kvm-unnamespaced.o FORCE\n+\t$(call if_changed,nm_filter)\n+\n+define rule_oc_o_o\n+\t$(call cmd_and_savecmd,objcopy)\n+\t$(call cmd,gen_objtooldep)\n+\t$(call cmd,gen_symversions_o)\n+endef\n+\n+OBJCOPYFLAGS_kvm-namespaced.o := -O default --localize-symbols=$(obj)/kvm_symbol_list\n+$(obj)/kvm-namespaced.o: $(obj)/kvm-unnamespaced.o $(obj)/kvm_symbol_list FORCE\n+\t$(call if_changed_rule,oc_o_o)\n+\n+kvm-arm64-y = kvm-namespaced.o\n+\n+targets += kvm-unnamespaced.o kvm_symbol_list kvm-namespaced.o\n+\n+endif\n+\n+obj-$(CONFIG_KVM_ARM64) += kvm-arm64.o\ndiff --git a/arch/s390/kvm/arm64/Makefile.gen b/arch/s390/kvm/arm64/Makefile.gen\nnew file mode 100644\nindex 00000000000000..2e8838bc69214c\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/Makefile.gen\n@@ -0,0 +1,30 @@\n+# SPDX-License-Identifier: GPL-2.0\n+#\n+# Extracts ARM64 marked sections to .inc files that are included by main source\n+# files\n+\n+# List of ARM64 C files to extract\n+ARM64_CFILES := \\\n+\tarm.c \\\n+\tguest.c \\\n+\treset.c \\\n+\thandle_exit.c \\\n+\tmmio.c \\\n+\n+quiet_cmd_extract_inc = GEN $@\n+ cmd_extract_inc = mkdir -p $(dir $@); \\\n+ $(AWK) -f $(src)/copy-arm64c.awk $\u003c \u003e $@ || \\\n+ { echo \"Error: No ARM64_S390_COMMON markers in $\u003c\" \u003e\u00262; rm -f $@; exit 1; }\n+\n+$(obj)/generated/%.inc: $(srctree)/arch/arm64/kvm/%.c $(src)/copy-arm64c.awk FORCE\n+\t$(call if_changed,extract_inc)\n+\n+ARM64_INC_FILES := $(foreach cfile,$(ARM64_CFILES),generated/$(basename $(cfile)).inc)\n+\n+targets += $(ARM64_INC_FILES)\n+clean-files += generated/*.inc\n+\n+$(addprefix $(obj)/,$(kvm-arm64-obj)): $(addprefix $(obj)/,$(ARM64_INC_FILES))\n+\n+$(foreach cfile,$(basename $(ARM64_CFILES)),\\\n+\t$(eval $(obj)/$(cfile).o: $(obj)/generated/$(cfile).inc))\ndiff --git a/arch/s390/kvm/arm64/arm.c b/arch/s390/kvm/arm64/arm.c\nnew file mode 100644\nindex 00000000000000..6ef47f7010bedc\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/arm.c\n@@ -0,0 +1,726 @@\n+// SPDX-License-Identifier: GPL-2.0\n+\n+#define KMSG_COMPONENT \"kvm-s390-arm64\"\n+#define pr_fmt(fmt) KMSG_COMPONENT \": \" fmt\n+\n+#include \u003clinux/miscdevice.h\u003e\n+#include \u003clinux/kvm.h\u003e\n+#include \u003clinux/kvm_types.h\u003e\n+#include \u003clinux/kvm_host.h\u003e\n+#include \u003clinux/fpu.h\u003e\n+\n+#include \u003casm/access-regs.h\u003e\n+\n+#include \u003carm64/kvm_emulate.h\u003e\n+#include \u003carm64/kvm_mmu.h\u003e\n+#include \u003carm64/sysreg.h\u003e\n+\n+#include \u003cgmap.h\u003e\n+\n+#include \"arm.h\"\n+#include \"guest.h\"\n+#include \"handle_exit.h\"\n+#include \"reset.h\"\n+\n+static unsigned long system_supported_vcpu_features(void);\n+\n+#define __INCL_GEN_ARM_FILE\n+#include \"generated/arm.inc\"\n+#undef __INCL_GEN_ARM_FILE\n+\n+int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)\n+{\n+\tint ret;\n+\n+\tswitch (ext) {\n+\tcase KVM_CAP_NR_VCPUS:\n+\tcase KVM_CAP_MAX_VCPUS:\n+\tcase KVM_CAP_MAX_VCPU_ID:\n+\t\tret = KVM_MAX_VCPUS;\n+\t\tbreak;\n+\tcase KVM_CAP_ARM_VM_IPA_SIZE:\n+\t\tret = get_kvm_ipa_limit();\n+\t\tbreak;\n+\tcase KVM_CAP_IOEVENTFD:\n+\tcase KVM_CAP_ARM_USER_IRQ:\n+\tcase KVM_CAP_PRE_FAULT_MEMORY:\n+\t\tret = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\tret = 0;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static u64 kvm_max_guest_address(void)\n+{\n+\tu64 max_addr;\n+\n+\tif (sclp.hamax == U64_MAX)\n+\t\tmax_addr = TASK_SIZE_MAX;\n+\telse\n+\t\tmax_addr = min_t(u64, TASK_SIZE_MAX, sclp.hamax);\n+\treturn ALIGN_DOWN(max_addr + 1, 1 \u003c\u003c 30) - 1;\n+}\n+\n+static int kvm_gmap_init(struct kvm *kvm)\n+{\n+\tstruct crst_table *table;\n+\n+\tkvm-\u003earch.gmap = gmap_new(kvm, gpa_to_gfn(kvm-\u003earch.guest_phys_size));\n+\n+\tif (!kvm-\u003earch.gmap)\n+\t\treturn -ENOMEM;\n+\n+\t/* arm64 (on s390) do not have pfault */\n+\tclear_bit(GMAP_FLAG_PFAULT_ENABLED, \u0026kvm-\u003earch.gmap-\u003eflags);\n+\tset_bit(GMAP_FLAG_ALLOW_HPAGE_1M, \u0026kvm-\u003earch.gmap-\u003eflags);\n+\n+\ttable = dereference_asce(kvm-\u003earch.gmap-\u003easce);\n+\tcrst_table_init((void *)table, _CRSTE_HOLE(table-\u003ecrstes[0].h.tt).val);\n+\n+\treturn 0;\n+}\n+\n+static int kvm_vm_type_ipa_size_shift(unsigned long type)\n+{\n+\tint phys_shift;\n+\n+\tphys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type);\n+\tif (phys_shift) {\n+\t\tif (phys_shift \u003e get_kvm_ipa_limit() ||\n+\t\t phys_shift \u003c ARM64_MIN_PARANGE_BITS)\n+\t\t\treturn -EINVAL;\n+\t} else {\n+\t\tphys_shift = KVM_PHYS_SHIFT;\n+\t\tif (phys_shift \u003e get_kvm_ipa_limit()) {\n+\t\t\tpr_warn_once(\"%s using unsupported default IPA limit\\n\",\n+\t\t\t\t current-\u003ecomm);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\treturn phys_shift;\n+}\n+\n+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)\n+{\n+\tchar debug_name[32];\n+\tint ret;\n+\n+\tif (type \u0026 ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)\n+\t\treturn -EINVAL;\n+\n+\tret = kvm_vm_type_ipa_size_shift(type);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\tkvm-\u003earch.guest_phys_size = 1UL \u003c\u003c ret;\n+\n+\tmutex_init(\u0026kvm-\u003earch.config_lock);\n+\tbitmap_zero(kvm-\u003earch.vcpu_features, KVM_VCPU_MAX_FEATURES);\n+\n+\tsnprintf(debug_name, sizeof(debug_name), \"kvm-arm64-%u\", current-\u003epid);\n+\tkvm-\u003earch.dbf = debug_register(debug_name, 32, 1, 7 * sizeof(long));\n+\tif (!kvm-\u003earch.dbf)\n+\t\treturn -ENOMEM;\n+\tdebug_register_view(kvm-\u003earch.dbf, \u0026debug_sprintf_view);\n+\n+\tret = kvm_gmap_init(kvm);\n+\tif (ret)\n+\t\tgoto out_err;\n+\tkvm-\u003earch.mem_limit = kvm_max_guest_address();\n+\n+\tVM_EVENT(kvm, 3, \"vm created with type %lu\", type);\n+\treturn 0;\n+\n+out_err:\n+\tdebug_unregister(kvm-\u003earch.dbf);\n+\n+\treturn ret;\n+}\n+\n+vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)\n+{\n+\treturn VM_FAULT_SIGBUS;\n+}\n+\n+long kvm_arch_dev_ioctl(struct file *filp,\n+\t\t\tunsigned int ioctl, unsigned long arg)\n+{\n+\treturn -EINVAL;\n+}\n+\n+void kvm_arch_destroy_vm(struct kvm *kvm)\n+{\n+\tkvm_destroy_vcpus(kvm);\n+\tdebug_unregister(kvm-\u003earch.dbf);\n+\tkvm-\u003earch.gmap = gmap_put(kvm-\u003earch.gmap);\n+}\n+\n+u32 get_kvm_ipa_limit(void)\n+{\n+\treturn fls64(kvm_max_guest_address() + 1) - 1;\n+}\n+\n+int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)\n+{\n+\treturn 0;\n+}\n+\n+int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)\n+{\n+\tstruct kvm_sae_block *sae_block = \u0026vcpu-\u003earch.sae_block;\n+\n+\tspin_lock_init(\u0026vcpu-\u003earch.mp_state_lock);\n+\n+\t/* Force users to call KVM_ARM_VCPU_INIT */\n+\tvcpu_clear_flag(vcpu, VCPU_INITIALIZED);\n+\n+\tvcpu-\u003earch.mc = kvm_s390_new_mmu_cache();\n+\tif (!vcpu-\u003earch.mc)\n+\t\treturn -ENOMEM;\n+\n+\tsae_block-\u003ehbasce = vcpu-\u003ekvm-\u003earch.gmap-\u003easce.val;\n+\tsae_block-\u003emso = 0L;\n+\tsae_block-\u003emsl = kvm_max_guest_address();\n+\n+\tVM_EVENT(vcpu-\u003ekvm, 3, \"create cpu %d at 0x%p, sae block at 0x%p, satellite at 0x%p\",\n+\t\t vcpu-\u003evcpu_id, vcpu, \u0026vcpu-\u003earch.sae_block, \u0026vcpu-\u003earch.save_area);\n+\treturn 0;\n+}\n+\n+void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)\n+{\n+}\n+\n+void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)\n+{\n+\tkvm_s390_free_mmu_cache(vcpu-\u003earch.mc);\n+\n+\tVCPU_EVENT(vcpu, 3, \"%s\", \"free cpu\");\n+}\n+\n+void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)\n+{\n+}\n+\n+void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu)\n+{\n+}\n+\n+void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)\n+{\n+\tsave_access_regs(\u0026vcpu-\u003earch.host_acrs[0]);\n+\tvcpu-\u003ecpu = cpu;\n+\n+\tlasrm(\u0026vcpu-\u003earch.save_area);\n+}\n+\n+void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)\n+{\n+\tstiasrm(\u0026vcpu-\u003earch.save_area);\n+\n+\tvcpu-\u003ecpu = -1;\n+\trestore_access_regs(\u0026vcpu-\u003earch.host_acrs[0]);\n+}\n+\n+int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,\n+\t\t\t\t struct kvm_mp_state *mp_state)\n+{\n+\t*mp_state = READ_ONCE(vcpu-\u003earch.mp_state);\n+\treturn 0;\n+}\n+\n+int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,\n+\t\t\t\t struct kvm_mp_state *mp_state)\n+{\n+\treturn -EINVAL;\n+}\n+\n+int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)\n+{\n+\treturn 0;\n+}\n+\n+static unsigned long system_supported_vcpu_features(void)\n+{\n+\treturn KVM_VCPU_VALID_FEATURES;\n+}\n+\n+bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)\n+{\n+\treturn vcpu_mode_priv(vcpu);\n+}\n+\n+int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)\n+{\n+\tstruct kvm *kvm = vcpu-\u003ekvm;\n+\n+\tif (!kvm_vcpu_initialized(vcpu))\n+\t\treturn -ENOEXEC;\n+\n+\tif (!kvm_arm_vcpu_is_finalized(vcpu))\n+\t\treturn -EPERM;\n+\n+\tif (likely(READ_ONCE(vcpu-\u003epid)))\n+\t\treturn 0;\n+\n+\tmutex_lock(\u0026kvm-\u003earch.config_lock);\n+\tset_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, \u0026kvm-\u003earch.flags);\n+\tmutex_unlock(\u0026kvm-\u003earch.config_lock);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * check_vcpu_requests - check and handle pending vCPU requests\n+ * @vcpu:\tthe VCPU pointer\n+ *\n+ * Return: 1 if we should enter the guest\n+ *\t 0 if we should exit to userspace\n+ *\t \u003c 0 if we should exit to userspace, where the return value indicates\n+ *\t an error\n+ */\n+static int check_vcpu_requests(struct kvm_vcpu *vcpu)\n+{\n+\tif (kvm_request_pending(vcpu)) {\n+\t\tif (kvm_check_request(KVM_REQ_VCPU_RESET, vcpu))\n+\t\t\tkvm_reset_vcpu(vcpu);\n+\t\t/*\n+\t\t * Clear IRQ_PENDING requests that were made to guarantee\n+\t\t * that a VCPU sees new virtual interrupts.\n+\t\t */\n+\t\tkvm_check_request(KVM_REQ_IRQ_PENDING, vcpu);\n+\t}\n+\n+\treturn 1;\n+}\n+\n+static int kvm_vcpu_initialize(struct kvm_vcpu *vcpu,\n+\t\t\t const struct kvm_vcpu_init *init)\n+{\n+\tunsigned long features = init-\u003efeatures[0];\n+\tstruct kvm *kvm = vcpu-\u003ekvm;\n+\tint ret = -EINVAL;\n+\n+\tmutex_lock(\u0026kvm-\u003earch.config_lock);\n+\n+\tif (test_bit(KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED, \u0026kvm-\u003earch.flags) \u0026\u0026\n+\t kvm_vcpu_init_changed(vcpu, init))\n+\t\tgoto out_unlock;\n+\n+\tbitmap_copy(kvm-\u003earch.vcpu_features, \u0026features, KVM_VCPU_MAX_FEATURES);\n+\n+\tkvm_reset_vcpu(vcpu);\n+\n+\tset_bit(KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED, \u0026kvm-\u003earch.flags);\n+\tvcpu_set_flag(vcpu, VCPU_INITIALIZED);\n+\n+\tret = 0;\n+out_unlock:\n+\tmutex_unlock(\u0026kvm-\u003earch.config_lock);\n+\treturn ret;\n+}\n+\n+static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,\n+\t\t\t const struct kvm_vcpu_init *init)\n+{\n+\tint ret;\n+\n+\tif (init-\u003etarget != KVM_ARM_TARGET_GENERIC_V8)\n+\t\treturn -EINVAL;\n+\n+\tret = kvm_vcpu_init_check_features(vcpu, init);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (!kvm_vcpu_initialized(vcpu))\n+\t\treturn kvm_vcpu_initialize(vcpu, init);\n+\n+\tif (kvm_vcpu_init_changed(vcpu, init))\n+\t\treturn -EINVAL;\n+\n+\tkvm_reset_vcpu(vcpu);\n+\n+\treturn 0;\n+}\n+\n+static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu,\n+\t\t\t\t\t struct kvm_vcpu_init *init)\n+{\n+\tstruct kvm_sae_save_area *save_area = \u0026vcpu-\u003earch.save_area;\n+\tstruct kvm_sae_block *sae_block = \u0026vcpu-\u003earch.sae_block;\n+\tint ret;\n+\n+\tsae_block-\u003esave_area = virt_to_phys(save_area);\n+\tsave_area-\u003esdo = virt_to_phys(sae_block);\n+\n+\tret = kvm_vcpu_set_target(vcpu, init);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tspin_lock(\u0026vcpu-\u003earch.mp_state_lock);\n+\tWRITE_ONCE(vcpu-\u003earch.mp_state.mp_state, KVM_MP_STATE_RUNNABLE);\n+\tspin_unlock(\u0026vcpu-\u003earch.mp_state_lock);\n+\n+\treturn 0;\n+}\n+\n+int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,\n+\t\t\t bool line_status)\n+{\n+\treturn 0;\n+}\n+\n+static void adjust_pc(struct kvm_vcpu *vcpu)\n+{\n+\tif (vcpu_get_flag(vcpu, INCREMENT_PC)) {\n+\t\tkvm_skip_instr(vcpu);\n+\t\tvcpu_clear_flag(vcpu, INCREMENT_PC);\n+\t}\n+}\n+\n+static void arm_vcpu_run(struct kvm_vcpu *vcpu)\n+{\n+\tstruct kvm_sae_block *sae_block = \u0026vcpu-\u003earch.sae_block;\n+\n+\tadjust_pc(vcpu);\n+\n+\tlocal_irq_disable();\n+\tguest_enter_irqoff();\n+\tlocal_irq_enable();\n+\n+\tsae_block-\u003eicptr = 0;\n+\n+\tsae64a(sae_block);\n+\n+\tlocal_irq_disable();\n+\tguest_exit_irqoff();\n+\tlocal_irq_enable();\n+}\n+\n+/** kvm_arch_vcpu_ioctl_run() - run arm64 vCPU\n+ *\n+ * Execute arm64 guest instructions using SAE.\n+ *\n+ * Returns:\n+ * 1 enter the guest (should not be observed by userspace)\n+ * 0 exit to userspace\n+ * \u003c 0 exit to userspace, where the return value indicates n error\n+ *\n+ *\n+ */\n+int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)\n+{\n+\tDECLARE_KERNEL_FPU_ONSTACK32(fpu_save);\n+\tstruct kvm_run *kvm_run = vcpu-\u003erun;\n+\tint ret;\n+\n+\tif (kvm_run-\u003eexit_reason == KVM_EXIT_MMIO) {\n+\t\tret = kvm_handle_mmio_return(vcpu);\n+\t\tif (ret \u003c= 0)\n+\t\t\treturn ret;\n+\t}\n+\n+\tvcpu_load(vcpu);\n+\n+\tkernel_fpu_begin(\u0026fpu_save, KERNEL_FPC | KERNEL_VXR);\n+\tload_vx_regs((vcpu-\u003earch.ctxt.vregs));\n+\n+\tif (!vcpu-\u003ewants_to_run) {\n+\t\tret = -EINTR;\n+\t\tgoto out;\n+\t}\n+\n+\tkvm_sigset_activate(vcpu);\n+\n+\tmight_fault();\n+\n+\tret = 1;\n+\tdo {\n+\t\tif (signal_pending(current)) {\n+\t\t\tkvm_run-\u003eexit_reason = KVM_EXIT_INTR;\n+\t\t\tret = -EINTR;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (need_resched())\n+\t\t\tschedule();\n+\n+\t\tif (ret \u003e 0)\n+\t\t\tret = check_vcpu_requests(vcpu);\n+\n+\t\tvcpu-\u003earch.sae_block.icptr = 0;\n+\n+\t\tarm_vcpu_run(vcpu);\n+\n+\t\tret = handle_exit(vcpu);\n+\n+\t} while (ret \u003e 0);\n+\n+\tkvm_sigset_deactivate(vcpu);\n+out:\n+\tif (unlikely(vcpu_get_flag(vcpu, INCREMENT_PC)))\n+\t\tadjust_pc(vcpu);\n+\n+\tsave_vx_regs(vcpu-\u003earch.ctxt.vregs);\n+\tkernel_fpu_end(\u0026fpu_save, KERNEL_FPC | KERNEL_VXR);\n+\tvcpu_put(vcpu);\n+\n+\treturn ret;\n+}\n+\n+long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)\n+{\n+\tstruct kvm_vcpu *vcpu = filp-\u003eprivate_data;\n+\tvoid __user *argp = (void __user *)arg;\n+\tstruct kvm_device_attr attr;\n+\tint ret;\n+\n+\tswitch (ioctl) {\n+\tcase KVM_ARM_VCPU_INIT: {\n+\t\tstruct kvm_vcpu_init init;\n+\n+\t\tret = -EFAULT;\n+\t\tif (copy_from_user(\u0026init, argp, sizeof(init)))\n+\t\t\tbreak;\n+\n+\t\tret = kvm_arch_vcpu_ioctl_vcpu_init(vcpu, \u0026init);\n+\t\tbreak;\n+\t}\n+\tcase KVM_SET_ONE_REG:\n+\tcase KVM_GET_ONE_REG: {\n+\t\tstruct kvm_one_reg reg;\n+\n+\t\tret = -ENOEXEC;\n+\t\tif (unlikely(!kvm_vcpu_initialized(vcpu)))\n+\t\t\tbreak;\n+\n+\t\tret = -EFAULT;\n+\t\tif (copy_from_user(\u0026reg, argp, sizeof(reg)))\n+\t\t\tbreak;\n+\n+\t\tif (kvm_check_request(KVM_REQ_VCPU_RESET, vcpu))\n+\t\t\tkvm_reset_vcpu(vcpu);\n+\n+\t\tif (ioctl == KVM_SET_ONE_REG)\n+\t\t\tret = kvm_arm_set_reg(vcpu, \u0026reg);\n+\t\telse\n+\t\t\tret = kvm_arm_get_reg(vcpu, \u0026reg);\n+\t\tbreak;\n+\t}\n+\tcase KVM_GET_REG_LIST: {\n+\t\tstruct kvm_reg_list __user *user_list = argp;\n+\t\tstruct kvm_reg_list reg_list;\n+\t\tunsigned int n;\n+\n+\t\tret = -ENOEXEC;\n+\t\tif (unlikely(!kvm_vcpu_initialized(vcpu)))\n+\t\t\tbreak;\n+\t\tret = -EPERM;\n+\t\tif (!kvm_arm_vcpu_is_finalized(vcpu))\n+\t\t\tbreak;\n+\t\tret = -EFAULT;\n+\t\tif (copy_from_user(\u0026reg_list, user_list, sizeof(reg_list)))\n+\t\t\tbreak;\n+\t\tn = reg_list.n;\n+\t\treg_list.n = kvm_arm_num_regs(vcpu);\n+\t\tif (copy_to_user(user_list, \u0026reg_list, sizeof(reg_list)))\n+\t\t\tbreak;\n+\t\tret = -E2BIG;\n+\t\tif (n \u003c reg_list.n)\n+\t\t\tbreak;\n+\t\tret = kvm_arm_copy_reg_indices(vcpu, user_list-\u003ereg);\n+\t\tbreak;\n+\t}\n+\tcase KVM_ARM_VCPU_FINALIZE: {\n+\t\tint what;\n+\n+\t\tif (!kvm_vcpu_initialized(vcpu))\n+\t\t\treturn -ENOEXEC;\n+\n+\t\tif (get_user(what, (const int __user *)argp))\n+\t\t\treturn -EFAULT;\n+\n+\t\tret = kvm_arm_vcpu_finalize(vcpu, what);\n+\t\tbreak;\n+\t}\n+\tcase KVM_SET_DEVICE_ATTR: {\n+\t\tret = -EFAULT;\n+\t\tif (copy_from_user(\u0026attr, argp, sizeof(attr)))\n+\t\t\tbreak;\n+\t\tret = kvm_arm_vcpu_set_attr(vcpu, \u0026attr);\n+\t\tbreak;\n+\t}\n+\tcase KVM_GET_DEVICE_ATTR: {\n+\t\tret = -EFAULT;\n+\t\tif (copy_from_user(\u0026attr, argp, sizeof(attr)))\n+\t\t\tbreak;\n+\t\tret = kvm_arm_vcpu_get_attr(vcpu, \u0026attr);\n+\t\tbreak;\n+\t}\n+\tcase KVM_HAS_DEVICE_ATTR: {\n+\t\tret = -EFAULT;\n+\t\tif (copy_from_user(\u0026attr, argp, sizeof(attr)))\n+\t\t\tbreak;\n+\t\tret = kvm_arm_vcpu_has_attr(vcpu, \u0026attr);\n+\t\tbreak;\n+\t}\n+\tdefault:\n+\t\tret = -EINVAL;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,\n+\t\t\t struct kvm_dirty_log *log)\n+{\n+\treturn gmap_get_dirty_log(kvm, log);\n+}\n+\n+bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)\n+{\n+\tscoped_guard(read_lock, \u0026kvm-\u003emmu_lock)\n+\t\treturn gmap_age_gfn(kvm-\u003earch.gmap, range-\u003estart, range-\u003eend);\n+}\n+\n+void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)\n+{\n+\tgfn_t last_gfn = memslot-\u003ebase_gfn + memslot-\u003enpages;\n+\n+\tscoped_guard(read_lock, \u0026kvm-\u003emmu_lock)\n+\t\tgmap_sync_dirty_log(kvm-\u003earch.gmap, memslot-\u003ebase_gfn, last_gfn);\n+}\n+\n+int kvm_arch_prepare_memory_region(struct kvm *kvm,\n+\t\t\t\t const struct kvm_memory_slot *old,\n+\t\t\t\t struct kvm_memory_slot *new,\n+\t\t\t\t enum kvm_mr_change change)\n+{\n+\treturn gmap_prepare_memory_region(kvm, old, new, change);\n+}\n+\n+void kvm_arch_commit_memory_region(struct kvm *kvm,\n+\t\t\t\t struct kvm_memory_slot *old,\n+\t\t\t\t const struct kvm_memory_slot *new,\n+\t\t\t\t enum kvm_mr_change change)\n+{\n+\tgmap_commit_memory_region(kvm, old, new, change);\n+}\n+\n+bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)\n+{\n+\treturn gmap_unmap_gfn_range(kvm-\u003earch.gmap, range-\u003eslot, range-\u003estart, range-\u003eend);\n+}\n+\n+bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)\n+{\n+\treturn gmap_test_age_gfn(kvm, range);\n+}\n+\n+long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\n+\t\t\t\t struct kvm_pre_fault_memory *range)\n+{\n+\treturn gmap_pre_fault_memory(vcpu, range);\n+}\n+\n+void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,\n+\t\t\t\t\t struct kvm_memory_slot *slot,\n+\t\t\t\t\t gfn_t gfn_offset,\n+\t\t\t\t\t unsigned long mask)\n+{\n+}\n+\n+int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)\n+{\n+\tvoid __user *argp = (void __user *)arg;\n+\n+\tswitch (ioctl) {\n+\tcase KVM_ARM_PREFERRED_TARGET: {\n+\t\tstruct kvm_vcpu_init init = {\n+\t\t\t.target = KVM_ARM_TARGET_GENERIC_V8,\n+\t\t};\n+\n+\t\tif (copy_to_user(argp, \u0026init, sizeof(init)))\n+\t\t\treturn -EFAULT;\n+\n+\t\treturn 0;\n+\t}\n+\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+}\n+\n+bool kvm_arch_irqchip_in_kernel(struct kvm *kvm)\n+{\n+\treturn false;\n+}\n+\n+void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)\n+{\n+}\n+\n+void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen)\n+{\n+}\n+\n+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,\n+\t\tstruct kvm *kvm, int irq_source_id,\n+\t\tint level, bool line_status)\n+{\n+\treturn -EINVAL;\n+}\n+\n+int kvm_set_routing_entry(struct kvm *kvm,\n+\t\t\t struct kvm_kernel_irq_routing_entry *e,\n+\t\t\t const struct kvm_irq_routing_entry *ue)\n+{\n+\treturn -EINVAL;\n+}\n+\n+void kvm_arch_flush_shadow_memslot(struct kvm *kvm,\n+\t\t\t\t struct kvm_memory_slot *slot)\n+{\n+}\n+\n+void kvm_arch_flush_shadow_all(struct kvm *kvm)\n+{\n+}\n+\n+int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)\n+{\n+\treturn 0;\n+}\n+\n+#ifdef CONFIG_HAVE_KVM_NO_POLL\n+__weak bool kvm_arch_no_poll(struct kvm_vcpu *vcpu)\n+{\n+\treturn false;\n+}\n+#endif\n+\n+long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,\n+\t\t\t\t unsigned long arg)\n+{\n+\treturn -ENOIOCTLCMD;\n+}\n+\n+static int __init kvm_s390_arm64_init(void)\n+{\n+\tif (!sclp.has_aef)\n+\t\treturn -ENXIO;\n+\n+\treturn kvm_init_with_dev(sizeof(struct kvm_vcpu), 0, THIS_MODULE,\n+\t\t\t\t KVM_DEV_NAME, MISC_DYNAMIC_MINOR);\n+}\n+\n+static __exit void kvm_s390_arm64_exit(void)\n+{\n+\tkvm_exit();\n+}\n+\n+module_init(kvm_s390_arm64_init);\n+module_exit(kvm_s390_arm64_exit);\ndiff --git a/arch/s390/kvm/arm64/arm.h b/arch/s390/kvm/arm64/arm.h\nnew file mode 100644\nindex 00000000000000..244c2b7a136f0d\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/arm.h\n@@ -0,0 +1,63 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#ifndef ARCH_S390_KVM_ARM64_H\n+#define ARCH_S390_KVM_ARM64_H\n+\n+#include \u003clinux/kvm_host.h\u003e\n+\n+#define KVM_DEV_NAME \"kvm-arm64\"\n+\n+#define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\\\n+do { \\\n+\tdebug_sprintf_event((d_kvm)-\u003earch.dbf, d_loglevel, KVM_DEV_NAME \": \" d_string \"\\n\", d_args); \\\n+} while (0)\n+\n+#define VCPU_EVENT(d_vcpu, d_loglevel, d_string, d_args...)\t\t\t\\\n+\tdo {\t\t\t\t\t\t\t\t\t\\\n+\t\tdebug_sprintf_event(\t\t\t\t\t\t\\\n+\t\t\t(d_vcpu)-\u003ekvm-\u003earch.dbf, d_loglevel,\t\t\t\\\n+\t\t\tKVM_DEV_NAME \" %02d[%016llx-%016llx]: \" d_string \"\\n\",\t\\\n+\t\t\t(d_vcpu)-\u003evcpu_id, (d_vcpu)-\u003earch.sae_block.pstate,\t\\\n+\t\t\t(d_vcpu)-\u003earch.sae_block.pc, d_args);\t\t\t\\\n+\t} while (0)\n+\n+static __always_inline bool kvm_s390_is_in_sie(struct kvm_vcpu *vcpu)\n+{\n+\treturn false;\n+}\n+\n+static __always_inline int kvm_is_ucontrol(struct kvm *kvm)\n+{\n+\treturn 0;\n+}\n+\n+static __always_inline int __kvm_s390_pv_destroy_page(struct page *page)\n+{\n+\treturn 0;\n+}\n+\n+static __always_inline void kvm_s390_vsie_gmap_notifier(struct gmap *gmap, gpa_t start, gpa_t end)\n+{\n+}\n+\n+static __always_inline int kvm_s390_pv_get_handle(struct kvm *kvm)\n+{\n+\treturn 0;\n+}\n+\n+static __always_inline int kvm_s390_is_migration_mode(struct kvm *kvm)\n+{\n+\treturn false;\n+}\n+\n+static __always_inline bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu)\n+{\n+\treturn false;\n+}\n+\n+/* should never be called */\n+static __always_inline int kvm_s390_vm_stop_migration(struct kvm *kvm)\n+{\n+\treturn -EINVAL;\n+}\n+\n+#endif /* ARCH_S390_KVM_ARM64_H */\ndiff --git a/arch/s390/kvm/arm64/copy-arm64c.awk b/arch/s390/kvm/arm64/copy-arm64c.awk\nnew file mode 100644\nindex 00000000000000..45d9c7034c177d\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/copy-arm64c.awk\n@@ -0,0 +1,69 @@\n+#!/usr/bin/awk -f\n+# SPDX-License-Identifier: GPL-2.0\n+#\n+# Extract marked sections from ARM64 C files for sharing with s390 KVM\n+#\n+# Usage: share-arm64-cfile.awk \u003cinput_file\u003e\n+#\n+# Extracts all sections between start/end markers. If no markers found, signals failure.\n+\n+BEGIN {\n+\t# Constants\n+\tstart_pattern = \"^#ifdef ARM64_S390_COMMON$\"\n+\tend_pattern = \"^#endif /\\\\* ARM64_S390_COMMON \\\\*/$\"\n+\n+\t# State variables\n+\tcopying = found_marker = 0\n+\tfile_header_done = 0\n+}\n+\n+!file_header_done {\n+\tif (/^\\/\\*/ || /^\\/\\/ SPDX-License-Identifier:/) {\n+\t\tprint\n+\t\tnext\n+\t}\n+\tif (/[[:space:]]\\*([[:space:]]|$)/) {\n+\t\tprint\n+\t\tnext\n+\t}\n+\tif (/\\*\\//) {\n+\t\tprint \" *\"\n+\t} else {\n+\t\tprint \"/*\"\n+\t}\n+\n+\tfilename = FILENAME\n+\tsub(/^.*arch\\/arm64\\//, \"arch/arm64/\", filename)\n+\tprint \" * This file was automatically generated from \" filename\n+\tprint \" * Do not modify this file directly.\"\n+\tprint \" */\"\n+\tprint \"\"\n+\tprint \"#ifndef __INCL_GEN_ARM_FILE\"\n+\tprint \"#error included .inc file w/o proper guard definition\"\n+\tprint \"#undef __INCL_GEN_ARM_FILE\"\n+\tprint \"#endif /* __INCL_GEN_ARM_FILE */\"\n+\tprint \"\"\n+\n+\tfile_header_done = 1\n+}\n+\n+$0 ~ start_pattern {\n+\tcopying = found_marker = 1\n+\tnext\n+}\n+\n+$0 ~ end_pattern {\n+\tcopying = 0\n+\tnext\n+}\n+\n+copying {\n+\tgsub(/#include \u003casm\\//, \"#include \u003carm64/\")\n+\tgsub(/#include \u003cuapi\\/asm\\//, \"#include \u003cuapi/arm64/\")\n+\tprint\n+\tnext\n+}\n+\n+END {\n+\texit !found_marker\n+}\ndiff --git a/arch/s390/kvm/arm64/guest.c b/arch/s390/kvm/arm64/guest.c\nnew file mode 100644\nindex 00000000000000..1197c91e6324ad\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/guest.c\n@@ -0,0 +1,169 @@\n+// SPDX-License-Identifier: GPL-2.0\n+#include \u003clinux/kvm_host.h\u003e\n+#include \u003clinux/kvm.h\u003e\n+\n+#include \u003carm64/kvm_emulate.h\u003e\n+#include \u003carm64/kvm_nested.h\u003e\n+\n+#include \"guest.h\"\n+\n+#define __INCL_GEN_ARM_FILE\n+#include \"generated/guest.inc\"\n+#undef __INCL_GEN_ARM_FILE\n+\n+const struct kvm_stats_desc kvm_vm_stats_desc[] = {\n+\tKVM_GENERIC_VM_STATS()\n+};\n+\n+const struct kvm_stats_header kvm_vm_stats_header = {\n+\t.name_size = KVM_STATS_NAME_SIZE,\n+\t.num_desc = ARRAY_SIZE(kvm_vm_stats_desc),\n+\t.id_offset = sizeof(struct kvm_stats_header),\n+\t.desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,\n+\t.data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +\n+\t\t sizeof(kvm_vm_stats_desc),\n+};\n+\n+const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {\n+\tKVM_GENERIC_VCPU_STATS(),\n+\t/* ARM64 stats */\n+\tSTATS_DESC_COUNTER(VCPU, hvc_exit_stat),\n+\tSTATS_DESC_COUNTER(VCPU, wfe_exit_stat),\n+\tSTATS_DESC_COUNTER(VCPU, wfi_exit_stat),\n+\tSTATS_DESC_COUNTER(VCPU, mmio_exit_user),\n+\tSTATS_DESC_COUNTER(VCPU, mmio_exit_kernel),\n+\tSTATS_DESC_COUNTER(VCPU, signal_exits),\n+\tSTATS_DESC_COUNTER(VCPU, exits),\n+\t/* GMAP stats */\n+\tSTATS_DESC_COUNTER(VCPU, pfault_sync),\n+};\n+\n+const struct kvm_stats_header kvm_vcpu_stats_header = {\n+\t.name_size = KVM_STATS_NAME_SIZE,\n+\t.num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc),\n+\t.id_offset = sizeof(struct kvm_stats_header),\n+\t.desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,\n+\t.data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +\n+\t\t sizeof(kvm_vcpu_stats_desc),\n+};\n+\n+int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)\n+{\n+\treturn copy_core_reg_indices(vcpu, uindices);\n+}\n+\n+unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)\n+{\n+\treturn num_core_regs(vcpu);\n+}\n+\n+int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)\n+{\n+\t/* We currently use nothing arch-specific in upper 32 bits */\n+\tif ((reg-\u003eid \u0026 ~KVM_REG_SIZE_MASK) \u003e\u003e 32 != KVM_REG_ARM64 \u003e\u003e 32)\n+\t\treturn -EINVAL;\n+\n+\tswitch (reg-\u003eid \u0026 KVM_REG_ARM_COPROC_MASK) {\n+\tcase KVM_REG_ARM_CORE:\n+\t\treturn get_core_reg(vcpu, reg);\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+}\n+\n+int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)\n+{\n+\t/* We currently use nothing arch-specific in upper 32 bits */\n+\tif ((reg-\u003eid \u0026 ~KVM_REG_SIZE_MASK) \u003e\u003e 32 != KVM_REG_ARM64 \u003e\u003e 32)\n+\t\treturn -EINVAL;\n+\n+\tswitch (reg-\u003eid \u0026 KVM_REG_ARM_COPROC_MASK) {\n+\tcase KVM_REG_ARM_CORE:\n+\t\treturn set_core_reg(vcpu, reg);\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+}\n+\n+int kvm_arm_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)\n+{\n+\tint ret;\n+\n+\tswitch (attr-\u003egroup) {\n+\tdefault:\n+\t\tret = -ENXIO;\n+\t\tbreak;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int kvm_arm_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)\n+{\n+\tint ret;\n+\n+\tswitch (attr-\u003egroup) {\n+\tdefault:\n+\t\tret = -ENXIO;\n+\t\tbreak;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int kvm_arm_vcpu_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)\n+{\n+\tint ret;\n+\n+\tswitch (attr-\u003egroup) {\n+\tdefault:\n+\t\tret = -ENXIO;\n+\t\tbreak;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)\n+{\n+\treturn -EINVAL;\n+}\n+\n+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)\n+{\n+\treturn -EINVAL;\n+}\n+\n+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,\n+\t\t\t\t struct kvm_sregs *sregs)\n+{\n+\treturn -EINVAL;\n+}\n+\n+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,\n+\t\t\t\t struct kvm_sregs *sregs)\n+{\n+\treturn -EINVAL;\n+}\n+\n+int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)\n+{\n+\treturn -EINVAL;\n+}\n+\n+int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)\n+{\n+\treturn -EINVAL;\n+}\n+\n+int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,\n+\t\t\t\t struct kvm_translation *tr)\n+{\n+\treturn -EINVAL;\n+}\n+\n+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,\n+\t\t\t\t\tstruct kvm_guest_debug *dbg)\n+{\n+\treturn -EINVAL;\n+}\ndiff --git a/arch/s390/kvm/arm64/guest.h b/arch/s390/kvm/arm64/guest.h\nnew file mode 100644\nindex 00000000000000..be367df99e3132\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/guest.h\n@@ -0,0 +1,14 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#ifndef KVM_ARM_GUEST_H\n+#define KVM_ARM_GUEST_H\n+\n+#include \u003clinux/kvm_host.h\u003e\n+\n+unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);\n+int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);\n+int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);\n+int kvm_arm_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);\n+int kvm_arm_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);\n+int kvm_arm_vcpu_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);\n+\n+#endif /* KVM_ARM_GUEST_H */\ndiff --git a/arch/s390/kvm/arm64/handle_exit.c b/arch/s390/kvm/arm64/handle_exit.c\nnew file mode 100644\nindex 00000000000000..96a45483e5b620\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/handle_exit.c\n@@ -0,0 +1,143 @@\n+// SPDX-License-Identifier: GPL-2.0\n+\n+#include \u003clinux/kvm_host.h\u003e\n+\n+#include \u003carm64/esr.h\u003e\n+#include \u003carm64/kvm_emulate.h\u003e\n+\n+#include \"handle_exit.h\"\n+\n+typedef int (*exit_handle_fn)(struct kvm_vcpu *);\n+exit_handle_fn arm_exit_handlers[ESR_ELx_EC_MAX + 1];\n+\n+#define __INCL_GEN_ARM_FILE\n+#include \"generated/handle_exit.inc\"\n+#undef __INCL_GEN_ARM_FILE\n+\n+#define PSCI_0_2_FN_SYSTEM_OFF\t\t0x84000008\n+#define PSCI_RET_NOT_SUPPORTED\t\t-1\n+#define PSCI_RET_INTERNAL_FAILURE\t-6\n+/*\n+ * Temporary smc/hvc handler. Non-compliant implementation (features missing).\n+ * Implements only system off so that test programs are able to end their execution\n+ */\n+static int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)\n+{\n+\tu32 func_id = vcpu_get_reg(vcpu, 0);\n+\tu64 val = PSCI_RET_NOT_SUPPORTED;\n+\tint ret = 1;\n+\n+\tif (func_id == PSCI_0_2_FN_SYSTEM_OFF) {\n+\t\tspin_lock(\u0026vcpu-\u003earch.mp_state_lock);\n+\t\tWRITE_ONCE(vcpu-\u003earch.mp_state.mp_state, KVM_MP_STATE_STOPPED);\n+\t\tspin_unlock(\u0026vcpu-\u003earch.mp_state_lock);\n+\t\tkvm_make_all_cpus_request(vcpu-\u003ekvm, KVM_REQ_SLEEP);\n+\t\tmemset(\u0026vcpu-\u003erun-\u003esystem_event, 0,\n+\t\t sizeof(vcpu-\u003erun-\u003esystem_event));\n+\t\tvcpu-\u003erun-\u003esystem_event.type = KVM_SYSTEM_EVENT_SHUTDOWN;\n+\t\tvcpu-\u003erun-\u003esystem_event.ndata = 1;\n+\t\tvcpu-\u003erun-\u003esystem_event.data[0] = 0;\n+\t\tvcpu-\u003erun-\u003eexit_reason = KVM_EXIT_SYSTEM_EVENT;\n+\t\tval = PSCI_RET_INTERNAL_FAILURE;\n+\t\tret = 0;\n+\t}\n+\tvcpu_set_reg(vcpu, 0, val);\n+\n+\treturn ret;\n+}\n+\n+static int handle_hvc(struct kvm_vcpu *vcpu)\n+{\n+\tvcpu-\u003estat.hvc_exit_stat++;\n+\treturn kvm_smccc_call_handler(vcpu);\n+}\n+\n+exit_handle_fn arm_exit_handlers[] = {\n+\t[0 ... ESR_ELx_EC_MAX]\t= kvm_handle_unknown_ec,\n+\t[ESR_ELx_EC_HVC64]\t= handle_hvc,\n+\t[ESR_ELx_EC_IABT_LOW]\t= kvm_handle_guest_abort,\n+\t[ESR_ELx_EC_DABT_LOW]\t= kvm_handle_guest_abort,\n+};\n+\n+/*\n+ * Return \u003e 0 to return to guest, \u003c 0 on error, 0 (and set exit_reason) on\n+ * proper exit to userspace.\n+ */\n+int handle_exit(struct kvm_vcpu *vcpu)\n+{\n+\tu8 icptr = vcpu-\u003earch.sae_block.icptr;\n+\tint ret = 1;\n+\n+\tswitch (icptr) {\n+\tcase SAE_ICPTR_SPURIOUS:\n+\t\tbreak;\n+\tcase SAE_ICPTR_VALIDITY:\n+\t\tWARN_ONCE(true, \"SAE: validity intercept. vir: 0x%04x\",\n+\t\t\t vcpu-\u003earch.sae_block.vir);\n+\t\tret = -EINVAL;\n+\t\tbreak;\n+\tcase SAE_ICPTR_HOST_ACCESS_EXCEPTION:\n+\tcase SAE_ICPTR_SYNCHRONOUS_EXCEPTION:\n+\t\tret = handle_trap_exceptions(vcpu);\n+\t\tbreak;\n+\tdefault:\n+\t\tWARN_ONCE(true, \"SAE: unknown interception reason 0x%02x\",\n+\t\t\t icptr);\n+\t\tret = -EINVAL;\n+\t}\n+\treturn ret;\n+}\n+\n+/* manually copied from arch/arm64/kernel/traps.c */\n+static const char * const esr_class_str[] = {\n+\t[0 ... ESR_ELx_EC_MAX]\t\t= \"UNRECOGNIZED EC\",\n+\t[ESR_ELx_EC_UNKNOWN]\t\t= \"Unknown/Uncategorized\",\n+\t[ESR_ELx_EC_WFx]\t\t= \"WFI/WFE\",\n+\t[ESR_ELx_EC_CP15_32]\t\t= \"CP15 MCR/MRC\",\n+\t[ESR_ELx_EC_CP15_64]\t\t= \"CP15 MCRR/MRRC\",\n+\t[ESR_ELx_EC_CP14_MR]\t\t= \"CP14 MCR/MRC\",\n+\t[ESR_ELx_EC_CP14_LS]\t\t= \"CP14 LDC/STC\",\n+\t[ESR_ELx_EC_FP_ASIMD]\t\t= \"ASIMD\",\n+\t[ESR_ELx_EC_CP10_ID]\t\t= \"CP10 MRC/VMRS\",\n+\t[ESR_ELx_EC_PAC]\t\t= \"PAC\",\n+\t[ESR_ELx_EC_CP14_64]\t\t= \"CP14 MCRR/MRRC\",\n+\t[ESR_ELx_EC_BTI]\t\t= \"BTI\",\n+\t[ESR_ELx_EC_ILL]\t\t= \"PSTATE.IL\",\n+\t[ESR_ELx_EC_SVC32]\t\t= \"SVC (AArch32)\",\n+\t[ESR_ELx_EC_HVC32]\t\t= \"HVC (AArch32)\",\n+\t[ESR_ELx_EC_SMC32]\t\t= \"SMC (AArch32)\",\n+\t[ESR_ELx_EC_SVC64]\t\t= \"SVC (AArch64)\",\n+\t[ESR_ELx_EC_HVC64]\t\t= \"HVC (AArch64)\",\n+\t[ESR_ELx_EC_SMC64]\t\t= \"SMC (AArch64)\",\n+\t[ESR_ELx_EC_SYS64]\t\t= \"MSR/MRS (AArch64)\",\n+\t[ESR_ELx_EC_SVE]\t\t= \"SVE\",\n+\t[ESR_ELx_EC_ERET]\t\t= \"ERET/ERETAA/ERETAB\",\n+\t[ESR_ELx_EC_FPAC]\t\t= \"FPAC\",\n+\t[ESR_ELx_EC_SME]\t\t= \"SME\",\n+\t[ESR_ELx_EC_IMP_DEF]\t\t= \"EL3 IMP DEF\",\n+\t[ESR_ELx_EC_IABT_LOW]\t\t= \"IABT (lower EL)\",\n+\t[ESR_ELx_EC_IABT_CUR]\t\t= \"IABT (current EL)\",\n+\t[ESR_ELx_EC_PC_ALIGN]\t\t= \"PC Alignment\",\n+\t[ESR_ELx_EC_DABT_LOW]\t\t= \"DABT (lower EL)\",\n+\t[ESR_ELx_EC_DABT_CUR]\t\t= \"DABT (current EL)\",\n+\t[ESR_ELx_EC_SP_ALIGN]\t\t= \"SP Alignment\",\n+\t[ESR_ELx_EC_MOPS]\t\t= \"MOPS\",\n+\t[ESR_ELx_EC_FP_EXC32]\t\t= \"FP (AArch32)\",\n+\t[ESR_ELx_EC_FP_EXC64]\t\t= \"FP (AArch64)\",\n+\t[ESR_ELx_EC_GCS]\t\t= \"Guarded Control Stack\",\n+\t[ESR_ELx_EC_SERROR]\t\t= \"SError\",\n+\t[ESR_ELx_EC_BREAKPT_LOW]\t= \"Breakpoint (lower EL)\",\n+\t[ESR_ELx_EC_BREAKPT_CUR]\t= \"Breakpoint (current EL)\",\n+\t[ESR_ELx_EC_SOFTSTP_LOW]\t= \"Software Step (lower EL)\",\n+\t[ESR_ELx_EC_SOFTSTP_CUR]\t= \"Software Step (current EL)\",\n+\t[ESR_ELx_EC_WATCHPT_LOW]\t= \"Watchpoint (lower EL)\",\n+\t[ESR_ELx_EC_WATCHPT_CUR]\t= \"Watchpoint (current EL)\",\n+\t[ESR_ELx_EC_BKPT32]\t\t= \"BKPT (AArch32)\",\n+\t[ESR_ELx_EC_VECTOR32]\t\t= \"Vector catch (AArch32)\",\n+\t[ESR_ELx_EC_BRK64]\t\t= \"BRK (AArch64)\",\n+};\n+\n+const char *esr_get_class_string(unsigned long esr)\n+{\n+\treturn esr_class_str[ESR_ELx_EC(esr)];\n+}\ndiff --git a/arch/s390/kvm/arm64/handle_exit.h b/arch/s390/kvm/arm64/handle_exit.h\nnew file mode 100644\nindex 00000000000000..65ae5872153753\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/handle_exit.h\n@@ -0,0 +1,9 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+#ifndef KVM_ARM64_HANDLE_EXIT_H\n+#define KVM_ARM64_HANDLE_EXIT_H\n+\n+#include \u003clinux/kvm_host.h\u003e\n+\n+int handle_exit(struct kvm_vcpu *vcpu);\n+\n+#endif /* KVM_ARM64_HANDLE_EXIT_H */\ndiff --git a/arch/s390/kvm/arm64/inject_fault.c b/arch/s390/kvm/arm64/inject_fault.c\nnew file mode 100644\nindex 00000000000000..425dbeaa421c6c\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/inject_fault.c\n@@ -0,0 +1,21 @@\n+// SPDX-License-Identifier: GPL-2.0\n+\n+#include \u003carm64/kvm_emulate.h\u003e\n+\n+/**\n+ * kvm_inject_undefined - inject an undefined instruction into the guest\n+ * @vcpu: The vCPU in which to inject the exception\n+ *\n+ * It is assumed that this code is called from the VCPU thread and that the\n+ * VCPU therefore is not currently executing guest code.\n+ */\n+void kvm_inject_undefined(struct kvm_vcpu *vcpu)\n+{\n+\t/* Stub until s390 supports arm64 sysregs TODO sysregs*/\n+}\n+\n+int kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr)\n+{\n+\t/* Stub until s390 supports arm64 sysregs TODO sysregs*/\n+\treturn 1;\n+}\ndiff --git a/arch/s390/kvm/arm64/mmio.c b/arch/s390/kvm/arm64/mmio.c\nnew file mode 100644\nindex 00000000000000..cfddfe3221961b\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/mmio.c\n@@ -0,0 +1,12 @@\n+// SPDX-License-Identifier: GPL-2.0\n+\n+#include \u003clinux/kvm_host.h\u003e\n+#include \u003clinux/bitfield.h\u003e\n+\n+#include \u003carm64/kvm_emulate.h\u003e\n+#include \u003carm64/kvm_mmu.h\u003e\n+#include \u003carm64/sysreg.h\u003e\n+\n+#define __INCL_GEN_ARM_FILE\n+#include \"generated/mmio.inc\"\n+#undef __INCL_GEN_ARM_FILE\ndiff --git a/arch/s390/kvm/arm64/mmu.c b/arch/s390/kvm/arm64/mmu.c\nnew file mode 100644\nindex 00000000000000..d5acabd762ba48\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/mmu.c\n@@ -0,0 +1,178 @@\n+// SPDX-License-Identifier: GPL-2.0\n+#include \u003clinux/kvm_host.h\u003e\n+\n+#include \u003carm64/kvm_emulate.h\u003e\n+#include \u003carm64/kvm_mmu.h\u003e\n+\n+#include \u003cfaultin.h\u003e\n+\n+static inline bool kvm_s390_cur_gmap_fault_is_write(struct kvm_vcpu *vcpu)\n+{\n+\treturn vcpu-\u003earch.sae_block.hai.pic == PGM_PROTECTION ||\n+\t vcpu-\u003earch.sae_block.hai.teid.fsi == TEID_FSI_STORE;\n+}\n+\n+/*\n+ * user_mem_abort() - handle a dat fault for the gmap of a vcpu\n+ *\n+ * Return: 0 on success, \u003c 0 in case of error.\n+ * Context: The mm lock must not be held before calling. May sleep.\n+ */\n+static int user_mem_abort(struct kvm_vcpu *vcpu, gpa_t fault_ipa,\n+\t\t\t struct kvm_memory_slot *slot, hva_t hva)\n+{\n+\tstruct guest_fault f = { };\n+\tint ret;\n+\n+\tif (kvm_s390_cur_gmap_fault_is_write(vcpu))\n+\t\tf.write_attempt = FOLL_WRITE;\n+\tf.gfn = gpa_to_gfn(fault_ipa);\n+\n+\tret = kvm_s390_faultin_gfn(vcpu, NULL, \u0026f);\n+\tif (ret \u003c= 0)\n+\t\treturn ret;\n+\tif (ret == PGM_ADDRESSING)\n+\t\t/*\n+\t\t * Without the relevant sysregs we cannot do anything for now.\n+\t\t * Go back to userspace with an error. TODO sysreg handling\n+\t\t */\n+\t\treturn -ENOEXEC;\n+\tKVM_BUG_ON(ret, vcpu-\u003ekvm);\n+\treturn -EINVAL;\n+}\n+\n+static int kvm_handle_pic(struct kvm_vcpu *vcpu, bool *translation)\n+{\n+\tswitch (kvm_vcpu_fault_pic(vcpu)) {\n+\t/* expected cases: */\n+\tcase PGM_ASCE_TYPE:\n+\tcase PGM_REGION_FIRST_TRANS:\n+\tcase PGM_REGION_SECOND_TRANS:\n+\tcase PGM_REGION_THIRD_TRANS:\n+\tcase PGM_SEGMENT_TRANSLATION:\n+\tcase PGM_PAGE_TRANSLATION:\n+\t\t*translation = true;\n+\t\tbreak;\n+\tcase PGM_PROTECTION:\n+\t\tbreak;\n+\t/* unexpected cases: */\n+\tcase 0:\n+\t\tKVM_BUG(1, vcpu-\u003ekvm, \"On MMU fault path but no fault occurred\");\n+\t\treturn -EFAULT;\n+\tdefault:\n+\t\tKVM_BUG(1, vcpu-\u003ekvm, \"Unexpected program interrupt 0x%x, TEID 0x%016lx\",\n+\t\t\tvcpu-\u003earch.sae_block.hai.pic, vcpu-\u003earch.sae_block.hai.teid.val);\n+\t\tsend_sig(SIGSEGV, current, 0);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)\n+{\n+\tstruct kvm_memory_slot *memslot;\n+\tbool translation = false;\n+\tphys_addr_t fault_ipa;\n+\tunsigned long esr;\n+\tunsigned long hva;\n+\tbool write_fault;\n+\tbool guest_size_err;\n+\tbool writable;\n+\tbool is_iabt;\n+\tint ret;\n+\tgfn_t gfn;\n+\tint idx;\n+\n+\tesr = kvm_vcpu_get_esr(vcpu);\n+\tfault_ipa = kvm_vcpu_get_fault_ipa(vcpu);\n+\tis_iabt = kvm_vcpu_trap_is_iabt(vcpu);\n+\tguest_size_err = vcpu-\u003earch.sae_block.icptr == SAE_ICPTR_GUEST_ADDRESS_SIZE;\n+\n+\tif (guest_size_err) {\n+\t\ttranslation = true;\n+\t} else {\n+\t\tret = kvm_handle_pic(vcpu, \u0026translation);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\n+\tif (translation) {\n+\t\t/*\n+\t\t * For both cases:\n+\t\t * Without the relevant sysregs we cannot do anything for now.\n+\t\t * Go back to userspace with an error. TODO sysreg handling\n+\t\t */\n+\t\tif (fault_ipa \u003e= BIT_ULL(get_kvm_ipa_limit()))\n+\t\t\treturn -ENOEXEC;\n+\n+\t\tif (fault_ipa \u003e= kvm_phys_size(vcpu-\u003ekvm))\n+\t\t\treturn -ENOEXEC;\n+\t}\n+\n+\tidx = srcu_read_lock(\u0026vcpu-\u003ekvm-\u003esrcu);\n+\n+\tgfn = fault_ipa \u003e\u003e PAGE_SHIFT;\n+\n+\tmemslot = gfn_to_memslot(vcpu-\u003ekvm, gfn);\n+\thva = gfn_to_hva_memslot_prot(memslot, gfn, \u0026writable);\n+\twrite_fault = kvm_is_write_fault(vcpu);\n+\tif (kvm_is_error_hva(hva) || (write_fault \u0026\u0026 !writable)) {\n+\t\tret = -ENOEXEC;\n+\t\t/*\n+\t\t * The guest has put either its instructions or its page-tables\n+\t\t * somewhere it shouldn't have. Userspace won't be able to do\n+\t\t * anything about this (there's no syndrome for a start).\n+\t\t *\n+\t\t * Without the relevant sysregs we cannot do anything for now.\n+\t\t * Go back to userspace with an error. TODO sysreg handling\n+\t\t */\n+\t\tif (is_iabt)\n+\t\t\tgoto out_unlock;\n+\n+\t\tif (kvm_vcpu_abt_iss1tw(vcpu)) {\n+\t\t\t/*\n+\t\t\t * Without the relevant sysregs we cannot do anything for now.\n+\t\t\t * Go back to userspace with an error. TODO sysreg handling\n+\t\t\t */\n+\t\t\tgoto out_unlock;\n+\t\t}\n+\n+\t\t/*\n+\t\t * Check for a cache maintenance operation. Assume the guest is\n+\t\t * cautious and skip instruction\n+\t\t */\n+\t\tif (kvm_is_error_hva(hva) \u0026\u0026 kvm_vcpu_dabt_is_cm(vcpu)) {\n+\t\t\tkvm_incr_pc(vcpu);\n+\t\t\tret = 1;\n+\t\t\tgoto out_unlock;\n+\t\t}\n+\n+\t\t/*\n+\t\t * The IPA is reported as [MAX:12], so we need to\n+\t\t * complement it with the bottom 12 bits from the\n+\t\t * faulting VA. This is always 12 bits, irrespective\n+\t\t * of the page size.\n+\t\t */\n+\t\tfault_ipa |= kvm_vcpu_get_hfar(vcpu) \u0026 ((1 \u003c\u003c 12) - 1);\n+\t\tret = io_mem_abort(vcpu, fault_ipa);\n+\t\tgoto out_unlock;\n+\t}\n+\n+\t/* Userspace should not be able to register out-of-bounds IPAs */\n+\tVM_BUG_ON(fault_ipa \u003e= kvm_phys_size(vcpu-\u003ekvm));\n+\t/*\n+\t * Proper guest size faults have been injected.\n+\t * In theory it's fine to have device memory higher than MSL,\n+\t * even if not currently possible, but that would have been handled above.\n+\t * So if we get here with a guest size intercept, we have a bug somewhere.\n+\t */\n+\tVM_BUG_ON(guest_size_err);\n+\n+\tret = user_mem_abort(vcpu, fault_ipa, memslot, hva);\n+\tif (!ret)\n+\t\tret = 1;\n+out_unlock:\n+\tsrcu_read_unlock(\u0026vcpu-\u003ekvm-\u003esrcu, idx);\n+\treturn ret;\n+}\ndiff --git a/arch/s390/kvm/arm64/reset.c b/arch/s390/kvm/arm64/reset.c\nnew file mode 100644\nindex 00000000000000..46edc792f84340\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/reset.c\n@@ -0,0 +1,62 @@\n+// SPDX-License-Identifier: GPL-2.0\n+\n+#include \u003clinux/kvm_host.h\u003e\n+\n+#include \u003carm64/kvm_emulate.h\u003e\n+#include \u003carm64/kvm_nested.h\u003e\n+\n+#include \"reset.h\"\n+\n+#define __INCL_GEN_ARM_FILE\n+#include \"generated/reset.inc\"\n+#undef __INCL_GEN_ARM_FILE\n+\n+bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)\n+{\n+\treturn true;\n+}\n+\n+void kvm_reset_vcpu(struct kvm_vcpu *vcpu)\n+{\n+\tstruct vcpu_reset_state reset_state;\n+\tbool loaded;\n+\n+\tspin_lock(\u0026vcpu-\u003earch.mp_state_lock);\n+\treset_state = vcpu-\u003earch.reset_state;\n+\tvcpu-\u003earch.reset_state.reset = false;\n+\tspin_unlock(\u0026vcpu-\u003earch.mp_state_lock);\n+\n+\t/*\n+\t * Disable preemption around the vcpu reset as we might otherwise race with\n+\t * preempt notifiers which call stiasrm/lasrm from put/load\n+\t */\n+\tpreempt_disable();\n+\n+\t/* The reset must run with an unloaded save area */\n+\tloaded = vcpu_is_loaded(vcpu);\n+\tif (loaded)\n+\t\tvcpu_put(vcpu);\n+\n+\tkvm_reset_vcpu_core_regs(vcpu);\n+\n+\t/* Reset special registers */\n+\tvcpu_reset_hcr(vcpu);\n+\n+\tif (reset_state.reset) {\n+\t\t*vcpu_pc(vcpu) = reset_state.pc;\n+\t\tvcpu_clear_flag(vcpu, PENDING_EXCEPTION);\n+\t\tvcpu_clear_flag(vcpu, EXCEPT_MASK);\n+\t\tvcpu_clear_flag(vcpu, INCREMENT_PC);\n+\t\tvcpu_set_reg(vcpu, 0, reset_state.r0);\n+\t}\n+\n+\tif (loaded)\n+\t\tvcpu_load(vcpu);\n+\n+\tpreempt_enable();\n+}\n+\n+int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature)\n+{\n+\treturn 0;\n+}\ndiff --git a/arch/s390/kvm/arm64/reset.h b/arch/s390/kvm/arm64/reset.h\nnew file mode 100644\nindex 00000000000000..a5c5304e47bcf7\n--- /dev/null\n+++ b/arch/s390/kvm/arm64/reset.h\n@@ -0,0 +1,11 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#ifndef KVM_ARM_RESET_H\n+#define KVM_ARM_RESET_H\n+\n+#include \u003clinux/kvm_host.h\u003e\n+\n+bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);\n+void kvm_reset_vcpu(struct kvm_vcpu *vcpu);\n+int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature);\n+\n+#endif /* KVM_ARM_RESET_H */\ndiff --git a/arch/s390/kvm/gmap/Makefile b/arch/s390/kvm/gmap/Makefile\nnew file mode 100644\nindex 00000000000000..4ca7635d1d0e82\n--- /dev/null\n+++ b/arch/s390/kvm/gmap/Makefile\n@@ -0,0 +1,12 @@\n+# SPDX-License-Identifier: GPL-2.0\n+\n+GMAP ?= ../gmap\n+\n+# Enable s390-specific guest management features (storage keys and CMMA)\n+KVM_MANAGES_S390_GUEST ?= y\n+USE_PREFIX_STUB := $(if $(filter y,$(KVM_MANAGES_S390_GUEST)),n,y)\n+\n+kvm-y += $(GMAP)/dat.o $(GMAP)/gmap.o $(GMAP)/faultin.o $(GMAP)/mmu.o\n+\n+kvm-$(KVM_MANAGES_S390_GUEST) += $(GMAP)/sk.o $(GMAP)/cmma.o $(GMAP)/prefix.o\n+kvm-$(USE_PREFIX_STUB) += $(GMAP)/prefix-stubs.o\ndiff --git a/arch/s390/kvm/gmap/cmma.c b/arch/s390/kvm/gmap/cmma.c\nnew file mode 100644\nindex 00000000000000..db729327aedaee\n--- /dev/null\n+++ b/arch/s390/kvm/gmap/cmma.c\n@@ -0,0 +1,313 @@\n+// SPDX-License-Identifier: GPL-2.0\n+\n+#include \u003clinux/mm.h\u003e\n+#include \u003clinux/kvm_host.h\u003e\n+#include \"cmma.h\"\n+#include \"gmap.h\"\n+\n+int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state *state, bool *dirty)\n+{\n+\tunion crste *crstep;\n+\tunion pgste pgste;\n+\tunion pte *ptep;\n+\tint res = 0;\n+\n+\tif (dat_entry_walk(NULL, gfn, asce, 0, TABLE_TYPE_PAGE_TABLE, \u0026crstep, \u0026ptep)) {\n+\t\t*state = (union essa_state) { .exception = 1 };\n+\t\treturn -1;\n+\t}\n+\n+\tpgste = pgste_get_lock(ptep);\n+\n+\t*state = (union essa_state) {\n+\t\t.content = (ptep-\u003eh.i \u003c\u003c 1) + (ptep-\u003eh.i \u0026\u0026 pgste.zero),\n+\t\t.nodat = pgste.nodat,\n+\t\t.usage = pgste.usage,\n+\t\t};\n+\n+\tswitch (orc) {\n+\tcase ESSA_GET_STATE:\n+\t\tres = -1;\n+\t\tbreak;\n+\tcase ESSA_SET_STABLE:\n+\t\tpgste.usage = PGSTE_GPS_USAGE_STABLE;\n+\t\tpgste.nodat = 0;\n+\t\tbreak;\n+\tcase ESSA_SET_UNUSED:\n+\t\tpgste.usage = PGSTE_GPS_USAGE_UNUSED;\n+\t\tif (ptep-\u003eh.i)\n+\t\t\tres = 1;\n+\t\tbreak;\n+\tcase ESSA_SET_VOLATILE:\n+\t\tpgste.usage = PGSTE_GPS_USAGE_VOLATILE;\n+\t\tif (ptep-\u003eh.i)\n+\t\t\tres = 1;\n+\t\tbreak;\n+\tcase ESSA_SET_POT_VOLATILE:\n+\t\tif (!ptep-\u003eh.i) {\n+\t\t\tpgste.usage = PGSTE_GPS_USAGE_POT_VOLATILE;\n+\t\t} else if (pgste.zero) {\n+\t\t\tpgste.usage = PGSTE_GPS_USAGE_VOLATILE;\n+\t\t} else if (!pgste.gc) {\n+\t\t\tpgste.usage = PGSTE_GPS_USAGE_VOLATILE;\n+\t\t\tres = 1;\n+\t\t}\n+\t\tbreak;\n+\tcase ESSA_SET_STABLE_RESIDENT:\n+\t\tpgste.usage = PGSTE_GPS_USAGE_STABLE;\n+\t\t/*\n+\t\t * Since the resident state can go away any time after this\n+\t\t * call, we will not make this page resident. We can revisit\n+\t\t * this decision if a guest will ever start using this.\n+\t\t */\n+\t\tbreak;\n+\tcase ESSA_SET_STABLE_IF_RESIDENT:\n+\t\tif (!ptep-\u003eh.i)\n+\t\t\tpgste.usage = PGSTE_GPS_USAGE_STABLE;\n+\t\tbreak;\n+\tcase ESSA_SET_STABLE_NODAT:\n+\t\tpgste.usage = PGSTE_GPS_USAGE_STABLE;\n+\t\tpgste.nodat = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\tWARN_ONCE(1, \"Invalid ORC!\");\n+\t\tres = -1;\n+\t\tbreak;\n+\t}\n+\t/* If we are discarding a page, set it to logical zero. */\n+\tpgste.zero = res == 1;\n+\tif (orc \u003e 0) {\n+\t\t*dirty = !pgste.cmma_d;\n+\t\tpgste.cmma_d = 1;\n+\t}\n+\n+\tpgste_set_unlock(ptep, pgste);\n+\n+\treturn res;\n+}\n+\n+static long dat_reset_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n+{\n+\tunion pgste pgste;\n+\n+\tpgste = pgste_get_lock(ptep);\n+\tpgste.usage = 0;\n+\tpgste.nodat = 0;\n+\tpgste.cmma_d = 0;\n+\tpgste_set_unlock(ptep, pgste);\n+\tif (need_resched())\n+\t\treturn next;\n+\treturn 0;\n+}\n+\n+long dat_reset_cmma(union asce asce, gfn_t start)\n+{\n+\tconst struct dat_walk_ops dat_reset_cmma_ops = {\n+\t\t.pte_entry = dat_reset_cmma_pte,\n+\t};\n+\n+\treturn _dat_walk_gfn_range(start, asce_end(asce), asce, \u0026dat_reset_cmma_ops,\n+\t\t\t\t DAT_WALK_IGN_HOLES, NULL);\n+}\n+\n+struct dat_get_cmma_state {\n+\tgfn_t start;\n+\tgfn_t end;\n+\tunsigned int count;\n+\tu8 *values;\n+\tatomic64_t *remaining;\n+};\n+\n+static long __dat_peek_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n+{\n+\tstruct dat_get_cmma_state *state = walk-\u003epriv;\n+\tunion pgste pgste;\n+\n+\tpgste = pgste_get_lock(ptep);\n+\tstate-\u003evalues[gfn - walk-\u003estart] = pgste.usage | (pgste.nodat \u003c\u003c 6);\n+\tpgste_set_unlock(ptep, pgste);\n+\tstate-\u003eend = next;\n+\n+\treturn 0;\n+}\n+\n+static long __dat_peek_cmma_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n+{\n+\tstruct dat_get_cmma_state *state = walk-\u003epriv;\n+\n+\tif (crstep-\u003eh.i)\n+\t\tstate-\u003eend = min(walk-\u003eend, next);\n+\treturn 0;\n+}\n+\n+int dat_peek_cmma(gfn_t start, union asce asce, unsigned int *count, u8 *values)\n+{\n+\tconst struct dat_walk_ops ops = {\n+\t\t.pte_entry = __dat_peek_cmma_pte,\n+\t\t.pmd_entry = __dat_peek_cmma_crste,\n+\t\t.pud_entry = __dat_peek_cmma_crste,\n+\t\t.p4d_entry = __dat_peek_cmma_crste,\n+\t\t.pgd_entry = __dat_peek_cmma_crste,\n+\t};\n+\tstruct dat_get_cmma_state state = { .values = values, };\n+\tint rc;\n+\n+\trc = _dat_walk_gfn_range(start, start + *count, asce, \u0026ops, DAT_WALK_DEFAULT, \u0026state);\n+\t*count = state.end \u003e= start ? state.end - start : 0;\n+\t/* Return success if at least one value was saved, otherwise an error. */\n+\treturn (rc == -EFAULT \u0026\u0026 *count \u003e 0) ? 0 : rc;\n+}\n+\n+static long __dat_get_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n+{\n+\tstruct dat_get_cmma_state *state = walk-\u003epriv;\n+\tunion pgste pgste;\n+\n+\tif (state-\u003estart != -1) {\n+\t\tif ((gfn - state-\u003eend) \u003e KVM_S390_MAX_BIT_DISTANCE)\n+\t\t\treturn 1;\n+\t\tif (gfn - state-\u003estart \u003e= state-\u003ecount)\n+\t\t\treturn 1;\n+\t}\n+\n+\tif (!READ_ONCE(*pgste_of(ptep)).cmma_d)\n+\t\treturn 0;\n+\n+\tpgste = pgste_get_lock(ptep);\n+\tif (pgste.cmma_d) {\n+\t\tif (state-\u003estart == -1)\n+\t\t\tstate-\u003estart = gfn;\n+\t\tpgste.cmma_d = 0;\n+\t\tatomic64_dec(state-\u003eremaining);\n+\t\tstate-\u003evalues[gfn - state-\u003estart] = pgste.usage | pgste.nodat \u003c\u003c 6;\n+\t\tstate-\u003eend = next;\n+\t}\n+\tpgste_set_unlock(ptep, pgste);\n+\treturn 0;\n+}\n+\n+int dat_get_cmma(union asce asce, gfn_t *start, unsigned int *count, u8 *values, atomic64_t *rem)\n+{\n+\tconst struct dat_walk_ops ops = { .pte_entry = __dat_get_cmma_pte, };\n+\tstruct dat_get_cmma_state state = {\n+\t\t.remaining = rem,\n+\t\t.values = values,\n+\t\t.count = *count,\n+\t\t.start = -1,\n+\t};\n+\n+\t_dat_walk_gfn_range(*start, asce_end(asce), asce, \u0026ops, DAT_WALK_IGN_HOLES, \u0026state);\n+\t/* If no dirty pages were found, wrap around and continue searching */\n+\tif (*start \u0026\u0026 state.start == -1)\n+\t\t_dat_walk_gfn_range(0, *start, asce, \u0026ops, DAT_WALK_IGN_HOLES, \u0026state);\n+\n+\tif (state.start == -1) {\n+\t\t*count = 0;\n+\t} else {\n+\t\t*count = state.end - state.start;\n+\t\t*start = state.start;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+struct dat_set_cmma_state {\n+\tunsigned long mask;\n+\tconst u8 *bits;\n+};\n+\n+static long __dat_set_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n+{\n+\tstruct dat_set_cmma_state *state = walk-\u003epriv;\n+\tunion pgste pgste, tmp;\n+\n+\ttmp.val = (state-\u003ebits[gfn - walk-\u003estart] \u003c\u003c 24) \u0026 state-\u003emask;\n+\n+\tpgste = pgste_get_lock(ptep);\n+\tpgste.usage = tmp.usage;\n+\tpgste.nodat = tmp.nodat;\n+\tpgste_set_unlock(ptep, pgste);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * dat_set_cmma_bits() - Set CMMA bits for a range of guest pages.\n+ * @mc: Cache used for allocations.\n+ * @asce: The ASCE of the guest.\n+ * @gfn: The guest frame of the fist page whose CMMA bits are to set.\n+ * @count: How many pages need to be processed.\n+ * @mask: Which PGSTE bits should be set.\n+ * @bits: Points to an array with the CMMA attributes.\n+ *\n+ * This function sets the CMMA attributes for the given pages. If the input\n+ * buffer has zero length, no action is taken, otherwise the attributes are\n+ * set and the mm-\u003econtext.uses_cmm flag is set.\n+ *\n+ * Each byte in @bits contains new values for bits 32-39 of the PGSTE.\n+ * Currently, only the fields NT and US are applied.\n+ *\n+ * Return: %0 in case of success, a negative error value otherwise.\n+ */\n+int dat_set_cmma_bits(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,\n+\t\t unsigned long count, unsigned long mask, const uint8_t *bits)\n+{\n+\tconst struct dat_walk_ops ops = { .pte_entry = __dat_set_cmma_pte, };\n+\tstruct dat_set_cmma_state state = { .mask = mask, .bits = bits, };\n+\tunion crste *crstep;\n+\tunion pte *ptep;\n+\tgfn_t cur;\n+\tint rc;\n+\n+\tfor (cur = ALIGN_DOWN(gfn, _PAGE_ENTRIES); cur \u003c gfn + count; cur += _PAGE_ENTRIES) {\n+\t\trc = dat_entry_walk(mc, cur, asce, DAT_WALK_ALLOC, TABLE_TYPE_PAGE_TABLE,\n+\t\t\t\t \u0026crstep, \u0026ptep);\n+\t\tif (rc)\n+\t\t\treturn rc;\n+\t}\n+\treturn _dat_walk_gfn_range(gfn, gfn + count, asce, \u0026ops, DAT_WALK_IGN_HOLES, \u0026state);\n+}\n+\n+static long __set_cmma_clean_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n+{\n+\tunion pgste pgste;\n+\n+\tpgste = pgste_get_lock(ptep);\n+\tpgste.cmma_d = 0;\n+\tpgste_set_unlock(ptep, pgste);\n+\n+\tif (need_resched())\n+\t\treturn next;\n+\treturn 0;\n+}\n+\n+static long __set_cmma_dirty_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n+{\n+\tunion pgste pgste;\n+\n+\tpgste = pgste_get_lock(ptep);\n+\tif (!pgste.cmma_d)\n+\t\tatomic64_inc(walk-\u003epriv);\n+\tpgste.cmma_d = 1;\n+\tpgste_set_unlock(ptep, pgste);\n+\n+\tif (need_resched())\n+\t\treturn next;\n+\treturn 0;\n+}\n+\n+void _gmap_set_cmma_all(struct gmap *gmap, bool dirty)\n+{\n+\tconst struct dat_walk_ops ops = {\n+\t\t.pte_entry = dirty ? __set_cmma_dirty_pte : __set_cmma_clean_pte,\n+\t};\n+\tgfn_t gfn = 0;\n+\n+\tdo {\n+\t\tscoped_guard(read_lock, \u0026gmap-\u003ekvm-\u003emmu_lock)\n+\t\t\tgfn = _dat_walk_gfn_range(gfn, asce_end(gmap-\u003easce), gmap-\u003easce, \u0026ops,\n+\t\t\t\t\t\t DAT_WALK_IGN_HOLES,\n+\t\t\t\t\t\t \u0026gmap-\u003ekvm-\u003earch.cmma_dirty_pages);\n+\t\tcond_resched();\n+\t} while (gfn);\n+}\ndiff --git a/arch/s390/kvm/gmap/cmma.h b/arch/s390/kvm/gmap/cmma.h\nnew file mode 100644\nindex 00000000000000..12b574ecf71189\n--- /dev/null\n+++ b/arch/s390/kvm/gmap/cmma.h\n@@ -0,0 +1,36 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+\n+#ifndef ARCH_KVM_GMAP_CMMA_H\n+#define ARCH_KVM_GMAP_CMMA_H\n+\n+#include \"dat.h\"\n+\n+#define ESSA_GET_STATE 0\n+#define ESSA_SET_STABLE 1\n+#define ESSA_SET_UNUSED 2\n+#define ESSA_SET_VOLATILE 3\n+#define ESSA_SET_POT_VOLATILE 4\n+#define ESSA_SET_STABLE_RESIDENT 5\n+#define ESSA_SET_STABLE_IF_RESIDENT 6\n+#define ESSA_SET_STABLE_NODAT 7\n+\n+int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state *state, bool *dirty);\n+long dat_reset_cmma(union asce asce, gfn_t start_gfn);\n+int dat_peek_cmma(gfn_t start, union asce asce, unsigned int *count, u8 *values);\n+int dat_get_cmma(union asce asce, gfn_t *start, unsigned int *count, u8 *values, atomic64_t *rem);\n+int dat_set_cmma_bits(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,\n+\t\t unsigned long count, unsigned long mask, const uint8_t *bits);\n+\n+void _gmap_set_cmma_all(struct gmap *gmap, bool dirty);\n+\n+static inline void gmap_set_cmma_all_dirty(struct gmap *gmap)\n+{\n+\t_gmap_set_cmma_all(gmap, true);\n+}\n+\n+static inline void gmap_set_cmma_all_clean(struct gmap *gmap)\n+{\n+\t_gmap_set_cmma_all(gmap, false);\n+}\n+\n+#endif /* ARCH_KVM_GMAP_CMMA_H */\ndiff --git a/arch/s390/kvm/dat.c b/arch/s390/kvm/gmap/dat.c\nsimilarity index 61%\nrename from arch/s390/kvm/dat.c\nrename to arch/s390/kvm/gmap/dat.c\nindex 5f1960ec982d04..4a98471395341e 100644\n--- a/arch/s390/kvm/dat.c\n+++ b/arch/s390/kvm/gmap/dat.c\n@@ -27,6 +27,9 @@\n #include \u003casm/page-states.h\u003e\n #include \u003casm/tlb.h\u003e\n #include \"dat.h\"\n+#include \"sk.h\"\n+#include \"cmma.h\"\n+\n \n int kvm_s390_mmu_cache_topup(struct kvm_s390_mmu_cache *mc)\n {\n@@ -611,229 +614,6 @@ long _dat_walk_gfn_range(gfn_t start, gfn_t end, union asce asce,\n \treturn dat_crste_walk_range(start, min(end, asce_end(asce)), table, \u0026walk);\n }\n \n-int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey)\n-{\n-\tunion crste *crstep;\n-\tunion pgste pgste;\n-\tunion pte *ptep;\n-\tint rc;\n-\n-\tskey-\u003eskey = 0;\n-\trc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, \u0026crstep, \u0026ptep);\n-\tif (rc)\n-\t\treturn rc;\n-\n-\tif (!ptep) {\n-\t\tunion crste crste;\n-\n-\t\tcrste = READ_ONCE(*crstep);\n-\t\tif (!crste.h.fc || !crste.s.fc1.pr)\n-\t\t\treturn 0;\n-\t\tskey-\u003eskey = page_get_storage_key(large_crste_to_phys(crste, gfn));\n-\t\treturn 0;\n-\t}\n-\tpgste = pgste_get_lock(ptep);\n-\tif (ptep-\u003eh.i) {\n-\t\tskey-\u003eacc = pgste.acc;\n-\t\tskey-\u003efp = pgste.fp;\n-\t} else {\n-\t\tskey-\u003eskey = page_get_storage_key(pte_origin(*ptep));\n-\t}\n-\tskey-\u003er |= pgste.gr;\n-\tskey-\u003ec |= pgste.gc;\n-\tpgste_set_unlock(ptep, pgste);\n-\treturn 0;\n-}\n-\n-static void dat_update_ptep_sd(union pgste old, union pgste pgste, union pte *ptep)\n-{\n-\tif (pgste.acc != old.acc || pgste.fp != old.fp || pgste.gr != old.gr || pgste.gc != old.gc)\n-\t\t__atomic64_or(_PAGE_SD, \u0026ptep-\u003eval);\n-}\n-\n-int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,\n-\t\t\tunion skey skey, bool nq)\n-{\n-\tunion pgste pgste, old;\n-\tunion crste *crstep;\n-\tunion pte *ptep;\n-\tint rc;\n-\n-\trc = dat_entry_walk(mc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,\n-\t\t\t \u0026crstep, \u0026ptep);\n-\tif (rc)\n-\t\treturn rc;\n-\n-\tif (!ptep) {\n-\t\tpage_set_storage_key(large_crste_to_phys(*crstep, gfn), skey.skey, !nq);\n-\t\treturn 0;\n-\t}\n-\n-\told = pgste_get_lock(ptep);\n-\tpgste = old;\n-\n-\tpgste.acc = skey.acc;\n-\tpgste.fp = skey.fp;\n-\tpgste.gc = skey.c;\n-\tpgste.gr = skey.r;\n-\n-\tif (!ptep-\u003eh.i) {\n-\t\tunion skey old_skey;\n-\n-\t\told_skey.skey = page_get_storage_key(pte_origin(*ptep));\n-\t\tpgste.hc |= old_skey.c;\n-\t\tpgste.hr |= old_skey.r;\n-\t\told_skey.c = old.gc;\n-\t\told_skey.r = old.gr;\n-\t\tskey.r = 0;\n-\t\tskey.c = 0;\n-\t\tpage_set_storage_key(pte_origin(*ptep), skey.skey, !nq);\n-\t}\n-\n-\tdat_update_ptep_sd(old, pgste, ptep);\n-\tpgste_set_unlock(ptep, pgste);\n-\treturn 0;\n-}\n-\n-static bool page_cond_set_storage_key(phys_addr_t paddr, union skey skey, union skey *oldkey,\n-\t\t\t\t bool nq, bool mr, bool mc)\n-{\n-\toldkey-\u003eskey = page_get_storage_key(paddr);\n-\tif (oldkey-\u003eacc == skey.acc \u0026\u0026 oldkey-\u003efp == skey.fp \u0026\u0026\n-\t (oldkey-\u003er == skey.r || mr) \u0026\u0026 (oldkey-\u003ec == skey.c || mc))\n-\t\treturn false;\n-\tpage_set_storage_key(paddr, skey.skey, !nq);\n-\treturn true;\n-}\n-\n-int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gfn_t gfn,\n-\t\t\t union skey skey, union skey *oldkey, bool nq, bool mr, bool mc)\n-{\n-\tunion pgste pgste, old;\n-\tunion crste *crstep;\n-\tunion skey prev;\n-\tunion pte *ptep;\n-\tint rc;\n-\n-\trc = dat_entry_walk(mmc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,\n-\t\t\t \u0026crstep, \u0026ptep);\n-\tif (rc)\n-\t\treturn rc;\n-\n-\tif (!ptep)\n-\t\treturn page_cond_set_storage_key(large_crste_to_phys(*crstep, gfn), skey, oldkey,\n-\t\t\t\t\t\t nq, mr, mc);\n-\n-\told = pgste_get_lock(ptep);\n-\tpgste = old;\n-\n-\trc = 1;\n-\tpgste.acc = skey.acc;\n-\tpgste.fp = skey.fp;\n-\tpgste.gc = skey.c;\n-\tpgste.gr = skey.r;\n-\n-\tif (!ptep-\u003eh.i) {\n-\t\trc = page_cond_set_storage_key(pte_origin(*ptep), skey, \u0026prev, nq, mr, mc);\n-\t\tpgste.hc |= prev.c;\n-\t\tpgste.hr |= prev.r;\n-\t\tprev.c |= old.gc;\n-\t\tprev.r |= old.gr;\n-\t} else {\n-\t\tprev.acc = old.acc;\n-\t\tprev.fp = old.fp;\n-\t\tprev.c = old.gc;\n-\t\tprev.r = old.gr;\n-\t}\n-\tif (oldkey)\n-\t\t*oldkey = prev;\n-\n-\tdat_update_ptep_sd(old, pgste, ptep);\n-\tpgste_set_unlock(ptep, pgste);\n-\treturn rc;\n-}\n-\n-int dat_reset_reference_bit(union asce asce, gfn_t gfn)\n-{\n-\tunion pgste pgste, old;\n-\tunion crste *crstep;\n-\tunion pte *ptep;\n-\tint rc;\n-\n-\trc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, \u0026crstep, \u0026ptep);\n-\tif (rc)\n-\t\treturn rc;\n-\n-\tif (!ptep) {\n-\t\tunion crste crste = READ_ONCE(*crstep);\n-\n-\t\tif (!crste.h.fc || !crste.s.fc1.pr)\n-\t\t\treturn 0;\n-\t\treturn page_reset_referenced(large_crste_to_phys(*crstep, gfn));\n-\t}\n-\told = pgste_get_lock(ptep);\n-\tpgste = old;\n-\n-\tif (!ptep-\u003eh.i) {\n-\t\trc = page_reset_referenced(pte_origin(*ptep));\n-\t\tpgste.hr = rc \u003e\u003e 1;\n-\t}\n-\trc |= (pgste.gr \u003c\u003c 1) | pgste.gc;\n-\tpgste.gr = 0;\n-\n-\tdat_update_ptep_sd(old, pgste, ptep);\n-\tpgste_set_unlock(ptep, pgste);\n-\treturn rc;\n-}\n-\n-static long dat_reset_skeys_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n-{\n-\tunion pgste pgste;\n-\n-\tpgste = pgste_get_lock(ptep);\n-\tpgste.acc = 0;\n-\tpgste.fp = 0;\n-\tpgste.gr = 0;\n-\tpgste.gc = 0;\n-\tif (ptep-\u003es.pr)\n-\t\tpage_set_storage_key(pte_origin(*ptep), PAGE_DEFAULT_KEY, 1);\n-\tpgste_set_unlock(ptep, pgste);\n-\n-\tif (need_resched())\n-\t\treturn next;\n-\treturn 0;\n-}\n-\n-static long dat_reset_skeys_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n-{\n-\tphys_addr_t addr, end, origin = crste_origin_large(*crstep);\n-\n-\tif (!crstep-\u003eh.fc || !crstep-\u003es.fc1.pr)\n-\t\treturn 0;\n-\n-\taddr = ((max(gfn, walk-\u003estart) - gfn) \u003c\u003c PAGE_SHIFT) + origin;\n-\tend = ((min(next, walk-\u003eend) - gfn) \u003c\u003c PAGE_SHIFT) + origin;\n-\twhile (ALIGN(addr + 1, _SEGMENT_SIZE) \u003c= end)\n-\t\taddr = sske_frame(addr, PAGE_DEFAULT_KEY);\n-\tfor ( ; addr \u003c end; addr += PAGE_SIZE)\n-\t\tpage_set_storage_key(addr, PAGE_DEFAULT_KEY, 1);\n-\n-\tif (need_resched())\n-\t\treturn next;\n-\treturn 0;\n-}\n-\n-long dat_reset_skeys(union asce asce, gfn_t start)\n-{\n-\tconst struct dat_walk_ops ops = {\n-\t\t.pte_entry = dat_reset_skeys_pte,\n-\t\t.pmd_entry = dat_reset_skeys_crste,\n-\t\t.pud_entry = dat_reset_skeys_crste,\n-\t};\n-\n-\treturn _dat_walk_gfn_range(start, asce_end(asce), asce, \u0026ops, DAT_WALK_IGN_HOLES, NULL);\n-}\n-\n struct slot_priv {\n \tunsigned long token;\n \tstruct kvm_s390_mmu_cache *mc;\n@@ -997,329 +777,3 @@ bool dat_test_age_gfn(union asce asce, gfn_t start, gfn_t end)\n {\n \treturn _dat_walk_gfn_range(start, end, asce, \u0026test_age_ops, 0, NULL) \u003e 0;\n }\n-\n-static long dat_set_pn_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n-{\n-\tunion crste newcrste, oldcrste;\n-\tint *n = walk-\u003epriv;\n-\n-\tdo {\n-\t\toldcrste = READ_ONCE(*crstep);\n-\t\tif (!oldcrste.h.fc || oldcrste.h.i || oldcrste.h.p)\n-\t\t\treturn 0;\n-\t\tif (oldcrste.s.fc1.prefix_notif)\n-\t\t\tbreak;\n-\t\tnewcrste = oldcrste;\n-\t\tnewcrste.s.fc1.prefix_notif = 1;\n-\t} while (!dat_crstep_xchg_atomic(crstep, oldcrste, newcrste, gfn, walk-\u003easce));\n-\t*n = 2;\n-\treturn 0;\n-}\n-\n-static long dat_set_pn_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n-{\n-\tint *n = walk-\u003epriv;\n-\tunion pgste pgste;\n-\n-\tpgste = pgste_get_lock(ptep);\n-\tif (!ptep-\u003eh.i \u0026\u0026 !ptep-\u003eh.p) {\n-\t\tpgste.prefix_notif = 1;\n-\t\t*n += 1;\n-\t}\n-\tpgste_set_unlock(ptep, pgste);\n-\treturn 0;\n-}\n-\n-int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn)\n-{\n-\tstatic const struct dat_walk_ops ops = {\n-\t\t.pte_entry = dat_set_pn_pte,\n-\t\t.pmd_entry = dat_set_pn_crste,\n-\t\t.pud_entry = dat_set_pn_crste,\n-\t};\n-\n-\tint n = 0;\n-\n-\t_dat_walk_gfn_range(gfn, gfn + 2, asce, \u0026ops, DAT_WALK_IGN_HOLES, \u0026n);\n-\tif (n != 2)\n-\t\treturn -EAGAIN;\n-\treturn 0;\n-}\n-\n-/**\n- * dat_perform_essa() - Perform ESSA actions on the PGSTE.\n- * @asce: The asce to operate on.\n- * @gfn: The guest page frame to operate on.\n- * @orc: The specific action to perform, see the ESSA_SET_* macros.\n- * @state: The storage attributes to be returned to the guest.\n- * @dirty: Returns whether the function dirtied a previously clean entry.\n- *\n- * Context: Called with kvm-\u003emmu_lock held.\n- *\n- * Return:\n- * * %1 if the page state has been altered and the page is to be added to the CBRL\n- * * %0 if the page state has been altered, but the page is not to be added to the CBRL\n- * * %-1 if the page state has not been altered and the page is not to be added to the CBRL\n- */\n-int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state *state, bool *dirty)\n-{\n-\tunion crste *crstep;\n-\tunion pgste pgste;\n-\tunion pte *ptep;\n-\tint res = 0;\n-\n-\tif (dat_entry_walk(NULL, gfn, asce, 0, TABLE_TYPE_PAGE_TABLE, \u0026crstep, \u0026ptep)) {\n-\t\t*state = (union essa_state) { .exception = 1 };\n-\t\treturn -1;\n-\t}\n-\n-\tpgste = pgste_get_lock(ptep);\n-\n-\t*state = (union essa_state) {\n-\t\t.content = (ptep-\u003eh.i \u003c\u003c 1) + (ptep-\u003eh.i \u0026\u0026 pgste.zero),\n-\t\t.nodat = pgste.nodat,\n-\t\t.usage = pgste.usage,\n-\t\t};\n-\n-\tswitch (orc) {\n-\tcase ESSA_GET_STATE:\n-\t\tres = -1;\n-\t\tbreak;\n-\tcase ESSA_SET_STABLE:\n-\t\tpgste.usage = PGSTE_GPS_USAGE_STABLE;\n-\t\tpgste.nodat = 0;\n-\t\tbreak;\n-\tcase ESSA_SET_UNUSED:\n-\t\tpgste.usage = PGSTE_GPS_USAGE_UNUSED;\n-\t\tif (ptep-\u003eh.i)\n-\t\t\tres = 1;\n-\t\tbreak;\n-\tcase ESSA_SET_VOLATILE:\n-\t\tpgste.usage = PGSTE_GPS_USAGE_VOLATILE;\n-\t\tif (ptep-\u003eh.i)\n-\t\t\tres = 1;\n-\t\tbreak;\n-\tcase ESSA_SET_POT_VOLATILE:\n-\t\tif (!ptep-\u003eh.i) {\n-\t\t\tpgste.usage = PGSTE_GPS_USAGE_POT_VOLATILE;\n-\t\t} else if (pgste.zero) {\n-\t\t\tpgste.usage = PGSTE_GPS_USAGE_VOLATILE;\n-\t\t} else if (!pgste.gc) {\n-\t\t\tpgste.usage = PGSTE_GPS_USAGE_VOLATILE;\n-\t\t\tres = 1;\n-\t\t}\n-\t\tbreak;\n-\tcase ESSA_SET_STABLE_RESIDENT:\n-\t\tpgste.usage = PGSTE_GPS_USAGE_STABLE;\n-\t\t/*\n-\t\t * Since the resident state can go away any time after this\n-\t\t * call, we will not make this page resident. We can revisit\n-\t\t * this decision if a guest will ever start using this.\n-\t\t */\n-\t\tbreak;\n-\tcase ESSA_SET_STABLE_IF_RESIDENT:\n-\t\tif (!ptep-\u003eh.i)\n-\t\t\tpgste.usage = PGSTE_GPS_USAGE_STABLE;\n-\t\tbreak;\n-\tcase ESSA_SET_STABLE_NODAT:\n-\t\tpgste.usage = PGSTE_GPS_USAGE_STABLE;\n-\t\tpgste.nodat = 1;\n-\t\tbreak;\n-\tdefault:\n-\t\tWARN_ONCE(1, \"Invalid ORC!\");\n-\t\tres = -1;\n-\t\tbreak;\n-\t}\n-\t/* If we are discarding a page, set it to logical zero. */\n-\tpgste.zero = res == 1;\n-\tif (orc \u003e 0) {\n-\t\t*dirty = !pgste.cmma_d;\n-\t\tpgste.cmma_d = 1;\n-\t}\n-\n-\tpgste_set_unlock(ptep, pgste);\n-\n-\treturn res;\n-}\n-\n-static long dat_reset_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n-{\n-\tunion pgste pgste;\n-\n-\tpgste = pgste_get_lock(ptep);\n-\tpgste.usage = 0;\n-\tpgste.nodat = 0;\n-\tpgste.cmma_d = 0;\n-\tpgste_set_unlock(ptep, pgste);\n-\tif (need_resched())\n-\t\treturn next;\n-\treturn 0;\n-}\n-\n-long dat_reset_cmma(union asce asce, gfn_t start)\n-{\n-\tconst struct dat_walk_ops dat_reset_cmma_ops = {\n-\t\t.pte_entry = dat_reset_cmma_pte,\n-\t};\n-\n-\treturn _dat_walk_gfn_range(start, asce_end(asce), asce, \u0026dat_reset_cmma_ops,\n-\t\t\t\t DAT_WALK_IGN_HOLES, NULL);\n-}\n-\n-struct dat_get_cmma_state {\n-\tgfn_t start;\n-\tgfn_t end;\n-\tunsigned int count;\n-\tu8 *values;\n-\tatomic64_t *remaining;\n-};\n-\n-static long __dat_peek_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n-{\n-\tstruct dat_get_cmma_state *state = walk-\u003epriv;\n-\tunion pgste pgste;\n-\n-\tpgste = pgste_get_lock(ptep);\n-\tstate-\u003evalues[gfn - walk-\u003estart] = pgste.usage | (pgste.nodat \u003c\u003c 6);\n-\tpgste_set_unlock(ptep, pgste);\n-\tstate-\u003eend = next;\n-\n-\treturn 0;\n-}\n-\n-static long __dat_peek_cmma_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n-{\n-\tstruct dat_get_cmma_state *state = walk-\u003epriv;\n-\n-\tif (crstep-\u003eh.i)\n-\t\tstate-\u003eend = min(walk-\u003eend, next);\n-\treturn 0;\n-}\n-\n-int dat_peek_cmma(gfn_t start, union asce asce, unsigned int *count, u8 *values)\n-{\n-\tconst struct dat_walk_ops ops = {\n-\t\t.pte_entry = __dat_peek_cmma_pte,\n-\t\t.pmd_entry = __dat_peek_cmma_crste,\n-\t\t.pud_entry = __dat_peek_cmma_crste,\n-\t\t.p4d_entry = __dat_peek_cmma_crste,\n-\t\t.pgd_entry = __dat_peek_cmma_crste,\n-\t};\n-\tstruct dat_get_cmma_state state = { .values = values, };\n-\tint rc;\n-\n-\trc = _dat_walk_gfn_range(start, start + *count, asce, \u0026ops, DAT_WALK_DEFAULT, \u0026state);\n-\t*count = state.end \u003e= start ? state.end - start : 0;\n-\t/* Return success if at least one value was saved, otherwise an error. */\n-\treturn (rc == -EFAULT \u0026\u0026 *count \u003e 0) ? 0 : rc;\n-}\n-\n-static long __dat_get_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n-{\n-\tstruct dat_get_cmma_state *state = walk-\u003epriv;\n-\tunion pgste pgste;\n-\n-\tif (state-\u003estart != -1) {\n-\t\tif ((gfn - state-\u003eend) \u003e KVM_S390_MAX_BIT_DISTANCE)\n-\t\t\treturn 1;\n-\t\tif (gfn - state-\u003estart \u003e= state-\u003ecount)\n-\t\t\treturn 1;\n-\t}\n-\n-\tif (!READ_ONCE(*pgste_of(ptep)).cmma_d)\n-\t\treturn 0;\n-\n-\tpgste = pgste_get_lock(ptep);\n-\tif (pgste.cmma_d) {\n-\t\tif (state-\u003estart == -1)\n-\t\t\tstate-\u003estart = gfn;\n-\t\tpgste.cmma_d = 0;\n-\t\tatomic64_dec(state-\u003eremaining);\n-\t\tstate-\u003evalues[gfn - state-\u003estart] = pgste.usage | pgste.nodat \u003c\u003c 6;\n-\t\tstate-\u003eend = next;\n-\t}\n-\tpgste_set_unlock(ptep, pgste);\n-\treturn 0;\n-}\n-\n-int dat_get_cmma(union asce asce, gfn_t *start, unsigned int *count, u8 *values, atomic64_t *rem)\n-{\n-\tconst struct dat_walk_ops ops = { .pte_entry = __dat_get_cmma_pte, };\n-\tstruct dat_get_cmma_state state = {\n-\t\t.remaining = rem,\n-\t\t.values = values,\n-\t\t.count = *count,\n-\t\t.start = -1,\n-\t};\n-\n-\t_dat_walk_gfn_range(*start, asce_end(asce), asce, \u0026ops, DAT_WALK_IGN_HOLES, \u0026state);\n-\t/* If no dirty pages were found, wrap around and continue searching */\n-\tif (*start \u0026\u0026 state.start == -1)\n-\t\t_dat_walk_gfn_range(0, *start, asce, \u0026ops, DAT_WALK_IGN_HOLES, \u0026state);\n-\n-\tif (state.start == -1) {\n-\t\t*count = 0;\n-\t} else {\n-\t\t*count = state.end - state.start;\n-\t\t*start = state.start;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-struct dat_set_cmma_state {\n-\tunsigned long mask;\n-\tconst u8 *bits;\n-};\n-\n-static long __dat_set_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n-{\n-\tstruct dat_set_cmma_state *state = walk-\u003epriv;\n-\tunion pgste pgste, tmp;\n-\n-\ttmp.val = (state-\u003ebits[gfn - walk-\u003estart] \u003c\u003c 24) \u0026 state-\u003emask;\n-\n-\tpgste = pgste_get_lock(ptep);\n-\tpgste.usage = tmp.usage;\n-\tpgste.nodat = tmp.nodat;\n-\tpgste_set_unlock(ptep, pgste);\n-\n-\treturn 0;\n-}\n-\n-/**\n- * dat_set_cmma_bits() - Set CMMA bits for a range of guest pages.\n- * @mc: Cache used for allocations.\n- * @asce: The ASCE of the guest.\n- * @gfn: The guest frame of the fist page whose CMMA bits are to set.\n- * @count: How many pages need to be processed.\n- * @mask: Which PGSTE bits should be set.\n- * @bits: Points to an array with the CMMA attributes.\n- *\n- * This function sets the CMMA attributes for the given pages. If the input\n- * buffer has zero length, no action is taken, otherwise the attributes are\n- * set and the mm-\u003econtext.uses_cmm flag is set.\n- *\n- * Each byte in @bits contains new values for bits 32-39 of the PGSTE.\n- * Currently, only the fields NT and US are applied.\n- *\n- * Return: %0 in case of success, a negative error value otherwise.\n- */\n-int dat_set_cmma_bits(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,\n-\t\t unsigned long count, unsigned long mask, const uint8_t *bits)\n-{\n-\tconst struct dat_walk_ops ops = { .pte_entry = __dat_set_cmma_pte, };\n-\tstruct dat_set_cmma_state state = { .mask = mask, .bits = bits, };\n-\tunion crste *crstep;\n-\tunion pte *ptep;\n-\tgfn_t cur;\n-\tint rc;\n-\n-\tfor (cur = ALIGN_DOWN(gfn, _PAGE_ENTRIES); cur \u003c gfn + count; cur += _PAGE_ENTRIES) {\n-\t\trc = dat_entry_walk(mc, cur, asce, DAT_WALK_ALLOC, TABLE_TYPE_PAGE_TABLE,\n-\t\t\t\t \u0026crstep, \u0026ptep);\n-\t\tif (rc)\n-\t\t\treturn rc;\n-\t}\n-\treturn _dat_walk_gfn_range(gfn, gfn + count, asce, \u0026ops, DAT_WALK_IGN_HOLES, \u0026state);\n-}\ndiff --git a/arch/s390/kvm/dat.h b/arch/s390/kvm/gmap/dat.h\nsimilarity index 96%\nrename from arch/s390/kvm/dat.h\nrename to arch/s390/kvm/gmap/dat.h\nindex fad605305e05c3..12153a74815f22 100644\n--- a/arch/s390/kvm/dat.h\n+++ b/arch/s390/kvm/gmap/dat.h\n@@ -6,8 +6,8 @@\n * Author(s): Claudio Imbrenda \u003cimbrenda@linux.ibm.com\u003e\n */\n \n-#ifndef __KVM_S390_DAT_H\n-#define __KVM_S390_DAT_H\n+#ifndef ARCH_KVM_GMAP_DAT_H\n+#define ARCH_KVM_GMAP_DAT_H\n \n #include \u003clinux/radix-tree.h\u003e\n #include \u003clinux/refcount.h\u003e\n@@ -532,13 +532,6 @@ int dat_entry_walk(struct kvm_s390_mmu_cache *mc, gfn_t gfn, union asce asce, in\n void dat_free_level(struct crst_table *table, bool owns_ptes);\n struct crst_table *dat_alloc_crst_sleepable(unsigned long init);\n int dat_set_asce_limit(struct kvm_s390_mmu_cache *mc, union asce *asce, int newtype);\n-int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey);\n-int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,\n-\t\t\tunion skey skey, bool nq);\n-int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gfn_t gfn,\n-\t\t\t union skey skey, union skey *oldkey, bool nq, bool mr, bool mc);\n-int dat_reset_reference_bit(union asce asce, gfn_t gfn);\n-long dat_reset_skeys(union asce asce, gfn_t start);\n \n unsigned long dat_get_ptval(struct page_table *table, struct ptval_param param);\n void dat_set_ptval(struct page_table *table, struct ptval_param param, unsigned long val);\n@@ -548,13 +541,6 @@ int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gf\n int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn);\n bool dat_test_age_gfn(union asce asce, gfn_t start, gfn_t end);\n \n-int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state *state, bool *dirty);\n-long dat_reset_cmma(union asce asce, gfn_t start_gfn);\n-int dat_peek_cmma(gfn_t start, union asce asce, unsigned int *count, u8 *values);\n-int dat_get_cmma(union asce asce, gfn_t *start, unsigned int *count, u8 *values, atomic64_t *rem);\n-int dat_set_cmma_bits(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,\n-\t\t unsigned long count, unsigned long mask, const uint8_t *bits);\n-\n int kvm_s390_mmu_cache_topup(struct kvm_s390_mmu_cache *mc);\n \n #define GFP_KVM_S390_MMU_CACHE (GFP_ATOMIC | __GFP_ACCOUNT | __GFP_NOWARN)\n@@ -975,4 +961,4 @@ static inline bool crste_is_ucas(union crste crste)\n \treturn is_pmd(crste) \u0026\u0026 crste.h.i \u0026\u0026 crste.h.fc0.tl == 1 \u0026\u0026 crste.h.fc == 0;\n }\n \n-#endif /* __KVM_S390_DAT_H */\n+#endif /* ARCH_KVM_GMAP_DAT_H */\ndiff --git a/arch/s390/kvm/faultin.c b/arch/s390/kvm/gmap/faultin.c\nsimilarity index 96%\nrename from arch/s390/kvm/faultin.c\nrename to arch/s390/kvm/gmap/faultin.c\nindex fee80047bd94ff..b417ba575e6e35 100644\n--- a/arch/s390/kvm/faultin.c\n+++ b/arch/s390/kvm/gmap/faultin.c\n@@ -9,10 +9,15 @@\n #include \u003clinux/kvm_host.h\u003e\n \n #include \"gmap.h\"\n-#include \"trace.h\"\n #include \"faultin.h\"\n-\n-bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu);\n+#ifdef KVM_S390_ARM64\n+#include \"arm.h\"\n+#else\n+#include \"s390.h\"\n+#endif\n+\n+#define CREATE_TRACE_POINTS\n+#include \"trace-gmap.h\"\n \n /*\n * kvm_s390_faultin_gfn() - handle a dat fault.\ndiff --git a/arch/s390/kvm/faultin.h b/arch/s390/kvm/gmap/faultin.h\nsimilarity index 96%\nrename from arch/s390/kvm/faultin.h\nrename to arch/s390/kvm/gmap/faultin.h\nindex f86176d2769c5f..f343b6fb6f16aa 100644\n--- a/arch/s390/kvm/faultin.h\n+++ b/arch/s390/kvm/gmap/faultin.h\n@@ -6,8 +6,8 @@\n * Author(s): Claudio Imbrenda \u003cimbrenda@linux.ibm.com\u003e\n */\n \n-#ifndef __KVM_S390_FAULTIN_H\n-#define __KVM_S390_FAULTIN_H\n+#ifndef ARCH_KVM_GMAP_FAULTIN_H\n+#define ARCH_KVM_GMAP_FAULTIN_H\n \n #include \u003clinux/kvm_host.h\u003e\n \n@@ -89,4 +89,4 @@ static inline int kvm_s390_get_guest_pages(struct kvm *kvm, struct guest_fault *\n #define kvm_s390_array_needs_retry_safe(kvm, seq, array) \\\n \tkvm_s390_multiple_faults_need_retry(kvm, seq, array, ARRAY_SIZE(array), false)\n \n-#endif /* __KVM_S390_FAULTIN_H */\n+#endif /* ARCH_KVM_GMAP_FAULTIN_H */\ndiff --git a/arch/s390/kvm/gmap.c b/arch/s390/kvm/gmap/gmap.c\nsimilarity index 93%\nrename from arch/s390/kvm/gmap.c\nrename to arch/s390/kvm/gmap/gmap.c\nindex 298fbaecec28d5..b2ba6ee85fefab 100644\n--- a/arch/s390/kvm/gmap.c\n+++ b/arch/s390/kvm/gmap/gmap.c\n@@ -20,15 +20,17 @@\n #include \u003casm/gmap_helpers.h\u003e\n \n #include \"dat.h\"\n+#include \"sk.h\"\n+#include \"cmma.h\"\n+\n #include \"gmap.h\"\n-#include \"kvm-s390.h\"\n+#ifdef KVM_S390_ARM64\n+#include \"arm.h\"\n+#else\n+#include \"s390.h\"\n+#endif\n #include \"faultin.h\"\n \n-static inline bool kvm_s390_is_in_sie(struct kvm_vcpu *vcpu)\n-{\n-\treturn vcpu-\u003earch.sie_block-\u003eprog0c \u0026 PROG_IN_SIE;\n-}\n-\n static int gmap_limit_to_type(gfn_t limit)\n {\n \tif (!limit)\n@@ -256,29 +258,6 @@ int s390_replace_asce(struct gmap *gmap)\n \treturn 0;\n }\n \n-bool _gmap_unmap_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end, bool hint)\n-{\n-\tstruct kvm *kvm = gmap-\u003ekvm;\n-\tstruct kvm_vcpu *vcpu;\n-\tgfn_t prefix_gfn;\n-\tunsigned long i;\n-\n-\tif (is_shadow(gmap))\n-\t\treturn false;\n-\tkvm_for_each_vcpu(i, vcpu, kvm) {\n-\t\t/* Match against both prefix pages */\n-\t\tprefix_gfn = gpa_to_gfn(kvm_s390_get_prefix(vcpu));\n-\t\tif (prefix_gfn \u003c end \u0026\u0026 gfn \u003c= prefix_gfn + 1) {\n-\t\t\tif (hint \u0026\u0026 kvm_s390_is_in_sie(vcpu))\n-\t\t\t\treturn false;\n-\t\t\tVCPU_EVENT(vcpu, 2, \"gmap notifier for %llx-%llx\",\n-\t\t\t\t gfn_to_gpa(gfn), gfn_to_gpa(end));\n-\t\t\tkvm_s390_sync_request(KVM_REQ_REFRESH_GUEST_PREFIX, vcpu);\n-\t\t}\n-\t}\n-\treturn true;\n-}\n-\n struct clear_young_pte_priv {\n \tstruct gmap *gmap;\n \tbool young;\n@@ -945,39 +924,6 @@ void gmap_split_huge_pages(struct gmap *gmap)\n \t} while (start);\n }\n \n-static int _gmap_enable_skeys(struct gmap *gmap)\n-{\n-\tgfn_t start = 0;\n-\tint rc;\n-\n-\tif (uses_skeys(gmap))\n-\t\treturn 0;\n-\n-\tset_bit(GMAP_FLAG_USES_SKEYS, \u0026gmap-\u003eflags);\n-\trc = gmap_helper_disable_cow_sharing();\n-\tif (rc) {\n-\t\tclear_bit(GMAP_FLAG_USES_SKEYS, \u0026gmap-\u003eflags);\n-\t\treturn rc;\n-\t}\n-\n-\tdo {\n-\t\tscoped_guard(write_lock, \u0026gmap-\u003ekvm-\u003emmu_lock)\n-\t\t\tstart = dat_reset_skeys(gmap-\u003easce, start);\n-\t\tcond_resched();\n-\t} while (start);\n-\treturn 0;\n-}\n-\n-int gmap_enable_skeys(struct gmap *gmap)\n-{\n-\tint rc;\n-\n-\tmmap_write_lock(gmap-\u003ekvm-\u003emm);\n-\trc = _gmap_enable_skeys(gmap);\n-\tmmap_write_unlock(gmap-\u003ekvm-\u003emm);\n-\treturn rc;\n-}\n-\n static long _destroy_pages_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n {\n \tif (!ptep-\u003es.pr)\n@@ -1098,50 +1044,6 @@ int gmap_protect_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gf\n \treturn 0;\n }\n \n-static long __set_cmma_clean_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n-{\n-\tunion pgste pgste;\n-\n-\tpgste = pgste_get_lock(ptep);\n-\tpgste.cmma_d = 0;\n-\tpgste_set_unlock(ptep, pgste);\n-\n-\tif (need_resched())\n-\t\treturn next;\n-\treturn 0;\n-}\n-\n-static long __set_cmma_dirty_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n-{\n-\tunion pgste pgste;\n-\n-\tpgste = pgste_get_lock(ptep);\n-\tif (!pgste.cmma_d)\n-\t\tatomic64_inc(walk-\u003epriv);\n-\tpgste.cmma_d = 1;\n-\tpgste_set_unlock(ptep, pgste);\n-\n-\tif (need_resched())\n-\t\treturn next;\n-\treturn 0;\n-}\n-\n-void _gmap_set_cmma_all(struct gmap *gmap, bool dirty)\n-{\n-\tconst struct dat_walk_ops ops = {\n-\t\t.pte_entry = dirty ? __set_cmma_dirty_pte : __set_cmma_clean_pte,\n-\t};\n-\tgfn_t gfn = 0;\n-\n-\tdo {\n-\t\tscoped_guard(read_lock, \u0026gmap-\u003ekvm-\u003emmu_lock)\n-\t\t\tgfn = _dat_walk_gfn_range(gfn, asce_end(gmap-\u003easce), gmap-\u003easce, \u0026ops,\n-\t\t\t\t\t\t DAT_WALK_IGN_HOLES,\n-\t\t\t\t\t\t \u0026gmap-\u003ekvm-\u003earch.cmma_dirty_pages);\n-\t\tcond_resched();\n-\t} while (gfn);\n-}\n-\n static void gmap_unshadow_level(struct gmap *sg, gfn_t r_gfn, int level)\n {\n \tunsigned long align = PAGE_SIZE;\ndiff --git a/arch/s390/kvm/gmap.h b/arch/s390/kvm/gmap/gmap.h\nsimilarity index 94%\nrename from arch/s390/kvm/gmap.h\nrename to arch/s390/kvm/gmap/gmap.h\nindex 39938d363ec9bb..0500c8c6c9cac4 100644\n--- a/arch/s390/kvm/gmap.h\n+++ b/arch/s390/kvm/gmap/gmap.h\n@@ -7,10 +7,13 @@\n * Claudio Imbrenda \u003cimbrenda@linux.ibm.com\u003e\n */\n \n-#ifndef ARCH_KVM_S390_GMAP_H\n-#define ARCH_KVM_S390_GMAP_H\n+#ifndef ARCH_KVM_GMAP_GMAP_H\n+#define ARCH_KVM_GMAP_GMAP_H\n+\n+#include \u003clinux/kvm_host.h\u003e\n \n #include \"dat.h\"\n+#include \"prefix.h\"\n \n /**\n * enum gmap_flags - Flags of a gmap.\n@@ -98,13 +101,11 @@ int gmap_set_limit(struct gmap *gmap, gfn_t limit);\n int gmap_ucas_translate(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, gpa_t *gaddr);\n int gmap_ucas_map(struct gmap *gmap, gfn_t p_gfn, gfn_t c_gfn, unsigned long count);\n void gmap_ucas_unmap(struct gmap *gmap, gfn_t c_gfn, unsigned long count);\n-int gmap_enable_skeys(struct gmap *gmap);\n int gmap_pv_destroy_range(struct gmap *gmap, gfn_t start, gfn_t end, bool interruptible);\n int gmap_insert_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gfn,\n \t\t gfn_t r_gfn, int level);\n int gmap_protect_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gfn, gfn_t r_gfn,\n \t\t kvm_pfn_t pfn, int level, bool wr);\n-void _gmap_set_cmma_all(struct gmap *gmap, bool dirty);\n void _gmap_handle_vsie_unshadow_event(struct gmap *parent, gfn_t gfn);\n struct gmap *gmap_create_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *gmap,\n \t\t\t\tunion asce asce, int edat_level);\n@@ -158,16 +159,6 @@ static inline void gmap_handle_vsie_unshadow_event(struct gmap *parent, gfn_t gf\n \t\t_gmap_handle_vsie_unshadow_event(parent, gfn);\n }\n \n-static inline bool gmap_mkold_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end)\n-{\n-\treturn _gmap_unmap_prefix(gmap, gfn, end, true);\n-}\n-\n-static inline bool gmap_unmap_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end)\n-{\n-\treturn _gmap_unmap_prefix(gmap, gfn, end, false);\n-}\n-\n /**\n * pte_needs_unshadow() -- Check if the pte operations triggers unshadowing.\n * @oldpte: the previous value for the guest pte.\n@@ -198,16 +189,6 @@ static inline bool pte_needs_unshadow(union pte oldpte, union pte newpte, union\n \treturn !newpte.h.p || !newpte.s.pr;\n }\n \n-static inline void gmap_set_cmma_all_dirty(struct gmap *gmap)\n-{\n-\t_gmap_set_cmma_all(gmap, true);\n-}\n-\n-static inline void gmap_set_cmma_all_clean(struct gmap *gmap)\n-{\n-\t_gmap_set_cmma_all(gmap, false);\n-}\n-\n static inline union pgste _gmap_ptep_xchg(struct gmap *gmap, union pte *ptep, union pte newpte,\n \t\t\t\t\t union pgste pgste, gfn_t gfn, bool needs_lock)\n {\n@@ -330,4 +311,17 @@ static inline bool gmap_is_shadow_valid(struct gmap *sg, union asce asce, int ed\n \treturn sg-\u003eguest_asce.val == asce.val \u0026\u0026 sg-\u003eedat_level == edat_level;\n }\n \n-#endif /* ARCH_KVM_S390_GMAP_H */\n+int gmap_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log);\n+int gmap_prepare_memory_region(struct kvm *kvm,\n+\t\t\t const struct kvm_memory_slot *old,\n+\t\t\t struct kvm_memory_slot *new,\n+\t\t\t enum kvm_mr_change change);\n+void gmap_commit_memory_region(struct kvm *kvm,\n+\t\t\t struct kvm_memory_slot *old,\n+\t\t\t const struct kvm_memory_slot *new,\n+\t\t\t enum kvm_mr_change change);\n+bool gmap_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range);\n+long gmap_pre_fault_memory(struct kvm_vcpu *vcpu,\n+\t\t\t struct kvm_pre_fault_memory *range);\n+\n+#endif /* ARCH_KVM_GMAP_GMAP_H */\ndiff --git a/arch/s390/kvm/gmap/mmu.c b/arch/s390/kvm/gmap/mmu.c\nnew file mode 100644\nindex 00000000000000..5bb6609b974b29\n--- /dev/null\n+++ b/arch/s390/kvm/gmap/mmu.c\n@@ -0,0 +1,193 @@\n+// SPDX-License-Identifier: GPL-2.0\n+\n+#include \u003clinux/kvm_types.h\u003e\n+#include \u003clinux/kvm_host.h\u003e\n+\n+#ifdef KVM_S390_ARM64\n+#include \"arm.h\"\n+#else\n+#include \"s390.h\"\n+#endif\n+#include \"gmap.h\"\n+#include \"dat.h\"\n+#include \"faultin.h\"\n+\n+/*\n+ * Get (and clear) the dirty memory log for a memory slot.\n+ */\n+int gmap_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)\n+{\n+\tint r;\n+\tunsigned long n;\n+\tstruct kvm_memory_slot *memslot;\n+\tint is_dirty;\n+\n+\tif (kvm_is_ucontrol(kvm))\n+\t\treturn -EINVAL;\n+\n+\tmutex_lock(\u0026kvm-\u003eslots_lock);\n+\n+\tr = -EINVAL;\n+\tif (log-\u003eslot \u003e= KVM_USER_MEM_SLOTS)\n+\t\tgoto out;\n+\n+\tr = kvm_get_dirty_log(kvm, log, \u0026is_dirty, \u0026memslot);\n+\tif (r)\n+\t\tgoto out;\n+\n+\t/* Clear the dirty log */\n+\tif (is_dirty) {\n+\t\tn = kvm_dirty_bitmap_bytes(memslot);\n+\t\tmemset(memslot-\u003edirty_bitmap, 0, n);\n+\t}\n+\tr = 0;\n+out:\n+\tmutex_unlock(\u0026kvm-\u003eslots_lock);\n+\treturn r;\n+}\n+\n+int gmap_prepare_memory_region(struct kvm *kvm,\n+\t\t\t const struct kvm_memory_slot *old,\n+\t\t\t struct kvm_memory_slot *new,\n+\t\t\t enum kvm_mr_change change)\n+{\n+\tif (kvm_is_ucontrol(kvm) \u0026\u0026 new \u0026\u0026 new-\u003eid \u003c KVM_USER_MEM_SLOTS)\n+\t\treturn -EINVAL;\n+\n+\t/* When we are protected, we should not change the memory slots */\n+\tif (kvm_s390_pv_get_handle(kvm))\n+\t\treturn -EINVAL;\n+\n+\tif (change != KVM_MR_DELETE \u0026\u0026 change != KVM_MR_FLAGS_ONLY) {\n+\t\t/*\n+\t\t * A few sanity checks. The memory in userland is ok to be\n+\t\t * fragmented into various different vmas. It is okay to mmap()\n+\t\t * and munmap() stuff in this slot after doing this call at any\n+\t\t * time.\n+\t\t */\n+\t\tif (new-\u003euserspace_addr \u0026 ~PAGE_MASK)\n+\t\t\treturn -EINVAL;\n+\t\tif ((new-\u003ebase_gfn + new-\u003enpages) * PAGE_SIZE \u003e kvm-\u003earch.mem_limit)\n+\t\t\treturn -EINVAL;\n+\t\tif (!asce_contains_gfn(kvm-\u003earch.gmap-\u003easce, new-\u003ebase_gfn + new-\u003enpages - 1))\n+\t\t\treturn -EINVAL;\n+\t}\n+\n+\tif (!kvm_s390_is_migration_mode(kvm))\n+\t\treturn 0;\n+\n+\t/*\n+\t * Turn off migration mode when:\n+\t * - userspace creates a new memslot with dirty logging off,\n+\t * - userspace modifies an existing memslot (MOVE or FLAGS_ONLY) and\n+\t * dirty logging is turned off.\n+\t * Migration mode expects dirty page logging being enabled to store\n+\t * its dirty bitmap.\n+\t */\n+\tif (change != KVM_MR_DELETE \u0026\u0026\n+\t !(new-\u003eflags \u0026 KVM_MEM_LOG_DIRTY_PAGES))\n+\t\tWARN(kvm_s390_vm_stop_migration(kvm),\n+\t\t \"Failed to stop migration mode\");\n+\n+\treturn 0;\n+}\n+\n+void gmap_commit_memory_region(struct kvm *kvm,\n+\t\t\t struct kvm_memory_slot *old,\n+\t\t\t const struct kvm_memory_slot *new,\n+\t\t\t enum kvm_mr_change change)\n+{\n+\tstruct kvm_s390_mmu_cache *mc = NULL;\n+\tint rc = 0;\n+\n+\tif (change == KVM_MR_FLAGS_ONLY)\n+\t\treturn;\n+\n+\tmc = kvm_s390_new_mmu_cache();\n+\tif (!mc) {\n+\t\trc = -ENOMEM;\n+\t\tgoto out;\n+\t}\n+\n+\tscoped_guard(write_lock, \u0026kvm-\u003emmu_lock) {\n+\t\tswitch (change) {\n+\t\tcase KVM_MR_DELETE:\n+\t\t\trc = dat_delete_slot(mc, kvm-\u003earch.gmap-\u003easce, old-\u003ebase_gfn, old-\u003enpages);\n+\t\t\tbreak;\n+\t\tcase KVM_MR_MOVE:\n+\t\t\trc = dat_delete_slot(mc, kvm-\u003earch.gmap-\u003easce, old-\u003ebase_gfn, old-\u003enpages);\n+\t\t\tif (rc)\n+\t\t\t\tbreak;\n+\t\t\tfallthrough;\n+\t\tcase KVM_MR_CREATE:\n+\t\t\trc = dat_create_slot(mc, kvm-\u003earch.gmap-\u003easce, new-\u003ebase_gfn, new-\u003enpages);\n+\t\t\tbreak;\n+\t\tcase KVM_MR_FLAGS_ONLY:\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tWARN(1, \"Unknown KVM MR CHANGE: %d\\n\", change);\n+\t\t}\n+\t}\n+out:\n+\tif (rc)\n+\t\tpr_warn(\"failed to commit memory region\\n\");\n+\tkvm_s390_free_mmu_cache(mc);\n+}\n+\n+/**\n+ * gmap_test_age_gfn() - test young\n+ * @kvm: the kvm instance\n+ * @range: the range of guest addresses whose young status needs to be cleared\n+ *\n+ * Context: called by KVM common code without holding the kvm mmu lock\n+ * Return: true if any page in the given range is young, otherwise 0.\n+ */\n+bool gmap_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)\n+{\n+\tscoped_guard(read_lock, \u0026kvm-\u003emmu_lock)\n+\t\treturn dat_test_age_gfn(kvm-\u003earch.gmap-\u003easce, range-\u003estart, range-\u003eend);\n+}\n+\n+/**\n+ * gmap_pre_fault_memory() - pre-fault and link gmap dat tables\n+ * @vcpu: the vcpu that shall appear to have generated the fault-in.\n+ * @range: the range that needs to be faulted in.\n+ *\n+ * The first page of the given range is faulted in and the corresponding gmap\n+ * page tables are created, as if the given vCPU had performed a read\n+ * operation.\n+ * If the range starts outside any memslots, an error is returned. An error is\n+ * also returned for UCONTROL VMs, which should instead use the\n+ * KVM_S390_VCPU_FAULT ioctl.\n+ *\n+ * Return:\n+ * * %-ENOENT if the range lies outside of a memslot.\n+ * * %-EINVAL in case of invalid state (for example if the VM is UCONTROL).\n+ * * %-EIO if errors happen while faulting-in the page (will trigger a warning\n+ * in the caller).\n+ * * other error codes \u003c 0 in case of other errors.\n+ * * otherwise a number \u003e 0 of bytes that have been faulted in successfully.\n+ */\n+long gmap_pre_fault_memory(struct kvm_vcpu *vcpu, struct kvm_pre_fault_memory *range)\n+{\n+\tstruct guest_fault f = { .gfn = gpa_to_gfn(range-\u003egpa), };\n+\tgpa_t end;\n+\tint rc;\n+\n+\tif (kvm_is_ucontrol(vcpu-\u003ekvm))\n+\t\treturn -EINVAL;\n+\n+\trc = kvm_s390_faultin_gfn(vcpu, NULL, \u0026f);\n+\tif (rc == PGM_ADDRESSING)\n+\t\treturn -ENOENT;\n+\tif (rc \u003e 0)\n+\t\treturn -EIO;\n+\tif (rc \u003c 0)\n+\t\treturn rc;\n+\n+\tif (f.ptep)\n+\t\treturn PAGE_SIZE;\n+\n+\tend = ALIGN(range-\u003egpa + PAGE_SIZE, f.crste_region3 ? _REGION3_SIZE : HPAGE_SIZE);\n+\treturn min(range-\u003esize, end - range-\u003egpa);\n+}\ndiff --git a/arch/s390/kvm/gmap/prefix-stubs.c b/arch/s390/kvm/gmap/prefix-stubs.c\nnew file mode 100644\nindex 00000000000000..d1d6286f454a74\n--- /dev/null\n+++ b/arch/s390/kvm/gmap/prefix-stubs.c\n@@ -0,0 +1,21 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * These stubs are used when building gmap for non-s390 guests\n+ * that don't need prefix page tracking.\n+ */\n+\n+#include \u003clinux/kvm_host.h\u003e\n+#include \u003clinux/kvm_types.h\u003e\n+\n+#include \"dat.h\"\n+#include \"prefix.h\"\n+\n+bool _gmap_unmap_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end, bool hint)\n+{\n+\treturn true;\n+}\n+\n+int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn)\n+{\n+\treturn 0;\n+}\ndiff --git a/arch/s390/kvm/gmap/prefix.c b/arch/s390/kvm/gmap/prefix.c\nnew file mode 100644\nindex 00000000000000..44caffed2da132\n--- /dev/null\n+++ b/arch/s390/kvm/gmap/prefix.c\n@@ -0,0 +1,80 @@\n+// SPDX-License-Identifier: GPL-2.0\n+\n+#include \u003clinux/kvm_host.h\u003e\n+#include \u003clinux/kvm_types.h\u003e\n+\n+#include \"gmap.h\"\n+#include \"dat.h\"\n+#include \"prefix.h\"\n+#include \"../s390/s390.h\"\n+\n+bool _gmap_unmap_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end, bool hint)\n+{\n+\tstruct kvm *kvm = gmap-\u003ekvm;\n+\tstruct kvm_vcpu *vcpu;\n+\tgfn_t prefix_gfn;\n+\tunsigned long i;\n+\n+\tif (is_shadow(gmap))\n+\t\treturn false;\n+\tkvm_for_each_vcpu(i, vcpu, kvm) {\n+\t\t/* Match against both prefix pages */\n+\t\tprefix_gfn = gpa_to_gfn(kvm_s390_get_prefix(vcpu));\n+\t\tif (prefix_gfn \u003c end \u0026\u0026 gfn \u003c= prefix_gfn + 1) {\n+\t\t\tif (hint \u0026\u0026 kvm_s390_is_in_sie(vcpu))\n+\t\t\t\treturn false;\n+\t\t\tVCPU_EVENT(vcpu, 2, \"gmap notifier for %llx-%llx\",\n+\t\t\t\t gfn_to_gpa(gfn), gfn_to_gpa(end));\n+\t\t\tkvm_s390_sync_request(KVM_REQ_REFRESH_GUEST_PREFIX, vcpu);\n+\t\t}\n+\t}\n+\treturn true;\n+}\n+\n+static long dat_set_pn_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n+{\n+\tunion crste newcrste, oldcrste;\n+\tint *n = walk-\u003epriv;\n+\n+\tdo {\n+\t\toldcrste = READ_ONCE(*crstep);\n+\t\tif (!oldcrste.h.fc || oldcrste.h.i || oldcrste.h.p)\n+\t\t\treturn 0;\n+\t\tif (oldcrste.s.fc1.prefix_notif)\n+\t\t\tbreak;\n+\t\tnewcrste = oldcrste;\n+\t\tnewcrste.s.fc1.prefix_notif = 1;\n+\t} while (!dat_crstep_xchg_atomic(crstep, oldcrste, newcrste, gfn, walk-\u003easce));\n+\t*n = 2;\n+\treturn 0;\n+}\n+\n+static long dat_set_pn_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n+{\n+\tint *n = walk-\u003epriv;\n+\tunion pgste pgste;\n+\n+\tpgste = pgste_get_lock(ptep);\n+\tif (!ptep-\u003eh.i \u0026\u0026 !ptep-\u003eh.p) {\n+\t\tpgste.prefix_notif = 1;\n+\t\t*n += 1;\n+\t}\n+\tpgste_set_unlock(ptep, pgste);\n+\treturn 0;\n+}\n+\n+int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn)\n+{\n+\tstatic const struct dat_walk_ops ops = {\n+\t\t.pte_entry = dat_set_pn_pte,\n+\t\t.pmd_entry = dat_set_pn_crste,\n+\t\t.pud_entry = dat_set_pn_crste,\n+\t};\n+\n+\tint n = 0;\n+\n+\t_dat_walk_gfn_range(gfn, gfn + 2, asce, \u0026ops, DAT_WALK_IGN_HOLES, \u0026n);\n+\tif (n != 2)\n+\t\treturn -EAGAIN;\n+\treturn 0;\n+}\ndiff --git a/arch/s390/kvm/gmap/prefix.h b/arch/s390/kvm/gmap/prefix.h\nnew file mode 100644\nindex 00000000000000..f1f3ace24f0321\n--- /dev/null\n+++ b/arch/s390/kvm/gmap/prefix.h\n@@ -0,0 +1,68 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+\n+#ifndef ARCH_KVM_GMAP_PREFIX_H\n+#define ARCH_KVM_GMAP_PREFIX_H\n+\n+#include \u003clinux/types.h\u003e\n+#include \u003clinux/kvm_types.h\u003e\n+\n+struct gmap;\n+union asce;\n+\n+/**\n+ * _gmap_unmap_prefix() - Notify vCPUs if prefix pages are affected\n+ * @gmap: The gmap\n+ * @gfn: Start of the range\n+ * @end: End of the range (exclusive)\n+ * @hint: If true, skip notification if vCPU is in SIE\n+ *\n+ * Check if any vCPU's prefix pages fall within the given range and\n+ * request prefix refresh if needed.\n+ *\n+ * Return: false if notification was skipped due to hint, true otherwise\n+ */\n+bool _gmap_unmap_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end, bool hint);\n+\n+/**\n+ * dat_set_prefix_notif_bit() - Set prefix notification bits\n+ * @asce: The address space control element\n+ * @gfn: Guest frame number of the prefix area\n+ *\n+ * Set the prefix notification bit in the page table entries for the\n+ * two prefix pages starting at @gfn.\n+ *\n+ * Return: 0 on success, -EAGAIN if not all bits could be set\n+ */\n+int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn);\n+\n+/**\n+ * gmap_mkold_prefix() - Mark prefix pages as old\n+ * @gmap: The gmap\n+ * @gfn: Start of the range\n+ * @end: End of the range (exclusive)\n+ *\n+ * Inline wrapper that calls _gmap_unmap_prefix with hint=true.\n+ *\n+ * Return: Result from _gmap_unmap_prefix\n+ */\n+static inline bool gmap_mkold_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end)\n+{\n+\treturn _gmap_unmap_prefix(gmap, gfn, end, true);\n+}\n+\n+/**\n+ * gmap_unmap_prefix() - Unconditionally notify about prefix pages\n+ * @gmap: The gmap\n+ * @gfn: Start of the range\n+ * @end: End of the range (exclusive)\n+ *\n+ * Inline wrapper that calls _gmap_unmap_prefix with hint=false.\n+ *\n+ * Return: Result from _gmap_unmap_prefix\n+ */\n+static inline bool gmap_unmap_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end)\n+{\n+\treturn _gmap_unmap_prefix(gmap, gfn, end, false);\n+}\n+\n+#endif /* ARCH_KVM_GMAP_PREFIX_H */\ndiff --git a/arch/s390/kvm/gmap/sk.c b/arch/s390/kvm/gmap/sk.c\nnew file mode 100644\nindex 00000000000000..eedd6eef670982\n--- /dev/null\n+++ b/arch/s390/kvm/gmap/sk.c\n@@ -0,0 +1,264 @@\n+// SPDX-License-Identifier: GPL-2.0\n+\n+#include \u003clinux/mm.h\u003e\n+#include \u003clinux/kvm_host.h\u003e\n+#include \u003clinux/pgalloc.h\u003e\n+#include \u003casm/gmap_helpers.h\u003e\n+#include \"sk.h\"\n+#include \"gmap.h\"\n+\n+static void dat_update_ptep_sd(union pgste old, union pgste pgste, union pte *ptep)\n+{\n+\tif (pgste.acc != old.acc || pgste.fp != old.fp || pgste.gr != old.gr || pgste.gc != old.gc)\n+\t\t__atomic64_or(_PAGE_SD, \u0026ptep-\u003eval);\n+}\n+\n+int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey)\n+{\n+\tunion crste *crstep;\n+\tunion pgste pgste;\n+\tunion pte *ptep;\n+\tint rc;\n+\n+\tskey-\u003eskey = 0;\n+\trc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, \u0026crstep, \u0026ptep);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\tif (!ptep) {\n+\t\tunion crste crste;\n+\n+\t\tcrste = READ_ONCE(*crstep);\n+\t\tif (!crste.h.fc || !crste.s.fc1.pr)\n+\t\t\treturn 0;\n+\t\tskey-\u003eskey = page_get_storage_key(large_crste_to_phys(crste, gfn));\n+\t\treturn 0;\n+\t}\n+\tpgste = pgste_get_lock(ptep);\n+\tif (ptep-\u003eh.i) {\n+\t\tskey-\u003eacc = pgste.acc;\n+\t\tskey-\u003efp = pgste.fp;\n+\t} else {\n+\t\tskey-\u003eskey = page_get_storage_key(pte_origin(*ptep));\n+\t}\n+\tskey-\u003er |= pgste.gr;\n+\tskey-\u003ec |= pgste.gc;\n+\tpgste_set_unlock(ptep, pgste);\n+\treturn 0;\n+}\n+\n+int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,\n+\t\t\tunion skey skey, bool nq)\n+{\n+\tunion pgste pgste, old;\n+\tunion crste *crstep;\n+\tunion pte *ptep;\n+\tint rc;\n+\n+\trc = dat_entry_walk(mc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,\n+\t\t\t \u0026crstep, \u0026ptep);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\tif (!ptep) {\n+\t\tpage_set_storage_key(large_crste_to_phys(*crstep, gfn), skey.skey, !nq);\n+\t\treturn 0;\n+\t}\n+\n+\told = pgste_get_lock(ptep);\n+\tpgste = old;\n+\n+\tpgste.acc = skey.acc;\n+\tpgste.fp = skey.fp;\n+\tpgste.gc = skey.c;\n+\tpgste.gr = skey.r;\n+\n+\tif (!ptep-\u003eh.i) {\n+\t\tunion skey old_skey;\n+\n+\t\told_skey.skey = page_get_storage_key(pte_origin(*ptep));\n+\t\tpgste.hc |= old_skey.c;\n+\t\tpgste.hr |= old_skey.r;\n+\t\told_skey.c = old.gc;\n+\t\told_skey.r = old.gr;\n+\t\tskey.r = 0;\n+\t\tskey.c = 0;\n+\t\tpage_set_storage_key(pte_origin(*ptep), skey.skey, !nq);\n+\t}\n+\n+\tdat_update_ptep_sd(old, pgste, ptep);\n+\tpgste_set_unlock(ptep, pgste);\n+\treturn 0;\n+}\n+\n+static bool page_cond_set_storage_key(phys_addr_t paddr, union skey skey, union skey *oldkey,\n+\t\t\t\t bool nq, bool mr, bool mc)\n+{\n+\toldkey-\u003eskey = page_get_storage_key(paddr);\n+\tif (oldkey-\u003eacc == skey.acc \u0026\u0026 oldkey-\u003efp == skey.fp \u0026\u0026\n+\t (oldkey-\u003er == skey.r || mr) \u0026\u0026 (oldkey-\u003ec == skey.c || mc))\n+\t\treturn false;\n+\tpage_set_storage_key(paddr, skey.skey, !nq);\n+\treturn true;\n+}\n+\n+int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gfn_t gfn,\n+\t\t\t union skey skey, union skey *oldkey, bool nq, bool mr, bool mc)\n+{\n+\tunion pgste pgste, old;\n+\tunion crste *crstep;\n+\tunion skey prev;\n+\tunion pte *ptep;\n+\tint rc;\n+\n+\trc = dat_entry_walk(mmc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,\n+\t\t\t \u0026crstep, \u0026ptep);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\tif (!ptep)\n+\t\treturn page_cond_set_storage_key(large_crste_to_phys(*crstep, gfn), skey, oldkey,\n+\t\t\t\t\t\t nq, mr, mc);\n+\n+\told = pgste_get_lock(ptep);\n+\tpgste = old;\n+\n+\trc = 1;\n+\tpgste.acc = skey.acc;\n+\tpgste.fp = skey.fp;\n+\tpgste.gc = skey.c;\n+\tpgste.gr = skey.r;\n+\n+\tif (!ptep-\u003eh.i) {\n+\t\trc = page_cond_set_storage_key(pte_origin(*ptep), skey, \u0026prev, nq, mr, mc);\n+\t\tpgste.hc |= prev.c;\n+\t\tpgste.hr |= prev.r;\n+\t\tprev.c |= old.gc;\n+\t\tprev.r |= old.gr;\n+\t} else {\n+\t\tprev.acc = old.acc;\n+\t\tprev.fp = old.fp;\n+\t\tprev.c = old.gc;\n+\t\tprev.r = old.gr;\n+\t}\n+\tif (oldkey)\n+\t\t*oldkey = prev;\n+\n+\tdat_update_ptep_sd(old, pgste, ptep);\n+\tpgste_set_unlock(ptep, pgste);\n+\treturn rc;\n+}\n+\n+int dat_reset_reference_bit(union asce asce, gfn_t gfn)\n+{\n+\tunion pgste pgste, old;\n+\tunion crste *crstep;\n+\tunion pte *ptep;\n+\tint rc;\n+\n+\trc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, \u0026crstep, \u0026ptep);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\tif (!ptep) {\n+\t\tunion crste crste = READ_ONCE(*crstep);\n+\n+\t\tif (!crste.h.fc || !crste.s.fc1.pr)\n+\t\t\treturn 0;\n+\t\treturn page_reset_referenced(large_crste_to_phys(*crstep, gfn));\n+\t}\n+\told = pgste_get_lock(ptep);\n+\tpgste = old;\n+\n+\tif (!ptep-\u003eh.i) {\n+\t\trc = page_reset_referenced(pte_origin(*ptep));\n+\t\tpgste.hr = rc \u003e\u003e 1;\n+\t}\n+\trc |= (pgste.gr \u003c\u003c 1) | pgste.gc;\n+\tpgste.gr = 0;\n+\n+\tdat_update_ptep_sd(old, pgste, ptep);\n+\tpgste_set_unlock(ptep, pgste);\n+\treturn rc;\n+}\n+\n+static long dat_reset_skeys_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n+{\n+\tunion pgste pgste;\n+\n+\tpgste = pgste_get_lock(ptep);\n+\tpgste.acc = 0;\n+\tpgste.fp = 0;\n+\tpgste.gr = 0;\n+\tpgste.gc = 0;\n+\tif (ptep-\u003es.pr)\n+\t\tpage_set_storage_key(pte_origin(*ptep), PAGE_DEFAULT_KEY, 1);\n+\tpgste_set_unlock(ptep, pgste);\n+\n+\tif (need_resched())\n+\t\treturn next;\n+\treturn 0;\n+}\n+\n+static long dat_reset_skeys_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)\n+{\n+\tphys_addr_t addr, end, origin = crste_origin_large(*crstep);\n+\n+\tif (!crstep-\u003eh.fc || !crstep-\u003es.fc1.pr)\n+\t\treturn 0;\n+\n+\taddr = ((max(gfn, walk-\u003estart) - gfn) \u003c\u003c PAGE_SHIFT) + origin;\n+\tend = ((min(next, walk-\u003eend) - gfn) \u003c\u003c PAGE_SHIFT) + origin;\n+\twhile (ALIGN(addr + 1, _SEGMENT_SIZE) \u003c= end)\n+\t\taddr = sske_frame(addr, PAGE_DEFAULT_KEY);\n+\tfor ( ; addr \u003c end; addr += PAGE_SIZE)\n+\t\tpage_set_storage_key(addr, PAGE_DEFAULT_KEY, 1);\n+\n+\tif (need_resched())\n+\t\treturn next;\n+\treturn 0;\n+}\n+\n+long dat_reset_skeys(union asce asce, gfn_t start)\n+{\n+\tconst struct dat_walk_ops ops = {\n+\t\t.pte_entry = dat_reset_skeys_pte,\n+\t\t.pmd_entry = dat_reset_skeys_crste,\n+\t\t.pud_entry = dat_reset_skeys_crste,\n+\t};\n+\n+\treturn _dat_walk_gfn_range(start, asce_end(asce), asce, \u0026ops, DAT_WALK_IGN_HOLES, NULL);\n+}\n+\n+static int _gmap_enable_skeys(struct gmap *gmap)\n+{\n+\tgfn_t start = 0;\n+\tint rc;\n+\n+\tif (uses_skeys(gmap))\n+\t\treturn 0;\n+\n+\tset_bit(GMAP_FLAG_USES_SKEYS, \u0026gmap-\u003eflags);\n+\trc = gmap_helper_disable_cow_sharing();\n+\tif (rc) {\n+\t\tclear_bit(GMAP_FLAG_USES_SKEYS, \u0026gmap-\u003eflags);\n+\t\treturn rc;\n+\t}\n+\n+\tdo {\n+\t\tscoped_guard(write_lock, \u0026gmap-\u003ekvm-\u003emmu_lock)\n+\t\t\tstart = dat_reset_skeys(gmap-\u003easce, start);\n+\t\tcond_resched();\n+\t} while (start);\n+\treturn 0;\n+}\n+\n+int gmap_enable_skeys(struct gmap *gmap)\n+{\n+\tint rc;\n+\n+\tmmap_write_lock(gmap-\u003ekvm-\u003emm);\n+\trc = _gmap_enable_skeys(gmap);\n+\tmmap_write_unlock(gmap-\u003ekvm-\u003emm);\n+\treturn rc;\n+}\ndiff --git a/arch/s390/kvm/gmap/sk.h b/arch/s390/kvm/gmap/sk.h\nnew file mode 100644\nindex 00000000000000..113ff8d0b0ab78\n--- /dev/null\n+++ b/arch/s390/kvm/gmap/sk.h\n@@ -0,0 +1,18 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+\n+#ifndef ARCH_KVM_GMAP_SK_H\n+#define ARCH_KVM_GMAP_SK_H\n+\n+#include \"dat.h\"\n+\n+int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey);\n+int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,\n+\t\t\tunion skey skey, bool nq);\n+int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gfn_t gfn,\n+\t\t\t union skey skey, union skey *oldkey, bool nq, bool mr, bool mc);\n+int dat_reset_reference_bit(union asce asce, gfn_t gfn);\n+long dat_reset_skeys(union asce asce, gfn_t start);\n+\n+int gmap_enable_skeys(struct gmap *gmap);\n+\n+#endif /* ARCH_KVM_GMAP_SK_H */\ndiff --git a/arch/s390/kvm/gmap/trace-gmap.h b/arch/s390/kvm/gmap/trace-gmap.h\nnew file mode 100644\nindex 00000000000000..25f8a527fddea2\n--- /dev/null\n+++ b/arch/s390/kvm/gmap/trace-gmap.h\n@@ -0,0 +1,59 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#if !defined(GMAP_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)\n+#define GMAP_TRACE_KVM_H\n+\n+#include \u003clinux/tracepoint.h\u003e\n+\n+#undef TRACE_SYSTEM\n+#define TRACE_SYSTEM kvm\n+#define TRACE_INCLUDE_PATH ../gmap\n+#undef TRACE_INCLUDE_FILE\n+#define TRACE_INCLUDE_FILE trace-gmap\n+\n+#ifdef KVM_S390_ARM64\n+#define __KVM_FIELDS \\\n+\t__field(unsigned long, pstate) \\\n+\t__field(unsigned long, pc)\n+#define __KVM_ASSIGN ({\\\n+\t__entry-\u003epstate = vcpu-\u003earch.sae_block.pstate; \\\n+\t__entry-\u003epc = vcpu-\u003earch.sae_block.pc; \\\n+\t})\n+#define __KVM_PRINT \\\n+\t__entry-\u003epstate, \\\n+\t__entry-\u003epc\n+#else\n+#define __KVM_FIELDS \\\n+\t__field(unsigned long, pswmask) \\\n+\t__field(unsigned long, pswaddr)\n+#define __KVM_ASSIGN ({\\\n+\t__entry-\u003epswmask = vcpu-\u003earch.sie_block-\u003egpsw.mask; \\\n+\t__entry-\u003epswaddr = vcpu-\u003earch.sie_block-\u003egpsw.addr; \\\n+\t})\n+#define __KVM_PRINT \\\n+\t__entry-\u003epswmask,\\\n+\t__entry-\u003epswaddr\n+#endif\n+\n+TRACE_EVENT(kvm_s390_major_guest_pfault,\n+\t TP_PROTO(struct kvm_vcpu *vcpu),\n+\t TP_ARGS(vcpu),\n+\n+\t TP_STRUCT__entry(\n+\t\t__field(int, id)\n+\t\t__KVM_FIELDS\n+\t\t),\n+\n+\t TP_fast_assign(\n+\t\t__entry-\u003eid = vcpu-\u003evcpu_id;\n+\t\t__KVM_ASSIGN\n+\t\t),\n+\t TP_printk(\"%02d[%016lx-%016lx]: major fault, maybe applicable for pfault\",\n+\t\t__entry-\u003eid,\n+\t\t__KVM_PRINT\n+\t\t)\n+\t );\n+\n+#endif /* GMAP_TRACE_KVM_H */\n+\n+/* This part must be outside protection */\n+#include \u003ctrace/define_trace.h\u003e\ndiff --git a/arch/s390/kvm/s390/Kconfig b/arch/s390/kvm/s390/Kconfig\nnew file mode 100644\nindex 00000000000000..4b7a7c2945e57c\n--- /dev/null\n+++ b/arch/s390/kvm/s390/Kconfig\n@@ -0,0 +1,41 @@\n+# SPDX-License-Identifier: GPL-2.0\n+#\n+# KVM_S390 configuration\n+\n+config KVM_S390\n+\tdef_tristate y\n+\tprompt \"Kernel-based Virtual Machine (KVM) support (s390)\"\n+\tselect KVM\n+\tselect HAVE_KVM_CPU_RELAX_INTERCEPT\n+\tselect KVM_ASYNC_PF\n+\tselect KVM_ASYNC_PF_SYNC\n+\tselect KVM_COMMON\n+\tselect HAVE_KVM_IRQCHIP\n+\tselect HAVE_KVM_IRQ_ROUTING\n+\tselect HAVE_KVM_INVALID_WAKEUPS\n+\tselect HAVE_KVM_NO_POLL\n+\tselect KVM_VFIO\n+\tselect VIRT_XFER_TO_GUEST_WORK\n+\tselect KVM_MMU_LOCKLESS_AGING\n+\tselect KVM_GENERIC_PRE_FAULT_MEMORY\n+\thelp\n+\t Support hosting paravirtualized s390 guest machines using the SIE\n+\t virtualization capability on the mainframe. This should work\n+\t on any 64bit machine.\n+\n+\t This module provides access to the hardware capabilities through\n+\t a character device node named /dev/kvm.\n+\n+\t To compile this as a module, choose M here: the module\n+\t will be called kvm.\n+\n+\t If unsure, say N.\n+\n+config KVM_S390_UCONTROL\n+\tbool \"Userspace controlled virtual machines\"\n+\tdepends on KVM_S390\n+\thelp\n+\t Allow CAP_SYS_ADMIN users to create KVM virtual machines that are\n+\t controlled by userspace.\n+\n+\t If unsure, say N.\ndiff --git a/arch/s390/kvm/s390/Makefile b/arch/s390/kvm/s390/Makefile\nnew file mode 100644\nindex 00000000000000..51aee874b36f38\n--- /dev/null\n+++ b/arch/s390/kvm/s390/Makefile\n@@ -0,0 +1,17 @@\n+# SPDX-License-Identifier: GPL-2.0\n+# Makefile for kernel virtual machines on s390\n+#\n+# Copyright IBM Corp. 2008\n+\n+KVM := ../../../../virt/kvm\n+include $(srctree)/virt/kvm/Makefile.kvm\n+include $(srctree)/arch/s390/kvm/gmap/Makefile\n+\n+ccflags-y := -I$(src) -I$(srctree)/arch/s390/kvm/gmap\n+\n+kvm-y += s390.o intercept.o interrupt.o priv.o sigp.o\n+kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o\n+\n+kvm-$(CONFIG_VFIO_PCI_ZDEV_KVM) += pci.o\n+\n+obj-$(CONFIG_KVM_S390) += kvm.o\ndiff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/s390/diag.c\nsimilarity index 99%\nrename from arch/s390/kvm/diag.c\nrename to arch/s390/kvm/s390/diag.c\nindex d89d1c381522a9..700d9b7b68bc45 100644\n--- a/arch/s390/kvm/diag.c\n+++ b/arch/s390/kvm/s390/diag.c\n@@ -12,7 +12,7 @@\n #include \u003clinux/kvm_host.h\u003e\n #include \u003casm/gmap_helpers.h\u003e\n #include \u003casm/virtio-ccw.h\u003e\n-#include \"kvm-s390.h\"\n+#include \"s390.h\"\n #include \"trace.h\"\n #include \"trace-s390.h\"\n #include \"gaccess.h\"\ndiff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/s390/gaccess.c\nsimilarity index 99%\nrename from arch/s390/kvm/gaccess.c\nrename to arch/s390/kvm/s390/gaccess.c\nindex 36102b2727fbff..2d82c931759769 100644\n--- a/arch/s390/kvm/gaccess.c\n+++ b/arch/s390/kvm/s390/gaccess.c\n@@ -17,9 +17,10 @@\n #include \u003casm/access-regs.h\u003e\n #include \u003casm/fault.h\u003e\n #include \u003casm/dat-bits.h\u003e\n-#include \"kvm-s390.h\"\n+#include \"s390.h\"\n #include \"dat.h\"\n #include \"gmap.h\"\n+#include \"sk.h\"\n #include \"gaccess.h\"\n #include \"faultin.h\"\n \ndiff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/s390/gaccess.h\nsimilarity index 99%\nrename from arch/s390/kvm/gaccess.h\nrename to arch/s390/kvm/s390/gaccess.h\nindex b5385cec60f456..ef922b3b499031 100644\n--- a/arch/s390/kvm/gaccess.h\n+++ b/arch/s390/kvm/s390/gaccess.h\n@@ -14,7 +14,7 @@\n #include \u003clinux/kvm_host.h\u003e\n #include \u003clinux/uaccess.h\u003e\n #include \u003clinux/ptrace.h\u003e\n-#include \"kvm-s390.h\"\n+#include \"s390.h\"\n \n /**\n * kvm_s390_real_to_abs - convert guest real address to guest absolute address\ndiff --git a/arch/s390/kvm/guestdbg.c b/arch/s390/kvm/s390/guestdbg.c\nsimilarity index 99%\nrename from arch/s390/kvm/guestdbg.c\nrename to arch/s390/kvm/s390/guestdbg.c\nindex 69835e1d4f207e..c880ebbdef2ff2 100644\n--- a/arch/s390/kvm/guestdbg.c\n+++ b/arch/s390/kvm/s390/guestdbg.c\n@@ -8,7 +8,7 @@\n */\n #include \u003clinux/kvm_host.h\u003e\n #include \u003clinux/errno.h\u003e\n-#include \"kvm-s390.h\"\n+#include \"s390.h\"\n #include \"gaccess.h\"\n \n /*\ndiff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/s390/intercept.c\nsimilarity index 99%\nrename from arch/s390/kvm/intercept.c\nrename to arch/s390/kvm/s390/intercept.c\nindex 1980df61ef304d..ca1205dfac8b07 100644\n--- a/arch/s390/kvm/intercept.c\n+++ b/arch/s390/kvm/s390/intercept.c\n@@ -17,7 +17,7 @@\n #include \u003casm/sysinfo.h\u003e\n #include \u003casm/uv.h\u003e\n \n-#include \"kvm-s390.h\"\n+#include \"s390.h\"\n #include \"gaccess.h\"\n #include \"trace.h\"\n #include \"trace-s390.h\"\ndiff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/s390/interrupt.c\nsimilarity index 99%\nrename from arch/s390/kvm/interrupt.c\nrename to arch/s390/kvm/s390/interrupt.c\nindex 9e3e6b0d72ad61..24c41c7a4c3d97 100644\n--- a/arch/s390/kvm/interrupt.c\n+++ b/arch/s390/kvm/s390/interrupt.c\n@@ -29,7 +29,7 @@\n #include \u003casm/nmi.h\u003e\n #include \u003casm/airq.h\u003e\n #include \u003casm/tpi.h\u003e\n-#include \"kvm-s390.h\"\n+#include \"s390.h\"\n #include \"gaccess.h\"\n #include \"trace-s390.h\"\n #include \"pci.h\"\ndiff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/s390/pci.c\nsimilarity index 99%\nrename from arch/s390/kvm/pci.c\nrename to arch/s390/kvm/s390/pci.c\nindex 5b075c38998e31..efdc1ddf6ba848 100644\n--- a/arch/s390/kvm/pci.c\n+++ b/arch/s390/kvm/s390/pci.c\n@@ -14,7 +14,7 @@\n #include \u003casm/pci_io.h\u003e\n #include \u003casm/sclp.h\u003e\n #include \"pci.h\"\n-#include \"kvm-s390.h\"\n+#include \"s390.h\"\n \n struct zpci_aift *aift;\n \ndiff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/s390/pci.h\nsimilarity index 100%\nrename from arch/s390/kvm/pci.h\nrename to arch/s390/kvm/s390/pci.h\ndiff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/s390/priv.c\nsimilarity index 99%\nrename from arch/s390/kvm/priv.c\nrename to arch/s390/kvm/s390/priv.c\nindex ad0ddc433a73c3..9bd3c07285baeb 100644\n--- a/arch/s390/kvm/priv.c\n+++ b/arch/s390/kvm/s390/priv.c\n@@ -26,9 +26,11 @@\n #include \u003casm/ap.h\u003e\n #include \u003casm/gmap_helpers.h\u003e\n #include \"gaccess.h\"\n-#include \"kvm-s390.h\"\n+#include \"s390.h\"\n #include \"trace.h\"\n #include \"gmap.h\"\n+#include \"sk.h\"\n+#include \"cmma.h\"\n \n static int handle_ri(struct kvm_vcpu *vcpu)\n {\ndiff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/s390/pv.c\nsimilarity index 99%\nrename from arch/s390/kvm/pv.c\nrename to arch/s390/kvm/s390/pv.c\nindex 1beacc841ca850..f6e03e9d371ad2 100644\n--- a/arch/s390/kvm/pv.c\n+++ b/arch/s390/kvm/s390/pv.c\n@@ -18,7 +18,7 @@\n #include \u003clinux/sched/mm.h\u003e\n #include \u003clinux/mmu_notifier.h\u003e\n #include \u003casm/gmap_helpers.h\u003e\n-#include \"kvm-s390.h\"\n+#include \"s390.h\"\n #include \"dat.h\"\n #include \"gaccess.h\"\n #include \"gmap.h\"\ndiff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/s390/s390.c\nsimilarity index 98%\nrename from arch/s390/kvm/kvm-s390.c\nrename to arch/s390/kvm/s390/s390.c\nindex 23c817595e28d5..b560c1e5792692 100644\n--- a/arch/s390/kvm/kvm-s390.c\n+++ b/arch/s390/kvm/s390/s390.c\n@@ -50,11 +50,13 @@\n #include \u003casm/fpu.h\u003e\n #include \u003casm/ap.h\u003e\n #include \u003casm/uv.h\u003e\n-#include \"kvm-s390.h\"\n+#include \"s390.h\"\n #include \"gaccess.h\"\n #include \"gmap.h\"\n #include \"faultin.h\"\n #include \"pci.h\"\n+#include \"sk.h\"\n+#include \"cmma.h\"\n \n #define CREATE_TRACE_POINTS\n #include \"trace.h\"\n@@ -746,33 +748,7 @@ static void sca_del_vcpu(struct kvm_vcpu *vcpu);\n int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,\n \t\t\t struct kvm_dirty_log *log)\n {\n-\tint r;\n-\tunsigned long n;\n-\tstruct kvm_memory_slot *memslot;\n-\tint is_dirty;\n-\n-\tif (kvm_is_ucontrol(kvm))\n-\t\treturn -EINVAL;\n-\n-\tmutex_lock(\u0026kvm-\u003eslots_lock);\n-\n-\tr = -EINVAL;\n-\tif (log-\u003eslot \u003e= KVM_USER_MEM_SLOTS)\n-\t\tgoto out;\n-\n-\tr = kvm_get_dirty_log(kvm, log, \u0026is_dirty, \u0026memslot);\n-\tif (r)\n-\t\tgoto out;\n-\n-\t/* Clear the dirty log */\n-\tif (is_dirty) {\n-\t\tn = kvm_dirty_bitmap_bytes(memslot);\n-\t\tmemset(memslot-\u003edirty_bitmap, 0, n);\n-\t}\n-\tr = 0;\n-out:\n-\tmutex_unlock(\u0026kvm-\u003eslots_lock);\n-\treturn r;\n+\treturn gmap_get_dirty_log(kvm, log);\n }\n \n static void icpt_operexc_on_all_vcpus(struct kvm *kvm)\n@@ -1268,7 +1244,7 @@ static int kvm_s390_vm_start_migration(struct kvm *kvm)\n * Must be called with kvm-\u003eslots_lock to avoid races with ourselves,\n * kvm_s390_vm_start_migration() and kvm_s390_get_cmma_bits().\n */\n-static int kvm_s390_vm_stop_migration(struct kvm *kvm)\n+int kvm_s390_vm_stop_migration(struct kvm *kvm)\n {\n \t/* migration mode already disabled */\n \tif (!kvm-\u003earch.migration_mode)\n@@ -5751,45 +5727,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,\n \t\t\t\t struct kvm_memory_slot *new,\n \t\t\t\t enum kvm_mr_change change)\n {\n-\tif (kvm_is_ucontrol(kvm) \u0026\u0026 new \u0026\u0026 new-\u003eid \u003c KVM_USER_MEM_SLOTS)\n-\t\treturn -EINVAL;\n-\n-\t/* When we are protected, we should not change the memory slots */\n-\tif (kvm_s390_pv_get_handle(kvm))\n-\t\treturn -EINVAL;\n-\n-\tif (change != KVM_MR_DELETE \u0026\u0026 change != KVM_MR_FLAGS_ONLY) {\n-\t\t/*\n-\t\t * A few sanity checks. The memory in userland is ok to be\n-\t\t * fragmented into various different vmas. It is okay to mmap()\n-\t\t * and munmap() stuff in this slot after doing this call at any\n-\t\t * time.\n-\t\t */\n-\t\tif (new-\u003euserspace_addr \u0026 ~PAGE_MASK)\n-\t\t\treturn -EINVAL;\n-\t\tif ((new-\u003ebase_gfn + new-\u003enpages) * PAGE_SIZE \u003e kvm-\u003earch.mem_limit)\n-\t\t\treturn -EINVAL;\n-\t\tif (!asce_contains_gfn(kvm-\u003earch.gmap-\u003easce, new-\u003ebase_gfn + new-\u003enpages - 1))\n-\t\t\treturn -EINVAL;\n-\t}\n-\n-\tif (!kvm-\u003earch.migration_mode)\n-\t\treturn 0;\n-\n-\t/*\n-\t * Turn off migration mode when:\n-\t * - userspace creates a new memslot with dirty logging off,\n-\t * - userspace modifies an existing memslot (MOVE or FLAGS_ONLY) and\n-\t * dirty logging is turned off.\n-\t * Migration mode expects dirty page logging being enabled to store\n-\t * its dirty bitmap.\n-\t */\n-\tif (change != KVM_MR_DELETE \u0026\u0026\n-\t !(new-\u003eflags \u0026 KVM_MEM_LOG_DIRTY_PAGES))\n-\t\tWARN(kvm_s390_vm_stop_migration(kvm),\n-\t\t \"Failed to stop migration mode\");\n-\n-\treturn 0;\n+\treturn gmap_prepare_memory_region(kvm, old, new, change);\n }\n \n void kvm_arch_commit_memory_region(struct kvm *kvm,\n@@ -5797,42 +5735,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,\n \t\t\t\tconst struct kvm_memory_slot *new,\n \t\t\t\tenum kvm_mr_change change)\n {\n-\tstruct kvm_s390_mmu_cache *mc = NULL;\n-\tint rc = 0;\n-\n-\tif (change == KVM_MR_FLAGS_ONLY)\n-\t\treturn;\n-\n-\tmc = kvm_s390_new_mmu_cache();\n-\tif (!mc) {\n-\t\trc = -ENOMEM;\n-\t\tgoto out;\n-\t}\n-\n-\tscoped_guard(write_lock, \u0026kvm-\u003emmu_lock) {\n-\t\tswitch (change) {\n-\t\tcase KVM_MR_DELETE:\n-\t\t\trc = dat_delete_slot(mc, kvm-\u003earch.gmap-\u003easce, old-\u003ebase_gfn, old-\u003enpages);\n-\t\t\tbreak;\n-\t\tcase KVM_MR_MOVE:\n-\t\t\trc = dat_delete_slot(mc, kvm-\u003earch.gmap-\u003easce, old-\u003ebase_gfn, old-\u003enpages);\n-\t\t\tif (rc)\n-\t\t\t\tbreak;\n-\t\t\tfallthrough;\n-\t\tcase KVM_MR_CREATE:\n-\t\t\trc = dat_create_slot(mc, kvm-\u003earch.gmap-\u003easce, new-\u003ebase_gfn, new-\u003enpages);\n-\t\t\tbreak;\n-\t\tcase KVM_MR_FLAGS_ONLY:\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tWARN(1, \"Unknown KVM MR CHANGE: %d\\n\", change);\n-\t\t}\n-\t}\n-out:\n-\tif (rc)\n-\t\tpr_warn(\"failed to commit memory region\\n\");\n-\tkvm_s390_free_mmu_cache(mc);\n-\treturn;\n+\tgmap_commit_memory_region(kvm, old, new, change);\n }\n \n /**\n@@ -5855,28 +5758,10 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,\n * * other error codes \u003c 0 in case of other errors.\n * * otherwise a number \u003e 0 of bytes that have been faulted in successfully.\n */\n-long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, struct kvm_pre_fault_memory *range)\n+long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\n+\t\t\t\t struct kvm_pre_fault_memory *range)\n {\n-\tstruct guest_fault f = { .gfn = gpa_to_gfn(range-\u003egpa), };\n-\tgpa_t end;\n-\tint rc;\n-\n-\tif (kvm_is_ucontrol(vcpu-\u003ekvm))\n-\t\treturn -EINVAL;\n-\n-\trc = kvm_s390_faultin_gfn(vcpu, NULL, \u0026f);\n-\tif (rc == PGM_ADDRESSING)\n-\t\treturn -ENOENT;\n-\tif (rc \u003e 0)\n-\t\treturn -EIO;\n-\tif (rc \u003c 0)\n-\t\treturn rc;\n-\n-\tif (f.ptep)\n-\t\treturn PAGE_SIZE;\n-\n-\tend = ALIGN(range-\u003egpa + PAGE_SIZE, f.crste_region3 ? _REGION3_SIZE : HPAGE_SIZE);\n-\treturn min(range-\u003esize, end - range-\u003egpa);\n+\treturn gmap_pre_fault_memory(vcpu, range);\n }\n \n /**\n@@ -5889,8 +5774,7 @@ long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, struct kvm_pre_fault_\n */\n bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)\n {\n-\tscoped_guard(read_lock, \u0026kvm-\u003emmu_lock)\n-\t\treturn dat_test_age_gfn(kvm-\u003earch.gmap-\u003easce, range-\u003estart, range-\u003eend);\n+\treturn gmap_test_age_gfn(kvm, range);\n }\n \n /**\n@@ -5924,6 +5808,14 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)\n \treturn gmap_unmap_gfn_range(kvm-\u003earch.gmap, range-\u003eslot, range-\u003estart, range-\u003eend);\n }\n \n+#ifdef CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE\n+/* Make s390 compile if arm64-on-s390 is selected */\n+int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)\n+{\n+\treturn 0;\n+}\n+#endif /* CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE */\n+\n static inline unsigned long nonhyp_mask(int i)\n {\n \tunsigned int nonhyp_fai = (sclp.hmfai \u003c\u003c i * 2) \u003e\u003e 30;\ndiff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/s390/s390.h\nsimilarity index 97%\nrename from arch/s390/kvm/kvm-s390.h\nrename to arch/s390/kvm/s390/s390.h\nindex 6d2842fb71a33a..aa206100723093 100644\n--- a/arch/s390/kvm/kvm-s390.h\n+++ b/arch/s390/kvm/s390/s390.h\n@@ -32,6 +32,11 @@ union kvm_s390_quad {\n \tunsigned char one;\n };\n \n+static inline bool kvm_s390_is_in_sie(struct kvm_vcpu *vcpu)\n+{\n+\treturn vcpu-\u003earch.sie_block-\u003eprog0c \u0026 PROG_IN_SIE;\n+}\n+\n static inline void kvm_s390_fpu_store(struct kvm_run *run)\n {\n \tfpu_stfpc(\u0026run-\u003es.regs.fpc);\n@@ -452,7 +457,7 @@ void kvm_s390_vsie_destroy(struct kvm *kvm);\n int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);\n int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);\n \n-/* implemented in kvm-s390.c */\n+/* implemented in s390.c */\n int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod);\n int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr);\n int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr);\n@@ -594,6 +599,11 @@ static inline bool kvm_s390_cur_gmap_fault_is_write(void)\n \treturn test_facility(75) \u0026\u0026 (current-\u003ethread.gmap_teid.fsi == TEID_FSI_STORE);\n }\n \n+static __always_inline int kvm_s390_is_migration_mode(struct kvm *kvm)\n+{\n+\treturn kvm-\u003earch.migration_mode;\n+}\n+\n /**\n * kvm_s390_vcpu_crypto_reset_all\n *\n@@ -624,4 +634,10 @@ void kvm_s390_vcpu_pci_enable_interp(struct kvm *kvm);\n */\n extern unsigned int diag9c_forwarding_hz;\n \n+/*\n+ * Must be called with kvm-\u003eslots_lock to avoid races with ourselves and\n+ * kvm_s390_vm_start_migration.\n+ */\n+int kvm_s390_vm_stop_migration(struct kvm *kvm);\n+\n #endif\ndiff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/s390/sigp.c\nsimilarity index 99%\nrename from arch/s390/kvm/sigp.c\nrename to arch/s390/kvm/s390/sigp.c\nindex 55c34cb354281e..131b3371ef4f8c 100644\n--- a/arch/s390/kvm/sigp.c\n+++ b/arch/s390/kvm/s390/sigp.c\n@@ -14,7 +14,7 @@\n #include \u003clinux/slab.h\u003e\n #include \u003casm/sigp.h\u003e\n #include \"gaccess.h\"\n-#include \"kvm-s390.h\"\n+#include \"s390.h\"\n #include \"trace.h\"\n \n static int __sigp_sense(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,\ndiff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/s390/trace-s390.h\nsimilarity index 100%\nrename from arch/s390/kvm/trace-s390.h\nrename to arch/s390/kvm/s390/trace-s390.h\ndiff --git a/arch/s390/kvm/trace.h b/arch/s390/kvm/s390/trace.h\nsimilarity index 97%\nrename from arch/s390/kvm/trace.h\nrename to arch/s390/kvm/s390/trace.h\nindex aa419eb6a0c808..97774fe09a85c5 100644\n--- a/arch/s390/kvm/trace.h\n+++ b/arch/s390/kvm/s390/trace.h\n@@ -45,20 +45,6 @@ TRACE_EVENT(kvm_s390_skey_related_inst,\n \t VCPU_TP_PRINTK(\"%s\", \"storage key related instruction\")\n \t);\n \n-TRACE_EVENT(kvm_s390_major_guest_pfault,\n-\t TP_PROTO(VCPU_PROTO_COMMON),\n-\t TP_ARGS(VCPU_ARGS_COMMON),\n-\n-\t TP_STRUCT__entry(\n-\t\t VCPU_FIELD_COMMON\n-\t\t ),\n-\n-\t TP_fast_assign(\n-\t\t VCPU_ASSIGN_COMMON\n-\t\t ),\n-\t VCPU_TP_PRINTK(\"%s\", \"major fault, maybe applicable for pfault\")\n-\t);\n-\n TRACE_EVENT(kvm_s390_pfault_init,\n \t TP_PROTO(VCPU_PROTO_COMMON, long pfault_token),\n \t TP_ARGS(VCPU_ARGS_COMMON, pfault_token),\ndiff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/s390/vsie.c\nsimilarity index 99%\nrename from arch/s390/kvm/vsie.c\nrename to arch/s390/kvm/s390/vsie.c\nindex eea24562e7db2b..c4a03b310fea40 100644\n--- a/arch/s390/kvm/vsie.c\n+++ b/arch/s390/kvm/s390/vsie.c\n@@ -23,7 +23,7 @@\n #include \u003casm/nmi.h\u003e\n #include \u003casm/dis.h\u003e\n #include \u003casm/facility.h\u003e\n-#include \"kvm-s390.h\"\n+#include \"s390.h\"\n #include \"gaccess.h\"\n #include \"gmap.h\"\n \ndiff --git a/arch/s390/tools/Makefile b/arch/s390/tools/Makefile\nindex f2862364fb4221..bd2a00d5ce2c93 100644\n--- a/arch/s390/tools/Makefile\n+++ b/arch/s390/tools/Makefile\n@@ -3,8 +3,13 @@\n # Makefile for s390 specific build tools\n #\n \n+include $(srctree)/arch/s390/tools/Makefile.arm64h\n+\n kapi := arch/$(ARCH)/include/generated/asm\n kapi-hdrs-y := $(kapi)/facility-defs.h $(kapi)/dis-defs.h\n+kapi-hdrs-$(CONFIG_KVM_ARM64) += $(ARM64_TARGETS)\n+\n+targets += $(addprefix ../../../,$(kapi-hdrs-y))\n \n PHONY += kapi\n \ndiff --git a/arch/s390/tools/Makefile.arm64h b/arch/s390/tools/Makefile.arm64h\nnew file mode 100644\nindex 00000000000000..0b32c124707d9a\n--- /dev/null\n+++ b/arch/s390/tools/Makefile.arm64h\n@@ -0,0 +1,58 @@\n+# SPDX-License-Identifier: GPL-2.0\n+#\n+# Share ARM64 headers with s390 KVM\n+#\n+\n+arm64api := $(objtree)/arch/$(ARCH)/include/generated/arm64\n+arm64uapi := $(objtree)/arch/$(ARCH)/include/generated/uapi/arm64\n+\n+# List of ARM64 headers to share with s390 KVM\n+# Format: [uapi:]header.h or [uapi:]header-part.h\n+#\n+# * header.h - from arch/arm64/include/asm/ to arm64/\n+# * uapi:header.h - from arch/arm64/include/uapi/asm/ to uapi/arm64/\n+# * header-part.h - generated as header-part.h from ARM64 header header.h\n+# * uapi:header-part.h - generated as header-part.h from ARM64 UAPI header header.h\n+# If a header contains partial markers (#ifdef ARM64_S390_COMMON) only this part will be copied.\n+# If the file does not contain any markers the whole file will be copied.\n+ARM64_SHARED_HEADERS := \\\n+\tbrk-imm.h \\\n+\tesr.h \\\n+\tkvm_arm.h \\\n+\tkvm_emulate-part.h \\\n+\tkvm_host.h \\\n+\tkvm_mmu.h \\\n+\tptrace.h \\\n+\tsysreg.h \\\n+\tuapi:hwcap.h \\\n+\tuapi:kvm.h \\\n+\tuapi:ptrace.h \\\n+\tuapi:sve_context.h \\\n+\n+quiet_cmd_gen_arm_hdr = GEN $@\n+ cmd_gen_arm_hdr = mkdir -p $(dir $@); \\\n+ $(AWK) -f $(src)/copy-arm64h.awk $\u003c \u003e $@ || \\\n+ $(AWK) -f $(src)/copy-arm64h-full.awk -v srcfile=\"$(subst $(srctree)/,,$(subst $(srctree)/../,,$\u003c))\" $\u003c \u003e $@\n+\n+arm64-type = $(firstword $(subst :, ,$(1)))\n+arm64-base = $(or $(word 2,$(subst :, ,$(1))),$(1))\n+arm64-src-base = $(patsubst %-part.h,%.h,$(call arm64-base,$(1)))\n+\n+arm64-src = $(srctree)/arch/arm64/include/$(if $(filter uapi,$(call arm64-type,$(1))),uapi/)asm/$(call arm64-src-base,$(1))\n+arm64-dst = $(objtree)/$(if $(filter uapi,$(call arm64-type,$(1))),$(arm64uapi),$(arm64api))/$(call arm64-base,$(1))\n+\n+$(foreach hdr,$(ARM64_SHARED_HEADERS),\\\n+\t$(eval $(call arm64-dst,$(hdr)): $(call arm64-src,$(hdr)) $(src)/copy-arm64h.awk $(src)/copy-arm64h-full.awk))\n+\n+ARM64_TARGETS := $(sort $(foreach hdr,$(ARM64_SHARED_HEADERS),$(call arm64-dst,$(hdr))))\n+\n+$(ARM64_TARGETS):\n+\t$(call cmd,gen_arm_hdr)\n+\n+quiet_cmd_gen_sysreg_arm64 = GEN $@\n+ cmd_gen_sysreg_arm64 = mkdir -p $(dir $@); $(AWK) -f $(srctree)/arch/arm64/tools/gen-sysreg.awk $(srctree)/arch/arm64/tools/sysreg \u003e $@\n+\n+$(arm64api)/sysreg-defs.h: $(srctree)/arch/arm64/tools/gen-sysreg.awk $(srctree)/arch/arm64/tools/sysreg FORCE\n+\t$(call if_changed,gen_sysreg_arm64)\n+\n+ARM64_TARGETS += $(arm64api)/sysreg-defs.h\ndiff --git a/arch/s390/tools/copy-arm64h-full.awk b/arch/s390/tools/copy-arm64h-full.awk\nnew file mode 100644\nindex 00000000000000..a9b85b347f780a\n--- /dev/null\n+++ b/arch/s390/tools/copy-arm64h-full.awk\n@@ -0,0 +1,43 @@\n+#!/usr/bin/awk -f\n+# SPDX-License-Identifier: GPL-2.0\n+#\n+# Process entire ARM64 headers for sharing with s390 KVM\n+#\n+# Usage: copy-arm64h-full.awk -v srcfile=\u003csource_path\u003e \u003cinput_file\u003e\n+#\n+# This processes the entire file (unlike copy-arm64h.awk which only extracts marked sections)\n+\n+BEGIN {\n+\tmax_guard_line = 25\n+\tguard_found = 0\n+\theader_added = 0\n+}\n+\n+# Find and process the include guard in the first few lines\n+NR \u003c= max_guard_line \u0026\u0026 !guard_found \u0026\u0026 /^#ifndef [A-Z_]+$/ {\n+\tguard_name = $2\n+\tguard_found = 1\n+\tprint \"/* This header was copied from \" srcfile \" */\"\n+\tprint \"\"\n+\tprint\n+\theader_added = 1\n+\tnext\n+}\n+\n+# Transform include directives\n+/^#include \u003cuapi\\/asm\\// {\n+\tsub(/\u003cuapi\\/asm\\//, \"\u003cuapi/arm64/\")\n+\tprint\n+\tnext\n+}\n+\n+/^#include \u003casm\\// {\n+\tsub(/\u003casm\\//, \"\u003carm64/\")\n+\tprint\n+\tnext\n+}\n+\n+# Pass through all other lines\n+{\n+\tprint\n+}\ndiff --git a/arch/s390/tools/copy-arm64h.awk b/arch/s390/tools/copy-arm64h.awk\nnew file mode 100644\nindex 00000000000000..33ceddd4116b4e\n--- /dev/null\n+++ b/arch/s390/tools/copy-arm64h.awk\n@@ -0,0 +1,71 @@\n+#!/usr/bin/awk -f\n+# SPDX-License-Identifier: GPL-2.0\n+#\n+# Extract marked sections from ARM64 headers for sharing with s390 KVM\n+#\n+# Usage: share-arm64-header.awk \u003cinput_file\u003e\n+#\n+# Extracts all sections between start/end markers. If no markers found, signals for fallback.\n+#TODO verification script or c file for arm to verify the ifdef things keep working\n+BEGIN {\n+\t# Constants\n+\tstart_pattern = \"^#ifdef ARM64_S390_COMMON$\"\n+\tend_pattern = \"^#endif \\\\/\\\\* ARM64_S390_COMMON \\\\*\\\\/$\"\n+\tmax_guard_line = 25\n+\n+\t# State variables\n+\tcopying = found_marker = 0\n+\tguard_name = \"\"\n+\tfile_header_done = 0\n+}\n+\n+NR \u003c= max_guard_line \u0026\u0026 !guard_name \u0026\u0026 /^#ifndef [A-Za-z0-9_]+$/ {\n+\tguard_name = $2\n+\tfilename = FILENAME\n+\tsub(/^.*arch\\/arm64\\//, \"arch/arm64/\", filename)\n+\tprint \"/*\"\n+\tprint \" * This header was automatically generated from \" filename\n+\tprint \" * Do not modify this file directly.\"\n+\tprint \" */\"\n+\tprint \"#ifndef \" guard_name\n+\tprint \"#define \" guard_name\n+\tprint \"\"\n+\tnext\n+}\n+\n+NR \u003e max_guard_line \u0026\u0026 !guard_name \u0026\u0026 !file_header_done {\n+\tprint \"error: no include guard found in first \" max_guard_line \" lines\" \u003e \"/dev/stderr\"\n+\tfile_header_done = 1\n+\texit 1\n+}\n+\n+!guard_name {\n+\tprint\n+\tnext\n+}\n+\n+$0 ~ start_pattern {\n+\tcopying = found_marker = 1\n+\tnext\n+}\n+\n+guard_name \u0026\u0026 !found_marker {\n+\tnext\n+}\n+\n+$0 ~ end_pattern { copying = 0; next }\n+\n+copying {\n+\tgsub(/#include \u003casm\\//, \"#include \u003carm64/\")\n+\tgsub(/#include \u003cuapi\\/asm\\//, \"#include \u003cuapi/arm64/\")\n+\tprint\n+\tnext\n+}\n+\n+END {\n+\tif (found_marker) {\n+\t\tprint \"\"\n+\t\tprint \"#endif /* \" guard_name \" */\"\n+\t}\n+\texit !found_marker\n+}\ndiff --git a/arch/s390/tools/opcodes.txt b/arch/s390/tools/opcodes.txt\nindex def2659f6602d2..0e4773c94af0d4 100644\n--- a/arch/s390/tools/opcodes.txt\n+++ b/arch/s390/tools/opcodes.txt\n@@ -594,6 +594,9 @@ b9a0\tclp\tRRF_U0RR\n b9a1\ttpei\tRRE_RR\n b9a2\tptf\tRRE_R0\n b9a4\tuvc\tRRF_URR\n+b9a5\tsae\tRRE_R0\n+b9a6\tlasrm\tRRE_R0\n+b9a7\tstiasrm\tRRE_R0\n b9aa\tlptea\tRRF_RURR2\n b9ab\tessa\tRRF_U0RR\n b9ac\tirbm\tRRE_RR\ndiff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h\nindex 5f6c1ce9673b7f..69a374e48fe735 100644\n--- a/arch/x86/include/asm/kvm_host.h\n+++ b/arch/x86/include/asm/kvm_host.h\n@@ -46,6 +46,8 @@\n \n #define __KVM_HAVE_ARCH_VCPU_DEBUGFS\n \n+#define HAVE_KVM_MMIO\n+\n /*\n * CONFIG_KVM_MAX_NR_VCPUS is defined iff CONFIG_KVM!=n, provide a dummy max if\n * KVM is disabled (arbitrarily use the default from CONFIG_KVM_MAX_NR_VCPUS).\ndiff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig\nindex 801bf9e520db33..da5d9fa8a11c07 100644\n--- a/arch/x86/kvm/Kconfig\n+++ b/arch/x86/kvm/Kconfig\n@@ -32,7 +32,6 @@ config KVM_X86\n \tselect VHOST_TASK\n \tselect KVM_ASYNC_PF\n \tselect USER_RETURN_NOTIFIER\n-\tselect KVM_MMIO\n \tselect SCHED_INFO\n \tselect PERF_EVENTS\n \tselect GUEST_PERF_EVENTS\ndiff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c\nindex c1cbae65d239f5..913edd9403e57a 100644\n--- a/arch/x86/kvm/mmu/tdp_mmu.c\n+++ b/arch/x86/kvm/mmu/tdp_mmu.c\n@@ -1089,7 +1089,7 @@ void kvm_tdp_mmu_invalidate_roots(struct kvm *kvm,\n \t * being destroyed in an error path of KVM_CREATE_VM.\n \t */\n \tif (IS_ENABLED(CONFIG_PROVE_LOCKING) \u0026\u0026\n-\t refcount_read(\u0026kvm-\u003eusers_count) \u0026\u0026 kvm-\u003ecreated_vcpus)\n+\t refcount_read(\u0026kvm-\u003erc.users_count) \u0026\u0026 kvm-\u003ecreated_vcpus)\n \t\tlockdep_assert_held_write(\u0026kvm-\u003emmu_lock);\n \n \t/*\ndiff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c\nindex 4272293478766b..f588129f7a4f7b 100644\n--- a/arch/x86/kvm/svm/sev.c\n+++ b/arch/x86/kvm/svm/sev.c\n@@ -115,7 +115,7 @@ static __always_inline void kvm_lockdep_assert_sev_lock_held(struct kvm *kvm)\n \t * Querying SEV+ support is safe if there are no other references, i.e.\n \t * if concurrent initialization of SEV+ is impossible.\n \t */\n-\tif (!refcount_read(\u0026kvm-\u003eusers_count))\n+\tif (!refcount_read(\u0026kvm-\u003erc.users_count))\n \t\treturn;\n \n \t/*\ndiff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h\nindex 6d6cd5904ddf66..a4647859fe1fac 100644\n--- a/arch/x86/kvm/vmx/nested.h\n+++ b/arch/x86/kvm/vmx/nested.h\n@@ -58,7 +58,7 @@ bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port,\n static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)\n {\n \tlockdep_assert_once(lockdep_is_held(\u0026vcpu-\u003emutex) ||\n-\t\t\t !refcount_read(\u0026vcpu-\u003ekvm-\u003eusers_count));\n+\t\t\t !refcount_read(\u0026vcpu-\u003ekvm-\u003erc.users_count));\n \n \treturn to_vmx(vcpu)-\u003enested.cached_vmcs12;\n }\n@@ -66,7 +66,7 @@ static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)\n static inline struct vmcs12 *get_shadow_vmcs12(struct kvm_vcpu *vcpu)\n {\n \tlockdep_assert_once(lockdep_is_held(\u0026vcpu-\u003emutex) ||\n-\t\t\t !refcount_read(\u0026vcpu-\u003ekvm-\u003eusers_count));\n+\t\t\t !refcount_read(\u0026vcpu-\u003ekvm-\u003erc.users_count));\n \n \treturn to_vmx(vcpu)-\u003enested.cached_shadow_vmcs12;\n }\ndiff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c\nindex 22dd797e62291f..e58d24b95bd1ee 100644\n--- a/drivers/s390/char/sclp_early.c\n+++ b/drivers/s390/char/sclp_early.c\n@@ -96,6 +96,7 @@ static void __init sclp_early_facilities_detect(void)\n \t\tsclp.has_ib = cpue-\u003eib;\n \t\tsclp.has_cei = cpue-\u003ecei;\n \t\tsclp.has_skey = cpue-\u003eskey;\n+\t\tsclp.has_aef = cpue-\u003eaef;\n \t\tbreak;\n \t}\n \ndiff --git a/drivers/vfio/device_cdev.c b/drivers/vfio/device_cdev.c\nindex 54abf312cf0496..a729be99d06ceb 100644\n--- a/drivers/vfio/device_cdev.c\n+++ b/drivers/vfio/device_cdev.c\n@@ -56,7 +56,7 @@ int vfio_device_fops_cdev_open(struct inode *inode, struct file *filep)\n static void vfio_df_get_kvm_safe(struct vfio_device_file *df)\n {\n \tspin_lock(\u0026df-\u003ekvm_ref_lock);\n-\tvfio_device_get_kvm_safe(df-\u003edevice, df-\u003ekvm);\n+\tvfio_device_get_kvm_safe(df-\u003edevice, df-\u003ekvm, df-\u003ekvm_module);\n \tspin_unlock(\u0026df-\u003ekvm_ref_lock);\n }\n \ndiff --git a/drivers/vfio/group.c b/drivers/vfio/group.c\nindex b2299e5bc6df34..fc24c0b2cc6fb4 100644\n--- a/drivers/vfio/group.c\n+++ b/drivers/vfio/group.c\n@@ -163,7 +163,7 @@ static int vfio_group_ioctl_set_container(struct vfio_group *group,\n static void vfio_device_group_get_kvm_safe(struct vfio_device *device)\n {\n \tspin_lock(\u0026device-\u003egroup-\u003ekvm_ref_lock);\n-\tvfio_device_get_kvm_safe(device, device-\u003egroup-\u003ekvm);\n+\tvfio_device_get_kvm_safe(device, device-\u003egroup-\u003ekvm, device-\u003egroup-\u003ekvm_module);\n \tspin_unlock(\u0026device-\u003egroup-\u003ekvm_ref_lock);\n }\n \n@@ -860,10 +860,11 @@ bool vfio_group_enforced_coherent(struct vfio_group *group)\n \treturn ret;\n }\n \n-void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm)\n+void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm, struct module *kvm_module)\n {\n \tspin_lock(\u0026group-\u003ekvm_ref_lock);\n \tgroup-\u003ekvm = kvm;\n+\tgroup-\u003ekvm_module = kvm_module;\n \tspin_unlock(\u0026group-\u003ekvm_ref_lock);\n }\n \ndiff --git a/drivers/vfio/vfio.h b/drivers/vfio/vfio.h\nindex e4b72e79b7e3e1..8209da17246c01 100644\n--- a/drivers/vfio/vfio.h\n+++ b/drivers/vfio/vfio.h\n@@ -22,8 +22,9 @@ struct vfio_device_file {\n \n \tu8 access_granted;\n \tu32 devid; /* only valid when iommufd is valid */\n-\tspinlock_t kvm_ref_lock; /* protect kvm field */\n+\tspinlock_t kvm_ref_lock; /* protect kvm and kvm_module fields */\n \tstruct kvm *kvm;\n+\tstruct module *kvm_module;\n \tstruct iommufd_ctx *iommufd; /* protected by struct vfio_device_set::lock */\n };\n \n@@ -89,6 +90,7 @@ struct vfio_group {\n \tenum vfio_group_type\t\ttype;\n \tstruct mutex\t\t\tgroup_lock;\n \tstruct kvm\t\t\t*kvm;\n+\tstruct module\t\t\t*kvm_module;\n \tstruct file\t\t\t*opened_file;\n \tstruct iommufd_ctx\t\t*iommufd;\n \tspinlock_t\t\t\tkvm_ref_lock;\n@@ -107,7 +109,7 @@ void vfio_device_group_unuse_iommu(struct vfio_device *device);\n void vfio_df_group_close(struct vfio_device_file *df);\n struct vfio_group *vfio_group_from_file(struct file *file);\n bool vfio_group_enforced_coherent(struct vfio_group *group);\n-void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm);\n+void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm, struct module *kvm_module);\n bool vfio_device_has_container(struct vfio_device *device);\n int __init vfio_group_init(void);\n void vfio_group_cleanup(void);\n@@ -170,7 +172,8 @@ static inline bool vfio_group_enforced_coherent(struct vfio_group *group)\n \treturn true;\n }\n \n-static inline void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm)\n+static inline void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm,\n+\t\t\t\t struct module *kvm_module)\n {\n }\n \n@@ -434,11 +437,13 @@ static inline void vfio_virqfd_exit(void)\n #endif\n \n #if IS_ENABLED(CONFIG_KVM)\n-void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm);\n+void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,\n+\t\t\t struct module *kvm_module);\n void vfio_device_put_kvm(struct vfio_device *device);\n #else\n static inline void vfio_device_get_kvm_safe(struct vfio_device *device,\n-\t\t\t\t\t struct kvm *kvm)\n+\t\t\t\t\t struct kvm *kvm,\n+\t\t\t\t\t struct module *kvm_module)\n {\n }\n \ndiff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c\nindex ed538aebb0b8e4..6bddea4d384ffd 100644\n--- a/drivers/vfio/vfio_main.c\n+++ b/drivers/vfio/vfio_main.c\n@@ -17,7 +17,7 @@\n #include \u003clinux/idr.h\u003e\n #include \u003clinux/iommu.h\u003e\n #if IS_ENABLED(CONFIG_KVM)\n-#include \u003clinux/kvm_host.h\u003e\n+#include \u003clinux/kvm_types.h\u003e\n #endif\n #include \u003clinux/list.h\u003e\n #include \u003clinux/miscdevice.h\u003e\n@@ -448,36 +448,26 @@ void vfio_unregister_group_dev(struct vfio_device *device)\n EXPORT_SYMBOL_GPL(vfio_unregister_group_dev);\n \n #if IS_ENABLED(CONFIG_KVM)\n-void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm)\n+void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,\n+\t\t\t struct module *kvm_module)\n {\n-\tvoid (*pfn)(struct kvm *kvm);\n-\tbool (*fn)(struct kvm *kvm);\n-\tbool ret;\n-\n \tlockdep_assert_held(\u0026device-\u003edev_set-\u003elock);\n \n \tif (!kvm)\n \t\treturn;\n \n-\tpfn = symbol_get(kvm_put_kvm);\n-\tif (WARN_ON(!pfn))\n+\tif (!try_module_get(kvm_module))\n \t\treturn;\n \n-\tfn = symbol_get(kvm_get_kvm_safe);\n-\tif (WARN_ON(!fn)) {\n-\t\tsymbol_put(kvm_put_kvm);\n-\t\treturn;\n-\t}\n+\tif (!kvm_get_kvm_safe(kvm))\n+\t\tgoto out_put_mod;\n \n-\tret = fn(kvm);\n-\tsymbol_put(kvm_get_kvm_safe);\n-\tif (!ret) {\n-\t\tsymbol_put(kvm_put_kvm);\n-\t\treturn;\n-\t}\n-\n-\tdevice-\u003eput_kvm = pfn;\n \tdevice-\u003ekvm = kvm;\n+\tdevice-\u003ekvm_module = kvm_module;\n+\treturn;\n+\n+out_put_mod:\n+\tmodule_put(kvm_module);\n }\n \n void vfio_device_put_kvm(struct vfio_device *device)\n@@ -487,15 +477,10 @@ void vfio_device_put_kvm(struct vfio_device *device)\n \tif (!device-\u003ekvm)\n \t\treturn;\n \n-\tif (WARN_ON(!device-\u003eput_kvm))\n-\t\tgoto clear;\n-\n-\tdevice-\u003eput_kvm(device-\u003ekvm);\n-\tdevice-\u003eput_kvm = NULL;\n-\tsymbol_put(kvm_put_kvm);\n-\n-clear:\n+\tkvm_put_kvm(device-\u003ekvm);\n \tdevice-\u003ekvm = NULL;\n+\tmodule_put(device-\u003ekvm_module);\n+\tdevice-\u003ekvm_module = NULL;\n }\n #endif\n \n@@ -1520,7 +1505,7 @@ bool vfio_file_enforced_coherent(struct file *file)\n }\n EXPORT_SYMBOL_GPL(vfio_file_enforced_coherent);\n \n-static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm)\n+static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module)\n {\n \tstruct vfio_device_file *df = file-\u003eprivate_data;\n \n@@ -1531,6 +1516,7 @@ static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm)\n \t */\n \tspin_lock(\u0026df-\u003ekvm_ref_lock);\n \tdf-\u003ekvm = kvm;\n+\tdf-\u003ekvm_module = kvm_module;\n \tspin_unlock(\u0026df-\u003ekvm_ref_lock);\n }\n \n@@ -1542,16 +1528,16 @@ static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm)\n * When a VFIO device is first opened the KVM will be available in\n * device-\u003ekvm if one was associated with the file.\n */\n-void vfio_file_set_kvm(struct file *file, struct kvm *kvm)\n+void vfio_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module)\n {\n \tstruct vfio_group *group;\n \n \tgroup = vfio_group_from_file(file);\n \tif (group)\n-\t\tvfio_group_set_kvm(group, kvm);\n+\t\tvfio_group_set_kvm(group, kvm, kvm_module);\n \n \tif (vfio_device_from_file(file))\n-\t\tvfio_device_file_set_kvm(file, kvm);\n+\t\tvfio_device_file_set_kvm(file, kvm, kvm_module);\n }\n EXPORT_SYMBOL_GPL(vfio_file_set_kvm);\n \ndiff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h\nindex ab8cfaec82d31e..bd380a2599108d 100644\n--- a/include/linux/kvm_host.h\n+++ b/include/linux/kvm_host.h\n@@ -768,6 +768,9 @@ struct kvm_memslots {\n };\n \n struct kvm {\n+\t/* Must be the first field, see function definitions in kvm_types.h. */\n+\tstruct kvm_refcount rc;\n+\n #ifdef KVM_HAVE_MMU_RWLOCK\n \trwlock_t mmu_lock;\n #else\n@@ -831,8 +834,7 @@ struct kvm {\n \tstruct list_head ioeventfds;\n \tstruct kvm_vm_stat stat;\n \tstruct kvm_arch arch;\n-\trefcount_t users_count;\n-#ifdef CONFIG_KVM_MMIO\n+#ifdef HAVE_KVM_MMIO\n \tstruct kvm_coalesced_mmio_ring *coalesced_mmio_ring;\n \tspinlock_t ring_lock;\n \tstruct list_head coalesced_zones;\n@@ -1067,12 +1069,11 @@ static inline void kvm_irqfd_exit(void)\n {\n }\n #endif\n-int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module);\n+int kvm_init(unsigned int vcpu_size, unsigned int vcpu_align, struct module *module);\n+int kvm_init_with_dev(unsigned int vcpu_size, unsigned int vcpu_align,\n+\t\t struct module *module, const char *dev_name, int minor);\n void kvm_exit(void);\n \n-void kvm_get_kvm(struct kvm *kvm);\n-bool kvm_get_kvm_safe(struct kvm *kvm);\n-void kvm_put_kvm(struct kvm *kvm);\n bool file_is_kvm(struct file *file);\n void kvm_put_kvm_no_destroy(struct kvm *kvm);\n \n@@ -1081,7 +1082,7 @@ static inline struct kvm_memslots *__kvm_memslots(struct kvm *kvm, int as_id)\n \tas_id = array_index_nospec(as_id, KVM_MAX_NR_ADDRESS_SPACES);\n \treturn srcu_dereference_check(kvm-\u003ememslots[as_id], \u0026kvm-\u003esrcu,\n \t\t\tlockdep_is_held(\u0026kvm-\u003eslots_lock) ||\n-\t\t\t!refcount_read(\u0026kvm-\u003eusers_count));\n+\t\t\t!refcount_read(\u0026kvm-\u003erc.users_count));\n }\n \n static inline struct kvm_memslots *kvm_memslots(struct kvm *kvm)\n@@ -1537,7 +1538,7 @@ void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu);\n void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu);\n bool kvm_vcpu_wake_up(struct kvm_vcpu *vcpu);\n \n-#ifndef CONFIG_S390\n+#ifndef CONFIG_KVM_S390\n void __kvm_vcpu_kick(struct kvm_vcpu *vcpu, bool wait);\n \n static inline void kvm_vcpu_kick(struct kvm_vcpu *vcpu)\ndiff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h\nindex a568d8e6f4e829..aadee536771a78 100644\n--- a/include/linux/kvm_types.h\n+++ b/include/linux/kvm_types.h\n@@ -33,6 +33,7 @@\n \n #include \u003clinux/mutex.h\u003e\n #include \u003clinux/spinlock_types.h\u003e\n+#include \u003clinux/refcount.h\u003e\n \n struct kvm;\n struct kvm_async_pf;\n@@ -140,6 +141,38 @@ struct kvm_vcpu_stat_generic {\n };\n \n #define KVM_STATS_NAME_SIZE\t48\n+\n+struct kvm_refcount {\n+\trefcount_t users_count;\n+\tvoid (*destroy)(struct kvm *kvm);\n+};\n+\n+static inline void kvm_get_kvm(struct kvm *kvm)\n+{\n+\tstruct kvm_refcount *rc = (struct kvm_refcount *)kvm;\n+\n+\trefcount_inc(\u0026rc-\u003eusers_count);\n+}\n+\n+/*\n+ * A safe version of kvm_get_kvm(), making sure the vm is not being destroyed.\n+ * Return true if kvm referenced successfully, false otherwise.\n+ */\n+static inline bool kvm_get_kvm_safe(struct kvm *kvm)\n+{\n+\tstruct kvm_refcount *rc = (struct kvm_refcount *)kvm;\n+\n+\treturn refcount_inc_not_zero(\u0026rc-\u003eusers_count);\n+}\n+\n+static inline void kvm_put_kvm(struct kvm *kvm)\n+{\n+\tstruct kvm_refcount *rc = (struct kvm_refcount *)kvm;\n+\n+\tif (refcount_dec_and_test(\u0026rc-\u003eusers_count))\n+\t\trc-\u003edestroy(kvm);\n+}\n+\n #endif /* !__ASSEMBLER__ */\n \n #endif /* __KVM_TYPES_H__ */\ndiff --git a/include/linux/vfio.h b/include/linux/vfio.h\nindex 31b826efba0008..81f04e60ebfda1 100644\n--- a/include/linux/vfio.h\n+++ b/include/linux/vfio.h\n@@ -55,6 +55,7 @@ struct vfio_device {\n \tunsigned int migration_flags;\n \tu8 precopy_info_v2;\n \tstruct kvm *kvm;\n+\tstruct module *kvm_module;\n \n \t/* Members below here are private, not for driver use */\n \tunsigned int index;\n@@ -66,7 +67,6 @@ struct vfio_device {\n \tunsigned int open_count;\n \tstruct completion comp;\n \tstruct iommufd_access *iommufd_access;\n-\tvoid (*put_kvm)(struct kvm *kvm);\n \tstruct inode *inode;\n #if IS_ENABLED(CONFIG_IOMMUFD)\n \tstruct iommufd_device *iommufd_device;\n@@ -377,7 +377,7 @@ static inline bool vfio_file_has_dev(struct file *file, struct vfio_device *devi\n #endif\n bool vfio_file_is_valid(struct file *file);\n bool vfio_file_enforced_coherent(struct file *file);\n-void vfio_file_set_kvm(struct file *file, struct kvm *kvm);\n+void vfio_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module);\n \n #define VFIO_PIN_PAGES_MAX_ENTRIES\t(PAGE_SIZE/sizeof(unsigned long))\n \ndiff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig\nindex 794976b88c6f97..c4a983e41765d9 100644\n--- a/virt/kvm/Kconfig\n+++ b/virt/kvm/Kconfig\n@@ -40,9 +40,6 @@ config NEED_KVM_DIRTY_RING_WITH_BITMAP\n \tbool\n \tdepends on HAVE_KVM_DIRTY_RING\n \n-config KVM_MMIO\n- bool\n-\n config KVM_ASYNC_PF\n bool\n \ndiff --git a/virt/kvm/Makefile.kvm b/virt/kvm/Makefile.kvm\nindex d047d4cf58c9fd..3c27c18b49a032 100644\n--- a/virt/kvm/Makefile.kvm\n+++ b/virt/kvm/Makefile.kvm\n@@ -5,9 +5,8 @@\n \n KVM ?= ../../../virt/kvm\n \n-kvm-y := $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/binary_stats.o\n+kvm-y := $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/binary_stats.o $(KVM)/coalesced_mmio.o\n kvm-$(CONFIG_KVM_VFIO) += $(KVM)/vfio.o\n-kvm-$(CONFIG_KVM_MMIO) += $(KVM)/coalesced_mmio.o\n kvm-$(CONFIG_KVM_ASYNC_PF) += $(KVM)/async_pf.o\n kvm-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(KVM)/irqchip.o\n kvm-$(CONFIG_HAVE_KVM_DIRTY_RING) += $(KVM)/dirty_ring.o\ndiff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c\nindex 6b1d9016109989..070eba3c65349b 100644\n--- a/virt/kvm/coalesced_mmio.c\n+++ b/virt/kvm/coalesced_mmio.c\n@@ -12,6 +12,8 @@\n #include \u003ckvm/iodev.h\u003e\n \n #include \u003clinux/kvm_host.h\u003e\n+\n+#ifdef HAVE_KVM_MMIO\n #include \u003clinux/slab.h\u003e\n #include \u003clinux/kvm.h\u003e\n \n@@ -188,3 +190,4 @@ int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,\n \t */\n \treturn 0;\n }\n+#endif /* ifdef HAVE_KVM_MMIO */\ndiff --git a/virt/kvm/coalesced_mmio.h b/virt/kvm/coalesced_mmio.h\nindex 36f84264ed257e..a8430d41945b9d 100644\n--- a/virt/kvm/coalesced_mmio.h\n+++ b/virt/kvm/coalesced_mmio.h\n@@ -11,7 +11,7 @@\n *\n */\n \n-#ifdef CONFIG_KVM_MMIO\n+#ifdef HAVE_KVM_MMIO\n \n #include \u003clinux/list.h\u003e\n \ndiff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c\nindex e44c20c049610d..6ac79d80e7ec01 100644\n--- a/virt/kvm/kvm_main.c\n+++ b/virt/kvm/kvm_main.c\n@@ -119,6 +119,7 @@ static struct dentry *kvm_debugfs_dir;\n \n static const struct file_operations stat_fops_per_vm;\n \n+static void kvm_destroy_vm(struct kvm *kvm);\n static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,\n \t\t\t unsigned long arg);\n #ifdef CONFIG_KVM_COMPAT\n@@ -1089,7 +1090,7 @@ static inline struct kvm_io_bus *kvm_get_bus_for_destruction(struct kvm *kvm,\n \t\t\t\t\t\t\t enum kvm_bus idx)\n {\n \treturn rcu_dereference_protected(kvm-\u003ebuses[idx],\n-\t\t\t\t\t !refcount_read(\u0026kvm-\u003eusers_count));\n+\t\t\t\t\t !refcount_read(\u0026kvm-\u003erc.users_count));\n }\n \n static int kvm_enable_virtualization(void);\n@@ -1146,7 +1147,9 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)\n \tif (r)\n \t\tgoto out_err_no_irq_routing;\n \n-\trefcount_set(\u0026kvm-\u003eusers_count, 1);\n+\tBUILD_BUG_ON(offsetof(struct kvm, rc) != 0);\n+\trefcount_set(\u0026kvm-\u003erc.users_count, 1);\n+\tkvm-\u003erc.destroy = kvm_destroy_vm;\n \n \tfor (i = 0; i \u003c kvm_arch_nr_memslot_as_ids(kvm); i++) {\n \t\tfor (j = 0; j \u003c 2; j++) {\n@@ -1216,7 +1219,7 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)\n out_err_no_disable:\n \tkvm_arch_destroy_vm(kvm);\n out_err_no_arch_destroy_vm:\n-\tWARN_ON_ONCE(!refcount_dec_and_test(\u0026kvm-\u003eusers_count));\n+\tWARN_ON_ONCE(!refcount_dec_and_test(\u0026kvm-\u003erc.users_count));\n \tfor (i = 0; i \u003c KVM_NR_BUSES; i++)\n \t\tkfree(kvm_get_bus_for_destruction(kvm, i));\n \tkvm_free_irq_routing(kvm);\n@@ -1309,29 +1312,6 @@ static void kvm_destroy_vm(struct kvm *kvm)\n \tmmdrop(mm);\n }\n \n-void kvm_get_kvm(struct kvm *kvm)\n-{\n-\trefcount_inc(\u0026kvm-\u003eusers_count);\n-}\n-EXPORT_SYMBOL_GPL(kvm_get_kvm);\n-\n-/*\n- * Make sure the vm is not during destruction, which is a safe version of\n- * kvm_get_kvm(). Return true if kvm referenced successfully, false otherwise.\n- */\n-bool kvm_get_kvm_safe(struct kvm *kvm)\n-{\n-\treturn refcount_inc_not_zero(\u0026kvm-\u003eusers_count);\n-}\n-EXPORT_SYMBOL_GPL(kvm_get_kvm_safe);\n-\n-void kvm_put_kvm(struct kvm *kvm)\n-{\n-\tif (refcount_dec_and_test(\u0026kvm-\u003eusers_count))\n-\t\tkvm_destroy_vm(kvm);\n-}\n-EXPORT_SYMBOL_GPL(kvm_put_kvm);\n-\n /*\n * Used to put a reference that was taken on behalf of an object associated\n * with a user-visible file descriptor, e.g. a vcpu or device, if installation\n@@ -1341,7 +1321,7 @@ EXPORT_SYMBOL_GPL(kvm_put_kvm);\n */\n void kvm_put_kvm_no_destroy(struct kvm *kvm)\n {\n-\tWARN_ON(refcount_dec_and_test(\u0026kvm-\u003eusers_count));\n+\tWARN_ON(refcount_dec_and_test(\u0026kvm-\u003erc.users_count));\n }\n EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_put_kvm_no_destroy);\n \n@@ -3520,7 +3500,7 @@ void mark_page_dirty_in_slot(struct kvm *kvm,\n \tif (WARN_ON_ONCE(vcpu \u0026\u0026 vcpu-\u003ekvm != kvm))\n \t\treturn;\n \n-\tWARN_ON_ONCE(!vcpu \u0026\u0026 refcount_read(\u0026kvm-\u003eusers_count) \u0026\u0026\n+\tWARN_ON_ONCE(!vcpu \u0026\u0026 refcount_read(\u0026kvm-\u003erc.users_count) \u0026\u0026\n \t\t !kvm_arch_allow_write_without_running_vcpu(kvm));\n #endif\n \n@@ -4055,7 +4035,7 @@ static vm_fault_t kvm_vcpu_fault(struct vm_fault *vmf)\n \telse if (vmf-\u003epgoff == KVM_PIO_PAGE_OFFSET)\n \t\tpage = virt_to_page(vcpu-\u003earch.pio_data);\n #endif\n-#ifdef CONFIG_KVM_MMIO\n+#ifdef HAVE_KVM_MMIO\n \telse if (vmf-\u003epgoff == KVM_COALESCED_MMIO_PAGE_OFFSET)\n \t\tpage = virt_to_page(vcpu-\u003ekvm-\u003ecoalesced_mmio_ring);\n #endif\n@@ -4881,7 +4861,7 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)\n \tcase KVM_CAP_ENABLE_CAP_VM:\n \tcase KVM_CAP_HALT_POLL:\n \t\treturn 1;\n-#ifdef CONFIG_KVM_MMIO\n+#ifdef HAVE_KVM_MMIO\n \tcase KVM_CAP_COALESCED_MMIO:\n \t\treturn KVM_COALESCED_MMIO_PAGE_OFFSET;\n \tcase KVM_CAP_COALESCED_PIO:\n@@ -5222,7 +5202,7 @@ static long kvm_vm_ioctl(struct file *filp,\n \t\tbreak;\n \t}\n #endif\n-#ifdef CONFIG_KVM_MMIO\n+#ifdef HAVE_KVM_MMIO\n \tcase KVM_REGISTER_COALESCED_MMIO: {\n \t\tstruct kvm_coalesced_mmio_zone zone;\n \n@@ -5544,7 +5524,7 @@ static long kvm_dev_ioctl(struct file *filp,\n #ifdef CONFIG_X86\n \t\tr += PAGE_SIZE; /* pio data page */\n #endif\n-#ifdef CONFIG_KVM_MMIO\n+#ifdef HAVE_KVM_MMIO\n \t\tr += PAGE_SIZE; /* coalesced mmio ring page */\n #endif\n \t\tbreak;\n@@ -5562,9 +5542,7 @@ static struct file_operations kvm_chardev_ops = {\n };\n \n static struct miscdevice kvm_dev = {\n-\tKVM_MINOR,\n-\t\"kvm\",\n-\t\u0026kvm_chardev_ops,\n+\t.fops = \u0026kvm_chardev_ops,\n };\n \n #ifdef CONFIG_KVM_GENERIC_HARDWARE_ENABLING\n@@ -6342,13 +6320,13 @@ static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm)\n \tkfree(env);\n }\n \n-static void kvm_init_debug(void)\n+static void kvm_init_debug(const char *dev_name)\n {\n \tconst struct file_operations *fops;\n \tconst struct kvm_stats_desc *pdesc;\n \tint i;\n \n-\tkvm_debugfs_dir = debugfs_create_dir(\"kvm\", NULL);\n+\tkvm_debugfs_dir = debugfs_create_dir(dev_name, NULL);\n \n \tfor (i = 0; i \u003c kvm_vm_stats_header.num_desc; ++i) {\n \t\tpdesc = \u0026kvm_vm_stats_desc[i];\n@@ -6484,11 +6462,22 @@ void kvm_unregister_perf_callbacks(void)\n }\n #endif\n \n-int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)\n+int kvm_init(unsigned int vcpu_size, unsigned int vcpu_align, struct module *module)\n+{\n+\treturn kvm_init_with_dev(vcpu_size, vcpu_align, module, \"kvm\", KVM_MINOR);\n+}\n+\n+int kvm_init_with_dev(unsigned int vcpu_size, unsigned int vcpu_align,\n+\t\t struct module *module, const char *dev_name, int minor)\n {\n \tint r;\n \tint cpu;\n \n+\tkvm_dev.minor = minor;\n+\tkvm_dev.name = kstrdup(dev_name, GFP_KERNEL);\n+\tif (!kvm_dev.name)\n+\t\treturn -ENOMEM;\n+\n \t/* A kmem cache lets us meet the alignment requirements of fx_save. */\n \tif (!vcpu_align)\n \t\tvcpu_align = __alignof__(struct kvm_vcpu);\n@@ -6499,8 +6488,9 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)\n \t\t\t\t\t offsetofend(struct kvm_vcpu, stats_id)\n \t\t\t\t\t - offsetof(struct kvm_vcpu, arch),\n \t\t\t\t\t NULL);\n+\tr = -ENOMEM;\n \tif (!kvm_vcpu_cache)\n-\t\treturn -ENOMEM;\n+\t\tgoto err_dev_name;\n \n \tfor_each_possible_cpu(cpu) {\n \t\tif (!alloc_cpumask_var_node(\u0026per_cpu(cpu_kick_mask, cpu),\n@@ -6526,7 +6516,7 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)\n \tkvm_preempt_ops.sched_in = kvm_sched_in;\n \tkvm_preempt_ops.sched_out = kvm_sched_out;\n \n-\tkvm_init_debug();\n+\tkvm_init_debug(kvm_dev.name);\n \n \tr = kvm_vfio_ops_init();\n \tif (WARN_ON_ONCE(r))\n@@ -6567,6 +6557,8 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)\n \tfor_each_possible_cpu(cpu)\n \t\tfree_cpumask_var(per_cpu(cpu_kick_mask, cpu));\n \tkmem_cache_destroy(kvm_vcpu_cache);\n+err_dev_name:\n+\tkfree(kvm_dev.name);\n \treturn r;\n }\n EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_init);\n@@ -6592,5 +6584,8 @@ void kvm_exit(void)\n \tkvm_vfio_ops_exit();\n \tkvm_async_pf_deinit();\n \tkvm_irqfd_exit();\n+\n+\tkfree(kvm_dev.name);\n+\tkvm_dev.name = NULL;\n }\n EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_exit);\ndiff --git a/virt/kvm/vfio.c b/virt/kvm/vfio.c\nindex 6cdc4e9a333a3f..c593f31136f96b 100644\n--- a/virt/kvm/vfio.c\n+++ b/virt/kvm/vfio.c\n@@ -37,13 +37,13 @@ struct kvm_vfio {\n \n static void kvm_vfio_file_set_kvm(struct file *file, struct kvm *kvm)\n {\n-\tvoid (*fn)(struct file *file, struct kvm *kvm);\n+\tvoid (*fn)(struct file *file, struct kvm *kvm, struct module *kvm_module);\n \n \tfn = symbol_get(vfio_file_set_kvm);\n \tif (!fn)\n \t\treturn;\n \n-\tfn(file, kvm);\n+\tfn(file, kvm, kvm ? THIS_MODULE : NULL);\n \n \tsymbol_put(vfio_file_set_kvm);\n }\n"
} |
| 2/1 | 2026/07/06 09:40 | agent | patch-evaluator |
5mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"KVM"
],
"FocusSymbols": [
"kvm_init_with_dev",
"vfio_device_get_kvm_safe",
"vfio_device_put_kvm",
"vfio_file_set_kvm",
"gmap_prepare_memory_region",
"gmap_commit_memory_region",
"gmap_get_dirty_log",
"gmap_test_age_gfn",
"gmap_pre_fault_memory",
"gmap_enable_skeys",
"dat_set_storage_key"
],
"Reasoning": "The patch introduces support for running arm64 guests on s390x hosts. While the actual arm64 execution requires the Arm Execution Facility (AEF) hardware feature which is not available in QEMU, the patch also significantly refactors the existing s390x KVM code (e.g., separating gmap and s390 specific KVM code) and modifies core KVM/VFIO reference counting logic (e.g., kvm_init_with_dev, vfio_device_get_kvm_safe). These core KVM and s390x KVM refactoring changes are reachable and should be fuzzed.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit dcc55d0914e18b996dc0d615bfdf95353e70be81
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Jul 6 09:40:50 2026 +0000
syz-cluster: applied patch under review
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 6b005c8fef7066..1cd7cd94a8554f 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -43,7 +43,9 @@ CC_FLAGS_NO_FPU := -mgeneral-regs-only
KBUILD_CFLAGS += $(CC_FLAGS_NO_FPU) \
$(compat_vdso) $(cc_has_k_constraint)
KBUILD_CFLAGS += $(call cc-disable-warning, psabi)
+KBUILD_CFLAGS += -DARM64_S390_COMMON
KBUILD_AFLAGS += $(compat_vdso)
+KBUILD_AFLAGS += -DARM64_S390_COMMON
ifeq ($(call rustc-min-version, 108500),y)
KBUILD_RUSTFLAGS += --target=aarch64-unknown-none-softfloat
diff --git a/arch/arm64/include/asm/brk-imm.h b/arch/arm64/include/asm/brk-imm.h
index beb42c62b6acc5..dd2d153dc0d81b 100644
--- a/arch/arm64/include/asm/brk-imm.h
+++ b/arch/arm64/include/asm/brk-imm.h
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2012 ARM Ltd.
*/
+/* Whole file is shared with s390 */
#ifndef __ASM_BRK_IMM_H
#define __ASM_BRK_IMM_H
diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index 81c17320a588d9..e25b742b09ac9f 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -3,11 +3,12 @@
* Copyright (C) 2013 - ARM Ltd
* Author: Marc Zyngier <marc.zyngier@arm.com>
*/
+/* Whole file is shared with s390 */
#ifndef __ASM_ESR_H
#define __ASM_ESR_H
-#include <asm/memory.h>
+#include <asm/brk-imm.h>
#include <asm/sysreg.h>
#define ESR_ELx_EC_UNKNOWN UL(0x00)
@@ -435,7 +436,7 @@
#define ESR_ELx_IT_GCSPOPX 7
#ifndef __ASSEMBLER__
-#include <asm/types.h>
+#include <linux/types.h>
static inline unsigned long esr_brk_comment(unsigned long esr)
{
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 3f9233b5a13081..cc4175176f947a 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -3,14 +3,16 @@
* Copyright (C) 2012,2013 - ARM Ltd
* Author: Marc Zyngier <marc.zyngier@arm.com>
*/
+/* Whole file is shared with s390 */
#ifndef __ARM64_KVM_ARM_H__
#define __ARM64_KVM_ARM_H__
+#include <linux/const.h>
+#include <linux/bits.h>
+#include <linux/types.h>
#include <asm/esr.h>
-#include <asm/memory.h>
#include <asm/sysreg.h>
-#include <asm/types.h>
/*
* Because I'm terribly lazy and that repainting the whole of the KVM
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 5bf3d7e1d92c77..15d6d6a08d3712 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -44,13 +44,18 @@ enum exception_type {
bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
void kvm_skip_instr32(struct kvm_vcpu *vcpu);
+#ifdef ARM64_S390_COMMON
void kvm_inject_undefined(struct kvm_vcpu *vcpu);
+#endif /* ARM64_S390_COMMON */
void kvm_inject_sync(struct kvm_vcpu *vcpu, u64 esr);
int kvm_inject_serror_esr(struct kvm_vcpu *vcpu, u64 esr);
+#ifdef ARM64_S390_COMMON
int kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr);
+#endif /* ARM64_S390_COMMON */
int kvm_inject_dabt_excl_atomic(struct kvm_vcpu *vcpu, u64 addr);
void kvm_inject_size_fault(struct kvm_vcpu *vcpu);
+#ifdef ARM64_S390_COMMON
static inline int kvm_inject_sea_dabt(struct kvm_vcpu *vcpu, u64 addr)
{
return kvm_inject_sea(vcpu, false, addr);
@@ -61,6 +66,8 @@ static inline int kvm_inject_sea_iabt(struct kvm_vcpu *vcpu, u64 addr)
return kvm_inject_sea(vcpu, true, addr);
}
+#endif /* ARM64_S390_COMMON */
+
static inline int kvm_inject_serror(struct kvm_vcpu *vcpu)
{
/*
@@ -133,12 +140,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)
@@ -159,6 +171,7 @@ static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
*vcpu_cpsr(vcpu) |= PSR_AA32_T_BIT;
}
+#ifdef ARM64_S390_COMMON
/*
* 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
@@ -167,16 +180,18 @@ static inline void vcpu_set_thumb(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;
}
+#endif /* ARM64_S390_COMMON */
+
static inline bool vcpu_is_el2_ctxt(const struct kvm_cpu_context *ctxt)
{
switch (ctxt->regs.pstate & (PSR_MODE32_BIT | PSR_MODE_MASK)) {
@@ -360,6 +375,7 @@ static inline u64 kvm_vcpu_get_disr(const struct kvm_vcpu *vcpu)
return vcpu->arch.fault.disr_el1;
}
+#ifdef ARM64_S390_COMMON
static inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu)
{
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_xVC_IMM_MASK;
@@ -437,6 +453,8 @@ static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC;
}
+#endif /* ARM64_S390_COMMON */
+
static inline
bool kvm_vcpu_trap_is_permission_fault(const struct kvm_vcpu *vcpu)
{
@@ -477,6 +495,7 @@ static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
return ESR_ELx_SYS64_ISS_RT(esr);
}
+#ifdef ARM64_S390_COMMON
static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
{
if (kvm_vcpu_abt_iss1tw(vcpu)) {
@@ -501,6 +520,8 @@ static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
return kvm_vcpu_dabt_iswrite(vcpu);
}
+#endif /* ARM64_S390_COMMON */
+
static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
{
return __vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
@@ -536,6 +557,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
return vcpu_read_sys_reg(vcpu, r) & bit;
}
+#ifdef ARM64_S390_COMMON
static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
unsigned long data,
unsigned int len)
@@ -611,6 +633,8 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
vcpu_set_flag((v), e); \
} while (0)
+#endif /* ARM64_S390_COMMON */
+
/*
* Returns a 'sanitised' view of CPTR_EL2, translating from nVHE to the VHE
* format if E2H isn't set.
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index bae2c4f92ef5c0..2fce38fd91529c 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -33,12 +33,15 @@
#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>
#define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
+#ifdef ARM64_S390_COMMON
#define KVM_VCPU_MAX_FEATURES 9
#define KVM_VCPU_VALID_FEATURES (BIT(KVM_VCPU_MAX_FEATURES) - 1)
@@ -56,6 +59,8 @@
#define KVM_REQ_MAP_L1_VNCR_EL2 KVM_ARCH_REQ(10)
#define KVM_REQ_VGIC_PROCESS_UPDATE KVM_ARCH_REQ(11)
+#endif /* ARM64_S390_COMMON */
+
#define KVM_DIRTY_LOG_MANUAL_CAPS (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \
KVM_DIRTY_LOG_INITIALLY_SET)
@@ -338,6 +343,7 @@ struct kvm_arch {
/* Protects VM-scoped configuration data */
struct mutex config_lock;
+#ifdef ARM64_S390_COMMON
/*
* If we encounter a data abort without valid instruction syndrome
* information, report this to user space. User space can (and
@@ -367,6 +373,8 @@ struct kvm_arch {
#define KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS 10
/* Unhandled SEAs are taken to userspace */
#define KVM_ARCH_FLAG_EXIT_SEA 11
+
+#endif /* ARM64_S390_COMMON */
unsigned long flags;
/* VM-wide vCPU feature set */
@@ -831,6 +839,8 @@ extern s64 kvm_nvhe_sym(hyp_physvirt_offset);
extern u64 kvm_nvhe_sym(hyp_cpu_logical_map)[NR_CPUS];
#define hyp_cpu_logical_map CHOOSE_NVHE_SYM(hyp_cpu_logical_map)
+#ifdef ARM64_S390_COMMON
+
struct vcpu_reset_state {
unsigned long pc;
unsigned long r0;
@@ -838,6 +848,8 @@ struct vcpu_reset_state {
bool reset;
};
+#endif /* ARM64_S390_COMMON */
+
struct vncr_tlb;
struct kvm_vcpu_arch {
@@ -947,6 +959,7 @@ struct kvm_vcpu_arch {
pid_t pid;
};
+#ifdef ARM64_S390_COMMON
/*
* Each 'flag' is composed of a comma-separated triplet:
*
@@ -980,6 +993,8 @@ struct kvm_vcpu_arch {
READ_ONCE(v->arch.flagset) & (m); \
})
+#endif /* ARM64_S390_COMMON */
+
/*
* Note that the set/clear accessors must be preempt-safe in order to
* avoid nesting them with load/put which also manipulate flags...
@@ -993,6 +1008,7 @@ struct kvm_vcpu_arch {
#define __vcpu_flags_preempt_enable() preempt_enable()
#endif
+#ifdef ARM64_S390_COMMON
#define __vcpu_set_flag(v, flagset, f, m) \
do { \
typeof(v->arch.flagset) *fset; \
@@ -1077,6 +1093,8 @@ struct kvm_vcpu_arch {
#define EXCEPT_AA64_EL2_FIQ __vcpu_except_flags(6)
#define EXCEPT_AA64_EL2_SERR __vcpu_except_flags(7)
+#endif /* ARM64_S390_COMMON */
+
/* Physical CPU not in supported_cpus */
#define ON_UNSUPPORTED_CPU __vcpu_single_flag(sflags, BIT(0))
/* WFIT instruction trapped */
@@ -1152,7 +1170,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
@@ -1183,6 +1201,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) \
@@ -1234,7 +1258,10 @@ struct kvm_vcpu_stat {
};
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
+#ifdef ARM64_S390_COMMON
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
+
+#endif /* ARM64_S390_COMMON */
int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
@@ -1319,6 +1346,7 @@ int __init populate_nv_trap_config(void);
void kvm_calculate_traps(struct kvm_vcpu *vcpu);
+#ifdef ARM64_S390_COMMON
/* MMIO helpers */
void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
@@ -1326,6 +1354,8 @@ 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);
+#endif /* ARM64_S390_COMMON */
+
/*
* Returns true if a Performance Monitoring Interrupt (PMI), a.k.a. perf event,
* arrived in guest context. For arm64, any event that arrives while a vCPU is
@@ -1500,8 +1530,11 @@ struct kvm *kvm_arch_alloc_vm(void);
#define kvm_vm_is_protected(kvm) (is_protected_kvm_enabled() && (kvm)->arch.pkvm.is_protected)
+#ifdef ARM64_S390_COMMON
#define vcpu_is_protected(vcpu) kvm_vm_is_protected((vcpu)->kvm)
+#endif /* ARM64_S390_COMMON */
+
int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature);
bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
@@ -1526,8 +1559,11 @@ 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))
+#ifdef ARM64_S390_COMMON
#define kvm_vcpu_initialized(v) vcpu_get_flag(v, VCPU_INITIALIZED)
+#endif /* ARM64_S390_COMMON */
+
int kvm_trng_call(struct kvm_vcpu *vcpu);
#ifdef CONFIG_KVM
extern phys_addr_t hyp_mem_base;
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 6eae7e7e2a6845..b782cae771fe89 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -142,12 +142,15 @@ static __always_inline unsigned long __kern_hyp_va(unsigned long v)
extern u32 __hyp_va_bits;
+#ifdef ARM64_S390_COMMON
/*
* We currently support using a VM-specified IPA size. For backward
* compatibility, the default IPA size is fixed to 40bits.
*/
#define KVM_PHYS_SHIFT (40)
+#endif /* ARM64_S390_COMMON */
+
#define kvm_phys_shift(mmu) VTCR_EL2_IPA((mmu)->vtcr)
#define kvm_phys_size(mmu) (_AC(1, ULL) << kvm_phys_shift(mmu))
#define kvm_phys_mask(mmu) (kvm_phys_size(mmu) - _AC(1, ULL))
@@ -178,9 +181,12 @@ void stage2_unmap_vm(struct kvm *kvm);
int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long type);
void kvm_uninit_stage2_mmu(struct kvm *kvm);
void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu);
+#ifdef ARM64_S390_COMMON
int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
phys_addr_t pa, unsigned long size, bool writable);
+#endif /* ARM64_S390_COMMON */
+
int kvm_handle_guest_sea(struct kvm_vcpu *vcpu);
int kvm_handle_guest_abort(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 39582511ad72f7..6eb122eb5fa62b 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -10,8 +10,13 @@
#include <asm/cpufeature.h>
+#ifdef ARM64_S390_COMMON
+#include <asm/sysreg.h>
+
#include <uapi/asm/ptrace.h>
+#endif /* ARM64_S390_COMMON */
+
/* Current Exception Level values, as contained in CurrentEL */
#define CurrentEL_EL1 (1 << 2)
#define CurrentEL_EL2 (2 << 2)
@@ -28,6 +33,8 @@
#define GIC_PRIO_PSR_I_SET GICV3_PRIO_PSR_I_SET
+#ifdef ARM64_S390_COMMON
+
/* Additional SPSR bits not exposed in the UABI */
#define PSR_MODE_THREAD_BIT (1 << 0)
#define PSR_IL_BIT (1 << 20)
@@ -68,6 +75,8 @@
#define PSR_AA32_IT_MASK 0x0600fc00 /* If-Then execution state mask */
#define PSR_AA32_GE_MASK 0x000f0000
+#endif /* ARM64_S390_COMMON */
+
#ifdef CONFIG_CPU_BIG_ENDIAN
#define PSR_AA32_ENDSTATE PSR_AA32_E_BIT
#else
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 7aa08d59d49448..58912a6b6fcd56 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -9,13 +9,17 @@
#ifndef __ASM_SYSREG_H
#define __ASM_SYSREG_H
+#ifdef ARM64_S390_COMMON
#include <linux/bits.h>
+#endif /* ARM64_S390_COMMON */
#include <linux/stringify.h>
#include <linux/kasan-tags.h>
#include <linux/kconfig.h>
#include <asm/gpr-num.h>
+#ifdef ARM64_S390_COMMON
+
/*
* ARMv8 ARM reserves the following encoding for system registers:
* (Ref: ARMv8 ARM, Section: "System instruction class encoding overview",
@@ -50,6 +54,8 @@
#define sys_reg_CRm(id) (((id) >> CRm_shift) & CRm_mask)
#define sys_reg_Op2(id) (((id) >> Op2_shift) & Op2_mask)
+#endif /* ARM64_S390_COMMON */
+
#ifndef CONFIG_BROKEN_GAS_INST
#ifdef __ASSEMBLER__
@@ -79,6 +85,8 @@
#endif /* CONFIG_BROKEN_GAS_INST */
+#ifdef ARM64_S390_COMMON
+
/*
* Instructions for modifying PSTATE fields.
* As per Arm ARM for v8-A, Section "C.5.1.3 op0 == 0b00, architectural hints,
@@ -91,8 +99,6 @@
*/
#define pstate_field(op1, op2) ((op1) << Op1_shift | (op2) << Op2_shift)
#define PSTATE_Imm_shift CRm_shift
-#define ENCODE_PSTATE(x, r) (0xd500401f | PSTATE_ ## r | ((!!x) << PSTATE_Imm_shift))
-#define SET_PSTATE(x, r) __emit_inst(ENCODE_PSTATE(x, r))
#define PSTATE_PAN pstate_field(0, 4)
#define PSTATE_UAO pstate_field(0, 3)
@@ -100,6 +106,11 @@
#define PSTATE_DIT pstate_field(3, 2)
#define PSTATE_TCO pstate_field(3, 4)
+#endif /* ARM64_S390_COMMON */
+
+#define ENCODE_PSTATE(x, r) (0xd500401f | PSTATE_ ## r | ((!!x) << PSTATE_Imm_shift))
+#define SET_PSTATE(x, r) __emit_inst(ENCODE_PSTATE(x, r))
+
#define SET_PSTATE_PAN(x) SET_PSTATE((x), PAN)
#define SET_PSTATE_UAO(x) SET_PSTATE((x), UAO)
#define SET_PSTATE_SSBS(x) SET_PSTATE((x), SSBS)
@@ -123,6 +134,8 @@
#define GSB_SYS_BARRIER_INSN __SYS_BARRIER_INSN(1, 0, 12, 0, 0, 31)
#define GSB_ACK_BARRIER_INSN __SYS_BARRIER_INSN(1, 0, 12, 0, 1, 31)
+#ifdef ARM64_S390_COMMON
+
/* Data cache zero operations */
#define SYS_DC_ISW sys_insn(1, 0, 7, 6, 2)
#define SYS_DC_IGSW sys_insn(1, 0, 7, 6, 4)
@@ -173,7 +186,7 @@
* come from here. The header relies on the definition of sys_reg()
* earlier in this file.
*/
-#include "asm/sysreg-defs.h"
+#include <asm/sysreg-defs.h>
/*
* System registers, organised loosely by encoding but grouped together
@@ -835,6 +848,8 @@
#define SCTLR_ELx_A (BIT(1))
#define SCTLR_ELx_M (BIT(0))
+#endif /* ARM64_S390_COMMON */
+
#ifdef CONFIG_CPU_BIG_ENDIAN
#define ENDIAN_SET_EL2 SCTLR_ELx_EE
#else
@@ -869,6 +884,8 @@
SCTLR_EL1_LSMAOE | SCTLR_EL1_nTLSMD | SCTLR_EL1_EIS | \
SCTLR_EL1_TSCXT | SCTLR_EL1_EOS)
+#ifdef ARM64_S390_COMMON
+
/* MAIR_ELx memory attributes (used by Linux) */
#define MAIR_ATTR_DEVICE_nGnRnE UL(0x00)
#define MAIR_ATTR_DEVICE_nGnRE UL(0x04)
@@ -1105,6 +1122,8 @@
#define GICV5_GICR_CDNMIA_TYPE_MASK GENMASK_ULL(31, 29)
#define GICV5_GICR_CDNMIA_ID_MASK GENMASK_ULL(23, 0)
+#endif /* ARM64_S390_COMMON */
+
#define gicr_insn(insn) read_sysreg_s(GICV5_OP_GICR_##insn)
#define gic_insn(v, insn) write_sysreg_s(v, GICV5_OP_GIC_##insn)
@@ -1254,6 +1273,8 @@
par; \
})
+#ifdef ARM64_S390_COMMON
+
#define SYS_FIELD_VALUE(reg, field, val) reg##_##field##_##val
#define SYS_FIELD_GET(reg, field, val) \
@@ -1266,6 +1287,8 @@
FIELD_PREP(reg##_##field##_MASK, \
SYS_FIELD_VALUE(reg, field, val))
-#endif
+#endif /* ARM64_S390_COMMON */
+
+#endif /* __ASSEMBLER__ */
#endif /* __ASM_SYSREG_H */
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 449154f9a4852d..dd138b730217e5 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/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 50adfff75be82e..c992308b2dcebc 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1580,6 +1580,7 @@ static unsigned long system_supported_vcpu_features(void)
return features;
}
+#ifdef ARM64_S390_COMMON
static int kvm_vcpu_init_check_features(struct kvm_vcpu *vcpu,
const struct kvm_vcpu_init *init)
{
@@ -1628,6 +1629,8 @@ static bool kvm_vcpu_init_changed(struct kvm_vcpu *vcpu,
KVM_VCPU_MAX_FEATURES);
}
+#endif /* ARM64_S390_COMMON */
+
static int kvm_setup_vcpu(struct kvm_vcpu *vcpu)
{
struct kvm *kvm = vcpu->kvm;
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index b01d6622b87206..5e1e1faa98c291 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -62,6 +62,7 @@ const struct kvm_stats_header kvm_vcpu_stats_header = {
sizeof(kvm_vcpu_stats_desc),
};
+#ifdef ARM64_S390_COMMON
static bool core_reg_offset_is_vreg(u64 off)
{
return off >= KVM_REG_ARM_CORE_REG(fp_regs.vregs) &&
@@ -134,19 +135,19 @@ 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->arch.ctxt.regs.regs[off];
+ return &vcpu_gp_regs(vcpu)[off];
case KVM_REG_ARM_CORE_REG(regs.sp):
- return &vcpu->arch.ctxt.regs.sp;
+ return vcpu_sp_el0(vcpu);
case KVM_REG_ARM_CORE_REG(regs.pc):
- return &vcpu->arch.ctxt.regs.pc;
+ return vcpu_pc(vcpu);
case KVM_REG_ARM_CORE_REG(regs.pstate):
- return &vcpu->arch.ctxt.regs.pstate;
+ 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);
@@ -170,13 +171,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;
@@ -306,6 +307,8 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
return err;
}
+#endif /* ARM64_S390_COMMON */
+
#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
#define vq_present(vqs, vq) (!!((vqs)[vq_word(vq)] & vq_mask(vq)))
@@ -543,6 +546,7 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
return -EINVAL;
}
+#ifdef ARM64_S390_COMMON
static int copy_core_reg_indices(const struct kvm_vcpu *vcpu,
u64 __user *uindices)
{
@@ -591,6 +595,8 @@ static unsigned long num_core_regs(const struct kvm_vcpu *vcpu)
return copy_core_reg_indices(vcpu, NULL);
}
+#endif /* ARM64_S390_COMMON */
+
static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
{
const unsigned int slices = vcpu_sve_slices(vcpu);
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 54aedf93c78b64..d511af145ee6ab 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -213,6 +213,7 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)
return 0;
}
+#ifdef ARM64_S390_COMMON
static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu)
{
u64 esr = kvm_vcpu_get_esr(vcpu);
@@ -224,6 +225,8 @@ static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu)
return 1;
}
+#endif /* ARM64_S390_COMMON */
+
/*
* Guest access to SVE registers should be routed to this handler only
* when the system doesn't support SVE.
@@ -404,6 +407,7 @@ static exit_handle_fn arm_exit_handlers[] = {
[ESR_ELx_EC_GCS] = kvm_handle_gcs,
};
+#ifdef ARM64_S390_COMMON
static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
{
u64 esr = kvm_vcpu_get_esr(vcpu);
@@ -439,6 +443,8 @@ static int handle_trap_exceptions(struct kvm_vcpu *vcpu)
return handled;
}
+#endif /* ARM64_S390_COMMON */
+
/*
* Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
* proper exit to userspace.
diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c
index bef40ddb16dbc2..82611442a2d13b 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 4fdfeabefeb432..a049983bd5c3ac 100644
--- a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
+++ b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
@@ -33,11 +33,11 @@ static inline void kvm_skip_instr(struct kvm_vcpu *vcpu)
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 18131e395e24c3..a57aec6dd85446 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -449,7 +449,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);
/*
@@ -895,7 +895,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?
*/
@@ -905,7 +905,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/mmio.c b/arch/arm64/kvm/mmio.c
index e2285ed8c91de6..876d56dd5b640a 100644
--- a/arch/arm64/kvm/mmio.c
+++ b/arch/arm64/kvm/mmio.c
@@ -10,6 +10,7 @@
#include "trace.h"
+#ifdef ARM64_S390_COMMON
void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data)
{
void *datap = NULL;
@@ -135,8 +136,11 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu)
if (!kvm_vcpu_dabt_issf(vcpu))
data = data & 0xffffffff;
+#endif /* ARM64_S390_COMMON */
trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
&data);
+ //TODO tracing
+#ifdef ARM64_S390_COMMON
data = vcpu_data_host_to_guest(vcpu, data, len);
vcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu), data);
}
@@ -171,8 +175,11 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
* though, so directly deliver an exception to the guest.
*/
if (!kvm_vcpu_dabt_isvalid(vcpu)) {
+#endif /* ARM64_S390_COMMON */
trace_kvm_mmio_nisv(*vcpu_pc(vcpu), esr,
kvm_vcpu_get_hfar(vcpu), fault_ipa);
+ //TODO tracing
+#ifdef ARM64_S390_COMMON
if (vcpu_is_protected(vcpu))
return kvm_inject_sea_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
@@ -223,14 +230,20 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt),
len);
+#endif /* ARM64_S390_COMMON */
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, &data);
+ //TODO tracing
+#ifdef ARM64_S390_COMMON
kvm_mmio_write_buf(data_buf, len, data);
ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,
data_buf);
} else {
+#endif /* ARM64_S390_COMMON */
trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len,
fault_ipa, NULL);
+ //TODO tracing
+#ifdef ARM64_S390_COMMON
ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_ipa, len,
data_buf);
@@ -257,3 +270,4 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
run->exit_reason = KVM_EXIT_MMIO;
return 0;
}
+#endif /* ARM64_S390_COMMON */
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index b963fd975aacaf..81d9f0faede2e0 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -34,6 +34,7 @@
static u32 __ro_after_init kvm_ipa_limit;
unsigned int __ro_after_init kvm_host_sve_max_vl;
+#ifdef ARM64_S390_COMMON
/*
* ARMv8 Reset Values
*/
@@ -46,6 +47,8 @@ unsigned int __ro_after_init kvm_host_sve_max_vl;
#define VCPU_RESET_PSTATE_SVC (PSR_AA32_MODE_SVC | PSR_AA32_A_BIT | \
PSR_AA32_I_BIT | PSR_AA32_F_BIT)
+#endif /* ARM64_S390_COMMON */
+
unsigned int __ro_after_init kvm_sve_max_vl;
int __init kvm_arm_init_sve(void)
@@ -169,6 +172,33 @@ static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
memset(vcpu->arch.sve_state, 0, vcpu_sve_state_size(vcpu));
}
+#ifdef ARM64_S390_COMMON
+static void kvm_reset_vcpu_core_regs(struct kvm_vcpu *vcpu)
+{
+ u32 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;
+
+ 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;
+}
+
+#endif /* ARM64_S390_COMMON */
+
/**
* kvm_reset_vcpu - sets core registers and sys_regs to reset value
* @vcpu: The VCPU pointer
@@ -191,7 +221,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,21 +239,8 @@ 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)));
- 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;
+ kvm_reset_vcpu_core_regs(vcpu);
/* Reset system registers */
kvm_reset_sys_regs(vcpu);
diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index 23cfbecebbd79a..47003a85b35a3d 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -27,6 +27,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 15da2d88c0c10c..f03872ba0ba8c6 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 c14b10821817b4..e3cb7c8c9461fd 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 b1b9a1d677581e..c65596fdf54f44 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 2d139c80757732..92d14438e31b16 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 9a0d1c1aca6c80..d97a4a51ec55e2 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 60017ceec9d2af..38333a01e5bbeb 100644
--- a/arch/riscv/include/asm/kvm_host.h
+++ b/arch/riscv/include/asm/kvm_host.h
@@ -26,6 +26,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 ec2cee0a39e01c..3aea8d4939d2eb 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/s390/Kconfig b/arch/s390/Kconfig
index 84404e6778d504..b2eaa2000b101f 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -834,7 +834,7 @@ config VFIO_CCW
config VFIO_AP
def_tristate n
prompt "VFIO support for AP devices"
- depends on KVM
+ depends on KVM_S390
depends on VFIO
depends on AP
select VFIO_MDEV
diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c
index 6bc950b92be766..b8906ba7e5e8ad 100644
--- a/arch/s390/boot/ipl_parm.c
+++ b/arch/s390/boot/ipl_parm.c
@@ -300,7 +300,7 @@ void parse_boot_command_line(void)
stack_protector_debug = 1;
#endif
-#if IS_ENABLED(CONFIG_KVM)
+#if IS_ENABLED(CONFIG_KVM_S390)
if (!strcmp(param, "prot_virt")) {
rc = kstrtobool(val, &enabled);
if (!rc && enabled)
diff --git a/arch/s390/boot/uv.c b/arch/s390/boot/uv.c
index 4568e8f81dac1d..f7b68bdcedc132 100644
--- a/arch/s390/boot/uv.c
+++ b/arch/s390/boot/uv.c
@@ -26,7 +26,7 @@ void uv_query_info(void)
if (uv_call(0, (uint64_t)&uvcb) && uvcb.header.rc != UVC_RC_MORE_DATA)
return;
- if (IS_ENABLED(CONFIG_KVM)) {
+ if (IS_ENABLED(CONFIG_KVM_S390)) {
memcpy(uv_info.inst_calls_list, uvcb.inst_calls_list, sizeof(uv_info.inst_calls_list));
uv_info.uv_base_stor_len = uvcb.uv_base_stor_len;
uv_info.guest_base_stor_len = uvcb.conf_base_phys_stor_len;
diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig
index 54637be87fb735..e9ad718a940854 100644
--- a/arch/s390/configs/debug_defconfig
+++ b/arch/s390/configs/debug_defconfig
@@ -63,7 +63,7 @@ CONFIG_IOMMUFD=y
CONFIG_CMM=m
CONFIG_APPLDATA_BASE=y
CONFIG_S390_HYPFS_FS=y
-CONFIG_KVM=m
+CONFIG_KVM_S390=m
CONFIG_KVM_S390_UCONTROL=y
CONFIG_S390_UNWIND_SELFTEST=m
CONFIG_S390_KPROBES_SANITY_TEST=m
diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
index 5f5114a253cf7c..20de85c96e9eb3 100644
--- a/arch/s390/configs/defconfig
+++ b/arch/s390/configs/defconfig
@@ -61,7 +61,8 @@ CONFIG_IOMMUFD=y
CONFIG_CMM=m
CONFIG_APPLDATA_BASE=y
CONFIG_S390_HYPFS_FS=y
-CONFIG_KVM=m
+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/arm64/kvm_emulate.h b/arch/s390/include/arm64/kvm_emulate.h
new file mode 100644
index 00000000000000..6ad21398f86f4b
--- /dev/null
+++ b/arch/s390/include/arm64/kvm_emulate.h
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#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 <arm64/kvm_arm.h>
+#include <arm64/sysreg.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;
+}
+
+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_AMO | HCR_IMO | HCR_FMO |
+ 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 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;
+}
+
+#define SPSR_SS BIT(21)
+
+static inline void kvm_skip_instr(struct kvm_vcpu *vcpu)
+{
+ *vcpu_pc(vcpu) += 4;
+ *vcpu_cpsr(vcpu) &= ~PSR_BTYPE_MASK;
+
+ /* advance the singlestep state machine */
+ *vcpu_cpsr(vcpu) &= ~SPSR_SS;
+}
+
+#include <arm64/kvm_emulate-part.h>
+
+#endif /* __S390_ARM64_KVM_EMULATE_H__ */
diff --git a/arch/s390/include/arm64/kvm_nested.h b/arch/s390/include/arm64/kvm_nested.h
new file mode 100644
index 00000000000000..e950b1a10c4176
--- /dev/null
+++ b/arch/s390/include/arm64/kvm_nested.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#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/include/asm/Kbuild b/arch/s390/include/asm/Kbuild
index 0c1fc47c3ba0a4..f6fd67d1c6513c 100644
--- a/arch/s390/include/asm/Kbuild
+++ b/arch/s390/include/asm/Kbuild
@@ -8,3 +8,6 @@ generic-y += asm-offsets.h
generic-y += mcs_spinlock.h
generic-y += mmzone.h
generic-y += ring_buffer.h
+
+generated-y += sysreg-gen-defs.h
+generated-y += kvm_arm64_modname.h
diff --git a/arch/s390/include/asm/asm-prototypes.h b/arch/s390/include/asm/asm-prototypes.h
index d4da4436d02bee..faa2afb259a1a9 100644
--- a/arch/s390/include/asm/asm-prototypes.h
+++ b/arch/s390/include/asm/asm-prototypes.h
@@ -6,6 +6,7 @@
#include <asm/bug.h>
#include <asm/fpu.h>
#include <asm/nospec-branch.h>
+#include <asm/sae.h>
#include <asm-generic/asm-prototypes.h>
#endif /* _ASM_S390_PROTOTYPES_H */
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index bb63fa4d20bb87..ad3108ecfb07be 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -123,6 +123,7 @@ enum {
HWCAP_NR_NNPA = 20,
HWCAP_NR_PCI_MIO = 21,
HWCAP_NR_SIE = 22,
+ HWCAP_NR_SAE = 23,
HWCAP_NR_MAX
};
@@ -150,6 +151,7 @@ enum {
#define HWCAP_NNPA BIT(HWCAP_NR_NNPA)
#define HWCAP_PCI_MIO BIT(HWCAP_NR_PCI_MIO)
#define HWCAP_SIE BIT(HWCAP_NR_SIE)
+#define HWCAP_SAE BIT(HWCAP_NR_SAE)
/*
* These are used to set parameters in the core dumps.
diff --git a/arch/s390/include/asm/kvm.h b/arch/s390/include/asm/kvm.h
new file mode 100644
index 00000000000000..aeb11dc631d5e4
--- /dev/null
+++ b/arch/s390/include/asm/kvm.h
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifdef KVM_S390_ARM64
+#include <uapi/arm64/kvm.h>
+#else
+#include <uapi/asm/kvm.h>
+#endif
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index eaa34c5bd3c110..0c22cc42be7e5d 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -1,778 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * definition for kernel virtual machines on s390
- *
- * Copyright IBM Corp. 2008, 2018
- *
- * Author(s): Carsten Otte <cotte@de.ibm.com>
- */
-
#ifndef ASM_KVM_HOST_H
#define ASM_KVM_HOST_H
-#include <linux/types.h>
-#include <linux/hrtimer.h>
-#include <linux/interrupt.h>
-#include <linux/kvm_types.h>
-#include <linux/kvm.h>
-#include <linux/seqlock.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/mmu_notifier.h>
-#include <asm/kvm_host_types.h>
-#include <asm/debug.h>
-#include <asm/cpu.h>
-#include <asm/fpu.h>
-#include <asm/isc.h>
-#include <asm/guarded_storage.h>
-
-#define KVM_HAVE_MMU_RWLOCK
-#define KVM_MAX_VCPUS 255
-
-#define KVM_INTERNAL_MEM_SLOTS 1
-
-/*
- * These seem to be used for allocating ->chip in the routing table, which we
- * don't use. 1 is as small as we can get to reduce the needed memory. If we
- * need to look at ->chip later on, we'll need to revisit this.
- */
-#define KVM_NR_IRQCHIPS 1
-#define KVM_IRQCHIP_NUM_PINS 1
-#define KVM_HALT_POLL_NS_DEFAULT 50000
-
-/* s390-specific vcpu->requests bit members */
-#define KVM_REQ_ENABLE_IBS KVM_ARCH_REQ(0)
-#define KVM_REQ_DISABLE_IBS KVM_ARCH_REQ(1)
-#define KVM_REQ_ICPT_OPEREXC KVM_ARCH_REQ(2)
-#define KVM_REQ_START_MIGRATION KVM_ARCH_REQ(3)
-#define KVM_REQ_STOP_MIGRATION KVM_ARCH_REQ(4)
-#define KVM_REQ_VSIE_RESTART KVM_ARCH_REQ(5)
-#define KVM_REQ_REFRESH_GUEST_PREFIX \
- KVM_ARCH_REQ_FLAGS(6, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
+#ifdef KVM_S390_ARM64
+#include <asm/kvm_host_arm64.h>
+#else
+#include <asm/kvm_host_s390.h>
+#endif
-struct kvm_vcpu_stat {
- struct kvm_vcpu_stat_generic generic;
- u64 exit_userspace;
- u64 exit_null;
- u64 exit_external_request;
- u64 exit_io_request;
- u64 exit_external_interrupt;
- u64 exit_stop_request;
- u64 exit_validity;
- u64 exit_instruction;
- u64 exit_pei;
- u64 halt_no_poll_steal;
- u64 instruction_lctl;
- u64 instruction_lctlg;
- u64 instruction_stctl;
- u64 instruction_stctg;
- u64 exit_program_interruption;
- u64 exit_instr_and_program;
- u64 exit_operation_exception;
- u64 deliver_ckc;
- u64 deliver_cputm;
- u64 deliver_external_call;
- u64 deliver_emergency_signal;
- u64 deliver_service_signal;
- u64 deliver_virtio;
- u64 deliver_stop_signal;
- u64 deliver_prefix_signal;
- u64 deliver_restart_signal;
- u64 deliver_program;
- u64 deliver_io;
- u64 deliver_machine_check;
- u64 exit_wait_state;
- u64 inject_ckc;
- u64 inject_cputm;
- u64 inject_external_call;
- u64 inject_emergency_signal;
- u64 inject_mchk;
- u64 inject_pfault_init;
- u64 inject_program;
- u64 inject_restart;
- u64 inject_set_prefix;
- u64 inject_stop_signal;
- u64 instruction_epsw;
- u64 instruction_gs;
- u64 instruction_io_other;
- u64 instruction_lpsw;
- u64 instruction_lpswe;
- u64 instruction_lpswey;
- u64 instruction_pfmf;
- u64 instruction_ptff;
- u64 instruction_sck;
- u64 instruction_sckpf;
- u64 instruction_stidp;
- u64 instruction_spx;
- u64 instruction_stpx;
- u64 instruction_stap;
- u64 instruction_iske;
- u64 instruction_ri;
- u64 instruction_rrbe;
- u64 instruction_sske;
- u64 instruction_ipte_interlock;
- u64 instruction_stsi;
- u64 instruction_stfl;
- u64 instruction_tb;
- u64 instruction_tpi;
- u64 instruction_tprot;
- u64 instruction_tsch;
- u64 instruction_sie;
- u64 instruction_essa;
- u64 instruction_sthyi;
- u64 instruction_sigp_sense;
- u64 instruction_sigp_sense_running;
- u64 instruction_sigp_external_call;
- u64 instruction_sigp_emergency;
- u64 instruction_sigp_cond_emergency;
- u64 instruction_sigp_start;
- u64 instruction_sigp_stop;
- u64 instruction_sigp_stop_store_status;
- u64 instruction_sigp_store_status;
- u64 instruction_sigp_store_adtl_status;
- u64 instruction_sigp_arch;
- u64 instruction_sigp_prefix;
- u64 instruction_sigp_restart;
- u64 instruction_sigp_init_cpu_reset;
- u64 instruction_sigp_cpu_reset;
- u64 instruction_sigp_unknown;
- u64 instruction_diagnose_10;
- u64 instruction_diagnose_44;
- u64 instruction_diagnose_9c;
- u64 diag_9c_ignored;
- u64 diag_9c_forward;
- u64 instruction_diagnose_258;
- u64 instruction_diagnose_308;
- u64 instruction_diagnose_500;
- u64 instruction_diagnose_other;
- u64 pfault_sync;
- u64 signal_exits;
-};
+static inline bool kvm_arch_pmi_in_guest(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
-#define PGM_OPERATION 0x01
-#define PGM_PRIVILEGED_OP 0x02
-#define PGM_EXECUTE 0x03
#define PGM_PROTECTION 0x04
#define PGM_ADDRESSING 0x05
-#define PGM_SPECIFICATION 0x06
-#define PGM_DATA 0x07
-#define PGM_FIXED_POINT_OVERFLOW 0x08
-#define PGM_FIXED_POINT_DIVIDE 0x09
-#define PGM_DECIMAL_OVERFLOW 0x0a
-#define PGM_DECIMAL_DIVIDE 0x0b
-#define PGM_HFP_EXPONENT_OVERFLOW 0x0c
-#define PGM_HFP_EXPONENT_UNDERFLOW 0x0d
-#define PGM_HFP_SIGNIFICANCE 0x0e
-#define PGM_HFP_DIVIDE 0x0f
#define PGM_SEGMENT_TRANSLATION 0x10
#define PGM_PAGE_TRANSLATION 0x11
-#define PGM_TRANSLATION_SPEC 0x12
-#define PGM_SPECIAL_OPERATION 0x13
-#define PGM_OPERAND 0x15
-#define PGM_TRACE_TABEL 0x16
-#define PGM_VECTOR_PROCESSING 0x1b
-#define PGM_SPACE_SWITCH 0x1c
-#define PGM_HFP_SQUARE_ROOT 0x1d
-#define PGM_PC_TRANSLATION_SPEC 0x1f
-#define PGM_AFX_TRANSLATION 0x20
-#define PGM_ASX_TRANSLATION 0x21
-#define PGM_LX_TRANSLATION 0x22
-#define PGM_EX_TRANSLATION 0x23
-#define PGM_PRIMARY_AUTHORITY 0x24
-#define PGM_SECONDARY_AUTHORITY 0x25
-#define PGM_LFX_TRANSLATION 0x26
-#define PGM_LSX_TRANSLATION 0x27
-#define PGM_ALET_SPECIFICATION 0x28
-#define PGM_ALEN_TRANSLATION 0x29
-#define PGM_ALE_SEQUENCE 0x2a
-#define PGM_ASTE_VALIDITY 0x2b
-#define PGM_ASTE_SEQUENCE 0x2c
-#define PGM_EXTENDED_AUTHORITY 0x2d
-#define PGM_LSTE_SEQUENCE 0x2e
-#define PGM_ASTE_INSTANCE 0x2f
-#define PGM_STACK_FULL 0x30
-#define PGM_STACK_EMPTY 0x31
-#define PGM_STACK_SPECIFICATION 0x32
-#define PGM_STACK_TYPE 0x33
-#define PGM_STACK_OPERATION 0x34
#define PGM_ASCE_TYPE 0x38
#define PGM_REGION_FIRST_TRANS 0x39
#define PGM_REGION_SECOND_TRANS 0x3a
#define PGM_REGION_THIRD_TRANS 0x3b
-#define PGM_SECURE_STORAGE_ACCESS 0x3d
-#define PGM_NON_SECURE_STORAGE_ACCESS 0x3e
-#define PGM_SECURE_STORAGE_VIOLATION 0x3f
-#define PGM_MONITOR 0x40
-#define PGM_PER 0x80
-#define PGM_CRYPTO_OPERATION 0x119
-
-/* irq types in ascend order of priorities */
-enum irq_types {
- IRQ_PEND_SET_PREFIX = 0,
- IRQ_PEND_RESTART,
- IRQ_PEND_SIGP_STOP,
- IRQ_PEND_IO_ISC_7,
- IRQ_PEND_IO_ISC_6,
- IRQ_PEND_IO_ISC_5,
- IRQ_PEND_IO_ISC_4,
- IRQ_PEND_IO_ISC_3,
- IRQ_PEND_IO_ISC_2,
- IRQ_PEND_IO_ISC_1,
- IRQ_PEND_IO_ISC_0,
- IRQ_PEND_VIRTIO,
- IRQ_PEND_PFAULT_DONE,
- IRQ_PEND_PFAULT_INIT,
- IRQ_PEND_EXT_HOST,
- IRQ_PEND_EXT_SERVICE,
- IRQ_PEND_EXT_SERVICE_EV,
- IRQ_PEND_EXT_TIMING,
- IRQ_PEND_EXT_CPU_TIMER,
- IRQ_PEND_EXT_CLOCK_COMP,
- IRQ_PEND_EXT_EXTERNAL,
- IRQ_PEND_EXT_EMERGENCY,
- IRQ_PEND_EXT_MALFUNC,
- IRQ_PEND_EXT_IRQ_KEY,
- IRQ_PEND_MCHK_REP,
- IRQ_PEND_PROG,
- IRQ_PEND_SVC,
- IRQ_PEND_MCHK_EX,
- IRQ_PEND_COUNT
-};
-
-/* We have 2M for virtio device descriptor pages. Smallest amount of
- * memory per page is 24 bytes (1 queue), so (2048*1024) / 24 = 87381
- */
-#define KVM_S390_MAX_VIRTIO_IRQS 87381
-
-/*
- * Repressible (non-floating) machine check interrupts
- * subclass bits in MCIC
- */
-#define MCHK_EXTD_BIT 58
-#define MCHK_DEGR_BIT 56
-#define MCHK_WARN_BIT 55
-#define MCHK_REP_MASK ((1UL << MCHK_DEGR_BIT) | \
- (1UL << MCHK_EXTD_BIT) | \
- (1UL << MCHK_WARN_BIT))
-
-/* Exigent machine check interrupts subclass bits in MCIC */
-#define MCHK_SD_BIT 63
-#define MCHK_PD_BIT 62
-#define MCHK_EX_MASK ((1UL << MCHK_SD_BIT) | (1UL << MCHK_PD_BIT))
-
-#define IRQ_PEND_EXT_MASK ((1UL << IRQ_PEND_EXT_IRQ_KEY) | \
- (1UL << IRQ_PEND_EXT_CLOCK_COMP) | \
- (1UL << IRQ_PEND_EXT_CPU_TIMER) | \
- (1UL << IRQ_PEND_EXT_MALFUNC) | \
- (1UL << IRQ_PEND_EXT_EMERGENCY) | \
- (1UL << IRQ_PEND_EXT_EXTERNAL) | \
- (1UL << IRQ_PEND_EXT_TIMING) | \
- (1UL << IRQ_PEND_EXT_HOST) | \
- (1UL << IRQ_PEND_EXT_SERVICE) | \
- (1UL << IRQ_PEND_EXT_SERVICE_EV) | \
- (1UL << IRQ_PEND_VIRTIO) | \
- (1UL << IRQ_PEND_PFAULT_INIT) | \
- (1UL << IRQ_PEND_PFAULT_DONE))
-
-#define IRQ_PEND_IO_MASK ((1UL << IRQ_PEND_IO_ISC_0) | \
- (1UL << IRQ_PEND_IO_ISC_1) | \
- (1UL << IRQ_PEND_IO_ISC_2) | \
- (1UL << IRQ_PEND_IO_ISC_3) | \
- (1UL << IRQ_PEND_IO_ISC_4) | \
- (1UL << IRQ_PEND_IO_ISC_5) | \
- (1UL << IRQ_PEND_IO_ISC_6) | \
- (1UL << IRQ_PEND_IO_ISC_7))
-
-#define IRQ_PEND_MCHK_MASK ((1UL << IRQ_PEND_MCHK_REP) | \
- (1UL << IRQ_PEND_MCHK_EX))
-
-#define IRQ_PEND_EXT_II_MASK ((1UL << IRQ_PEND_EXT_CPU_TIMER) | \
- (1UL << IRQ_PEND_EXT_CLOCK_COMP) | \
- (1UL << IRQ_PEND_EXT_EMERGENCY) | \
- (1UL << IRQ_PEND_EXT_EXTERNAL) | \
- (1UL << IRQ_PEND_EXT_SERVICE) | \
- (1UL << IRQ_PEND_EXT_SERVICE_EV))
-
-struct kvm_s390_interrupt_info {
- struct list_head list;
- u64 type;
- union {
- struct kvm_s390_io_info io;
- struct kvm_s390_ext_info ext;
- struct kvm_s390_pgm_info pgm;
- struct kvm_s390_emerg_info emerg;
- struct kvm_s390_extcall_info extcall;
- struct kvm_s390_prefix_info prefix;
- struct kvm_s390_stop_info stop;
- struct kvm_s390_mchk_info mchk;
- };
-};
-
-struct kvm_s390_irq_payload {
- struct kvm_s390_io_info io;
- struct kvm_s390_ext_info ext;
- struct kvm_s390_pgm_info pgm;
- struct kvm_s390_emerg_info emerg;
- struct kvm_s390_extcall_info extcall;
- struct kvm_s390_prefix_info prefix;
- struct kvm_s390_stop_info stop;
- struct kvm_s390_mchk_info mchk;
-};
-
-struct kvm_s390_local_interrupt {
- spinlock_t lock;
- DECLARE_BITMAP(sigp_emerg_pending, KVM_MAX_VCPUS);
- struct kvm_s390_irq_payload irq;
- unsigned long pending_irqs;
-};
-
-#define FIRQ_LIST_IO_ISC_0 0
-#define FIRQ_LIST_IO_ISC_1 1
-#define FIRQ_LIST_IO_ISC_2 2
-#define FIRQ_LIST_IO_ISC_3 3
-#define FIRQ_LIST_IO_ISC_4 4
-#define FIRQ_LIST_IO_ISC_5 5
-#define FIRQ_LIST_IO_ISC_6 6
-#define FIRQ_LIST_IO_ISC_7 7
-#define FIRQ_LIST_PFAULT 8
-#define FIRQ_LIST_VIRTIO 9
-#define FIRQ_LIST_COUNT 10
-#define FIRQ_CNTR_IO 0
-#define FIRQ_CNTR_SERVICE 1
-#define FIRQ_CNTR_VIRTIO 2
-#define FIRQ_CNTR_PFAULT 3
-#define FIRQ_MAX_COUNT 4
-
-/* mask the AIS mode for a given ISC */
-#define AIS_MODE_MASK(isc) (0x80 >> isc)
-
-#define KVM_S390_AIS_MODE_ALL 0
-#define KVM_S390_AIS_MODE_SINGLE 1
-
-struct kvm_s390_float_interrupt {
- unsigned long pending_irqs;
- unsigned long masked_irqs;
- spinlock_t lock;
- struct list_head lists[FIRQ_LIST_COUNT];
- int counters[FIRQ_MAX_COUNT];
- struct kvm_s390_mchk_info mchk;
- struct kvm_s390_ext_info srv_signal;
- int last_sleep_cpu;
- spinlock_t ais_lock;
- u8 simm;
- u8 nimm;
-};
-
-struct kvm_hw_wp_info_arch {
- unsigned long addr;
- unsigned long phys_addr;
- int len;
- char *old_data;
-};
-
-struct kvm_hw_bp_info_arch {
- unsigned long addr;
- int len;
-};
-
-/*
- * Only the upper 16 bits of kvm_guest_debug->control are arch specific.
- * Further KVM_GUESTDBG flags which an be used from userspace can be found in
- * arch/s390/include/uapi/asm/kvm.h
- */
-#define KVM_GUESTDBG_EXIT_PENDING 0x10000000
-
-#define guestdbg_enabled(vcpu) \
- (vcpu->guest_debug & KVM_GUESTDBG_ENABLE)
-#define guestdbg_sstep_enabled(vcpu) \
- (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
-#define guestdbg_hw_bp_enabled(vcpu) \
- (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
-#define guestdbg_exit_pending(vcpu) (guestdbg_enabled(vcpu) && \
- (vcpu->guest_debug & KVM_GUESTDBG_EXIT_PENDING))
-
-#define KVM_GUESTDBG_VALID_MASK \
- (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP |\
- KVM_GUESTDBG_USE_HW_BP | KVM_GUESTDBG_EXIT_PENDING)
-
-struct kvm_guestdbg_info_arch {
- unsigned long cr0;
- unsigned long cr9;
- unsigned long cr10;
- unsigned long cr11;
- struct kvm_hw_bp_info_arch *hw_bp_info;
- struct kvm_hw_wp_info_arch *hw_wp_info;
- int nr_hw_bp;
- int nr_hw_wp;
- unsigned long last_bp;
-};
-
-struct kvm_s390_pv_vcpu {
- u64 handle;
- unsigned long stor_base;
-};
-
-struct kvm_vcpu_arch {
- struct kvm_s390_sie_block *sie_block;
- /* if vsie is active, currently executed shadow sie control block */
- struct kvm_s390_sie_block *vsie_block;
- unsigned int host_acrs[NUM_ACRS];
- struct gs_cb *host_gscb;
- struct kvm_s390_local_interrupt local_int;
- struct hrtimer ckc_timer;
- struct kvm_s390_pgm_info pgm;
- struct gmap *gmap;
- struct kvm_guestdbg_info_arch guestdbg;
- unsigned long pfault_token;
- unsigned long pfault_select;
- unsigned long pfault_compare;
- bool cputm_enabled;
- /*
- * The seqcount protects updates to cputm_start and sie_block.cputm,
- * this way we can have non-blocking reads with consistent values.
- * Only the owning VCPU thread (vcpu->cpu) is allowed to change these
- * values and to start/stop/enable/disable cpu timer accounting.
- */
- seqcount_t cputm_seqcount;
- __u64 cputm_start;
- bool gs_enabled;
- bool skey_enabled;
- /* Indicator if the access registers have been loaded from guest */
- bool acrs_loaded;
- struct kvm_s390_pv_vcpu pv;
- union diag318_info diag318_info;
- struct kvm_s390_mmu_cache *mc;
-};
-
-struct kvm_vm_stat {
- struct kvm_vm_stat_generic generic;
- u64 inject_io;
- u64 io_390_adapter_map;
- u64 io_390_adapter_unmap;
- u64 io_390_inatomic;
- u64 io_flic_inject_airq;
- u64 io_set_adapter_int;
- u64 io_390_inatomic_no_inject;
- u64 inject_float_mchk;
- u64 inject_pfault_done;
- u64 inject_service_signal;
- u64 inject_virtio;
- u64 aen_forward;
- u64 gmap_shadow_create;
- u64 gmap_shadow_reuse;
- u64 gmap_shadow_r1_entry;
- u64 gmap_shadow_r2_entry;
- u64 gmap_shadow_r3_entry;
- u64 gmap_shadow_sg_entry;
- u64 gmap_shadow_pg_entry;
-};
-
-struct kvm_arch_memory_slot {
-};
-
-struct s390_map_info {
- struct list_head list;
- __u64 guest_addr;
- __u64 addr;
- struct page *page;
-};
-
-struct s390_io_adapter {
- unsigned int id;
- int isc;
- bool maskable;
- bool masked;
- bool swap;
- bool suppressible;
- spinlock_t maps_lock;
- struct list_head maps;
- unsigned int nr_maps;
-};
-
-#define MAX_S390_IO_ADAPTERS ((MAX_ISC + 1) * 8)
-#define MAX_S390_ADAPTER_MAPS 256
-
-/* maximum size of facilities and facility mask is 2k bytes */
-#define S390_ARCH_FAC_LIST_SIZE_BYTE (1<<11)
-#define S390_ARCH_FAC_LIST_SIZE_U64 \
- (S390_ARCH_FAC_LIST_SIZE_BYTE / sizeof(u64))
-#define S390_ARCH_FAC_MASK_SIZE_BYTE S390_ARCH_FAC_LIST_SIZE_BYTE
-#define S390_ARCH_FAC_MASK_SIZE_U64 \
- (S390_ARCH_FAC_MASK_SIZE_BYTE / sizeof(u64))
-
-struct kvm_s390_cpu_model {
- /* facility mask supported by kvm & hosting machine */
- __u64 fac_mask[S390_ARCH_FAC_MASK_SIZE_U64];
- struct kvm_s390_vm_cpu_subfunc subfuncs;
- /* facility list requested by guest (in dma page) */
- __u64 *fac_list;
- u64 cpuid;
- unsigned short ibc;
- /* subset of available UV-features for pv-guests enabled by user space */
- struct kvm_s390_vm_cpu_uv_feat uv_feat_guest;
-};
-
-#define S390_ARCH_FAC_FORMAT_2 2
-struct kvm_s390_flcb2 {
- union {
- struct {
- u8 reserved0[7];
- u8 length;
- };
- u64 header_val;
- };
- u64 facilities[S390_ARCH_FAC_LIST_SIZE_U64];
-};
-
-typedef int (*crypto_hook)(struct kvm_vcpu *vcpu);
-struct kvm_s390_crypto {
- struct kvm_s390_crypto_cb *crycb;
- struct rw_semaphore pqap_hook_rwsem;
- crypto_hook *pqap_hook;
- __u32 crycbd;
- __u8 aes_kw;
- __u8 dea_kw;
- __u8 apie;
-};
-
-#define APCB0_MASK_SIZE 1
-struct kvm_s390_apcb0 {
- __u64 apm[APCB0_MASK_SIZE]; /* 0x0000 */
- __u64 aqm[APCB0_MASK_SIZE]; /* 0x0008 */
- __u64 adm[APCB0_MASK_SIZE]; /* 0x0010 */
- __u64 reserved18; /* 0x0018 */
-};
-
-#define APCB1_MASK_SIZE 4
-struct kvm_s390_apcb1 {
- __u64 apm[APCB1_MASK_SIZE]; /* 0x0000 */
- __u64 aqm[APCB1_MASK_SIZE]; /* 0x0020 */
- __u64 adm[APCB1_MASK_SIZE]; /* 0x0040 */
- __u64 reserved60[4]; /* 0x0060 */
-};
-
-struct kvm_s390_crypto_cb {
- struct kvm_s390_apcb0 apcb0; /* 0x0000 */
- __u8 reserved20[0x0048 - 0x0020]; /* 0x0020 */
- __u8 dea_wrapping_key_mask[24]; /* 0x0048 */
- __u8 aes_wrapping_key_mask[32]; /* 0x0060 */
- struct kvm_s390_apcb1 apcb1; /* 0x0080 */
-};
-
-struct kvm_s390_gisa {
- union {
- struct { /* common to all formats */
- u32 next_alert;
- u8 ipm;
- u8 reserved01[2];
- u8 iam;
- };
- struct { /* format 0 */
- u32 next_alert;
- u8 ipm;
- u8 reserved01;
- u8 : 6;
- u8 g : 1;
- u8 c : 1;
- u8 iam;
- u8 reserved02[4];
- u32 airq_count;
- } g0;
- struct { /* format 1 */
- u32 next_alert;
- u8 ipm;
- u8 simm;
- u8 nimm;
- u8 iam;
- u8 aism[8];
- u8 : 6;
- u8 g : 1;
- u8 c : 1;
- u8 reserved03[11];
- u32 airq_count;
- } g1;
- struct {
- u64 word[4];
- } u64;
- };
-};
-
-struct kvm_s390_gib {
- u32 alert_list_origin;
- u32 reserved01;
- u8:5;
- u8 nisc:3;
- u8 reserved03[3];
- u32 reserved04[5];
-};
-
-/*
- * sie_page2 has to be allocated as DMA because fac_list, crycb and
- * gisa need 31bit addresses in the sie control block.
- */
-struct sie_page2 {
- __u64 fac_list[S390_ARCH_FAC_LIST_SIZE_U64]; /* 0x0000 */
- struct kvm_s390_crypto_cb crycb; /* 0x0800 */
- struct kvm_s390_gisa gisa; /* 0x0900 */
- struct kvm *kvm; /* 0x0920 */
- u8 reserved928[0x1000 - 0x928]; /* 0x0928 */
-};
-
-struct vsie_page;
-
-struct kvm_s390_vsie {
- struct mutex mutex;
- struct radix_tree_root addr_to_page;
- int page_count;
- int next;
- struct vsie_page *pages[KVM_MAX_VCPUS];
-};
-
-struct kvm_s390_gisa_iam {
- u8 mask;
- spinlock_t ref_lock;
- u32 ref_count[MAX_ISC + 1];
-};
-
-struct kvm_s390_gisa_interrupt {
- struct kvm_s390_gisa *origin;
- struct kvm_s390_gisa_iam alert;
- struct hrtimer timer;
- u64 expires;
- DECLARE_BITMAP(kicked_mask, KVM_MAX_VCPUS);
-};
-
-struct kvm_s390_pv {
- u64 handle;
- u64 guest_len;
- unsigned long stor_base;
- void *stor_var;
- bool dumping;
- void *set_aside;
- struct list_head need_cleanup;
- struct mmu_notifier mmu_notifier;
- /* Protects against concurrent import-like operations */
- struct mutex import_lock;
-};
-
-struct kvm_s390_mmu_cache;
-
-struct kvm_arch {
- struct esca_block *sca;
- debug_info_t *dbf;
- struct kvm_s390_float_interrupt float_int;
- struct kvm_device *flic;
- struct gmap *gmap;
- unsigned long mem_limit;
- int css_support;
- int use_irqchip;
- int use_cmma;
- int use_pfmfi;
- int use_skf;
- int use_zpci_interp;
- int user_cpu_state_ctrl;
- int user_sigp;
- int user_stsi;
- int user_instr0;
- int user_operexec;
- int allow_vsie_esamode;
- struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
- wait_queue_head_t ipte_wq;
- int ipte_lock_count;
- struct mutex ipte_mutex;
- spinlock_t start_stop_lock;
- struct sie_page2 *sie_page2;
- struct kvm_s390_cpu_model model;
- struct kvm_s390_crypto crypto;
- struct kvm_s390_vsie vsie;
- u8 epdx;
- u64 epoch;
- int migration_mode;
- atomic64_t cmma_dirty_pages;
- /* subset of available cpu features enabled by user space */
- DECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
- /* indexed by vcpu_idx */
- DECLARE_BITMAP(idle_mask, KVM_MAX_VCPUS);
- struct kvm_s390_gisa_interrupt gisa_int;
- struct kvm_s390_pv pv;
- struct list_head kzdev_list;
- spinlock_t kzdev_list_lock;
- struct kvm_s390_mmu_cache *mc;
-};
-
-#define KVM_HVA_ERR_BAD (-1UL)
-#define KVM_HVA_ERR_RO_BAD (-2UL)
-
-static inline bool kvm_is_error_hva(unsigned long addr)
-{
- return IS_ERR_VALUE(addr);
-}
-
-#define ASYNC_PF_PER_VCPU 64
-struct kvm_arch_async_pf {
- unsigned long pfault_token;
-};
-
-bool kvm_arch_can_dequeue_async_page_present(struct kvm_vcpu *vcpu);
-
-void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,
- struct kvm_async_pf *work);
-
-bool kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
- struct kvm_async_pf *work);
-
-void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
- struct kvm_async_pf *work);
-
-static inline void kvm_arch_async_page_present_queued(struct kvm_vcpu *vcpu) {}
-
-void kvm_arch_crypto_clear_masks(struct kvm *kvm);
-void kvm_arch_crypto_set_masks(struct kvm *kvm, unsigned long *apm,
- unsigned long *aqm, unsigned long *adm);
-
-#define SIE64_RETURN_NORMAL 0
-#define SIE64_RETURN_MCCK 1
-
-int __sie64a(phys_addr_t sie_block_phys, struct kvm_s390_sie_block *sie_block, u64 *rsa,
- unsigned long gasce);
-
-static inline int sie64a(struct kvm_s390_sie_block *sie_block, u64 *rsa, unsigned long gasce)
-{
- return __sie64a(virt_to_phys(sie_block), sie_block, rsa, gasce);
-}
-
-extern char sie_exit;
-
-bool kvm_s390_pv_is_protected(struct kvm *kvm);
-bool kvm_s390_pv_cpu_is_protected(struct kvm_vcpu *vcpu);
-
-extern int kvm_s390_enter_exit_sie(struct kvm_s390_sie_block *scb,
- u64 *gprs, unsigned long gasce);
-
-extern int kvm_s390_gisc_register(struct kvm *kvm, u32 gisc);
-extern int kvm_s390_gisc_unregister(struct kvm *kvm, u32 gisc);
-
-bool kvm_s390_is_gpa_in_memslot(struct kvm *kvm, gpa_t gpa);
-
-static inline void kvm_arch_free_memslot(struct kvm *kvm,
- struct kvm_memory_slot *slot) {}
-static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
-static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {}
-static inline void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
- struct kvm_memory_slot *slot) {}
-static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {}
-static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {}
-
-#define __KVM_HAVE_ARCH_VM_FREE
-void kvm_arch_free_vm(struct kvm *kvm);
-
-struct zpci_kvm_hook {
- int (*kvm_register)(void *opaque, struct kvm *kvm);
- void (*kvm_unregister)(void *opaque);
-};
-
-extern struct zpci_kvm_hook zpci_kvm_hook;
-
-#endif
+#endif /* ASM_KVM_HOST_H */
diff --git a/arch/s390/include/asm/kvm_host_arm64.h b/arch/s390/include/asm/kvm_host_arm64.h
new file mode 100644
index 00000000000000..6d08856fe39538
--- /dev/null
+++ b/arch/s390/include/asm/kvm_host_arm64.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ASM_KVM_HOST_ARM64_H
+#define ASM_KVM_HOST_ARM64_H
+
+#include <linux/bug.h>
+
+#include <asm/kvm_host_types.h>
+#include <asm/debug.h>
+
+#define vcpu_gp_regs(v) ((v)->arch.sae_block.gpr)
+
+#define HAVE_KVM_MMIO
+
+#include <arm64/kvm_host.h>
+#include <asm/sae.h>
+
+#define KVM_HAVE_MMU_RWLOCK
+#define KVM_MAX_VCPUS 1
+
+#define KVM_HALT_POLL_NS_DEFAULT 50000
+
+/* Minimal (=no) vgic definitions */
+#define KVM_IRQCHIP_NUM_PINS 1
+#define irqchip_in_kernel(_v) false;
+
+#define __ctxt_sys_reg(ctx, reg) NULL
+struct kvm_cpu_context {
+ /*
+ * These are just for 32 bit, which we don't have, making them RES0.
+ * They are exposed to user space.
+ */
+ u64 spsr_abt;
+ u64 spsr_und;
+ u64 spsr_irq;
+ u64 spsr_fiq;
+
+ __vector128 __aligned(16) vregs[32];
+};
+
+struct kvm_vcpu_arch {
+ struct kvm_sae_block sae_block;
+ struct kvm_sae_save_area save_area;
+ struct kvm_cpu_context ctxt;
+
+ u32 host_acrs[NUM_ACRS];
+
+ /* Hypervisor Configuration Register */
+ u64 hcr_elz;
+
+ /* Configuration flags, set once and for all before the vcpu can run */
+ u8 cflags;
+
+ /* Input flags to the hypervisor code, potentially cleared after use */
+ u8 iflags;
+
+ /* State flags for kernel bookkeeping, unused by the hypervisor code */
+ u8 sflags;
+
+ /*
+ * Don't run the guest (internal implementation need).
+ *
+ * Contrary to the flags above, this is set/cleared outside of
+ * a vcpu context, and thus cannot be mixed with the flags
+ * themselves (or the flag accesses need to be made atomic).
+ */
+ bool pause;
+
+ /* vcpu power state */
+ struct kvm_mp_state mp_state;
+ /* lock for mp_state & reset_state.reset */
+ spinlock_t mp_state_lock;
+
+ /* vcpu reset state */
+ struct vcpu_reset_state reset_state;
+
+ /* GMAP */
+ struct gmap *gmap;
+ struct kvm_s390_mmu_cache *mc;
+
+ void *debugfs_state_data;
+};
+
+struct kvm_vcpu_stat {
+ struct kvm_vcpu_stat_generic generic;
+ /* ARM64 stats */
+ u64 hvc_exit_stat;
+ u64 wfe_exit_stat;
+ u64 wfi_exit_stat;
+ u64 mmio_exit_user;
+ u64 mmio_exit_kernel;
+ u64 signal_exits;
+ u64 exits;
+ /* GMAP stats */
+ u64 pfault_sync;
+};
+
+#define kvm_vcpu_get_sp_el1(__vcpu) (&((__vcpu)->arch.sae_block.sp_el1))
+#define kvm_vcpu_get_vreg(__vcpu, _off) (&(__vcpu)->arch.ctxt.vregs[_off])
+#define kvm_vcpu_get_vregs(__vcpu) (&(__vcpu)->arch.ctxt.vregs)
+#define kvm_vcpu_get_fpsr(__vcpu) (&(__vcpu)->arch.sae_block.fpsr)
+#define kvm_vcpu_get_fpcr(__vcpu) (&(__vcpu)->arch.sae_block.fpcr)
+
+#define __vcpu_flags_preempt_disable() preempt_disable()
+#define __vcpu_flags_preempt_enable() preempt_enable()
+
+#define _vcpu_get_flag(v, flagset, ...) \
+ __vcpu_get_flag(&(v)->arch.flagset, __VA_ARGS__)
+#define _vcpu_set_flag(v, flagset, ...) \
+ __vcpu_set_flag(&(v)->arch.flagset, __VA_ARGS__)
+#define _vcpu_clear_flag(v, flagset, ...) \
+ __vcpu_clear_flag(&(v)->arch.flagset, __VA_ARGS__)
+#define _vcpu_test_and_clear_flag(v, flagset, ...) \
+ __vcpu_test_and_clear_flag(&(v)->arch.flagset, __VA_ARGS__)
+
+#define kvm_has_mte(_kvm) false
+#define vcpu_has_sve(_vcpu) false
+#define vcpu_has_ptrauth(_vcpu) false
+
+struct kvm_arch_memory_slot {
+};
+
+struct kvm_arch {
+ struct gmap *gmap;
+ u64 guest_phys_size;
+
+ /* VM-wide vCPU feature set */
+ unsigned long flags;
+
+ /* Protects VM-scoped configuration data */
+ struct mutex config_lock;
+
+ debug_info_t *dbf;
+
+ DECLARE_BITMAP(vcpu_features, KVM_VCPU_MAX_FEATURES);
+
+ unsigned long mem_limit;
+};
+
+static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature)
+{
+ return test_bit(feature, ka->vcpu_features);
+}
+
+#define vcpu_has_feature(v, f) __vcpu_has_feature(&(v)->kvm->arch, (f))
+
+struct kvm_vm_stat {
+ struct kvm_vm_stat_generic generic;
+};
+
+#define kvm_vm_is_protected(_kvm) false
+
+#define vcpu_is_loaded(_vcpu) ((_vcpu)->cpu != -1)
+
+#define KVM_HVA_ERR_BAD -1UL
+#define KVM_HVA_ERR_RO_BAD -2UL
+
+#define kvm_phys_size(__kvm) ((__kvm)->arch.guest_phys_size)
+static inline bool kvm_is_error_hva(unsigned long addr)
+{
+ return IS_ERR_VALUE(addr);
+}
+
+u32 get_kvm_ipa_limit(void);
+
+static inline void kvm_arch_sync_events(struct kvm *kvm) {}
+static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
+
+int kvm_handle_guest_abort(struct kvm_vcpu *vcpu);
+
+/* arm64 guests do not use async-pf. Defined because Kbuild requires it as s390 kvm turns it on. */
+#define ASYNC_PF_PER_VCPU 0
+struct kvm_arch_async_pf {
+ unsigned long pfault_token;
+};
+
+#define __unsupp_async_call(fn) WARN_ONCE(true, "async not supported on kvm-arm64 %s", fn)
+
+static inline bool kvm_arch_can_dequeue_async_page_present(struct kvm_vcpu *vcpu)
+{
+ __unsupp_async_call(__func__);
+ return false;
+};
+
+static inline void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+ __unsupp_async_call(__func__);
+};
+
+static inline bool kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+ __unsupp_async_call(__func__);
+ return false;
+};
+
+static inline void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+ __unsupp_async_call(__func__);
+};
+
+static inline void kvm_arch_async_page_present_queued(struct kvm_vcpu *vcpu)
+{
+ __unsupp_async_call(__func__);
+};
+
+#define kvm_supports_32bit_el0() false
+
+#endif /* ASM_KVM_HOST_ARM64_H */
diff --git a/arch/s390/include/asm/kvm_host_arm64_types.h b/arch/s390/include/asm/kvm_host_arm64_types.h
new file mode 100644
index 00000000000000..3882d5462a05a8
--- /dev/null
+++ b/arch/s390/include/asm/kvm_host_arm64_types.h
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ASM_KVM_HOST_ARM64_TYPES_H
+#define ASM_KVM_HOST_ARM64_TYPES_H
+
+#include <linux/types.h>
+#include <linux/kvm_types.h>
+#include <linux/compiler_attributes.h>
+#include <asm/page.h>
+#include <asm/fault.h>
+
+struct kvm_sae_block {
+ u64 _0000[16]; /* 0x0000 */
+#define SAE_ICPTR_SPURIOUS 0x00
+#define SAE_ICPTR_VALIDITY 0x01
+#define SAE_ICPTR_HOST_ACCESS_EXCEPTION 0x02
+#define SAE_ICPTR_SYNCHRONOUS_EXCEPTION 0x03
+#define SAE_ICPTR_TIMER 0x04
+#define SAE_ICPTR_PE_INTERCOMM 0x05
+#define SAE_ICPTR_GUEST_ADDRESS_SIZE 0x06
+#define SAE_ICPTR_STOP 0x07
+#define SAE_ICPTR_SYSTEM_REGISTER 0x08
+#define SAE_ICPTR_PMU 0x09
+#define SAE_ICPTR_MAINTENANCE 0x0a
+ u8 icptr; /* 0x0080 */
+ u8 _0081[7]; /* 0x0081 */
+ u64 scad; /* 0x0088 */
+ u64 _0090[16]; /* 0x00b0 */
+ u32 cntp_ctl; /* 0x0110 */
+ u32 cntv_ctl; /* 0x0114 */
+ u8 irq_ctl; /* 0x0118 */
+ u8 _0119[7]; /* 0x0119 */
+ struct {
+ u64 ich_hcr_el2; /* 0x0120 */
+ u64 ich_vmcr_el2; /* 0x0128 */
+ u64 ich_ap0r0_el2; /* 0x0130 */
+ u64 ich_ap1r0_el2; /* 0x0138 */
+ u64 _0140[2]; /* 0x0140 */
+ u64 ich_lrn_el2[4]; /* 0x0150 */
+ u64 _0170[4]; /* 0x0170 */
+ } ic_regs;
+ u64 _0190[12]; /* 0x0190 */
+ u64 contextidr_el1; /* 0x01f0 */
+ u32 wip; /* 0x01f8 */
+ u32 _01fc; /* 0x01fc */
+#define SAE_SD_FORMAT_0 0x00
+ u8 sdf; /* 0x0200 */
+ u8 _0201[7]; /* 0x0201 */
+ u64 mso; /* 0x0208 */
+ u64 msl; /* 0x0210 */
+ u64 hbasce; /* 0x0218 */
+ u64 _0220; /* 0x0220 */
+ u64 gpto; /* 0x0228 */
+ u64 ic; /* 0x0230 */
+ u64 ec; /* 0x0238 */
+ u64 save_area; /* 0x0240 */
+ u64 _0248[7]; /* 0x0248 */
+ u8 _0280[6]; /* 0x0280 */
+ u16 lrcpua; /* 0x0286 */
+ u64 pstate; /* 0x0288 */
+ u64 pc; /* 0x0290 */
+ u64 sp_el0; /* 0x0298 */
+ u64 sp_el1; /* 0x02a0 */
+ u64 _02a8; /* 0x02a8 */
+ u64 fpcr; /* 0x02b0 */
+ u64 fpsr; /* 0x02b8 */
+ u16 sve_pregs[16]; /* 0x02c0 */
+ u16 sve_ffr; /* 0x02e0 */
+ u8 _02e2[6]; /* 0x02e2 */
+ u64 _02e8[3]; /* 0x02e8 */
+
+ u64 gpr[31]; /* 0x0300 */
+ u64 _03f8; /* 0x03f8 */
+
+ union {
+ u64 icptd[8]; /* 0x0400 */
+ /* validity-interception reason; icptr 0x01 */
+#define SAE_VIR_UNKNOWN 0x00
+#define SAE_VIR_UNSUPP_FORMAT 0x01
+#define SAE_VIR_MSO_BOUNDS 0x02
+#define SAE_VIR_MSLA 0x03
+#define SAE_VIR_MGPAS 0x04
+#define SAE_VIR_INVAL_SYSREG 0x05
+#define SAE_VIR_HOST_CONTROL 0x06
+#define SAE_VIR_SCA 0x07
+#define SAE_VIR_MSO_ALIGN 0x08
+#define SAE_VIR_HLC 0x09
+#define SAE_VIR_IRPTC 0x0a
+ u16 vir; /* 0x0400 */
+ /* host access interception details; icptr 0x02 */
+ struct {
+ u64 esr_elz; /* 0x0400 */
+ u8 _0408[6]; /* 0x0408 */
+ u16 pic; /* 0x040e */
+ union teid teid; /* 0x0410 */
+ gva_t far_elz; /* 0x0418 */
+ gva_t vaddr; /* 0x0420 */
+ u64 suppl; /* 0x0428 */
+ u8 gltl; /* 0x0430 */
+ u8 _0431[7]; /* 0x0431 */
+ u64 _0438; /* 0x0438 */
+ } hai;
+ /* exception-interception details; icptr 0x03 */
+ struct {
+ u64 esr_elz; /* 0x0400 */
+ u64 _0408[2]; /* 0x0408 */
+ gva_t far_elz; /* 0x0418 */
+ } trap;
+ /* timer-interception reason; icptr 0x04 */
+#define SAE_IR_TIMER_ID_VIRT BIT(6)
+#define SAE_IR_TIMER_ID_PHYS BIT(7)
+ u8 tir; /* 0x0400 */
+ };
+ u64 _0440[376]; /* 0x0440 */
+} __packed __aligned(PAGE_SIZE);
+static_assert(sizeof(struct kvm_sae_block) == PAGE_SIZE);
+
+struct kvm_sae_save_area {
+#define SAE_SAVE_AREA_FORMAT_0 0x00
+ u8 saf; /* 0x0000 */
+ u8 _0001[5]; /* 0x0001 */
+#define SAE_SAS_VALID BIT(0)
+ u16 sas; /* 0x0006 */
+ u64 sdo; /* 0x0008 */
+ u64 _0010[2]; /* 0x0010 */
+ u64 regs[508]; /* 0x0020 */
+} __packed __aligned(PAGE_SIZE);
+static_assert(sizeof(struct kvm_sae_save_area) == PAGE_SIZE);
+
+#endif /* ASM_KVM_HOST_ARM64_TYPES_H */
diff --git a/arch/s390/include/asm/kvm_host_s390.h b/arch/s390/include/asm/kvm_host_s390.h
new file mode 100644
index 00000000000000..7b7aa166cff730
--- /dev/null
+++ b/arch/s390/include/asm/kvm_host_s390.h
@@ -0,0 +1,773 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * definition for kernel virtual machines on s390
+ *
+ * Copyright IBM Corp. 2008, 2018
+ *
+ * Author(s): Carsten Otte <cotte@de.ibm.com>
+ */
+
+
+#ifndef ASM_KVM_HOST_S390_H
+#define ASM_KVM_HOST_S390_H
+
+#include <linux/types.h>
+#include <linux/hrtimer.h>
+#include <linux/interrupt.h>
+#include <linux/kvm_types.h>
+#include <linux/kvm.h>
+#include <linux/seqlock.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/mmu_notifier.h>
+#include <asm/kvm_host_types.h>
+#include <asm/debug.h>
+#include <asm/cpu.h>
+#include <asm/fpu.h>
+#include <asm/isc.h>
+#include <asm/guarded_storage.h>
+
+#define KVM_HAVE_MMU_RWLOCK
+#define KVM_MAX_VCPUS 255
+
+#define KVM_INTERNAL_MEM_SLOTS 1
+
+/*
+ * These seem to be used for allocating ->chip in the routing table, which we
+ * don't use. 1 is as small as we can get to reduce the needed memory. If we
+ * need to look at ->chip later on, we'll need to revisit this.
+ */
+#define KVM_NR_IRQCHIPS 1
+#define KVM_IRQCHIP_NUM_PINS 1
+#define KVM_HALT_POLL_NS_DEFAULT 50000
+
+/* s390-specific vcpu->requests bit members */
+#define KVM_REQ_ENABLE_IBS KVM_ARCH_REQ(0)
+#define KVM_REQ_DISABLE_IBS KVM_ARCH_REQ(1)
+#define KVM_REQ_ICPT_OPEREXC KVM_ARCH_REQ(2)
+#define KVM_REQ_START_MIGRATION KVM_ARCH_REQ(3)
+#define KVM_REQ_STOP_MIGRATION KVM_ARCH_REQ(4)
+#define KVM_REQ_VSIE_RESTART KVM_ARCH_REQ(5)
+#define KVM_REQ_REFRESH_GUEST_PREFIX \
+ KVM_ARCH_REQ_FLAGS(6, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
+
+struct kvm_vcpu_stat {
+ struct kvm_vcpu_stat_generic generic;
+ u64 exit_userspace;
+ u64 exit_null;
+ u64 exit_external_request;
+ u64 exit_io_request;
+ u64 exit_external_interrupt;
+ u64 exit_stop_request;
+ u64 exit_validity;
+ u64 exit_instruction;
+ u64 exit_pei;
+ u64 halt_no_poll_steal;
+ u64 instruction_lctl;
+ u64 instruction_lctlg;
+ u64 instruction_stctl;
+ u64 instruction_stctg;
+ u64 exit_program_interruption;
+ u64 exit_instr_and_program;
+ u64 exit_operation_exception;
+ u64 deliver_ckc;
+ u64 deliver_cputm;
+ u64 deliver_external_call;
+ u64 deliver_emergency_signal;
+ u64 deliver_service_signal;
+ u64 deliver_virtio;
+ u64 deliver_stop_signal;
+ u64 deliver_prefix_signal;
+ u64 deliver_restart_signal;
+ u64 deliver_program;
+ u64 deliver_io;
+ u64 deliver_machine_check;
+ u64 exit_wait_state;
+ u64 inject_ckc;
+ u64 inject_cputm;
+ u64 inject_external_call;
+ u64 inject_emergency_signal;
+ u64 inject_mchk;
+ u64 inject_pfault_init;
+ u64 inject_program;
+ u64 inject_restart;
+ u64 inject_set_prefix;
+ u64 inject_stop_signal;
+ u64 instruction_epsw;
+ u64 instruction_gs;
+ u64 instruction_io_other;
+ u64 instruction_lpsw;
+ u64 instruction_lpswe;
+ u64 instruction_lpswey;
+ u64 instruction_pfmf;
+ u64 instruction_ptff;
+ u64 instruction_sck;
+ u64 instruction_sckpf;
+ u64 instruction_stidp;
+ u64 instruction_spx;
+ u64 instruction_stpx;
+ u64 instruction_stap;
+ u64 instruction_iske;
+ u64 instruction_ri;
+ u64 instruction_rrbe;
+ u64 instruction_sske;
+ u64 instruction_ipte_interlock;
+ u64 instruction_stsi;
+ u64 instruction_stfl;
+ u64 instruction_tb;
+ u64 instruction_tpi;
+ u64 instruction_tprot;
+ u64 instruction_tsch;
+ u64 instruction_sie;
+ u64 instruction_essa;
+ u64 instruction_sthyi;
+ u64 instruction_sigp_sense;
+ u64 instruction_sigp_sense_running;
+ u64 instruction_sigp_external_call;
+ u64 instruction_sigp_emergency;
+ u64 instruction_sigp_cond_emergency;
+ u64 instruction_sigp_start;
+ u64 instruction_sigp_stop;
+ u64 instruction_sigp_stop_store_status;
+ u64 instruction_sigp_store_status;
+ u64 instruction_sigp_store_adtl_status;
+ u64 instruction_sigp_arch;
+ u64 instruction_sigp_prefix;
+ u64 instruction_sigp_restart;
+ u64 instruction_sigp_init_cpu_reset;
+ u64 instruction_sigp_cpu_reset;
+ u64 instruction_sigp_unknown;
+ u64 instruction_diagnose_10;
+ u64 instruction_diagnose_44;
+ u64 instruction_diagnose_9c;
+ u64 diag_9c_ignored;
+ u64 diag_9c_forward;
+ u64 instruction_diagnose_258;
+ u64 instruction_diagnose_308;
+ u64 instruction_diagnose_500;
+ u64 instruction_diagnose_other;
+ u64 pfault_sync;
+ u64 signal_exits;
+};
+
+#define PGM_OPERATION 0x01
+#define PGM_PRIVILEGED_OP 0x02
+#define PGM_EXECUTE 0x03
+/* 0x04 & 0x05 defined in kvm_host.h */
+#define PGM_SPECIFICATION 0x06
+#define PGM_DATA 0x07
+#define PGM_FIXED_POINT_OVERFLOW 0x08
+#define PGM_FIXED_POINT_DIVIDE 0x09
+#define PGM_DECIMAL_OVERFLOW 0x0a
+#define PGM_DECIMAL_DIVIDE 0x0b
+#define PGM_HFP_EXPONENT_OVERFLOW 0x0c
+#define PGM_HFP_EXPONENT_UNDERFLOW 0x0d
+#define PGM_HFP_SIGNIFICANCE 0x0e
+#define PGM_HFP_DIVIDE 0x0f
+/* 0x10 & 0x11 defined in kvm_host.h */
+#define PGM_TRANSLATION_SPEC 0x12
+#define PGM_SPECIAL_OPERATION 0x13
+#define PGM_OPERAND 0x15
+#define PGM_TRACE_TABEL 0x16
+#define PGM_VECTOR_PROCESSING 0x1b
+#define PGM_SPACE_SWITCH 0x1c
+#define PGM_HFP_SQUARE_ROOT 0x1d
+#define PGM_PC_TRANSLATION_SPEC 0x1f
+#define PGM_AFX_TRANSLATION 0x20
+#define PGM_ASX_TRANSLATION 0x21
+#define PGM_LX_TRANSLATION 0x22
+#define PGM_EX_TRANSLATION 0x23
+#define PGM_PRIMARY_AUTHORITY 0x24
+#define PGM_SECONDARY_AUTHORITY 0x25
+#define PGM_LFX_TRANSLATION 0x26
+#define PGM_LSX_TRANSLATION 0x27
+#define PGM_ALET_SPECIFICATION 0x28
+#define PGM_ALEN_TRANSLATION 0x29
+#define PGM_ALE_SEQUENCE 0x2a
+#define PGM_ASTE_VALIDITY 0x2b
+#define PGM_ASTE_SEQUENCE 0x2c
+#define PGM_EXTENDED_AUTHORITY 0x2d
+#define PGM_LSTE_SEQUENCE 0x2e
+#define PGM_ASTE_INSTANCE 0x2f
+#define PGM_STACK_FULL 0x30
+#define PGM_STACK_EMPTY 0x31
+#define PGM_STACK_SPECIFICATION 0x32
+#define PGM_STACK_TYPE 0x33
+#define PGM_STACK_OPERATION 0x34
+/* 0x38 - 0x3b defined in kvm_host.h */
+#define PGM_SECURE_STORAGE_ACCESS 0x3d
+#define PGM_NON_SECURE_STORAGE_ACCESS 0x3e
+#define PGM_SECURE_STORAGE_VIOLATION 0x3f
+#define PGM_MONITOR 0x40
+#define PGM_PER 0x80
+#define PGM_CRYPTO_OPERATION 0x119
+
+/* irq types in ascend order of priorities */
+enum irq_types {
+ IRQ_PEND_SET_PREFIX = 0,
+ IRQ_PEND_RESTART,
+ IRQ_PEND_SIGP_STOP,
+ IRQ_PEND_IO_ISC_7,
+ IRQ_PEND_IO_ISC_6,
+ IRQ_PEND_IO_ISC_5,
+ IRQ_PEND_IO_ISC_4,
+ IRQ_PEND_IO_ISC_3,
+ IRQ_PEND_IO_ISC_2,
+ IRQ_PEND_IO_ISC_1,
+ IRQ_PEND_IO_ISC_0,
+ IRQ_PEND_VIRTIO,
+ IRQ_PEND_PFAULT_DONE,
+ IRQ_PEND_PFAULT_INIT,
+ IRQ_PEND_EXT_HOST,
+ IRQ_PEND_EXT_SERVICE,
+ IRQ_PEND_EXT_SERVICE_EV,
+ IRQ_PEND_EXT_TIMING,
+ IRQ_PEND_EXT_CPU_TIMER,
+ IRQ_PEND_EXT_CLOCK_COMP,
+ IRQ_PEND_EXT_EXTERNAL,
+ IRQ_PEND_EXT_EMERGENCY,
+ IRQ_PEND_EXT_MALFUNC,
+ IRQ_PEND_EXT_IRQ_KEY,
+ IRQ_PEND_MCHK_REP,
+ IRQ_PEND_PROG,
+ IRQ_PEND_SVC,
+ IRQ_PEND_MCHK_EX,
+ IRQ_PEND_COUNT
+};
+
+/* We have 2M for virtio device descriptor pages. Smallest amount of
+ * memory per page is 24 bytes (1 queue), so (2048*1024) / 24 = 87381
+ */
+#define KVM_S390_MAX_VIRTIO_IRQS 87381
+
+/*
+ * Repressible (non-floating) machine check interrupts
+ * subclass bits in MCIC
+ */
+#define MCHK_EXTD_BIT 58
+#define MCHK_DEGR_BIT 56
+#define MCHK_WARN_BIT 55
+#define MCHK_REP_MASK ((1UL << MCHK_DEGR_BIT) | \
+ (1UL << MCHK_EXTD_BIT) | \
+ (1UL << MCHK_WARN_BIT))
+
+/* Exigent machine check interrupts subclass bits in MCIC */
+#define MCHK_SD_BIT 63
+#define MCHK_PD_BIT 62
+#define MCHK_EX_MASK ((1UL << MCHK_SD_BIT) | (1UL << MCHK_PD_BIT))
+
+#define IRQ_PEND_EXT_MASK ((1UL << IRQ_PEND_EXT_IRQ_KEY) | \
+ (1UL << IRQ_PEND_EXT_CLOCK_COMP) | \
+ (1UL << IRQ_PEND_EXT_CPU_TIMER) | \
+ (1UL << IRQ_PEND_EXT_MALFUNC) | \
+ (1UL << IRQ_PEND_EXT_EMERGENCY) | \
+ (1UL << IRQ_PEND_EXT_EXTERNAL) | \
+ (1UL << IRQ_PEND_EXT_TIMING) | \
+ (1UL << IRQ_PEND_EXT_HOST) | \
+ (1UL << IRQ_PEND_EXT_SERVICE) | \
+ (1UL << IRQ_PEND_EXT_SERVICE_EV) | \
+ (1UL << IRQ_PEND_VIRTIO) | \
+ (1UL << IRQ_PEND_PFAULT_INIT) | \
+ (1UL << IRQ_PEND_PFAULT_DONE))
+
+#define IRQ_PEND_IO_MASK ((1UL << IRQ_PEND_IO_ISC_0) | \
+ (1UL << IRQ_PEND_IO_ISC_1) | \
+ (1UL << IRQ_PEND_IO_ISC_2) | \
+ (1UL << IRQ_PEND_IO_ISC_3) | \
+ (1UL << IRQ_PEND_IO_ISC_4) | \
+ (1UL << IRQ_PEND_IO_ISC_5) | \
+ (1UL << IRQ_PEND_IO_ISC_6) | \
+ (1UL << IRQ_PEND_IO_ISC_7))
+
+#define IRQ_PEND_MCHK_MASK ((1UL << IRQ_PEND_MCHK_REP) | \
+ (1UL << IRQ_PEND_MCHK_EX))
+
+#define IRQ_PEND_EXT_II_MASK ((1UL << IRQ_PEND_EXT_CPU_TIMER) | \
+ (1UL << IRQ_PEND_EXT_CLOCK_COMP) | \
+ (1UL << IRQ_PEND_EXT_EMERGENCY) | \
+ (1UL << IRQ_PEND_EXT_EXTERNAL) | \
+ (1UL << IRQ_PEND_EXT_SERVICE) | \
+ (1UL << IRQ_PEND_EXT_SERVICE_EV))
+
+struct kvm_s390_interrupt_info {
+ struct list_head list;
+ u64 type;
+ union {
+ struct kvm_s390_io_info io;
+ struct kvm_s390_ext_info ext;
+ struct kvm_s390_pgm_info pgm;
+ struct kvm_s390_emerg_info emerg;
+ struct kvm_s390_extcall_info extcall;
+ struct kvm_s390_prefix_info prefix;
+ struct kvm_s390_stop_info stop;
+ struct kvm_s390_mchk_info mchk;
+ };
+};
+
+struct kvm_s390_irq_payload {
+ struct kvm_s390_io_info io;
+ struct kvm_s390_ext_info ext;
+ struct kvm_s390_pgm_info pgm;
+ struct kvm_s390_emerg_info emerg;
+ struct kvm_s390_extcall_info extcall;
+ struct kvm_s390_prefix_info prefix;
+ struct kvm_s390_stop_info stop;
+ struct kvm_s390_mchk_info mchk;
+};
+
+struct kvm_s390_local_interrupt {
+ spinlock_t lock;
+ DECLARE_BITMAP(sigp_emerg_pending, KVM_MAX_VCPUS);
+ struct kvm_s390_irq_payload irq;
+ unsigned long pending_irqs;
+};
+
+#define FIRQ_LIST_IO_ISC_0 0
+#define FIRQ_LIST_IO_ISC_1 1
+#define FIRQ_LIST_IO_ISC_2 2
+#define FIRQ_LIST_IO_ISC_3 3
+#define FIRQ_LIST_IO_ISC_4 4
+#define FIRQ_LIST_IO_ISC_5 5
+#define FIRQ_LIST_IO_ISC_6 6
+#define FIRQ_LIST_IO_ISC_7 7
+#define FIRQ_LIST_PFAULT 8
+#define FIRQ_LIST_VIRTIO 9
+#define FIRQ_LIST_COUNT 10
+#define FIRQ_CNTR_IO 0
+#define FIRQ_CNTR_SERVICE 1
+#define FIRQ_CNTR_VIRTIO 2
+#define FIRQ_CNTR_PFAULT 3
+#define FIRQ_MAX_COUNT 4
+
+/* mask the AIS mode for a given ISC */
+#define AIS_MODE_MASK(isc) (0x80 >> isc)
+
+#define KVM_S390_AIS_MODE_ALL 0
+#define KVM_S390_AIS_MODE_SINGLE 1
+
+struct kvm_s390_float_interrupt {
+ unsigned long pending_irqs;
+ unsigned long masked_irqs;
+ spinlock_t lock;
+ struct list_head lists[FIRQ_LIST_COUNT];
+ int counters[FIRQ_MAX_COUNT];
+ struct kvm_s390_mchk_info mchk;
+ struct kvm_s390_ext_info srv_signal;
+ int last_sleep_cpu;
+ spinlock_t ais_lock;
+ u8 simm;
+ u8 nimm;
+};
+
+struct kvm_hw_wp_info_arch {
+ unsigned long addr;
+ unsigned long phys_addr;
+ int len;
+ char *old_data;
+};
+
+struct kvm_hw_bp_info_arch {
+ unsigned long addr;
+ int len;
+};
+
+/*
+ * Only the upper 16 bits of kvm_guest_debug->control are arch specific.
+ * Further KVM_GUESTDBG flags which an be used from userspace can be found in
+ * arch/s390/include/uapi/asm/kvm.h
+ */
+#define KVM_GUESTDBG_EXIT_PENDING 0x10000000
+
+#define guestdbg_enabled(vcpu) \
+ (vcpu->guest_debug & KVM_GUESTDBG_ENABLE)
+#define guestdbg_sstep_enabled(vcpu) \
+ (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+#define guestdbg_hw_bp_enabled(vcpu) \
+ (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
+#define guestdbg_exit_pending(vcpu) (guestdbg_enabled(vcpu) && \
+ (vcpu->guest_debug & KVM_GUESTDBG_EXIT_PENDING))
+
+#define KVM_GUESTDBG_VALID_MASK \
+ (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP |\
+ KVM_GUESTDBG_USE_HW_BP | KVM_GUESTDBG_EXIT_PENDING)
+
+struct kvm_guestdbg_info_arch {
+ unsigned long cr0;
+ unsigned long cr9;
+ unsigned long cr10;
+ unsigned long cr11;
+ struct kvm_hw_bp_info_arch *hw_bp_info;
+ struct kvm_hw_wp_info_arch *hw_wp_info;
+ int nr_hw_bp;
+ int nr_hw_wp;
+ unsigned long last_bp;
+};
+
+struct kvm_s390_pv_vcpu {
+ u64 handle;
+ unsigned long stor_base;
+};
+
+struct kvm_vcpu_arch {
+ struct kvm_s390_sie_block *sie_block;
+ /* if vsie is active, currently executed shadow sie control block */
+ struct kvm_s390_sie_block *vsie_block;
+ unsigned int host_acrs[NUM_ACRS];
+ struct gs_cb *host_gscb;
+ struct kvm_s390_local_interrupt local_int;
+ struct hrtimer ckc_timer;
+ struct kvm_s390_pgm_info pgm;
+ struct gmap *gmap;
+ struct kvm_guestdbg_info_arch guestdbg;
+ unsigned long pfault_token;
+ unsigned long pfault_select;
+ unsigned long pfault_compare;
+ bool cputm_enabled;
+ /*
+ * The seqcount protects updates to cputm_start and sie_block.cputm,
+ * this way we can have non-blocking reads with consistent values.
+ * Only the owning VCPU thread (vcpu->cpu) is allowed to change these
+ * values and to start/stop/enable/disable cpu timer accounting.
+ */
+ seqcount_t cputm_seqcount;
+ __u64 cputm_start;
+ bool gs_enabled;
+ bool skey_enabled;
+ /* Indicator if the access registers have been loaded from guest */
+ bool acrs_loaded;
+ struct kvm_s390_pv_vcpu pv;
+ union diag318_info diag318_info;
+ struct kvm_s390_mmu_cache *mc;
+};
+
+struct kvm_vm_stat {
+ struct kvm_vm_stat_generic generic;
+ u64 inject_io;
+ u64 io_390_adapter_map;
+ u64 io_390_adapter_unmap;
+ u64 io_390_inatomic;
+ u64 io_flic_inject_airq;
+ u64 io_set_adapter_int;
+ u64 io_390_inatomic_no_inject;
+ u64 inject_float_mchk;
+ u64 inject_pfault_done;
+ u64 inject_service_signal;
+ u64 inject_virtio;
+ u64 aen_forward;
+ u64 gmap_shadow_create;
+ u64 gmap_shadow_reuse;
+ u64 gmap_shadow_r1_entry;
+ u64 gmap_shadow_r2_entry;
+ u64 gmap_shadow_r3_entry;
+ u64 gmap_shadow_sg_entry;
+ u64 gmap_shadow_pg_entry;
+};
+
+struct kvm_arch_memory_slot {
+};
+
+struct s390_map_info {
+ struct list_head list;
+ __u64 guest_addr;
+ __u64 addr;
+ struct page *page;
+};
+
+struct s390_io_adapter {
+ unsigned int id;
+ int isc;
+ bool maskable;
+ bool masked;
+ bool swap;
+ bool suppressible;
+ spinlock_t maps_lock;
+ struct list_head maps;
+ unsigned int nr_maps;
+};
+
+#define MAX_S390_IO_ADAPTERS ((MAX_ISC + 1) * 8)
+#define MAX_S390_ADAPTER_MAPS 256
+
+/* maximum size of facilities and facility mask is 2k bytes */
+#define S390_ARCH_FAC_LIST_SIZE_BYTE (1<<11)
+#define S390_ARCH_FAC_LIST_SIZE_U64 \
+ (S390_ARCH_FAC_LIST_SIZE_BYTE / sizeof(u64))
+#define S390_ARCH_FAC_MASK_SIZE_BYTE S390_ARCH_FAC_LIST_SIZE_BYTE
+#define S390_ARCH_FAC_MASK_SIZE_U64 \
+ (S390_ARCH_FAC_MASK_SIZE_BYTE / sizeof(u64))
+
+struct kvm_s390_cpu_model {
+ /* facility mask supported by kvm & hosting machine */
+ __u64 fac_mask[S390_ARCH_FAC_MASK_SIZE_U64];
+ struct kvm_s390_vm_cpu_subfunc subfuncs;
+ /* facility list requested by guest (in dma page) */
+ __u64 *fac_list;
+ u64 cpuid;
+ unsigned short ibc;
+ /* subset of available UV-features for pv-guests enabled by user space */
+ struct kvm_s390_vm_cpu_uv_feat uv_feat_guest;
+};
+
+#define S390_ARCH_FAC_FORMAT_2 2
+struct kvm_s390_flcb2 {
+ union {
+ struct {
+ u8 reserved0[7];
+ u8 length;
+ };
+ u64 header_val;
+ };
+ u64 facilities[S390_ARCH_FAC_LIST_SIZE_U64];
+};
+
+typedef int (*crypto_hook)(struct kvm_vcpu *vcpu);
+
+struct kvm_s390_crypto {
+ struct kvm_s390_crypto_cb *crycb;
+ struct rw_semaphore pqap_hook_rwsem;
+ crypto_hook *pqap_hook;
+ __u32 crycbd;
+ __u8 aes_kw;
+ __u8 dea_kw;
+ __u8 apie;
+};
+
+#define APCB0_MASK_SIZE 1
+struct kvm_s390_apcb0 {
+ __u64 apm[APCB0_MASK_SIZE]; /* 0x0000 */
+ __u64 aqm[APCB0_MASK_SIZE]; /* 0x0008 */
+ __u64 adm[APCB0_MASK_SIZE]; /* 0x0010 */
+ __u64 reserved18; /* 0x0018 */
+};
+
+#define APCB1_MASK_SIZE 4
+struct kvm_s390_apcb1 {
+ __u64 apm[APCB1_MASK_SIZE]; /* 0x0000 */
+ __u64 aqm[APCB1_MASK_SIZE]; /* 0x0020 */
+ __u64 adm[APCB1_MASK_SIZE]; /* 0x0040 */
+ __u64 reserved60[4]; /* 0x0060 */
+};
+
+struct kvm_s390_crypto_cb {
+ struct kvm_s390_apcb0 apcb0; /* 0x0000 */
+ __u8 reserved20[0x0048 - 0x0020]; /* 0x0020 */
+ __u8 dea_wrapping_key_mask[24]; /* 0x0048 */
+ __u8 aes_wrapping_key_mask[32]; /* 0x0060 */
+ struct kvm_s390_apcb1 apcb1; /* 0x0080 */
+};
+
+struct kvm_s390_gisa {
+ union {
+ struct { /* common to all formats */
+ u32 next_alert;
+ u8 ipm;
+ u8 reserved01[2];
+ u8 iam;
+ };
+ struct { /* format 0 */
+ u32 next_alert;
+ u8 ipm;
+ u8 reserved01;
+ u8 : 6;
+ u8 g : 1;
+ u8 c : 1;
+ u8 iam;
+ u8 reserved02[4];
+ u32 airq_count;
+ } g0;
+ struct { /* format 1 */
+ u32 next_alert;
+ u8 ipm;
+ u8 simm;
+ u8 nimm;
+ u8 iam;
+ u8 aism[8];
+ u8 : 6;
+ u8 g : 1;
+ u8 c : 1;
+ u8 reserved03[11];
+ u32 airq_count;
+ } g1;
+ struct {
+ u64 word[4];
+ } u64;
+ };
+};
+
+struct kvm_s390_gib {
+ u32 alert_list_origin;
+ u32 reserved01;
+ u8:5;
+ u8 nisc:3;
+ u8 reserved03[3];
+ u32 reserved04[5];
+};
+
+/*
+ * sie_page2 has to be allocated as DMA because fac_list, crycb and
+ * gisa need 31bit addresses in the sie control block.
+ */
+struct sie_page2 {
+ __u64 fac_list[S390_ARCH_FAC_LIST_SIZE_U64]; /* 0x0000 */
+ struct kvm_s390_crypto_cb crycb; /* 0x0800 */
+ struct kvm_s390_gisa gisa; /* 0x0900 */
+ struct kvm *kvm; /* 0x0920 */
+ u8 reserved928[0x1000 - 0x928]; /* 0x0928 */
+};
+
+struct vsie_page;
+
+struct kvm_s390_vsie {
+ struct mutex mutex;
+ struct radix_tree_root addr_to_page;
+ int page_count;
+ int next;
+ struct vsie_page *pages[KVM_MAX_VCPUS];
+};
+
+struct kvm_s390_gisa_iam {
+ u8 mask;
+ spinlock_t ref_lock;
+ u32 ref_count[MAX_ISC + 1];
+};
+
+struct kvm_s390_gisa_interrupt {
+ struct kvm_s390_gisa *origin;
+ struct kvm_s390_gisa_iam alert;
+ struct hrtimer timer;
+ u64 expires;
+ DECLARE_BITMAP(kicked_mask, KVM_MAX_VCPUS);
+};
+
+struct kvm_s390_pv {
+ u64 handle;
+ u64 guest_len;
+ unsigned long stor_base;
+ void *stor_var;
+ bool dumping;
+ void *set_aside;
+ struct list_head need_cleanup;
+ struct mmu_notifier mmu_notifier;
+ /* Protects against concurrent import-like operations */
+ struct mutex import_lock;
+};
+
+struct kvm_s390_mmu_cache;
+
+struct kvm_arch {
+ struct esca_block *sca;
+ debug_info_t *dbf;
+ struct kvm_s390_float_interrupt float_int;
+ struct kvm_device *flic;
+ struct gmap *gmap;
+ unsigned long mem_limit;
+ int css_support;
+ int use_irqchip;
+ int use_cmma;
+ int use_pfmfi;
+ int use_skf;
+ int use_zpci_interp;
+ int user_cpu_state_ctrl;
+ int user_sigp;
+ int user_stsi;
+ int user_instr0;
+ int user_operexec;
+ int allow_vsie_esamode;
+ struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
+ wait_queue_head_t ipte_wq;
+ int ipte_lock_count;
+ struct mutex ipte_mutex;
+ spinlock_t start_stop_lock;
+ struct sie_page2 *sie_page2;
+ struct kvm_s390_cpu_model model;
+ struct kvm_s390_crypto crypto;
+ struct kvm_s390_vsie vsie;
+ u8 epdx;
+ u64 epoch;
+ int migration_mode;
+ atomic64_t cmma_dirty_pages;
+ /* subset of available cpu features enabled by user space */
+ DECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
+ /* indexed by vcpu_idx */
+ DECLARE_BITMAP(idle_mask, KVM_MAX_VCPUS);
+ struct kvm_s390_gisa_interrupt gisa_int;
+ struct kvm_s390_pv pv;
+ struct list_head kzdev_list;
+ spinlock_t kzdev_list_lock;
+ struct kvm_s390_mmu_cache *mc;
+};
+
+#define KVM_HVA_ERR_BAD (-1UL)
+#define KVM_HVA_ERR_RO_BAD (-2UL)
+
+static inline bool kvm_is_error_hva(unsigned long addr)
+{
+ return IS_ERR_VALUE(addr);
+}
+
+#define ASYNC_PF_PER_VCPU 64
+struct kvm_arch_async_pf {
+ unsigned long pfault_token;
+};
+
+bool kvm_arch_can_dequeue_async_page_present(struct kvm_vcpu *vcpu);
+
+void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work);
+
+bool kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work);
+
+void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work);
+
+static inline void kvm_arch_async_page_present_queued(struct kvm_vcpu *vcpu) {}
+
+void kvm_arch_crypto_clear_masks(struct kvm *kvm);
+void kvm_arch_crypto_set_masks(struct kvm *kvm, unsigned long *apm,
+ unsigned long *aqm, unsigned long *adm);
+
+#define SIE64_RETURN_NORMAL 0
+#define SIE64_RETURN_MCCK 1
+
+int __sie64a(phys_addr_t sie_block_phys, struct kvm_s390_sie_block *sie_block, u64 *rsa,
+ unsigned long gasce);
+
+static inline int sie64a(struct kvm_s390_sie_block *sie_block, u64 *rsa, unsigned long gasce)
+{
+ return __sie64a(virt_to_phys(sie_block), sie_block, rsa, gasce);
+}
+
+extern char sie_exit;
+
+bool kvm_s390_pv_is_protected(struct kvm *kvm);
+bool kvm_s390_pv_cpu_is_protected(struct kvm_vcpu *vcpu);
+
+extern int kvm_s390_enter_exit_sie(struct kvm_s390_sie_block *scb,
+ u64 *gprs, unsigned long gasce);
+
+extern int kvm_s390_gisc_register(struct kvm *kvm, u32 gisc);
+extern int kvm_s390_gisc_unregister(struct kvm *kvm, u32 gisc);
+
+bool kvm_s390_is_gpa_in_memslot(struct kvm *kvm, gpa_t gpa);
+
+static inline void kvm_arch_free_memslot(struct kvm *kvm,
+ struct kvm_memory_slot *slot) {}
+static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
+static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {}
+static inline void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
+ struct kvm_memory_slot *slot) {}
+static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {}
+static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {}
+
+#define __KVM_HAVE_ARCH_VM_FREE
+void kvm_arch_free_vm(struct kvm *kvm);
+
+struct zpci_kvm_hook {
+ int (*kvm_register)(void *opaque, struct kvm *kvm);
+ void (*kvm_unregister)(void *opaque);
+};
+
+extern struct zpci_kvm_hook zpci_kvm_hook;
+
+#endif /* ASM_KVM_HOST_S390_H */
diff --git a/arch/s390/include/asm/kvm_host_s390_types.h b/arch/s390/include/asm/kvm_host_s390_types.h
new file mode 100644
index 00000000000000..5cf746095bfd12
--- /dev/null
+++ b/arch/s390/include/asm/kvm_host_s390_types.h
@@ -0,0 +1,347 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_KVM_HOST_S390_TYPES_H
+#define _ASM_KVM_HOST_S390_TYPES_H
+
+#include <linux/atomic.h>
+#include <linux/types.h>
+
+#define KVM_S390_BSCA_CPU_SLOTS 64
+#define KVM_S390_ESCA_CPU_SLOTS 248
+
+#define SIGP_CTRL_C 0x80
+#define SIGP_CTRL_SCN_MASK 0x3f
+
+union bsca_sigp_ctrl {
+ __u8 value;
+ struct {
+ __u8 c : 1;
+ __u8 r : 1;
+ __u8 scn : 6;
+ };
+};
+
+union esca_sigp_ctrl {
+ __u16 value;
+ struct {
+ __u8 c : 1;
+ __u8 reserved: 7;
+ __u8 scn;
+ };
+};
+
+struct esca_entry {
+ union esca_sigp_ctrl sigp_ctrl;
+ __u16 reserved1[3];
+ __u64 sda;
+ __u64 reserved2[6];
+};
+
+struct bsca_entry {
+ __u8 reserved0;
+ union bsca_sigp_ctrl sigp_ctrl;
+ __u16 reserved[3];
+ __u64 sda;
+ __u64 reserved2[2];
+};
+
+union ipte_control {
+ unsigned long val;
+ struct {
+ unsigned long k : 1;
+ unsigned long kh : 31;
+ unsigned long kg : 32;
+ };
+};
+
+/*
+ * Utility is defined as two bytes but having it four bytes wide
+ * generates more efficient code. Since the following bytes are
+ * reserved this makes no functional difference.
+ */
+union sca_utility {
+ __u32 val;
+ struct {
+ __u32 mtcr : 1;
+ __u32 : 31;
+ };
+};
+
+struct bsca_block {
+ union ipte_control ipte_control;
+ __u64 reserved[5];
+ __u64 mcn;
+ union sca_utility utility;
+ __u8 reserved2[4];
+ struct bsca_entry cpu[KVM_S390_BSCA_CPU_SLOTS];
+};
+
+struct esca_block {
+ union ipte_control ipte_control;
+ __u64 reserved1[6];
+ union sca_utility utility;
+ __u8 reserved2[4];
+ __u64 mcn[4];
+ __u64 reserved3[20];
+ struct esca_entry cpu[KVM_S390_ESCA_CPU_SLOTS];
+};
+
+/*
+ * This struct is used to store some machine check info from lowcore
+ * for machine checks that happen while the guest is running.
+ * This info in host's lowcore might be overwritten by a second machine
+ * check from host when host is in the machine check's high-level handling.
+ * The size is 24 bytes.
+ */
+struct mcck_volatile_info {
+ __u64 mcic;
+ __u64 failing_storage_address;
+ __u32 ext_damage_code;
+ __u32 reserved;
+};
+
+#define CR0_INITIAL_MASK (CR0_UNUSED_56 | CR0_INTERRUPT_KEY_SUBMASK | \
+ CR0_MEASUREMENT_ALERT_SUBMASK)
+#define CR14_INITIAL_MASK (CR14_UNUSED_32 | CR14_UNUSED_33 | \
+ CR14_EXTERNAL_DAMAGE_SUBMASK)
+
+#define SIDAD_SIZE_MASK 0xff
+#define sida_addr(sie_block) phys_to_virt((sie_block)->sidad & PAGE_MASK)
+#define sida_size(sie_block) \
+ ((((sie_block)->sidad & SIDAD_SIZE_MASK) + 1) * PAGE_SIZE)
+
+#define CPUSTAT_STOPPED 0x80000000
+#define CPUSTAT_WAIT 0x10000000
+#define CPUSTAT_ECALL_PEND 0x08000000
+#define CPUSTAT_STOP_INT 0x04000000
+#define CPUSTAT_IO_INT 0x02000000
+#define CPUSTAT_EXT_INT 0x01000000
+#define CPUSTAT_RUNNING 0x00800000
+#define CPUSTAT_RETAINED 0x00400000
+#define CPUSTAT_TIMING_SUB 0x00020000
+#define CPUSTAT_SIE_SUB 0x00010000
+#define CPUSTAT_RRF 0x00008000
+#define CPUSTAT_SLSV 0x00004000
+#define CPUSTAT_SLSR 0x00002000
+#define CPUSTAT_ZARCH 0x00000800
+#define CPUSTAT_MCDS 0x00000100
+#define CPUSTAT_KSS 0x00000200
+#define CPUSTAT_SM 0x00000080
+#define CPUSTAT_IBS 0x00000040
+#define CPUSTAT_GED2 0x00000010
+#define CPUSTAT_G 0x00000008
+#define CPUSTAT_GED 0x00000004
+#define CPUSTAT_J 0x00000002
+#define CPUSTAT_P 0x00000001
+
+struct kvm_s390_sie_block {
+ atomic_t cpuflags; /* 0x0000 */
+ __u32 : 1; /* 0x0004 */
+ __u32 prefix : 19;
+ __u32 ibc : 12;
+ __u8 reserved08[4]; /* 0x0008 */
+#define PROG_IN_SIE (1<<0)
+ __u32 prog0c; /* 0x000c */
+ union {
+ __u8 reserved10[16]; /* 0x0010 */
+ struct {
+ __u64 pv_handle_cpu;
+ __u64 pv_handle_config;
+ };
+ };
+#define PROG_BLOCK_SIE (1<<0)
+#define PROG_REQUEST (1<<1)
+ atomic_t prog20; /* 0x0020 */
+ __u8 reserved24[4]; /* 0x0024 */
+ __u64 cputm; /* 0x0028 */
+ __u64 ckc; /* 0x0030 */
+ __u64 epoch; /* 0x0038 */
+ __u32 svcc; /* 0x0040 */
+#define LCTL_CR0 0x8000
+#define LCTL_CR6 0x0200
+#define LCTL_CR9 0x0040
+#define LCTL_CR10 0x0020
+#define LCTL_CR11 0x0010
+#define LCTL_CR14 0x0002
+ __u16 lctl; /* 0x0044 */
+ __s16 icpua; /* 0x0046 */
+#define ICTL_OPEREXC 0x80000000
+#define ICTL_PINT 0x20000000
+#define ICTL_LPSW 0x00400000
+#define ICTL_STCTL 0x00040000
+#define ICTL_ISKE 0x00004000
+#define ICTL_SSKE 0x00002000
+#define ICTL_RRBE 0x00001000
+#define ICTL_TPROT 0x00000200
+ __u32 ictl; /* 0x0048 */
+#define ECA_CEI 0x80000000
+#define ECA_IB 0x40000000
+#define ECA_SIGPI 0x10000000
+#define ECA_MVPGI 0x01000000
+#define ECA_AIV 0x00200000
+#define ECA_VX 0x00020000
+#define ECA_PROTEXCI 0x00002000
+#define ECA_APIE 0x00000008
+#define ECA_SII 0x00000001
+ __u32 eca; /* 0x004c */
+#define ICPT_INST 0x04
+#define ICPT_PROGI 0x08
+#define ICPT_INSTPROGI 0x0C
+#define ICPT_EXTREQ 0x10
+#define ICPT_EXTINT 0x14
+#define ICPT_IOREQ 0x18
+#define ICPT_WAIT 0x1c
+#define ICPT_VALIDITY 0x20
+#define ICPT_STOP 0x28
+#define ICPT_OPEREXC 0x2C
+#define ICPT_PARTEXEC 0x38
+#define ICPT_IOINST 0x40
+#define ICPT_KSS 0x5c
+#define ICPT_MCHKREQ 0x60
+#define ICPT_INT_ENABLE 0x64
+#define ICPT_PV_INSTR 0x68
+#define ICPT_PV_NOTIFY 0x6c
+#define ICPT_PV_PREF 0x70
+ __u8 icptcode; /* 0x0050 */
+ __u8 icptstatus; /* 0x0051 */
+ __u16 ihcpu; /* 0x0052 */
+ __u8 reserved54; /* 0x0054 */
+#define IICTL_CODE_NONE 0x00
+#define IICTL_CODE_MCHK 0x01
+#define IICTL_CODE_EXT 0x02
+#define IICTL_CODE_IO 0x03
+#define IICTL_CODE_RESTART 0x04
+#define IICTL_CODE_SPECIFICATION 0x10
+#define IICTL_CODE_OPERAND 0x11
+ __u8 iictl; /* 0x0055 */
+ __u16 ipa; /* 0x0056 */
+ __u32 ipb; /* 0x0058 */
+ __u32 scaoh; /* 0x005c */
+#define FPF_BPBC 0x20
+ __u8 fpf; /* 0x0060 */
+#define ECB_GS 0x40
+#define ECB_TE 0x10
+#define ECB_SPECI 0x08
+#define ECB_SRSI 0x04
+#define ECB_HOSTPROTINT 0x02
+#define ECB_PTF 0x01
+ __u8 ecb; /* 0x0061 */
+#define ECB2_CMMA 0x80
+#define ECB2_IEP 0x20
+#define ECB2_PFMFI 0x08
+#define ECB2_ESCA 0x04
+#define ECB2_ZPCI_LSI 0x02
+ __u8 ecb2; /* 0x0062 */
+#define ECB3_AISI 0x20
+#define ECB3_AISII 0x10
+#define ECB3_DEA 0x08
+#define ECB3_AES 0x04
+#define ECB3_RI 0x01
+ __u8 ecb3; /* 0x0063 */
+#define ESCA_SCAOL_MASK ~0x3fU
+ __u32 scaol; /* 0x0064 */
+ __u8 sdf; /* 0x0068 */
+ __u8 epdx; /* 0x0069 */
+ __u8 cpnc; /* 0x006a */
+ __u8 reserved6b; /* 0x006b */
+ __u32 todpr; /* 0x006c */
+#define GISA_FORMAT1 0x00000001
+ __u32 gd; /* 0x0070 */
+ __u8 reserved74[12]; /* 0x0074 */
+ __u64 mso; /* 0x0080 */
+ __u64 msl; /* 0x0088 */
+ psw_t gpsw; /* 0x0090 */
+ __u64 gg14; /* 0x00a0 */
+ __u64 gg15; /* 0x00a8 */
+ __u8 reservedb0[8]; /* 0x00b0 */
+#define HPID_KVM 0x4
+#define HPID_VSIE 0x5
+ __u8 hpid; /* 0x00b8 */
+ __u8 reservedb9[7]; /* 0x00b9 */
+ union {
+ struct {
+ __u32 eiparams; /* 0x00c0 */
+ __u16 extcpuaddr; /* 0x00c4 */
+ __u16 eic; /* 0x00c6 */
+ };
+ __u64 mcic; /* 0x00c0 */
+ } __packed;
+ __u32 reservedc8; /* 0x00c8 */
+ union {
+ struct {
+ __u16 pgmilc; /* 0x00cc */
+ __u16 iprcc; /* 0x00ce */
+ };
+ __u32 edc; /* 0x00cc */
+ } __packed;
+ union {
+ struct {
+ __u32 dxc; /* 0x00d0 */
+ __u16 mcn; /* 0x00d4 */
+ __u8 perc; /* 0x00d6 */
+ __u8 peratmid; /* 0x00d7 */
+ };
+ __u64 faddr; /* 0x00d0 */
+ } __packed;
+ __u64 peraddr; /* 0x00d8 */
+ __u8 eai; /* 0x00e0 */
+ __u8 peraid; /* 0x00e1 */
+ __u8 oai; /* 0x00e2 */
+ __u8 armid; /* 0x00e3 */
+ __u8 reservede4[4]; /* 0x00e4 */
+ union {
+ __u64 tecmc; /* 0x00e8 */
+ struct {
+ __u16 subchannel_id; /* 0x00e8 */
+ __u16 subchannel_nr; /* 0x00ea */
+ __u32 io_int_parm; /* 0x00ec */
+ __u32 io_int_word; /* 0x00f0 */
+ };
+ } __packed;
+ __u8 reservedf4[8]; /* 0x00f4 */
+#define CRYCB_FORMAT_MASK 0x00000003
+#define CRYCB_FORMAT0 0x00000000
+#define CRYCB_FORMAT1 0x00000001
+#define CRYCB_FORMAT2 0x00000003
+ __u32 crycbd; /* 0x00fc */
+ __u64 gcr[16]; /* 0x0100 */
+ union {
+ __u64 gbea; /* 0x0180 */
+ __u64 sidad;
+ };
+ __u8 reserved188[8]; /* 0x0188 */
+ __u64 sdnxo; /* 0x0190 */
+ __u8 reserved198[8]; /* 0x0198 */
+ __u32 fac; /* 0x01a0 */
+ __u8 reserved1a4[20]; /* 0x01a4 */
+ __u64 cbrlo; /* 0x01b8 */
+ __u8 reserved1c0[8]; /* 0x01c0 */
+#define ECD_HOSTREGMGMT 0x20000000
+#define ECD_MEF 0x08000000
+#define ECD_ETOKENF 0x02000000
+#define ECD_ECC 0x00200000
+#define ECD_HMAC 0x00004000
+ __u32 ecd; /* 0x01c8 */
+ __u8 reserved1cc[18]; /* 0x01cc */
+ __u64 pp; /* 0x01de */
+ __u8 reserved1e6[2]; /* 0x01e6 */
+ __u64 itdba; /* 0x01e8 */
+ __u64 riccbd; /* 0x01f0 */
+ __u64 gvrd; /* 0x01f8 */
+} __packed __aligned(512);
+
+struct kvm_s390_itdb {
+ __u8 data[256];
+};
+
+struct sie_page {
+ struct kvm_s390_sie_block sie_block;
+ struct mcck_volatile_info mcck_info; /* 0x0200 */
+ __u8 reserved218[360]; /* 0x0218 */
+ __u64 pv_grregs[16]; /* 0x0380 */
+ __u8 reserved400[512]; /* 0x0400 */
+ struct kvm_s390_itdb itdb; /* 0x0600 */
+ __u8 reserved700[2304]; /* 0x0700 */
+};
+
+#endif /* _ASM_KVM_HOST_S390_TYPES_H */
diff --git a/arch/s390/include/asm/kvm_host_types.h b/arch/s390/include/asm/kvm_host_types.h
index 3f50942bdfe6c7..d308739ebcf570 100644
--- a/arch/s390/include/asm/kvm_host_types.h
+++ b/arch/s390/include/asm/kvm_host_types.h
@@ -1,347 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_KVM_HOST_TYPES_H
-#define _ASM_KVM_HOST_TYPES_H
+#ifndef ASM_KVM_HOST_TYPES_H
+#define ASM_KVM_HOST_TYPES_H
-#include <linux/atomic.h>
-#include <linux/types.h>
+#ifdef KVM_S390_ARM64
+#include <asm/kvm_host_arm64_types.h>
+#else
+#include <asm/kvm_host_s390_types.h>
+#endif /* KVM_S390_ARM64 */
-#define KVM_S390_BSCA_CPU_SLOTS 64
-#define KVM_S390_ESCA_CPU_SLOTS 248
-
-#define SIGP_CTRL_C 0x80
-#define SIGP_CTRL_SCN_MASK 0x3f
-
-union bsca_sigp_ctrl {
- __u8 value;
- struct {
- __u8 c : 1;
- __u8 r : 1;
- __u8 scn : 6;
- };
-};
-
-union esca_sigp_ctrl {
- __u16 value;
- struct {
- __u8 c : 1;
- __u8 reserved: 7;
- __u8 scn;
- };
-};
-
-struct esca_entry {
- union esca_sigp_ctrl sigp_ctrl;
- __u16 reserved1[3];
- __u64 sda;
- __u64 reserved2[6];
-};
-
-struct bsca_entry {
- __u8 reserved0;
- union bsca_sigp_ctrl sigp_ctrl;
- __u16 reserved[3];
- __u64 sda;
- __u64 reserved2[2];
-};
-
-union ipte_control {
- unsigned long val;
- struct {
- unsigned long k : 1;
- unsigned long kh : 31;
- unsigned long kg : 32;
- };
-};
-
-/*
- * Utility is defined as two bytes but having it four bytes wide
- * generates more efficient code. Since the following bytes are
- * reserved this makes no functional difference.
- */
-union sca_utility {
- __u32 val;
- struct {
- __u32 mtcr : 1;
- __u32 : 31;
- };
-};
-
-struct bsca_block {
- union ipte_control ipte_control;
- __u64 reserved[5];
- __u64 mcn;
- union sca_utility utility;
- __u8 reserved2[4];
- struct bsca_entry cpu[KVM_S390_BSCA_CPU_SLOTS];
-};
-
-struct esca_block {
- union ipte_control ipte_control;
- __u64 reserved1[6];
- union sca_utility utility;
- __u8 reserved2[4];
- __u64 mcn[4];
- __u64 reserved3[20];
- struct esca_entry cpu[KVM_S390_ESCA_CPU_SLOTS];
-};
-
-/*
- * This struct is used to store some machine check info from lowcore
- * for machine checks that happen while the guest is running.
- * This info in host's lowcore might be overwritten by a second machine
- * check from host when host is in the machine check's high-level handling.
- * The size is 24 bytes.
- */
-struct mcck_volatile_info {
- __u64 mcic;
- __u64 failing_storage_address;
- __u32 ext_damage_code;
- __u32 reserved;
-};
-
-#define CR0_INITIAL_MASK (CR0_UNUSED_56 | CR0_INTERRUPT_KEY_SUBMASK | \
- CR0_MEASUREMENT_ALERT_SUBMASK)
-#define CR14_INITIAL_MASK (CR14_UNUSED_32 | CR14_UNUSED_33 | \
- CR14_EXTERNAL_DAMAGE_SUBMASK)
-
-#define SIDAD_SIZE_MASK 0xff
-#define sida_addr(sie_block) phys_to_virt((sie_block)->sidad & PAGE_MASK)
-#define sida_size(sie_block) \
- ((((sie_block)->sidad & SIDAD_SIZE_MASK) + 1) * PAGE_SIZE)
-
-#define CPUSTAT_STOPPED 0x80000000
-#define CPUSTAT_WAIT 0x10000000
-#define CPUSTAT_ECALL_PEND 0x08000000
-#define CPUSTAT_STOP_INT 0x04000000
-#define CPUSTAT_IO_INT 0x02000000
-#define CPUSTAT_EXT_INT 0x01000000
-#define CPUSTAT_RUNNING 0x00800000
-#define CPUSTAT_RETAINED 0x00400000
-#define CPUSTAT_TIMING_SUB 0x00020000
-#define CPUSTAT_SIE_SUB 0x00010000
-#define CPUSTAT_RRF 0x00008000
-#define CPUSTAT_SLSV 0x00004000
-#define CPUSTAT_SLSR 0x00002000
-#define CPUSTAT_ZARCH 0x00000800
-#define CPUSTAT_MCDS 0x00000100
-#define CPUSTAT_KSS 0x00000200
-#define CPUSTAT_SM 0x00000080
-#define CPUSTAT_IBS 0x00000040
-#define CPUSTAT_GED2 0x00000010
-#define CPUSTAT_G 0x00000008
-#define CPUSTAT_GED 0x00000004
-#define CPUSTAT_J 0x00000002
-#define CPUSTAT_P 0x00000001
-
-struct kvm_s390_sie_block {
- atomic_t cpuflags; /* 0x0000 */
- __u32 : 1; /* 0x0004 */
- __u32 prefix : 19;
- __u32 ibc : 12;
- __u8 reserved08[4]; /* 0x0008 */
-#define PROG_IN_SIE (1<<0)
- __u32 prog0c; /* 0x000c */
- union {
- __u8 reserved10[16]; /* 0x0010 */
- struct {
- __u64 pv_handle_cpu;
- __u64 pv_handle_config;
- };
- };
-#define PROG_BLOCK_SIE (1<<0)
-#define PROG_REQUEST (1<<1)
- atomic_t prog20; /* 0x0020 */
- __u8 reserved24[4]; /* 0x0024 */
- __u64 cputm; /* 0x0028 */
- __u64 ckc; /* 0x0030 */
- __u64 epoch; /* 0x0038 */
- __u32 svcc; /* 0x0040 */
-#define LCTL_CR0 0x8000
-#define LCTL_CR6 0x0200
-#define LCTL_CR9 0x0040
-#define LCTL_CR10 0x0020
-#define LCTL_CR11 0x0010
-#define LCTL_CR14 0x0002
- __u16 lctl; /* 0x0044 */
- __s16 icpua; /* 0x0046 */
-#define ICTL_OPEREXC 0x80000000
-#define ICTL_PINT 0x20000000
-#define ICTL_LPSW 0x00400000
-#define ICTL_STCTL 0x00040000
-#define ICTL_ISKE 0x00004000
-#define ICTL_SSKE 0x00002000
-#define ICTL_RRBE 0x00001000
-#define ICTL_TPROT 0x00000200
- __u32 ictl; /* 0x0048 */
-#define ECA_CEI 0x80000000
-#define ECA_IB 0x40000000
-#define ECA_SIGPI 0x10000000
-#define ECA_MVPGI 0x01000000
-#define ECA_AIV 0x00200000
-#define ECA_VX 0x00020000
-#define ECA_PROTEXCI 0x00002000
-#define ECA_APIE 0x00000008
-#define ECA_SII 0x00000001
- __u32 eca; /* 0x004c */
-#define ICPT_INST 0x04
-#define ICPT_PROGI 0x08
-#define ICPT_INSTPROGI 0x0C
-#define ICPT_EXTREQ 0x10
-#define ICPT_EXTINT 0x14
-#define ICPT_IOREQ 0x18
-#define ICPT_WAIT 0x1c
-#define ICPT_VALIDITY 0x20
-#define ICPT_STOP 0x28
-#define ICPT_OPEREXC 0x2C
-#define ICPT_PARTEXEC 0x38
-#define ICPT_IOINST 0x40
-#define ICPT_KSS 0x5c
-#define ICPT_MCHKREQ 0x60
-#define ICPT_INT_ENABLE 0x64
-#define ICPT_PV_INSTR 0x68
-#define ICPT_PV_NOTIFY 0x6c
-#define ICPT_PV_PREF 0x70
- __u8 icptcode; /* 0x0050 */
- __u8 icptstatus; /* 0x0051 */
- __u16 ihcpu; /* 0x0052 */
- __u8 reserved54; /* 0x0054 */
-#define IICTL_CODE_NONE 0x00
-#define IICTL_CODE_MCHK 0x01
-#define IICTL_CODE_EXT 0x02
-#define IICTL_CODE_IO 0x03
-#define IICTL_CODE_RESTART 0x04
-#define IICTL_CODE_SPECIFICATION 0x10
-#define IICTL_CODE_OPERAND 0x11
- __u8 iictl; /* 0x0055 */
- __u16 ipa; /* 0x0056 */
- __u32 ipb; /* 0x0058 */
- __u32 scaoh; /* 0x005c */
-#define FPF_BPBC 0x20
- __u8 fpf; /* 0x0060 */
-#define ECB_GS 0x40
-#define ECB_TE 0x10
-#define ECB_SPECI 0x08
-#define ECB_SRSI 0x04
-#define ECB_HOSTPROTINT 0x02
-#define ECB_PTF 0x01
- __u8 ecb; /* 0x0061 */
-#define ECB2_CMMA 0x80
-#define ECB2_IEP 0x20
-#define ECB2_PFMFI 0x08
-#define ECB2_ESCA 0x04
-#define ECB2_ZPCI_LSI 0x02
- __u8 ecb2; /* 0x0062 */
-#define ECB3_AISI 0x20
-#define ECB3_AISII 0x10
-#define ECB3_DEA 0x08
-#define ECB3_AES 0x04
-#define ECB3_RI 0x01
- __u8 ecb3; /* 0x0063 */
-#define ESCA_SCAOL_MASK ~0x3fU
- __u32 scaol; /* 0x0064 */
- __u8 sdf; /* 0x0068 */
- __u8 epdx; /* 0x0069 */
- __u8 cpnc; /* 0x006a */
- __u8 reserved6b; /* 0x006b */
- __u32 todpr; /* 0x006c */
-#define GISA_FORMAT1 0x00000001
- __u32 gd; /* 0x0070 */
- __u8 reserved74[12]; /* 0x0074 */
- __u64 mso; /* 0x0080 */
- __u64 msl; /* 0x0088 */
- psw_t gpsw; /* 0x0090 */
- __u64 gg14; /* 0x00a0 */
- __u64 gg15; /* 0x00a8 */
- __u8 reservedb0[8]; /* 0x00b0 */
-#define HPID_KVM 0x4
-#define HPID_VSIE 0x5
- __u8 hpid; /* 0x00b8 */
- __u8 reservedb9[7]; /* 0x00b9 */
- union {
- struct {
- __u32 eiparams; /* 0x00c0 */
- __u16 extcpuaddr; /* 0x00c4 */
- __u16 eic; /* 0x00c6 */
- };
- __u64 mcic; /* 0x00c0 */
- } __packed;
- __u32 reservedc8; /* 0x00c8 */
- union {
- struct {
- __u16 pgmilc; /* 0x00cc */
- __u16 iprcc; /* 0x00ce */
- };
- __u32 edc; /* 0x00cc */
- } __packed;
- union {
- struct {
- __u32 dxc; /* 0x00d0 */
- __u16 mcn; /* 0x00d4 */
- __u8 perc; /* 0x00d6 */
- __u8 peratmid; /* 0x00d7 */
- };
- __u64 faddr; /* 0x00d0 */
- } __packed;
- __u64 peraddr; /* 0x00d8 */
- __u8 eai; /* 0x00e0 */
- __u8 peraid; /* 0x00e1 */
- __u8 oai; /* 0x00e2 */
- __u8 armid; /* 0x00e3 */
- __u8 reservede4[4]; /* 0x00e4 */
- union {
- __u64 tecmc; /* 0x00e8 */
- struct {
- __u16 subchannel_id; /* 0x00e8 */
- __u16 subchannel_nr; /* 0x00ea */
- __u32 io_int_parm; /* 0x00ec */
- __u32 io_int_word; /* 0x00f0 */
- };
- } __packed;
- __u8 reservedf4[8]; /* 0x00f4 */
-#define CRYCB_FORMAT_MASK 0x00000003
-#define CRYCB_FORMAT0 0x00000000
-#define CRYCB_FORMAT1 0x00000001
-#define CRYCB_FORMAT2 0x00000003
- __u32 crycbd; /* 0x00fc */
- __u64 gcr[16]; /* 0x0100 */
- union {
- __u64 gbea; /* 0x0180 */
- __u64 sidad;
- };
- __u8 reserved188[8]; /* 0x0188 */
- __u64 sdnxo; /* 0x0190 */
- __u8 reserved198[8]; /* 0x0198 */
- __u32 fac; /* 0x01a0 */
- __u8 reserved1a4[20]; /* 0x01a4 */
- __u64 cbrlo; /* 0x01b8 */
- __u8 reserved1c0[8]; /* 0x01c0 */
-#define ECD_HOSTREGMGMT 0x20000000
-#define ECD_MEF 0x08000000
-#define ECD_ETOKENF 0x02000000
-#define ECD_ECC 0x00200000
-#define ECD_HMAC 0x00004000
- __u32 ecd; /* 0x01c8 */
- __u8 reserved1cc[18]; /* 0x01cc */
- __u64 pp; /* 0x01de */
- __u8 reserved1e6[2]; /* 0x01e6 */
- __u64 itdba; /* 0x01e8 */
- __u64 riccbd; /* 0x01f0 */
- __u64 gvrd; /* 0x01f8 */
-} __packed __aligned(512);
-
-struct kvm_s390_itdb {
- __u8 data[256];
-};
-
-struct sie_page {
- struct kvm_s390_sie_block sie_block;
- struct mcck_volatile_info mcck_info; /* 0x0200 */
- __u8 reserved218[360]; /* 0x0218 */
- __u64 pv_grregs[16]; /* 0x0380 */
- __u8 reserved400[512]; /* 0x0400 */
- struct kvm_s390_itdb itdb; /* 0x0600 */
- __u8 reserved700[2304]; /* 0x0700 */
-};
-
-#endif /* _ASM_KVM_HOST_TYPES_H */
+#endif /* ASM_KVM_HOST_TYPES_H */
diff --git a/arch/s390/include/asm/sae.h b/arch/s390/include/asm/sae.h
new file mode 100644
index 00000000000000..fe010a1a772975
--- /dev/null
+++ b/arch/s390/include/asm/sae.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_S390_SAE_H
+#define __ASM_S390_SAE_H
+
+#include "linux/linkage.h"
+#include <linux/types.h>
+
+/* defined in arch/s390/kernel/entry.S */
+asmlinkage int __sae64a(phys_addr_t sae_block_phys);
+
+#ifndef __ASSEMBLER__
+#include <linux/io.h>
+#include <asm/kvm_host_arm64_types.h>
+
+/**
+ * __sae64a() - Start Arm Execution
+ */
+static inline void sae64a(struct kvm_sae_block *sae_block)
+{
+ __sae64a(virt_to_phys(sae_block));
+}
+
+/**
+ * stiasrm() - STore and Invalidate Arm System Register Multiple
+ * @save_area: Pointer to SAE save area
+ *
+ * Store the guest system register to the save area.
+ * The values in the guest are not valid anymore..
+ */
+static __always_inline void stiasrm(struct kvm_sae_save_area *save_area)
+{
+ asm volatile(
+ " .insn rre,0xb9a70000,%[r1],0\n"
+ : "+m"(*save_area)
+ : [r1] "a"(save_area)
+ );
+}
+
+/**
+ * lasrm() - Load Arm System Register Multiple
+ *
+ * @save_area: Pointer to SAE save area
+ *
+ * Load the system registers from save_area into the guest.
+ */
+static __always_inline void lasrm(struct kvm_sae_save_area *save_area)
+{
+ asm volatile(
+ " .insn rre,0xb9a60000,%[r1],0\n"
+ :
+ : "m"(*save_area), [r1] "a"(save_area)
+ );
+}
+
+#endif /* !__ASSEMBLER__ */
+#endif /* __ASM_S390_SAE_H */
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h
index f2d49055805437..f669569cf78df6 100644
--- a/arch/s390/include/asm/sclp.h
+++ b/arch/s390/include/asm/sclp.h
@@ -53,7 +53,9 @@ struct sclp_core_entry {
u8 siif : 1;
u8 sigpif : 1;
u8 : 3;
- u8 reserved2[3];
+ u8 aef: 1;
+ u8 : 7;
+ u8 reserved2[2];
u8 : 2;
u8 ib : 1;
u8 cei : 1;
@@ -106,6 +108,7 @@ struct sclp_info {
unsigned char has_aeni : 1;
unsigned char has_aisi : 1;
unsigned char has_astfleie2 : 1;
+ unsigned char has_aef : 1;
unsigned int ibc;
unsigned int mtid;
unsigned int mtid_cp;
diff --git a/arch/s390/include/asm/stacktrace.h b/arch/s390/include/asm/stacktrace.h
index ac3606c3babe49..2d332d7c814594 100644
--- a/arch/s390/include/asm/stacktrace.h
+++ b/arch/s390/include/asm/stacktrace.h
@@ -59,6 +59,7 @@ static inline bool on_stack(struct stack_info *info,
struct stack_frame {
union {
unsigned long empty[9];
+ /* SIE stack frame */
struct {
unsigned long sie_control_block;
unsigned long sie_savearea;
@@ -68,6 +69,10 @@ struct stack_frame {
unsigned long sie_guest_asce;
unsigned long sie_irq;
};
+ /* SAE stack frame */
+ struct {
+ unsigned long sae_bear;
+ };
};
unsigned long gprs[10];
unsigned long back_chain;
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index f6dd2b67dcee74..f9f9c2246074f8 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -70,6 +70,7 @@ int main(void)
OFFSET(__SF_SIE_CONTROL_PHYS, stack_frame, sie_control_block_phys);
OFFSET(__SF_SIE_GUEST_ASCE, stack_frame, sie_guest_asce);
OFFSET(__SF_SIE_IRQ, stack_frame, sie_irq);
+ OFFSET(__SF_SAE_BEAR, stack_frame, sae_bear);
DEFINE(STACK_FRAME_OVERHEAD, sizeof(struct stack_frame));
BLANK();
OFFSET(__SFUSER_BACKCHAIN, stack_frame_user, back_chain);
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index b27239c03d7992..464f8918d447fb 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -57,7 +57,7 @@ decompressor_handled_param(cmma);
decompressor_handled_param(relocate_lowcore);
decompressor_handled_param(bootdebug);
__decompressor_handled_param(debug_alternative, debug-alternative);
-#if IS_ENABLED(CONFIG_KVM)
+#if IS_ENABLED(CONFIG_KVM_S390)
decompressor_handled_param(prot_virt);
#endif
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 79a45efae23d06..248bea26921bef 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -113,7 +113,7 @@ _LPP_OFFSET = __LC_LPP
"jnz .+8; .insn rrf,0xb2e80000,0,0,13,0", ALT_SPEC(82)
.endm
-#if IS_ENABLED(CONFIG_KVM)
+#if IS_ENABLED(CONFIG_KVM_S390)
.macro SIEEXIT sie_control,lowcore
lg %r9,\sie_control # get control block pointer
ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE
@@ -184,7 +184,7 @@ EXPORT_SYMBOL(__WARN_trap)
#endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */
-#if IS_ENABLED(CONFIG_KVM)
+#if IS_ENABLED(CONFIG_KVM_S390)
/*
* __sie64a calling convention:
* %r2 pointer to sie control block phys
@@ -244,6 +244,31 @@ EXPORT_SYMBOL(__sie64a)
EXPORT_SYMBOL(sie_exit)
#endif
+#if IS_ENABLED(CONFIG_KVM_ARM64)
+/*
+ * __sae64a calling convention:
+ * %r2 pointer to sae control block physical address
+ */
+SYM_FUNC_START(__sae64a)
+ stmg %r6,%r14,__SF_GPRS(%r15) # store kernel registers
+ STBEAR __SF_SAE_BEAR(%r15) # save breaking event address register
+ .insn rre,0xb9a50000,%r2,0 # Start Arm Execution
+# Let the next instruction be NOP to avoid triggering a machine check
+# and handling it in a guest as result of the instruction execution.
+ nopr 7
+ LBEAR __SF_SAE_BEAR(%r15) # restore breaking event address register
+ lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
+ xgr %r0,%r0 # clear guest registers to
+ xgr %r1,%r1 # prevent speculative use
+ xgr %r3,%r3
+ xgr %r2,%r2
+ xgr %r4,%r4
+ xgr %r5,%r5
+ BR_EX %r14
+SYM_FUNC_END(__sae64a)
+EXPORT_SYMBOL(__sae64a)
+#endif
+
/*
* SVC interrupt handler routine. System calls are synchronous events and
* are entered with interrupts disabled.
@@ -315,7 +340,7 @@ SYM_CODE_START(pgm_check_handler)
xgr %r10,%r10
tmhh %r8,0x0001 # coming from user space?
jo 3f # -> fault in user space
-#if IS_ENABLED(CONFIG_KVM)
+#if IS_ENABLED(CONFIG_KVM_S390)
lg %r11,__LC_CURRENT(%r13)
tm __TI_sie(%r11),0xff
jz 1f
@@ -397,7 +422,7 @@ SYM_CODE_START(\name)
lmg %r8,%r9,\lc_old_psw(%r13)
tmhh %r8,0x0001 # interrupting from user ?
jnz 1f
-#if IS_ENABLED(CONFIG_KVM)
+#if IS_ENABLED(CONFIG_KVM_S390)
lg %r10,__LC_CURRENT(%r13)
tm __TI_sie(%r10),0xff
jz 0f
@@ -475,7 +500,7 @@ SYM_CODE_START(mcck_int_handler)
jnz .Lmcck_user
TSTMSK __LC_MCCK_CODE(%r13),MCCK_CODE_PSW_IA_VALID
jno .Lmcck_panic
-#if IS_ENABLED(CONFIG_KVM)
+#if IS_ENABLED(CONFIG_KVM_S390)
lg %r10,__LC_CURRENT(%r13)
tm __TI_sie(%r10),0xff
jz .Lmcck_user
diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c
index 606750bae508df..6441746b8e7209 100644
--- a/arch/s390/kernel/perf_event.c
+++ b/arch/s390/kernel/perf_event.c
@@ -37,7 +37,7 @@ static bool is_in_guest(struct pt_regs *regs)
{
if (user_mode(regs))
return false;
-#if IS_ENABLED(CONFIG_KVM)
+#if IS_ENABLED(CONFIG_KVM_S390)
return instruction_pointer(regs) == (unsigned long) &sie_exit;
#else
return false;
diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c
index e33a3eccda5688..6da55a158027eb 100644
--- a/arch/s390/kernel/processor.c
+++ b/arch/s390/kernel/processor.c
@@ -150,6 +150,7 @@ static void show_cpu_summary(struct seq_file *m, void *v)
[HWCAP_NR_NNPA] = "nnpa",
[HWCAP_NR_PCI_MIO] = "pcimio",
[HWCAP_NR_SIE] = "sie",
+ [HWCAP_NR_SAE] = "sae",
};
int i, cpu;
@@ -254,6 +255,8 @@ static int __init setup_hwcaps(void)
/* virtualization support */
if (sclp.has_sief2)
elf_hwcap |= HWCAP_SIE;
+ if (sclp.has_aef)
+ elf_hwcap |= HWCAP_SAE;
return 0;
}
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index 8d3ee17a1bcbcf..bbae58aa8bc467 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -17,40 +17,9 @@ menuconfig VIRTUALIZATION
if VIRTUALIZATION
config KVM
- def_tristate y
- prompt "Kernel-based Virtual Machine (KVM) support"
- select HAVE_KVM_CPU_RELAX_INTERCEPT
- select KVM_ASYNC_PF
- select KVM_ASYNC_PF_SYNC
- select KVM_COMMON
- select HAVE_KVM_IRQCHIP
- select HAVE_KVM_IRQ_ROUTING
- select HAVE_KVM_INVALID_WAKEUPS
- select HAVE_KVM_NO_POLL
- select KVM_VFIO
- select VIRT_XFER_TO_GUEST_WORK
- select KVM_MMU_LOCKLESS_AGING
- select KVM_GENERIC_PRE_FAULT_MEMORY
- help
- Support hosting paravirtualized guest machines using the SIE
- virtualization capability on the mainframe. This should work
- on any 64bit machine.
-
- This module provides access to the hardware capabilities through
- a character device node named /dev/kvm.
-
- To compile this as a module, choose M here: the module
- will be called kvm.
-
- If unsure, say N.
-
-config KVM_S390_UCONTROL
- bool "Userspace controlled virtual machines"
- depends on KVM
- help
- Allow CAP_SYS_ADMIN users to create KVM virtual machines that are
- controlled by userspace.
+ tristate
- If unsure, say N.
+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 dac9d53b23d8b7..38bdd7c9b42d25 100644
--- a/arch/s390/kvm/Makefile
+++ b/arch/s390/kvm/Makefile
@@ -3,13 +3,5 @@
#
# Copyright IBM Corp. 2008
-include $(srctree)/virt/kvm/Makefile.kvm
-
-ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
-
-kvm-y += kvm-s390.o intercept.o interrupt.o priv.o sigp.o
-kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o
-kvm-y += dat.o gmap.o faultin.o
-
-kvm-$(CONFIG_VFIO_PCI_ZDEV_KVM) += pci.o
-obj-$(CONFIG_KVM) += kvm.o
+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 00000000000000..99a7fc3b71c0e1
--- /dev/null
+++ b/arch/s390/kvm/arm64/Kconfig
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config KVM_ARM64
+ def_tristate y
+ prompt "Kernel-based Virtual Machine (KVM) support for arm64 guests"
+ depends on HAS_IOMEM
+ 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 KVM_GENERIC_PRE_FAULT_MEMORY
+ 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 00000000000000..566040725ab57a
--- /dev/null
+++ b/arch/s390/kvm/arm64/Makefile
@@ -0,0 +1,94 @@
+# SPDX-License-Identifier: GPL-2.0
+
+KVM := ../../../../virt/kvm
+include $(srctree)/virt/kvm/Makefile.kvm
+KVM_MANAGES_S390_GUEST = n
+include $(srctree)/arch/s390/kvm/gmap/Makefile
+include $(src)/Makefile.gen
+
+ccflags-y += -I $(src) -I $(objtree)/$(obj) -I$(srctree)/arch/s390/kvm/gmap -I$(srctree)/arch/arm64/include -I$(srctree)/arch/arm64/kvm -DKVM_S390_ARM64
+
+kvm-arm64-obj := \
+ arm.o \
+ guest.o \
+ handle_exit.o \
+ inject_fault.o \
+ mmu.o \
+ mmio.o \
+ reset.o \
+
+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 --whole-archive
+$(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.
+# TODO extract do script
+quiet_cmd_nm_filter = NMFLTR $@
+ cmd_nm_filter = $(NM) -jU $< | sort -u > $@
+
+$(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
diff --git a/arch/s390/kvm/arm64/Makefile.gen b/arch/s390/kvm/arm64/Makefile.gen
new file mode 100644
index 00000000000000..2e8838bc69214c
--- /dev/null
+++ b/arch/s390/kvm/arm64/Makefile.gen
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Extracts ARM64 marked sections to .inc files that are included by main source
+# files
+
+# List of ARM64 C files to extract
+ARM64_CFILES := \
+ arm.c \
+ guest.c \
+ reset.c \
+ handle_exit.c \
+ mmio.c \
+
+quiet_cmd_extract_inc = GEN $@
+ cmd_extract_inc = mkdir -p $(dir $@); \
+ $(AWK) -f $(src)/copy-arm64c.awk $< > $@ || \
+ { echo "Error: No ARM64_S390_COMMON markers in $<" >&2; rm -f $@; exit 1; }
+
+$(obj)/generated/%.inc: $(srctree)/arch/arm64/kvm/%.c $(src)/copy-arm64c.awk FORCE
+ $(call if_changed,extract_inc)
+
+ARM64_INC_FILES := $(foreach cfile,$(ARM64_CFILES),generated/$(basename $(cfile)).inc)
+
+targets += $(ARM64_INC_FILES)
+clean-files += generated/*.inc
+
+$(addprefix $(obj)/,$(kvm-arm64-obj)): $(addprefix $(obj)/,$(ARM64_INC_FILES))
+
+$(foreach cfile,$(basename $(ARM64_CFILES)),\
+ $(eval $(obj)/$(cfile).o: $(obj)/generated/$(cfile).inc))
diff --git a/arch/s390/kvm/arm64/arm.c b/arch/s390/kvm/arm64/arm.c
new file mode 100644
index 00000000000000..6ef47f7010bedc
--- /dev/null
+++ b/arch/s390/kvm/arm64/arm.c
@@ -0,0 +1,726 @@
+// 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 <linux/fpu.h>
+
+#include <asm/access-regs.h>
+
+#include <arm64/kvm_emulate.h>
+#include <arm64/kvm_mmu.h>
+#include <arm64/sysreg.h>
+
+#include <gmap.h>
+
+#include "arm.h"
+#include "guest.h"
+#include "handle_exit.h"
+#include "reset.h"
+
+static unsigned long system_supported_vcpu_features(void);
+
+#define __INCL_GEN_ARM_FILE
+#include "generated/arm.inc"
+#undef __INCL_GEN_ARM_FILE
+
+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;
+ case KVM_CAP_IOEVENTFD:
+ case KVM_CAP_ARM_USER_IRQ:
+ case KVM_CAP_PRE_FAULT_MEMORY:
+ ret = 1;
+ 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;
+}
+
+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;
+}
+
+static 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\n",
+ current->comm);
+ return -EINVAL;
+ }
+ }
+
+ return phys_shift;
+}
+
+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;
+}
+
+long kvm_arch_dev_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ 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;
+}
+
+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)
+{
+}
+
+void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu)
+{
+}
+
+void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+ save_access_regs(&vcpu->arch.host_acrs[0]);
+ vcpu->cpu = cpu;
+
+ lasrm(&vcpu->arch.save_area);
+}
+
+void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
+{
+ stiasrm(&vcpu->arch.save_area);
+
+ vcpu->cpu = -1;
+ restore_access_regs(&vcpu->arch.host_acrs[0]);
+}
+
+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;
+}
+
+static unsigned long system_supported_vcpu_features(void)
+{
+ return KVM_VCPU_VALID_FEATURES;
+}
+
+bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
+{
+ return vcpu_mode_priv(vcpu);
+}
+
+int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
+{
+ struct kvm *kvm = vcpu->kvm;
+
+ if (!kvm_vcpu_initialized(vcpu))
+ return -ENOEXEC;
+
+ if (!kvm_arm_vcpu_is_finalized(vcpu))
+ return -EPERM;
+
+ if (likely(READ_ONCE(vcpu->pid)))
+ return 0;
+
+ mutex_lock(&kvm->arch.config_lock);
+ set_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags);
+ mutex_unlock(&kvm->arch.config_lock);
+
+ return 0;
+}
+
+/**
+ * check_vcpu_requests - check and handle pending vCPU requests
+ * @vcpu: the VCPU pointer
+ *
+ * Return: 1 if we should enter the guest
+ * 0 if we should exit to userspace
+ * < 0 if we should exit to userspace, where the return value indicates
+ * an error
+ */
+static int check_vcpu_requests(struct kvm_vcpu *vcpu)
+{
+ if (kvm_request_pending(vcpu)) {
+ if (kvm_check_request(KVM_REQ_VCPU_RESET, vcpu))
+ kvm_reset_vcpu(vcpu);
+ /*
+ * Clear IRQ_PENDING requests that were made to guarantee
+ * that a VCPU sees new virtual interrupts.
+ */
+ kvm_check_request(KVM_REQ_IRQ_PENDING, vcpu);
+ }
+
+ return 1;
+}
+
+static int kvm_vcpu_initialize(struct kvm_vcpu *vcpu,
+ const struct kvm_vcpu_init *init)
+{
+ unsigned long features = init->features[0];
+ struct kvm *kvm = vcpu->kvm;
+ int ret = -EINVAL;
+
+ mutex_lock(&kvm->arch.config_lock);
+
+ if (test_bit(KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED, &kvm->arch.flags) &&
+ kvm_vcpu_init_changed(vcpu, init))
+ goto out_unlock;
+
+ bitmap_copy(kvm->arch.vcpu_features, &features, KVM_VCPU_MAX_FEATURES);
+
+ kvm_reset_vcpu(vcpu);
+
+ set_bit(KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED, &kvm->arch.flags);
+ vcpu_set_flag(vcpu, VCPU_INITIALIZED);
+
+ ret = 0;
+out_unlock:
+ mutex_unlock(&kvm->arch.config_lock);
+ return ret;
+}
+
+static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
+ const struct kvm_vcpu_init *init)
+{
+ int ret;
+
+ if (init->target != KVM_ARM_TARGET_GENERIC_V8)
+ return -EINVAL;
+
+ ret = kvm_vcpu_init_check_features(vcpu, init);
+ if (ret)
+ return ret;
+
+ if (!kvm_vcpu_initialized(vcpu))
+ return kvm_vcpu_initialize(vcpu, init);
+
+ if (kvm_vcpu_init_changed(vcpu, init))
+ return -EINVAL;
+
+ kvm_reset_vcpu(vcpu);
+
+ return 0;
+}
+
+static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu,
+ struct kvm_vcpu_init *init)
+{
+ struct kvm_sae_save_area *save_area = &vcpu->arch.save_area;
+ struct kvm_sae_block *sae_block = &vcpu->arch.sae_block;
+ int ret;
+
+ sae_block->save_area = virt_to_phys(save_area);
+ save_area->sdo = virt_to_phys(sae_block);
+
+ ret = kvm_vcpu_set_target(vcpu, init);
+ if (ret)
+ return ret;
+
+ spin_lock(&vcpu->arch.mp_state_lock);
+ WRITE_ONCE(vcpu->arch.mp_state.mp_state, KVM_MP_STATE_RUNNABLE);
+ spin_unlock(&vcpu->arch.mp_state_lock);
+
+ return 0;
+}
+
+int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
+ bool line_status)
+{
+ return 0;
+}
+
+static void adjust_pc(struct kvm_vcpu *vcpu)
+{
+ if (vcpu_get_flag(vcpu, INCREMENT_PC)) {
+ kvm_skip_instr(vcpu);
+ vcpu_clear_flag(vcpu, INCREMENT_PC);
+ }
+}
+
+static void arm_vcpu_run(struct kvm_vcpu *vcpu)
+{
+ struct kvm_sae_block *sae_block = &vcpu->arch.sae_block;
+
+ adjust_pc(vcpu);
+
+ local_irq_disable();
+ guest_enter_irqoff();
+ local_irq_enable();
+
+ sae_block->icptr = 0;
+
+ sae64a(sae_block);
+
+ local_irq_disable();
+ guest_exit_irqoff();
+ local_irq_enable();
+}
+
+/** kvm_arch_vcpu_ioctl_run() - run arm64 vCPU
+ *
+ * Execute arm64 guest instructions using SAE.
+ *
+ * Returns:
+ * 1 enter the guest (should not be observed by userspace)
+ * 0 exit to userspace
+ * < 0 exit to userspace, where the return value indicates n error
+ *
+ *
+ */
+int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
+{
+ DECLARE_KERNEL_FPU_ONSTACK32(fpu_save);
+ struct kvm_run *kvm_run = vcpu->run;
+ int ret;
+
+ if (kvm_run->exit_reason == KVM_EXIT_MMIO) {
+ ret = kvm_handle_mmio_return(vcpu);
+ if (ret <= 0)
+ return ret;
+ }
+
+ vcpu_load(vcpu);
+
+ kernel_fpu_begin(&fpu_save, KERNEL_FPC | KERNEL_VXR);
+ load_vx_regs((vcpu->arch.ctxt.vregs));
+
+ if (!vcpu->wants_to_run) {
+ ret = -EINTR;
+ goto out;
+ }
+
+ kvm_sigset_activate(vcpu);
+
+ might_fault();
+
+ ret = 1;
+ do {
+ if (signal_pending(current)) {
+ kvm_run->exit_reason = KVM_EXIT_INTR;
+ ret = -EINTR;
+ continue;
+ }
+
+ if (need_resched())
+ schedule();
+
+ if (ret > 0)
+ ret = check_vcpu_requests(vcpu);
+
+ vcpu->arch.sae_block.icptr = 0;
+
+ arm_vcpu_run(vcpu);
+
+ ret = handle_exit(vcpu);
+
+ } while (ret > 0);
+
+ kvm_sigset_deactivate(vcpu);
+out:
+ if (unlikely(vcpu_get_flag(vcpu, INCREMENT_PC)))
+ adjust_pc(vcpu);
+
+ save_vx_regs(vcpu->arch.ctxt.vregs);
+ kernel_fpu_end(&fpu_save, KERNEL_FPC | KERNEL_VXR);
+ vcpu_put(vcpu);
+
+ return ret;
+}
+
+long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
+{
+ struct kvm_vcpu *vcpu = filp->private_data;
+ void __user *argp = (void __user *)arg;
+ struct kvm_device_attr attr;
+ int ret;
+
+ switch (ioctl) {
+ case KVM_ARM_VCPU_INIT: {
+ struct kvm_vcpu_init init;
+
+ ret = -EFAULT;
+ if (copy_from_user(&init, argp, sizeof(init)))
+ break;
+
+ ret = kvm_arch_vcpu_ioctl_vcpu_init(vcpu, &init);
+ break;
+ }
+ case KVM_SET_ONE_REG:
+ case KVM_GET_ONE_REG: {
+ struct kvm_one_reg reg;
+
+ ret = -ENOEXEC;
+ if (unlikely(!kvm_vcpu_initialized(vcpu)))
+ break;
+
+ ret = -EFAULT;
+ if (copy_from_user(®, argp, sizeof(reg)))
+ break;
+
+ if (kvm_check_request(KVM_REQ_VCPU_RESET, vcpu))
+ kvm_reset_vcpu(vcpu);
+
+ if (ioctl == KVM_SET_ONE_REG)
+ ret = kvm_arm_set_reg(vcpu, ®);
+ else
+ ret = kvm_arm_get_reg(vcpu, ®);
+ break;
+ }
+ case KVM_GET_REG_LIST: {
+ struct kvm_reg_list __user *user_list = argp;
+ struct kvm_reg_list reg_list;
+ unsigned int n;
+
+ ret = -ENOEXEC;
+ if (unlikely(!kvm_vcpu_initialized(vcpu)))
+ break;
+ ret = -EPERM;
+ if (!kvm_arm_vcpu_is_finalized(vcpu))
+ break;
+ ret = -EFAULT;
+ if (copy_from_user(®_list, user_list, sizeof(reg_list)))
+ break;
+ n = reg_list.n;
+ reg_list.n = kvm_arm_num_regs(vcpu);
+ if (copy_to_user(user_list, ®_list, sizeof(reg_list)))
+ break;
+ ret = -E2BIG;
+ if (n < reg_list.n)
+ break;
+ ret = kvm_arm_copy_reg_indices(vcpu, user_list->reg);
+ break;
+ }
+ case KVM_ARM_VCPU_FINALIZE: {
+ int what;
+
+ if (!kvm_vcpu_initialized(vcpu))
+ return -ENOEXEC;
+
+ if (get_user(what, (const int __user *)argp))
+ return -EFAULT;
+
+ ret = kvm_arm_vcpu_finalize(vcpu, what);
+ break;
+ }
+ case KVM_SET_DEVICE_ATTR: {
+ ret = -EFAULT;
+ if (copy_from_user(&attr, argp, sizeof(attr)))
+ break;
+ ret = kvm_arm_vcpu_set_attr(vcpu, &attr);
+ break;
+ }
+ case KVM_GET_DEVICE_ATTR: {
+ ret = -EFAULT;
+ if (copy_from_user(&attr, argp, sizeof(attr)))
+ break;
+ ret = kvm_arm_vcpu_get_attr(vcpu, &attr);
+ break;
+ }
+ case KVM_HAS_DEVICE_ATTR: {
+ ret = -EFAULT;
+ if (copy_from_user(&attr, argp, sizeof(attr)))
+ break;
+ ret = kvm_arm_vcpu_has_attr(vcpu, &attr);
+ break;
+ }
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+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);
+}
+
+long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,
+ struct kvm_pre_fault_memory *range)
+{
+ return gmap_pre_fault_memory(vcpu, range);
+}
+
+void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
+ struct kvm_memory_slot *slot,
+ gfn_t gfn_offset,
+ unsigned long mask)
+{
+}
+
+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;
+}
+
+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 int __init 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 00000000000000..244c2b7a136f0d
--- /dev/null
+++ b/arch/s390/kvm/arm64/arm.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ARCH_S390_KVM_ARM64_H
+#define ARCH_S390_KVM_ARM64_H
+
+#include <linux/kvm_host.h>
+
+#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 */
diff --git a/arch/s390/kvm/arm64/copy-arm64c.awk b/arch/s390/kvm/arm64/copy-arm64c.awk
new file mode 100644
index 00000000000000..45d9c7034c177d
--- /dev/null
+++ b/arch/s390/kvm/arm64/copy-arm64c.awk
@@ -0,0 +1,69 @@
+#!/usr/bin/awk -f
+# SPDX-License-Identifier: GPL-2.0
+#
+# Extract marked sections from ARM64 C files for sharing with s390 KVM
+#
+# Usage: share-arm64-cfile.awk <input_file>
+#
+# Extracts all sections between start/end markers. If no markers found, signals failure.
+
+BEGIN {
+ # Constants
+ start_pattern = "^#ifdef ARM64_S390_COMMON$"
+ end_pattern = "^#endif /\\* ARM64_S390_COMMON \\*/$"
+
+ # State variables
+ copying = found_marker = 0
+ file_header_done = 0
+}
+
+!file_header_done {
+ if (/^\/\*/ || /^\/\/ SPDX-License-Identifier:/) {
+ print
+ next
+ }
+ if (/[[:space:]]\*([[:space:]]|$)/) {
+ print
+ next
+ }
+ if (/\*\//) {
+ print " *"
+ } else {
+ print "/*"
+ }
+
+ filename = FILENAME
+ sub(/^.*arch\/arm64\//, "arch/arm64/", filename)
+ print " * This file was automatically generated from " filename
+ print " * Do not modify this file directly."
+ print " */"
+ print ""
+ print "#ifndef __INCL_GEN_ARM_FILE"
+ print "#error included .inc file w/o proper guard definition"
+ print "#undef __INCL_GEN_ARM_FILE"
+ print "#endif /* __INCL_GEN_ARM_FILE */"
+ print ""
+
+ file_header_done = 1
+}
+
+$0 ~ start_pattern {
+ copying = found_marker = 1
+ next
+}
+
+$0 ~ end_pattern {
+ copying = 0
+ next
+}
+
+copying {
+ gsub(/#include <asm\//, "#include <arm64/")
+ gsub(/#include <uapi\/asm\//, "#include <uapi/arm64/")
+ print
+ next
+}
+
+END {
+ exit !found_marker
+}
diff --git a/arch/s390/kvm/arm64/guest.c b/arch/s390/kvm/arm64/guest.c
new file mode 100644
index 00000000000000..1197c91e6324ad
--- /dev/null
+++ b/arch/s390/kvm/arm64/guest.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+
+#include <arm64/kvm_emulate.h>
+#include <arm64/kvm_nested.h>
+
+#include "guest.h"
+
+#define __INCL_GEN_ARM_FILE
+#include "generated/guest.inc"
+#undef __INCL_GEN_ARM_FILE
+
+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_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ /* We currently use nothing arch-specific in upper 32 bits */
+ if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
+ return -EINVAL;
+
+ switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
+ case KVM_REG_ARM_CORE:
+ return get_core_reg(vcpu, reg);
+ default:
+ return -EINVAL;
+ }
+}
+
+int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ /* We currently use nothing arch-specific in upper 32 bits */
+ if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
+ return -EINVAL;
+
+ switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
+ case KVM_REG_ARM_CORE:
+ return set_core_reg(vcpu, reg);
+ default:
+ return -EINVAL;
+ }
+}
+
+int kvm_arm_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
+{
+ int ret;
+
+ switch (attr->group) {
+ default:
+ ret = -ENXIO;
+ break;
+ }
+
+ return ret;
+}
+
+int kvm_arm_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
+{
+ int ret;
+
+ switch (attr->group) {
+ default:
+ ret = -ENXIO;
+ break;
+ }
+
+ return ret;
+}
+
+int kvm_arm_vcpu_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
+{
+ int ret;
+
+ switch (attr->group) {
+ default:
+ ret = -ENXIO;
+ break;
+ }
+
+ return ret;
+}
+
+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 00000000000000..be367df99e3132
--- /dev/null
+++ b/arch/s390/kvm/arm64/guest.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef KVM_ARM_GUEST_H
+#define KVM_ARM_GUEST_H
+
+#include <linux/kvm_host.h>
+
+unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
+int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+int kvm_arm_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
+int kvm_arm_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
+int kvm_arm_vcpu_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
+
+#endif /* KVM_ARM_GUEST_H */
diff --git a/arch/s390/kvm/arm64/handle_exit.c b/arch/s390/kvm/arm64/handle_exit.c
new file mode 100644
index 00000000000000..96a45483e5b620
--- /dev/null
+++ b/arch/s390/kvm/arm64/handle_exit.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kvm_host.h>
+
+#include <arm64/esr.h>
+#include <arm64/kvm_emulate.h>
+
+#include "handle_exit.h"
+
+typedef int (*exit_handle_fn)(struct kvm_vcpu *);
+exit_handle_fn arm_exit_handlers[ESR_ELx_EC_MAX + 1];
+
+#define __INCL_GEN_ARM_FILE
+#include "generated/handle_exit.inc"
+#undef __INCL_GEN_ARM_FILE
+
+#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,
+ [ESR_ELx_EC_IABT_LOW] = kvm_handle_guest_abort,
+ [ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort,
+};
+
+/*
+ * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
+ * proper exit to userspace.
+ */
+int handle_exit(struct kvm_vcpu *vcpu)
+{
+ u8 icptr = vcpu->arch.sae_block.icptr;
+ int ret = 1;
+
+ switch (icptr) {
+ case SAE_ICPTR_SPURIOUS:
+ break;
+ case SAE_ICPTR_VALIDITY:
+ WARN_ONCE(true, "SAE: validity intercept. vir: 0x%04x",
+ 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;
+ default:
+ WARN_ONCE(true, "SAE: unknown interception reason 0x%02x",
+ icptr);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/* manually copied from arch/arm64/kernel/traps.c */
+static const char * const 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)];
+}
diff --git a/arch/s390/kvm/arm64/handle_exit.h b/arch/s390/kvm/arm64/handle_exit.h
new file mode 100644
index 00000000000000..65ae5872153753
--- /dev/null
+++ b/arch/s390/kvm/arm64/handle_exit.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef KVM_ARM64_HANDLE_EXIT_H
+#define KVM_ARM64_HANDLE_EXIT_H
+
+#include <linux/kvm_host.h>
+
+int handle_exit(struct kvm_vcpu *vcpu);
+
+#endif /* KVM_ARM64_HANDLE_EXIT_H */
diff --git a/arch/s390/kvm/arm64/inject_fault.c b/arch/s390/kvm/arm64/inject_fault.c
new file mode 100644
index 00000000000000..425dbeaa421c6c
--- /dev/null
+++ b/arch/s390/kvm/arm64/inject_fault.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <arm64/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;
+}
diff --git a/arch/s390/kvm/arm64/mmio.c b/arch/s390/kvm/arm64/mmio.c
new file mode 100644
index 00000000000000..cfddfe3221961b
--- /dev/null
+++ b/arch/s390/kvm/arm64/mmio.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kvm_host.h>
+#include <linux/bitfield.h>
+
+#include <arm64/kvm_emulate.h>
+#include <arm64/kvm_mmu.h>
+#include <arm64/sysreg.h>
+
+#define __INCL_GEN_ARM_FILE
+#include "generated/mmio.inc"
+#undef __INCL_GEN_ARM_FILE
diff --git a/arch/s390/kvm/arm64/mmu.c b/arch/s390/kvm/arm64/mmu.c
new file mode 100644
index 00000000000000..d5acabd762ba48
--- /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 <arm64/kvm_emulate.h>
+#include <arm64/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;
+}
diff --git a/arch/s390/kvm/arm64/reset.c b/arch/s390/kvm/arm64/reset.c
new file mode 100644
index 00000000000000..46edc792f84340
--- /dev/null
+++ b/arch/s390/kvm/arm64/reset.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kvm_host.h>
+
+#include <arm64/kvm_emulate.h>
+#include <arm64/kvm_nested.h>
+
+#include "reset.h"
+
+#define __INCL_GEN_ARM_FILE
+#include "generated/reset.inc"
+#undef __INCL_GEN_ARM_FILE
+
+bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
+{
+ return true;
+}
+
+void kvm_reset_vcpu(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_reset_state reset_state;
+ bool loaded;
+
+ spin_lock(&vcpu->arch.mp_state_lock);
+ reset_state = vcpu->arch.reset_state;
+ vcpu->arch.reset_state.reset = false;
+ spin_unlock(&vcpu->arch.mp_state_lock);
+
+ /*
+ * Disable preemption around the vcpu reset as we might otherwise race with
+ * preempt notifiers which call stiasrm/lasrm from put/load
+ */
+ preempt_disable();
+
+ /* The reset must run with an unloaded save area */
+ loaded = vcpu_is_loaded(vcpu);
+ if (loaded)
+ vcpu_put(vcpu);
+
+ kvm_reset_vcpu_core_regs(vcpu);
+
+ /* Reset special registers */
+ vcpu_reset_hcr(vcpu);
+
+ if (reset_state.reset) {
+ *vcpu_pc(vcpu) = reset_state.pc;
+ vcpu_clear_flag(vcpu, PENDING_EXCEPTION);
+ vcpu_clear_flag(vcpu, EXCEPT_MASK);
+ vcpu_clear_flag(vcpu, INCREMENT_PC);
+ vcpu_set_reg(vcpu, 0, reset_state.r0);
+ }
+
+ if (loaded)
+ vcpu_load(vcpu);
+
+ preempt_enable();
+}
+
+int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature)
+{
+ return 0;
+}
diff --git a/arch/s390/kvm/arm64/reset.h b/arch/s390/kvm/arm64/reset.h
new file mode 100644
index 00000000000000..a5c5304e47bcf7
--- /dev/null
+++ b/arch/s390/kvm/arm64/reset.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef KVM_ARM_RESET_H
+#define KVM_ARM_RESET_H
+
+#include <linux/kvm_host.h>
+
+bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
+void kvm_reset_vcpu(struct kvm_vcpu *vcpu);
+int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature);
+
+#endif /* KVM_ARM_RESET_H */
diff --git a/arch/s390/kvm/gmap/Makefile b/arch/s390/kvm/gmap/Makefile
new file mode 100644
index 00000000000000..4ca7635d1d0e82
--- /dev/null
+++ b/arch/s390/kvm/gmap/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+
+GMAP ?= ../gmap
+
+# Enable s390-specific guest management features (storage keys and CMMA)
+KVM_MANAGES_S390_GUEST ?= y
+USE_PREFIX_STUB := $(if $(filter y,$(KVM_MANAGES_S390_GUEST)),n,y)
+
+kvm-y += $(GMAP)/dat.o $(GMAP)/gmap.o $(GMAP)/faultin.o $(GMAP)/mmu.o
+
+kvm-$(KVM_MANAGES_S390_GUEST) += $(GMAP)/sk.o $(GMAP)/cmma.o $(GMAP)/prefix.o
+kvm-$(USE_PREFIX_STUB) += $(GMAP)/prefix-stubs.o
diff --git a/arch/s390/kvm/gmap/cmma.c b/arch/s390/kvm/gmap/cmma.c
new file mode 100644
index 00000000000000..db729327aedaee
--- /dev/null
+++ b/arch/s390/kvm/gmap/cmma.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/mm.h>
+#include <linux/kvm_host.h>
+#include "cmma.h"
+#include "gmap.h"
+
+int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state *state, bool *dirty)
+{
+ union crste *crstep;
+ union pgste pgste;
+ union pte *ptep;
+ int res = 0;
+
+ if (dat_entry_walk(NULL, gfn, asce, 0, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep)) {
+ *state = (union essa_state) { .exception = 1 };
+ return -1;
+ }
+
+ pgste = pgste_get_lock(ptep);
+
+ *state = (union essa_state) {
+ .content = (ptep->h.i << 1) + (ptep->h.i && pgste.zero),
+ .nodat = pgste.nodat,
+ .usage = pgste.usage,
+ };
+
+ switch (orc) {
+ case ESSA_GET_STATE:
+ res = -1;
+ break;
+ case ESSA_SET_STABLE:
+ pgste.usage = PGSTE_GPS_USAGE_STABLE;
+ pgste.nodat = 0;
+ break;
+ case ESSA_SET_UNUSED:
+ pgste.usage = PGSTE_GPS_USAGE_UNUSED;
+ if (ptep->h.i)
+ res = 1;
+ break;
+ case ESSA_SET_VOLATILE:
+ pgste.usage = PGSTE_GPS_USAGE_VOLATILE;
+ if (ptep->h.i)
+ res = 1;
+ break;
+ case ESSA_SET_POT_VOLATILE:
+ if (!ptep->h.i) {
+ pgste.usage = PGSTE_GPS_USAGE_POT_VOLATILE;
+ } else if (pgste.zero) {
+ pgste.usage = PGSTE_GPS_USAGE_VOLATILE;
+ } else if (!pgste.gc) {
+ pgste.usage = PGSTE_GPS_USAGE_VOLATILE;
+ res = 1;
+ }
+ break;
+ case ESSA_SET_STABLE_RESIDENT:
+ pgste.usage = PGSTE_GPS_USAGE_STABLE;
+ /*
+ * Since the resident state can go away any time after this
+ * call, we will not make this page resident. We can revisit
+ * this decision if a guest will ever start using this.
+ */
+ break;
+ case ESSA_SET_STABLE_IF_RESIDENT:
+ if (!ptep->h.i)
+ pgste.usage = PGSTE_GPS_USAGE_STABLE;
+ break;
+ case ESSA_SET_STABLE_NODAT:
+ pgste.usage = PGSTE_GPS_USAGE_STABLE;
+ pgste.nodat = 1;
+ break;
+ default:
+ WARN_ONCE(1, "Invalid ORC!");
+ res = -1;
+ break;
+ }
+ /* If we are discarding a page, set it to logical zero. */
+ pgste.zero = res == 1;
+ if (orc > 0) {
+ *dirty = !pgste.cmma_d;
+ pgste.cmma_d = 1;
+ }
+
+ pgste_set_unlock(ptep, pgste);
+
+ return res;
+}
+
+static long dat_reset_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
+{
+ union pgste pgste;
+
+ pgste = pgste_get_lock(ptep);
+ pgste.usage = 0;
+ pgste.nodat = 0;
+ pgste.cmma_d = 0;
+ pgste_set_unlock(ptep, pgste);
+ if (need_resched())
+ return next;
+ return 0;
+}
+
+long dat_reset_cmma(union asce asce, gfn_t start)
+{
+ const struct dat_walk_ops dat_reset_cmma_ops = {
+ .pte_entry = dat_reset_cmma_pte,
+ };
+
+ return _dat_walk_gfn_range(start, asce_end(asce), asce, &dat_reset_cmma_ops,
+ DAT_WALK_IGN_HOLES, NULL);
+}
+
+struct dat_get_cmma_state {
+ gfn_t start;
+ gfn_t end;
+ unsigned int count;
+ u8 *values;
+ atomic64_t *remaining;
+};
+
+static long __dat_peek_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
+{
+ struct dat_get_cmma_state *state = walk->priv;
+ union pgste pgste;
+
+ pgste = pgste_get_lock(ptep);
+ state->values[gfn - walk->start] = pgste.usage | (pgste.nodat << 6);
+ pgste_set_unlock(ptep, pgste);
+ state->end = next;
+
+ return 0;
+}
+
+static long __dat_peek_cmma_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
+{
+ struct dat_get_cmma_state *state = walk->priv;
+
+ if (crstep->h.i)
+ state->end = min(walk->end, next);
+ return 0;
+}
+
+int dat_peek_cmma(gfn_t start, union asce asce, unsigned int *count, u8 *values)
+{
+ const struct dat_walk_ops ops = {
+ .pte_entry = __dat_peek_cmma_pte,
+ .pmd_entry = __dat_peek_cmma_crste,
+ .pud_entry = __dat_peek_cmma_crste,
+ .p4d_entry = __dat_peek_cmma_crste,
+ .pgd_entry = __dat_peek_cmma_crste,
+ };
+ struct dat_get_cmma_state state = { .values = values, };
+ int rc;
+
+ rc = _dat_walk_gfn_range(start, start + *count, asce, &ops, DAT_WALK_DEFAULT, &state);
+ *count = state.end >= start ? state.end - start : 0;
+ /* Return success if at least one value was saved, otherwise an error. */
+ return (rc == -EFAULT && *count > 0) ? 0 : rc;
+}
+
+static long __dat_get_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
+{
+ struct dat_get_cmma_state *state = walk->priv;
+ union pgste pgste;
+
+ if (state->start != -1) {
+ if ((gfn - state->end) > KVM_S390_MAX_BIT_DISTANCE)
+ return 1;
+ if (gfn - state->start >= state->count)
+ return 1;
+ }
+
+ if (!READ_ONCE(*pgste_of(ptep)).cmma_d)
+ return 0;
+
+ pgste = pgste_get_lock(ptep);
+ if (pgste.cmma_d) {
+ if (state->start == -1)
+ state->start = gfn;
+ pgste.cmma_d = 0;
+ atomic64_dec(state->remaining);
+ state->values[gfn - state->start] = pgste.usage | pgste.nodat << 6;
+ state->end = next;
+ }
+ pgste_set_unlock(ptep, pgste);
+ return 0;
+}
+
+int dat_get_cmma(union asce asce, gfn_t *start, unsigned int *count, u8 *values, atomic64_t *rem)
+{
+ const struct dat_walk_ops ops = { .pte_entry = __dat_get_cmma_pte, };
+ struct dat_get_cmma_state state = {
+ .remaining = rem,
+ .values = values,
+ .count = *count,
+ .start = -1,
+ };
+
+ _dat_walk_gfn_range(*start, asce_end(asce), asce, &ops, DAT_WALK_IGN_HOLES, &state);
+ /* If no dirty pages were found, wrap around and continue searching */
+ if (*start && state.start == -1)
+ _dat_walk_gfn_range(0, *start, asce, &ops, DAT_WALK_IGN_HOLES, &state);
+
+ if (state.start == -1) {
+ *count = 0;
+ } else {
+ *count = state.end - state.start;
+ *start = state.start;
+ }
+
+ return 0;
+}
+
+struct dat_set_cmma_state {
+ unsigned long mask;
+ const u8 *bits;
+};
+
+static long __dat_set_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
+{
+ struct dat_set_cmma_state *state = walk->priv;
+ union pgste pgste, tmp;
+
+ tmp.val = (state->bits[gfn - walk->start] << 24) & state->mask;
+
+ pgste = pgste_get_lock(ptep);
+ pgste.usage = tmp.usage;
+ pgste.nodat = tmp.nodat;
+ pgste_set_unlock(ptep, pgste);
+
+ return 0;
+}
+
+/**
+ * dat_set_cmma_bits() - Set CMMA bits for a range of guest pages.
+ * @mc: Cache used for allocations.
+ * @asce: The ASCE of the guest.
+ * @gfn: The guest frame of the fist page whose CMMA bits are to set.
+ * @count: How many pages need to be processed.
+ * @mask: Which PGSTE bits should be set.
+ * @bits: Points to an array with the CMMA attributes.
+ *
+ * This function sets the CMMA attributes for the given pages. If the input
+ * buffer has zero length, no action is taken, otherwise the attributes are
+ * set and the mm->context.uses_cmm flag is set.
+ *
+ * Each byte in @bits contains new values for bits 32-39 of the PGSTE.
+ * Currently, only the fields NT and US are applied.
+ *
+ * Return: %0 in case of success, a negative error value otherwise.
+ */
+int dat_set_cmma_bits(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,
+ unsigned long count, unsigned long mask, const uint8_t *bits)
+{
+ const struct dat_walk_ops ops = { .pte_entry = __dat_set_cmma_pte, };
+ struct dat_set_cmma_state state = { .mask = mask, .bits = bits, };
+ union crste *crstep;
+ union pte *ptep;
+ gfn_t cur;
+ int rc;
+
+ for (cur = ALIGN_DOWN(gfn, _PAGE_ENTRIES); cur < gfn + count; cur += _PAGE_ENTRIES) {
+ rc = dat_entry_walk(mc, cur, asce, DAT_WALK_ALLOC, TABLE_TYPE_PAGE_TABLE,
+ &crstep, &ptep);
+ if (rc)
+ return rc;
+ }
+ return _dat_walk_gfn_range(gfn, gfn + count, asce, &ops, DAT_WALK_IGN_HOLES, &state);
+}
+
+static long __set_cmma_clean_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
+{
+ union pgste pgste;
+
+ pgste = pgste_get_lock(ptep);
+ pgste.cmma_d = 0;
+ pgste_set_unlock(ptep, pgste);
+
+ if (need_resched())
+ return next;
+ return 0;
+}
+
+static long __set_cmma_dirty_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
+{
+ union pgste pgste;
+
+ pgste = pgste_get_lock(ptep);
+ if (!pgste.cmma_d)
+ atomic64_inc(walk->priv);
+ pgste.cmma_d = 1;
+ pgste_set_unlock(ptep, pgste);
+
+ if (need_resched())
+ return next;
+ return 0;
+}
+
+void _gmap_set_cmma_all(struct gmap *gmap, bool dirty)
+{
+ const struct dat_walk_ops ops = {
+ .pte_entry = dirty ? __set_cmma_dirty_pte : __set_cmma_clean_pte,
+ };
+ gfn_t gfn = 0;
+
+ do {
+ scoped_guard(read_lock, &gmap->kvm->mmu_lock)
+ gfn = _dat_walk_gfn_range(gfn, asce_end(gmap->asce), gmap->asce, &ops,
+ DAT_WALK_IGN_HOLES,
+ &gmap->kvm->arch.cmma_dirty_pages);
+ cond_resched();
+ } while (gfn);
+}
diff --git a/arch/s390/kvm/gmap/cmma.h b/arch/s390/kvm/gmap/cmma.h
new file mode 100644
index 00000000000000..12b574ecf71189
--- /dev/null
+++ b/arch/s390/kvm/gmap/cmma.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef ARCH_KVM_GMAP_CMMA_H
+#define ARCH_KVM_GMAP_CMMA_H
+
+#include "dat.h"
+
+#define ESSA_GET_STATE 0
+#define ESSA_SET_STABLE 1
+#define ESSA_SET_UNUSED 2
+#define ESSA_SET_VOLATILE 3
+#define ESSA_SET_POT_VOLATILE 4
+#define ESSA_SET_STABLE_RESIDENT 5
+#define ESSA_SET_STABLE_IF_RESIDENT 6
+#define ESSA_SET_STABLE_NODAT 7
+
+int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state *state, bool *dirty);
+long dat_reset_cmma(union asce asce, gfn_t start_gfn);
+int dat_peek_cmma(gfn_t start, union asce asce, unsigned int *count, u8 *values);
+int dat_get_cmma(union asce asce, gfn_t *start, unsigned int *count, u8 *values, atomic64_t *rem);
+int dat_set_cmma_bits(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,
+ unsigned long count, unsigned long mask, const uint8_t *bits);
+
+void _gmap_set_cmma_all(struct gmap *gmap, bool dirty);
+
+static inline void gmap_set_cmma_all_dirty(struct gmap *gmap)
+{
+ _gmap_set_cmma_all(gmap, true);
+}
+
+static inline void gmap_set_cmma_all_clean(struct gmap *gmap)
+{
+ _gmap_set_cmma_all(gmap, false);
+}
+
+#endif /* ARCH_KVM_GMAP_CMMA_H */
diff --git a/arch/s390/kvm/dat.c b/arch/s390/kvm/gmap/dat.c
similarity index 61%
rename from arch/s390/kvm/dat.c
rename to arch/s390/kvm/gmap/dat.c
index 5f1960ec982d04..4a98471395341e 100644
--- a/arch/s390/kvm/dat.c
+++ b/arch/s390/kvm/gmap/dat.c
@@ -27,6 +27,9 @@
#include <asm/page-states.h>
#include <asm/tlb.h>
#include "dat.h"
+#include "sk.h"
+#include "cmma.h"
+
int kvm_s390_mmu_cache_topup(struct kvm_s390_mmu_cache *mc)
{
@@ -611,229 +614,6 @@ long _dat_walk_gfn_range(gfn_t start, gfn_t end, union asce asce,
return dat_crste_walk_range(start, min(end, asce_end(asce)), table, &walk);
}
-int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey)
-{
- union crste *crstep;
- union pgste pgste;
- union pte *ptep;
- int rc;
-
- skey->skey = 0;
- rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
- if (rc)
- return rc;
-
- if (!ptep) {
- union crste crste;
-
- crste = READ_ONCE(*crstep);
- if (!crste.h.fc || !crste.s.fc1.pr)
- return 0;
- skey->skey = page_get_storage_key(large_crste_to_phys(crste, gfn));
- return 0;
- }
- pgste = pgste_get_lock(ptep);
- if (ptep->h.i) {
- skey->acc = pgste.acc;
- skey->fp = pgste.fp;
- } else {
- skey->skey = page_get_storage_key(pte_origin(*ptep));
- }
- skey->r |= pgste.gr;
- skey->c |= pgste.gc;
- pgste_set_unlock(ptep, pgste);
- return 0;
-}
-
-static void dat_update_ptep_sd(union pgste old, union pgste pgste, union pte *ptep)
-{
- if (pgste.acc != old.acc || pgste.fp != old.fp || pgste.gr != old.gr || pgste.gc != old.gc)
- __atomic64_or(_PAGE_SD, &ptep->val);
-}
-
-int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,
- union skey skey, bool nq)
-{
- union pgste pgste, old;
- union crste *crstep;
- union pte *ptep;
- int rc;
-
- rc = dat_entry_walk(mc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,
- &crstep, &ptep);
- if (rc)
- return rc;
-
- if (!ptep) {
- page_set_storage_key(large_crste_to_phys(*crstep, gfn), skey.skey, !nq);
- return 0;
- }
-
- old = pgste_get_lock(ptep);
- pgste = old;
-
- pgste.acc = skey.acc;
- pgste.fp = skey.fp;
- pgste.gc = skey.c;
- pgste.gr = skey.r;
-
- if (!ptep->h.i) {
- union skey old_skey;
-
- old_skey.skey = page_get_storage_key(pte_origin(*ptep));
- pgste.hc |= old_skey.c;
- pgste.hr |= old_skey.r;
- old_skey.c = old.gc;
- old_skey.r = old.gr;
- skey.r = 0;
- skey.c = 0;
- page_set_storage_key(pte_origin(*ptep), skey.skey, !nq);
- }
-
- dat_update_ptep_sd(old, pgste, ptep);
- pgste_set_unlock(ptep, pgste);
- return 0;
-}
-
-static bool page_cond_set_storage_key(phys_addr_t paddr, union skey skey, union skey *oldkey,
- bool nq, bool mr, bool mc)
-{
- oldkey->skey = page_get_storage_key(paddr);
- if (oldkey->acc == skey.acc && oldkey->fp == skey.fp &&
- (oldkey->r == skey.r || mr) && (oldkey->c == skey.c || mc))
- return false;
- page_set_storage_key(paddr, skey.skey, !nq);
- return true;
-}
-
-int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gfn_t gfn,
- union skey skey, union skey *oldkey, bool nq, bool mr, bool mc)
-{
- union pgste pgste, old;
- union crste *crstep;
- union skey prev;
- union pte *ptep;
- int rc;
-
- rc = dat_entry_walk(mmc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,
- &crstep, &ptep);
- if (rc)
- return rc;
-
- if (!ptep)
- return page_cond_set_storage_key(large_crste_to_phys(*crstep, gfn), skey, oldkey,
- nq, mr, mc);
-
- old = pgste_get_lock(ptep);
- pgste = old;
-
- rc = 1;
- pgste.acc = skey.acc;
- pgste.fp = skey.fp;
- pgste.gc = skey.c;
- pgste.gr = skey.r;
-
- if (!ptep->h.i) {
- rc = page_cond_set_storage_key(pte_origin(*ptep), skey, &prev, nq, mr, mc);
- pgste.hc |= prev.c;
- pgste.hr |= prev.r;
- prev.c |= old.gc;
- prev.r |= old.gr;
- } else {
- prev.acc = old.acc;
- prev.fp = old.fp;
- prev.c = old.gc;
- prev.r = old.gr;
- }
- if (oldkey)
- *oldkey = prev;
-
- dat_update_ptep_sd(old, pgste, ptep);
- pgste_set_unlock(ptep, pgste);
- return rc;
-}
-
-int dat_reset_reference_bit(union asce asce, gfn_t gfn)
-{
- union pgste pgste, old;
- union crste *crstep;
- union pte *ptep;
- int rc;
-
- rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
- if (rc)
- return rc;
-
- if (!ptep) {
- union crste crste = READ_ONCE(*crstep);
-
- if (!crste.h.fc || !crste.s.fc1.pr)
- return 0;
- return page_reset_referenced(large_crste_to_phys(*crstep, gfn));
- }
- old = pgste_get_lock(ptep);
- pgste = old;
-
- if (!ptep->h.i) {
- rc = page_reset_referenced(pte_origin(*ptep));
- pgste.hr = rc >> 1;
- }
- rc |= (pgste.gr << 1) | pgste.gc;
- pgste.gr = 0;
-
- dat_update_ptep_sd(old, pgste, ptep);
- pgste_set_unlock(ptep, pgste);
- return rc;
-}
-
-static long dat_reset_skeys_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
-{
- union pgste pgste;
-
- pgste = pgste_get_lock(ptep);
- pgste.acc = 0;
- pgste.fp = 0;
- pgste.gr = 0;
- pgste.gc = 0;
- if (ptep->s.pr)
- page_set_storage_key(pte_origin(*ptep), PAGE_DEFAULT_KEY, 1);
- pgste_set_unlock(ptep, pgste);
-
- if (need_resched())
- return next;
- return 0;
-}
-
-static long dat_reset_skeys_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
-{
- phys_addr_t addr, end, origin = crste_origin_large(*crstep);
-
- if (!crstep->h.fc || !crstep->s.fc1.pr)
- return 0;
-
- addr = ((max(gfn, walk->start) - gfn) << PAGE_SHIFT) + origin;
- end = ((min(next, walk->end) - gfn) << PAGE_SHIFT) + origin;
- while (ALIGN(addr + 1, _SEGMENT_SIZE) <= end)
- addr = sske_frame(addr, PAGE_DEFAULT_KEY);
- for ( ; addr < end; addr += PAGE_SIZE)
- page_set_storage_key(addr, PAGE_DEFAULT_KEY, 1);
-
- if (need_resched())
- return next;
- return 0;
-}
-
-long dat_reset_skeys(union asce asce, gfn_t start)
-{
- const struct dat_walk_ops ops = {
- .pte_entry = dat_reset_skeys_pte,
- .pmd_entry = dat_reset_skeys_crste,
- .pud_entry = dat_reset_skeys_crste,
- };
-
- return _dat_walk_gfn_range(start, asce_end(asce), asce, &ops, DAT_WALK_IGN_HOLES, NULL);
-}
-
struct slot_priv {
unsigned long token;
struct kvm_s390_mmu_cache *mc;
@@ -997,329 +777,3 @@ bool dat_test_age_gfn(union asce asce, gfn_t start, gfn_t end)
{
return _dat_walk_gfn_range(start, end, asce, &test_age_ops, 0, NULL) > 0;
}
-
-static long dat_set_pn_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
-{
- union crste newcrste, oldcrste;
- int *n = walk->priv;
-
- do {
- oldcrste = READ_ONCE(*crstep);
- if (!oldcrste.h.fc || oldcrste.h.i || oldcrste.h.p)
- return 0;
- if (oldcrste.s.fc1.prefix_notif)
- break;
- newcrste = oldcrste;
- newcrste.s.fc1.prefix_notif = 1;
- } while (!dat_crstep_xchg_atomic(crstep, oldcrste, newcrste, gfn, walk->asce));
- *n = 2;
- return 0;
-}
-
-static long dat_set_pn_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
-{
- int *n = walk->priv;
- union pgste pgste;
-
- pgste = pgste_get_lock(ptep);
- if (!ptep->h.i && !ptep->h.p) {
- pgste.prefix_notif = 1;
- *n += 1;
- }
- pgste_set_unlock(ptep, pgste);
- return 0;
-}
-
-int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn)
-{
- static const struct dat_walk_ops ops = {
- .pte_entry = dat_set_pn_pte,
- .pmd_entry = dat_set_pn_crste,
- .pud_entry = dat_set_pn_crste,
- };
-
- int n = 0;
-
- _dat_walk_gfn_range(gfn, gfn + 2, asce, &ops, DAT_WALK_IGN_HOLES, &n);
- if (n != 2)
- return -EAGAIN;
- return 0;
-}
-
-/**
- * dat_perform_essa() - Perform ESSA actions on the PGSTE.
- * @asce: The asce to operate on.
- * @gfn: The guest page frame to operate on.
- * @orc: The specific action to perform, see the ESSA_SET_* macros.
- * @state: The storage attributes to be returned to the guest.
- * @dirty: Returns whether the function dirtied a previously clean entry.
- *
- * Context: Called with kvm->mmu_lock held.
- *
- * Return:
- * * %1 if the page state has been altered and the page is to be added to the CBRL
- * * %0 if the page state has been altered, but the page is not to be added to the CBRL
- * * %-1 if the page state has not been altered and the page is not to be added to the CBRL
- */
-int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state *state, bool *dirty)
-{
- union crste *crstep;
- union pgste pgste;
- union pte *ptep;
- int res = 0;
-
- if (dat_entry_walk(NULL, gfn, asce, 0, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep)) {
- *state = (union essa_state) { .exception = 1 };
- return -1;
- }
-
- pgste = pgste_get_lock(ptep);
-
- *state = (union essa_state) {
- .content = (ptep->h.i << 1) + (ptep->h.i && pgste.zero),
- .nodat = pgste.nodat,
- .usage = pgste.usage,
- };
-
- switch (orc) {
- case ESSA_GET_STATE:
- res = -1;
- break;
- case ESSA_SET_STABLE:
- pgste.usage = PGSTE_GPS_USAGE_STABLE;
- pgste.nodat = 0;
- break;
- case ESSA_SET_UNUSED:
- pgste.usage = PGSTE_GPS_USAGE_UNUSED;
- if (ptep->h.i)
- res = 1;
- break;
- case ESSA_SET_VOLATILE:
- pgste.usage = PGSTE_GPS_USAGE_VOLATILE;
- if (ptep->h.i)
- res = 1;
- break;
- case ESSA_SET_POT_VOLATILE:
- if (!ptep->h.i) {
- pgste.usage = PGSTE_GPS_USAGE_POT_VOLATILE;
- } else if (pgste.zero) {
- pgste.usage = PGSTE_GPS_USAGE_VOLATILE;
- } else if (!pgste.gc) {
- pgste.usage = PGSTE_GPS_USAGE_VOLATILE;
- res = 1;
- }
- break;
- case ESSA_SET_STABLE_RESIDENT:
- pgste.usage = PGSTE_GPS_USAGE_STABLE;
- /*
- * Since the resident state can go away any time after this
- * call, we will not make this page resident. We can revisit
- * this decision if a guest will ever start using this.
- */
- break;
- case ESSA_SET_STABLE_IF_RESIDENT:
- if (!ptep->h.i)
- pgste.usage = PGSTE_GPS_USAGE_STABLE;
- break;
- case ESSA_SET_STABLE_NODAT:
- pgste.usage = PGSTE_GPS_USAGE_STABLE;
- pgste.nodat = 1;
- break;
- default:
- WARN_ONCE(1, "Invalid ORC!");
- res = -1;
- break;
- }
- /* If we are discarding a page, set it to logical zero. */
- pgste.zero = res == 1;
- if (orc > 0) {
- *dirty = !pgste.cmma_d;
- pgste.cmma_d = 1;
- }
-
- pgste_set_unlock(ptep, pgste);
-
- return res;
-}
-
-static long dat_reset_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
-{
- union pgste pgste;
-
- pgste = pgste_get_lock(ptep);
- pgste.usage = 0;
- pgste.nodat = 0;
- pgste.cmma_d = 0;
- pgste_set_unlock(ptep, pgste);
- if (need_resched())
- return next;
- return 0;
-}
-
-long dat_reset_cmma(union asce asce, gfn_t start)
-{
- const struct dat_walk_ops dat_reset_cmma_ops = {
- .pte_entry = dat_reset_cmma_pte,
- };
-
- return _dat_walk_gfn_range(start, asce_end(asce), asce, &dat_reset_cmma_ops,
- DAT_WALK_IGN_HOLES, NULL);
-}
-
-struct dat_get_cmma_state {
- gfn_t start;
- gfn_t end;
- unsigned int count;
- u8 *values;
- atomic64_t *remaining;
-};
-
-static long __dat_peek_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
-{
- struct dat_get_cmma_state *state = walk->priv;
- union pgste pgste;
-
- pgste = pgste_get_lock(ptep);
- state->values[gfn - walk->start] = pgste.usage | (pgste.nodat << 6);
- pgste_set_unlock(ptep, pgste);
- state->end = next;
-
- return 0;
-}
-
-static long __dat_peek_cmma_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
-{
- struct dat_get_cmma_state *state = walk->priv;
-
- if (crstep->h.i)
- state->end = min(walk->end, next);
- return 0;
-}
-
-int dat_peek_cmma(gfn_t start, union asce asce, unsigned int *count, u8 *values)
-{
- const struct dat_walk_ops ops = {
- .pte_entry = __dat_peek_cmma_pte,
- .pmd_entry = __dat_peek_cmma_crste,
- .pud_entry = __dat_peek_cmma_crste,
- .p4d_entry = __dat_peek_cmma_crste,
- .pgd_entry = __dat_peek_cmma_crste,
- };
- struct dat_get_cmma_state state = { .values = values, };
- int rc;
-
- rc = _dat_walk_gfn_range(start, start + *count, asce, &ops, DAT_WALK_DEFAULT, &state);
- *count = state.end >= start ? state.end - start : 0;
- /* Return success if at least one value was saved, otherwise an error. */
- return (rc == -EFAULT && *count > 0) ? 0 : rc;
-}
-
-static long __dat_get_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
-{
- struct dat_get_cmma_state *state = walk->priv;
- union pgste pgste;
-
- if (state->start != -1) {
- if ((gfn - state->end) > KVM_S390_MAX_BIT_DISTANCE)
- return 1;
- if (gfn - state->start >= state->count)
- return 1;
- }
-
- if (!READ_ONCE(*pgste_of(ptep)).cmma_d)
- return 0;
-
- pgste = pgste_get_lock(ptep);
- if (pgste.cmma_d) {
- if (state->start == -1)
- state->start = gfn;
- pgste.cmma_d = 0;
- atomic64_dec(state->remaining);
- state->values[gfn - state->start] = pgste.usage | pgste.nodat << 6;
- state->end = next;
- }
- pgste_set_unlock(ptep, pgste);
- return 0;
-}
-
-int dat_get_cmma(union asce asce, gfn_t *start, unsigned int *count, u8 *values, atomic64_t *rem)
-{
- const struct dat_walk_ops ops = { .pte_entry = __dat_get_cmma_pte, };
- struct dat_get_cmma_state state = {
- .remaining = rem,
- .values = values,
- .count = *count,
- .start = -1,
- };
-
- _dat_walk_gfn_range(*start, asce_end(asce), asce, &ops, DAT_WALK_IGN_HOLES, &state);
- /* If no dirty pages were found, wrap around and continue searching */
- if (*start && state.start == -1)
- _dat_walk_gfn_range(0, *start, asce, &ops, DAT_WALK_IGN_HOLES, &state);
-
- if (state.start == -1) {
- *count = 0;
- } else {
- *count = state.end - state.start;
- *start = state.start;
- }
-
- return 0;
-}
-
-struct dat_set_cmma_state {
- unsigned long mask;
- const u8 *bits;
-};
-
-static long __dat_set_cmma_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
-{
- struct dat_set_cmma_state *state = walk->priv;
- union pgste pgste, tmp;
-
- tmp.val = (state->bits[gfn - walk->start] << 24) & state->mask;
-
- pgste = pgste_get_lock(ptep);
- pgste.usage = tmp.usage;
- pgste.nodat = tmp.nodat;
- pgste_set_unlock(ptep, pgste);
-
- return 0;
-}
-
-/**
- * dat_set_cmma_bits() - Set CMMA bits for a range of guest pages.
- * @mc: Cache used for allocations.
- * @asce: The ASCE of the guest.
- * @gfn: The guest frame of the fist page whose CMMA bits are to set.
- * @count: How many pages need to be processed.
- * @mask: Which PGSTE bits should be set.
- * @bits: Points to an array with the CMMA attributes.
- *
- * This function sets the CMMA attributes for the given pages. If the input
- * buffer has zero length, no action is taken, otherwise the attributes are
- * set and the mm->context.uses_cmm flag is set.
- *
- * Each byte in @bits contains new values for bits 32-39 of the PGSTE.
- * Currently, only the fields NT and US are applied.
- *
- * Return: %0 in case of success, a negative error value otherwise.
- */
-int dat_set_cmma_bits(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,
- unsigned long count, unsigned long mask, const uint8_t *bits)
-{
- const struct dat_walk_ops ops = { .pte_entry = __dat_set_cmma_pte, };
- struct dat_set_cmma_state state = { .mask = mask, .bits = bits, };
- union crste *crstep;
- union pte *ptep;
- gfn_t cur;
- int rc;
-
- for (cur = ALIGN_DOWN(gfn, _PAGE_ENTRIES); cur < gfn + count; cur += _PAGE_ENTRIES) {
- rc = dat_entry_walk(mc, cur, asce, DAT_WALK_ALLOC, TABLE_TYPE_PAGE_TABLE,
- &crstep, &ptep);
- if (rc)
- return rc;
- }
- return _dat_walk_gfn_range(gfn, gfn + count, asce, &ops, DAT_WALK_IGN_HOLES, &state);
-}
diff --git a/arch/s390/kvm/dat.h b/arch/s390/kvm/gmap/dat.h
similarity index 96%
rename from arch/s390/kvm/dat.h
rename to arch/s390/kvm/gmap/dat.h
index fad605305e05c3..12153a74815f22 100644
--- a/arch/s390/kvm/dat.h
+++ b/arch/s390/kvm/gmap/dat.h
@@ -6,8 +6,8 @@
* Author(s): Claudio Imbrenda <imbrenda@linux.ibm.com>
*/
-#ifndef __KVM_S390_DAT_H
-#define __KVM_S390_DAT_H
+#ifndef ARCH_KVM_GMAP_DAT_H
+#define ARCH_KVM_GMAP_DAT_H
#include <linux/radix-tree.h>
#include <linux/refcount.h>
@@ -532,13 +532,6 @@ int dat_entry_walk(struct kvm_s390_mmu_cache *mc, gfn_t gfn, union asce asce, in
void dat_free_level(struct crst_table *table, bool owns_ptes);
struct crst_table *dat_alloc_crst_sleepable(unsigned long init);
int dat_set_asce_limit(struct kvm_s390_mmu_cache *mc, union asce *asce, int newtype);
-int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey);
-int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,
- union skey skey, bool nq);
-int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gfn_t gfn,
- union skey skey, union skey *oldkey, bool nq, bool mr, bool mc);
-int dat_reset_reference_bit(union asce asce, gfn_t gfn);
-long dat_reset_skeys(union asce asce, gfn_t start);
unsigned long dat_get_ptval(struct page_table *table, struct ptval_param param);
void dat_set_ptval(struct page_table *table, struct ptval_param param, unsigned long val);
@@ -548,13 +541,6 @@ int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gf
int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn);
bool dat_test_age_gfn(union asce asce, gfn_t start, gfn_t end);
-int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state *state, bool *dirty);
-long dat_reset_cmma(union asce asce, gfn_t start_gfn);
-int dat_peek_cmma(gfn_t start, union asce asce, unsigned int *count, u8 *values);
-int dat_get_cmma(union asce asce, gfn_t *start, unsigned int *count, u8 *values, atomic64_t *rem);
-int dat_set_cmma_bits(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,
- unsigned long count, unsigned long mask, const uint8_t *bits);
-
int kvm_s390_mmu_cache_topup(struct kvm_s390_mmu_cache *mc);
#define GFP_KVM_S390_MMU_CACHE (GFP_ATOMIC | __GFP_ACCOUNT | __GFP_NOWARN)
@@ -975,4 +961,4 @@ static inline bool crste_is_ucas(union crste crste)
return is_pmd(crste) && crste.h.i && crste.h.fc0.tl == 1 && crste.h.fc == 0;
}
-#endif /* __KVM_S390_DAT_H */
+#endif /* ARCH_KVM_GMAP_DAT_H */
diff --git a/arch/s390/kvm/faultin.c b/arch/s390/kvm/gmap/faultin.c
similarity index 96%
rename from arch/s390/kvm/faultin.c
rename to arch/s390/kvm/gmap/faultin.c
index fee80047bd94ff..b417ba575e6e35 100644
--- a/arch/s390/kvm/faultin.c
+++ b/arch/s390/kvm/gmap/faultin.c
@@ -9,10 +9,15 @@
#include <linux/kvm_host.h>
#include "gmap.h"
-#include "trace.h"
#include "faultin.h"
-
-bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu);
+#ifdef KVM_S390_ARM64
+#include "arm.h"
+#else
+#include "s390.h"
+#endif
+
+#define CREATE_TRACE_POINTS
+#include "trace-gmap.h"
/*
* kvm_s390_faultin_gfn() - handle a dat fault.
diff --git a/arch/s390/kvm/faultin.h b/arch/s390/kvm/gmap/faultin.h
similarity index 96%
rename from arch/s390/kvm/faultin.h
rename to arch/s390/kvm/gmap/faultin.h
index f86176d2769c5f..f343b6fb6f16aa 100644
--- a/arch/s390/kvm/faultin.h
+++ b/arch/s390/kvm/gmap/faultin.h
@@ -6,8 +6,8 @@
* Author(s): Claudio Imbrenda <imbrenda@linux.ibm.com>
*/
-#ifndef __KVM_S390_FAULTIN_H
-#define __KVM_S390_FAULTIN_H
+#ifndef ARCH_KVM_GMAP_FAULTIN_H
+#define ARCH_KVM_GMAP_FAULTIN_H
#include <linux/kvm_host.h>
@@ -89,4 +89,4 @@ static inline int kvm_s390_get_guest_pages(struct kvm *kvm, struct guest_fault *
#define kvm_s390_array_needs_retry_safe(kvm, seq, array) \
kvm_s390_multiple_faults_need_retry(kvm, seq, array, ARRAY_SIZE(array), false)
-#endif /* __KVM_S390_FAULTIN_H */
+#endif /* ARCH_KVM_GMAP_FAULTIN_H */
diff --git a/arch/s390/kvm/gmap.c b/arch/s390/kvm/gmap/gmap.c
similarity index 93%
rename from arch/s390/kvm/gmap.c
rename to arch/s390/kvm/gmap/gmap.c
index 298fbaecec28d5..b2ba6ee85fefab 100644
--- a/arch/s390/kvm/gmap.c
+++ b/arch/s390/kvm/gmap/gmap.c
@@ -20,15 +20,17 @@
#include <asm/gmap_helpers.h>
#include "dat.h"
+#include "sk.h"
+#include "cmma.h"
+
#include "gmap.h"
-#include "kvm-s390.h"
+#ifdef KVM_S390_ARM64
+#include "arm.h"
+#else
+#include "s390.h"
+#endif
#include "faultin.h"
-static inline bool kvm_s390_is_in_sie(struct kvm_vcpu *vcpu)
-{
- return vcpu->arch.sie_block->prog0c & PROG_IN_SIE;
-}
-
static int gmap_limit_to_type(gfn_t limit)
{
if (!limit)
@@ -256,29 +258,6 @@ int s390_replace_asce(struct gmap *gmap)
return 0;
}
-bool _gmap_unmap_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end, bool hint)
-{
- struct kvm *kvm = gmap->kvm;
- struct kvm_vcpu *vcpu;
- gfn_t prefix_gfn;
- unsigned long i;
-
- if (is_shadow(gmap))
- return false;
- kvm_for_each_vcpu(i, vcpu, kvm) {
- /* Match against both prefix pages */
- prefix_gfn = gpa_to_gfn(kvm_s390_get_prefix(vcpu));
- if (prefix_gfn < end && gfn <= prefix_gfn + 1) {
- if (hint && kvm_s390_is_in_sie(vcpu))
- return false;
- VCPU_EVENT(vcpu, 2, "gmap notifier for %llx-%llx",
- gfn_to_gpa(gfn), gfn_to_gpa(end));
- kvm_s390_sync_request(KVM_REQ_REFRESH_GUEST_PREFIX, vcpu);
- }
- }
- return true;
-}
-
struct clear_young_pte_priv {
struct gmap *gmap;
bool young;
@@ -945,39 +924,6 @@ void gmap_split_huge_pages(struct gmap *gmap)
} while (start);
}
-static int _gmap_enable_skeys(struct gmap *gmap)
-{
- gfn_t start = 0;
- int rc;
-
- if (uses_skeys(gmap))
- return 0;
-
- set_bit(GMAP_FLAG_USES_SKEYS, &gmap->flags);
- rc = gmap_helper_disable_cow_sharing();
- if (rc) {
- clear_bit(GMAP_FLAG_USES_SKEYS, &gmap->flags);
- return rc;
- }
-
- do {
- scoped_guard(write_lock, &gmap->kvm->mmu_lock)
- start = dat_reset_skeys(gmap->asce, start);
- cond_resched();
- } while (start);
- return 0;
-}
-
-int gmap_enable_skeys(struct gmap *gmap)
-{
- int rc;
-
- mmap_write_lock(gmap->kvm->mm);
- rc = _gmap_enable_skeys(gmap);
- mmap_write_unlock(gmap->kvm->mm);
- return rc;
-}
-
static long _destroy_pages_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
{
if (!ptep->s.pr)
@@ -1098,50 +1044,6 @@ int gmap_protect_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gf
return 0;
}
-static long __set_cmma_clean_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
-{
- union pgste pgste;
-
- pgste = pgste_get_lock(ptep);
- pgste.cmma_d = 0;
- pgste_set_unlock(ptep, pgste);
-
- if (need_resched())
- return next;
- return 0;
-}
-
-static long __set_cmma_dirty_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
-{
- union pgste pgste;
-
- pgste = pgste_get_lock(ptep);
- if (!pgste.cmma_d)
- atomic64_inc(walk->priv);
- pgste.cmma_d = 1;
- pgste_set_unlock(ptep, pgste);
-
- if (need_resched())
- return next;
- return 0;
-}
-
-void _gmap_set_cmma_all(struct gmap *gmap, bool dirty)
-{
- const struct dat_walk_ops ops = {
- .pte_entry = dirty ? __set_cmma_dirty_pte : __set_cmma_clean_pte,
- };
- gfn_t gfn = 0;
-
- do {
- scoped_guard(read_lock, &gmap->kvm->mmu_lock)
- gfn = _dat_walk_gfn_range(gfn, asce_end(gmap->asce), gmap->asce, &ops,
- DAT_WALK_IGN_HOLES,
- &gmap->kvm->arch.cmma_dirty_pages);
- cond_resched();
- } while (gfn);
-}
-
static void gmap_unshadow_level(struct gmap *sg, gfn_t r_gfn, int level)
{
unsigned long align = PAGE_SIZE;
diff --git a/arch/s390/kvm/gmap.h b/arch/s390/kvm/gmap/gmap.h
similarity index 94%
rename from arch/s390/kvm/gmap.h
rename to arch/s390/kvm/gmap/gmap.h
index 39938d363ec9bb..0500c8c6c9cac4 100644
--- a/arch/s390/kvm/gmap.h
+++ b/arch/s390/kvm/gmap/gmap.h
@@ -7,10 +7,13 @@
* Claudio Imbrenda <imbrenda@linux.ibm.com>
*/
-#ifndef ARCH_KVM_S390_GMAP_H
-#define ARCH_KVM_S390_GMAP_H
+#ifndef ARCH_KVM_GMAP_GMAP_H
+#define ARCH_KVM_GMAP_GMAP_H
+
+#include <linux/kvm_host.h>
#include "dat.h"
+#include "prefix.h"
/**
* enum gmap_flags - Flags of a gmap.
@@ -98,13 +101,11 @@ int gmap_set_limit(struct gmap *gmap, gfn_t limit);
int gmap_ucas_translate(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, gpa_t *gaddr);
int gmap_ucas_map(struct gmap *gmap, gfn_t p_gfn, gfn_t c_gfn, unsigned long count);
void gmap_ucas_unmap(struct gmap *gmap, gfn_t c_gfn, unsigned long count);
-int gmap_enable_skeys(struct gmap *gmap);
int gmap_pv_destroy_range(struct gmap *gmap, gfn_t start, gfn_t end, bool interruptible);
int gmap_insert_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gfn,
gfn_t r_gfn, int level);
int gmap_protect_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gfn, gfn_t r_gfn,
kvm_pfn_t pfn, int level, bool wr);
-void _gmap_set_cmma_all(struct gmap *gmap, bool dirty);
void _gmap_handle_vsie_unshadow_event(struct gmap *parent, gfn_t gfn);
struct gmap *gmap_create_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *gmap,
union asce asce, int edat_level);
@@ -158,16 +159,6 @@ static inline void gmap_handle_vsie_unshadow_event(struct gmap *parent, gfn_t gf
_gmap_handle_vsie_unshadow_event(parent, gfn);
}
-static inline bool gmap_mkold_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end)
-{
- return _gmap_unmap_prefix(gmap, gfn, end, true);
-}
-
-static inline bool gmap_unmap_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end)
-{
- return _gmap_unmap_prefix(gmap, gfn, end, false);
-}
-
/**
* pte_needs_unshadow() -- Check if the pte operations triggers unshadowing.
* @oldpte: the previous value for the guest pte.
@@ -198,16 +189,6 @@ static inline bool pte_needs_unshadow(union pte oldpte, union pte newpte, union
return !newpte.h.p || !newpte.s.pr;
}
-static inline void gmap_set_cmma_all_dirty(struct gmap *gmap)
-{
- _gmap_set_cmma_all(gmap, true);
-}
-
-static inline void gmap_set_cmma_all_clean(struct gmap *gmap)
-{
- _gmap_set_cmma_all(gmap, false);
-}
-
static inline union pgste _gmap_ptep_xchg(struct gmap *gmap, union pte *ptep, union pte newpte,
union pgste pgste, gfn_t gfn, bool needs_lock)
{
@@ -330,4 +311,17 @@ static inline bool gmap_is_shadow_valid(struct gmap *sg, union asce asce, int ed
return sg->guest_asce.val == asce.val && sg->edat_level == edat_level;
}
-#endif /* ARCH_KVM_S390_GMAP_H */
+int gmap_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log);
+int gmap_prepare_memory_region(struct kvm *kvm,
+ const struct kvm_memory_slot *old,
+ struct kvm_memory_slot *new,
+ enum kvm_mr_change change);
+void gmap_commit_memory_region(struct kvm *kvm,
+ struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new,
+ enum kvm_mr_change change);
+bool gmap_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range);
+long gmap_pre_fault_memory(struct kvm_vcpu *vcpu,
+ struct kvm_pre_fault_memory *range);
+
+#endif /* ARCH_KVM_GMAP_GMAP_H */
diff --git a/arch/s390/kvm/gmap/mmu.c b/arch/s390/kvm/gmap/mmu.c
new file mode 100644
index 00000000000000..5bb6609b974b29
--- /dev/null
+++ b/arch/s390/kvm/gmap/mmu.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kvm_types.h>
+#include <linux/kvm_host.h>
+
+#ifdef KVM_S390_ARM64
+#include "arm.h"
+#else
+#include "s390.h"
+#endif
+#include "gmap.h"
+#include "dat.h"
+#include "faultin.h"
+
+/*
+ * Get (and clear) the dirty memory log for a memory slot.
+ */
+int gmap_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
+{
+ int r;
+ unsigned long n;
+ struct kvm_memory_slot *memslot;
+ int is_dirty;
+
+ if (kvm_is_ucontrol(kvm))
+ return -EINVAL;
+
+ mutex_lock(&kvm->slots_lock);
+
+ r = -EINVAL;
+ if (log->slot >= KVM_USER_MEM_SLOTS)
+ goto out;
+
+ r = kvm_get_dirty_log(kvm, log, &is_dirty, &memslot);
+ if (r)
+ goto out;
+
+ /* Clear the dirty log */
+ if (is_dirty) {
+ n = kvm_dirty_bitmap_bytes(memslot);
+ memset(memslot->dirty_bitmap, 0, n);
+ }
+ r = 0;
+out:
+ mutex_unlock(&kvm->slots_lock);
+ return r;
+}
+
+int gmap_prepare_memory_region(struct kvm *kvm,
+ const struct kvm_memory_slot *old,
+ struct kvm_memory_slot *new,
+ enum kvm_mr_change change)
+{
+ if (kvm_is_ucontrol(kvm) && new && new->id < KVM_USER_MEM_SLOTS)
+ return -EINVAL;
+
+ /* When we are protected, we should not change the memory slots */
+ if (kvm_s390_pv_get_handle(kvm))
+ return -EINVAL;
+
+ if (change != KVM_MR_DELETE && change != KVM_MR_FLAGS_ONLY) {
+ /*
+ * A few sanity checks. The memory in userland is ok to be
+ * fragmented into various different vmas. It is okay to mmap()
+ * and munmap() stuff in this slot after doing this call at any
+ * time.
+ */
+ if (new->userspace_addr & ~PAGE_MASK)
+ return -EINVAL;
+ if ((new->base_gfn + new->npages) * PAGE_SIZE > kvm->arch.mem_limit)
+ return -EINVAL;
+ if (!asce_contains_gfn(kvm->arch.gmap->asce, new->base_gfn + new->npages - 1))
+ return -EINVAL;
+ }
+
+ if (!kvm_s390_is_migration_mode(kvm))
+ return 0;
+
+ /*
+ * Turn off migration mode when:
+ * - userspace creates a new memslot with dirty logging off,
+ * - userspace modifies an existing memslot (MOVE or FLAGS_ONLY) and
+ * dirty logging is turned off.
+ * Migration mode expects dirty page logging being enabled to store
+ * its dirty bitmap.
+ */
+ if (change != KVM_MR_DELETE &&
+ !(new->flags & KVM_MEM_LOG_DIRTY_PAGES))
+ WARN(kvm_s390_vm_stop_migration(kvm),
+ "Failed to stop migration mode");
+
+ return 0;
+}
+
+void gmap_commit_memory_region(struct kvm *kvm,
+ struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new,
+ enum kvm_mr_change change)
+{
+ struct kvm_s390_mmu_cache *mc = NULL;
+ int rc = 0;
+
+ if (change == KVM_MR_FLAGS_ONLY)
+ return;
+
+ mc = kvm_s390_new_mmu_cache();
+ if (!mc) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ scoped_guard(write_lock, &kvm->mmu_lock) {
+ switch (change) {
+ case KVM_MR_DELETE:
+ rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
+ break;
+ case KVM_MR_MOVE:
+ rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
+ if (rc)
+ break;
+ fallthrough;
+ case KVM_MR_CREATE:
+ rc = dat_create_slot(mc, kvm->arch.gmap->asce, new->base_gfn, new->npages);
+ break;
+ case KVM_MR_FLAGS_ONLY:
+ break;
+ default:
+ WARN(1, "Unknown KVM MR CHANGE: %d\n", change);
+ }
+ }
+out:
+ if (rc)
+ pr_warn("failed to commit memory region\n");
+ kvm_s390_free_mmu_cache(mc);
+}
+
+/**
+ * gmap_test_age_gfn() - test young
+ * @kvm: the kvm instance
+ * @range: the range of guest addresses whose young status needs to be cleared
+ *
+ * Context: called by KVM common code without holding the kvm mmu lock
+ * Return: true if any page in the given range is young, otherwise 0.
+ */
+bool gmap_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
+{
+ scoped_guard(read_lock, &kvm->mmu_lock)
+ return dat_test_age_gfn(kvm->arch.gmap->asce, range->start, range->end);
+}
+
+/**
+ * gmap_pre_fault_memory() - pre-fault and link gmap dat tables
+ * @vcpu: the vcpu that shall appear to have generated the fault-in.
+ * @range: the range that needs to be faulted in.
+ *
+ * The first page of the given range is faulted in and the corresponding gmap
+ * page tables are created, as if the given vCPU had performed a read
+ * operation.
+ * If the range starts outside any memslots, an error is returned. An error is
+ * also returned for UCONTROL VMs, which should instead use the
+ * KVM_S390_VCPU_FAULT ioctl.
+ *
+ * Return:
+ * * %-ENOENT if the range lies outside of a memslot.
+ * * %-EINVAL in case of invalid state (for example if the VM is UCONTROL).
+ * * %-EIO if errors happen while faulting-in the page (will trigger a warning
+ * in the caller).
+ * * other error codes < 0 in case of other errors.
+ * * otherwise a number > 0 of bytes that have been faulted in successfully.
+ */
+long gmap_pre_fault_memory(struct kvm_vcpu *vcpu, struct kvm_pre_fault_memory *range)
+{
+ struct guest_fault f = { .gfn = gpa_to_gfn(range->gpa), };
+ gpa_t end;
+ int rc;
+
+ if (kvm_is_ucontrol(vcpu->kvm))
+ return -EINVAL;
+
+ rc = kvm_s390_faultin_gfn(vcpu, NULL, &f);
+ if (rc == PGM_ADDRESSING)
+ return -ENOENT;
+ if (rc > 0)
+ return -EIO;
+ if (rc < 0)
+ return rc;
+
+ if (f.ptep)
+ return PAGE_SIZE;
+
+ end = ALIGN(range->gpa + PAGE_SIZE, f.crste_region3 ? _REGION3_SIZE : HPAGE_SIZE);
+ return min(range->size, end - range->gpa);
+}
diff --git a/arch/s390/kvm/gmap/prefix-stubs.c b/arch/s390/kvm/gmap/prefix-stubs.c
new file mode 100644
index 00000000000000..d1d6286f454a74
--- /dev/null
+++ b/arch/s390/kvm/gmap/prefix-stubs.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * These stubs are used when building gmap for non-s390 guests
+ * that don't need prefix page tracking.
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/kvm_types.h>
+
+#include "dat.h"
+#include "prefix.h"
+
+bool _gmap_unmap_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end, bool hint)
+{
+ return true;
+}
+
+int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn)
+{
+ return 0;
+}
diff --git a/arch/s390/kvm/gmap/prefix.c b/arch/s390/kvm/gmap/prefix.c
new file mode 100644
index 00000000000000..44caffed2da132
--- /dev/null
+++ b/arch/s390/kvm/gmap/prefix.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kvm_host.h>
+#include <linux/kvm_types.h>
+
+#include "gmap.h"
+#include "dat.h"
+#include "prefix.h"
+#include "../s390/s390.h"
+
+bool _gmap_unmap_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end, bool hint)
+{
+ struct kvm *kvm = gmap->kvm;
+ struct kvm_vcpu *vcpu;
+ gfn_t prefix_gfn;
+ unsigned long i;
+
+ if (is_shadow(gmap))
+ return false;
+ kvm_for_each_vcpu(i, vcpu, kvm) {
+ /* Match against both prefix pages */
+ prefix_gfn = gpa_to_gfn(kvm_s390_get_prefix(vcpu));
+ if (prefix_gfn < end && gfn <= prefix_gfn + 1) {
+ if (hint && kvm_s390_is_in_sie(vcpu))
+ return false;
+ VCPU_EVENT(vcpu, 2, "gmap notifier for %llx-%llx",
+ gfn_to_gpa(gfn), gfn_to_gpa(end));
+ kvm_s390_sync_request(KVM_REQ_REFRESH_GUEST_PREFIX, vcpu);
+ }
+ }
+ return true;
+}
+
+static long dat_set_pn_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
+{
+ union crste newcrste, oldcrste;
+ int *n = walk->priv;
+
+ do {
+ oldcrste = READ_ONCE(*crstep);
+ if (!oldcrste.h.fc || oldcrste.h.i || oldcrste.h.p)
+ return 0;
+ if (oldcrste.s.fc1.prefix_notif)
+ break;
+ newcrste = oldcrste;
+ newcrste.s.fc1.prefix_notif = 1;
+ } while (!dat_crstep_xchg_atomic(crstep, oldcrste, newcrste, gfn, walk->asce));
+ *n = 2;
+ return 0;
+}
+
+static long dat_set_pn_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
+{
+ int *n = walk->priv;
+ union pgste pgste;
+
+ pgste = pgste_get_lock(ptep);
+ if (!ptep->h.i && !ptep->h.p) {
+ pgste.prefix_notif = 1;
+ *n += 1;
+ }
+ pgste_set_unlock(ptep, pgste);
+ return 0;
+}
+
+int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn)
+{
+ static const struct dat_walk_ops ops = {
+ .pte_entry = dat_set_pn_pte,
+ .pmd_entry = dat_set_pn_crste,
+ .pud_entry = dat_set_pn_crste,
+ };
+
+ int n = 0;
+
+ _dat_walk_gfn_range(gfn, gfn + 2, asce, &ops, DAT_WALK_IGN_HOLES, &n);
+ if (n != 2)
+ return -EAGAIN;
+ return 0;
+}
diff --git a/arch/s390/kvm/gmap/prefix.h b/arch/s390/kvm/gmap/prefix.h
new file mode 100644
index 00000000000000..f1f3ace24f0321
--- /dev/null
+++ b/arch/s390/kvm/gmap/prefix.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef ARCH_KVM_GMAP_PREFIX_H
+#define ARCH_KVM_GMAP_PREFIX_H
+
+#include <linux/types.h>
+#include <linux/kvm_types.h>
+
+struct gmap;
+union asce;
+
+/**
+ * _gmap_unmap_prefix() - Notify vCPUs if prefix pages are affected
+ * @gmap: The gmap
+ * @gfn: Start of the range
+ * @end: End of the range (exclusive)
+ * @hint: If true, skip notification if vCPU is in SIE
+ *
+ * Check if any vCPU's prefix pages fall within the given range and
+ * request prefix refresh if needed.
+ *
+ * Return: false if notification was skipped due to hint, true otherwise
+ */
+bool _gmap_unmap_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end, bool hint);
+
+/**
+ * dat_set_prefix_notif_bit() - Set prefix notification bits
+ * @asce: The address space control element
+ * @gfn: Guest frame number of the prefix area
+ *
+ * Set the prefix notification bit in the page table entries for the
+ * two prefix pages starting at @gfn.
+ *
+ * Return: 0 on success, -EAGAIN if not all bits could be set
+ */
+int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn);
+
+/**
+ * gmap_mkold_prefix() - Mark prefix pages as old
+ * @gmap: The gmap
+ * @gfn: Start of the range
+ * @end: End of the range (exclusive)
+ *
+ * Inline wrapper that calls _gmap_unmap_prefix with hint=true.
+ *
+ * Return: Result from _gmap_unmap_prefix
+ */
+static inline bool gmap_mkold_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end)
+{
+ return _gmap_unmap_prefix(gmap, gfn, end, true);
+}
+
+/**
+ * gmap_unmap_prefix() - Unconditionally notify about prefix pages
+ * @gmap: The gmap
+ * @gfn: Start of the range
+ * @end: End of the range (exclusive)
+ *
+ * Inline wrapper that calls _gmap_unmap_prefix with hint=false.
+ *
+ * Return: Result from _gmap_unmap_prefix
+ */
+static inline bool gmap_unmap_prefix(struct gmap *gmap, gfn_t gfn, gfn_t end)
+{
+ return _gmap_unmap_prefix(gmap, gfn, end, false);
+}
+
+#endif /* ARCH_KVM_GMAP_PREFIX_H */
diff --git a/arch/s390/kvm/gmap/sk.c b/arch/s390/kvm/gmap/sk.c
new file mode 100644
index 00000000000000..eedd6eef670982
--- /dev/null
+++ b/arch/s390/kvm/gmap/sk.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/mm.h>
+#include <linux/kvm_host.h>
+#include <linux/pgalloc.h>
+#include <asm/gmap_helpers.h>
+#include "sk.h"
+#include "gmap.h"
+
+static void dat_update_ptep_sd(union pgste old, union pgste pgste, union pte *ptep)
+{
+ if (pgste.acc != old.acc || pgste.fp != old.fp || pgste.gr != old.gr || pgste.gc != old.gc)
+ __atomic64_or(_PAGE_SD, &ptep->val);
+}
+
+int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey)
+{
+ union crste *crstep;
+ union pgste pgste;
+ union pte *ptep;
+ int rc;
+
+ skey->skey = 0;
+ rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
+ if (rc)
+ return rc;
+
+ if (!ptep) {
+ union crste crste;
+
+ crste = READ_ONCE(*crstep);
+ if (!crste.h.fc || !crste.s.fc1.pr)
+ return 0;
+ skey->skey = page_get_storage_key(large_crste_to_phys(crste, gfn));
+ return 0;
+ }
+ pgste = pgste_get_lock(ptep);
+ if (ptep->h.i) {
+ skey->acc = pgste.acc;
+ skey->fp = pgste.fp;
+ } else {
+ skey->skey = page_get_storage_key(pte_origin(*ptep));
+ }
+ skey->r |= pgste.gr;
+ skey->c |= pgste.gc;
+ pgste_set_unlock(ptep, pgste);
+ return 0;
+}
+
+int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,
+ union skey skey, bool nq)
+{
+ union pgste pgste, old;
+ union crste *crstep;
+ union pte *ptep;
+ int rc;
+
+ rc = dat_entry_walk(mc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,
+ &crstep, &ptep);
+ if (rc)
+ return rc;
+
+ if (!ptep) {
+ page_set_storage_key(large_crste_to_phys(*crstep, gfn), skey.skey, !nq);
+ return 0;
+ }
+
+ old = pgste_get_lock(ptep);
+ pgste = old;
+
+ pgste.acc = skey.acc;
+ pgste.fp = skey.fp;
+ pgste.gc = skey.c;
+ pgste.gr = skey.r;
+
+ if (!ptep->h.i) {
+ union skey old_skey;
+
+ old_skey.skey = page_get_storage_key(pte_origin(*ptep));
+ pgste.hc |= old_skey.c;
+ pgste.hr |= old_skey.r;
+ old_skey.c = old.gc;
+ old_skey.r = old.gr;
+ skey.r = 0;
+ skey.c = 0;
+ page_set_storage_key(pte_origin(*ptep), skey.skey, !nq);
+ }
+
+ dat_update_ptep_sd(old, pgste, ptep);
+ pgste_set_unlock(ptep, pgste);
+ return 0;
+}
+
+static bool page_cond_set_storage_key(phys_addr_t paddr, union skey skey, union skey *oldkey,
+ bool nq, bool mr, bool mc)
+{
+ oldkey->skey = page_get_storage_key(paddr);
+ if (oldkey->acc == skey.acc && oldkey->fp == skey.fp &&
+ (oldkey->r == skey.r || mr) && (oldkey->c == skey.c || mc))
+ return false;
+ page_set_storage_key(paddr, skey.skey, !nq);
+ return true;
+}
+
+int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gfn_t gfn,
+ union skey skey, union skey *oldkey, bool nq, bool mr, bool mc)
+{
+ union pgste pgste, old;
+ union crste *crstep;
+ union skey prev;
+ union pte *ptep;
+ int rc;
+
+ rc = dat_entry_walk(mmc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,
+ &crstep, &ptep);
+ if (rc)
+ return rc;
+
+ if (!ptep)
+ return page_cond_set_storage_key(large_crste_to_phys(*crstep, gfn), skey, oldkey,
+ nq, mr, mc);
+
+ old = pgste_get_lock(ptep);
+ pgste = old;
+
+ rc = 1;
+ pgste.acc = skey.acc;
+ pgste.fp = skey.fp;
+ pgste.gc = skey.c;
+ pgste.gr = skey.r;
+
+ if (!ptep->h.i) {
+ rc = page_cond_set_storage_key(pte_origin(*ptep), skey, &prev, nq, mr, mc);
+ pgste.hc |= prev.c;
+ pgste.hr |= prev.r;
+ prev.c |= old.gc;
+ prev.r |= old.gr;
+ } else {
+ prev.acc = old.acc;
+ prev.fp = old.fp;
+ prev.c = old.gc;
+ prev.r = old.gr;
+ }
+ if (oldkey)
+ *oldkey = prev;
+
+ dat_update_ptep_sd(old, pgste, ptep);
+ pgste_set_unlock(ptep, pgste);
+ return rc;
+}
+
+int dat_reset_reference_bit(union asce asce, gfn_t gfn)
+{
+ union pgste pgste, old;
+ union crste *crstep;
+ union pte *ptep;
+ int rc;
+
+ rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
+ if (rc)
+ return rc;
+
+ if (!ptep) {
+ union crste crste = READ_ONCE(*crstep);
+
+ if (!crste.h.fc || !crste.s.fc1.pr)
+ return 0;
+ return page_reset_referenced(large_crste_to_phys(*crstep, gfn));
+ }
+ old = pgste_get_lock(ptep);
+ pgste = old;
+
+ if (!ptep->h.i) {
+ rc = page_reset_referenced(pte_origin(*ptep));
+ pgste.hr = rc >> 1;
+ }
+ rc |= (pgste.gr << 1) | pgste.gc;
+ pgste.gr = 0;
+
+ dat_update_ptep_sd(old, pgste, ptep);
+ pgste_set_unlock(ptep, pgste);
+ return rc;
+}
+
+static long dat_reset_skeys_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
+{
+ union pgste pgste;
+
+ pgste = pgste_get_lock(ptep);
+ pgste.acc = 0;
+ pgste.fp = 0;
+ pgste.gr = 0;
+ pgste.gc = 0;
+ if (ptep->s.pr)
+ page_set_storage_key(pte_origin(*ptep), PAGE_DEFAULT_KEY, 1);
+ pgste_set_unlock(ptep, pgste);
+
+ if (need_resched())
+ return next;
+ return 0;
+}
+
+static long dat_reset_skeys_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
+{
+ phys_addr_t addr, end, origin = crste_origin_large(*crstep);
+
+ if (!crstep->h.fc || !crstep->s.fc1.pr)
+ return 0;
+
+ addr = ((max(gfn, walk->start) - gfn) << PAGE_SHIFT) + origin;
+ end = ((min(next, walk->end) - gfn) << PAGE_SHIFT) + origin;
+ while (ALIGN(addr + 1, _SEGMENT_SIZE) <= end)
+ addr = sske_frame(addr, PAGE_DEFAULT_KEY);
+ for ( ; addr < end; addr += PAGE_SIZE)
+ page_set_storage_key(addr, PAGE_DEFAULT_KEY, 1);
+
+ if (need_resched())
+ return next;
+ return 0;
+}
+
+long dat_reset_skeys(union asce asce, gfn_t start)
+{
+ const struct dat_walk_ops ops = {
+ .pte_entry = dat_reset_skeys_pte,
+ .pmd_entry = dat_reset_skeys_crste,
+ .pud_entry = dat_reset_skeys_crste,
+ };
+
+ return _dat_walk_gfn_range(start, asce_end(asce), asce, &ops, DAT_WALK_IGN_HOLES, NULL);
+}
+
+static int _gmap_enable_skeys(struct gmap *gmap)
+{
+ gfn_t start = 0;
+ int rc;
+
+ if (uses_skeys(gmap))
+ return 0;
+
+ set_bit(GMAP_FLAG_USES_SKEYS, &gmap->flags);
+ rc = gmap_helper_disable_cow_sharing();
+ if (rc) {
+ clear_bit(GMAP_FLAG_USES_SKEYS, &gmap->flags);
+ return rc;
+ }
+
+ do {
+ scoped_guard(write_lock, &gmap->kvm->mmu_lock)
+ start = dat_reset_skeys(gmap->asce, start);
+ cond_resched();
+ } while (start);
+ return 0;
+}
+
+int gmap_enable_skeys(struct gmap *gmap)
+{
+ int rc;
+
+ mmap_write_lock(gmap->kvm->mm);
+ rc = _gmap_enable_skeys(gmap);
+ mmap_write_unlock(gmap->kvm->mm);
+ return rc;
+}
diff --git a/arch/s390/kvm/gmap/sk.h b/arch/s390/kvm/gmap/sk.h
new file mode 100644
index 00000000000000..113ff8d0b0ab78
--- /dev/null
+++ b/arch/s390/kvm/gmap/sk.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef ARCH_KVM_GMAP_SK_H
+#define ARCH_KVM_GMAP_SK_H
+
+#include "dat.h"
+
+int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey);
+int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,
+ union skey skey, bool nq);
+int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gfn_t gfn,
+ union skey skey, union skey *oldkey, bool nq, bool mr, bool mc);
+int dat_reset_reference_bit(union asce asce, gfn_t gfn);
+long dat_reset_skeys(union asce asce, gfn_t start);
+
+int gmap_enable_skeys(struct gmap *gmap);
+
+#endif /* ARCH_KVM_GMAP_SK_H */
diff --git a/arch/s390/kvm/gmap/trace-gmap.h b/arch/s390/kvm/gmap/trace-gmap.h
new file mode 100644
index 00000000000000..25f8a527fddea2
--- /dev/null
+++ b/arch/s390/kvm/gmap/trace-gmap.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if !defined(GMAP_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define GMAP_TRACE_KVM_H
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvm
+#define TRACE_INCLUDE_PATH ../gmap
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace-gmap
+
+#ifdef KVM_S390_ARM64
+#define __KVM_FIELDS \
+ __field(unsigned long, pstate) \
+ __field(unsigned long, pc)
+#define __KVM_ASSIGN ({\
+ __entry->pstate = vcpu->arch.sae_block.pstate; \
+ __entry->pc = vcpu->arch.sae_block.pc; \
+ })
+#define __KVM_PRINT \
+ __entry->pstate, \
+ __entry->pc
+#else
+#define __KVM_FIELDS \
+ __field(unsigned long, pswmask) \
+ __field(unsigned long, pswaddr)
+#define __KVM_ASSIGN ({\
+ __entry->pswmask = vcpu->arch.sie_block->gpsw.mask; \
+ __entry->pswaddr = vcpu->arch.sie_block->gpsw.addr; \
+ })
+#define __KVM_PRINT \
+ __entry->pswmask,\
+ __entry->pswaddr
+#endif
+
+TRACE_EVENT(kvm_s390_major_guest_pfault,
+ TP_PROTO(struct kvm_vcpu *vcpu),
+ TP_ARGS(vcpu),
+
+ TP_STRUCT__entry(
+ __field(int, id)
+ __KVM_FIELDS
+ ),
+
+ TP_fast_assign(
+ __entry->id = vcpu->vcpu_id;
+ __KVM_ASSIGN
+ ),
+ TP_printk("%02d[%016lx-%016lx]: major fault, maybe applicable for pfault",
+ __entry->id,
+ __KVM_PRINT
+ )
+ );
+
+#endif /* GMAP_TRACE_KVM_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/arch/s390/kvm/s390/Kconfig b/arch/s390/kvm/s390/Kconfig
new file mode 100644
index 00000000000000..4b7a7c2945e57c
--- /dev/null
+++ b/arch/s390/kvm/s390/Kconfig
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# KVM_S390 configuration
+
+config KVM_S390
+ def_tristate y
+ prompt "Kernel-based Virtual Machine (KVM) support (s390)"
+ select KVM
+ select HAVE_KVM_CPU_RELAX_INTERCEPT
+ select KVM_ASYNC_PF
+ select KVM_ASYNC_PF_SYNC
+ select KVM_COMMON
+ select HAVE_KVM_IRQCHIP
+ select HAVE_KVM_IRQ_ROUTING
+ select HAVE_KVM_INVALID_WAKEUPS
+ select HAVE_KVM_NO_POLL
+ select KVM_VFIO
+ select VIRT_XFER_TO_GUEST_WORK
+ select KVM_MMU_LOCKLESS_AGING
+ select KVM_GENERIC_PRE_FAULT_MEMORY
+ help
+ Support hosting paravirtualized s390 guest machines using the SIE
+ virtualization capability on the mainframe. This should work
+ on any 64bit machine.
+
+ This module provides access to the hardware capabilities through
+ a character device node named /dev/kvm.
+
+ To compile this as a module, choose M here: the module
+ will be called kvm.
+
+ If unsure, say N.
+
+config KVM_S390_UCONTROL
+ bool "Userspace controlled virtual machines"
+ depends on KVM_S390
+ help
+ Allow CAP_SYS_ADMIN users to create KVM virtual machines that are
+ controlled by userspace.
+
+ If unsure, say N.
diff --git a/arch/s390/kvm/s390/Makefile b/arch/s390/kvm/s390/Makefile
new file mode 100644
index 00000000000000..51aee874b36f38
--- /dev/null
+++ b/arch/s390/kvm/s390/Makefile
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for kernel virtual machines on s390
+#
+# Copyright IBM Corp. 2008
+
+KVM := ../../../../virt/kvm
+include $(srctree)/virt/kvm/Makefile.kvm
+include $(srctree)/arch/s390/kvm/gmap/Makefile
+
+ccflags-y := -I$(src) -I$(srctree)/arch/s390/kvm/gmap
+
+kvm-y += s390.o intercept.o interrupt.o priv.o sigp.o
+kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o
+
+kvm-$(CONFIG_VFIO_PCI_ZDEV_KVM) += pci.o
+
+obj-$(CONFIG_KVM_S390) += kvm.o
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/s390/diag.c
similarity index 99%
rename from arch/s390/kvm/diag.c
rename to arch/s390/kvm/s390/diag.c
index d89d1c381522a9..700d9b7b68bc45 100644
--- a/arch/s390/kvm/diag.c
+++ b/arch/s390/kvm/s390/diag.c
@@ -12,7 +12,7 @@
#include <linux/kvm_host.h>
#include <asm/gmap_helpers.h>
#include <asm/virtio-ccw.h>
-#include "kvm-s390.h"
+#include "s390.h"
#include "trace.h"
#include "trace-s390.h"
#include "gaccess.h"
diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/s390/gaccess.c
similarity index 99%
rename from arch/s390/kvm/gaccess.c
rename to arch/s390/kvm/s390/gaccess.c
index 36102b2727fbff..2d82c931759769 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/s390/gaccess.c
@@ -17,9 +17,10 @@
#include <asm/access-regs.h>
#include <asm/fault.h>
#include <asm/dat-bits.h>
-#include "kvm-s390.h"
+#include "s390.h"
#include "dat.h"
#include "gmap.h"
+#include "sk.h"
#include "gaccess.h"
#include "faultin.h"
diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/s390/gaccess.h
similarity index 99%
rename from arch/s390/kvm/gaccess.h
rename to arch/s390/kvm/s390/gaccess.h
index b5385cec60f456..ef922b3b499031 100644
--- a/arch/s390/kvm/gaccess.h
+++ b/arch/s390/kvm/s390/gaccess.h
@@ -14,7 +14,7 @@
#include <linux/kvm_host.h>
#include <linux/uaccess.h>
#include <linux/ptrace.h>
-#include "kvm-s390.h"
+#include "s390.h"
/**
* kvm_s390_real_to_abs - convert guest real address to guest absolute address
diff --git a/arch/s390/kvm/guestdbg.c b/arch/s390/kvm/s390/guestdbg.c
similarity index 99%
rename from arch/s390/kvm/guestdbg.c
rename to arch/s390/kvm/s390/guestdbg.c
index 69835e1d4f207e..c880ebbdef2ff2 100644
--- a/arch/s390/kvm/guestdbg.c
+++ b/arch/s390/kvm/s390/guestdbg.c
@@ -8,7 +8,7 @@
*/
#include <linux/kvm_host.h>
#include <linux/errno.h>
-#include "kvm-s390.h"
+#include "s390.h"
#include "gaccess.h"
/*
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/s390/intercept.c
similarity index 99%
rename from arch/s390/kvm/intercept.c
rename to arch/s390/kvm/s390/intercept.c
index 1980df61ef304d..ca1205dfac8b07 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/s390/intercept.c
@@ -17,7 +17,7 @@
#include <asm/sysinfo.h>
#include <asm/uv.h>
-#include "kvm-s390.h"
+#include "s390.h"
#include "gaccess.h"
#include "trace.h"
#include "trace-s390.h"
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/s390/interrupt.c
similarity index 99%
rename from arch/s390/kvm/interrupt.c
rename to arch/s390/kvm/s390/interrupt.c
index 9e3e6b0d72ad61..24c41c7a4c3d97 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/s390/interrupt.c
@@ -29,7 +29,7 @@
#include <asm/nmi.h>
#include <asm/airq.h>
#include <asm/tpi.h>
-#include "kvm-s390.h"
+#include "s390.h"
#include "gaccess.h"
#include "trace-s390.h"
#include "pci.h"
diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/s390/pci.c
similarity index 99%
rename from arch/s390/kvm/pci.c
rename to arch/s390/kvm/s390/pci.c
index 5b075c38998e31..efdc1ddf6ba848 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/s390/pci.c
@@ -14,7 +14,7 @@
#include <asm/pci_io.h>
#include <asm/sclp.h>
#include "pci.h"
-#include "kvm-s390.h"
+#include "s390.h"
struct zpci_aift *aift;
diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/s390/pci.h
similarity index 100%
rename from arch/s390/kvm/pci.h
rename to arch/s390/kvm/s390/pci.h
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/s390/priv.c
similarity index 99%
rename from arch/s390/kvm/priv.c
rename to arch/s390/kvm/s390/priv.c
index ad0ddc433a73c3..9bd3c07285baeb 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/s390/priv.c
@@ -26,9 +26,11 @@
#include <asm/ap.h>
#include <asm/gmap_helpers.h>
#include "gaccess.h"
-#include "kvm-s390.h"
+#include "s390.h"
#include "trace.h"
#include "gmap.h"
+#include "sk.h"
+#include "cmma.h"
static int handle_ri(struct kvm_vcpu *vcpu)
{
diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/s390/pv.c
similarity index 99%
rename from arch/s390/kvm/pv.c
rename to arch/s390/kvm/s390/pv.c
index 1beacc841ca850..f6e03e9d371ad2 100644
--- a/arch/s390/kvm/pv.c
+++ b/arch/s390/kvm/s390/pv.c
@@ -18,7 +18,7 @@
#include <linux/sched/mm.h>
#include <linux/mmu_notifier.h>
#include <asm/gmap_helpers.h>
-#include "kvm-s390.h"
+#include "s390.h"
#include "dat.h"
#include "gaccess.h"
#include "gmap.h"
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/s390/s390.c
similarity index 98%
rename from arch/s390/kvm/kvm-s390.c
rename to arch/s390/kvm/s390/s390.c
index 23c817595e28d5..b560c1e5792692 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/s390/s390.c
@@ -50,11 +50,13 @@
#include <asm/fpu.h>
#include <asm/ap.h>
#include <asm/uv.h>
-#include "kvm-s390.h"
+#include "s390.h"
#include "gaccess.h"
#include "gmap.h"
#include "faultin.h"
#include "pci.h"
+#include "sk.h"
+#include "cmma.h"
#define CREATE_TRACE_POINTS
#include "trace.h"
@@ -746,33 +748,7 @@ static void sca_del_vcpu(struct kvm_vcpu *vcpu);
int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
struct kvm_dirty_log *log)
{
- int r;
- unsigned long n;
- struct kvm_memory_slot *memslot;
- int is_dirty;
-
- if (kvm_is_ucontrol(kvm))
- return -EINVAL;
-
- mutex_lock(&kvm->slots_lock);
-
- r = -EINVAL;
- if (log->slot >= KVM_USER_MEM_SLOTS)
- goto out;
-
- r = kvm_get_dirty_log(kvm, log, &is_dirty, &memslot);
- if (r)
- goto out;
-
- /* Clear the dirty log */
- if (is_dirty) {
- n = kvm_dirty_bitmap_bytes(memslot);
- memset(memslot->dirty_bitmap, 0, n);
- }
- r = 0;
-out:
- mutex_unlock(&kvm->slots_lock);
- return r;
+ return gmap_get_dirty_log(kvm, log);
}
static void icpt_operexc_on_all_vcpus(struct kvm *kvm)
@@ -1268,7 +1244,7 @@ static int kvm_s390_vm_start_migration(struct kvm *kvm)
* Must be called with kvm->slots_lock to avoid races with ourselves,
* kvm_s390_vm_start_migration() and kvm_s390_get_cmma_bits().
*/
-static int kvm_s390_vm_stop_migration(struct kvm *kvm)
+int kvm_s390_vm_stop_migration(struct kvm *kvm)
{
/* migration mode already disabled */
if (!kvm->arch.migration_mode)
@@ -5751,45 +5727,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *new,
enum kvm_mr_change change)
{
- if (kvm_is_ucontrol(kvm) && new && new->id < KVM_USER_MEM_SLOTS)
- return -EINVAL;
-
- /* When we are protected, we should not change the memory slots */
- if (kvm_s390_pv_get_handle(kvm))
- return -EINVAL;
-
- if (change != KVM_MR_DELETE && change != KVM_MR_FLAGS_ONLY) {
- /*
- * A few sanity checks. The memory in userland is ok to be
- * fragmented into various different vmas. It is okay to mmap()
- * and munmap() stuff in this slot after doing this call at any
- * time.
- */
- if (new->userspace_addr & ~PAGE_MASK)
- return -EINVAL;
- if ((new->base_gfn + new->npages) * PAGE_SIZE > kvm->arch.mem_limit)
- return -EINVAL;
- if (!asce_contains_gfn(kvm->arch.gmap->asce, new->base_gfn + new->npages - 1))
- return -EINVAL;
- }
-
- if (!kvm->arch.migration_mode)
- return 0;
-
- /*
- * Turn off migration mode when:
- * - userspace creates a new memslot with dirty logging off,
- * - userspace modifies an existing memslot (MOVE or FLAGS_ONLY) and
- * dirty logging is turned off.
- * Migration mode expects dirty page logging being enabled to store
- * its dirty bitmap.
- */
- if (change != KVM_MR_DELETE &&
- !(new->flags & KVM_MEM_LOG_DIRTY_PAGES))
- WARN(kvm_s390_vm_stop_migration(kvm),
- "Failed to stop migration mode");
-
- return 0;
+ return gmap_prepare_memory_region(kvm, old, new, change);
}
void kvm_arch_commit_memory_region(struct kvm *kvm,
@@ -5797,42 +5735,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
const struct kvm_memory_slot *new,
enum kvm_mr_change change)
{
- struct kvm_s390_mmu_cache *mc = NULL;
- int rc = 0;
-
- if (change == KVM_MR_FLAGS_ONLY)
- return;
-
- mc = kvm_s390_new_mmu_cache();
- if (!mc) {
- rc = -ENOMEM;
- goto out;
- }
-
- scoped_guard(write_lock, &kvm->mmu_lock) {
- switch (change) {
- case KVM_MR_DELETE:
- rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
- break;
- case KVM_MR_MOVE:
- rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
- if (rc)
- break;
- fallthrough;
- case KVM_MR_CREATE:
- rc = dat_create_slot(mc, kvm->arch.gmap->asce, new->base_gfn, new->npages);
- break;
- case KVM_MR_FLAGS_ONLY:
- break;
- default:
- WARN(1, "Unknown KVM MR CHANGE: %d\n", change);
- }
- }
-out:
- if (rc)
- pr_warn("failed to commit memory region\n");
- kvm_s390_free_mmu_cache(mc);
- return;
+ gmap_commit_memory_region(kvm, old, new, change);
}
/**
@@ -5855,28 +5758,10 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
* * other error codes < 0 in case of other errors.
* * otherwise a number > 0 of bytes that have been faulted in successfully.
*/
-long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, struct kvm_pre_fault_memory *range)
+long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,
+ struct kvm_pre_fault_memory *range)
{
- struct guest_fault f = { .gfn = gpa_to_gfn(range->gpa), };
- gpa_t end;
- int rc;
-
- if (kvm_is_ucontrol(vcpu->kvm))
- return -EINVAL;
-
- rc = kvm_s390_faultin_gfn(vcpu, NULL, &f);
- if (rc == PGM_ADDRESSING)
- return -ENOENT;
- if (rc > 0)
- return -EIO;
- if (rc < 0)
- return rc;
-
- if (f.ptep)
- return PAGE_SIZE;
-
- end = ALIGN(range->gpa + PAGE_SIZE, f.crste_region3 ? _REGION3_SIZE : HPAGE_SIZE);
- return min(range->size, end - range->gpa);
+ return gmap_pre_fault_memory(vcpu, range);
}
/**
@@ -5889,8 +5774,7 @@ long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, struct kvm_pre_fault_
*/
bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
{
- scoped_guard(read_lock, &kvm->mmu_lock)
- return dat_test_age_gfn(kvm->arch.gmap->asce, range->start, range->end);
+ return gmap_test_age_gfn(kvm, range);
}
/**
@@ -5924,6 +5808,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;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/s390/s390.h
similarity index 97%
rename from arch/s390/kvm/kvm-s390.h
rename to arch/s390/kvm/s390/s390.h
index 6d2842fb71a33a..aa206100723093 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/s390/s390.h
@@ -32,6 +32,11 @@ union kvm_s390_quad {
unsigned char one;
};
+static inline bool kvm_s390_is_in_sie(struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.sie_block->prog0c & PROG_IN_SIE;
+}
+
static inline void kvm_s390_fpu_store(struct kvm_run *run)
{
fpu_stfpc(&run->s.regs.fpc);
@@ -452,7 +457,7 @@ void kvm_s390_vsie_destroy(struct kvm *kvm);
int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
-/* implemented in kvm-s390.c */
+/* implemented in s390.c */
int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod);
int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr);
int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr);
@@ -594,6 +599,11 @@ static inline bool kvm_s390_cur_gmap_fault_is_write(void)
return test_facility(75) && (current->thread.gmap_teid.fsi == TEID_FSI_STORE);
}
+static __always_inline int kvm_s390_is_migration_mode(struct kvm *kvm)
+{
+ return kvm->arch.migration_mode;
+}
+
/**
* kvm_s390_vcpu_crypto_reset_all
*
@@ -624,4 +634,10 @@ void kvm_s390_vcpu_pci_enable_interp(struct kvm *kvm);
*/
extern unsigned int diag9c_forwarding_hz;
+/*
+ * Must be called with kvm->slots_lock to avoid races with ourselves and
+ * kvm_s390_vm_start_migration.
+ */
+int kvm_s390_vm_stop_migration(struct kvm *kvm);
+
#endif
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/s390/sigp.c
similarity index 99%
rename from arch/s390/kvm/sigp.c
rename to arch/s390/kvm/s390/sigp.c
index 55c34cb354281e..131b3371ef4f8c 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/s390/sigp.c
@@ -14,7 +14,7 @@
#include <linux/slab.h>
#include <asm/sigp.h>
#include "gaccess.h"
-#include "kvm-s390.h"
+#include "s390.h"
#include "trace.h"
static int __sigp_sense(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
diff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/s390/trace-s390.h
similarity index 100%
rename from arch/s390/kvm/trace-s390.h
rename to arch/s390/kvm/s390/trace-s390.h
diff --git a/arch/s390/kvm/trace.h b/arch/s390/kvm/s390/trace.h
similarity index 97%
rename from arch/s390/kvm/trace.h
rename to arch/s390/kvm/s390/trace.h
index aa419eb6a0c808..97774fe09a85c5 100644
--- a/arch/s390/kvm/trace.h
+++ b/arch/s390/kvm/s390/trace.h
@@ -45,20 +45,6 @@ TRACE_EVENT(kvm_s390_skey_related_inst,
VCPU_TP_PRINTK("%s", "storage key related instruction")
);
-TRACE_EVENT(kvm_s390_major_guest_pfault,
- TP_PROTO(VCPU_PROTO_COMMON),
- TP_ARGS(VCPU_ARGS_COMMON),
-
- TP_STRUCT__entry(
- VCPU_FIELD_COMMON
- ),
-
- TP_fast_assign(
- VCPU_ASSIGN_COMMON
- ),
- VCPU_TP_PRINTK("%s", "major fault, maybe applicable for pfault")
- );
-
TRACE_EVENT(kvm_s390_pfault_init,
TP_PROTO(VCPU_PROTO_COMMON, long pfault_token),
TP_ARGS(VCPU_ARGS_COMMON, pfault_token),
diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/s390/vsie.c
similarity index 99%
rename from arch/s390/kvm/vsie.c
rename to arch/s390/kvm/s390/vsie.c
index eea24562e7db2b..c4a03b310fea40 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/s390/vsie.c
@@ -23,7 +23,7 @@
#include <asm/nmi.h>
#include <asm/dis.h>
#include <asm/facility.h>
-#include "kvm-s390.h"
+#include "s390.h"
#include "gaccess.h"
#include "gmap.h"
diff --git a/arch/s390/tools/Makefile b/arch/s390/tools/Makefile
index f2862364fb4221..bd2a00d5ce2c93 100644
--- a/arch/s390/tools/Makefile
+++ b/arch/s390/tools/Makefile
@@ -3,8 +3,13 @@
# Makefile for s390 specific build tools
#
+include $(srctree)/arch/s390/tools/Makefile.arm64h
+
kapi := arch/$(ARCH)/include/generated/asm
kapi-hdrs-y := $(kapi)/facility-defs.h $(kapi)/dis-defs.h
+kapi-hdrs-$(CONFIG_KVM_ARM64) += $(ARM64_TARGETS)
+
+targets += $(addprefix ../../../,$(kapi-hdrs-y))
PHONY += kapi
diff --git a/arch/s390/tools/Makefile.arm64h b/arch/s390/tools/Makefile.arm64h
new file mode 100644
index 00000000000000..0b32c124707d9a
--- /dev/null
+++ b/arch/s390/tools/Makefile.arm64h
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Share ARM64 headers with s390 KVM
+#
+
+arm64api := $(objtree)/arch/$(ARCH)/include/generated/arm64
+arm64uapi := $(objtree)/arch/$(ARCH)/include/generated/uapi/arm64
+
+# List of ARM64 headers to share with s390 KVM
+# Format: [uapi:]header.h or [uapi:]header-part.h
+#
+# * header.h - from arch/arm64/include/asm/ to arm64/
+# * uapi:header.h - from arch/arm64/include/uapi/asm/ to uapi/arm64/
+# * header-part.h - generated as header-part.h from ARM64 header header.h
+# * uapi:header-part.h - generated as header-part.h from ARM64 UAPI header header.h
+# If a header contains partial markers (#ifdef ARM64_S390_COMMON) only this part will be copied.
+# If the file does not contain any markers the whole file will be copied.
+ARM64_SHARED_HEADERS := \
+ brk-imm.h \
+ esr.h \
+ kvm_arm.h \
+ kvm_emulate-part.h \
+ kvm_host.h \
+ kvm_mmu.h \
+ ptrace.h \
+ sysreg.h \
+ uapi:hwcap.h \
+ uapi:kvm.h \
+ uapi:ptrace.h \
+ uapi:sve_context.h \
+
+quiet_cmd_gen_arm_hdr = GEN $@
+ cmd_gen_arm_hdr = mkdir -p $(dir $@); \
+ $(AWK) -f $(src)/copy-arm64h.awk $< > $@ || \
+ $(AWK) -f $(src)/copy-arm64h-full.awk -v srcfile="$(subst $(srctree)/,,$(subst $(srctree)/../,,$<))" $< > $@
+
+arm64-type = $(firstword $(subst :, ,$(1)))
+arm64-base = $(or $(word 2,$(subst :, ,$(1))),$(1))
+arm64-src-base = $(patsubst %-part.h,%.h,$(call arm64-base,$(1)))
+
+arm64-src = $(srctree)/arch/arm64/include/$(if $(filter uapi,$(call arm64-type,$(1))),uapi/)asm/$(call arm64-src-base,$(1))
+arm64-dst = $(objtree)/$(if $(filter uapi,$(call arm64-type,$(1))),$(arm64uapi),$(arm64api))/$(call arm64-base,$(1))
+
+$(foreach hdr,$(ARM64_SHARED_HEADERS),\
+ $(eval $(call arm64-dst,$(hdr)): $(call arm64-src,$(hdr)) $(src)/copy-arm64h.awk $(src)/copy-arm64h-full.awk))
+
+ARM64_TARGETS := $(sort $(foreach hdr,$(ARM64_SHARED_HEADERS),$(call arm64-dst,$(hdr))))
+
+$(ARM64_TARGETS):
+ $(call cmd,gen_arm_hdr)
+
+quiet_cmd_gen_sysreg_arm64 = GEN $@
+ cmd_gen_sysreg_arm64 = mkdir -p $(dir $@); $(AWK) -f $(srctree)/arch/arm64/tools/gen-sysreg.awk $(srctree)/arch/arm64/tools/sysreg > $@
+
+$(arm64api)/sysreg-defs.h: $(srctree)/arch/arm64/tools/gen-sysreg.awk $(srctree)/arch/arm64/tools/sysreg FORCE
+ $(call if_changed,gen_sysreg_arm64)
+
+ARM64_TARGETS += $(arm64api)/sysreg-defs.h
diff --git a/arch/s390/tools/copy-arm64h-full.awk b/arch/s390/tools/copy-arm64h-full.awk
new file mode 100644
index 00000000000000..a9b85b347f780a
--- /dev/null
+++ b/arch/s390/tools/copy-arm64h-full.awk
@@ -0,0 +1,43 @@
+#!/usr/bin/awk -f
+# SPDX-License-Identifier: GPL-2.0
+#
+# Process entire ARM64 headers for sharing with s390 KVM
+#
+# Usage: copy-arm64h-full.awk -v srcfile=<source_path> <input_file>
+#
+# This processes the entire file (unlike copy-arm64h.awk which only extracts marked sections)
+
+BEGIN {
+ max_guard_line = 25
+ guard_found = 0
+ header_added = 0
+}
+
+# Find and process the include guard in the first few lines
+NR <= max_guard_line && !guard_found && /^#ifndef [A-Z_]+$/ {
+ guard_name = $2
+ guard_found = 1
+ print "/* This header was copied from " srcfile " */"
+ print ""
+ print
+ header_added = 1
+ next
+}
+
+# Transform include directives
+/^#include <uapi\/asm\// {
+ sub(/<uapi\/asm\//, "<uapi/arm64/")
+ print
+ next
+}
+
+/^#include <asm\// {
+ sub(/<asm\//, "<arm64/")
+ print
+ next
+}
+
+# Pass through all other lines
+{
+ print
+}
diff --git a/arch/s390/tools/copy-arm64h.awk b/arch/s390/tools/copy-arm64h.awk
new file mode 100644
index 00000000000000..33ceddd4116b4e
--- /dev/null
+++ b/arch/s390/tools/copy-arm64h.awk
@@ -0,0 +1,71 @@
+#!/usr/bin/awk -f
+# SPDX-License-Identifier: GPL-2.0
+#
+# Extract marked sections from ARM64 headers for sharing with s390 KVM
+#
+# Usage: share-arm64-header.awk <input_file>
+#
+# Extracts all sections between start/end markers. If no markers found, signals for fallback.
+#TODO verification script or c file for arm to verify the ifdef things keep working
+BEGIN {
+ # Constants
+ start_pattern = "^#ifdef ARM64_S390_COMMON$"
+ end_pattern = "^#endif \\/\\* ARM64_S390_COMMON \\*\\/$"
+ max_guard_line = 25
+
+ # State variables
+ copying = found_marker = 0
+ guard_name = ""
+ file_header_done = 0
+}
+
+NR <= max_guard_line && !guard_name && /^#ifndef [A-Za-z0-9_]+$/ {
+ guard_name = $2
+ filename = FILENAME
+ sub(/^.*arch\/arm64\//, "arch/arm64/", filename)
+ print "/*"
+ print " * This header was automatically generated from " filename
+ print " * Do not modify this file directly."
+ print " */"
+ print "#ifndef " guard_name
+ print "#define " guard_name
+ print ""
+ next
+}
+
+NR > max_guard_line && !guard_name && !file_header_done {
+ print "error: no include guard found in first " max_guard_line " lines" > "/dev/stderr"
+ file_header_done = 1
+ exit 1
+}
+
+!guard_name {
+ print
+ next
+}
+
+$0 ~ start_pattern {
+ copying = found_marker = 1
+ next
+}
+
+guard_name && !found_marker {
+ next
+}
+
+$0 ~ end_pattern { copying = 0; next }
+
+copying {
+ gsub(/#include <asm\//, "#include <arm64/")
+ gsub(/#include <uapi\/asm\//, "#include <uapi/arm64/")
+ print
+ next
+}
+
+END {
+ if (found_marker) {
+ print ""
+ print "#endif /* " guard_name " */"
+ }
+ exit !found_marker
+}
diff --git a/arch/s390/tools/opcodes.txt b/arch/s390/tools/opcodes.txt
index def2659f6602d2..0e4773c94af0d4 100644
--- a/arch/s390/tools/opcodes.txt
+++ b/arch/s390/tools/opcodes.txt
@@ -594,6 +594,9 @@ b9a0 clp RRF_U0RR
b9a1 tpei RRE_RR
b9a2 ptf RRE_R0
b9a4 uvc RRF_URR
+b9a5 sae RRE_R0
+b9a6 lasrm RRE_R0
+b9a7 stiasrm RRE_R0
b9aa lptea RRF_RURR2
b9ab essa RRF_U0RR
b9ac irbm RRE_RR
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 5f6c1ce9673b7f..69a374e48fe735 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -46,6 +46,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 801bf9e520db33..da5d9fa8a11c07 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/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
index c1cbae65d239f5..913edd9403e57a 100644
--- a/arch/x86/kvm/mmu/tdp_mmu.c
+++ b/arch/x86/kvm/mmu/tdp_mmu.c
@@ -1089,7 +1089,7 @@ void kvm_tdp_mmu_invalidate_roots(struct kvm *kvm,
* being destroyed in an error path of KVM_CREATE_VM.
*/
if (IS_ENABLED(CONFIG_PROVE_LOCKING) &&
- refcount_read(&kvm->users_count) && kvm->created_vcpus)
+ refcount_read(&kvm->rc.users_count) && kvm->created_vcpus)
lockdep_assert_held_write(&kvm->mmu_lock);
/*
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 4272293478766b..f588129f7a4f7b 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -115,7 +115,7 @@ static __always_inline void kvm_lockdep_assert_sev_lock_held(struct kvm *kvm)
* Querying SEV+ support is safe if there are no other references, i.e.
* if concurrent initialization of SEV+ is impossible.
*/
- if (!refcount_read(&kvm->users_count))
+ if (!refcount_read(&kvm->rc.users_count))
return;
/*
diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h
index 6d6cd5904ddf66..a4647859fe1fac 100644
--- a/arch/x86/kvm/vmx/nested.h
+++ b/arch/x86/kvm/vmx/nested.h
@@ -58,7 +58,7 @@ bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port,
static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
{
lockdep_assert_once(lockdep_is_held(&vcpu->mutex) ||
- !refcount_read(&vcpu->kvm->users_count));
+ !refcount_read(&vcpu->kvm->rc.users_count));
return to_vmx(vcpu)->nested.cached_vmcs12;
}
@@ -66,7 +66,7 @@ static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
static inline struct vmcs12 *get_shadow_vmcs12(struct kvm_vcpu *vcpu)
{
lockdep_assert_once(lockdep_is_held(&vcpu->mutex) ||
- !refcount_read(&vcpu->kvm->users_count));
+ !refcount_read(&vcpu->kvm->rc.users_count));
return to_vmx(vcpu)->nested.cached_shadow_vmcs12;
}
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index 22dd797e62291f..e58d24b95bd1ee 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -96,6 +96,7 @@ static void __init sclp_early_facilities_detect(void)
sclp.has_ib = cpue->ib;
sclp.has_cei = cpue->cei;
sclp.has_skey = cpue->skey;
+ sclp.has_aef = cpue->aef;
break;
}
diff --git a/drivers/vfio/device_cdev.c b/drivers/vfio/device_cdev.c
index 54abf312cf0496..a729be99d06ceb 100644
--- a/drivers/vfio/device_cdev.c
+++ b/drivers/vfio/device_cdev.c
@@ -56,7 +56,7 @@ int vfio_device_fops_cdev_open(struct inode *inode, struct file *filep)
static void vfio_df_get_kvm_safe(struct vfio_device_file *df)
{
spin_lock(&df->kvm_ref_lock);
- vfio_device_get_kvm_safe(df->device, df->kvm);
+ vfio_device_get_kvm_safe(df->device, df->kvm, df->kvm_module);
spin_unlock(&df->kvm_ref_lock);
}
diff --git a/drivers/vfio/group.c b/drivers/vfio/group.c
index b2299e5bc6df34..fc24c0b2cc6fb4 100644
--- a/drivers/vfio/group.c
+++ b/drivers/vfio/group.c
@@ -163,7 +163,7 @@ static int vfio_group_ioctl_set_container(struct vfio_group *group,
static void vfio_device_group_get_kvm_safe(struct vfio_device *device)
{
spin_lock(&device->group->kvm_ref_lock);
- vfio_device_get_kvm_safe(device, device->group->kvm);
+ vfio_device_get_kvm_safe(device, device->group->kvm, device->group->kvm_module);
spin_unlock(&device->group->kvm_ref_lock);
}
@@ -860,10 +860,11 @@ bool vfio_group_enforced_coherent(struct vfio_group *group)
return ret;
}
-void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm)
+void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm, struct module *kvm_module)
{
spin_lock(&group->kvm_ref_lock);
group->kvm = kvm;
+ group->kvm_module = kvm_module;
spin_unlock(&group->kvm_ref_lock);
}
diff --git a/drivers/vfio/vfio.h b/drivers/vfio/vfio.h
index e4b72e79b7e3e1..8209da17246c01 100644
--- a/drivers/vfio/vfio.h
+++ b/drivers/vfio/vfio.h
@@ -22,8 +22,9 @@ struct vfio_device_file {
u8 access_granted;
u32 devid; /* only valid when iommufd is valid */
- spinlock_t kvm_ref_lock; /* protect kvm field */
+ spinlock_t kvm_ref_lock; /* protect kvm and kvm_module fields */
struct kvm *kvm;
+ struct module *kvm_module;
struct iommufd_ctx *iommufd; /* protected by struct vfio_device_set::lock */
};
@@ -89,6 +90,7 @@ struct vfio_group {
enum vfio_group_type type;
struct mutex group_lock;
struct kvm *kvm;
+ struct module *kvm_module;
struct file *opened_file;
struct iommufd_ctx *iommufd;
spinlock_t kvm_ref_lock;
@@ -107,7 +109,7 @@ void vfio_device_group_unuse_iommu(struct vfio_device *device);
void vfio_df_group_close(struct vfio_device_file *df);
struct vfio_group *vfio_group_from_file(struct file *file);
bool vfio_group_enforced_coherent(struct vfio_group *group);
-void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm);
+void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm, struct module *kvm_module);
bool vfio_device_has_container(struct vfio_device *device);
int __init vfio_group_init(void);
void vfio_group_cleanup(void);
@@ -170,7 +172,8 @@ static inline bool vfio_group_enforced_coherent(struct vfio_group *group)
return true;
}
-static inline void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm)
+static inline void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm,
+ struct module *kvm_module)
{
}
@@ -434,11 +437,13 @@ static inline void vfio_virqfd_exit(void)
#endif
#if IS_ENABLED(CONFIG_KVM)
-void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm);
+void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,
+ struct module *kvm_module);
void vfio_device_put_kvm(struct vfio_device *device);
#else
static inline void vfio_device_get_kvm_safe(struct vfio_device *device,
- struct kvm *kvm)
+ struct kvm *kvm,
+ struct module *kvm_module)
{
}
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index ed538aebb0b8e4..6bddea4d384ffd 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -17,7 +17,7 @@
#include <linux/idr.h>
#include <linux/iommu.h>
#if IS_ENABLED(CONFIG_KVM)
-#include <linux/kvm_host.h>
+#include <linux/kvm_types.h>
#endif
#include <linux/list.h>
#include <linux/miscdevice.h>
@@ -448,36 +448,26 @@ void vfio_unregister_group_dev(struct vfio_device *device)
EXPORT_SYMBOL_GPL(vfio_unregister_group_dev);
#if IS_ENABLED(CONFIG_KVM)
-void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm)
+void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,
+ struct module *kvm_module)
{
- void (*pfn)(struct kvm *kvm);
- bool (*fn)(struct kvm *kvm);
- bool ret;
-
lockdep_assert_held(&device->dev_set->lock);
if (!kvm)
return;
- pfn = symbol_get(kvm_put_kvm);
- if (WARN_ON(!pfn))
+ if (!try_module_get(kvm_module))
return;
- fn = symbol_get(kvm_get_kvm_safe);
- if (WARN_ON(!fn)) {
- symbol_put(kvm_put_kvm);
- return;
- }
+ if (!kvm_get_kvm_safe(kvm))
+ goto out_put_mod;
- ret = fn(kvm);
- symbol_put(kvm_get_kvm_safe);
- if (!ret) {
- symbol_put(kvm_put_kvm);
- return;
- }
-
- device->put_kvm = pfn;
device->kvm = kvm;
+ device->kvm_module = kvm_module;
+ return;
+
+out_put_mod:
+ module_put(kvm_module);
}
void vfio_device_put_kvm(struct vfio_device *device)
@@ -487,15 +477,10 @@ void vfio_device_put_kvm(struct vfio_device *device)
if (!device->kvm)
return;
- if (WARN_ON(!device->put_kvm))
- goto clear;
-
- device->put_kvm(device->kvm);
- device->put_kvm = NULL;
- symbol_put(kvm_put_kvm);
-
-clear:
+ kvm_put_kvm(device->kvm);
device->kvm = NULL;
+ module_put(device->kvm_module);
+ device->kvm_module = NULL;
}
#endif
@@ -1520,7 +1505,7 @@ bool vfio_file_enforced_coherent(struct file *file)
}
EXPORT_SYMBOL_GPL(vfio_file_enforced_coherent);
-static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm)
+static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module)
{
struct vfio_device_file *df = file->private_data;
@@ -1531,6 +1516,7 @@ static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm)
*/
spin_lock(&df->kvm_ref_lock);
df->kvm = kvm;
+ df->kvm_module = kvm_module;
spin_unlock(&df->kvm_ref_lock);
}
@@ -1542,16 +1528,16 @@ static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm)
* When a VFIO device is first opened the KVM will be available in
* device->kvm if one was associated with the file.
*/
-void vfio_file_set_kvm(struct file *file, struct kvm *kvm)
+void vfio_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module)
{
struct vfio_group *group;
group = vfio_group_from_file(file);
if (group)
- vfio_group_set_kvm(group, kvm);
+ vfio_group_set_kvm(group, kvm, kvm_module);
if (vfio_device_from_file(file))
- vfio_device_file_set_kvm(file, kvm);
+ vfio_device_file_set_kvm(file, kvm, kvm_module);
}
EXPORT_SYMBOL_GPL(vfio_file_set_kvm);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index ab8cfaec82d31e..bd380a2599108d 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -768,6 +768,9 @@ struct kvm_memslots {
};
struct kvm {
+ /* Must be the first field, see function definitions in kvm_types.h. */
+ struct kvm_refcount rc;
+
#ifdef KVM_HAVE_MMU_RWLOCK
rwlock_t mmu_lock;
#else
@@ -831,8 +834,7 @@ struct kvm {
struct list_head ioeventfds;
struct kvm_vm_stat stat;
struct kvm_arch arch;
- refcount_t users_count;
-#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;
@@ -1067,12 +1069,11 @@ 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);
-void kvm_get_kvm(struct kvm *kvm);
-bool kvm_get_kvm_safe(struct kvm *kvm);
-void kvm_put_kvm(struct kvm *kvm);
bool file_is_kvm(struct file *file);
void kvm_put_kvm_no_destroy(struct kvm *kvm);
@@ -1081,7 +1082,7 @@ static inline struct kvm_memslots *__kvm_memslots(struct kvm *kvm, int as_id)
as_id = array_index_nospec(as_id, KVM_MAX_NR_ADDRESS_SPACES);
return srcu_dereference_check(kvm->memslots[as_id], &kvm->srcu,
lockdep_is_held(&kvm->slots_lock) ||
- !refcount_read(&kvm->users_count));
+ !refcount_read(&kvm->rc.users_count));
}
static inline struct kvm_memslots *kvm_memslots(struct kvm *kvm)
@@ -1537,7 +1538,7 @@ void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu);
void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu);
bool kvm_vcpu_wake_up(struct kvm_vcpu *vcpu);
-#ifndef CONFIG_S390
+#ifndef CONFIG_KVM_S390
void __kvm_vcpu_kick(struct kvm_vcpu *vcpu, bool wait);
static inline void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
index a568d8e6f4e829..aadee536771a78 100644
--- a/include/linux/kvm_types.h
+++ b/include/linux/kvm_types.h
@@ -33,6 +33,7 @@
#include <linux/mutex.h>
#include <linux/spinlock_types.h>
+#include <linux/refcount.h>
struct kvm;
struct kvm_async_pf;
@@ -140,6 +141,38 @@ struct kvm_vcpu_stat_generic {
};
#define KVM_STATS_NAME_SIZE 48
+
+struct kvm_refcount {
+ refcount_t users_count;
+ void (*destroy)(struct kvm *kvm);
+};
+
+static inline void kvm_get_kvm(struct kvm *kvm)
+{
+ struct kvm_refcount *rc = (struct kvm_refcount *)kvm;
+
+ refcount_inc(&rc->users_count);
+}
+
+/*
+ * A safe version of kvm_get_kvm(), making sure the vm is not being destroyed.
+ * Return true if kvm referenced successfully, false otherwise.
+ */
+static inline bool kvm_get_kvm_safe(struct kvm *kvm)
+{
+ struct kvm_refcount *rc = (struct kvm_refcount *)kvm;
+
+ return refcount_inc_not_zero(&rc->users_count);
+}
+
+static inline void kvm_put_kvm(struct kvm *kvm)
+{
+ struct kvm_refcount *rc = (struct kvm_refcount *)kvm;
+
+ if (refcount_dec_and_test(&rc->users_count))
+ rc->destroy(kvm);
+}
+
#endif /* !__ASSEMBLER__ */
#endif /* __KVM_TYPES_H__ */
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index 31b826efba0008..81f04e60ebfda1 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -55,6 +55,7 @@ struct vfio_device {
unsigned int migration_flags;
u8 precopy_info_v2;
struct kvm *kvm;
+ struct module *kvm_module;
/* Members below here are private, not for driver use */
unsigned int index;
@@ -66,7 +67,6 @@ struct vfio_device {
unsigned int open_count;
struct completion comp;
struct iommufd_access *iommufd_access;
- void (*put_kvm)(struct kvm *kvm);
struct inode *inode;
#if IS_ENABLED(CONFIG_IOMMUFD)
struct iommufd_device *iommufd_device;
@@ -377,7 +377,7 @@ static inline bool vfio_file_has_dev(struct file *file, struct vfio_device *devi
#endif
bool vfio_file_is_valid(struct file *file);
bool vfio_file_enforced_coherent(struct file *file);
-void vfio_file_set_kvm(struct file *file, struct kvm *kvm);
+void vfio_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module);
#define VFIO_PIN_PAGES_MAX_ENTRIES (PAGE_SIZE/sizeof(unsigned long))
diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig
index 794976b88c6f97..c4a983e41765d9 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 d047d4cf58c9fd..3c27c18b49a032 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 6b1d9016109989..070eba3c65349b 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 36f84264ed257e..a8430d41945b9d 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 e44c20c049610d..6ac79d80e7ec01 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -119,6 +119,7 @@ static struct dentry *kvm_debugfs_dir;
static const struct file_operations stat_fops_per_vm;
+static void kvm_destroy_vm(struct kvm *kvm);
static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
unsigned long arg);
#ifdef CONFIG_KVM_COMPAT
@@ -1089,7 +1090,7 @@ static inline struct kvm_io_bus *kvm_get_bus_for_destruction(struct kvm *kvm,
enum kvm_bus idx)
{
return rcu_dereference_protected(kvm->buses[idx],
- !refcount_read(&kvm->users_count));
+ !refcount_read(&kvm->rc.users_count));
}
static int kvm_enable_virtualization(void);
@@ -1146,7 +1147,9 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
if (r)
goto out_err_no_irq_routing;
- refcount_set(&kvm->users_count, 1);
+ BUILD_BUG_ON(offsetof(struct kvm, rc) != 0);
+ refcount_set(&kvm->rc.users_count, 1);
+ kvm->rc.destroy = kvm_destroy_vm;
for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
for (j = 0; j < 2; j++) {
@@ -1216,7 +1219,7 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
out_err_no_disable:
kvm_arch_destroy_vm(kvm);
out_err_no_arch_destroy_vm:
- WARN_ON_ONCE(!refcount_dec_and_test(&kvm->users_count));
+ WARN_ON_ONCE(!refcount_dec_and_test(&kvm->rc.users_count));
for (i = 0; i < KVM_NR_BUSES; i++)
kfree(kvm_get_bus_for_destruction(kvm, i));
kvm_free_irq_routing(kvm);
@@ -1309,29 +1312,6 @@ static void kvm_destroy_vm(struct kvm *kvm)
mmdrop(mm);
}
-void kvm_get_kvm(struct kvm *kvm)
-{
- refcount_inc(&kvm->users_count);
-}
-EXPORT_SYMBOL_GPL(kvm_get_kvm);
-
-/*
- * Make sure the vm is not during destruction, which is a safe version of
- * kvm_get_kvm(). Return true if kvm referenced successfully, false otherwise.
- */
-bool kvm_get_kvm_safe(struct kvm *kvm)
-{
- return refcount_inc_not_zero(&kvm->users_count);
-}
-EXPORT_SYMBOL_GPL(kvm_get_kvm_safe);
-
-void kvm_put_kvm(struct kvm *kvm)
-{
- if (refcount_dec_and_test(&kvm->users_count))
- kvm_destroy_vm(kvm);
-}
-EXPORT_SYMBOL_GPL(kvm_put_kvm);
-
/*
* Used to put a reference that was taken on behalf of an object associated
* with a user-visible file descriptor, e.g. a vcpu or device, if installation
@@ -1341,7 +1321,7 @@ EXPORT_SYMBOL_GPL(kvm_put_kvm);
*/
void kvm_put_kvm_no_destroy(struct kvm *kvm)
{
- WARN_ON(refcount_dec_and_test(&kvm->users_count));
+ WARN_ON(refcount_dec_and_test(&kvm->rc.users_count));
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_put_kvm_no_destroy);
@@ -3520,7 +3500,7 @@ void mark_page_dirty_in_slot(struct kvm *kvm,
if (WARN_ON_ONCE(vcpu && vcpu->kvm != kvm))
return;
- WARN_ON_ONCE(!vcpu && refcount_read(&kvm->users_count) &&
+ WARN_ON_ONCE(!vcpu && refcount_read(&kvm->rc.users_count) &&
!kvm_arch_allow_write_without_running_vcpu(kvm));
#endif
@@ -4055,7 +4035,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
@@ -4881,7 +4861,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:
@@ -5222,7 +5202,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;
@@ -5544,7 +5524,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;
@@ -5562,9 +5542,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
@@ -6342,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];
@@ -6484,11 +6462,22 @@ 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.minor = minor;
+ kvm_dev.name = kstrdup(dev_name, GFP_KERNEL);
+ if (!kvm_dev.name)
+ return -ENOMEM;
+
/* A kmem cache lets us meet the alignment requirements of fx_save. */
if (!vcpu_align)
vcpu_align = __alignof__(struct kvm_vcpu);
@@ -6499,8 +6488,9 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)
offsetofend(struct kvm_vcpu, stats_id)
- offsetof(struct kvm_vcpu, arch),
NULL);
+ r = -ENOMEM;
if (!kvm_vcpu_cache)
- return -ENOMEM;
+ goto err_dev_name;
for_each_possible_cpu(cpu) {
if (!alloc_cpumask_var_node(&per_cpu(cpu_kick_mask, cpu),
@@ -6526,7 +6516,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))
@@ -6567,6 +6557,8 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)
for_each_possible_cpu(cpu)
free_cpumask_var(per_cpu(cpu_kick_mask, cpu));
kmem_cache_destroy(kvm_vcpu_cache);
+err_dev_name:
+ kfree(kvm_dev.name);
return r;
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_init);
@@ -6592,5 +6584,8 @@ void kvm_exit(void)
kvm_vfio_ops_exit();
kvm_async_pf_deinit();
kvm_irqfd_exit();
+
+ kfree(kvm_dev.name);
+ kvm_dev.name = NULL;
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_exit);
diff --git a/virt/kvm/vfio.c b/virt/kvm/vfio.c
index 6cdc4e9a333a3f..c593f31136f96b 100644
--- a/virt/kvm/vfio.c
+++ b/virt/kvm/vfio.c
@@ -37,13 +37,13 @@ struct kvm_vfio {
static void kvm_vfio_file_set_kvm(struct file *file, struct kvm *kvm)
{
- void (*fn)(struct file *file, struct kvm *kvm);
+ void (*fn)(struct file *file, struct kvm *kvm, struct module *kvm_module);
fn = symbol_get(vfio_file_set_kvm);
if (!fn)
return;
- fn(file, kvm);
+ fn(file, kvm, kvm ? THIS_MODULE : NULL);
symbol_put(vfio_file_set_kvm);
}
|
| 3/2 | 2026/07/06 09:40 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 129848 output: 18 thoughts: 579 Thoughts: **Analyzing the Arm64 Guest on s390 Host KVM Patch Series** Okay, so I'm looking at this patch series that adds support for running arm64 guests on s390 hosts using KVM. It's a significant change, touching files in `arch/s390/kvm/` and `arch/arm64/kvm/`, and it introduces a whole new directory, `arch/s390/kvm/arm64/`. My immediate thought is, "Is this even reachable, and is it worth the effort to fuzz?" My initial scan reveals a new KVM module, `kvm-arm64`, being introduced for s390. This module registers a device, likely `/dev/kvm-arm64`, and I can see the `kvm_init_with_dev` call in `arch/s390/kvm/arm64/arm.c` confirming the device name. However, a red flag immediately pops up. The initialization function, `kvm_s390_arm64_init`, has a critical check: `if (!sclp.has_aef)`. Now, what is `aef`? My gut tells me it's "Arm Execution Facility," but the critical question is, does QEMU support this? If it doesn't, this entire code path is dead in a typical virtualized environment. This patch seems quite new and possibly experimental, or perhaps internal to IBM, so it makes me think QEMU likely *doesn't* support this feature yet. Now, the prompt specifically mentions code paths unreachable in virtualized environments like QEMU. If `sclp.has_aef` is a hardware feature, can it be faked, or is it natively supported by QEMU? I need to verify whether `aef` is supported, and, if not, if this feature is required to initialize the new KVM module, because this may be a non-starter. Time to search the kernel code for `has_aef`. |
| 4/2 | 2026/07/06 09:41 | tool | grepper |
0mArgs:{
"Expression": "has_aef"
}Results: {
"Output": "arch/s390/include/asm/sclp.h=75=struct sclp_info {\n--\narch/s390/include/asm/sclp.h-110-\tunsigned char has_astfleie2 : 1;\narch/s390/include/asm/sclp.h:111:\tunsigned char has_aef : 1;\narch/s390/include/asm/sclp.h-112-\tunsigned int ibc;\n--\narch/s390/kernel/processor.c=182=static int __init setup_hwcaps(void)\n--\narch/s390/kernel/processor.c-257-\t\telf_hwcap |= HWCAP_SIE;\narch/s390/kernel/processor.c:258:\tif (sclp.has_aef)\narch/s390/kernel/processor.c-259-\t\telf_hwcap |= HWCAP_SAE;\n--\narch/s390/kvm/arm64/arm.c=711=static int __init kvm_s390_arm64_init(void)\narch/s390/kvm/arm64/arm.c-712-{\narch/s390/kvm/arm64/arm.c:713:\tif (!sclp.has_aef)\narch/s390/kvm/arm64/arm.c-714-\t\treturn -ENXIO;\n--\ndrivers/s390/char/sclp_early.c=26=static void __init sclp_early_facilities_detect(void)\n--\ndrivers/s390/char/sclp_early.c-98-\t\tsclp.has_skey = cpue-\u003eskey;\ndrivers/s390/char/sclp_early.c:99:\t\tsclp.has_aef = cpue-\u003eaef;\ndrivers/s390/char/sclp_early.c-100-\t\tbreak;\n"
} |
| 5/2 | 2026/07/06 09:41 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 131426 output: 24 thoughts: 688 Thoughts: **My Assessment of the AEF Facility and Fuzzing Feasibility** Okay, so here's the situation. I'm looking at this `sclp.has_aef` flag, which gets set from `cpue->aef` in `sclp_early_facilities_detect`. The crux of the matter is that if QEMU *doesn't* emulate this feature—the Arm Execution Facility—the `kvm-arm64` module is going to choke with an `-ENXIO` error during loading. That's a huge red flag. My immediate thought is, can we somehow bypass this dependency? But given that this is a *hardware* facility, specifically the "SAE" (Start Arm Execution) feature on s390x, my gut feeling is that we're completely stuck in virtualized environments like GCE or QEMU, since this is a CPU-level feature that's probably very niche. It's almost certainly not public and probably proprietary. The prompt, of course, is hammering this point home. It specifically mentions code paths unreachable in virtualized environments, even with emulated hardware like USB gadgets or mac80211_hwsim. If this is a new CPU feature, then it's highly unlikely that QEMU has added emulation for it yet. Let me double check if any software emulation exists... Nope, it's tied to the `sae` CPU instruction (`.insn rre,0xb9a50000,%r2,0`), so it's a hard hardware dependency. The question becomes, if this feature is genuinely unreachable, should I be setting `WorthFuzzing=false`? The answer seems like a resounding yes. It's a waste of time to target an unreachable code path. Okay, let's just make sure this is bulletproof. Can we spoof `sclp.has_aef`, or does QEMU have something up its sleeve? No, as far as I can tell, QEMU's s390x target doesn't even touch `aef` or `sae`. That's not surprising given the niche nature of running ARM64 on s390x. The prompt, again, underlines that this is a deliberate design to avoid these unreachable areas. Since this `sclp.has_aef` flag depends on a specific mainframe hardware feature that QEMU doesn't emulate, the `kvm-arm64` module fails to load from the start, returning `-ENXIO` in `init` and nothing is reachable. To be absolutely sure, let's verify if `kvm_s390_arm64_init` is the sole entry point. Yep, `module_init(kvm_s390_arm64_init)`. If that fails, it fails. The other changes are in `arch/arm64/kvm/` but that's conditional behind `#ifdef ARM64_S390_COMMON`, which is only defined when building `kvm-arm64` on s390x. Quick check the `arch/arm64/Makefile` confirms `-DARM64_S390_COMMON` is in `KBUILD_CFLAGS`. Bottom line: I'm going to set `WorthFuzzing=false`. This code path is dead in the water in all practical fuzzing environments. |
| 6/2 | 2026/07/06 09:41 | tool | grepper |
0mArgs:{
"Expression": "ARM64_S390_COMMON"
}Results: {
"Output": "arch/arm64/Makefile=45=KBUILD_CFLAGS\t+= $(call cc-disable-warning, psabi)\narch/arm64/Makefile:46:KBUILD_CFLAGS\t+= -DARM64_S390_COMMON\narch/arm64/Makefile-47-KBUILD_AFLAGS\t+= $(compat_vdso)\narch/arm64/Makefile:48:KBUILD_AFLAGS\t+= -DARM64_S390_COMMON\narch/arm64/Makefile-49-\n--\narch/arm64/include/asm/kvm_emulate.h=45=void kvm_skip_instr32(struct kvm_vcpu *vcpu);\narch/arm64/include/asm/kvm_emulate.h-46-\narch/arm64/include/asm/kvm_emulate.h:47:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_emulate.h-48-void kvm_inject_undefined(struct kvm_vcpu *vcpu);\narch/arm64/include/asm/kvm_emulate.h:49:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_emulate.h-50-void kvm_inject_sync(struct kvm_vcpu *vcpu, u64 esr);\narch/arm64/include/asm/kvm_emulate.h=51=int kvm_inject_serror_esr(struct kvm_vcpu *vcpu, u64 esr);\narch/arm64/include/asm/kvm_emulate.h:52:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_emulate.h-53-int kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr);\narch/arm64/include/asm/kvm_emulate.h:54:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_emulate.h-55-int kvm_inject_dabt_excl_atomic(struct kvm_vcpu *vcpu, u64 addr);\narch/arm64/include/asm/kvm_emulate.h=56=void kvm_inject_size_fault(struct kvm_vcpu *vcpu);\narch/arm64/include/asm/kvm_emulate.h-57-\narch/arm64/include/asm/kvm_emulate.h:58:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_emulate.h-59-static inline int kvm_inject_sea_dabt(struct kvm_vcpu *vcpu, u64 addr)\n--\narch/arm64/include/asm/kvm_emulate.h=64=static inline int kvm_inject_sea_iabt(struct kvm_vcpu *vcpu, u64 addr)\n--\narch/arm64/include/asm/kvm_emulate.h-68-\narch/arm64/include/asm/kvm_emulate.h:69:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_emulate.h-70-\n--\narch/arm64/include/asm/kvm_emulate.h=169=static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)\n--\narch/arm64/include/asm/kvm_emulate.h-173-\narch/arm64/include/asm/kvm_emulate.h:174:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_emulate.h-175-/*\n--\narch/arm64/include/asm/kvm_emulate.h=186=static __always_inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,\n--\narch/arm64/include/asm/kvm_emulate.h-192-\narch/arm64/include/asm/kvm_emulate.h:193:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_emulate.h-194-\n--\narch/arm64/include/asm/kvm_emulate.h=373=static inline u64 kvm_vcpu_get_disr(const struct kvm_vcpu *vcpu)\n--\narch/arm64/include/asm/kvm_emulate.h-377-\narch/arm64/include/asm/kvm_emulate.h:378:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_emulate.h-379-static inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu)\n--\narch/arm64/include/asm/kvm_emulate.h=451=static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)\n--\narch/arm64/include/asm/kvm_emulate.h-455-\narch/arm64/include/asm/kvm_emulate.h:456:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_emulate.h-457-\n--\narch/arm64/include/asm/kvm_emulate.h=492=static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)\n--\narch/arm64/include/asm/kvm_emulate.h-497-\narch/arm64/include/asm/kvm_emulate.h:498:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_emulate.h-499-static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)\n--\narch/arm64/include/asm/kvm_emulate.h-522-\narch/arm64/include/asm/kvm_emulate.h:523:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_emulate.h-524-\n--\narch/arm64/include/asm/kvm_emulate.h=546=static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)\n--\narch/arm64/include/asm/kvm_emulate.h-559-\narch/arm64/include/asm/kvm_emulate.h:560:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_emulate.h-561-static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,\n--\narch/arm64/include/asm/kvm_emulate.h=623=static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)\n--\narch/arm64/include/asm/kvm_emulate.h-635-\narch/arm64/include/asm/kvm_emulate.h:636:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_emulate.h-637-\n--\narch/arm64/include/asm/kvm_host.h-43-\narch/arm64/include/asm/kvm_host.h:44:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_host.h-45-#define KVM_VCPU_MAX_FEATURES 9\n--\narch/arm64/include/asm/kvm_host.h-61-\narch/arm64/include/asm/kvm_host.h:62:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_host.h-63-\n--\narch/arm64/include/asm/kvm_host.h=314=struct kvm_arch {\n--\narch/arm64/include/asm/kvm_host.h-345-\narch/arm64/include/asm/kvm_host.h:346:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_host.h-347-\t/*\n--\narch/arm64/include/asm/kvm_host.h-376-\narch/arm64/include/asm/kvm_host.h:377:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_host.h-378-\tunsigned long flags;\n--\narch/arm64/include/asm/kvm_host.h=839=extern u64 kvm_nvhe_sym(hyp_cpu_logical_map)[NR_CPUS];\n--\narch/arm64/include/asm/kvm_host.h-841-\narch/arm64/include/asm/kvm_host.h:842:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_host.h-843-\narch/arm64/include/asm/kvm_host.h=844=struct vcpu_reset_state {\n--\narch/arm64/include/asm/kvm_host.h-850-\narch/arm64/include/asm/kvm_host.h:851:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_host.h-852-\n--\narch/arm64/include/asm/kvm_host.h=855=struct kvm_vcpu_arch {\n--\narch/arm64/include/asm/kvm_host.h-961-\narch/arm64/include/asm/kvm_host.h:962:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_host.h-963-/*\n--\narch/arm64/include/asm/kvm_host.h-995-\narch/arm64/include/asm/kvm_host.h:996:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_host.h-997-\n--\narch/arm64/include/asm/kvm_host.h-1010-\narch/arm64/include/asm/kvm_host.h:1011:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_host.h-1012-#define __vcpu_set_flag(v, flagset, f, m)\t\t\t\\\n--\narch/arm64/include/asm/kvm_host.h-1095-\narch/arm64/include/asm/kvm_host.h:1096:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_host.h-1097-\n--\narch/arm64/include/asm/kvm_host.h=1260=unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);\narch/arm64/include/asm/kvm_host.h:1261:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_host.h-1262-int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);\narch/arm64/include/asm/kvm_host.h-1263-\narch/arm64/include/asm/kvm_host.h:1264:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_host.h-1265-int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);\n--\narch/arm64/include/asm/kvm_host.h=1347=void kvm_calculate_traps(struct kvm_vcpu *vcpu);\narch/arm64/include/asm/kvm_host.h-1348-\narch/arm64/include/asm/kvm_host.h:1349:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_host.h-1350-/* MMIO helpers */\n--\narch/arm64/include/asm/kvm_host.h=1355=int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa);\narch/arm64/include/asm/kvm_host.h-1356-\narch/arm64/include/asm/kvm_host.h:1357:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_host.h-1358-\n--\narch/arm64/include/asm/kvm_host.h=1525=struct kvm *kvm_arch_alloc_vm(void);\n--\narch/arm64/include/asm/kvm_host.h-1532-\narch/arm64/include/asm/kvm_host.h:1533:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_host.h-1534-#define vcpu_is_protected(vcpu)\t\tkvm_vm_is_protected((vcpu)-\u003ekvm)\narch/arm64/include/asm/kvm_host.h-1535-\narch/arm64/include/asm/kvm_host.h:1536:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_host.h-1537-\n--\narch/arm64/include/asm/kvm_host.h=1554=static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature)\n--\narch/arm64/include/asm/kvm_host.h-1561-\narch/arm64/include/asm/kvm_host.h:1562:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_host.h-1563-#define kvm_vcpu_initialized(v) vcpu_get_flag(v, VCPU_INITIALIZED)\narch/arm64/include/asm/kvm_host.h-1564-\narch/arm64/include/asm/kvm_host.h:1565:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_host.h-1566-\n--\narch/arm64/include/asm/kvm_mmu.h=143=extern u32 __hyp_va_bits;\narch/arm64/include/asm/kvm_mmu.h-144-\narch/arm64/include/asm/kvm_mmu.h:145:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_mmu.h-146-/*\n--\narch/arm64/include/asm/kvm_mmu.h-151-\narch/arm64/include/asm/kvm_mmu.h:152:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_mmu.h-153-\n--\narch/arm64/include/asm/kvm_mmu.h=183=void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu);\narch/arm64/include/asm/kvm_mmu.h:184:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/kvm_mmu.h-185-int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,\n--\narch/arm64/include/asm/kvm_mmu.h-187-\narch/arm64/include/asm/kvm_mmu.h:188:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/kvm_mmu.h-189-\n--\narch/arm64/include/asm/ptrace.h-12-\narch/arm64/include/asm/ptrace.h:13:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/ptrace.h-14-#include \u003casm/sysreg.h\u003e\n--\narch/arm64/include/asm/ptrace.h-17-\narch/arm64/include/asm/ptrace.h:18:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/ptrace.h-19-\n--\narch/arm64/include/asm/ptrace.h-35-\narch/arm64/include/asm/ptrace.h:36:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/ptrace.h-37-\n--\narch/arm64/include/asm/ptrace.h-77-\narch/arm64/include/asm/ptrace.h:78:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/ptrace.h-79-\n--\narch/arm64/include/asm/sysreg.h-11-\narch/arm64/include/asm/sysreg.h:12:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/sysreg.h-13-#include \u003clinux/bits.h\u003e\narch/arm64/include/asm/sysreg.h:14:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/sysreg.h-15-#include \u003clinux/stringify.h\u003e\n--\narch/arm64/include/asm/sysreg.h-20-\narch/arm64/include/asm/sysreg.h:21:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/sysreg.h-22-\n--\narch/arm64/include/asm/sysreg.h-56-\narch/arm64/include/asm/sysreg.h:57:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/sysreg.h-58-\n--\narch/arm64/include/asm/sysreg.h-87-\narch/arm64/include/asm/sysreg.h:88:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/sysreg.h-89-\n--\narch/arm64/include/asm/sysreg.h-108-\narch/arm64/include/asm/sysreg.h:109:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/sysreg.h-110-\n--\narch/arm64/include/asm/sysreg.h-136-\narch/arm64/include/asm/sysreg.h:137:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/sysreg.h-138-\n--\narch/arm64/include/asm/sysreg.h-850-\narch/arm64/include/asm/sysreg.h:851:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/sysreg.h-852-\n--\narch/arm64/include/asm/sysreg.h-886-\narch/arm64/include/asm/sysreg.h:887:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/sysreg.h-888-\n--\narch/arm64/include/asm/sysreg.h-1124-\narch/arm64/include/asm/sysreg.h:1125:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/sysreg.h-1126-\n--\narch/arm64/include/asm/sysreg.h-1275-\narch/arm64/include/asm/sysreg.h:1276:#ifdef ARM64_S390_COMMON\narch/arm64/include/asm/sysreg.h-1277-\n--\narch/arm64/include/asm/sysreg.h-1289-\narch/arm64/include/asm/sysreg.h:1290:#endif /* ARM64_S390_COMMON */\narch/arm64/include/asm/sysreg.h-1291-\n--\narch/arm64/kvm/arm.c=1559=static unsigned long system_supported_vcpu_features(void)\n--\narch/arm64/kvm/arm.c-1582-\narch/arm64/kvm/arm.c:1583:#ifdef ARM64_S390_COMMON\narch/arm64/kvm/arm.c-1584-static int kvm_vcpu_init_check_features(struct kvm_vcpu *vcpu,\n--\narch/arm64/kvm/arm.c=1623=static bool kvm_vcpu_init_changed(struct kvm_vcpu *vcpu,\n--\narch/arm64/kvm/arm.c-1631-\narch/arm64/kvm/arm.c:1632:#endif /* ARM64_S390_COMMON */\narch/arm64/kvm/arm.c-1633-\n--\narch/arm64/kvm/guest.c=56=const struct kvm_stats_header kvm_vcpu_stats_header = {\n--\narch/arm64/kvm/guest.c-64-\narch/arm64/kvm/guest.c:65:#ifdef ARM64_S390_COMMON\narch/arm64/kvm/guest.c-66-static bool core_reg_offset_is_vreg(u64 off)\n--\narch/arm64/kvm/guest.c=216=static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)\n--\narch/arm64/kvm/guest.c-309-\narch/arm64/kvm/guest.c:310:#endif /* ARM64_S390_COMMON */\narch/arm64/kvm/guest.c-311-\n--\narch/arm64/kvm/guest.c=544=int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)\n--\narch/arm64/kvm/guest.c-548-\narch/arm64/kvm/guest.c:549:#ifdef ARM64_S390_COMMON\narch/arm64/kvm/guest.c-550-static int copy_core_reg_indices(const struct kvm_vcpu *vcpu,\n--\narch/arm64/kvm/guest.c=593=static unsigned long num_core_regs(const struct kvm_vcpu *vcpu)\n--\narch/arm64/kvm/guest.c-597-\narch/arm64/kvm/guest.c:598:#endif /* ARM64_S390_COMMON */\narch/arm64/kvm/guest.c-599-\n--\narch/arm64/kvm/handle_exit.c=191=static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)\n--\narch/arm64/kvm/handle_exit.c-215-\narch/arm64/kvm/handle_exit.c:216:#ifdef ARM64_S390_COMMON\narch/arm64/kvm/handle_exit.c-217-static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu)\n--\narch/arm64/kvm/handle_exit.c-227-\narch/arm64/kvm/handle_exit.c:228:#endif /* ARM64_S390_COMMON */\narch/arm64/kvm/handle_exit.c-229-\n--\narch/arm64/kvm/handle_exit.c=379=static exit_handle_fn arm_exit_handlers[] = {\n--\narch/arm64/kvm/handle_exit.c-409-\narch/arm64/kvm/handle_exit.c:410:#ifdef ARM64_S390_COMMON\narch/arm64/kvm/handle_exit.c-411-static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)\n--\narch/arm64/kvm/handle_exit.c=425=static int handle_trap_exceptions(struct kvm_vcpu *vcpu)\n--\narch/arm64/kvm/handle_exit.c-445-\narch/arm64/kvm/handle_exit.c:446:#endif /* ARM64_S390_COMMON */\narch/arm64/kvm/handle_exit.c-447-\n--\narch/arm64/kvm/mmio.c-12-\narch/arm64/kvm/mmio.c:13:#ifdef ARM64_S390_COMMON\narch/arm64/kvm/mmio.c-14-void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data)\n--\narch/arm64/kvm/mmio.c=109=int kvm_handle_mmio_return(struct kvm_vcpu *vcpu)\n--\narch/arm64/kvm/mmio.c-138-\narch/arm64/kvm/mmio.c:139:#endif /* ARM64_S390_COMMON */\narch/arm64/kvm/mmio.c-140-\t\ttrace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run-\u003emmio.phys_addr,\n--\narch/arm64/kvm/mmio.c-142-\t\t//TODO tracing\narch/arm64/kvm/mmio.c:143:#ifdef ARM64_S390_COMMON\narch/arm64/kvm/mmio.c-144-\t\tdata = vcpu_data_host_to_guest(vcpu, data, len);\n--\narch/arm64/kvm/mmio.c=157=int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)\n--\narch/arm64/kvm/mmio.c-177-\tif (!kvm_vcpu_dabt_isvalid(vcpu)) {\narch/arm64/kvm/mmio.c:178:#endif /* ARM64_S390_COMMON */\narch/arm64/kvm/mmio.c-179-\t\ttrace_kvm_mmio_nisv(*vcpu_pc(vcpu), esr,\n--\narch/arm64/kvm/mmio.c-181-\t\t//TODO tracing\narch/arm64/kvm/mmio.c:182:#ifdef ARM64_S390_COMMON\narch/arm64/kvm/mmio.c-183-\n--\narch/arm64/kvm/mmio.c-232-\narch/arm64/kvm/mmio.c:233:#endif /* ARM64_S390_COMMON */\narch/arm64/kvm/mmio.c-234-\t\ttrace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, \u0026data);\narch/arm64/kvm/mmio.c-235-\t//TODO tracing\narch/arm64/kvm/mmio.c:236:#ifdef ARM64_S390_COMMON\narch/arm64/kvm/mmio.c-237-\t\tkvm_mmio_write_buf(data_buf, len, data);\n--\narch/arm64/kvm/mmio.c-241-\t} else {\narch/arm64/kvm/mmio.c:242:#endif /* ARM64_S390_COMMON */\narch/arm64/kvm/mmio.c-243-\t\ttrace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len,\n--\narch/arm64/kvm/mmio.c-245-\t//TODO tracing\narch/arm64/kvm/mmio.c:246:#ifdef ARM64_S390_COMMON\narch/arm64/kvm/mmio.c-247-\n--\narch/arm64/kvm/mmio.c-272-}\narch/arm64/kvm/mmio.c:273:#endif /* ARM64_S390_COMMON */\n--\narch/arm64/kvm/reset.c=35=unsigned int __ro_after_init kvm_host_sve_max_vl;\narch/arm64/kvm/reset.c-36-\narch/arm64/kvm/reset.c:37:#ifdef ARM64_S390_COMMON\narch/arm64/kvm/reset.c-38-/*\n--\narch/arm64/kvm/reset.c-49-\narch/arm64/kvm/reset.c:50:#endif /* ARM64_S390_COMMON */\narch/arm64/kvm/reset.c-51-\n--\narch/arm64/kvm/reset.c=169=static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)\n--\narch/arm64/kvm/reset.c-174-\narch/arm64/kvm/reset.c:175:#ifdef ARM64_S390_COMMON\narch/arm64/kvm/reset.c-176-static void kvm_reset_vcpu_core_regs(struct kvm_vcpu *vcpu)\n--\narch/arm64/kvm/reset.c-199-\narch/arm64/kvm/reset.c:200:#endif /* ARM64_S390_COMMON */\narch/arm64/kvm/reset.c-201-\n--\narch/s390/kvm/arm64/Makefile.gen=14=quiet_cmd_extract_inc = GEN $@\n--\narch/s390/kvm/arm64/Makefile.gen-16- $(AWK) -f $(src)/copy-arm64c.awk $\u003c \u003e $@ || \\\narch/s390/kvm/arm64/Makefile.gen:17: { echo \"Error: No ARM64_S390_COMMON markers in $\u003c\" \u003e\u00262; rm -f $@; exit 1; }\narch/s390/kvm/arm64/Makefile.gen-18-\n--\narch/s390/kvm/arm64/copy-arm64c.awk=10=BEGIN {\narch/s390/kvm/arm64/copy-arm64c.awk-11-\t# Constants\narch/s390/kvm/arm64/copy-arm64c.awk:12:\tstart_pattern = \"^#ifdef ARM64_S390_COMMON$\"\narch/s390/kvm/arm64/copy-arm64c.awk:13:\tend_pattern = \"^#endif /\\\\* ARM64_S390_COMMON \\\\*/$\"\narch/s390/kvm/arm64/copy-arm64c.awk-14-\n--\narch/s390/tools/Makefile.arm64h=7=arm64uapi := $(objtree)/arch/$(ARCH)/include/generated/uapi/arm64\n--\narch/s390/tools/Makefile.arm64h-15-# * uapi:header-part.h - generated as header-part.h from ARM64 UAPI header header.h\narch/s390/tools/Makefile.arm64h:16:# If a header contains partial markers (#ifdef ARM64_S390_COMMON) only this part will be copied.\narch/s390/tools/Makefile.arm64h-17-# If the file does not contain any markers the whole file will be copied.\n--\narch/s390/tools/copy-arm64h.awk=10=BEGIN {\narch/s390/tools/copy-arm64h.awk-11-\t# Constants\narch/s390/tools/copy-arm64h.awk:12:\tstart_pattern = \"^#ifdef ARM64_S390_COMMON$\"\narch/s390/tools/copy-arm64h.awk:13:\tend_pattern = \"^#endif \\\\/\\\\* ARM64_S390_COMMON \\\\*\\\\/$\"\narch/s390/tools/copy-arm64h.awk-14-\tmax_guard_line = 25\n"
} |
| 7/2 | 2026/07/06 09:41 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 141628 output: 18 thoughts: 549 Thoughts: **Analyzing Code Reachability in a Virtualized s390x Environment** Okay, so the build system is doing something pretty smart – it's sharing code between `arm64/kvm/` and `s390/kvm/arm64/` using preprocessor directives. I see that it's pulling code out from ARM64 and sticking it in the s390x tree. My question is, is this code even *reachable* in a virtualized context, like QEMU? The core issue seems to hinge on `sclp.has_aef` and the `kvm_s390_arm64_init` function. If `aef` (Arm Execution Facility) is required, and QEMU doesn't emulate it, the initialization routine will return `-ENXIO`, effectively killing the module load. So, first instinct, can I just enable `CONFIG_KVM_ARM64` and see if the module loads? If it fails, that entire code section in `arch/s390/kvm/arm64/` is unreachable. Alright, let's see. ... Nope, it fails. So, that's that, right? Are there any other possible ways to get to it? No, the init function is the only way in. But wait, hold on. Is there any existing QEMU support for this `aef` facility, or is it a known hardware facility? Ideally, I'd check the QEMU source code. I can't do that here, but based on the prompt's instructions: "Return WorthFuzzing=false if the patch only contains: - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware". That's what I am dealing with, I think, it's not supported by QEMU. If `aef` is a new feature on s390x, it's highly probable it's not emulated by QEMU yet, or it's an IBM proprietary feature. I need to be sure. Can we *fake* it? Let's trace it back. In `sclp_early_facilities_detect`, `sclp.has_aef` is directly assigned from `cpue->aef`. This comes from the SCLP interface, the hypervisor/hardware interaction on s390x. If QEMU doesn't provide it, it's zero. Is there an option somewhere in the virtual machine to turn it on? No, you can't force it since it comes from hardware. Any command line parameters? I should check `arch/s390/kernel/early.c` or something similar, but based on these facts it's likely not there. |
| 8/2 | 2026/07/06 09:41 | tool | grepper |
0mArgs:{
"Expression": "has_aef"
}Results: {
"Output": "arch/s390/include/asm/sclp.h=75=struct sclp_info {\n--\narch/s390/include/asm/sclp.h-110-\tunsigned char has_astfleie2 : 1;\narch/s390/include/asm/sclp.h:111:\tunsigned char has_aef : 1;\narch/s390/include/asm/sclp.h-112-\tunsigned int ibc;\n--\narch/s390/kernel/processor.c=182=static int __init setup_hwcaps(void)\n--\narch/s390/kernel/processor.c-257-\t\telf_hwcap |= HWCAP_SIE;\narch/s390/kernel/processor.c:258:\tif (sclp.has_aef)\narch/s390/kernel/processor.c-259-\t\telf_hwcap |= HWCAP_SAE;\n--\narch/s390/kvm/arm64/arm.c=711=static int __init kvm_s390_arm64_init(void)\narch/s390/kvm/arm64/arm.c-712-{\narch/s390/kvm/arm64/arm.c:713:\tif (!sclp.has_aef)\narch/s390/kvm/arm64/arm.c-714-\t\treturn -ENXIO;\n--\ndrivers/s390/char/sclp_early.c=26=static void __init sclp_early_facilities_detect(void)\n--\ndrivers/s390/char/sclp_early.c-98-\t\tsclp.has_skey = cpue-\u003eskey;\ndrivers/s390/char/sclp_early.c:99:\t\tsclp.has_aef = cpue-\u003eaef;\ndrivers/s390/char/sclp_early.c-100-\t\tbreak;\n"
} |
| 9/2 | 2026/07/06 09:42 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 143341 output: 21 thoughts: 694 Thoughts: **Analyzing the Reachability of This Patch** Okay, so I'm looking at this patch and immediately, the initial thought is, there's no easy way to force `has_aef` to be set via the command line. If QEMU doesn't support this feature – and it's looking like a significant one, running ARM64 on s390x – then it's effectively unreachable, which I can't be sure of without investigation. I'm usually wary of new s390x CPU features, as QEMU emulation often lags. But hang on, is this actually a *real* feature? "Arm Execution Facility" on s390x? Yes, it appears IBM has announced this. It definitely requires hardware support – that `sae` instruction (`.insn rre,0xb9a50000,%r2,0`) is the key. So, if QEMU doesn't emulate that, any attempt to execute it will result in a `SIGILL` or `PGM_OPERATION` exception. Even if we somehow bypassed the `sclp.has_aef` check, the `sae` instruction is going to trap. So, the core function, the actual ARM64 execution, is inaccessible in a virtualized environment like QEMU without specific emulation. I should be concerned about this new instruction and facility. But wait, what if QEMU *does* support it? If it's a patch series under review, it's possible QEMU support is being developed concurrently, but it's not in the mainline QEMU that syzkaller uses. Syzkaller uses standard QEMU. If QEMU doesn't support it, syzkaller can't fuzz it. Okay, let's consider other parts of the patch that *might* be reachable. This patch modifies `arch/s390/kvm/gmap/` and `arch/s390/kvm/s390/`. It looks like it's refactoring existing s390 KVM code to separate `gmap` and `s390` specific KVM code, so that `arm64` KVM can reuse `gmap`. *That* refactoring of `gmap` and `s390` KVM code *is* reachable! This is the key. Let me check the diff for `arch/s390/kvm/`. I can see the renames: `arch/s390/kvm/dat.c` to `arch/s390/kvm/gmap/dat.c`, etc. It also modifies `arch/s390/kvm/Kconfig` and `arch/s390/kvm/Makefile`. And it splits `gmap.c` into several files: `gmap.c`, `sk.c`, `cmma.c`, `prefix.c`, `mmu.c`. These changes *definitely* impact the existing s390x KVM implementation! If syzkaller is running on s390x (which it does, we have s390x instances), it will test the refactored `gmap` and `s390` KVM code. I need to verify that this refactored code is compiled and reachable. I need to see this through to the end. |
| 10/2 | 2026/07/06 09:42 | tool | grepper |
0mArgs:{
"Expression": "gmap_enable_skeys"
}Results: {
"Output": "arch/s390/kvm/gmap/sk.c=222=long dat_reset_skeys(union asce asce, gfn_t start)\n--\narch/s390/kvm/gmap/sk.c-232-\narch/s390/kvm/gmap/sk.c:233:static int _gmap_enable_skeys(struct gmap *gmap)\narch/s390/kvm/gmap/sk.c-234-{\n--\narch/s390/kvm/gmap/sk.c-255-\narch/s390/kvm/gmap/sk.c:256:int gmap_enable_skeys(struct gmap *gmap)\narch/s390/kvm/gmap/sk.c-257-{\n--\narch/s390/kvm/gmap/sk.c-260-\tmmap_write_lock(gmap-\u003ekvm-\u003emm);\narch/s390/kvm/gmap/sk.c:261:\trc = _gmap_enable_skeys(gmap);\narch/s390/kvm/gmap/sk.c-262-\tmmap_write_unlock(gmap-\u003ekvm-\u003emm);\n--\narch/s390/kvm/gmap/sk.h=14=long dat_reset_skeys(union asce asce, gfn_t start);\narch/s390/kvm/gmap/sk.h-15-\narch/s390/kvm/gmap/sk.h:16:int gmap_enable_skeys(struct gmap *gmap);\narch/s390/kvm/gmap/sk.h-17-\n--\narch/s390/kvm/s390/priv.c=219=int kvm_s390_skey_check_enable(struct kvm_vcpu *vcpu)\n--\narch/s390/kvm/s390/priv.c-227-\narch/s390/kvm/s390/priv.c:228:\trc = gmap_enable_skeys(vcpu-\u003earch.gmap);\narch/s390/kvm/s390/priv.c-229-\tVCPU_EVENT(vcpu, 3, \"enabling storage keys for guest: %d\", rc);\n--\narch/s390/kvm/s390/s390.c=2194=static int kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)\n--\narch/s390/kvm/s390/s390.c-2218-\t/* Enable storage key handling for the guest */\narch/s390/kvm/s390/s390.c:2219:\tr = gmap_enable_skeys(kvm-\u003earch.gmap);\narch/s390/kvm/s390/s390.c-2220-\tif (r)\n"
} |
| 11/2 | 2026/07/06 09:42 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 145615 output: 27 thoughts: 552 Thoughts: **Analyzing the s390x KVM Refactoring for Fuzzing Potential** Okay, so this patch series is definitely touching the existing s390x KVM implementation. Good, that's the starting point. The primary action seems to be refactoring code within the `arch/s390/kvm/gmap/` directory. They're pulling code out of `gmap.c` and `dat.c` and splitting it into several new files like `sk.c`, `cmma.c`, `prefix.c`, and `mmu.c`. Wait, `gmap.c` and `dat.c` were already there, right? Let's quickly verify... ah, yep, the diff confirms they're *renaming* them into the `gmap` subdirectory. So, it's a refactoring effort, specifically for the s390x KVM code. This means the code *is* reachable and testable within the s390x environment. The instructions say that if the patch modifies "reachable core kernel logic, drivers, or architectures", we should use search tools to verify it can be executed, and then return `WorthFuzzing=true`. Since it's refactoring KVM code for s390x, it unequivocally modifies reachable core kernel logic. Now, the next crucial question: is this *just* a code movement, or are there any functional changes introduced? Let's dig into `arch/s390/kvm/gmap/mmu.c`. Aha, it contains functions like `gmap_get_dirty_log`, `gmap_prepare_memory_region`, `gmap_commit_memory_region`, `gmap_test_age_gfn`, and `gmap_pre_fault_memory`. These were *previously* in `arch/s390/kvm/kvm-s390.c`, which is now called `s390.c`. So, it's primarily a code reorganization to enhance sharing with the new `kvm-arm64` module, which is a key observation. However, even though the primary goal is sharing and refactoring, this doesn't guarantee there aren't *subtle* bugs introduced during the code's movement. Any refactoring is inherently risky. Code transformations can easily introduce new issues or expose pre-existing vulnerabilities in unexpected ways. The potential for side effects, even in pure refactoring, is significant. Therefore, given the modification of core kernel logic and the inherent risk of introducing bugs via refactoring, I believe this code is absolutely worth fuzzing. The s390x KVM code path needs to be thoroughly tested. I should probably also check the `s390.c` file to ensure there are no surprises there... just to be completely certain. |
| 12/2 | 2026/07/06 09:42 | tool | grepper |
0mArgs:{
"Expression": "kvm_s390_vm_stop_migration"
}Results: {
"Output": "arch/s390/kvm/arm64/arm.h=52=static __always_inline bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu)\n--\narch/s390/kvm/arm64/arm.h-57-/* should never be called */\narch/s390/kvm/arm64/arm.h:58:static __always_inline int kvm_s390_vm_stop_migration(struct kvm *kvm)\narch/s390/kvm/arm64/arm.h-59-{\n--\narch/s390/kvm/gmap/mmu.c=49=int gmap_prepare_memory_region(struct kvm *kvm,\n--\narch/s390/kvm/gmap/mmu.c-88-\t !(new-\u003eflags \u0026 KVM_MEM_LOG_DIRTY_PAGES))\narch/s390/kvm/gmap/mmu.c:89:\t\tWARN(kvm_s390_vm_stop_migration(kvm),\narch/s390/kvm/gmap/mmu.c-90-\t\t \"Failed to stop migration mode\");\n--\narch/s390/kvm/s390/s390.c=1187=static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req)\n--\narch/s390/kvm/s390/s390.c-1197- * Must be called with kvm-\u003esrcu held to avoid races on memslots, and with\narch/s390/kvm/s390/s390.c:1198: * kvm-\u003eslots_lock to avoid races with ourselves, kvm_s390_vm_stop_migration(),\narch/s390/kvm/s390/s390.c-1199- * and kvm_s390_get_cmma_bits().\n--\narch/s390/kvm/s390/s390.c=1201=static int kvm_s390_vm_start_migration(struct kvm *kvm)\n--\narch/s390/kvm/s390/s390.c-1246- */\narch/s390/kvm/s390/s390.c:1247:int kvm_s390_vm_stop_migration(struct kvm *kvm)\narch/s390/kvm/s390/s390.c-1248-{\n--\narch/s390/kvm/s390/s390.c=1272=static int kvm_s390_vm_set_migration(struct kvm *kvm,\n--\narch/s390/kvm/s390/s390.c-1282-\tcase KVM_S390_VM_MIGRATION_STOP:\narch/s390/kvm/s390/s390.c:1283:\t\tres = kvm_s390_vm_stop_migration(kvm);\narch/s390/kvm/s390/s390.c-1284-\t\tbreak;\n--\narch/s390/kvm/s390/s390.h=635=extern unsigned int diag9c_forwarding_hz;\n--\narch/s390/kvm/s390/s390.h-640- */\narch/s390/kvm/s390/s390.h:641:int kvm_s390_vm_stop_migration(struct kvm *kvm);\narch/s390/kvm/s390/s390.h-642-\n"
} |
| 13/2 | 2026/07/06 09:42 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 147821 output: 25 thoughts: 107 Thoughts: **Analyzing the KVM/VFIO Patch** Okay, so this patch is doing some interesting things. It looks like it's adding a `struct kvm_refcount rc` and `kvm_module` to `vfio_device_get_kvm_safe`, specifically in `include/linux/kvm_host.h` and `virt/kvm/kvm_main.c`. Hmm, I wonder what the motivation is? It seems like `vfio_device_get_kvm_safe` now takes a `struct module *kvm_module` as an argument. That's a significant change to its signature. I should check `drivers/vfio/vfio_main.c` to see how that new module is used. I'll need to understand the implications of this change and why it's necessary. |
| 14/2 | 2026/07/06 09:42 | tool | grepper |
0mArgs:{
"Expression": "vfio_device_get_kvm_safe"
}Results: {
"Output": "drivers/vfio/device_cdev.c=56=static void vfio_df_get_kvm_safe(struct vfio_device_file *df)\n--\ndrivers/vfio/device_cdev.c-58-\tspin_lock(\u0026df-\u003ekvm_ref_lock);\ndrivers/vfio/device_cdev.c:59:\tvfio_device_get_kvm_safe(df-\u003edevice, df-\u003ekvm, df-\u003ekvm_module);\ndrivers/vfio/device_cdev.c-60-\tspin_unlock(\u0026df-\u003ekvm_ref_lock);\n--\ndrivers/vfio/group.c=163=static void vfio_device_group_get_kvm_safe(struct vfio_device *device)\n--\ndrivers/vfio/group.c-165-\tspin_lock(\u0026device-\u003egroup-\u003ekvm_ref_lock);\ndrivers/vfio/group.c:166:\tvfio_device_get_kvm_safe(device, device-\u003egroup-\u003ekvm, device-\u003egroup-\u003ekvm_module);\ndrivers/vfio/group.c-167-\tspin_unlock(\u0026device-\u003egroup-\u003ekvm_ref_lock);\n--\ndrivers/vfio/vfio.h=434=static inline void vfio_virqfd_exit(void)\n--\ndrivers/vfio/vfio.h-439-#if IS_ENABLED(CONFIG_KVM)\ndrivers/vfio/vfio.h:440:void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,\ndrivers/vfio/vfio.h-441-\t\t\t struct module *kvm_module);\ndrivers/vfio/vfio.h=442=void vfio_device_put_kvm(struct vfio_device *device);\ndrivers/vfio/vfio.h-443-#else\ndrivers/vfio/vfio.h:444:static inline void vfio_device_get_kvm_safe(struct vfio_device *device,\ndrivers/vfio/vfio.h-445-\t\t\t\t\t struct kvm *kvm,\n--\ndrivers/vfio/vfio_main.c=448=EXPORT_SYMBOL_GPL(vfio_unregister_group_dev);\n--\ndrivers/vfio/vfio_main.c-450-#if IS_ENABLED(CONFIG_KVM)\ndrivers/vfio/vfio_main.c:451:void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,\ndrivers/vfio/vfio_main.c-452-\t\t\t struct module *kvm_module)\n"
} |
| 15/2 | 2026/07/06 09:42 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 148816 output: 23 thoughts: 117 Thoughts: **VFIO and KVM Interaction: A Critical Patch** Okay, so this patch is a significant one. It looks like they're fundamentally altering how VFIO gets access to some KVM functionality. Specifically, the `vfio_device_get_kvm_safe` function is being updated. Instead of relying on `symbol_get` to grab `kvm_get_kvm_safe`, it's now accepting a `struct module *kvm_module` and using `try_module_get(kvm_module)`. This is a core kernel change, right at the intersection of VFIO and KVM! This definitely isn't limited to a single architecture like s390x. This is going to impact all architectures that leverage VFIO and KVM, so this could have some pretty broad implications. I should dig into this a bit more. Let me go over to `virt/kvm/kvm_main.c` and see if there are any related changes there. I need to understand the full scope of this refactor. |
| 16/2 | 2026/07/06 09:43 | tool | grepper |
0mArgs:{
"Expression": "kvm_get_kvm_safe"
}Results: {
"Output": "arch/arm64/kvm/ptdump.c=165=static int kvm_ptdump_guest_open(struct inode *m, struct file *file)\n--\narch/arm64/kvm/ptdump.c-171-\narch/arm64/kvm/ptdump.c:172:\tif (!kvm_get_kvm_safe(kvm))\narch/arm64/kvm/ptdump.c-173-\t\treturn -ENOENT;\n--\narch/arm64/kvm/ptdump.c=225=static int kvm_pgtable_debugfs_open(struct inode *m, struct file *file,\n--\narch/arm64/kvm/ptdump.c-232-\narch/arm64/kvm/ptdump.c:233:\tif (!kvm_get_kvm_safe(kvm))\narch/arm64/kvm/ptdump.c-234-\t\treturn -ENOENT;\n--\narch/x86/kvm/Makefile=59=exports_grep_trailer := --include='*.[ch]' -nrw $(srctree)/virt/kvm $(srctree)/arch/x86/kvm | \\\n--\narch/x86/kvm/Makefile-64-\t\t\t\t-e kvm_get_kvm \\\narch/x86/kvm/Makefile:65:\t\t\t\t-e kvm_get_kvm_safe \\\narch/x86/kvm/Makefile-66-\t\t\t\t-e kvm_put_kvm\n--\narch/x86/kvm/debugfs.c=160=static int kvm_mmu_rmaps_stat_open(struct inode *inode, struct file *file)\n--\narch/x86/kvm/debugfs.c-164-\narch/x86/kvm/debugfs.c:165:\tif (!kvm_get_kvm_safe(kvm))\narch/x86/kvm/debugfs.c-166-\t\treturn -ENOENT;\n--\ndrivers/vfio/vfio_main.c=451=void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,\n--\ndrivers/vfio/vfio_main.c-461-\ndrivers/vfio/vfio_main.c:462:\tif (!kvm_get_kvm_safe(kvm))\ndrivers/vfio/vfio_main.c-463-\t\tgoto out_put_mod;\n--\ninclude/linux/kvm_types.h=150=static inline void kvm_get_kvm(struct kvm *kvm)\n--\ninclude/linux/kvm_types.h-160- */\ninclude/linux/kvm_types.h:161:static inline bool kvm_get_kvm_safe(struct kvm *kvm)\ninclude/linux/kvm_types.h-162-{\n--\nvirt/kvm/kvm_main.c=6072=static int kvm_debugfs_open(struct inode *inode, struct file *file,\n--\nvirt/kvm/kvm_main.c-6080-\t * The debugfs files are a reference to the kvm struct which\nvirt/kvm/kvm_main.c:6081: * is still valid when kvm_destroy_vm is called. kvm_get_kvm_safe\nvirt/kvm/kvm_main.c-6082- * avoids the race between open and the removal of the debugfs directory.\nvirt/kvm/kvm_main.c-6083-\t */\nvirt/kvm/kvm_main.c:6084:\tif (!kvm_get_kvm_safe(stat_data-\u003ekvm))\nvirt/kvm/kvm_main.c-6085-\t\treturn -ENOENT;\n"
} |
| 17/2 | 2026/07/06 09:43 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 150168 output: 22 thoughts: 1129 Thoughts: **Analyzing the KVM Core Refactoring and Reachability** Okay, so this patch is doing some significant refactoring within the KVM core. It looks like they're moving `kvm_get_kvm_safe` and `kvm_put_kvm` to `static inline` functions in `kvm_types.h`. That immediately tells me they're trying to optimize those calls, likely for performance. The introduction of `struct kvm_refcount` and the change to `struct kvm` is a clear indicator that the reference counting mechanism is being overhauled. This is a crucial change and worth investigating more deeply. The signature change to `kvm_init` to `kvm_init(unsigned int vcpu_size, unsigned int vcpu_align, struct module *module)` is interesting and probably linked to the introduction of `kvm_init_with_dev`. This suggests a more flexible initialization approach, perhaps allowing for multiple KVM instances or more granular control over device initialization. The fact that `kvm_init` is called by every KVM architecture module (x86, AMD, s390, ARM, etc.) makes it clear that these changes are absolutely reachable and functional across the entire KVM ecosystem. Also `kvm_get_kvm_safe` is used by VFIO, so this refactoring impacts VFIO, too. Looking back at `virt/kvm/kvm_main.c`, the refactoring of `kvm_create_vm` to use the `rc` refcount field is a key. The use of `kvm->rc.destroy` to store the destruction function, which is now static, is a clever approach to manage the lifecycle of KVM instances. This is a very targeted refactoring and a good candidate for fuzzing. My primary focus needs to be on identifying the changed symbols. Beyond the core KVM logic, there will be architectural implications, especially the S390x refactoring. It seems the core KVM changes are centered around `virt/kvm/kvm_main.c` and `drivers/vfio/vfio_main.c`. The key symbols appear to be: `kvm_init_with_dev`, `kvm_create_vm`, `vfio_device_get_kvm_safe`, `vfio_device_put_kvm`, and `vfio_file_set_kvm`. The `static inline` nature of `kvm_get_kvm_safe` and `kvm_put_kvm` means they won't be visible as symbols directly, but `vfio_device_get_kvm_safe` is still important. For S390x, the refactoring is quite significant, and it looks like a whole new set of APIs are being touched, likely related to memory management and guest address space operations. I need to dig into these, as they are crucial for understanding the impact on S390x systems. For S390x, I'll need to focus on: `gmap_get_dirty_log`, `gmap_prepare_memory_region`, `gmap_commit_memory_region`, `gmap_test_age_gfn`, `gmap_pre_fault_memory`, `dat_perform_essa`, `dat_reset_cmma`, `dat_peek_cmma`, `dat_get_cmma`, `dat_set_cmma_bits`, `dat_get_storage_key`, `dat_set_storage_key`, `dat_cond_set_storage_key`, `dat_reset_reference_bit`, `dat_reset_skeys`, and `gmap_enable_skeys`. I need a smaller focus set of symbols. From Core KVM, I'll examine `kvm_init_with_dev`, `vfio_device_get_kvm_safe`, `vfio_device_put_kvm`, and `vfio_file_set_kvm`. From S390x KVM, let's look into `gmap_prepare_memory_region`, `gmap_commit_memory_region`, `gmap_get_dirty_log`, `gmap_enable_skeys`, and `dat_set_storage_key`. Now, I need to verify that `gmap_prepare_memory_region` is actually a symbol, but this looks like a good set of functions to start with for analysis and fuzzing. |
| 18/2 | 2026/07/06 09:43 | tool | grepper |
0mArgs:{
"Expression": "gmap_prepare_memory_region"
}Results: {
"Output": "arch/s390/kvm/arm64/arm.c=597=int kvm_arch_prepare_memory_region(struct kvm *kvm,\n--\narch/s390/kvm/arm64/arm.c-601-{\narch/s390/kvm/arm64/arm.c:602:\treturn gmap_prepare_memory_region(kvm, old, new, change);\narch/s390/kvm/arm64/arm.c-603-}\n--\narch/s390/kvm/gmap/gmap.h=314=int gmap_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log);\narch/s390/kvm/gmap/gmap.h:315:int gmap_prepare_memory_region(struct kvm *kvm,\narch/s390/kvm/gmap/gmap.h-316-\t\t\t const struct kvm_memory_slot *old,\n--\narch/s390/kvm/gmap/mmu.c=18=int gmap_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)\n--\narch/s390/kvm/gmap/mmu.c-48-\narch/s390/kvm/gmap/mmu.c:49:int gmap_prepare_memory_region(struct kvm *kvm,\narch/s390/kvm/gmap/mmu.c-50-\t\t\t const struct kvm_memory_slot *old,\n--\narch/s390/kvm/s390/s390.c=5725=int kvm_arch_prepare_memory_region(struct kvm *kvm,\n--\narch/s390/kvm/s390/s390.c-5729-{\narch/s390/kvm/s390/s390.c:5730:\treturn gmap_prepare_memory_region(kvm, old, new, change);\narch/s390/kvm/s390/s390.c-5731-}\n"
} |
| 19/2 | 2026/07/06 09:43 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 152870 output: 22 thoughts: 30 Thoughts: Here's my attempt at summarizing those thoughts, speaking as an expert: **Symbol Exploration: A Quick Mental Run-Through** Okay, so I've confirmed that `gmap_prepare_memory_region` is indeed a defined symbol. Now, the question that immediately pops into my head is, what about the function `kvm_init_with_dev`? It's related somehow, I'd bet. I need to understand its role and how it interacts with the larger memory management context. I'll need to remember to look into that. |
| 20/2 | 2026/07/06 09:44 | tool | grepper |
0mArgs:{
"Expression": "kvm_init_with_dev"
}Results: {
"Output": "arch/s390/kvm/arm64/arm.c=711=static int __init kvm_s390_arm64_init(void)\n--\narch/s390/kvm/arm64/arm.c-715-\narch/s390/kvm/arm64/arm.c:716:\treturn kvm_init_with_dev(sizeof(struct kvm_vcpu), 0, THIS_MODULE,\narch/s390/kvm/arm64/arm.c-717-\t\t\t\t KVM_DEV_NAME, MISC_DYNAMIC_MINOR);\n--\ninclude/linux/kvm_host.h=1072=int kvm_init(unsigned int vcpu_size, unsigned int vcpu_align, struct module *module);\ninclude/linux/kvm_host.h:1073:int kvm_init_with_dev(unsigned int vcpu_size, unsigned int vcpu_align,\ninclude/linux/kvm_host.h-1074-\t\t struct module *module, const char *dev_name, int minor);\n--\nvirt/kvm/kvm_main.c=6465=int kvm_init(unsigned int vcpu_size, unsigned int vcpu_align, struct module *module)\nvirt/kvm/kvm_main.c-6466-{\nvirt/kvm/kvm_main.c:6467:\treturn kvm_init_with_dev(vcpu_size, vcpu_align, module, \"kvm\", KVM_MINOR);\nvirt/kvm/kvm_main.c-6468-}\nvirt/kvm/kvm_main.c-6469-\nvirt/kvm/kvm_main.c:6470:int kvm_init_with_dev(unsigned int vcpu_size, unsigned int vcpu_align,\nvirt/kvm/kvm_main.c-6471-\t\t struct module *module, const char *dev_name, int minor)\n"
} |
| 21/2 | 2026/07/06 09:44 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 153554 output: 25 thoughts: 33 Thoughts: Okay, here's my interpretation of those thoughts, summarized from my perspective as an expert in the field: **Symbol Queries and Dependencies** Alright, so the focus is on a couple of specific symbols in the context of KVM and VFIO. The initial thought confirms that `kvm_init_with_dev` is, in fact, a symbol. That's a fundamental starting point. Now, the next logical question – a crucial one – is concerning `vfio_device_get_kvm_safe`. What's the relationship between these two? What's the context of this function call, and what's the broader architectural implication? Is this about initialization, security, resource access, or synchronization? I need to understand how `vfio_device_get_kvm_safe` interacts with the KVM initialization process represented by `kvm_init_with_dev`. This is where the core of the investigation likely lies. I have a hunch that this has something to do with making VFIO devices usable within KVM. |
| 22/2 | 2026/07/06 09:44 | tool | grepper |
0mArgs:{
"Expression": "vfio_device_get_kvm_safe"
}Results: {
"Output": "drivers/vfio/device_cdev.c=56=static void vfio_df_get_kvm_safe(struct vfio_device_file *df)\n--\ndrivers/vfio/device_cdev.c-58-\tspin_lock(\u0026df-\u003ekvm_ref_lock);\ndrivers/vfio/device_cdev.c:59:\tvfio_device_get_kvm_safe(df-\u003edevice, df-\u003ekvm, df-\u003ekvm_module);\ndrivers/vfio/device_cdev.c-60-\tspin_unlock(\u0026df-\u003ekvm_ref_lock);\n--\ndrivers/vfio/group.c=163=static void vfio_device_group_get_kvm_safe(struct vfio_device *device)\n--\ndrivers/vfio/group.c-165-\tspin_lock(\u0026device-\u003egroup-\u003ekvm_ref_lock);\ndrivers/vfio/group.c:166:\tvfio_device_get_kvm_safe(device, device-\u003egroup-\u003ekvm, device-\u003egroup-\u003ekvm_module);\ndrivers/vfio/group.c-167-\tspin_unlock(\u0026device-\u003egroup-\u003ekvm_ref_lock);\n--\ndrivers/vfio/vfio.h=434=static inline void vfio_virqfd_exit(void)\n--\ndrivers/vfio/vfio.h-439-#if IS_ENABLED(CONFIG_KVM)\ndrivers/vfio/vfio.h:440:void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,\ndrivers/vfio/vfio.h-441-\t\t\t struct module *kvm_module);\ndrivers/vfio/vfio.h=442=void vfio_device_put_kvm(struct vfio_device *device);\ndrivers/vfio/vfio.h-443-#else\ndrivers/vfio/vfio.h:444:static inline void vfio_device_get_kvm_safe(struct vfio_device *device,\ndrivers/vfio/vfio.h-445-\t\t\t\t\t struct kvm *kvm,\n--\ndrivers/vfio/vfio_main.c=448=EXPORT_SYMBOL_GPL(vfio_unregister_group_dev);\n--\ndrivers/vfio/vfio_main.c-450-#if IS_ENABLED(CONFIG_KVM)\ndrivers/vfio/vfio_main.c:451:void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,\ndrivers/vfio/vfio_main.c-452-\t\t\t struct module *kvm_module)\n"
} |
| 23/2 | 2026/07/06 09:44 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 154511 output: 23 thoughts: 34 Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue: **Checking on VFIO Symbol Availability** Alright, let's see. So, I see that `vfio_device_get_kvm_safe` is definitely a symbol, that's straightforward enough. No surprises there. Now, the more pertinent question is... what about `vfio_file_set_kvm`? That's the one that always causes a hiccup. I need to make sure this symbol is accessible. I have an inkling it might not always be there... and that's usually my starting point whenever dealing with that particular subsystem. Gotta verify its availability. |
| 24/2 | 2026/07/06 09:44 | tool | grepper |
0mArgs:{
"Expression": "vfio_file_set_kvm"
}Results: {
"Output": "drivers/vfio/vfio_main.c=1508=static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module)\n--\ndrivers/vfio/vfio_main.c-1523-/**\ndrivers/vfio/vfio_main.c:1524: * vfio_file_set_kvm - Link a kvm with VFIO drivers\ndrivers/vfio/vfio_main.c-1525- * @file: VFIO group file or VFIO device file\n--\ndrivers/vfio/vfio_main.c-1530- */\ndrivers/vfio/vfio_main.c:1531:void vfio_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module)\ndrivers/vfio/vfio_main.c-1532-{\n--\ndrivers/vfio/vfio_main.c-1541-}\ndrivers/vfio/vfio_main.c:1542:EXPORT_SYMBOL_GPL(vfio_file_set_kvm);\ndrivers/vfio/vfio_main.c-1543-\n--\ninclude/linux/vfio.h=379=bool vfio_file_enforced_coherent(struct file *file);\ninclude/linux/vfio.h:380:void vfio_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module);\ninclude/linux/vfio.h-381-\n--\nvirt/kvm/vfio.c=32=struct kvm_vfio {\n--\nvirt/kvm/vfio.c-37-\nvirt/kvm/vfio.c:38:static void kvm_vfio_file_set_kvm(struct file *file, struct kvm *kvm)\nvirt/kvm/vfio.c-39-{\n--\nvirt/kvm/vfio.c-41-\nvirt/kvm/vfio.c:42:\tfn = symbol_get(vfio_file_set_kvm);\nvirt/kvm/vfio.c-43-\tif (!fn)\n--\nvirt/kvm/vfio.c-47-\nvirt/kvm/vfio.c:48:\tsymbol_put(vfio_file_set_kvm);\nvirt/kvm/vfio.c-49-}\n--\nvirt/kvm/vfio.c=143=static int kvm_vfio_file_add(struct kvm_device *dev, unsigned int fd)\n--\nvirt/kvm/vfio.c-170-\nvirt/kvm/vfio.c:171:\tkvm_vfio_file_set_kvm(kvf-\u003efile, dev-\u003ekvm);\nvirt/kvm/vfio.c-172-\tkvm_vfio_update_coherency(dev);\n--\nvirt/kvm/vfio.c=177=static void kvm_vfio_file_free(struct kvm_device *dev, struct kvm_vfio_file *kvf)\n--\nvirt/kvm/vfio.c-181-#endif\nvirt/kvm/vfio.c:182:\tkvm_vfio_file_set_kvm(kvf-\u003efile, NULL);\nvirt/kvm/vfio.c-183-\tfput(kvf-\u003efile);\n"
} |
| 25/2 | 2026/07/06 09:44 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 155593 output: 22 thoughts: 32 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Analyzing Symbol Dependencies** Right, `vfio_file_set_kvm` *is* a known symbol, that much is clear. My next line of inquiry would naturally lead me to the specifics of `gmap_commit_memory_region`. I want to understand its relationship to the setup. Is it involved in the actual mapping of guest memory or is it just handling meta data? Understanding that function’s purpose, call graph, and data structures is critical to grasping how memory is actually handed off. That's my next focal point. I need to understand the connection. |
| 26/2 | 2026/07/06 09:44 | tool | grepper |
0mArgs:{
"Expression": "gmap_commit_memory_region"
}Results: {
"Output": "arch/s390/kvm/arm64/arm.c=605=void kvm_arch_commit_memory_region(struct kvm *kvm,\n--\narch/s390/kvm/arm64/arm.c-609-{\narch/s390/kvm/arm64/arm.c:610:\tgmap_commit_memory_region(kvm, old, new, change);\narch/s390/kvm/arm64/arm.c-611-}\n--\narch/s390/kvm/gmap/gmap.h=315=int gmap_prepare_memory_region(struct kvm *kvm,\n--\narch/s390/kvm/gmap/gmap.h-318-\t\t\t enum kvm_mr_change change);\narch/s390/kvm/gmap/gmap.h:319:void gmap_commit_memory_region(struct kvm *kvm,\narch/s390/kvm/gmap/gmap.h-320-\t\t\t struct kvm_memory_slot *old,\n--\narch/s390/kvm/gmap/mmu.c=49=int gmap_prepare_memory_region(struct kvm *kvm,\n--\narch/s390/kvm/gmap/mmu.c-94-\narch/s390/kvm/gmap/mmu.c:95:void gmap_commit_memory_region(struct kvm *kvm,\narch/s390/kvm/gmap/mmu.c-96-\t\t\t struct kvm_memory_slot *old,\n--\narch/s390/kvm/s390/s390.c=5733=void kvm_arch_commit_memory_region(struct kvm *kvm,\n--\narch/s390/kvm/s390/s390.c-5737-{\narch/s390/kvm/s390/s390.c:5738:\tgmap_commit_memory_region(kvm, old, new, change);\narch/s390/kvm/s390/s390.c-5739-}\n"
} |
| 27/2 | 2026/07/06 09:44 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 156376 output: 21 thoughts: 30 Thoughts: Here's my take on those thoughts: **Analyzing Memory Management** Okay, so I've confirmed that `gmap_commit_memory_region` is indeed a defined symbol. Now, the next logical step is to delve into how Secure Keys are enabled within this context. I need to understand the relationship between committing memory regions and the activation of those security features. Specifically, I'll be looking at the function `gmap_enable_skeys` and its potential interactions with `gmap_commit_memory_region`. I want to see if the key mechanism is used and under what specific conditions. This will help me to determine how securely-keyed memory regions are initialized and managed. |
| 28/2 | 2026/07/06 09:44 | tool | grepper |
0mArgs:{
"Expression": "gmap_enable_skeys"
}Results: {
"Output": "arch/s390/kvm/gmap/sk.c=222=long dat_reset_skeys(union asce asce, gfn_t start)\n--\narch/s390/kvm/gmap/sk.c-232-\narch/s390/kvm/gmap/sk.c:233:static int _gmap_enable_skeys(struct gmap *gmap)\narch/s390/kvm/gmap/sk.c-234-{\n--\narch/s390/kvm/gmap/sk.c-255-\narch/s390/kvm/gmap/sk.c:256:int gmap_enable_skeys(struct gmap *gmap)\narch/s390/kvm/gmap/sk.c-257-{\n--\narch/s390/kvm/gmap/sk.c-260-\tmmap_write_lock(gmap-\u003ekvm-\u003emm);\narch/s390/kvm/gmap/sk.c:261:\trc = _gmap_enable_skeys(gmap);\narch/s390/kvm/gmap/sk.c-262-\tmmap_write_unlock(gmap-\u003ekvm-\u003emm);\n--\narch/s390/kvm/gmap/sk.h=14=long dat_reset_skeys(union asce asce, gfn_t start);\narch/s390/kvm/gmap/sk.h-15-\narch/s390/kvm/gmap/sk.h:16:int gmap_enable_skeys(struct gmap *gmap);\narch/s390/kvm/gmap/sk.h-17-\n--\narch/s390/kvm/s390/priv.c=219=int kvm_s390_skey_check_enable(struct kvm_vcpu *vcpu)\n--\narch/s390/kvm/s390/priv.c-227-\narch/s390/kvm/s390/priv.c:228:\trc = gmap_enable_skeys(vcpu-\u003earch.gmap);\narch/s390/kvm/s390/priv.c-229-\tVCPU_EVENT(vcpu, 3, \"enabling storage keys for guest: %d\", rc);\n--\narch/s390/kvm/s390/s390.c=2194=static int kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)\n--\narch/s390/kvm/s390/s390.c-2218-\t/* Enable storage key handling for the guest */\narch/s390/kvm/s390/s390.c:2219:\tr = gmap_enable_skeys(kvm-\u003earch.gmap);\narch/s390/kvm/s390/s390.c-2220-\tif (r)\n"
} |
| 29/2 | 2026/07/06 09:44 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 157389 output: 21 thoughts: 29 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Analyzing Symbol Definitions** Right, `gmap_enable_skeys` is definitely a symbol. No surprises there. Now, let me shift gears and quickly verify what `dat_set_storage_key` is doing. I need to refresh my mental model of that function. Let's see how it interacts with storage keys. I want to make sure I understand the scope of impact and possible interactions before I continue. This could be important for the task I'm about to do. |
| 30/2 | 2026/07/06 09:44 | tool | grepper |
0mArgs:{
"Expression": "dat_set_storage_key"
}Results: {
"Output": "arch/s390/kvm/gmap/dat.c=155=bool __must_check dat_crstep_xchg_atomic(union crste *crstep, union crste old, union crste new,\n--\narch/s390/kvm/gmap/dat.c-164-\narch/s390/kvm/gmap/dat.c:165:static void dat_set_storage_key_from_pgste(union pte pte, union pgste pgste)\narch/s390/kvm/gmap/dat.c-166-{\n--\narch/s390/kvm/gmap/dat.c=191=union pgste __dat_ptep_xchg(union pte *ptep, union pgste pgste, union pte new, gfn_t gfn,\n--\narch/s390/kvm/gmap/dat.c-213-\t\t\t/* Invalid to valid: restore storage keys from PGSTE. */\narch/s390/kvm/gmap/dat.c:214:\t\t\tdat_set_storage_key_from_pgste(new, pgste);\narch/s390/kvm/gmap/dat.c-215-\t\telse if (!old.h.i \u0026\u0026 new.h.i)\n--\narch/s390/kvm/gmap/sk.c=16=int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey)\n--\narch/s390/kvm/gmap/sk.c-49-\narch/s390/kvm/gmap/sk.c:50:int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,\narch/s390/kvm/gmap/sk.c-51-\t\t\tunion skey skey, bool nq)\n--\narch/s390/kvm/gmap/sk.h=8=int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey);\narch/s390/kvm/gmap/sk.h:9:int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gfn,\narch/s390/kvm/gmap/sk.h-10-\t\t\tunion skey skey, bool nq);\n--\narch/s390/kvm/s390/s390.c=2194=static int kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)\n--\narch/s390/kvm/s390/s390.c-2242-\t\t\tfor (i = 0 ; i \u003c args-\u003ecount; i++) {\narch/s390/kvm/s390/s390.c:2243:\t\t\t\tr = dat_set_storage_key(mc, kvm-\u003earch.gmap-\u003easce,\narch/s390/kvm/s390/s390.c-2244-\t\t\t\t\t\t\targs-\u003estart_gfn + i, keys[i], 0);\n"
} |
| 31/2 | 2026/07/06 09:44 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 158418 output: 22 thoughts: 30 Thoughts: Okay, here's my interpretation of those thoughts, presented as a first-person expert summary: **Analyzing a Data Storage Key and Initialization Process** Alright, so the system's clearly using a symbol for `dat_set_storage_key`. Good, that makes sense. It's a clean way to represent the data storage key in this context, avoids string comparisons, and allows for more efficient lookup internally. Now, I want to trace its usage. I'm going to dig into the `kvm_init_with_dev` function. That's likely where this `dat_set_storage_key` symbol is being used. I'll check how it's initialized. This will likely give me insight into the relationship between the key and the device setup. Looking at it, I can see it's linked to the initialization process of the Key Value Manager with the device, which makes total sense from what I know. Now, let's see how they connect... |
| 32/2 | 2026/07/06 09:44 | tool | grepper |
0mArgs:{
"Expression": "kvm_init_with_dev"
}Results: {
"Output": "arch/s390/kvm/arm64/arm.c=711=static int __init kvm_s390_arm64_init(void)\n--\narch/s390/kvm/arm64/arm.c-715-\narch/s390/kvm/arm64/arm.c:716:\treturn kvm_init_with_dev(sizeof(struct kvm_vcpu), 0, THIS_MODULE,\narch/s390/kvm/arm64/arm.c-717-\t\t\t\t KVM_DEV_NAME, MISC_DYNAMIC_MINOR);\n--\ninclude/linux/kvm_host.h=1072=int kvm_init(unsigned int vcpu_size, unsigned int vcpu_align, struct module *module);\ninclude/linux/kvm_host.h:1073:int kvm_init_with_dev(unsigned int vcpu_size, unsigned int vcpu_align,\ninclude/linux/kvm_host.h-1074-\t\t struct module *module, const char *dev_name, int minor);\n--\nvirt/kvm/kvm_main.c=6465=int kvm_init(unsigned int vcpu_size, unsigned int vcpu_align, struct module *module)\nvirt/kvm/kvm_main.c-6466-{\nvirt/kvm/kvm_main.c:6467:\treturn kvm_init_with_dev(vcpu_size, vcpu_align, module, \"kvm\", KVM_MINOR);\nvirt/kvm/kvm_main.c-6468-}\nvirt/kvm/kvm_main.c-6469-\nvirt/kvm/kvm_main.c:6470:int kvm_init_with_dev(unsigned int vcpu_size, unsigned int vcpu_align,\nvirt/kvm/kvm_main.c-6471-\t\t struct module *module, const char *dev_name, int minor)\n"
} |
| 33/2 | 2026/07/06 09:45 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 159190 output: 25 thoughts: 34 Thoughts: Okay, here's my take on those thoughts, framed as an expert's inner monologue: **Checking on that KVM Initialization** Right, so `kvm_init_with_dev`... yep, that's definitely a defined symbol. Now, the next logical step in this investigation is to dive into the call site, specifically, `vfio_device_get_kvm_safe`. That function likely interacts with KVM in some way. I need to understand how it uses or depends on `kvm_init_with_dev`. Perhaps it's called after, perhaps it contains an initialization. I need to figure out the interplay. Gotta check the definition and see what the function does with that KVM initialization process. Let's see how `vfio_device_get_kvm_safe` utilizes the symbol, and what context that provides for the broader architecture. |
| 34/2 | 2026/07/06 09:45 | tool | grepper |
0mArgs:{
"Expression": "vfio_device_get_kvm_safe"
}Results: {
"Output": "drivers/vfio/device_cdev.c=56=static void vfio_df_get_kvm_safe(struct vfio_device_file *df)\n--\ndrivers/vfio/device_cdev.c-58-\tspin_lock(\u0026df-\u003ekvm_ref_lock);\ndrivers/vfio/device_cdev.c:59:\tvfio_device_get_kvm_safe(df-\u003edevice, df-\u003ekvm, df-\u003ekvm_module);\ndrivers/vfio/device_cdev.c-60-\tspin_unlock(\u0026df-\u003ekvm_ref_lock);\n--\ndrivers/vfio/group.c=163=static void vfio_device_group_get_kvm_safe(struct vfio_device *device)\n--\ndrivers/vfio/group.c-165-\tspin_lock(\u0026device-\u003egroup-\u003ekvm_ref_lock);\ndrivers/vfio/group.c:166:\tvfio_device_get_kvm_safe(device, device-\u003egroup-\u003ekvm, device-\u003egroup-\u003ekvm_module);\ndrivers/vfio/group.c-167-\tspin_unlock(\u0026device-\u003egroup-\u003ekvm_ref_lock);\n--\ndrivers/vfio/vfio.h=434=static inline void vfio_virqfd_exit(void)\n--\ndrivers/vfio/vfio.h-439-#if IS_ENABLED(CONFIG_KVM)\ndrivers/vfio/vfio.h:440:void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,\ndrivers/vfio/vfio.h-441-\t\t\t struct module *kvm_module);\ndrivers/vfio/vfio.h=442=void vfio_device_put_kvm(struct vfio_device *device);\ndrivers/vfio/vfio.h-443-#else\ndrivers/vfio/vfio.h:444:static inline void vfio_device_get_kvm_safe(struct vfio_device *device,\ndrivers/vfio/vfio.h-445-\t\t\t\t\t struct kvm *kvm,\n--\ndrivers/vfio/vfio_main.c=448=EXPORT_SYMBOL_GPL(vfio_unregister_group_dev);\n--\ndrivers/vfio/vfio_main.c-450-#if IS_ENABLED(CONFIG_KVM)\ndrivers/vfio/vfio_main.c:451:void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm,\ndrivers/vfio/vfio_main.c-452-\t\t\t struct module *kvm_module)\n"
} |
| 35/2 | 2026/07/06 09:45 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 160117 output: 23 thoughts: 35 Thoughts: Here's my thought process, summarized as you requested: **Deconstructing a VFIO Symbol** Okay, so `vfio_device_get_kvm_safe` is a definite symbol. My next move is to dissect its related functions. I'm going to look at how `vfio_file_set_kvm` interacts with it. That's the logical next step in tracing the call path or understanding the broader context of this specific symbol and how it's being used within the VFIO architecture. This should reveal the connections between the device, the file descriptor setup, and the KVM integration I'm interested in. I'm building a mental map of the flow, one symbol at a time. |
| 36/2 | 2026/07/06 09:45 | tool | grepper |
0mArgs:{
"Expression": "vfio_file_set_kvm"
}Results: {
"Output": "drivers/vfio/vfio_main.c=1508=static void vfio_device_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module)\n--\ndrivers/vfio/vfio_main.c-1523-/**\ndrivers/vfio/vfio_main.c:1524: * vfio_file_set_kvm - Link a kvm with VFIO drivers\ndrivers/vfio/vfio_main.c-1525- * @file: VFIO group file or VFIO device file\n--\ndrivers/vfio/vfio_main.c-1530- */\ndrivers/vfio/vfio_main.c:1531:void vfio_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module)\ndrivers/vfio/vfio_main.c-1532-{\n--\ndrivers/vfio/vfio_main.c-1541-}\ndrivers/vfio/vfio_main.c:1542:EXPORT_SYMBOL_GPL(vfio_file_set_kvm);\ndrivers/vfio/vfio_main.c-1543-\n--\ninclude/linux/vfio.h=379=bool vfio_file_enforced_coherent(struct file *file);\ninclude/linux/vfio.h:380:void vfio_file_set_kvm(struct file *file, struct kvm *kvm, struct module *kvm_module);\ninclude/linux/vfio.h-381-\n--\nvirt/kvm/vfio.c=32=struct kvm_vfio {\n--\nvirt/kvm/vfio.c-37-\nvirt/kvm/vfio.c:38:static void kvm_vfio_file_set_kvm(struct file *file, struct kvm *kvm)\nvirt/kvm/vfio.c-39-{\n--\nvirt/kvm/vfio.c-41-\nvirt/kvm/vfio.c:42:\tfn = symbol_get(vfio_file_set_kvm);\nvirt/kvm/vfio.c-43-\tif (!fn)\n--\nvirt/kvm/vfio.c-47-\nvirt/kvm/vfio.c:48:\tsymbol_put(vfio_file_set_kvm);\nvirt/kvm/vfio.c-49-}\n--\nvirt/kvm/vfio.c=143=static int kvm_vfio_file_add(struct kvm_device *dev, unsigned int fd)\n--\nvirt/kvm/vfio.c-170-\nvirt/kvm/vfio.c:171:\tkvm_vfio_file_set_kvm(kvf-\u003efile, dev-\u003ekvm);\nvirt/kvm/vfio.c-172-\tkvm_vfio_update_coherency(dev);\n--\nvirt/kvm/vfio.c=177=static void kvm_vfio_file_free(struct kvm_device *dev, struct kvm_vfio_file *kvf)\n--\nvirt/kvm/vfio.c-181-#endif\nvirt/kvm/vfio.c:182:\tkvm_vfio_file_set_kvm(kvf-\u003efile, NULL);\nvirt/kvm/vfio.c-183-\tfput(kvf-\u003efile);\n"
} |
| 37/2 | 2026/07/06 09:45 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 161206 output: 22 thoughts: 32 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Analyzing `vfio_file_set_kvm` and `gmap_get_dirty_log`** Right, `vfio_file_set_kvm`. Yep, that rings a bell. Definitely a symbol, no question. Now, I need to understand its relationship to the broader picture, and, specifically, how it might interact with the dirty page logging mechanism. Therefore, let's pivot to investigating `gmap_get_dirty_log`. It's crucial to understand how this function works, the data structures it accesses, and the underlying algorithms. My initial thought process now revolves around how this logging mechanism is tied into the virtual machine's memory management, and potential performance implications. Does `vfio_file_set_kvm` have any influence on where or how these dirty pages are being tracked or handled? Are there any potential bottlenecks I should be aware of? Are there race conditions that could come into play given a multiple core scenario? These are the kinds of questions I will need to answer as I dig deeper. |
| 38/2 | 2026/07/06 09:45 | tool | grepper |
0mArgs:{
"Expression": "gmap_get_dirty_log"
}Results: {
"Output": "arch/s390/kvm/arm64/arm.c=577=int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,\n--\narch/s390/kvm/arm64/arm.c-579-{\narch/s390/kvm/arm64/arm.c:580:\treturn gmap_get_dirty_log(kvm, log);\narch/s390/kvm/arm64/arm.c-581-}\n--\narch/s390/kvm/gmap/gmap.h=309=static inline bool gmap_is_shadow_valid(struct gmap *sg, union asce asce, int edat_level)\n--\narch/s390/kvm/gmap/gmap.h-313-\narch/s390/kvm/gmap/gmap.h:314:int gmap_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log);\narch/s390/kvm/gmap/gmap.h-315-int gmap_prepare_memory_region(struct kvm *kvm,\n--\narch/s390/kvm/gmap/mmu.c-17- */\narch/s390/kvm/gmap/mmu.c:18:int gmap_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)\narch/s390/kvm/gmap/mmu.c-19-{\n--\narch/s390/kvm/s390/s390.c=748=int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,\n--\narch/s390/kvm/s390/s390.c-750-{\narch/s390/kvm/s390/s390.c:751:\treturn gmap_get_dirty_log(kvm, log);\narch/s390/kvm/s390/s390.c-752-}\n"
} |
| 39/2 | 2026/07/06 09:45 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 162056 output: 23 thoughts: 32 Thoughts: Okay, here's my take on those thoughts, framed as my own: **Analyzing `gmap_get_dirty_log` and `gmap_test_age_gfn`** Right, `gmap_get_dirty_log` - confirmed, that's a symbol. No surprises there. Now, let's pivot and take a closer look at `gmap_test_age_gfn`. I need to understand its relationship to the dirty log functionality. It's likely a test function, but the "age" part suggests a specific test case related to the aging or tracking of dirty pages within the Gmap context. I'll need to dig into the implementation of `gmap_test_age_gfn` to determine what it actually does and how it interacts with the dirty log symbol. I'm expecting some sort of verification here. |
| 40/2 | 2026/07/06 09:45 | tool | grepper |
0mArgs:{
"Expression": "gmap_test_age_gfn"
}Results: {
"Output": "arch/s390/kvm/arm64/arm.c=618=bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)\narch/s390/kvm/arm64/arm.c-619-{\narch/s390/kvm/arm64/arm.c:620:\treturn gmap_test_age_gfn(kvm, range);\narch/s390/kvm/arm64/arm.c-621-}\n--\narch/s390/kvm/gmap/gmap.h=319=void gmap_commit_memory_region(struct kvm *kvm,\n--\narch/s390/kvm/gmap/gmap.h-322-\t\t\t enum kvm_mr_change change);\narch/s390/kvm/gmap/gmap.h:323:bool gmap_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range);\narch/s390/kvm/gmap/gmap.h-324-long gmap_pre_fault_memory(struct kvm_vcpu *vcpu,\n--\narch/s390/kvm/gmap/mmu.c=95=void gmap_commit_memory_region(struct kvm *kvm,\n--\narch/s390/kvm/gmap/mmu.c-137-/**\narch/s390/kvm/gmap/mmu.c:138: * gmap_test_age_gfn() - test young\narch/s390/kvm/gmap/mmu.c-139- * @kvm: the kvm instance\n--\narch/s390/kvm/gmap/mmu.c-144- */\narch/s390/kvm/gmap/mmu.c:145:bool gmap_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)\narch/s390/kvm/gmap/mmu.c-146-{\n--\narch/s390/kvm/s390/s390.c=5775=bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)\narch/s390/kvm/s390/s390.c-5776-{\narch/s390/kvm/s390/s390.c:5777:\treturn gmap_test_age_gfn(kvm, range);\narch/s390/kvm/s390/s390.c-5778-}\n"
} |
| 41/2 | 2026/07/06 09:45 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 163016 output: 22 thoughts: 32 Thoughts: Okay, here's my interpretation of those thoughts, presented as a first-person expert summary: **Analyzing Symbolic References** Alright, so the system flagged `gmap_test_age_gfn`. Yep, that's definitely a symbol, a named entity within the code that represents something specific. We need to be precise about these things. Now, let's pivot and take a look at `gmap_pre_fault_memory`. This is where the core functionality could be. |
| 42/2 | 2026/07/06 09:45 | tool | grepper |
0mArgs:{
"Expression": "gmap_pre_fault_memory"
}Results: {
"Output": "arch/s390/kvm/arm64/arm.c=623=long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\n--\narch/s390/kvm/arm64/arm.c-625-{\narch/s390/kvm/arm64/arm.c:626:\treturn gmap_pre_fault_memory(vcpu, range);\narch/s390/kvm/arm64/arm.c-627-}\n--\narch/s390/kvm/gmap/gmap.h=323=bool gmap_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range);\narch/s390/kvm/gmap/gmap.h:324:long gmap_pre_fault_memory(struct kvm_vcpu *vcpu,\narch/s390/kvm/gmap/gmap.h-325-\t\t\t struct kvm_pre_fault_memory *range);\n--\narch/s390/kvm/gmap/mmu.c=145=bool gmap_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)\n--\narch/s390/kvm/gmap/mmu.c-151-/**\narch/s390/kvm/gmap/mmu.c:152: * gmap_pre_fault_memory() - pre-fault and link gmap dat tables\narch/s390/kvm/gmap/mmu.c-153- * @vcpu: the vcpu that shall appear to have generated the fault-in.\n--\narch/s390/kvm/gmap/mmu.c-170- */\narch/s390/kvm/gmap/mmu.c:171:long gmap_pre_fault_memory(struct kvm_vcpu *vcpu, struct kvm_pre_fault_memory *range)\narch/s390/kvm/gmap/mmu.c-172-{\n--\narch/s390/kvm/s390/s390.c=5761=long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,\n--\narch/s390/kvm/s390/s390.c-5763-{\narch/s390/kvm/s390/s390.c:5764:\treturn gmap_pre_fault_memory(vcpu, range);\narch/s390/kvm/s390/s390.c-5765-}\n"
} |
| 43/2 | 2026/07/06 09:45 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 163881 output: 17 thoughts: 443 Thoughts: **Analyzing the Kernel Symbol and Configuration Dependencies** Okay, so I've confirmed that `gmap_pre_fault_memory` is indeed a recognized symbol within this context. Now, I need to get a handle on the key functions and how they relate to the bigger picture. My focus symbols here are these: `kvm_init_with_dev`, `vfio_device_get_kvm_safe`, `vfio_device_put_kvm`, `vfio_file_set_kvm`, `gmap_prepare_memory_region`, `gmap_commit_memory_region`, `gmap_get_dirty_log`, `gmap_test_age_gfn`, and `dat_set_storage_key`, including the one from earlier, `gmap_pre_fault_memory`. Now, the crucial question: What specific kernel configuration options are at play? The patch introduces `CONFIG_KVM_ARM64` and `CONFIG_KVM_S390`, which now replaces the old `CONFIG_KVM` on s390x. But wait... `CONFIG_KVM` is now a tristate, and sources `arch/s390/kvm/s390/Kconfig` and `arch/s390/kvm/arm64/Kconfig`. This means the s390x-specific KVM configuration is controlled by `CONFIG_KVM_S390` while `CONFIG_KVM_ARM64` is for the arm64 on s390x KVM config. I need to think this through. Since `CONFIG_KVM_ARM64` is unreachable in QEMU, it's not strictly necessary for fuzzing, but it doesn't hurt. However, and this is important, `CONFIG_KVM_S390` is required to compile the s390x KVM code. A quick clarification: `CONFIG_KVM_S390` is selected by `CONFIG_KVM`. Nope, `CONFIG_KVM` is just a menuconfig or tristate that includes the others. Alright, I'll need to check the `arch/s390/kvm/Kconfig` file to be completely certain. |
| 44/2 | 2026/07/06 09:45 | tool | grepper |
0mArgs:{
"Expression": "config KVM"
}Results: {
"Output": "arch/arm64/kvm/Kconfig=18=if VIRTUALIZATION\narch/arm64/kvm/Kconfig-19-\narch/arm64/kvm/Kconfig:20:menuconfig KVM\narch/arm64/kvm/Kconfig-21-\tbool \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/loongarch/kvm/Kconfig=18=if VIRTUALIZATION\narch/loongarch/kvm/Kconfig-19-\narch/loongarch/kvm/Kconfig:20:config KVM\narch/loongarch/kvm/Kconfig-21-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/mips/kvm/Kconfig=16=if VIRTUALIZATION\narch/mips/kvm/Kconfig-17-\narch/mips/kvm/Kconfig:18:config KVM\narch/mips/kvm/Kconfig-19-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/mips/kvm/Kconfig-29-\narch/mips/kvm/Kconfig:30:config KVM_MIPS_DEBUG_COP0_COUNTERS\narch/mips/kvm/Kconfig-31-\tbool \"Maintain counters for COP0 accesses\"\n--\narch/powerpc/kvm/Kconfig=18=if VIRTUALIZATION\narch/powerpc/kvm/Kconfig-19-\narch/powerpc/kvm/Kconfig:20:config KVM\narch/powerpc/kvm/Kconfig-21-\tbool\n--\narch/powerpc/kvm/Kconfig-25-\narch/powerpc/kvm/Kconfig:26:config KVM_BOOK3S_HANDLER\narch/powerpc/kvm/Kconfig-27-\tbool\narch/powerpc/kvm/Kconfig-28-\narch/powerpc/kvm/Kconfig:29:config KVM_BOOK3S_32_HANDLER\narch/powerpc/kvm/Kconfig-30-\tbool\n--\narch/powerpc/kvm/Kconfig-32-\narch/powerpc/kvm/Kconfig:33:config KVM_BOOK3S_64_HANDLER\narch/powerpc/kvm/Kconfig-34-\tbool\n--\narch/powerpc/kvm/Kconfig-36-\narch/powerpc/kvm/Kconfig:37:config KVM_BOOK3S_PR_POSSIBLE\narch/powerpc/kvm/Kconfig-38-\tbool\narch/powerpc/kvm/Kconfig-39-\narch/powerpc/kvm/Kconfig:40:config KVM_BOOK3S_HV_POSSIBLE\narch/powerpc/kvm/Kconfig-41-\tbool\narch/powerpc/kvm/Kconfig-42-\narch/powerpc/kvm/Kconfig:43:config KVM_BOOK3S_32\narch/powerpc/kvm/Kconfig-44-\ttristate \"KVM support for PowerPC book3s_32 processors\"\n--\narch/powerpc/kvm/Kconfig-59-\narch/powerpc/kvm/Kconfig:60:config KVM_BOOK3S_64\narch/powerpc/kvm/Kconfig-61-\ttristate \"KVM support for PowerPC book3s_64 processors\"\n--\narch/powerpc/kvm/Kconfig-76-\narch/powerpc/kvm/Kconfig:77:config KVM_BOOK3S_64_HV\narch/powerpc/kvm/Kconfig-78-\ttristate \"KVM for POWER7 and later using hypervisor mode in host\"\n--\narch/powerpc/kvm/Kconfig-97-\narch/powerpc/kvm/Kconfig:98:config KVM_BOOK3S_64_PR\narch/powerpc/kvm/Kconfig-99-\ttristate \"KVM support without using hypervisor mode in host\"\n--\narch/powerpc/kvm/Kconfig-123-\narch/powerpc/kvm/Kconfig:124:config KVM_BOOK3S_HV_EXIT_TIMING\narch/powerpc/kvm/Kconfig-125-\tbool\narch/powerpc/kvm/Kconfig-126-\narch/powerpc/kvm/Kconfig:127:config KVM_BOOK3S_HV_P9_TIMING\narch/powerpc/kvm/Kconfig-128-\tbool \"Detailed timing for the P9 entry point\"\n--\narch/powerpc/kvm/Kconfig-139-\narch/powerpc/kvm/Kconfig:140:config KVM_BOOK3S_HV_P8_TIMING\narch/powerpc/kvm/Kconfig-141-\tbool \"Detailed timing for hypervisor real-mode code (for POWER8)\"\n--\narch/powerpc/kvm/Kconfig-154-\narch/powerpc/kvm/Kconfig:155:config KVM_BOOK3S_HV_NESTED_PMU_WORKAROUND\narch/powerpc/kvm/Kconfig-156-\tbool \"Nested L0 host workaround for L1 KVM host PMU handling bug\" if EXPERT\n--\narch/powerpc/kvm/Kconfig-169-\narch/powerpc/kvm/Kconfig:170:config KVM_BOOK3S_HV_PMU\narch/powerpc/kvm/Kconfig-171-\ttristate \"Hypervisor Perf events for KVM Book3s-HV\"\n--\narch/powerpc/kvm/Kconfig-181-\narch/powerpc/kvm/Kconfig:182:config KVM_BOOKE_HV\narch/powerpc/kvm/Kconfig-183-\tbool\narch/powerpc/kvm/Kconfig-184-\narch/powerpc/kvm/Kconfig:185:config KVM_EXIT_TIMING\narch/powerpc/kvm/Kconfig-186-\tbool \"Detailed exit timing\"\n--\narch/powerpc/kvm/Kconfig-195-\narch/powerpc/kvm/Kconfig:196:config KVM_E500V2\narch/powerpc/kvm/Kconfig-197-\tbool \"KVM support for PowerPC E500v2 processors\"\n--\narch/powerpc/kvm/Kconfig-209-\narch/powerpc/kvm/Kconfig:210:config KVM_E500MC\narch/powerpc/kvm/Kconfig-211-\tbool \"KVM support for PowerPC E500MC/E5500/E6500 processors\"\n--\narch/powerpc/kvm/Kconfig-224-\narch/powerpc/kvm/Kconfig:225:config KVM_MPIC\narch/powerpc/kvm/Kconfig-226-\tbool \"KVM in-kernel MPIC emulation\"\n--\narch/powerpc/kvm/Kconfig-236-\narch/powerpc/kvm/Kconfig:237:config KVM_XICS\narch/powerpc/kvm/Kconfig-238-\tbool \"KVM in-kernel XICS emulation\"\n--\narch/powerpc/kvm/Kconfig-246-\narch/powerpc/kvm/Kconfig:247:config KVM_XIVE\narch/powerpc/kvm/Kconfig-248-\tbool\n--\narch/powerpc/platforms/Kconfig=22=source \"arch/powerpc/platforms/microwatt/Kconfig\"\narch/powerpc/platforms/Kconfig-23-\narch/powerpc/platforms/Kconfig:24:config KVM_GUEST\narch/powerpc/platforms/Kconfig-25-\tbool \"KVM Guest support\"\n--\narch/riscv/kvm/Kconfig=18=if VIRTUALIZATION\narch/riscv/kvm/Kconfig-19-\narch/riscv/kvm/Kconfig:20:config KVM\narch/riscv/kvm/Kconfig-21-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/s390/kvm/Kconfig=17=if VIRTUALIZATION\narch/s390/kvm/Kconfig-18-\narch/s390/kvm/Kconfig:19:config KVM\narch/s390/kvm/Kconfig-20-\ttristate\n--\narch/s390/kvm/arm64/Kconfig-2-\narch/s390/kvm/arm64/Kconfig:3:config KVM_ARM64\narch/s390/kvm/arm64/Kconfig-4-\tdef_tristate y\n--\narch/s390/kvm/s390/Kconfig-4-\narch/s390/kvm/s390/Kconfig:5:config KVM_S390\narch/s390/kvm/s390/Kconfig-6-\tdef_tristate y\n--\narch/s390/kvm/s390/Kconfig-33-\narch/s390/kvm/s390/Kconfig:34:config KVM_S390_UCONTROL\narch/s390/kvm/s390/Kconfig-35-\tbool \"Userspace controlled virtual machines\"\n--\narch/x86/Kconfig=826=source \"arch/x86/xen/Kconfig\"\narch/x86/Kconfig-827-\narch/x86/Kconfig:828:config KVM_GUEST\narch/x86/Kconfig-829-\tbool \"KVM Guest support (including kvmclock)\"\n--\narch/x86/kvm/Kconfig=18=if VIRTUALIZATION\narch/x86/kvm/Kconfig-19-\narch/x86/kvm/Kconfig:20:config KVM_X86\narch/x86/kvm/Kconfig-21-\tdef_tristate KVM if (KVM_INTEL != n || KVM_AMD != n)\n--\narch/x86/kvm/Kconfig-50-\narch/x86/kvm/Kconfig:51:config KVM\narch/x86/kvm/Kconfig-52-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/x86/kvm/Kconfig-67-\narch/x86/kvm/Kconfig:68:config KVM_WERROR\narch/x86/kvm/Kconfig-69-\tbool \"Compile KVM with -Werror\"\n--\narch/x86/kvm/Kconfig-81-\narch/x86/kvm/Kconfig:82:config KVM_SW_PROTECTED_VM\narch/x86/kvm/Kconfig-83-\tbool \"Enable support for KVM software-protected VMs\"\n--\narch/x86/kvm/Kconfig-94-\narch/x86/kvm/Kconfig:95:config KVM_INTEL\narch/x86/kvm/Kconfig-96-\ttristate \"KVM for Intel (and compatible) processors support\"\n--\narch/x86/kvm/Kconfig-105-\narch/x86/kvm/Kconfig:106:config KVM_INTEL_PROVE_VE\narch/x86/kvm/Kconfig-107- bool \"Check that guests do not receive #VE exceptions\"\n--\narch/x86/kvm/Kconfig=121=config X86_SGX_KVM\n--\narch/x86/kvm/Kconfig-132-\narch/x86/kvm/Kconfig:133:config KVM_INTEL_TDX\narch/x86/kvm/Kconfig-134-\tbool \"Intel Trust Domain Extensions (TDX) support\"\n--\narch/x86/kvm/Kconfig-144-\narch/x86/kvm/Kconfig:145:config KVM_AMD\narch/x86/kvm/Kconfig-146-\ttristate \"KVM for AMD processors support\"\n--\narch/x86/kvm/Kconfig-154-\narch/x86/kvm/Kconfig:155:config KVM_AMD_SEV\narch/x86/kvm/Kconfig-156-\tbool \"AMD Secure Encrypted Virtualization (SEV) support\"\n--\narch/x86/kvm/Kconfig-170-\narch/x86/kvm/Kconfig:171:config KVM_IOAPIC\narch/x86/kvm/Kconfig-172-\tbool \"I/O APIC, PIC, and PIT emulation\"\n--\narch/x86/kvm/Kconfig-180-\narch/x86/kvm/Kconfig:181:config KVM_SMM\narch/x86/kvm/Kconfig-182-\tbool \"System Management Mode emulation\"\n--\narch/x86/kvm/Kconfig-191-\narch/x86/kvm/Kconfig:192:config KVM_HYPERV\narch/x86/kvm/Kconfig-193-\tbool \"Support for Microsoft Hyper-V emulation\"\n--\narch/x86/kvm/Kconfig-205-\narch/x86/kvm/Kconfig:206:config KVM_XEN\narch/x86/kvm/Kconfig-207-\tbool \"Support for Xen hypercall interface\"\n--\narch/x86/kvm/Kconfig-214-\narch/x86/kvm/Kconfig:215:config KVM_PROVE_MMU\narch/x86/kvm/Kconfig-216-\tbool \"Prove KVM MMU correctness\"\n--\narch/x86/kvm/Kconfig-227-\narch/x86/kvm/Kconfig:228:config KVM_EXTERNAL_WRITE_TRACKING\narch/x86/kvm/Kconfig-229-\tbool\narch/x86/kvm/Kconfig-230-\narch/x86/kvm/Kconfig:231:config KVM_MAX_NR_VCPUS\narch/x86/kvm/Kconfig-232-\tint \"Maximum number of vCPUs per KVM guest\"\n--\nvirt/kvm/Kconfig-3-\nvirt/kvm/Kconfig:4:config KVM_COMMON\nvirt/kvm/Kconfig-5- bool\n--\nvirt/kvm/Kconfig=39=config NEED_KVM_DIRTY_RING_WITH_BITMAP\n--\nvirt/kvm/Kconfig-42-\nvirt/kvm/Kconfig:43:config KVM_ASYNC_PF\nvirt/kvm/Kconfig-44- bool\n--\nvirt/kvm/Kconfig-46-# Toggle to switch between direct notification and batch job\nvirt/kvm/Kconfig:47:config KVM_ASYNC_PF_SYNC\nvirt/kvm/Kconfig-48- bool\n--\nvirt/kvm/Kconfig=56=config HAVE_KVM_CPU_RELAX_INTERCEPT\n--\nvirt/kvm/Kconfig-58-\nvirt/kvm/Kconfig:59:config KVM_VFIO\nvirt/kvm/Kconfig-60- bool\n--\nvirt/kvm/Kconfig=62=config HAVE_KVM_INVALID_WAKEUPS\n--\nvirt/kvm/Kconfig-64-\nvirt/kvm/Kconfig:65:config KVM_GENERIC_DIRTYLOG_READ_PROTECT\nvirt/kvm/Kconfig-66- bool\nvirt/kvm/Kconfig-67-\nvirt/kvm/Kconfig:68:config KVM_GENERIC_PRE_FAULT_MEMORY\nvirt/kvm/Kconfig-69- bool\nvirt/kvm/Kconfig-70-\nvirt/kvm/Kconfig:71:config KVM_COMPAT\nvirt/kvm/Kconfig-72- def_bool y\n--\nvirt/kvm/Kconfig=88=config HAVE_KVM_PM_NOTIFIER\n--\nvirt/kvm/Kconfig-90-\nvirt/kvm/Kconfig:91:config KVM_GENERIC_HARDWARE_ENABLING\nvirt/kvm/Kconfig-92- bool\nvirt/kvm/Kconfig-93-\nvirt/kvm/Kconfig:94:config KVM_ELIDE_TLB_FLUSH_IF_YOUNG\nvirt/kvm/Kconfig-95- bool\nvirt/kvm/Kconfig-96-\nvirt/kvm/Kconfig:97:config KVM_MMU_LOCKLESS_AGING\nvirt/kvm/Kconfig-98- bool\nvirt/kvm/Kconfig-99-\nvirt/kvm/Kconfig:100:config KVM_GENERIC_MEMORY_ATTRIBUTES\nvirt/kvm/Kconfig-101- bool\nvirt/kvm/Kconfig-102-\nvirt/kvm/Kconfig:103:config KVM_GUEST_MEMFD\nvirt/kvm/Kconfig-104- select XARRAY_MULTI\n"
} |
| 45/2 | 2026/07/06 09:46 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 169241 output: 313 thoughts: 571 Thoughts: **My KVM Configuration Strategy**
Okay, so I'm looking at how to configure this fuzzing setup for KVM, specifically considering the s390x architecture. My initial thought was that `KVM_S390` is the key, and the patch confirms that it's crucial. I noticed that the patch actually modifies `arch/s390/kvm/s390/Kconfig` to define `KVM_S390`, which replaces the general `KVM` option on s390x.
The more I dig, `KVM` is now a tristate in `arch/s390/kvm/Kconfig` that sources `s390/Kconfig` and `arm64/Kconfig`. So I need to make sure that both `KVM` and `KVM_S390` are enabled. I can accomplish this by focusing on only `KVM_S390` and then adding `KVM_ARM64` as enable configurations.
Then, there is the matter of dependencies. `KVM_ARM64` depends on `HAS_IOMEM` and `KVM`, I thought. I realize that enabling `KVM_ARM64` may not be directly reachable because `sclp.has_aef` is false in QEMU. However, it's harmless to enable, so let's include it.
The primary focus should be the core KVM changes and s390x KVM refactoring, since that is testable. They are reachable and beneficial for fuzzing. The reasoning is: the patch supports arm64 guests on s390x hosts. The s390x refactoring modifies the core KVM and VFIO ref counting logic, and is reachable for fuzzer.
In summary, here's my configuration:
* **WorthFuzzing:** `true`
* **FocusSymbols:**
* `kvm_init_with_dev`
* `vfio_device_get_kvm_safe`
* `vfio_device_put_kvm`
* `vfio_file_set_kvm`
* `gmap_prepare_memory_region`
* `gmap_commit_memory_region`
* `gmap_get_dirty_log`
* `gmap_test_age_gfn`
* `gmap_pre_fault_memory`
* `gmap_enable_skeys`
* `dat_set_storage_key`
* **EnableConfigs:**
* `KVM_S390`
* `KVM_ARM64`
|
| 46/2 | 2026/07/06 09:46 | tool | set-results |
0mError:the following configs do not exist in the kernel tree: KVM_S390, KVM_ARM64 Args: {
"EnableConfigs": [
"KVM_S390",
"KVM_ARM64"
],
"FocusSymbols": [
"kvm_init_with_dev",
"vfio_device_get_kvm_safe",
"vfio_device_put_kvm",
"vfio_file_set_kvm",
"gmap_prepare_memory_region",
"gmap_commit_memory_region",
"gmap_get_dirty_log",
"gmap_test_age_gfn",
"gmap_pre_fault_memory",
"gmap_enable_skeys",
"dat_set_storage_key"
],
"Reasoning": "The patch introduces support for running arm64 guests on s390x hosts. While the actual arm64 execution requires the Arm Execution Facility (AEF) hardware feature which is not available in QEMU, the patch also significantly refactors the existing s390x KVM code (e.g., separating gmap and s390 specific KVM code) and modifies core KVM/VFIO reference counting logic (e.g., kvm_init_with_dev, vfio_device_get_kvm_safe). These core KVM and s390x KVM refactoring changes are reachable and should be fuzzed.",
"WorthFuzzing": true
}Results: {
"error": "the following configs do not exist in the kernel tree: KVM_S390, KVM_ARM64"
} |
| 47/2 | 2026/07/06 09:46 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 170778 output: 22 thoughts: 217 Thoughts: **Investigating Newly Added Kernel Configuration Options** Okay, hold on a second. The tool is telling me that `KVM_S390` and `KVM_ARM64` aren't defined within the kernel tree. That doesn't seem right; I *know* those are core KVM options for s390 and arm64 architectures. Ah, right, the patch! The whole point of the patch is to *add* these configs. Let's double-check the diff to be absolutely sure. Okay, here we are: ``` diff --git a/arch/s390/kvm/s390/Kconfig b/arch/s390/kvm/s390/Kconfig +config KVM_S390 diff --git a/arch/s390/kvm/arm64/Kconfig b/arch/s390/kvm/arm64/Kconfig +config KVM_ARM64 ``` Yep, they're being added. Now, why is the tool still complaining? Hmmm... is it possible the tool is referencing the base tree, prior to the patch being applied? No, that can't be it. The tool is checking against my current workspace, which *already* has this patch applied, so the definitions *should* be there. Time to directly check if they are indeed present within my current workspace. |
| 48/2 | 2026/07/06 09:46 | tool | grepper |
0mArgs:{
"Expression": "config KVM_S390"
}Results: {
"Output": "arch/s390/kvm/s390/Kconfig-4-\narch/s390/kvm/s390/Kconfig:5:config KVM_S390\narch/s390/kvm/s390/Kconfig-6-\tdef_tristate y\n--\narch/s390/kvm/s390/Kconfig-33-\narch/s390/kvm/s390/Kconfig:34:config KVM_S390_UCONTROL\narch/s390/kvm/s390/Kconfig-35-\tbool \"Userspace controlled virtual machines\"\n"
} |
| 49/2 | 2026/07/06 09:46 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 171509 output: 299 thoughts: 125 Thoughts: **Troubleshooting `set-results` Config Check** Okay, so this `set-results` tool seems to have a bug in its configuration checks. It’s supposed to validate the configurations, and I suspect it's looking at the Kconfig files directly, perhaps parsing them in some way. However, it seems to have missed the newly added configs because they are included via the `source` directive. In this specific patch, I see that the problem is rooted in the addition of `source "arch/s390/kvm/s390/Kconfig"` to `arch/s390/kvm/Kconfig`. If the tool is giving me a false negative on the existence of these configs, my best bet is to check if `KVM` is already enabled as that is the main configuration. I can either use that, or just omit them if `KVM` is present. So, first things first, let's just make sure that `KVM` is actually defined, which would make my path simpler. |
| 50/2 | 2026/07/06 09:46 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"KVM"
],
"FocusSymbols": [
"kvm_init_with_dev",
"vfio_device_get_kvm_safe",
"vfio_device_put_kvm",
"vfio_file_set_kvm",
"gmap_prepare_memory_region",
"gmap_commit_memory_region",
"gmap_get_dirty_log",
"gmap_test_age_gfn",
"gmap_pre_fault_memory",
"gmap_enable_skeys",
"dat_set_storage_key"
],
"Reasoning": "The patch introduces support for running arm64 guests on s390x hosts. While the actual arm64 execution requires the Arm Execution Facility (AEF) hardware feature which is not available in QEMU, the patch also significantly refactors the existing s390x KVM code (e.g., separating gmap and s390 specific KVM code) and modifies core KVM/VFIO reference counting logic (e.g., kvm_init_with_dev, vfio_device_get_kvm_safe). These core KVM and s390x KVM refactoring changes are reachable and should be fuzzed.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"KVM"
],
"FocusSymbols": [
"kvm_init_with_dev",
"vfio_device_get_kvm_safe",
"vfio_device_put_kvm",
"vfio_file_set_kvm",
"gmap_prepare_memory_region",
"gmap_commit_memory_region",
"gmap_get_dirty_log",
"gmap_test_age_gfn",
"gmap_pre_fault_memory",
"gmap_enable_skeys",
"dat_set_storage_key"
],
"Reasoning": "The patch introduces support for running arm64 guests on s390x hosts. While the actual arm64 execution requires the Arm Execution Facility (AEF) hardware feature which is not available in QEMU, the patch also significantly refactors the existing s390x KVM code (e.g., separating gmap and s390 specific KVM code) and modifies core KVM/VFIO reference counting logic (e.g., kvm_init_with_dev, vfio_device_get_kvm_safe). These core KVM and s390x KVM refactoring changes are reachable and should be fuzzed.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|