Commit 45ce0314 authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

Merge tag 'kvmarm-fixes-6.10-1' of...

Merge tag 'kvmarm-fixes-6.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD

KVM/arm64 fixes for 6.10, take #1

- Large set of FP/SVE fixes for pKVM, addressing the fallout
  from the per-CPU data rework and making sure that the host
  is not involved in the FP/SVE switching any more

- Allow FEAT_BTI to be enabled with NV now that FEAT_PAUTH
  is copletely supported

- Fix for the respective priorities of Failed PAC, Illegal
  Execution state and Instruction Abort exceptions

- Fix the handling of AArch32 instruction traps failing their
  condition code, which was broken by the introduction of
  ESR_EL2.ISS2

- Allow vpcus running in AArch32 state to be restored in
  System mode

- Fix AArch32 GPR restore that would lose the 64 bit state
  under some conditions
parents b50788f7 afb91f5f
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -146,7 +146,7 @@
/* Coprocessor traps */
.macro __init_el2_cptr
	__check_hvhe .LnVHE_\@, x1
	mov	x0, #(CPACR_EL1_FPEN_EL1EN | CPACR_EL1_FPEN_EL0EN)
	mov	x0, #CPACR_ELx_FPEN
	msr	cpacr_el1, x0
	b	.Lskip_set_cptr_\@
.LnVHE_\@:
@@ -277,7 +277,7 @@

	// (h)VHE case
	mrs	x0, cpacr_el1			// Disable SVE traps
	orr	x0, x0, #(CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN)
	orr	x0, x0, #CPACR_ELx_ZEN
	msr	cpacr_el1, x0
	b	.Lskip_set_cptr_\@

@@ -298,7 +298,7 @@

	// (h)VHE case
	mrs	x0, cpacr_el1			// Disable SME traps
	orr	x0, x0, #(CPACR_EL1_SMEN_EL0EN | CPACR_EL1_SMEN_EL1EN)
	orr	x0, x0, #CPACR_ELx_SMEN
	msr	cpacr_el1, x0
	b	.Lskip_set_cptr_sme_\@

+6 −0
Original line number Diff line number Diff line
@@ -305,6 +305,12 @@
				 GENMASK(19, 14) |	\
				 BIT(11))

#define CPTR_VHE_EL2_RES0	(GENMASK(63, 32) |	\
				 GENMASK(27, 26) |	\
				 GENMASK(23, 22) |	\
				 GENMASK(19, 18) |	\
				 GENMASK(15, 0))

/* Hyp Debug Configuration Register bits */
#define MDCR_EL2_E2TB_MASK	(UL(0x3))
#define MDCR_EL2_E2TB_SHIFT	(UL(24))
+66 −5
Original line number Diff line number Diff line
@@ -557,6 +557,68 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
		vcpu_set_flag((v), e);					\
	} while (0)

#define __build_check_all_or_none(r, bits)				\
	BUILD_BUG_ON(((r) & (bits)) && ((r) & (bits)) != (bits))

#define __cpacr_to_cptr_clr(clr, set)					\
	({								\
		u64 cptr = 0;						\
									\
		if ((set) & CPACR_ELx_FPEN)				\
			cptr |= CPTR_EL2_TFP;				\
		if ((set) & CPACR_ELx_ZEN)				\
			cptr |= CPTR_EL2_TZ;				\
		if ((set) & CPACR_ELx_SMEN)				\
			cptr |= CPTR_EL2_TSM;				\
		if ((clr) & CPACR_ELx_TTA)				\
			cptr |= CPTR_EL2_TTA;				\
		if ((clr) & CPTR_EL2_TAM)				\
			cptr |= CPTR_EL2_TAM;				\
		if ((clr) & CPTR_EL2_TCPAC)				\
			cptr |= CPTR_EL2_TCPAC;				\
									\
		cptr;							\
	})

#define __cpacr_to_cptr_set(clr, set)					\
	({								\
		u64 cptr = 0;						\
									\
		if ((clr) & CPACR_ELx_FPEN)				\
			cptr |= CPTR_EL2_TFP;				\
		if ((clr) & CPACR_ELx_ZEN)				\
			cptr |= CPTR_EL2_TZ;				\
		if ((clr) & CPACR_ELx_SMEN)				\
			cptr |= CPTR_EL2_TSM;				\
		if ((set) & CPACR_ELx_TTA)				\
			cptr |= CPTR_EL2_TTA;				\
		if ((set) & CPTR_EL2_TAM)				\
			cptr |= CPTR_EL2_TAM;				\
		if ((set) & CPTR_EL2_TCPAC)				\
			cptr |= CPTR_EL2_TCPAC;				\
									\
		cptr;							\
	})

#define cpacr_clear_set(clr, set)					\
	do {								\
		BUILD_BUG_ON((set) & CPTR_VHE_EL2_RES0);		\
		BUILD_BUG_ON((clr) & CPACR_ELx_E0POE);			\
		__build_check_all_or_none((clr), CPACR_ELx_FPEN);	\
		__build_check_all_or_none((set), CPACR_ELx_FPEN);	\
		__build_check_all_or_none((clr), CPACR_ELx_ZEN);	\
		__build_check_all_or_none((set), CPACR_ELx_ZEN);	\
		__build_check_all_or_none((clr), CPACR_ELx_SMEN);	\
		__build_check_all_or_none((set), CPACR_ELx_SMEN);	\
									\
		if (has_vhe() || has_hvhe())				\
			sysreg_clear_set(cpacr_el1, clr, set);		\
		else							\
			sysreg_clear_set(cptr_el2,			\
					 __cpacr_to_cptr_clr(clr, set),	\
					 __cpacr_to_cptr_set(clr, set));\
	} while (0)

static __always_inline void kvm_write_cptr_el2(u64 val)
{
	if (has_vhe() || has_hvhe())
@@ -570,17 +632,16 @@ static __always_inline u64 kvm_get_reset_cptr_el2(struct kvm_vcpu *vcpu)
	u64 val;

	if (has_vhe()) {
		val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN |
		       CPACR_EL1_ZEN_EL1EN);
		val = (CPACR_ELx_FPEN | CPACR_EL1_ZEN_EL1EN);
		if (cpus_have_final_cap(ARM64_SME))
			val |= CPACR_EL1_SMEN_EL1EN;
	} else if (has_hvhe()) {
		val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN);
		val = CPACR_ELx_FPEN;

		if (!vcpu_has_sve(vcpu) || !guest_owns_fp_regs())
			val |= CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN;
			val |= CPACR_ELx_ZEN;
		if (cpus_have_final_cap(ARM64_SME))
			val |= CPACR_EL1_SMEN_EL1EN | CPACR_EL1_SMEN_EL0EN;
			val |= CPACR_ELx_SMEN;
	} else {
		val = CPTR_NVHE_EL2_RES1;

+24 −1
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ static inline enum kvm_mode kvm_get_mode(void) { return KVM_MODE_NONE; };
DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);

extern unsigned int __ro_after_init kvm_sve_max_vl;
extern unsigned int __ro_after_init kvm_host_sve_max_vl;
int __init kvm_arm_init_sve(void);

u32 __attribute_const__ kvm_target_cpu(void);
@@ -521,6 +522,20 @@ struct kvm_cpu_context {
	u64 *vncr_array;
};

struct cpu_sve_state {
	__u64 zcr_el1;

	/*
	 * Ordering is important since __sve_save_state/__sve_restore_state
	 * relies on it.
	 */
	__u32 fpsr;
	__u32 fpcr;

	/* Must be SVE_VQ_BYTES (128 bit) aligned. */
	__u8 sve_regs[];
};

/*
 * This structure is instantiated on a per-CPU basis, and contains
 * data that is:
@@ -534,7 +549,15 @@ struct kvm_cpu_context {
 */
struct kvm_host_data {
	struct kvm_cpu_context host_ctxt;
	struct user_fpsimd_state *fpsimd_state;	/* hyp VA */

	/*
	 * All pointers in this union are hyp VA.
	 * sve_state is only used in pKVM and if system_supports_sve().
	 */
	union {
		struct user_fpsimd_state *fpsimd_state;
		struct cpu_sve_state *sve_state;
	};

	/* Ownership of the FP regs */
	enum {
+3 −1
Original line number Diff line number Diff line
@@ -111,7 +111,8 @@ void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu);

void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
void __sve_restore_state(void *sve_pffr, u32 *fpsr);
void __sve_save_state(void *sve_pffr, u32 *fpsr, int save_ffr);
void __sve_restore_state(void *sve_pffr, u32 *fpsr, int restore_ffr);

u64 __guest_enter(struct kvm_vcpu *vcpu);

@@ -142,5 +143,6 @@ extern u64 kvm_nvhe_sym(id_aa64smfr0_el1_sys_val);

extern unsigned long kvm_nvhe_sym(__icache_flags);
extern unsigned int kvm_nvhe_sym(kvm_arm_vmid_bits);
extern unsigned int kvm_nvhe_sym(kvm_host_sve_max_vl);

#endif /* __ARM64_KVM_HYP_H__ */
Loading