Commit 377d0e5d authored by Oliver Upton's avatar Oliver Upton
Browse files

Merge branch kvm-arm64/ctr-el0 into kvmarm/next



* kvm-arm64/ctr-el0:
  : Support for user changes to CTR_EL0, courtesy of Sebastian Ott
  :
  : Allow userspace to change the guest-visible value of CTR_EL0 for a VM,
  : so long as the requested value represents a subset of features supported
  : by hardware. In other words, prevent the VMM from over-promising the
  : capabilities of hardware.
  :
  : Make this happen by fitting CTR_EL0 into the existing infrastructure for
  : feature ID registers.
  KVM: selftests: Assert that MPIDR_EL1 is unchanged across vCPU reset
  KVM: arm64: nv: Unfudge ID_AA64PFR0_EL1 masking
  KVM: selftests: arm64: Test writes to CTR_EL0
  KVM: arm64: rename functions for invariant sys regs
  KVM: arm64: show writable masks for feature registers
  KVM: arm64: Treat CTR_EL0 as a VM feature ID register
  KVM: arm64: unify code to prepare traps
  KVM: arm64: nv: Use accessors for modifying ID registers
  KVM: arm64: Add helper for writing ID regs
  KVM: arm64: Use read-only helper for reading VM ID registers
  KVM: arm64: Make idregs debugfs iterator search sysreg table directly
  KVM: arm64: Get sys_reg encoding from descriptor in idregs_debug_show()

Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parents 435a9f60 b0539664
Loading
Loading
Loading
Loading
+9 −31
Original line number Diff line number Diff line
@@ -69,41 +69,19 @@ static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)

static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
{
	if (!vcpu_has_run_once(vcpu))
		vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
	if (has_vhe() || has_hvhe())
		vcpu->arch.hcr_el2 |= HCR_E2H;
	if (cpus_have_final_cap(ARM64_HAS_RAS_EXTN)) {
		/* route synchronous external abort exceptions to EL2 */
		vcpu->arch.hcr_el2 |= HCR_TEA;
		/* trap error record accesses */
		vcpu->arch.hcr_el2 |= HCR_TERR;
	}

	if (cpus_have_final_cap(ARM64_HAS_STAGE2_FWB)) {
		vcpu->arch.hcr_el2 |= HCR_FWB;
	} else {
	/*
	 * For non-FWB CPUs, we trap VM ops (HCR_EL2.TVM) until M+C
	 * get set in SCTLR_EL1 such that we can detect when the guest
	 * MMU gets turned on and do the necessary cache maintenance
	 * then.
	 */
	if (!cpus_have_final_cap(ARM64_HAS_STAGE2_FWB))
		vcpu->arch.hcr_el2 |= HCR_TVM;
}

	if (cpus_have_final_cap(ARM64_HAS_EVT) &&
	    !cpus_have_final_cap(ARM64_MISMATCHED_CACHE_TYPE))
		vcpu->arch.hcr_el2 |= HCR_TID4;
	else
		vcpu->arch.hcr_el2 |= HCR_TID2;

	if (vcpu_el1_is_32bit(vcpu))
		vcpu->arch.hcr_el2 &= ~HCR_RW;

	if (kvm_has_mte(vcpu->kvm))
		vcpu->arch.hcr_el2 |= HCR_ATA;
}

static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
{
	return (unsigned long *)&vcpu->arch.hcr_el2;
+22 −4
Original line number Diff line number Diff line
@@ -362,11 +362,11 @@ struct kvm_arch {
	 * Atomic access to multiple idregs are guarded by kvm_arch.config_lock.
	 */
#define IDREG_IDX(id)		(((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))
#define IDX_IDREG(idx)		sys_reg(3, 0, 0, ((idx) >> 3) + 1, (idx) & Op2_mask)
#define IDREG(kvm, id)		((kvm)->arch.id_regs[IDREG_IDX(id)])
#define KVM_ARM_ID_REG_NUM	(IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
	u64 id_regs[KVM_ARM_ID_REG_NUM];

	u64 ctr_el0;

	/* Masks for VNCR-baked sysregs */
	struct kvm_sysreg_masks	*sysreg_masks;

@@ -1180,7 +1180,7 @@ int __init populate_nv_trap_config(void);
bool lock_all_vcpus(struct kvm *kvm);
void unlock_all_vcpus(struct kvm *kvm);

void kvm_init_sysreg(struct kvm_vcpu *);
void kvm_calculate_traps(struct kvm_vcpu *vcpu);

/* MMIO helpers */
void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
@@ -1391,6 +1391,24 @@ static inline void kvm_hyp_reserve(void) { }
void kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu);
bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu);

static inline u64 *__vm_id_reg(struct kvm_arch *ka, u32 reg)
{
	switch (reg) {
	case sys_reg(3, 0, 0, 1, 0) ... sys_reg(3, 0, 0, 7, 7):
		return &ka->id_regs[IDREG_IDX(reg)];
	case SYS_CTR_EL0:
		return &ka->ctr_el0;
	default:
		WARN_ON_ONCE(1);
		return NULL;
	}
}

#define kvm_read_vm_id_reg(kvm, reg)					\
	({ u64 __val = *__vm_id_reg(&(kvm)->arch, reg); __val; })

void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);

#define __expand_field_sign_unsigned(id, fld, val)			\
	((u64)SYS_FIELD_VALUE(id, fld, val))

@@ -1407,7 +1425,7 @@ bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu);

#define get_idreg_field_unsigned(kvm, id, fld)				\
	({								\
		u64 __val = IDREG((kvm), SYS_##id);			\
		u64 __val = kvm_read_vm_id_reg((kvm), SYS_##id);	\
		FIELD_GET(id##_##fld##_MASK, __val);			\
	})

+1 −1
Original line number Diff line number Diff line
@@ -836,7 +836,7 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
	 * This needs to happen after NV has imposed its own restrictions on
	 * the feature set
	 */
	kvm_init_sysreg(vcpu);
	kvm_calculate_traps(vcpu);

	ret = kvm_timer_enable(vcpu);
	if (ret)
+123 −135
Original line number Diff line number Diff line
@@ -799,24 +799,23 @@ void kvm_arch_flush_shadow_all(struct kvm *kvm)
 * This list should get updated as new features get added to the NV
 * support, and new extension to the architecture.
 */
static u64 limit_nv_id_reg(u32 id, u64 val)
static void limit_nv_id_regs(struct kvm *kvm)
{
	u64 tmp;
	u64 val, tmp;

	switch (id) {
	case SYS_ID_AA64ISAR0_EL1:
	/* Support everything but TME */
	val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64ISAR0_EL1);
	val &= ~NV_FTR(ISAR0, TME);
		break;
	kvm_set_vm_id_reg(kvm, SYS_ID_AA64ISAR0_EL1, val);

	case SYS_ID_AA64ISAR1_EL1:
	/* Support everything but Spec Invalidation and LS64 */
	val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64ISAR1_EL1);
	val &= ~(NV_FTR(ISAR1, LS64)	|
		 NV_FTR(ISAR1, SPECRES));
		break;
	kvm_set_vm_id_reg(kvm, SYS_ID_AA64ISAR1_EL1, val);

	case SYS_ID_AA64PFR0_EL1:
	/* No AMU, MPAM, S-EL2, RAS or SVE */
	val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1);
	val &= ~(GENMASK_ULL(55, 52)	|
		 NV_FTR(PFR0, AMU)	|
		 NV_FTR(PFR0, MPAM)	|
@@ -830,17 +829,17 @@ static u64 limit_nv_id_reg(u32 id, u64 val)
	val |= FIELD_PREP(NV_FTR(PFR0, EL1), 0b0001);
	val |= FIELD_PREP(NV_FTR(PFR0, EL2), 0b0001);
	val |= FIELD_PREP(NV_FTR(PFR0, EL3), 0b0001);
		break;
	kvm_set_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1, val);

	case SYS_ID_AA64PFR1_EL1:
	/* Only support BTI, SSBS, CSV2_frac */
	val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64PFR1_EL1);
	val &= (NV_FTR(PFR1, BT)	|
		NV_FTR(PFR1, SSBS)	|
		NV_FTR(PFR1, CSV2_frac));
		break;
	kvm_set_vm_id_reg(kvm, SYS_ID_AA64PFR1_EL1, val);

	case SYS_ID_AA64MMFR0_EL1:
	/* Hide ECV, ExS, Secure Memory */
	val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64MMFR0_EL1);
	val &= ~(NV_FTR(MMFR0, ECV)		|
		 NV_FTR(MMFR0, EXS)		|
		 NV_FTR(MMFR0, TGRAN4_2)	|
@@ -883,18 +882,18 @@ static u64 limit_nv_id_reg(u32 id, u64 val)
		val &= ~NV_FTR(MMFR0, PARANGE);
		val |= FIELD_PREP(NV_FTR(MMFR0, PARANGE), 0b0101);
	}
		break;
	kvm_set_vm_id_reg(kvm, SYS_ID_AA64MMFR0_EL1, val);

	case SYS_ID_AA64MMFR1_EL1:
	val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64MMFR1_EL1);
	val &= (NV_FTR(MMFR1, HCX)	|
		NV_FTR(MMFR1, PAN)	|
		NV_FTR(MMFR1, LO)	|
		NV_FTR(MMFR1, HPDS)	|
		NV_FTR(MMFR1, VH)	|
		NV_FTR(MMFR1, VMIDBits));
		break;
	kvm_set_vm_id_reg(kvm, SYS_ID_AA64MMFR1_EL1, val);

	case SYS_ID_AA64MMFR2_EL1:
	val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64MMFR2_EL1);
	val &= ~(NV_FTR(MMFR2, BBM)	|
		 NV_FTR(MMFR2, TTL)	|
		 GENMASK_ULL(47, 44)	|
@@ -904,17 +903,16 @@ static u64 limit_nv_id_reg(u32 id, u64 val)

	/* Force TTL support */
	val |= FIELD_PREP(NV_FTR(MMFR2, TTL), 0b0001);
		break;
	kvm_set_vm_id_reg(kvm, SYS_ID_AA64MMFR2_EL1, val);

	case SYS_ID_AA64MMFR4_EL1:
	val = 0;
	if (!cpus_have_final_cap(ARM64_HAS_HCR_NV1))
		val |= FIELD_PREP(NV_FTR(MMFR4, E2H0),
				  ID_AA64MMFR4_EL1_E2H0_NI_NV1);
		break;
	kvm_set_vm_id_reg(kvm, SYS_ID_AA64MMFR4_EL1, val);

	case SYS_ID_AA64DFR0_EL1:
	/* Only limited support for PMU, Debug, BPs and WPs */
	val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64DFR0_EL1);
	val &= (NV_FTR(DFR0, PMUVer)	|
		NV_FTR(DFR0, WRPs)	|
		NV_FTR(DFR0, BRPs)	|
@@ -926,15 +924,7 @@ static u64 limit_nv_id_reg(u32 id, u64 val)
		val &= ~NV_FTR(DFR0, DebugVer);
		val |= FIELD_PREP(NV_FTR(DFR0, DebugVer), 0b0111);
	}
		break;

	default:
		/* Unknown register, just wipe it clean */
		val = 0;
		break;
	}

	return val;
	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)
@@ -979,9 +969,7 @@ int kvm_init_nv_sysregs(struct kvm *kvm)
		goto out;
	}

	for (int i = 0; i < KVM_ARM_ID_REG_NUM; i++)
		kvm->arch.id_regs[i] = limit_nv_id_reg(IDX_IDREG(i),
						       kvm->arch.id_regs[i]);
	limit_nv_id_regs(kvm);

	/* VTTBR_EL2 */
	res0 = res1 = 0;
+1 −1
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@ static u32 __kvm_pmu_event_mask(unsigned int pmuver)

static u32 kvm_pmu_event_mask(struct kvm *kvm)
{
	u64 dfr0 = IDREG(kvm, SYS_ID_AA64DFR0_EL1);
	u64 dfr0 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64DFR0_EL1);
	u8 pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, dfr0);

	return __kvm_pmu_event_mask(pmuver);
Loading