Commit 8800b7c4 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

KVM: arm64: Add RMW specific sysreg accessor



In a number of cases, we perform a Read-Modify-Write operation on
a system register, meaning that we would apply the RESx masks twice.

Instead, provide a new accessor that performs this RMW operation,
allowing the masks to be applied exactly once per operation.

Reviewed-by: default avatarMiguel Luis <miguel.luis@oracle.com>
Reviewed-by: default avatarOliver Upton <oliver.upton@linux.dev>
Link: https://lore.kernel.org/r/20250603070824.1192795-3-maz@kernel.org


Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parent 6678791e
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -1118,6 +1118,17 @@ u64 kvm_vcpu_apply_reg_masks(const struct kvm_vcpu *, enum vcpu_sysreg, u64);
		ctxt_sys_reg(ctxt, (r)) = __v;				\
	} while (0)

#define __vcpu_rmw_sys_reg(v, r, op, val)				\
	do {								\
		const struct kvm_cpu_context *ctxt = &(v)->arch.ctxt;	\
		u64 __v = ctxt_sys_reg(ctxt, (r));			\
		__v op (val);						\
		if (vcpu_has_nv((v)) && (r) >= __SANITISED_REG_START__)	\
			__v = kvm_vcpu_apply_reg_masks((v), (r), __v);	\
									\
		ctxt_sys_reg(ctxt, (r)) = __v;				\
	} while (0)

#define __vcpu_sys_reg(v,r)						\
	(*({								\
		const struct kvm_cpu_context *ctxt = &(v)->arch.ctxt;	\
+2 −2
Original line number Diff line number Diff line
@@ -216,9 +216,9 @@ void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu)
void kvm_debug_handle_oslar(struct kvm_vcpu *vcpu, u64 val)
{
	if (val & OSLAR_EL1_OSLK)
		__vcpu_sys_reg(vcpu, OSLSR_EL1) |= OSLSR_EL1_OSLK;
		__vcpu_rmw_sys_reg(vcpu, OSLSR_EL1, |=, OSLSR_EL1_OSLK);
	else
		__vcpu_sys_reg(vcpu, OSLSR_EL1) &= ~OSLSR_EL1_OSLK;
		__vcpu_rmw_sys_reg(vcpu, OSLSR_EL1, &=, ~OSLSR_EL1_OSLK);

	preempt_disable();
	kvm_arch_vcpu_put(vcpu);
+2 −2
Original line number Diff line number Diff line
@@ -70,8 +70,8 @@ static void __sysreg_save_vel2_state(struct kvm_vcpu *vcpu)
		 */
		val = read_sysreg_el1(SYS_CNTKCTL);
		val &= CNTKCTL_VALID_BITS;
		__vcpu_sys_reg(vcpu, CNTHCTL_EL2) &= ~CNTKCTL_VALID_BITS;
		__vcpu_sys_reg(vcpu, CNTHCTL_EL2) |= val;
		__vcpu_rmw_sys_reg(vcpu, CNTHCTL_EL2, &=, ~CNTKCTL_VALID_BITS);
		__vcpu_rmw_sys_reg(vcpu, CNTHCTL_EL2, |=, val);
	}

	__vcpu_assign_sys_reg(vcpu, SP_EL2,	 read_sysreg(sp_el1));
+1 −1
Original line number Diff line number Diff line
@@ -1757,7 +1757,7 @@ int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu)

out:
	for (enum vcpu_sysreg sr = __SANITISED_REG_START__; sr < NR_SYS_REGS; sr++)
		(void)__vcpu_sys_reg(vcpu, sr);
		__vcpu_rmw_sys_reg(vcpu, sr, |=, 0);

	return 0;
}
+5 −5
Original line number Diff line number Diff line
@@ -510,7 +510,7 @@ static void kvm_pmu_counter_increment(struct kvm_vcpu *vcpu,
			continue;

		/* Mark overflow */
		__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
		__vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, |=, BIT(i));

		if (kvm_pmu_counter_can_chain(pmc))
			kvm_pmu_counter_increment(vcpu, BIT(i + 1),
@@ -556,7 +556,7 @@ static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
	perf_event->attr.sample_period = period;
	perf_event->hw.sample_period = period;

	__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
	__vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, |=, BIT(idx));

	if (kvm_pmu_counter_can_chain(pmc))
		kvm_pmu_counter_increment(vcpu, BIT(idx + 1),
@@ -914,9 +914,9 @@ void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu)
{
	u64 mask = kvm_pmu_implemented_counter_mask(vcpu);

	__vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= mask;
	__vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= mask;
	__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= mask;
	__vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, &=, mask);
	__vcpu_rmw_sys_reg(vcpu, PMINTENSET_EL1, &=, mask);
	__vcpu_rmw_sys_reg(vcpu, PMCNTENSET_EL0, &=, mask);

	kvm_pmu_reprogram_counter_mask(vcpu, mask);
}
Loading