Commit 4abc8108 authored by Marc Zyngier's avatar Marc Zyngier Committed by Junhao He
Browse files

KVM: arm64: Exclude FP ownership from kvm_vcpu_arch

mainline inclusion
from mainline-v6.9-rc1
commit 5294afdbf45aced5295fe5941c58b40c41c23800
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8EC9K
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=5294afdbf45aced5295fe5941c58b40c41c23800



--------------------------------

In retrospect, it is fairly obvious that the FP state ownership
is only meaningful for a given CPU, and that locating this
information in the vcpu was just a mistake.

Move the ownership tracking into the host data structure, and
rename it from fp_state to fp_owner, which is a better description
(name suggested by Mark Brown).

Reviewed-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Signed-off-by: default avatarJunhao He <hejunhao3@huawei.com>
parent 122733f3
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -616,7 +616,7 @@ static __always_inline u64 kvm_get_reset_cptr_el2(struct kvm_vcpu *vcpu)
		val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN);

		if (!vcpu_has_sve(vcpu) ||
		    (vcpu->arch.fp_state != FP_STATE_GUEST_OWNED))
		    (*host_data_ptr(fp_owner) != FP_STATE_GUEST_OWNED))
			val |= CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN;
		if (cpus_have_final_cap(ARM64_SME))
			val |= CPACR_EL1_SMEN_EL1EN | CPACR_EL1_SMEN_EL0EN;
@@ -624,7 +624,7 @@ static __always_inline u64 kvm_get_reset_cptr_el2(struct kvm_vcpu *vcpu)
		val = CPTR_NVHE_EL2_RES1;

		if (vcpu_has_sve(vcpu) &&
		    (vcpu->arch.fp_state == FP_STATE_GUEST_OWNED))
		    (*host_data_ptr(fp_owner) == FP_STATE_GUEST_OWNED))
			val |= CPTR_EL2_TZ;
		if (cpus_have_final_cap(ARM64_SME))
			val &= ~CPTR_EL2_TSM;
+7 −7
Original line number Diff line number Diff line
@@ -465,6 +465,13 @@ struct kvm_host_data {
	struct kvm_cpu_context host_ctxt;
	struct user_fpsimd_state *fpsimd_state;	/* hyp VA */

	/* Ownership of the FP regs */
	enum {
		FP_STATE_FREE,
		FP_STATE_HOST_OWNED,
		FP_STATE_GUEST_OWNED,
	} fp_owner;

	/*
	 * host_debug_state contains the host registers which are
	 * saved and restored during world switches.
@@ -540,13 +547,6 @@ struct kvm_vcpu_arch {
	/* Exception Information */
	struct kvm_vcpu_fault_info fault;

	/* Ownership of the FP regs */
	enum {
		FP_STATE_FREE,
		FP_STATE_HOST_OWNED,
		FP_STATE_GUEST_OWNED,
	} fp_state;

	/* Configuration flags, set once and for all before the vcpu can run */
	u8 cflags;

+0 −6
Original line number Diff line number Diff line
@@ -449,12 +449,6 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)

	vcpu->arch.mmu_page_cache.gfp_zero = __GFP_ZERO;

	/*
	 * Default value for the FP state, will be overloaded at load
	 * time if we support FP (pretty likely)
	 */
	vcpu->arch.fp_state = FP_STATE_FREE;

	/* Set up the timer */
	kvm_timer_vcpu_init(vcpu);

+5 −5
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
	 * guest in kvm_arch_vcpu_ctxflush_fp() and override this to
	 * FP_STATE_FREE if the flag set.
	 */
	vcpu->arch.fp_state = FP_STATE_HOST_OWNED;
	*host_data_ptr(fp_owner) = FP_STATE_HOST_OWNED;
	*host_data_ptr(fpsimd_state) = kern_hyp_va(&current->thread.uw.fpsimd_state);

	vcpu_clear_flag(vcpu, HOST_SVE_ENABLED);
@@ -109,7 +109,7 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
		 * been saved, this is very unlikely to happen.
		 */
		if (read_sysreg_s(SYS_SVCR) & (SVCR_SM_MASK | SVCR_ZA_MASK)) {
			vcpu->arch.fp_state = FP_STATE_FREE;
			*host_data_ptr(fp_owner) = FP_STATE_FREE;
			fpsimd_save_and_flush_cpu_state();
		}
	}
@@ -125,7 +125,7 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
void kvm_arch_vcpu_ctxflush_fp(struct kvm_vcpu *vcpu)
{
	if (test_thread_flag(TIF_FOREIGN_FPSTATE))
		vcpu->arch.fp_state = FP_STATE_FREE;
		*host_data_ptr(fp_owner) = FP_STATE_FREE;
}

/*
@@ -141,7 +141,7 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)

	WARN_ON_ONCE(!irqs_disabled());

	if (vcpu->arch.fp_state == FP_STATE_GUEST_OWNED) {
	if (*host_data_ptr(fp_owner) == FP_STATE_GUEST_OWNED) {

		/*
		 * Currently we do not support SME guests so SVCR is
@@ -194,7 +194,7 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
		isb();
	}

	if (vcpu->arch.fp_state == FP_STATE_GUEST_OWNED) {
	if (*host_data_ptr(fp_owner) == FP_STATE_GUEST_OWNED) {
		if (vcpu_has_sve(vcpu)) {
			__vcpu_sys_reg(vcpu, ZCR_EL1) = read_sysreg_el1(SYS_ZCR);

+3 −3
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ extern struct kvm_exception_table_entry __stop___kvm_ex_table;
/* Check whether the FP regs are owned by the guest */
static inline bool guest_owns_fp_regs(struct kvm_vcpu *vcpu)
{
	return vcpu->arch.fp_state == FP_STATE_GUEST_OWNED;
	return *host_data_ptr(fp_owner) == FP_STATE_GUEST_OWNED;
}

/* Save the 32-bit only FPSIMD system register state */
@@ -364,7 +364,7 @@ static bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
	isb();

	/* Write out the host state if it's in the registers */
	if (vcpu->arch.fp_state == FP_STATE_HOST_OWNED)
	if (*host_data_ptr(fp_owner) == FP_STATE_HOST_OWNED)
		__fpsimd_save_state(*host_data_ptr(fpsimd_state));

	/* Restore the guest state */
@@ -377,7 +377,7 @@ static bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
	if (!(read_sysreg(hcr_el2) & HCR_RW))
		write_sysreg(__vcpu_sys_reg(vcpu, FPEXC32_EL2), fpexc32_el2);

	vcpu->arch.fp_state = FP_STATE_GUEST_OWNED;
	*host_data_ptr(fp_owner) = FP_STATE_GUEST_OWNED;

	return true;
}
Loading