Commit d0d81e03 authored by Oliver Upton's avatar Oliver Upton
Browse files

KVM: arm64: Load VPIDR_EL2 with the VM's MIDR_EL1 value

Userspace will soon be able to change the value of MIDR_EL1. Prepare by
loading VPIDR_EL2 with the guest value for non-nested VMs.

Since VPIDR_EL2 is set for any VM, get rid of the NV-specific cleanup of
reloading the hardware value on vcpu_put(). And for nVHE, load the
hardware value before switching to the host.

Link: https://lore.kernel.org/r/20250225005401.679536-4-oliver.upton@linux.dev


Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parent b4043e7c
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -43,6 +43,11 @@ static inline u64 *ctxt_mdscr_el1(struct kvm_cpu_context *ctxt)
	return &ctxt_sys_reg(ctxt, MDSCR_EL1);
}

static inline u64 ctxt_midr_el1(struct kvm_cpu_context *ctxt)
{
	return read_cpuid_id();
}

static inline void __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
{
	*ctxt_mdscr_el1(ctxt)	= read_sysreg(mdscr_el1);
@@ -168,8 +173,9 @@ static inline void __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)
}

static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt,
					      u64 mpidr)
					      u64 midr, u64 mpidr)
{
	write_sysreg(midr,				vpidr_el2);
	write_sysreg(mpidr,				vmpidr_el2);

	if (has_vhe() ||
+3 −1
Original line number Diff line number Diff line
@@ -28,7 +28,9 @@ void __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)

void __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
{
	__sysreg_restore_el1_state(ctxt, ctxt_sys_reg(ctxt, MPIDR_EL1));
	u64 midr = ctxt_midr_el1(ctxt);

	__sysreg_restore_el1_state(ctxt, midr, ctxt_sys_reg(ctxt, MPIDR_EL1));
	__sysreg_restore_common_state(ctxt);
	__sysreg_restore_user_state(ctxt);
	__sysreg_restore_el2_return_state(ctxt);
+10 −18
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ static void __sysreg_restore_vel2_state(struct kvm_vcpu *vcpu)
	write_sysreg(__vcpu_sys_reg(vcpu, PAR_EL1),	par_el1);
	write_sysreg(__vcpu_sys_reg(vcpu, TPIDR_EL1),	tpidr_el1);

	write_sysreg(ctxt_midr_el1(&vcpu->arch.ctxt),			vpidr_el2);
	write_sysreg(__vcpu_sys_reg(vcpu, MPIDR_EL1),			vmpidr_el2);
	write_sysreg_el1(__vcpu_sys_reg(vcpu, MAIR_EL2),		SYS_MAIR);
	write_sysreg_el1(__vcpu_sys_reg(vcpu, VBAR_EL2),		SYS_VBAR);
@@ -191,7 +192,7 @@ void __vcpu_load_switch_sysregs(struct kvm_vcpu *vcpu)
{
	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
	struct kvm_cpu_context *host_ctxt;
	u64 mpidr;
	u64 midr, mpidr;

	host_ctxt = host_data_ptr(host_ctxt);
	__sysreg_save_user_state(host_ctxt);
@@ -220,23 +221,18 @@ void __vcpu_load_switch_sysregs(struct kvm_vcpu *vcpu)
		__sysreg_restore_vel2_state(vcpu);
	} else {
		if (vcpu_has_nv(vcpu)) {
			/*
			 * Use the guest hypervisor's VPIDR_EL2 when in a
			 * nested state. The hardware value of MIDR_EL1 gets
			 * restored on put.
			 */
			write_sysreg(ctxt_sys_reg(guest_ctxt, VPIDR_EL2), vpidr_el2);

			/*
			 * As we're restoring a nested guest, set the value
			 * provided by the guest hypervisor.
			 */
			midr = ctxt_sys_reg(guest_ctxt, VPIDR_EL2);
			mpidr = ctxt_sys_reg(guest_ctxt, VMPIDR_EL2);
		} else {
			midr = ctxt_midr_el1(guest_ctxt);
			mpidr = ctxt_sys_reg(guest_ctxt, MPIDR_EL1);
		}

		__sysreg_restore_el1_state(guest_ctxt, mpidr);
		__sysreg_restore_el1_state(guest_ctxt, midr, mpidr);
	}

	vcpu_set_flag(vcpu, SYSREGS_ON_CPU);
@@ -271,9 +267,5 @@ void __vcpu_put_switch_sysregs(struct kvm_vcpu *vcpu)
	/* Restore host user state */
	__sysreg_restore_user_state(host_ctxt);

	/* If leaving a nesting guest, restore MIDR_EL1 default view */
	if (vcpu_has_nv(vcpu))
		write_sysreg(read_cpuid_id(),	vpidr_el2);

	vcpu_clear_flag(vcpu, SYSREGS_ON_CPU);
}