Commit 3bb7dceb authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

Merge tag 'kvmarm-fixes-6.14-2' of...

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

KVM/arm64 fixes for 6.14, take #2

- Large set of fixes for vector handling, specially in the interactions
  between host and guest state. This fixes a number of bugs affecting
  actual deployments, and greatly simplifies the FP/SIMD/SVE handling.
  Thanks to Mark Rutland for dealing with this thankless task.

- Fix an ugly race between vcpu and vgic creation/init, resulting in
  unexpected behaviours.

- Fix use of kernel VAs at EL2 when emulating timers with nVHE.

- Small set of pKVM improvements and cleanups.
parents 43fb96ae b3aa9283
Loading
Loading
Loading
Loading
+0 −42
Original line number Diff line number Diff line
@@ -605,48 +605,6 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
					 __cpacr_to_cptr_set(clr, set));\
	} while (0)

static __always_inline void kvm_write_cptr_el2(u64 val)
{
	if (has_vhe() || has_hvhe())
		write_sysreg(val, cpacr_el1);
	else
		write_sysreg(val, cptr_el2);
}

/* Resets the value of cptr_el2 when returning to the host. */
static __always_inline void __kvm_reset_cptr_el2(struct kvm *kvm)
{
	u64 val;

	if (has_vhe()) {
		val = (CPACR_EL1_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;

		if (!kvm_has_sve(kvm) || !guest_owns_fp_regs())
			val |= CPACR_EL1_ZEN;
		if (cpus_have_final_cap(ARM64_SME))
			val |= CPACR_EL1_SMEN;
	} else {
		val = CPTR_NVHE_EL2_RES1;

		if (kvm_has_sve(kvm) && guest_owns_fp_regs())
			val |= CPTR_EL2_TZ;
		if (!cpus_have_final_cap(ARM64_SME))
			val |= CPTR_EL2_TSM;
	}

	kvm_write_cptr_el2(val);
}

#ifdef __KVM_NVHE_HYPERVISOR__
#define kvm_reset_cptr_el2(v)	__kvm_reset_cptr_el2(kern_hyp_va((v)->kvm))
#else
#define kvm_reset_cptr_el2(v)	__kvm_reset_cptr_el2((v)->kvm)
#endif

/*
 * Returns a 'sanitised' view of CPTR_EL2, translating from nVHE to the VHE
 * format if E2H isn't set.
+6 −18
Original line number Diff line number Diff line
@@ -100,7 +100,7 @@ static inline void push_hyp_memcache(struct kvm_hyp_memcache *mc,
static inline void *pop_hyp_memcache(struct kvm_hyp_memcache *mc,
				     void *(*to_va)(phys_addr_t phys))
{
	phys_addr_t *p = to_va(mc->head);
	phys_addr_t *p = to_va(mc->head & PAGE_MASK);

	if (!mc->nr_pages)
		return NULL;
@@ -615,8 +615,6 @@ struct cpu_sve_state {
struct kvm_host_data {
#define KVM_HOST_DATA_FLAG_HAS_SPE			0
#define KVM_HOST_DATA_FLAG_HAS_TRBE			1
#define KVM_HOST_DATA_FLAG_HOST_SVE_ENABLED		2
#define KVM_HOST_DATA_FLAG_HOST_SME_ENABLED		3
#define KVM_HOST_DATA_FLAG_TRBE_ENABLED			4
#define KVM_HOST_DATA_FLAG_EL1_TRACING_CONFIGURED	5
	unsigned long flags;
@@ -624,23 +622,13 @@ struct kvm_host_data {
	struct kvm_cpu_context host_ctxt;

	/*
	 * All pointers in this union are hyp VA.
	 * 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;
	};

	union {
		/* HYP VA pointer to the host storage for FPMR */
		u64	*fpmr_ptr;
		/*
		 * Used by pKVM only, as it needs to provide storage
		 * for the host
		 */
	/* Used by pKVM only. */
	u64	fpmr;
	};

	/* Ownership of the FP regs */
	enum {
+0 −25
Original line number Diff line number Diff line
@@ -1694,31 +1694,6 @@ void fpsimd_signal_preserve_current_state(void)
		sve_to_fpsimd(current);
}

/*
 * Called by KVM when entering the guest.
 */
void fpsimd_kvm_prepare(void)
{
	if (!system_supports_sve())
		return;

	/*
	 * KVM does not save host SVE state since we can only enter
	 * the guest from a syscall so the ABI means that only the
	 * non-saved SVE state needs to be saved.  If we have left
	 * SVE enabled for performance reasons then update the task
	 * state to be FPSIMD only.
	 */
	get_cpu_fpsimd_context();

	if (test_and_clear_thread_flag(TIF_SVE)) {
		sve_to_fpsimd(current);
		current->thread.fp_type = FP_STATE_FPSIMD;
	}

	put_cpu_fpsimd_context();
}

/*
 * Associate current's FPSIMD context with this cpu
 * The caller must have ownership of the cpu FPSIMD context before calling
+7 −9
Original line number Diff line number Diff line
@@ -447,21 +447,19 @@ static void kvm_timer_update_status(struct arch_timer_context *ctx, bool level)
static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
				 struct arch_timer_context *timer_ctx)
{
	int ret;

	kvm_timer_update_status(timer_ctx, new_level);

	timer_ctx->irq.level = new_level;
	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_irq(timer_ctx),
				   timer_ctx->irq.level);

	if (!userspace_irqchip(vcpu->kvm)) {
		ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu,
	if (userspace_irqchip(vcpu->kvm))
		return;

	kvm_vgic_inject_irq(vcpu->kvm, vcpu,
			    timer_irq(timer_ctx),
			    timer_ctx->irq.level,
			    timer_ctx);
		WARN_ON(ret);
	}
}

/* Only called for a fully emulated timer */
+0 −8
Original line number Diff line number Diff line
@@ -2481,14 +2481,6 @@ static void finalize_init_hyp_mode(void)
			per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_state =
				kern_hyp_va(sve_state);
		}
	} else {
		for_each_possible_cpu(cpu) {
			struct user_fpsimd_state *fpsimd_state;

			fpsimd_state = &per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->host_ctxt.fp_regs;
			per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->fpsimd_state =
				kern_hyp_va(fpsimd_state);
		}
	}
}

Loading