Commit 6d4b81e2 authored by Oliver Upton's avatar Oliver Upton
Browse files

Merge branch kvm-arm64/nv-pmu into kvmarm/next



* kvm-arm64/nv-pmu:
  : Support for vEL2 PMU controls
  :
  : Align the vEL2 PMU support with the current state of non-nested KVM,
  : including:
  :
  :  - Trap routing, with the annoying complication of EL2 traps that apply
  :    in Host EL0
  :
  :  - PMU emulation, using the correct configuration bits depending on
  :    whether a counter falls in the hypervisor or guest range of PMCs
  :
  :  - Perf event swizzling across nested boundaries, as the event filtering
  :    needs to be remapped to cope with vEL2
  KVM: arm64: nv: Reprogram PMU events affected by nested transition
  KVM: arm64: nv: Apply EL2 event filtering when in hyp context
  KVM: arm64: nv: Honor MDCR_EL2.HLP
  KVM: arm64: nv: Honor MDCR_EL2.HPME
  KVM: arm64: Add helpers to determine if PMC counts at a given EL
  KVM: arm64: nv: Adjust range of accessible PMCs according to HPMN
  KVM: arm64: Rename kvm_pmu_valid_counter_mask()
  KVM: arm64: nv: Advertise support for FEAT_HPMN0
  KVM: arm64: nv: Describe trap behaviour of MDCR_EL2.HPMN
  KVM: arm64: nv: Honor MDCR_EL2.{TPM, TPMCR} in Host EL0
  KVM: arm64: nv: Reinject traps that take effect in Host EL0
  KVM: arm64: nv: Rename BEHAVE_FORWARD_ANY
  KVM: arm64: nv: Allow coarse-grained trap combos to use complex traps
  KVM: arm64: Describe RES0/RES1 bits of MDCR_EL2
  arm64: sysreg: Add new definitions for ID_AA64DFR0_EL1
  arm64: sysreg: Migrate MDCR_EL2 definition to table
  arm64: sysreg: Describe ID_AA64DFR2_EL1 fields

Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parents 4bc1a880 ae323e03
Loading
Loading
Loading
Loading
+0 −29
Original line number Diff line number Diff line
@@ -312,35 +312,6 @@
				 GENMASK(19, 18) |	\
				 GENMASK(15, 0))

/* Hyp Debug Configuration Register bits */
#define MDCR_EL2_E2TB_MASK	(UL(0x3))
#define MDCR_EL2_E2TB_SHIFT	(UL(24))
#define MDCR_EL2_HPMFZS		(UL(1) << 36)
#define MDCR_EL2_HPMFZO		(UL(1) << 29)
#define MDCR_EL2_MTPME		(UL(1) << 28)
#define MDCR_EL2_TDCC		(UL(1) << 27)
#define MDCR_EL2_HLP		(UL(1) << 26)
#define MDCR_EL2_HCCD		(UL(1) << 23)
#define MDCR_EL2_TTRF		(UL(1) << 19)
#define MDCR_EL2_HPMD		(UL(1) << 17)
#define MDCR_EL2_TPMS		(UL(1) << 14)
#define MDCR_EL2_E2PB_MASK	(UL(0x3))
#define MDCR_EL2_E2PB_SHIFT	(UL(12))
#define MDCR_EL2_TDRA		(UL(1) << 11)
#define MDCR_EL2_TDOSA		(UL(1) << 10)
#define MDCR_EL2_TDA		(UL(1) << 9)
#define MDCR_EL2_TDE		(UL(1) << 8)
#define MDCR_EL2_HPME		(UL(1) << 7)
#define MDCR_EL2_TPM		(UL(1) << 6)
#define MDCR_EL2_TPMCR		(UL(1) << 5)
#define MDCR_EL2_HPMN_MASK	(UL(0x1F))
#define MDCR_EL2_RES0		(GENMASK(63, 37) |	\
				 GENMASK(35, 30) |	\
				 GENMASK(25, 24) |	\
				 GENMASK(22, 20) |	\
				 BIT(18) |		\
				 GENMASK(16, 15))

/*
 * FGT register definitions
 *
+5 −0
Original line number Diff line number Diff line
@@ -225,6 +225,11 @@ static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)
	return vcpu_has_nv(vcpu) && __is_hyp_ctxt(&vcpu->arch.ctxt);
}

static inline bool vcpu_is_host_el0(const struct kvm_vcpu *vcpu)
{
	return is_hyp_ctxt(vcpu) && !vcpu_is_el2(vcpu);
}

/*
 * The layout of SPSR for an AArch32 state is different when observed from an
 * AArch64 SPSR_ELx or an AArch32 SPSR_*. This function generates the AArch32
+1 −1
Original line number Diff line number Diff line
@@ -469,7 +469,6 @@ enum vcpu_sysreg {
	/* EL2 registers */
	SCTLR_EL2,	/* System Control Register (EL2) */
	ACTLR_EL2,	/* Auxiliary Control Register (EL2) */
	MDCR_EL2,	/* Monitor Debug Configuration Register (EL2) */
	CPTR_EL2,	/* Architectural Feature Trap Register (EL2) */
	HACR_EL2,	/* Hypervisor Auxiliary Control Register */
	ZCR_EL2,	/* SVE Control Register (EL2) */
@@ -501,6 +500,7 @@ enum vcpu_sysreg {
	/* Anything from this can be RES0/RES1 sanitised */
	MARKER(__SANITISED_REG_START__),
	TCR2_EL2,	/* Extended Translation Control Register (EL2) */
	MDCR_EL2,	/* Monitor Debug Configuration Register (EL2) */

	/* Any VNCR-capable reg goes after this point */
	MARKER(__VNCR_START__),
+175 −114
Original line number Diff line number Diff line
@@ -16,9 +16,13 @@

enum trap_behaviour {
	BEHAVE_HANDLE_LOCALLY	= 0,

	BEHAVE_FORWARD_READ	= BIT(0),
	BEHAVE_FORWARD_WRITE	= BIT(1),
	BEHAVE_FORWARD_ANY	= BEHAVE_FORWARD_READ | BEHAVE_FORWARD_WRITE,
	BEHAVE_FORWARD_RW	= BEHAVE_FORWARD_READ | BEHAVE_FORWARD_WRITE,

	/* Traps that take effect in Host EL0, this is rare! */
	BEHAVE_FORWARD_IN_HOST_EL0	= BIT(2),
};

struct trap_bits {
@@ -105,6 +109,7 @@ enum cgt_group_id {
	CGT_HCR_TPU_TOCU,
	CGT_HCR_NV1_nNV2_ENSCXT,
	CGT_MDCR_TPM_TPMCR,
	CGT_MDCR_TPM_HPMN,
	CGT_MDCR_TDE_TDA,
	CGT_MDCR_TDE_TDOSA,
	CGT_MDCR_TDE_TDRA,
@@ -121,6 +126,7 @@ enum cgt_group_id {
	CGT_CNTHCTL_EL1PTEN,

	CGT_CPTR_TTA,
	CGT_MDCR_HPMN,

	/* Must be last */
	__NR_CGT_GROUP_IDS__
@@ -137,7 +143,7 @@ static const struct trap_bits coarse_trap_bits[] = {
		.index		= HCR_EL2,
		.value 		= HCR_TID2,
		.mask		= HCR_TID2,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TID3] = {
		.index		= HCR_EL2,
@@ -161,37 +167,37 @@ static const struct trap_bits coarse_trap_bits[] = {
		.index		= HCR_EL2,
		.value		= HCR_TIDCP,
		.mask		= HCR_TIDCP,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TACR] = {
		.index		= HCR_EL2,
		.value		= HCR_TACR,
		.mask		= HCR_TACR,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TSW] = {
		.index		= HCR_EL2,
		.value		= HCR_TSW,
		.mask		= HCR_TSW,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TPC] = { /* Also called TCPC when FEAT_DPB is implemented */
		.index		= HCR_EL2,
		.value		= HCR_TPC,
		.mask		= HCR_TPC,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TPU] = {
		.index		= HCR_EL2,
		.value		= HCR_TPU,
		.mask		= HCR_TPU,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TTLB] = {
		.index		= HCR_EL2,
		.value		= HCR_TTLB,
		.mask		= HCR_TTLB,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TVM] = {
		.index		= HCR_EL2,
@@ -203,7 +209,7 @@ static const struct trap_bits coarse_trap_bits[] = {
		.index		= HCR_EL2,
		.value		= HCR_TDZ,
		.mask		= HCR_TDZ,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TRVM] = {
		.index		= HCR_EL2,
@@ -215,199 +221,201 @@ static const struct trap_bits coarse_trap_bits[] = {
		.index		= HCR_EL2,
		.value		= HCR_TLOR,
		.mask		= HCR_TLOR,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TERR] = {
		.index		= HCR_EL2,
		.value		= HCR_TERR,
		.mask		= HCR_TERR,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_APK] = {
		.index		= HCR_EL2,
		.value		= 0,
		.mask		= HCR_APK,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_NV] = {
		.index		= HCR_EL2,
		.value		= HCR_NV,
		.mask		= HCR_NV,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_NV_nNV2] = {
		.index		= HCR_EL2,
		.value		= HCR_NV,
		.mask		= HCR_NV | HCR_NV2,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_NV1_nNV2] = {
		.index		= HCR_EL2,
		.value		= HCR_NV | HCR_NV1,
		.mask		= HCR_NV | HCR_NV1 | HCR_NV2,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_AT] = {
		.index		= HCR_EL2,
		.value		= HCR_AT,
		.mask		= HCR_AT,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_nFIEN] = {
		.index		= HCR_EL2,
		.value		= 0,
		.mask		= HCR_FIEN,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TID4] = {
		.index		= HCR_EL2,
		.value 		= HCR_TID4,
		.mask		= HCR_TID4,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TICAB] = {
		.index		= HCR_EL2,
		.value 		= HCR_TICAB,
		.mask		= HCR_TICAB,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TOCU] = {
		.index		= HCR_EL2,
		.value 		= HCR_TOCU,
		.mask		= HCR_TOCU,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_ENSCXT] = {
		.index		= HCR_EL2,
		.value 		= 0,
		.mask		= HCR_ENSCXT,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TTLBIS] = {
		.index		= HCR_EL2,
		.value		= HCR_TTLBIS,
		.mask		= HCR_TTLBIS,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCR_TTLBOS] = {
		.index		= HCR_EL2,
		.value		= HCR_TTLBOS,
		.mask		= HCR_TTLBOS,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_MDCR_TPMCR] = {
		.index		= MDCR_EL2,
		.value		= MDCR_EL2_TPMCR,
		.mask		= MDCR_EL2_TPMCR,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW |
				  BEHAVE_FORWARD_IN_HOST_EL0,
	},
	[CGT_MDCR_TPM] = {
		.index		= MDCR_EL2,
		.value		= MDCR_EL2_TPM,
		.mask		= MDCR_EL2_TPM,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW |
				  BEHAVE_FORWARD_IN_HOST_EL0,
	},
	[CGT_MDCR_TDE] = {
		.index		= MDCR_EL2,
		.value		= MDCR_EL2_TDE,
		.mask		= MDCR_EL2_TDE,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_MDCR_TDA] = {
		.index		= MDCR_EL2,
		.value		= MDCR_EL2_TDA,
		.mask		= MDCR_EL2_TDA,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_MDCR_TDOSA] = {
		.index		= MDCR_EL2,
		.value		= MDCR_EL2_TDOSA,
		.mask		= MDCR_EL2_TDOSA,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_MDCR_TDRA] = {
		.index		= MDCR_EL2,
		.value		= MDCR_EL2_TDRA,
		.mask		= MDCR_EL2_TDRA,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_MDCR_E2PB] = {
		.index		= MDCR_EL2,
		.value		= 0,
		.mask		= BIT(MDCR_EL2_E2PB_SHIFT),
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_MDCR_TPMS] = {
		.index		= MDCR_EL2,
		.value		= MDCR_EL2_TPMS,
		.mask		= MDCR_EL2_TPMS,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_MDCR_TTRF] = {
		.index		= MDCR_EL2,
		.value		= MDCR_EL2_TTRF,
		.mask		= MDCR_EL2_TTRF,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_MDCR_E2TB] = {
		.index		= MDCR_EL2,
		.value		= 0,
		.mask		= BIT(MDCR_EL2_E2TB_SHIFT),
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_MDCR_TDCC] = {
		.index		= MDCR_EL2,
		.value		= MDCR_EL2_TDCC,
		.mask		= MDCR_EL2_TDCC,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_CPTR_TAM] = {
		.index		= CPTR_EL2,
		.value		= CPTR_EL2_TAM,
		.mask		= CPTR_EL2_TAM,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_CPTR_TCPAC] = {
		.index		= CPTR_EL2,
		.value		= CPTR_EL2_TCPAC,
		.mask		= CPTR_EL2_TCPAC,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCRX_EnFPM] = {
		.index		= HCRX_EL2,
		.value 		= 0,
		.mask		= HCRX_EL2_EnFPM,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_HCRX_TCR2En] = {
		.index		= HCRX_EL2,
		.value 		= 0,
		.mask		= HCRX_EL2_TCR2En,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_ICH_HCR_TC] = {
		.index		= ICH_HCR_EL2,
		.value		= ICH_HCR_TC,
		.mask		= ICH_HCR_TC,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_ICH_HCR_TALL0] = {
		.index		= ICH_HCR_EL2,
		.value		= ICH_HCR_TALL0,
		.mask		= ICH_HCR_TALL0,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_ICH_HCR_TALL1] = {
		.index		= ICH_HCR_EL2,
		.value		= ICH_HCR_TALL1,
		.mask		= ICH_HCR_TALL1,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
	[CGT_ICH_HCR_TDIR] = {
		.index		= ICH_HCR_EL2,
		.value		= ICH_HCR_TDIR,
		.mask		= ICH_HCR_TDIR,
		.behaviour	= BEHAVE_FORWARD_ANY,
		.behaviour	= BEHAVE_FORWARD_RW,
	},
};

@@ -428,6 +436,7 @@ static const enum cgt_group_id *coarse_control_combo[] = {
	MCB(CGT_HCR_TPU_TOCU,		CGT_HCR_TPU, CGT_HCR_TOCU),
	MCB(CGT_HCR_NV1_nNV2_ENSCXT,	CGT_HCR_NV1_nNV2, CGT_HCR_ENSCXT),
	MCB(CGT_MDCR_TPM_TPMCR,		CGT_MDCR_TPM, CGT_MDCR_TPMCR),
	MCB(CGT_MDCR_TPM_HPMN,		CGT_MDCR_TPM, CGT_MDCR_HPMN),
	MCB(CGT_MDCR_TDE_TDA,		CGT_MDCR_TDE, CGT_MDCR_TDA),
	MCB(CGT_MDCR_TDE_TDOSA,		CGT_MDCR_TDE, CGT_MDCR_TDOSA),
	MCB(CGT_MDCR_TDE_TDRA,		CGT_MDCR_TDE, CGT_MDCR_TDRA),
@@ -467,7 +476,7 @@ static enum trap_behaviour check_cnthctl_el1pcten(struct kvm_vcpu *vcpu)
	if (get_sanitized_cnthctl(vcpu) & (CNTHCTL_EL1PCTEN << 10))
		return BEHAVE_HANDLE_LOCALLY;

	return BEHAVE_FORWARD_ANY;
	return BEHAVE_FORWARD_RW;
}

static enum trap_behaviour check_cnthctl_el1pten(struct kvm_vcpu *vcpu)
@@ -475,7 +484,7 @@ static enum trap_behaviour check_cnthctl_el1pten(struct kvm_vcpu *vcpu)
	if (get_sanitized_cnthctl(vcpu) & (CNTHCTL_EL1PCEN << 10))
		return BEHAVE_HANDLE_LOCALLY;

	return BEHAVE_FORWARD_ANY;
	return BEHAVE_FORWARD_RW;
}

static enum trap_behaviour check_cptr_tta(struct kvm_vcpu *vcpu)
@@ -486,7 +495,35 @@ static enum trap_behaviour check_cptr_tta(struct kvm_vcpu *vcpu)
		val = translate_cptr_el2_to_cpacr_el1(val);

	if (val & CPACR_ELx_TTA)
		return BEHAVE_FORWARD_ANY;
		return BEHAVE_FORWARD_RW;

	return BEHAVE_HANDLE_LOCALLY;
}

static enum trap_behaviour check_mdcr_hpmn(struct kvm_vcpu *vcpu)
{
	u32 sysreg = esr_sys64_to_sysreg(kvm_vcpu_get_esr(vcpu));
	unsigned int idx;


	switch (sysreg) {
	case SYS_PMEVTYPERn_EL0(0) ... SYS_PMEVTYPERn_EL0(30):
	case SYS_PMEVCNTRn_EL0(0) ... SYS_PMEVCNTRn_EL0(30):
		idx = (sys_reg_CRm(sysreg) & 0x3) << 3 | sys_reg_Op2(sysreg);
		break;
	case SYS_PMXEVTYPER_EL0:
	case SYS_PMXEVCNTR_EL0:
		idx = SYS_FIELD_GET(PMSELR_EL0, SEL,
				    __vcpu_sys_reg(vcpu, PMSELR_EL0));
		break;
	default:
		/* Someone used this trap helper for something else... */
		KVM_BUG_ON(1, vcpu->kvm);
		return BEHAVE_HANDLE_LOCALLY;
	}

	if (kvm_pmu_counter_is_hyp(vcpu, idx))
		return BEHAVE_FORWARD_RW | BEHAVE_FORWARD_IN_HOST_EL0;

	return BEHAVE_HANDLE_LOCALLY;
}
@@ -498,6 +535,7 @@ static const complex_condition_check ccc[] = {
	CCC(CGT_CNTHCTL_EL1PCTEN, check_cnthctl_el1pcten),
	CCC(CGT_CNTHCTL_EL1PTEN, check_cnthctl_el1pten),
	CCC(CGT_CPTR_TTA, check_cptr_tta),
	CCC(CGT_MDCR_HPMN, check_mdcr_hpmn),
};

/*
@@ -916,77 +954,77 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = {
	SR_TRAP(SYS_PMOVSCLR_EL0,	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMCEID0_EL0,	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMCEID1_EL0,	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMXEVTYPER_EL0,	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMXEVTYPER_EL0,	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMSWINC_EL0,	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMSELR_EL0,		CGT_MDCR_TPM),
	SR_TRAP(SYS_PMXEVCNTR_EL0,	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMXEVCNTR_EL0,	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMCCNTR_EL0,	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMUSERENR_EL0,	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMINTENSET_EL1,	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMINTENCLR_EL1,	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMMIR_EL1,		CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(0),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(1),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(2),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(3),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(4),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(5),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(6),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(7),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(8),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(9),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(10),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(11),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(12),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(13),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(14),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(15),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(16),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(17),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(18),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(19),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(20),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(21),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(22),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(23),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(24),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(25),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(26),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(27),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(28),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(29),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(30),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(0),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(1),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(2),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(3),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(4),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(5),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(6),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(7),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(8),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(9),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(10),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(11),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(12),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(13),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(14),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(15),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(16),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(17),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(18),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(19),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(20),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(21),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(22),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(23),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(24),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(25),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(26),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(27),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(28),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(29),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVTYPERn_EL0(30),	CGT_MDCR_TPM),
	SR_TRAP(SYS_PMEVCNTRn_EL0(0),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(1),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(2),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(3),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(4),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(5),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(6),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(7),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(8),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(9),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(10),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(11),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(12),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(13),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(14),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(15),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(16),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(17),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(18),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(19),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(20),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(21),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(22),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(23),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(24),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(25),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(26),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(27),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(28),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(29),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVCNTRn_EL0(30),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(0),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(1),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(2),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(3),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(4),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(5),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(6),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(7),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(8),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(9),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(10),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(11),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(12),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(13),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(14),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(15),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(16),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(17),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(18),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(19),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(20),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(21),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(22),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(23),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(24),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(25),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(26),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(27),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(28),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(29),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMEVTYPERn_EL0(30),	CGT_MDCR_TPM_HPMN),
	SR_TRAP(SYS_PMCCFILTR_EL0,	CGT_MDCR_TPM),
	SR_TRAP(SYS_MDCCSR_EL0,		CGT_MDCR_TDCC_TDE_TDA),
	SR_TRAP(SYS_MDCCINT_EL1,	CGT_MDCR_TDCC_TDE_TDA),
@@ -2017,7 +2055,8 @@ int __init populate_nv_trap_config(void)
		cgids = coarse_control_combo[id - __MULTIPLE_CONTROL_BITS__];

		for (int i = 0; cgids[i] != __RESERVED__; i++) {
			if (cgids[i] >= __MULTIPLE_CONTROL_BITS__) {
			if (cgids[i] >= __MULTIPLE_CONTROL_BITS__ &&
			    cgids[i] < __COMPLEX_CONDITIONS__) {
				kvm_err("Recursive MCB %d/%d\n", id, cgids[i]);
				ret = -EINVAL;
			}
@@ -2122,11 +2161,19 @@ static u64 kvm_get_sysreg_res0(struct kvm *kvm, enum vcpu_sysreg sr)
	return masks->mask[sr - __VNCR_START__].res0;
}

static bool check_fgt_bit(struct kvm *kvm, bool is_read,
static bool check_fgt_bit(struct kvm_vcpu *vcpu, bool is_read,
			  u64 val, const union trap_config tc)
{
	struct kvm *kvm = vcpu->kvm;
	enum vcpu_sysreg sr;

	/*
	 * KVM doesn't know about any FGTs that apply to the host, and hopefully
	 * that'll remain the case.
	 */
	if (is_hyp_ctxt(vcpu))
		return false;

	if (tc.pol)
		return (val & BIT(tc.bit));

@@ -2203,7 +2250,15 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index)
	 * If we're not nesting, immediately return to the caller, with the
	 * sysreg index, should we have it.
	 */
	if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu))
	if (!vcpu_has_nv(vcpu))
		goto local;

	/*
	 * There are a few traps that take effect InHost, but are constrained
	 * to EL0. Don't bother with computing the trap behaviour if the vCPU
	 * isn't in EL0.
	 */
	if (is_hyp_ctxt(vcpu) && !vcpu_is_host_el0(vcpu))
		goto local;

	switch ((enum fgt_group_id)tc.fgt) {
@@ -2249,12 +2304,14 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index)
		goto local;
	}

	if (tc.fgt != __NO_FGT_GROUP__ && check_fgt_bit(vcpu->kvm, is_read,
							val, tc))
	if (tc.fgt != __NO_FGT_GROUP__ && check_fgt_bit(vcpu, is_read, val, tc))
		goto inject;

	b = compute_trap_behaviour(vcpu, tc);

	if (!(b & BEHAVE_FORWARD_IN_HOST_EL0) && vcpu_is_host_el0(vcpu))
		goto local;

	if (((b & BEHAVE_FORWARD_READ) && is_read) ||
	    ((b & BEHAVE_FORWARD_WRITE) && !is_read))
		goto inject;
@@ -2389,6 +2446,8 @@ void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu)

	kvm_arch_vcpu_load(vcpu, smp_processor_id());
	preempt_enable();

	kvm_pmu_nested_transition(vcpu);
}

static void kvm_inject_el2_exception(struct kvm_vcpu *vcpu, u64 esr_el2,
@@ -2471,6 +2530,8 @@ static int kvm_inject_nested(struct kvm_vcpu *vcpu, u64 esr_el2,
	kvm_arch_vcpu_load(vcpu, smp_processor_id());
	preempt_enable();

	kvm_pmu_nested_transition(vcpu);

	return 1;
}

+40 −2
Original line number Diff line number Diff line
@@ -917,12 +917,13 @@ static void limit_nv_id_regs(struct kvm *kvm)
				  ID_AA64MMFR4_EL1_E2H0_NI_NV1);
	kvm_set_vm_id_reg(kvm, SYS_ID_AA64MMFR4_EL1, val);

	/* Only limited support for PMU, Debug, BPs and WPs */
	/* Only limited support for PMU, Debug, BPs, WPs, and HPMN0 */
	val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64DFR0_EL1);
	val &= (NV_FTR(DFR0, PMUVer)	|
		NV_FTR(DFR0, WRPs)	|
		NV_FTR(DFR0, BRPs)	|
		NV_FTR(DFR0, DebugVer));
		NV_FTR(DFR0, DebugVer)	|
		NV_FTR(DFR0, HPMN0));

	/* Cap Debug to ARMv8.1 */
	tmp = FIELD_GET(NV_FTR(DFR0, DebugVer), val);
@@ -1233,6 +1234,43 @@ int kvm_init_nv_sysregs(struct kvm *kvm)
		res0 |= SCTLR_EL1_EPAN;
	set_sysreg_masks(kvm, SCTLR_EL1, res0, res1);

	/* MDCR_EL2 */
	res0 = MDCR_EL2_RES0;
	res1 = MDCR_EL2_RES1;
	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMUVer, IMP))
		res0 |= (MDCR_EL2_HPMN | MDCR_EL2_TPMCR |
			 MDCR_EL2_TPM | MDCR_EL2_HPME);
	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMSVer, IMP))
		res0 |= MDCR_EL2_E2PB | MDCR_EL2_TPMS;
	if (!kvm_has_feat(kvm, ID_AA64DFR1_EL1, SPMU, IMP))
		res0 |= MDCR_EL2_EnSPM;
	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMUVer, V3P1))
		res0 |= MDCR_EL2_HPMD;
	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceFilt, IMP))
		res0 |= MDCR_EL2_TTRF;
	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMUVer, V3P5))
		res0 |= MDCR_EL2_HCCD | MDCR_EL2_HLP;
	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceBuffer, IMP))
		res0 |= MDCR_EL2_E2TB;
	if (!kvm_has_feat(kvm, ID_AA64MMFR0_EL1, FGT, IMP))
		res0 |= MDCR_EL2_TDCC;
	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, MTPMU, IMP) ||
	    kvm_has_feat(kvm, ID_AA64PFR0_EL1, EL3, IMP))
		res0 |= MDCR_EL2_MTPME;
	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMUVer, V3P7))
		res0 |= MDCR_EL2_HPMFZO;
	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMSS, IMP))
		res0 |= MDCR_EL2_PMSSE;
	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMSVer, V1P2))
		res0 |= MDCR_EL2_HPMFZS;
	if (!kvm_has_feat(kvm, ID_AA64DFR1_EL1, EBEP, IMP))
		res0 |= MDCR_EL2_PMEE;
	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, DebugVer, V8P9))
		res0 |= MDCR_EL2_EBWE;
	if (!kvm_has_feat(kvm, ID_AA64DFR2_EL1, STEP, IMP))
		res0 |= MDCR_EL2_EnSTEPOP;
	set_sysreg_masks(kvm, MDCR_EL2, res0, res1);

	return 0;
}

Loading