Merge branch kvm-arm64/s390-7.4 into kvmarm-master/next

* kvm-arm64/s390-7.4:
  : \
  : Add the first attempt at sharing code with s390 in an effort to support
  : the arm64-on-s390 effort. This relies on ARM64_S390_COMMON markers in
  : relevant places.  Patches courtesy of Steffen Eiden.
  : /
  KVM: arm64: Share arm64 code with s390
  arm64: Share arm64 headers with s390
  arm64: Prepare sharing arm64 headers with s390
  KVM: arm64: Use accessor functions for core regs
  KVM: arm64: Access elements of vcpu_gp_regs individually
  arm64: sysreg: Convert SPSR_ELx to automatic register generation
  arm64: ptrace: Use constants for compat register numbers

Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
Marc Zyngier 2026-10-11 10:48:49 +01:00
commit 1d800989ce
15 changed files with 284 additions and 110 deletions

View File

@ -45,6 +45,9 @@ KBUILD_CFLAGS += $(CC_FLAGS_NO_FPU) \
KBUILD_CFLAGS += $(call cc-disable-warning, psabi)
KBUILD_AFLAGS += $(compat_vdso)
# Enable all code shared to s390
KBUILD_CPPFLAGS += -DARM64_S390_COMMON=1
ifeq ($(call rustc-min-version, 108500),y)
KBUILD_RUSTFLAGS += --target=aarch64-unknown-none-softfloat
else

View File

@ -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

View File

@ -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 __always_inline bool esr_trap_is_iabt(unsigned long esr)
{

View File

@ -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

View File

@ -44,6 +44,7 @@ enum exception_type {
bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
void kvm_skip_instr32(struct kvm_vcpu *vcpu);
#if ARM64_S390_COMMON == 1
void kvm_inject_undefined(struct kvm_vcpu *vcpu);
void kvm_inject_sync(struct kvm_vcpu *vcpu, u64 esr);
int kvm_inject_serror_esr(struct kvm_vcpu *vcpu, u64 esr);
@ -75,6 +76,8 @@ static inline int kvm_inject_serror(struct kvm_vcpu *vcpu)
void kvm_vcpu_wfi(struct kvm_vcpu *vcpu);
#endif /* ARM64_S390_COMMON == 1 */
void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu);
int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2);
int kvm_inject_nested_irq(struct kvm_vcpu *vcpu);
@ -133,12 +136,37 @@ 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(struct kvm_vcpu *vcpu)
{
return (unsigned long *)&vcpu->arch.ctxt.regs.sp;
}
static __always_inline u64 *vcpu_sp_el1(struct kvm_vcpu *vcpu)
{
return __ctxt_sys_reg(&vcpu->arch.ctxt, SP_EL1);
}
static __always_inline __u128 *vcpu_vreg(struct kvm_vcpu *vcpu, int n)
{
return &vcpu->arch.ctxt.fp_regs.vregs[n];
}
static __always_inline __u32 *vcpu_fpsr(struct kvm_vcpu *vcpu)
{
return &vcpu->arch.ctxt.fp_regs.fpsr;
}
static __always_inline __u32 *vcpu_fpcr(struct kvm_vcpu *vcpu)
{
return &vcpu->arch.ctxt.fp_regs.fpcr;
}
static __always_inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
@ -159,6 +187,7 @@ static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
*vcpu_cpsr(vcpu) |= PSR_AA32_T_BIT;
}
#if ARM64_S390_COMMON == 1
/*
* 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 +196,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 == 1 */
static inline bool vcpu_is_el2_ctxt(const struct kvm_cpu_context *ctxt)
{
switch (ctxt->regs.pstate & (PSR_MODE32_BIT | PSR_MODE_MASK)) {
@ -336,16 +367,6 @@ static __always_inline u64 kvm_vcpu_get_esr(const struct kvm_vcpu *vcpu)
return vcpu->arch.fault.esr_el2;
}
static __always_inline bool esr_abt_is_s1ptw(unsigned long esr)
{
return esr & ESR_ELx_S1PTW;
}
static __always_inline bool esr_abt_is_exec_fault(unsigned long esr)
{
return esr_trap_is_iabt(esr) && !esr_abt_is_s1ptw(esr);
}
static inline bool guest_hyp_wfx_traps_enabled(const struct kvm_vcpu *vcpu)
{
u64 esr = kvm_vcpu_get_esr(vcpu);
@ -389,6 +410,12 @@ static inline u64 kvm_vcpu_get_disr(const struct kvm_vcpu *vcpu)
return vcpu->arch.fault.disr_el1;
}
#if ARM64_S390_COMMON == 1
static __always_inline bool esr_abt_is_s1ptw(unsigned long esr)
{
return esr & ESR_ELx_S1PTW;
}
static inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu)
{
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_xVC_IMM_MASK;
@ -456,6 +483,13 @@ 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 == 1 */
static __always_inline bool esr_abt_is_exec_fault(unsigned long esr)
{
return esr_trap_is_iabt(esr) && !esr_abt_is_s1ptw(esr);
}
static inline
bool kvm_vcpu_trap_is_permission_fault(const struct kvm_vcpu *vcpu)
{
@ -479,6 +513,7 @@ static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
return ESR_ELx_SYS64_ISS_RT(esr);
}
#if ARM64_S390_COMMON == 1
static inline bool esr_abt_is_write_fault(unsigned long esr)
{
if (esr_abt_is_s1ptw(esr)) {
@ -508,6 +543,8 @@ static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
return esr_abt_is_write_fault(kvm_vcpu_get_esr(vcpu));
}
#endif /* ARM64_S390_COMMON == 1 */
static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
{
return __vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
@ -549,6 +586,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
return vcpu_read_sys_reg(vcpu, r) & bit;
}
#if ARM64_S390_COMMON == 1
static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
unsigned long data,
unsigned int len)
@ -624,6 +662,8 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
vcpu_set_flag((v), e); \
} while (0)
#endif /* ARM64_S390_COMMON == 1 */
/*
* Returns a 'sanitised' view of CPTR_EL2, translating from nVHE to the VHE
* format if E2H isn't set.
@ -725,6 +765,12 @@ static inline void vcpu_set_hcrx(struct kvm_vcpu *vcpu)
}
}
static inline void kvm_reset_fpsimd(struct kvm_vcpu *vcpu)
{
memset(&vcpu->arch.ctxt.fp_regs, 0, sizeof(vcpu->arch.ctxt.fp_regs));
}
#if ARM64_S390_COMMON == 1
/* Reset a vcpu's core registers. */
static inline void kvm_reset_vcpu_core(struct kvm_vcpu *vcpu)
{
@ -738,15 +784,19 @@ static inline void kvm_reset_vcpu_core(struct kvm_vcpu *vcpu)
pstate = VCPU_RESET_PSTATE_EL1;
/* Reset core registers */
memset(vcpu_gp_regs(vcpu), 0, sizeof(*vcpu_gp_regs(vcpu)));
memset(&vcpu->arch.ctxt.fp_regs, 0, sizeof(vcpu->arch.ctxt.fp_regs));
memset(vcpu_gp_regs(vcpu), 0, sizeof(vcpu_gp_regs(vcpu)));
*vcpu_pc(vcpu) = 0;
*vcpu_sp_el0(vcpu) = 0;
kvm_reset_fpsimd(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_gp_regs(vcpu)->pstate = pstate;
*vcpu_cpsr(vcpu) = pstate;
}
#endif /* ARM64_S390_COMMON == 1 */
/* PSCI reset handling for a vcpu. */
static inline void kvm_reset_vcpu_psci(struct kvm_vcpu *vcpu,
struct vcpu_reset_state *reset_state)

View File

@ -41,6 +41,7 @@
#define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
#if ARM64_S390_COMMON == 1
#define KVM_VCPU_MAX_FEATURES 10
#define KVM_VCPU_VALID_FEATURES (BIT(KVM_VCPU_MAX_FEATURES) - 1)
@ -59,6 +60,50 @@
#define KVM_REQ_VGIC_PROCESS_UPDATE KVM_ARCH_REQ(11)
#define KVM_REQ_RELOAD_GICv5 KVM_ARCH_REQ(12)
/* Bit indices for kvm_arch::flags */
enum {
/*
* If we encounter a data abort without valid instruction syndrome
* information, report this to user space. User space can (and
* should) opt in to this feature if KVM_CAP_ARM_NISV_TO_USER is
* supported.
*/
KVM_ARCH_FLAG_RETURN_NISV_IO_ABORT_TO_USER,
/* Memory Tagging Extension enabled for the guest */
KVM_ARCH_FLAG_MTE_ENABLED,
/* At least one vCPU has ran in the VM */
KVM_ARCH_FLAG_HAS_RAN_ONCE,
/* The vCPU feature set for the VM is configured */
KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED,
/* PSCI SYSTEM_SUSPEND enabled for the guest */
KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED,
/* VM counter offset */
KVM_ARCH_FLAG_VM_COUNTER_OFFSET,
/* Timer PPIs made immutable */
KVM_ARCH_FLAG_TIMER_PPIS_IMMUTABLE,
/* Initial ID reg values loaded */
KVM_ARCH_FLAG_ID_REGS_INITIALIZED,
/* Fine-Grained UNDEF initialised */
KVM_ARCH_FLAG_FGU_INITIALIZED,
/* SVE exposed to guest */
KVM_ARCH_FLAG_GUEST_HAS_SVE,
/* MIDR_EL1, REVIDR_EL1, and AIDR_EL1 are writable from userspace */
KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS,
/* Unhandled SEAs are taken to userspace */
KVM_ARCH_FLAG_EXIT_SEA,
/* No further ID register changes possible */
KVM_ARCH_FLAG_ID_REGS_FINAL,
};
struct vcpu_reset_state {
unsigned long pc;
unsigned long r0;
bool be;
bool reset;
};
#endif /* ARM64_S390_COMMON == 1 */
#define KVM_DIRTY_LOG_MANUAL_CAPS (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \
KVM_DIRTY_LOG_INITIALLY_SET)
@ -357,37 +402,6 @@ struct kvm_arch {
/* Protects VM-scoped configuration data */
struct mutex config_lock;
/*
* If we encounter a data abort without valid instruction syndrome
* information, report this to user space. User space can (and
* should) opt in to this feature if KVM_CAP_ARM_NISV_TO_USER is
* supported.
*/
#define KVM_ARCH_FLAG_RETURN_NISV_IO_ABORT_TO_USER 0
/* Memory Tagging Extension enabled for the guest */
#define KVM_ARCH_FLAG_MTE_ENABLED 1
/* At least one vCPU has ran in the VM */
#define KVM_ARCH_FLAG_HAS_RAN_ONCE 2
/* The vCPU feature set for the VM is configured */
#define KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED 3
/* PSCI SYSTEM_SUSPEND enabled for the guest */
#define KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED 4
/* VM counter offset */
#define KVM_ARCH_FLAG_VM_COUNTER_OFFSET 5
/* Timer PPIs made immutable */
#define KVM_ARCH_FLAG_TIMER_PPIS_IMMUTABLE 6
/* Initial ID reg values loaded */
#define KVM_ARCH_FLAG_ID_REGS_INITIALIZED 7
/* Fine-Grained UNDEF initialised */
#define KVM_ARCH_FLAG_FGU_INITIALIZED 8
/* SVE exposed to guest */
#define KVM_ARCH_FLAG_GUEST_HAS_SVE 9
/* MIDR_EL1, REVIDR_EL1, and AIDR_EL1 are writable from userspace */
#define KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS 10
/* Unhandled SEAs are taken to userspace */
#define KVM_ARCH_FLAG_EXIT_SEA 11
/* No further ID register changes possible */
#define KVM_ARCH_FLAG_ID_REGS_FINAL 12
unsigned long flags;
/* VM-wide vCPU feature set */
@ -856,13 +870,6 @@ extern s64 kvm_nvhe_sym(hyp_physvirt_offset);
extern u64 kvm_nvhe_sym(hyp_cpu_logical_map)[NR_CPUS];
#define hyp_cpu_logical_map CHOOSE_NVHE_SYM(hyp_cpu_logical_map)
struct vcpu_reset_state {
unsigned long pc;
unsigned long r0;
bool be;
bool reset;
};
struct vncr_tlb;
struct kvm_vcpu_arch {
@ -972,6 +979,7 @@ struct kvm_vcpu_arch {
pid_t pid;
};
#if ARM64_S390_COMMON == 1
/*
* Each 'flag' is composed of a comma-separated triplet:
*
@ -1067,6 +1075,11 @@ struct kvm_vcpu_arch {
/* pKVM VCPU setup completed */
#define VCPU_PKVM_FINALIZED __vcpu_single_flag(cflags, BIT(2))
int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature);
bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
#define kvm_arm_vcpu_sve_finalized(vcpu) vcpu_get_flag(vcpu, VCPU_SVE_FINALIZED)
/* Exception pending */
#define PENDING_EXCEPTION __vcpu_single_flag(iflags, BIT(0))
/*
@ -1125,6 +1138,8 @@ struct kvm_vcpu_arch {
/* KVM is currently emulating an L2 to L1 exception */
#define IN_NESTED_EXCEPTION __vcpu_single_flag(sflags, BIT(9))
#endif /* ARM64_S390_COMMON == 1 */
#define vcpu_sve_max_vq(vcpu) sve_vq_from_vl((vcpu)->arch.sve_max_vl)
#define vcpu_sve_zcr_elx(vcpu) \
@ -1182,7 +1197,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
@ -1263,14 +1278,6 @@ struct kvm_vcpu_stat {
u64 exits;
};
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu);
int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
int __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
struct kvm_vcpu_events *events);
@ -1304,6 +1311,15 @@ int __init populate_nv_trap_config(void);
void kvm_calculate_traps(struct kvm_vcpu *vcpu);
#if ARM64_S390_COMMON == 1
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu);
int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
/* 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);
@ -1311,6 +1327,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 == 1 */
/*
* 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
@ -1487,11 +1505,6 @@ struct kvm *kvm_arch_alloc_vm(void);
#define vcpu_is_protected(vcpu) kvm_vm_is_protected((vcpu)->kvm)
int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature);
bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
#define kvm_arm_vcpu_sve_finalized(vcpu) vcpu_get_flag(vcpu, VCPU_SVE_FINALIZED)
#define kvm_has_mte(kvm) \
(system_supports_mte() && \
test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &(kvm)->arch.flags))
@ -1508,11 +1521,15 @@ static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature)
return test_bit(feature, ka->vcpu_features);
}
#if ARM64_S390_COMMON == 1
#define kvm_vcpu_has_feature(k, f) __vcpu_has_feature(&(k)->arch, (f))
#define vcpu_has_feature(v, f) __vcpu_has_feature(&(v)->kvm->arch, (f))
#define kvm_vcpu_initialized(v) vcpu_get_flag(v, VCPU_INITIALIZED)
#endif /* ARM64_S390_COMMON == 1 */
int kvm_trng_call(struct kvm_vcpu *vcpu);
#ifdef CONFIG_KVM
extern phys_addr_t hyp_mem_base;

View File

@ -26,6 +26,8 @@
#define GIC_PRIO_PSR_I_SET GICV3_PRIO_PSR_I_SET
#if ARM64_S390_COMMON == 1
/* Additional SPSR bits not exposed in the UABI */
#define PSR_MODE_THREAD_BIT (1 << 0)
#define PSR_IL_BIT (1 << 20)
@ -66,6 +68,8 @@
#define PSR_AA32_IT_MASK 0x0600fc00 /* If-Then execution state mask */
#define PSR_AA32_GE_MASK 0x000f0000
#endif /* ARM64_S390_COMMON == 1 */
#ifdef CONFIG_CPU_BIG_ENDIAN
#define PSR_AA32_ENDSTATE PSR_AA32_E_BIT
#else
@ -102,26 +106,48 @@
#define COMPAT_USER_SZ 296
/* Architecturally defined mapping between AArch32 and AArch64 registers */
enum {
__compat_fp = 11,
__compat_sp = 13,
__compat_lr = 14,
__compat_sp_hyp = 15,
__compat_lr_irq = 16,
__compat_sp_irq = 17,
__compat_lr_svc = 18,
__compat_sp_svc = 19,
__compat_lr_abt = 20,
__compat_sp_abt = 21,
__compat_lr_und = 22,
__compat_sp_und = 23,
__compat_r8_fiq = 24,
__compat_r9_fiq = 25,
__compat_r10_fiq = 26,
__compat_r11_fiq = 27,
__compat_r12_fiq = 28,
__compat_sp_fiq = 29,
__compat_lr_fiq = 30,
};
#define compat_usr(x) regs[(x)]
#define compat_fp regs[11]
#define compat_sp regs[13]
#define compat_lr regs[14]
#define compat_sp_hyp regs[15]
#define compat_lr_irq regs[16]
#define compat_sp_irq regs[17]
#define compat_lr_svc regs[18]
#define compat_sp_svc regs[19]
#define compat_lr_abt regs[20]
#define compat_sp_abt regs[21]
#define compat_lr_und regs[22]
#define compat_sp_und regs[23]
#define compat_r8_fiq regs[24]
#define compat_r9_fiq regs[25]
#define compat_r10_fiq regs[26]
#define compat_r11_fiq regs[27]
#define compat_r12_fiq regs[28]
#define compat_sp_fiq regs[29]
#define compat_lr_fiq regs[30]
#define compat_fp regs[__compat_fp]
#define compat_sp regs[__compat_sp]
#define compat_lr regs[__compat_lr]
#define compat_sp_hyp regs[__compat_sp_hyp]
#define compat_lr_irq regs[__compat_lr_irq]
#define compat_sp_irq regs[__compat_sp_irq]
#define compat_lr_svc regs[__compat_lr_svc]
#define compat_sp_svc regs[__compat_sp_svc]
#define compat_lr_abt regs[__compat_lr_abt]
#define compat_sp_abt regs[__compat_sp_abt]
#define compat_lr_und regs[__compat_lr_und]
#define compat_sp_und regs[__compat_sp_und]
#define compat_r8_fiq regs[__compat_r8_fiq]
#define compat_r9_fiq regs[__compat_r9_fiq]
#define compat_r10_fiq regs[__compat_r10_fiq]
#define compat_r11_fiq regs[__compat_r11_fiq]
#define compat_r12_fiq regs[__compat_r12_fiq]
#define compat_sp_fiq regs[__compat_sp_fiq]
#define compat_lr_fiq regs[__compat_lr_fiq]
static inline unsigned long compat_psr_to_pstate(const unsigned long psr)
{

View File

@ -16,6 +16,8 @@
#include <asm/gpr-num.h>
#if ARM64_S390_COMMON == 1
/*
* ARMv8 ARM reserves the following encoding for system registers:
* (Ref: ARMv8 ARM, Section: "System instruction class encoding overview",
@ -50,6 +52,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 == 1 */
#ifndef CONFIG_BROKEN_GAS_INST
#ifdef __ASSEMBLER__
@ -123,6 +127,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)
#if ARM64_S390_COMMON == 1
/* 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)
@ -295,7 +301,6 @@
#define SYS_APGAKEYLO_EL1 sys_reg(3, 0, 2, 3, 0)
#define SYS_APGAKEYHI_EL1 sys_reg(3, 0, 2, 3, 1)
#define SYS_SPSR_EL1 sys_reg(3, 0, 4, 0, 0)
#define SYS_ELR_EL1 sys_reg(3, 0, 4, 0, 1)
#define SYS_ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0)
@ -518,7 +523,6 @@
#define SYS_VTTBR_EL2 sys_reg(3, 4, 2, 1, 0)
#define SYS_HAFGRTR_EL2 sys_reg(3, 4, 3, 1, 6)
#define SYS_SPSR_EL2 sys_reg(3, 4, 4, 0, 0)
#define SYS_ELR_EL2 sys_reg(3, 4, 4, 0, 1)
#define SYS_SP_EL1 sys_reg(3, 4, 4, 1, 0)
#define SYS_SPSR_irq sys_reg(3, 4, 4, 3, 0)
@ -604,7 +608,6 @@
#define SYS_BRBCR_EL12 sys_reg(2, 5, 9, 0, 0)
#define SYS_TTBR0_EL12 sys_reg(3, 5, 2, 0, 0)
#define SYS_TTBR1_EL12 sys_reg(3, 5, 2, 0, 1)
#define SYS_SPSR_EL12 sys_reg(3, 5, 4, 0, 0)
#define SYS_ELR_EL12 sys_reg(3, 5, 4, 0, 1)
#define SYS_AFSR0_EL12 sys_reg(3, 5, 5, 1, 0)
#define SYS_AFSR1_EL12 sys_reg(3, 5, 5, 1, 1)
@ -835,6 +838,8 @@
#define SCTLR_ELx_A (BIT(1))
#define SCTLR_ELx_M (BIT(0))
#endif /* ARM64_S390_COMMON == 1 */
#ifdef CONFIG_CPU_BIG_ENDIAN
#define ENDIAN_SET_EL2 SCTLR_ELx_EE
#else
@ -869,6 +874,7 @@
SCTLR_EL1_LSMAOE | SCTLR_EL1_nTLSMD | SCTLR_EL1_EIS | \
SCTLR_EL1_TSCXT | SCTLR_EL1_EOS)
#if ARM64_S390_COMMON == 1
/* MAIR_ELx memory attributes (used by Linux) */
#define MAIR_ATTR_DEVICE_nGnRnE UL(0x00)
#define MAIR_ATTR_DEVICE_nGnRE UL(0x04)
@ -1116,6 +1122,8 @@
#define GICV5_GIC_VDPEND_TYPE_MASK GENMASK_ULL(31, 29)
#define GICV5_GIC_VDPEND_ID_MASK GENMASK_ULL(23, 0)
#endif /* ARM64_S390_COMMON == 1 */
#define gicr_insn(insn) read_sysreg_s(GICV5_OP_GICR_##insn)
#define gic_insn(v, insn) write_sysreg_s(v, GICV5_OP_GIC_##insn)
@ -1265,6 +1273,8 @@
par; \
})
#if ARM64_S390_COMMON == 1
#define SYS_FIELD_VALUE(reg, field, val) reg##_##field##_##val
#define SYS_FIELD_GET(reg, field, val) \
@ -1277,6 +1287,8 @@
FIELD_PREP(reg##_##field##_MASK, \
SYS_FIELD_VALUE(reg, field, val))
#endif
#endif /* ARM64_S390_COMMON == 1 */
#endif /* __ASSEMBLER__ */
#endif /* __ASM_SYSREG_H */

View File

@ -1616,6 +1616,7 @@ static unsigned long system_supported_vcpu_features(void)
return features;
}
#if ARM64_S390_COMMON == 1
static int kvm_vcpu_init_check_features(struct kvm_vcpu *vcpu,
const struct kvm_vcpu_init *init)
{
@ -1669,6 +1670,8 @@ static bool kvm_vcpu_init_changed(struct kvm_vcpu *vcpu,
KVM_VCPU_MAX_FEATURES);
}
#endif /* ARM64_S390_COMMON == 1 */
static int kvm_setup_vcpu(struct kvm_vcpu *vcpu)
{
struct kvm *kvm = vcpu->kvm;

View File

@ -62,6 +62,7 @@ const struct kvm_stats_header kvm_vcpu_stats_header = {
sizeof(kvm_vcpu_stats_desc),
};
#if ARM64_S390_COMMON == 1
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 vcpu_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 vcpu_vreg(vcpu, off);
case KVM_REG_ARM_CORE_REG(fp_regs.fpsr):
return &vcpu->arch.ctxt.fp_regs.fpsr;
return vcpu_fpsr(vcpu);
case KVM_REG_ARM_CORE_REG(fp_regs.fpcr):
return &vcpu->arch.ctxt.fp_regs.fpcr;
return vcpu_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 == 1 */
#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;
}
#if ARM64_S390_COMMON == 1
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 == 1 */
static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
{
const unsigned int slices = vcpu_sve_slices(vcpu);

View File

@ -276,12 +276,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_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_lr_und] = return_address;
break;
}

View File

@ -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);
}

View File

@ -470,7 +470,7 @@ static inline bool kvm_hyp_handle_mops(struct kvm_vcpu *vcpu, u64 *exit_code)
u64 spsr;
*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);
/*
@ -902,7 +902,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?
*/

View File

@ -10,6 +10,7 @@
#include "trace.h"
#if ARM64_S390_COMMON == 1
void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data)
{
void *datap = NULL;
@ -258,3 +259,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 == 1 */

View File

@ -401,6 +401,57 @@ Res0 3:1
Field 0 SO
EndSysreg
SysregFields SPSR_ELx
Res0 63:37
Field 36 UINJ
Field 35 PACM
Field 34 EXLOCK
Res0 33
Field 32 PM
Field 31 N
Field 30 Z
Field 29 C
Field 28 V
Res0 27:26
Field 25 TCO
Field 24 DIT
Field 23 UAO
Field 22 PAN
Field 21 SS
Field 20 IL
Res0 19:14
Field 13 ALLINT
Field 12 SSBS
Field 11:10 BTYPE
Field 9 D
Field 8 A
Field 7 I
Field 6 F
Res0 5
Field 4 M4
Enum 3:0 M
0b0000 EL0
0b0100 EL1t
0b0101 EL1h
0b1000 EL2t
0b1001 EL2h
0b1100 EL3t
0b1101 EL3h
EndEnum
EndSysregFields
Sysreg SPSR_EL1 3 0 4 0 0
Fields SPSR_ELx
EndSysreg
Sysreg SPSR_EL2 3 4 4 0 0
Fields SPSR_ELx
EndSysreg
Sysreg SPSR_EL12 3 5 4 0 0
Mapping SPSR_EL1
EndSysreg
Sysreg ID_PFR0_EL1 3 0 0 1 0
Res0 63:32
UnsignedEnum 31:28 RAS