Commit a0162020 authored by Marc Zyngier's avatar Marc Zyngier Committed by Oliver Upton
Browse files

KVM: arm64: Extend masking facility to arbitrary registers



We currently only use the masking (RES0/RES1) facility for VNCR
registers, as they are memory-based and thus easy to sanitise.

But we could apply the same thing to other registers if we:

- split the sanitisation from __VNCR_START__
- apply the sanitisation when reading from a HW register

This involves a new "marker" in the vcpu_sysreg enum, which
defines the point at which the sanitisation applies (the VNCR
registers being of course after this marker).

Whle we are at it, rename kvm_vcpu_sanitise_vncr_reg() to
kvm_vcpu_apply_reg_masks(), which is vaguely more explicit,
and harden set_sysreg_masks() against setting masks for
random registers...

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Reviewed-by: default avatarJoey Gouly <joey.gouly@arm.com>
Link: https://lore.kernel.org/r/20241023145345.1613824-10-maz@kernel.org


Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parent 14ca930d
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -374,7 +374,7 @@ struct kvm_arch {

	u64 ctr_el0;

	/* Masks for VNCR-baked sysregs */
	/* Masks for VNCR-backed and general EL2 sysregs */
	struct kvm_sysreg_masks	*sysreg_masks;

	/*
@@ -408,6 +408,9 @@ struct kvm_vcpu_fault_info {
	r = __VNCR_START__ + ((VNCR_ ## r) / 8),	\
	__after_##r = __MAX__(__before_##r - 1, r)

#define MARKER(m)				\
	m, __after_##m = m - 1

enum vcpu_sysreg {
	__INVALID_SYSREG__,   /* 0 is reserved as an invalid value */
	MPIDR_EL1,	/* MultiProcessor Affinity Register */
@@ -494,7 +497,11 @@ enum vcpu_sysreg {
	CNTHV_CTL_EL2,
	CNTHV_CVAL_EL2,

	__VNCR_START__,	/* Any VNCR-capable reg goes after this point */
	/* Anything from this can be RES0/RES1 sanitised */
	MARKER(__SANITISED_REG_START__),

	/* Any VNCR-capable reg goes after this point */
	MARKER(__VNCR_START__),

	VNCR(SCTLR_EL1),/* System Control Register */
	VNCR(ACTLR_EL1),/* Auxiliary Control Register */
@@ -554,7 +561,7 @@ struct kvm_sysreg_masks {
	struct {
		u64	res0;
		u64	res1;
	} mask[NR_SYS_REGS - __VNCR_START__];
	} mask[NR_SYS_REGS - __SANITISED_REG_START__];
};

struct kvm_cpu_context {
@@ -1002,13 +1009,13 @@ static inline u64 *___ctxt_sys_reg(const struct kvm_cpu_context *ctxt, int r)

#define ctxt_sys_reg(c,r)	(*__ctxt_sys_reg(c,r))

u64 kvm_vcpu_sanitise_vncr_reg(const struct kvm_vcpu *, enum vcpu_sysreg);
u64 kvm_vcpu_apply_reg_masks(const struct kvm_vcpu *, enum vcpu_sysreg, u64);
#define __vcpu_sys_reg(v,r)						\
	(*({								\
		const struct kvm_cpu_context *ctxt = &(v)->arch.ctxt;	\
		u64 *__r = __ctxt_sys_reg(ctxt, (r));			\
		if (vcpu_has_nv((v)) && (r) >= __VNCR_START__)		\
			*__r = kvm_vcpu_sanitise_vncr_reg((v), (r));	\
		if (vcpu_has_nv((v)) && (r) >= __SANITISED_REG_START__)	\
			*__r = kvm_vcpu_apply_reg_masks((v), (r), *__r);\
		__r;							\
	}))

+8 −4
Original line number Diff line number Diff line
@@ -933,15 +933,15 @@ static void limit_nv_id_regs(struct kvm *kvm)
	kvm_set_vm_id_reg(kvm, SYS_ID_AA64DFR0_EL1, val);
}

u64 kvm_vcpu_sanitise_vncr_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg sr)
u64 kvm_vcpu_apply_reg_masks(const struct kvm_vcpu *vcpu,
			     enum vcpu_sysreg sr, u64 v)
{
	u64 v = ctxt_sys_reg(&vcpu->arch.ctxt, sr);
	struct kvm_sysreg_masks *masks;

	masks = vcpu->kvm->arch.sysreg_masks;

	if (masks) {
		sr -= __VNCR_START__;
		sr -= __SANITISED_REG_START__;

		v &= ~masks->mask[sr].res0;
		v |= masks->mask[sr].res1;
@@ -952,7 +952,11 @@ u64 kvm_vcpu_sanitise_vncr_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg sr)

static void set_sysreg_masks(struct kvm *kvm, int sr, u64 res0, u64 res1)
{
	int i = sr - __VNCR_START__;
	int i = sr - __SANITISED_REG_START__;

	BUILD_BUG_ON(!__builtin_constant_p(sr));
	BUILD_BUG_ON(sr < __SANITISED_REG_START__);
	BUILD_BUG_ON(sr >= NR_SYS_REGS);

	kvm->arch.sysreg_masks->mask[i].res0 = res0;
	kvm->arch.sysreg_masks->mask[i].res1 = res1;
+3 −0
Original line number Diff line number Diff line
@@ -189,6 +189,9 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg)

		/* Get the current version of the EL1 counterpart. */
		WARN_ON(!__vcpu_read_sys_reg_from_cpu(el1r, &val));
		if (reg >= __SANITISED_REG_START__)
			val = kvm_vcpu_apply_reg_masks(vcpu, reg, val);

		return val;
	}