mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-29 09:12:07 +00:00
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: Oliver Upton <oliver.upton@linux.dev>
This commit is contained in:
commit
6d4b81e2e7
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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__),
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,11 @@ static bool kvm_pmc_is_64bit(struct kvm_pmc *pmc)
|
||||
|
||||
static bool kvm_pmc_has_64bit_overflow(struct kvm_pmc *pmc)
|
||||
{
|
||||
u64 val = kvm_vcpu_read_pmcr(kvm_pmc_to_vcpu(pmc));
|
||||
struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
|
||||
u64 val = kvm_vcpu_read_pmcr(vcpu);
|
||||
|
||||
if (kvm_pmu_counter_is_hyp(vcpu, pmc->idx))
|
||||
return __vcpu_sys_reg(vcpu, MDCR_EL2) & MDCR_EL2_HLP;
|
||||
|
||||
return (pmc->idx < ARMV8_PMU_CYCLE_IDX && (val & ARMV8_PMU_PMCR_LP)) ||
|
||||
(pmc->idx == ARMV8_PMU_CYCLE_IDX && (val & ARMV8_PMU_PMCR_LC));
|
||||
@ -111,6 +115,11 @@ static u32 counter_index_to_evtreg(u64 idx)
|
||||
return (idx == ARMV8_PMU_CYCLE_IDX) ? PMCCFILTR_EL0 : PMEVTYPER0_EL0 + idx;
|
||||
}
|
||||
|
||||
static u64 kvm_pmc_read_evtreg(const struct kvm_pmc *pmc)
|
||||
{
|
||||
return __vcpu_sys_reg(kvm_pmc_to_vcpu(pmc), counter_index_to_evtreg(pmc->idx));
|
||||
}
|
||||
|
||||
static u64 kvm_pmu_get_pmc_value(struct kvm_pmc *pmc)
|
||||
{
|
||||
struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
|
||||
@ -244,7 +253,7 @@ void kvm_pmu_vcpu_init(struct kvm_vcpu *vcpu)
|
||||
*/
|
||||
void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long mask = kvm_pmu_valid_counter_mask(vcpu);
|
||||
unsigned long mask = kvm_pmu_implemented_counter_mask(vcpu);
|
||||
int i;
|
||||
|
||||
for_each_set_bit(i, &mask, 32)
|
||||
@ -265,7 +274,37 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
|
||||
irq_work_sync(&vcpu->arch.pmu.overflow_work);
|
||||
}
|
||||
|
||||
u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
|
||||
bool kvm_pmu_counter_is_hyp(struct kvm_vcpu *vcpu, unsigned int idx)
|
||||
{
|
||||
unsigned int hpmn;
|
||||
|
||||
if (!vcpu_has_nv(vcpu) || idx == ARMV8_PMU_CYCLE_IDX)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Programming HPMN=0 is CONSTRAINED UNPREDICTABLE if FEAT_HPMN0 isn't
|
||||
* implemented. Since KVM's ability to emulate HPMN=0 does not directly
|
||||
* depend on hardware (all PMU registers are trapped), make the
|
||||
* implementation choice that all counters are included in the second
|
||||
* range reserved for EL2/EL3.
|
||||
*/
|
||||
hpmn = SYS_FIELD_GET(MDCR_EL2, HPMN, __vcpu_sys_reg(vcpu, MDCR_EL2));
|
||||
return idx >= hpmn;
|
||||
}
|
||||
|
||||
u64 kvm_pmu_accessible_counter_mask(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 mask = kvm_pmu_implemented_counter_mask(vcpu);
|
||||
u64 hpmn;
|
||||
|
||||
if (!vcpu_has_nv(vcpu) || vcpu_is_el2(vcpu))
|
||||
return mask;
|
||||
|
||||
hpmn = SYS_FIELD_GET(MDCR_EL2, HPMN, __vcpu_sys_reg(vcpu, MDCR_EL2));
|
||||
return mask & ~GENMASK(vcpu->kvm->arch.pmcr_n - 1, hpmn);
|
||||
}
|
||||
|
||||
u64 kvm_pmu_implemented_counter_mask(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 val = FIELD_GET(ARMV8_PMU_PMCR_N, kvm_vcpu_read_pmcr(vcpu));
|
||||
|
||||
@ -574,7 +613,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
|
||||
kvm_pmu_set_counter_value(vcpu, ARMV8_PMU_CYCLE_IDX, 0);
|
||||
|
||||
if (val & ARMV8_PMU_PMCR_P) {
|
||||
unsigned long mask = kvm_pmu_valid_counter_mask(vcpu);
|
||||
unsigned long mask = kvm_pmu_accessible_counter_mask(vcpu);
|
||||
mask &= ~BIT(ARMV8_PMU_CYCLE_IDX);
|
||||
for_each_set_bit(i, &mask, 32)
|
||||
kvm_pmu_set_pmc_value(kvm_vcpu_idx_to_pmc(vcpu, i), 0, true);
|
||||
@ -585,8 +624,44 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
|
||||
static bool kvm_pmu_counter_is_enabled(struct kvm_pmc *pmc)
|
||||
{
|
||||
struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
|
||||
return (kvm_vcpu_read_pmcr(vcpu) & ARMV8_PMU_PMCR_E) &&
|
||||
(__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(pmc->idx));
|
||||
unsigned int mdcr = __vcpu_sys_reg(vcpu, MDCR_EL2);
|
||||
|
||||
if (!(__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(pmc->idx)))
|
||||
return false;
|
||||
|
||||
if (kvm_pmu_counter_is_hyp(vcpu, pmc->idx))
|
||||
return mdcr & MDCR_EL2_HPME;
|
||||
|
||||
return kvm_vcpu_read_pmcr(vcpu) & ARMV8_PMU_PMCR_E;
|
||||
}
|
||||
|
||||
static bool kvm_pmc_counts_at_el0(struct kvm_pmc *pmc)
|
||||
{
|
||||
u64 evtreg = kvm_pmc_read_evtreg(pmc);
|
||||
bool nsu = evtreg & ARMV8_PMU_EXCLUDE_NS_EL0;
|
||||
bool u = evtreg & ARMV8_PMU_EXCLUDE_EL0;
|
||||
|
||||
return u == nsu;
|
||||
}
|
||||
|
||||
static bool kvm_pmc_counts_at_el1(struct kvm_pmc *pmc)
|
||||
{
|
||||
u64 evtreg = kvm_pmc_read_evtreg(pmc);
|
||||
bool nsk = evtreg & ARMV8_PMU_EXCLUDE_NS_EL1;
|
||||
bool p = evtreg & ARMV8_PMU_EXCLUDE_EL1;
|
||||
|
||||
return p == nsk;
|
||||
}
|
||||
|
||||
static bool kvm_pmc_counts_at_el2(struct kvm_pmc *pmc)
|
||||
{
|
||||
struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
|
||||
u64 mdcr = __vcpu_sys_reg(vcpu, MDCR_EL2);
|
||||
|
||||
if (!kvm_pmu_counter_is_hyp(vcpu, pmc->idx) && (mdcr & MDCR_EL2_HPMD))
|
||||
return false;
|
||||
|
||||
return kvm_pmc_read_evtreg(pmc) & ARMV8_PMU_INCLUDE_EL2;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -599,17 +674,15 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc)
|
||||
struct arm_pmu *arm_pmu = vcpu->kvm->arch.arm_pmu;
|
||||
struct perf_event *event;
|
||||
struct perf_event_attr attr;
|
||||
u64 eventsel, reg, data;
|
||||
bool p, u, nsk, nsu;
|
||||
u64 eventsel, evtreg;
|
||||
|
||||
reg = counter_index_to_evtreg(pmc->idx);
|
||||
data = __vcpu_sys_reg(vcpu, reg);
|
||||
evtreg = kvm_pmc_read_evtreg(pmc);
|
||||
|
||||
kvm_pmu_stop_counter(pmc);
|
||||
if (pmc->idx == ARMV8_PMU_CYCLE_IDX)
|
||||
eventsel = ARMV8_PMUV3_PERFCTR_CPU_CYCLES;
|
||||
else
|
||||
eventsel = data & kvm_pmu_event_mask(vcpu->kvm);
|
||||
eventsel = evtreg & kvm_pmu_event_mask(vcpu->kvm);
|
||||
|
||||
/*
|
||||
* Neither SW increment nor chained events need to be backed
|
||||
@ -627,22 +700,25 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc)
|
||||
!test_bit(eventsel, vcpu->kvm->arch.pmu_filter))
|
||||
return;
|
||||
|
||||
p = data & ARMV8_PMU_EXCLUDE_EL1;
|
||||
u = data & ARMV8_PMU_EXCLUDE_EL0;
|
||||
nsk = data & ARMV8_PMU_EXCLUDE_NS_EL1;
|
||||
nsu = data & ARMV8_PMU_EXCLUDE_NS_EL0;
|
||||
|
||||
memset(&attr, 0, sizeof(struct perf_event_attr));
|
||||
attr.type = arm_pmu->pmu.type;
|
||||
attr.size = sizeof(attr);
|
||||
attr.pinned = 1;
|
||||
attr.disabled = !kvm_pmu_counter_is_enabled(pmc);
|
||||
attr.exclude_user = (u != nsu);
|
||||
attr.exclude_kernel = (p != nsk);
|
||||
attr.exclude_user = !kvm_pmc_counts_at_el0(pmc);
|
||||
attr.exclude_hv = 1; /* Don't count EL2 events */
|
||||
attr.exclude_host = 1; /* Don't count host events */
|
||||
attr.config = eventsel;
|
||||
|
||||
/*
|
||||
* Filter events at EL1 (i.e. vEL2) when in a hyp context based on the
|
||||
* guest's EL2 filter.
|
||||
*/
|
||||
if (unlikely(is_hyp_ctxt(vcpu)))
|
||||
attr.exclude_kernel = !kvm_pmc_counts_at_el2(pmc);
|
||||
else
|
||||
attr.exclude_kernel = !kvm_pmc_counts_at_el1(pmc);
|
||||
|
||||
/*
|
||||
* If counting with a 64bit counter, advertise it to the perf
|
||||
* code, carefully dealing with the initial sample period
|
||||
@ -804,7 +880,7 @@ u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
|
||||
|
||||
void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 mask = kvm_pmu_valid_counter_mask(vcpu);
|
||||
u64 mask = kvm_pmu_implemented_counter_mask(vcpu);
|
||||
|
||||
kvm_pmu_handle_pmcr(vcpu, kvm_vcpu_read_pmcr(vcpu));
|
||||
|
||||
@ -1139,3 +1215,32 @@ u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu)
|
||||
|
||||
return u64_replace_bits(pmcr, vcpu->kvm->arch.pmcr_n, ARMV8_PMU_PMCR_N);
|
||||
}
|
||||
|
||||
void kvm_pmu_nested_transition(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
bool reprogrammed = false;
|
||||
unsigned long mask;
|
||||
int i;
|
||||
|
||||
if (!kvm_vcpu_has_pmu(vcpu))
|
||||
return;
|
||||
|
||||
mask = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
|
||||
for_each_set_bit(i, &mask, 32) {
|
||||
struct kvm_pmc *pmc = kvm_vcpu_idx_to_pmc(vcpu, i);
|
||||
|
||||
/*
|
||||
* We only need to reconfigure events where the filter is
|
||||
* different at EL1 vs. EL2, as we're multiplexing the true EL1
|
||||
* event filter bit for nested.
|
||||
*/
|
||||
if (kvm_pmc_counts_at_el1(pmc) == kvm_pmc_counts_at_el2(pmc))
|
||||
continue;
|
||||
|
||||
kvm_pmu_create_perf_event(pmc);
|
||||
reprogrammed = true;
|
||||
}
|
||||
|
||||
if (reprogrammed)
|
||||
kvm_vcpu_pmu_restore_guest(vcpu);
|
||||
}
|
||||
|
@ -1168,7 +1168,7 @@ static int set_pmreg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, u64 va
|
||||
{
|
||||
bool set;
|
||||
|
||||
val &= kvm_pmu_valid_counter_mask(vcpu);
|
||||
val &= kvm_pmu_accessible_counter_mask(vcpu);
|
||||
|
||||
switch (r->reg) {
|
||||
case PMOVSSET_EL0:
|
||||
@ -1191,7 +1191,7 @@ static int set_pmreg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, u64 va
|
||||
|
||||
static int get_pmreg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, u64 *val)
|
||||
{
|
||||
u64 mask = kvm_pmu_valid_counter_mask(vcpu);
|
||||
u64 mask = kvm_pmu_accessible_counter_mask(vcpu);
|
||||
|
||||
*val = __vcpu_sys_reg(vcpu, r->reg) & mask;
|
||||
return 0;
|
||||
@ -1205,7 +1205,7 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
if (pmu_access_el0_disabled(vcpu))
|
||||
return false;
|
||||
|
||||
mask = kvm_pmu_valid_counter_mask(vcpu);
|
||||
mask = kvm_pmu_accessible_counter_mask(vcpu);
|
||||
if (p->is_write) {
|
||||
val = p->regval & mask;
|
||||
if (r->Op2 & 0x1) {
|
||||
@ -1228,7 +1228,7 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
u64 mask = kvm_pmu_valid_counter_mask(vcpu);
|
||||
u64 mask = kvm_pmu_accessible_counter_mask(vcpu);
|
||||
|
||||
if (check_pmu_access_disabled(vcpu, 0))
|
||||
return false;
|
||||
@ -1252,7 +1252,7 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
u64 mask = kvm_pmu_valid_counter_mask(vcpu);
|
||||
u64 mask = kvm_pmu_accessible_counter_mask(vcpu);
|
||||
|
||||
if (pmu_access_el0_disabled(vcpu))
|
||||
return false;
|
||||
@ -1282,7 +1282,7 @@ static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
if (pmu_write_swinc_el0_disabled(vcpu))
|
||||
return false;
|
||||
|
||||
mask = kvm_pmu_valid_counter_mask(vcpu);
|
||||
mask = kvm_pmu_accessible_counter_mask(vcpu);
|
||||
kvm_pmu_software_increment(vcpu, p->regval & mask);
|
||||
return true;
|
||||
}
|
||||
|
@ -1200,7 +1200,7 @@ UnsignedEnum 55:52 BRBE
|
||||
0b0001 IMP
|
||||
0b0010 BRBE_V1P1
|
||||
EndEnum
|
||||
Enum 51:48 MTPMU
|
||||
SignedEnum 51:48 MTPMU
|
||||
0b0000 NI_IMPDEF
|
||||
0b0001 IMP
|
||||
0b1111 NI
|
||||
@ -1208,6 +1208,7 @@ EndEnum
|
||||
UnsignedEnum 47:44 TraceBuffer
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
0b0010 TRBE_V1P1
|
||||
EndEnum
|
||||
UnsignedEnum 43:40 TraceFilt
|
||||
0b0000 NI
|
||||
@ -1224,11 +1225,18 @@ UnsignedEnum 35:32 PMSVer
|
||||
0b0011 V1P2
|
||||
0b0100 V1P3
|
||||
0b0101 V1P4
|
||||
0b0110 V1P5
|
||||
EndEnum
|
||||
Field 31:28 CTX_CMPs
|
||||
Res0 27:24
|
||||
UnsignedEnum 27:24 SEBEP
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
Field 23:20 WRPs
|
||||
Res0 19:16
|
||||
UnsignedEnum 19:16 PMSS
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
Field 15:12 BRPs
|
||||
UnsignedEnum 11:8 PMUVer
|
||||
0b0000 NI
|
||||
@ -1238,6 +1246,7 @@ UnsignedEnum 11:8 PMUVer
|
||||
0b0110 V3P5
|
||||
0b0111 V3P7
|
||||
0b1000 V3P8
|
||||
0b1001 V3P9
|
||||
0b1111 IMP_DEF
|
||||
EndEnum
|
||||
UnsignedEnum 7:4 TraceVer
|
||||
@ -1287,6 +1296,32 @@ Field 15:8 BRPs
|
||||
Field 7:0 SYSPMUID
|
||||
EndSysreg
|
||||
|
||||
Sysreg ID_AA64DFR2_EL1 3 0 0 5 2
|
||||
Res0 63:28
|
||||
UnsignedEnum 27:24 TRBE_EXC
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 23:20 SPE_nVM
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
UnsignedEnum 19:16 SPE_EXC
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
Res0 15:8
|
||||
UnsignedEnum 7:4 BWE
|
||||
0b0000 NI
|
||||
0b0001 FEAT_BWE
|
||||
0b0002 FEAT_BWE2
|
||||
EndEnum
|
||||
UnsignedEnum 3:0 STEP
|
||||
0b0000 NI
|
||||
0b0001 IMP
|
||||
EndEnum
|
||||
EndSysreg
|
||||
|
||||
Sysreg ID_AA64AFR0_EL1 3 0 0 5 4
|
||||
Res0 63:32
|
||||
Field 31:28 IMPDEF7
|
||||
@ -2389,6 +2424,41 @@ Field 1 AFSR1_EL1
|
||||
Field 0 AFSR0_EL1
|
||||
EndSysregFields
|
||||
|
||||
Sysreg MDCR_EL2 3 4 1 1 1
|
||||
Res0 63:51
|
||||
Field 50 EnSTEPOP
|
||||
Res0 49:44
|
||||
Field 43 EBWE
|
||||
Res0 42
|
||||
Field 41:40 PMEE
|
||||
Res0 39:37
|
||||
Field 36 HPMFZS
|
||||
Res0 35:32
|
||||
Field 31:30 PMSSE
|
||||
Field 29 HPMFZO
|
||||
Field 28 MTPME
|
||||
Field 27 TDCC
|
||||
Field 26 HLP
|
||||
Field 25:24 E2TB
|
||||
Field 23 HCCD
|
||||
Res0 22:20
|
||||
Field 19 TTRF
|
||||
Res0 18
|
||||
Field 17 HPMD
|
||||
Res0 16
|
||||
Field 15 EnSPM
|
||||
Field 14 TPMS
|
||||
Field 13:12 E2PB
|
||||
Field 11 TDRA
|
||||
Field 10 TDOSA
|
||||
Field 9 TDA
|
||||
Field 8 TDE
|
||||
Field 7 HPME
|
||||
Field 6 TPM
|
||||
Field 5 TPMCR
|
||||
Field 4:0 HPMN
|
||||
EndSysreg
|
||||
|
||||
Sysreg HFGRTR_EL2 3 4 1 1 4
|
||||
Fields HFGxTR_EL2
|
||||
EndSysreg
|
||||
|
@ -47,7 +47,8 @@ static __always_inline bool kvm_arm_support_pmu_v3(void)
|
||||
#define kvm_arm_pmu_irq_initialized(v) ((v)->arch.pmu.irq_num >= VGIC_NR_SGIS)
|
||||
u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
|
||||
void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val);
|
||||
u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu);
|
||||
u64 kvm_pmu_implemented_counter_mask(struct kvm_vcpu *vcpu);
|
||||
u64 kvm_pmu_accessible_counter_mask(struct kvm_vcpu *vcpu);
|
||||
u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1);
|
||||
void kvm_pmu_vcpu_init(struct kvm_vcpu *vcpu);
|
||||
void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu);
|
||||
@ -96,6 +97,8 @@ int kvm_arm_set_default_pmu(struct kvm *kvm);
|
||||
u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm);
|
||||
|
||||
u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu);
|
||||
bool kvm_pmu_counter_is_hyp(struct kvm_vcpu *vcpu, unsigned int idx);
|
||||
void kvm_pmu_nested_transition(struct kvm_vcpu *vcpu);
|
||||
#else
|
||||
struct kvm_pmu {
|
||||
};
|
||||
@ -113,7 +116,11 @@ static inline u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
static inline void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu,
|
||||
u64 select_idx, u64 val) {}
|
||||
static inline u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
|
||||
static inline u64 kvm_pmu_implemented_counter_mask(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline u64 kvm_pmu_accessible_counter_mask(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -187,6 +194,13 @@ static inline u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool kvm_pmu_counter_is_hyp(struct kvm_vcpu *vcpu, unsigned int idx)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void kvm_pmu_nested_transition(struct kvm_vcpu *vcpu) {}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user