diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index efe56258..7b9b2ed9 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -16,9 +16,9 @@ target_link_libraries(rmm-lib rmm-lib-realm rmm-lib-rmm_el3_ifc rmm-lib-smc - t_cose rmm-lib-timers - rmm-lib-xlat) + rmm-lib-xlat + t_cose) add_subdirectory("allocator") add_subdirectory("arch") @@ -29,8 +29,8 @@ add_subdirectory("gic") add_subdirectory("mbedtls") add_subdirectory("measurement") add_subdirectory("realm") -add_subdirectory("smc") add_subdirectory("rmm_el3_ifc") +add_subdirectory("smc") add_subdirectory("t_cose") add_subdirectory("timers") add_subdirectory("xlat") diff --git a/lib/allocator/include/memory_alloc.h b/lib/allocator/include/memory_alloc.h index 5346395e..1ff2b9e7 100644 --- a/lib/allocator/include/memory_alloc.h +++ b/lib/allocator/include/memory_alloc.h @@ -11,11 +11,15 @@ struct _memory_header; typedef struct memory_header_s memory_header_t; -/* - * Number of pages per REC to be allocated. MbedTLS needs 8K of heap - * for attestation usecases. - */ +/* MbedTLS needs 8K of heap for attestation usecases */ #define REC_HEAP_PAGES 2 +#define REC_HEAP_SIZE (REC_HEAP_PAGES * SZ_4K) + +/* Number of pages per REC for PMU state */ +#define REC_PMU_PAGES 1 + +/* Number of pages per REC to be allocated */ +#define REC_NUM_PAGES (REC_HEAP_PAGES + REC_PMU_PAGES) struct buffer_alloc_ctx { unsigned char *buf; @@ -36,7 +40,6 @@ struct memory_header_s { size_t magic2; }; - /* * Function to assign a heap context to the current CPU for * use by the MbedCrypto. In case the heap needs to be isolated diff --git a/lib/arch/CMakeLists.txt b/lib/arch/CMakeLists.txt index bb0367e2..8afba1a6 100644 --- a/lib/arch/CMakeLists.txt +++ b/lib/arch/CMakeLists.txt @@ -6,7 +6,8 @@ add_library(rmm-lib-arch) target_link_libraries(rmm-lib-arch - PRIVATE rmm-lib-common) + PRIVATE rmm-lib-common + rmm-lib-smc) target_include_directories(rmm-lib-arch PUBLIC "include" @@ -14,7 +15,8 @@ target_include_directories(rmm-lib-arch target_sources(rmm-lib-arch PRIVATE "src/arch_features.c" - "src/fpu_helpers.c") + "src/fpu_helpers.c" + "src/pmu.c") if(NOT RMM_ARCH STREQUAL fake_host) target_sources(rmm-lib-arch diff --git a/lib/arch/include/arch.h b/lib/arch/include/arch.h index cc46639f..6d898fe1 100644 --- a/lib/arch/include/arch.h +++ b/lib/arch/include/arch.h @@ -395,6 +395,9 @@ #define ID_AA64DFR0_EL1_HPMN0_SHIFT UL(60) #define ID_AA64DFR0_EL1_HPMN0_WIDTH UL(4) +#define ID_AA64DFR0_EL1_ExtTrcBuff_SHIFT UL(56) +#define ID_AA64DFR0_EL1_ExtTrcBuff_WIDTH UL(4) + #define ID_AA64DFR0_EL1_BRBE_SHIFT UL(52) #define ID_AA64DFR0_EL1_BRBE_WIDTH UL(4) @@ -416,15 +419,26 @@ #define ID_AA64DFR0_EL1_CTX_CMPS_SHIFT UL(28) #define ID_AA64DFR0_EL1_CTX_CMPS_WIDTH UL(4) +#define ID_AA64DFR0_EL1_SEBEP_SHIFT UL(24) +#define ID_AA64DFR0_EL1_SEBEP_WIDTH UL(4) + #define ID_AA64DFR0_EL1_WRPs_SHIFT UL(20) #define ID_AA64DFR0_EL1_WRPs_WIDTH UL(4) +#define ID_AA64DFR0_EL1_PMSS_SHIFT UL(16) +#define ID_AA64DFR0_EL1_PMSS_WIDTH UL(4) + #define ID_AA64DFR0_EL1_BRPs_SHIFT UL(12) #define ID_AA64DFR0_EL1_BRPs_WIDTH UL(4) #define ID_AA64DFR0_EL1_PMUVer_SHIFT UL(8) #define ID_AA64DFR0_EL1_PMUVer_WIDTH UL(4) +/* Performance Monitors Extension version */ +#define ID_AA64DFR0_EL1_PMUv3p7 UL(7) +#define ID_AA64DFR0_EL1_PMUv3p8 UL(8) +#define ID_AA64DFR0_EL1_PMUv3p9 UL(9) + #define ID_AA64DFR0_EL1_TraceVer_SHIFT UL(4) #define ID_AA64DFR0_EL1_TraceVer_WIDTH UL(4) @@ -432,11 +446,18 @@ #define ID_AA64DFR0_EL1_DebugVer_WIDTH UL(4) /* Debug architecture version */ -#define ID_AA64DFR0_EL1_DebugVer_8 UL(6) -#define ID_AA64DFR0_EL1_DebugVer_8_VHE UL(7) -#define ID_AA64DFR0_EL1_DebugVer_8_2 UL(8) -#define ID_AA64DFR0_EL1_DebugVer_8_4 UL(9) -#define ID_AA64DFR0_EL1_DebugVer_8_8 UL(10) +#define ID_AA64DFR0_EL1_Debugv8 UL(6) +#define ID_AA64DFR0_EL1_DebugVHE UL(7) +#define ID_AA64DFR0_EL1_Debugv8p2 UL(8) +#define ID_AA64DFR0_EL1_Debugv8p4 UL(9) +#define ID_AA64DFR0_EL1_Debugv8p8 UL(10) + +/* ID_AA64DFR1_EL1 definitions */ +#define ID_AA64DFR1_EL1_EBEP_SHIFT UL(48) +#define ID_AA64DFR1_EL1_EBEP_WIDTH UL(4) + +#define ID_AA64DFR1_EL1_ICNTR_SHIFT UL(36) +#define ID_AA64DFR1_EL1_ICNTR_WIDTH UL(4) /* ID_AA64PFR0_EL1 definitions */ #define ID_AA64PFR0_EL1_SVE_SHIFT UL(32) @@ -463,34 +484,35 @@ #define ID_AA64MMFR0_EL1_ECV_SHIFT UL(60) #define ID_AA64MMFR0_EL1_ECV_WIDTH UL(4) -#define ID_AA64MMFR0_EL1_ECV_NOT_SUPPORTED ULL(0x0) -#define ID_AA64MMFR0_EL1_ECV_SUPPORTED ULL(0x1) +#define ID_AA64MMFR0_EL1_ECV_NOT_SUPPORTED UL(0x0) +#define ID_AA64MMFR0_EL1_ECV_SUPPORTED UL(0x1) #define ID_AA64MMFR0_EL1_ECV_SELF_SYNCH ULL(0x2) #define ID_AA64MMFR0_EL1_FGT_SHIFT UL(56) #define ID_AA64MMFR0_EL1_FGT_WIDTH UL(4) -#define ID_AA64MMFR0_EL1_FGT_SUPPORTED ULL(0x1) -#define ID_AA64MMFR0_EL1_FGT_NOT_SUPPORTED ULL(0x0) +#define ID_AA64MMFR0_EL1_FGT_NOT_SUPPORTED UL(0x0) +#define ID_AA64MMFR0_EL1_FGT_SUPPORTED UL(0x1) +#define ID_AA64MMFR0_EL1_FGT2_SUPPORTED UL(0x2) #define ID_AA64MMFR0_EL1_TGRAN4_2_SHIFT U(40) #define ID_AA64MMFR0_EL1_TGRAN4_2_WIDTH U(4) -#define ID_AA64MMFR0_EL1_TGRAN4_2_TGRAN4 ULL(0x0) -#define ID_AA64MMFR0_EL1_TGRAN4_2_NOT_SUPPORTED ULL(0x1) -#define ID_AA64MMFR0_EL1_TGRAN4_2_SUPPORTED ULL(0x2) -#define ID_AA64MMFR0_EL1_TGRAN4_2_LPA2 ULL(0x3) +#define ID_AA64MMFR0_EL1_TGRAN4_2_TGRAN4 UL(0x0) +#define ID_AA64MMFR0_EL1_TGRAN4_2_NOT_SUPPORTED UL(0x1) +#define ID_AA64MMFR0_EL1_TGRAN4_2_SUPPORTED UL(0x2) +#define ID_AA64MMFR0_EL1_TGRAN4_2_LPA2 UL(0x3) #define ID_AA64MMFR0_EL1_TGRAN16_2_SHIFT UL(32) #define ID_AA64MMFR0_EL1_TGRAN16_2_WIDTH UL(4) -#define ID_AA64MMFR0_EL1_TGRAN16_2_TGRAN16 ULL(0x0) -#define ID_AA64MMFR0_EL1_TGRAN16_2_NOT_SUPPORTED ULL(0x1) -#define ID_AA64MMFR0_EL1_TGRAN16_2_SUPPORTED ULL(0x2) -#define ID_AA64MMFR0_EL1_TGRAN16_2_LPA2 ULL(0x3) +#define ID_AA64MMFR0_EL1_TGRAN16_2_TGRAN16 UL(0x0) +#define ID_AA64MMFR0_EL1_TGRAN16_2_NOT_SUPPORTED UL(0x1) +#define ID_AA64MMFR0_EL1_TGRAN16_2_SUPPORTED UL(0x2) +#define ID_AA64MMFR0_EL1_TGRAN16_2_LPA2 UL(0x3) #define ID_AA64MMFR0_EL1_TGRAN4_SHIFT UL(28) #define ID_AA64MMFR0_EL1_TGRAN4_WIDTH UL(4) -#define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED ULL(0x0) -#define ID_AA64MMFR0_EL1_TGRAN4_LPA2 ULL(0x1) -#define ID_AA64MMFR0_EL1_TGRAN4_NOT_SUPPORTED ULL(0xf) +#define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED UL(0x0) +#define ID_AA64MMFR0_EL1_TGRAN4_LPA2 UL(0x1) +#define ID_AA64MMFR0_EL1_TGRAN4_NOT_SUPPORTED UL(0xf) #define ID_AA64MMFR0_EL1_TGRAN64_SHIFT UL(24) #define ID_AA64MMFR0_EL1_TGRAN64_WIDTH UL(4) @@ -627,10 +649,17 @@ SCTLR_EL1_SA0 | SCTLR_EL1_SA) /* PMCR_EL0 Definitions */ -#define PMCR_EL0_LC_BIT (UL(1) << 6) - -#define PMCR_EL0_RES1 PMCR_EL0_LC_BIT - +#define PMCR_EL0_N_SHIFT 11 +#define PMCR_EL0_N_WIDTH 5 +#define PMCR_EL0_LC_BIT (UL(1) << 6) +#define PMCR_EL0_DP_BIT (UL(1) << 5) +#define PMCR_EL0_C_BIT (UL(1) << 2) +#define PMCR_EL0_P_BIT (UL(1) << 1) +#define PMCR_EL0_E_BIT (UL(1) << 0) + +#define PMCR_EL0_INIT (PMCR_EL0_LC_BIT | PMCR_EL0_DP_BIT) +#define PMCR_EL0_INIT_RESET (PMCR_EL0_INIT | PMCR_EL0_C_BIT | \ + PMCR_EL0_P_BIT) /* MDSCR_EL1 Definitions */ #define MDSCR_EL1_TDCC_BIT (UL(1) << 12) @@ -721,6 +750,10 @@ CPTR_EL2_RES1) /* MDCR_EL2 definitions */ +#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) @@ -735,9 +768,16 @@ #define MDCR_EL2_HPME_BIT (UL(1) << 7) #define MDCR_EL2_TPM_BIT (UL(1) << 6) #define MDCR_EL2_TPMCR_BIT (UL(1) << 5) -#define MDCR_EL2_INIT (MDCR_EL2_TPMCR_BIT \ - | MDCR_EL2_TPM_BIT \ - | MDCR_EL2_TDA_BIT) + +#define MDCR_EL2_HPMN_SHIFT UL(0) +#define MDCR_EL2_HPMN_WIDTH UL(5) + +#define MDCR_EL2_INIT (MDCR_EL2_MTPME | \ + MDCR_EL2_HCCD | \ + MDCR_EL2_HPMD | \ + MDCR_EL2_TDA_BIT | \ + MDCR_EL2_TPM_BIT | \ + MDCR_EL2_TPMCR_BIT) /* MPIDR definitions */ #define MPIDR_EL1_AFF_MASK 0xFF diff --git a/lib/arch/include/arch_features.h b/lib/arch/include/arch_features.h index 23fe6c01..8efed1eb 100644 --- a/lib/arch/include/arch_features.h +++ b/lib/arch/include/arch_features.h @@ -51,7 +51,7 @@ static inline bool is_feat_vmid16_present(void) /* * Check if FEAT_LPA2 is implemented. - * 4KB granule at stage 2 supports 52-bit input and output addresses: + * 4KB granule at stage 2 supports 52-bit input and output addresses: * ID_AA64MMFR0_EL1.TGran4_2 bits [43:40]: 0b0011 */ static inline bool is_feat_lpa2_4k_present(void) @@ -60,6 +60,16 @@ static inline bool is_feat_lpa2_4k_present(void) read_id_aa64mmfr0_el1()) == ID_AA64MMFR0_EL1_TGRAN4_2_LPA2); } +/* + * Returns Performance Monitors Extension version. + * ID_AA64DFR0_EL1.PMUVer, bits [11:8]: + * 0b0000: Performance Monitors Extension not implemented + */ +static inline unsigned int read_pmu_version(void) +{ + return EXTRACT(ID_AA64DFR0_EL1_PMUVer, read_id_aa64dfr0_el1()); +} + unsigned int arch_feat_get_pa_width(void); #endif /* ARCH_FEATURES_H */ diff --git a/lib/arch/include/arch_helpers.h b/lib/arch/include/arch_helpers.h index 805e4882..2338604f 100644 --- a/lib/arch/include/arch_helpers.h +++ b/lib/arch/include/arch_helpers.h @@ -186,7 +186,85 @@ DEFINE_SYSREG_RW_FUNCS(sp_el0) DEFINE_SYSREG_RW_FUNCS(sp_el1) DEFINE_SYSREG_RW_FUNCS(elr_el12) DEFINE_SYSREG_RW_FUNCS(spsr_el12) + +DEFINE_SYSREG_RW_FUNCS(pmccfiltr_el0) +DEFINE_SYSREG_RW_FUNCS(pmccntr_el0) +DEFINE_SYSREG_RW_FUNCS(pmcntenclr_el0) +DEFINE_SYSREG_RW_FUNCS(pmcntenset_el0) +DEFINE_SYSREG_RW_FUNCS(pmcr_el0) +DEFINE_SYSREG_RW_FUNCS(pmintenclr_el1) +DEFINE_SYSREG_RW_FUNCS(pmintenset_el1) +DEFINE_SYSREG_RW_FUNCS(pmovsclr_el0) +DEFINE_SYSREG_RW_FUNCS(pmovsset_el0) +DEFINE_SYSREG_RW_FUNCS(pmselr_el0) DEFINE_SYSREG_RW_FUNCS(pmuserenr_el0) +DEFINE_SYSREG_RW_FUNCS(pmxevcntr_el0) +DEFINE_SYSREG_RW_FUNCS(pmxevtyper_el0) + +DEFINE_SYSREG_RW_FUNCS(pmevcntr0_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr1_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr2_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr3_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr4_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr5_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr6_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr7_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr8_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr9_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr10_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr11_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr12_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr13_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr14_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr15_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr16_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr17_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr18_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr19_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr20_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr21_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr22_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr23_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr24_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr25_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr26_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr27_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr28_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr29_el0) +DEFINE_SYSREG_RW_FUNCS(pmevcntr30_el0) + +DEFINE_SYSREG_RW_FUNCS(pmevtyper0_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper1_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper2_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper3_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper4_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper5_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper6_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper7_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper8_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper9_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper10_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper11_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper12_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper13_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper14_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper15_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper16_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper17_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper18_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper19_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper20_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper21_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper22_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper23_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper24_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper25_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper26_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper27_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper28_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper29_el0) +DEFINE_SYSREG_RW_FUNCS(pmevtyper30_el0) + DEFINE_SYSREG_RW_FUNCS(tpidrro_el0) DEFINE_SYSREG_RW_FUNCS(tpidr_el0) DEFINE_SYSREG_RW_FUNCS(tpidr_el2) @@ -226,12 +304,17 @@ DEFINE_RENAME_SYSREG_READ_FUNC(ID_AA64MMFR1_EL1, id_aa64mmfr1_el1) DEFINE_RENAME_SYSREG_READ_FUNC(ID_AA64MMFR2_EL1, id_aa64mmfr2_el1) DEFINE_RENAME_SYSREG_READ_FUNC(ID_AA64PFR0_EL1, id_aa64pfr0_el1) DEFINE_RENAME_SYSREG_READ_FUNC(ID_AA64PFR1_EL1, id_aa64pfr1_el1) -DEFINE_RENAME_SYSREG_RW_FUNCS(icc_hppir1_el1, ICC_HPPIR1_EL1) +DEFINE_SYSREG_READ_FUNC(id_aa64afr0_el1) +DEFINE_SYSREG_READ_FUNC(id_aa64afr1_el1) +DEFINE_SYSREG_READ_FUNC(id_aa64dfr0_el1) +DEFINE_SYSREG_READ_FUNC(id_aa64dfr1_el1) DEFINE_SYSREG_READ_FUNC(id_aa64isar0_el1) +DEFINE_SYSREG_READ_FUNC(id_aa64isar1_el1) DEFINE_SYSREG_READ_FUNC(id_aa64mmfr0_el1) DEFINE_SYSREG_READ_FUNC(id_aa64mmfr1_el1) DEFINE_SYSREG_READ_FUNC(id_aa64mmfr2_el1) DEFINE_SYSREG_READ_FUNC(id_aa64pfr0_el1) +DEFINE_SYSREG_READ_FUNC(id_aa64pfr1_el1) DEFINE_RENAME_SYSREG_RW_FUNCS(mpam0_el1, MPAM0_EL1) DEFINE_SYSREG_READ_FUNC(id_afr0_el1) DEFINE_SYSREG_READ_FUNC(CurrentEl) @@ -303,7 +386,6 @@ DEFINE_SYSREG_READ_FUNC(isr_el1) DEFINE_SYSREG_RW_FUNCS(mdcr_el2) DEFINE_SYSREG_RW_FUNCS(hstr_el2) -DEFINE_SYSREG_RW_FUNCS(pmcr_el0) DEFINE_SYSREG_RW_FUNCS(mpam2_el2) DEFINE_SYSREG_RW_FUNCS(mpamhcr_el2) DEFINE_SYSREG_RW_FUNCS(pmscr_el2) @@ -335,7 +417,7 @@ DEFINE_RENAME_SYSREG_RW_FUNCS(cntpoff_el2, CNTPOFF_EL2) ******************************************************************************/ DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el2, ICC_SRE_EL2) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_ctrl_el1, ICC_CTLR_EL1) -DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir1_el2, ICC_HPPIR1_EL1) +DEFINE_RENAME_SYSREG_RW_FUNCS(icc_hppir1_el1, ICC_HPPIR1_EL1) /******************************************************************************* * Virtual GIC register accessor prototypes diff --git a/lib/arch/include/pmu.h b/lib/arch/include/pmu.h new file mode 100644 index 00000000..5d1588dd --- /dev/null +++ b/lib/arch/include/pmu.h @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * SPDX-FileCopyrightText: Copyright TF-RMM Contributors. + */ + +#ifndef PMU_H +#define PMU_H + +#include +#include + +struct rmi_rec_exit; +struct rec; + +struct pmev_regs { + unsigned long pmevcntr_el0; + unsigned long pmevtyper_el0; +}; + +/* + * PMU context structure. + * Align on cache writeback granule to minimise cache line + * thashing when allocated as an array for use by each CPU. + */ +struct pmu_state { + unsigned long pmccfiltr_el0; + unsigned long pmccntr_el0; + unsigned long pmcntenset_el0; + unsigned long pmcntenclr_el0; + unsigned long pmintenset_el1; + unsigned long pmintenclr_el1; + unsigned long pmovsset_el0; + unsigned long pmovsclr_el0; + unsigned long pmselr_el0; + unsigned long pmuserenr_el0; + unsigned long pmxevcntr_el0; + unsigned long pmxevtyper_el0; + + struct pmev_regs pmev_regs[31]; + +} __aligned(CACHE_WRITEBACK_GRANULE); + +void pmu_save_state(struct pmu_state *pmu, unsigned int num_cnts); +void pmu_restore_state(struct pmu_state *pmu, unsigned int num_cnts); +void pmu_update_rec_exit(struct rmi_rec_exit *rec_exit); + +#endif /* PMU_H */ diff --git a/lib/arch/src/pmu.c b/lib/arch/src/pmu.c new file mode 100644 index 00000000..53c6f6b3 --- /dev/null +++ b/lib/arch/src/pmu.c @@ -0,0 +1,155 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * SPDX-FileCopyrightText: Copyright TF-RMM Contributors. + */ + +#include +#include +#include +#include +#include + +/* Clear bits P0-P30, C and F0 */ +#define PMU_CLEAR_ALL 0x1FFFFFFFF + +#define READ_PMEV_EL0(n) { \ + case n: \ + pmu->pmev_regs[n].pmevcntr_el0 = read_pmevcntr##n##_el0(); \ + pmu->pmev_regs[n].pmevtyper_el0 = read_pmevtyper##n##_el0(); \ +} + +#define WRITE_PMEV_EL0(n) { \ + case n: \ + write_pmevcntr##n##_el0(pmu->pmev_regs[n].pmevcntr_el0); \ + write_pmevtyper##n##_el0(pmu->pmev_regs[n].pmevtyper_el0); \ +} + +/* + * Save PMU context to memory with number of event counters + * passed in 'num_cnts' and disable all event counters. + */ +void pmu_save_state(struct pmu_state *pmu, unsigned int num_cnts) +{ + assert(pmu != NULL); + + pmu->pmccfiltr_el0 = read_pmccfiltr_el0(); + pmu->pmccntr_el0 = read_pmccntr_el0(); + pmu->pmcntenset_el0 = read_pmcntenset_el0(); + pmu->pmcntenclr_el0 = read_pmcntenclr_el0(); + pmu->pmintenset_el1 = read_pmintenset_el1(); + pmu->pmintenclr_el1 = read_pmintenclr_el1(); + pmu->pmovsset_el0 = read_pmovsset_el0(); + pmu->pmovsclr_el0 = read_pmovsclr_el0(); + pmu->pmselr_el0 = read_pmselr_el0(); + pmu->pmuserenr_el0 = read_pmuserenr_el0(); + pmu->pmxevcntr_el0 = read_pmxevcntr_el0(); + pmu->pmxevtyper_el0 = read_pmxevtyper_el0(); + + if (num_cnts != 0UL) { + switch (--num_cnts) { + READ_PMEV_EL0(30); + READ_PMEV_EL0(29); + READ_PMEV_EL0(28); + READ_PMEV_EL0(27); + READ_PMEV_EL0(26); + READ_PMEV_EL0(25); + READ_PMEV_EL0(24); + READ_PMEV_EL0(23); + READ_PMEV_EL0(22); + READ_PMEV_EL0(21); + READ_PMEV_EL0(20); + READ_PMEV_EL0(19); + READ_PMEV_EL0(18); + READ_PMEV_EL0(17); + READ_PMEV_EL0(16); + READ_PMEV_EL0(15); + READ_PMEV_EL0(14); + READ_PMEV_EL0(13); + READ_PMEV_EL0(12); + READ_PMEV_EL0(11); + READ_PMEV_EL0(10); + READ_PMEV_EL0(9); + READ_PMEV_EL0(8); + READ_PMEV_EL0(7); + READ_PMEV_EL0(6); + READ_PMEV_EL0(5); + READ_PMEV_EL0(4); + READ_PMEV_EL0(3); + READ_PMEV_EL0(2); + READ_PMEV_EL0(1); + default: + pmu->pmev_regs[0].pmevcntr_el0 = read_pmevcntr0_el0(); + pmu->pmev_regs[0].pmevtyper_el0 = read_pmevtyper0_el0(); + } + } +} + +/* + * Restore PMU context from memory with + * number of event counters passed in 'num_cnts'. + */ +void pmu_restore_state(struct pmu_state *pmu, unsigned int num_cnts) +{ + assert(pmu != NULL); + + write_pmcntenset_el0(pmu->pmcntenset_el0); + write_pmcntenclr_el0(pmu->pmcntenclr_el0 ^ PMU_CLEAR_ALL); + write_pmintenset_el1(pmu->pmintenset_el1); + write_pmintenclr_el1(pmu->pmintenclr_el1 ^ PMU_CLEAR_ALL); + write_pmovsset_el0(pmu->pmovsset_el0); + write_pmovsclr_el0(pmu->pmovsclr_el0 ^ PMU_CLEAR_ALL); + write_pmselr_el0(pmu->pmselr_el0); + write_pmuserenr_el0(pmu->pmuserenr_el0); + write_pmxevcntr_el0(pmu->pmxevcntr_el0); + write_pmxevtyper_el0(pmu->pmxevtyper_el0); + + if (num_cnts != 0U) { + switch (--num_cnts) { + WRITE_PMEV_EL0(30); + WRITE_PMEV_EL0(29); + WRITE_PMEV_EL0(28); + WRITE_PMEV_EL0(27); + WRITE_PMEV_EL0(26); + WRITE_PMEV_EL0(25); + WRITE_PMEV_EL0(24); + WRITE_PMEV_EL0(23); + WRITE_PMEV_EL0(22); + WRITE_PMEV_EL0(21); + WRITE_PMEV_EL0(20); + WRITE_PMEV_EL0(19); + WRITE_PMEV_EL0(18); + WRITE_PMEV_EL0(17); + WRITE_PMEV_EL0(16); + WRITE_PMEV_EL0(15); + WRITE_PMEV_EL0(14); + WRITE_PMEV_EL0(13); + WRITE_PMEV_EL0(12); + WRITE_PMEV_EL0(11); + WRITE_PMEV_EL0(10); + WRITE_PMEV_EL0(9); + WRITE_PMEV_EL0(8); + WRITE_PMEV_EL0(7); + WRITE_PMEV_EL0(6); + WRITE_PMEV_EL0(5); + WRITE_PMEV_EL0(4); + WRITE_PMEV_EL0(3); + WRITE_PMEV_EL0(2); + WRITE_PMEV_EL0(1); + default: + write_pmevcntr0_el0(pmu->pmev_regs[0].pmevcntr_el0); + write_pmevtyper0_el0(pmu->pmev_regs[0].pmevtyper_el0); + } + } +} + +/* + * Expose Realm PMU state on REC exit. + */ +void pmu_update_rec_exit(struct rmi_rec_exit *rec_exit) +{ + assert(rec_exit != NULL); + + rec_exit->pmu_ovf = read_pmovsset_el0(); + rec_exit->pmu_intr_en = read_pmintenset_el1(); + rec_exit->pmu_cntr_en = read_pmcntenset_el0(); +} diff --git a/lib/realm/include/realm.h b/lib/realm/include/realm.h index 24c0202c..cd1ec793 100644 --- a/lib/realm/include/realm.h +++ b/lib/realm/include/realm.h @@ -72,6 +72,12 @@ struct rd { /* Algorithm to use for measurements */ enum hash_algo algorithm; + /* PMU enabled flag */ + bool pmu_enabled; + + /* Number of PMU counters */ + unsigned int pmu_num_cnts; + /* Realm measurement */ unsigned char measurement[MEASUREMENT_SLOT_NR][MAX_MEASUREMENT_SIZE]; diff --git a/lib/realm/include/rec.h b/lib/realm/include/rec.h index 457226d1..c1677e44 100644 --- a/lib/realm/include/rec.h +++ b/lib/realm/include/rec.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,6 @@ struct sysreg_state { unsigned long elr_el1; unsigned long spsr_el1; unsigned long pmcr_el0; - unsigned long pmuserenr_el0; unsigned long tpidrro_el0; unsigned long tpidr_el0; unsigned long csselr_el1; @@ -84,6 +84,7 @@ struct common_sysreg_state { unsigned long vttbr_el2; unsigned long vtcr_el2; unsigned long hcr_el2; + unsigned long mdcr_el2; }; /* @@ -96,25 +97,27 @@ struct ns_state { unsigned long icc_sre_el2; struct fpu_state *fpu; /* FPU/SVE saved lazily. */ struct sve_state *sve; + struct pmu_state *pmu; } __attribute__((aligned(CACHE_WRITEBACK_GRANULE))); /* - * This structure contains pointers to data that is allocated - * in auxilary granules. + * This structure contains pointers to data that are allocated + * in auxilary granules for a REC. */ struct rec_aux_data { - uint8_t *attest_heap_buf; /* Pointer to the heap buffer of this REC. */ + uint8_t *attest_heap_buf; /* pointer to the heap buffer */ + struct pmu_state *pmu; /* pointer to PMU state */ }; -/* This structure is used for storing FPU/SIMD context for realm. */ +/* This structure is used for storing FPU/SIMD context for REC */ struct rec_fpu_context { struct fpu_state fpu; bool used; }; struct rec { - struct granule *g_rec; /* the granule in which this rec lives */ - unsigned long rec_idx; /* Which rec is this */ + struct granule *g_rec; /* the granule in which this REC lives */ + unsigned long rec_idx; /* which REC is this */ bool runnable; unsigned long regs[31]; @@ -139,6 +142,8 @@ struct rec { int s2_starting_level; struct granule *g_rtt; struct granule *g_rd; + bool pmu_enabled; + unsigned int pmu_num_cnts; } realm_info; struct { @@ -153,7 +158,7 @@ struct rec { unsigned long far; } last_run_info; - /* Structure for storing FPU/SIMD context for realm. */ + /* Structure for storing FPU/SIMD context for Realm */ struct rec_fpu_context fpu_ctx; /* Pointer to per-cpu non-secure state */ diff --git a/lib/smc/include/smc-rmi.h b/lib/smc/include/smc-rmi.h index 678036b3..6c6268b9 100644 --- a/lib/smc/include/smc-rmi.h +++ b/lib/smc/include/smc-rmi.h @@ -429,7 +429,16 @@ struct rmi_rec_exit { unsigned char ripas_value; /* 0x510 */ }, 0x500, 0x600); /* Host call immediate value */ - SET_MEMBER_RMI(unsigned int imm, 0x600, 0x800); /* 0x600 */ + SET_MEMBER_RMI(unsigned int imm, 0x600, 0x700); /* 0x600 */ + + /* PMU overflow */ + SET_MEMBER_RMI(unsigned long pmu_ovf, 0x700, 0x708); /* 0x700 */ + + /* PMU interrupt enable */ + SET_MEMBER_RMI(unsigned long pmu_intr_en, 0x708, 0x710); /* 0x708 */ + + /* PMU counter enable */ + SET_MEMBER_RMI(unsigned long pmu_cntr_en, 0x710, 0x800); /* 0x710 */ }; /* @@ -440,7 +449,7 @@ struct rmi_rec_run { /* Entry information */ SET_MEMBER_RMI(struct rmi_rec_entry entry, 0, 0x800); /* Offset 0 */ /* Exit information */ - SET_MEMBER_RMI(struct rmi_rec_exit exit, 0x800, 0x1000); /* 0x800 */ + SET_MEMBER_RMI(struct rmi_rec_exit exit, 0x800, 0x1000);/* 0x800 */ }; #endif /* __ASSEMBLER__ */ diff --git a/lib/smc/src/smc-rmi-offsets.c b/lib/smc/src/smc-rmi-offsets.c index 4750dacd..9b594c21 100644 --- a/lib/smc/src/smc-rmi-offsets.c +++ b/lib/smc/src/smc-rmi-offsets.c @@ -48,6 +48,9 @@ COMPILER_ASSERT(offsetof(struct rmi_rec_exit, ripas_base) == 0x500); COMPILER_ASSERT(offsetof(struct rmi_rec_exit, ripas_size) == 0x508); COMPILER_ASSERT(offsetof(struct rmi_rec_exit, ripas_value) == 0x510); COMPILER_ASSERT(offsetof(struct rmi_rec_exit, imm) == 0x600); +COMPILER_ASSERT(offsetof(struct rmi_rec_exit, pmu_ovf) == 0x700); +COMPILER_ASSERT(offsetof(struct rmi_rec_exit, pmu_intr_en) == 0x708); +COMPILER_ASSERT(offsetof(struct rmi_rec_exit, pmu_cntr_en) == 0x710); COMPILER_ASSERT(sizeof(struct rmi_rec_run) <= GRANULE_SIZE); COMPILER_ASSERT(offsetof(struct rmi_rec_run, entry) == 0); diff --git a/lib/timers/src/timers.c b/lib/timers/src/timers.c index f16a6ad7..fa76307f 100644 --- a/lib/timers/src/timers.c +++ b/lib/timers/src/timers.c @@ -58,7 +58,7 @@ bool check_pending_timers(struct rec *rec) /* * We don't want to run the Realm just to immediately exit due a - * physical interrupt casused by one of the timer interrupts not having + * physical interrupt caused by one of the timer interrupts not having * been retired from the CPU interface yet. Check that the interrupts * are retired before entering the Realm. */ diff --git a/plat/host/common/src/host_utils.c b/plat/host/common/src/host_utils.c index 263f518a..910bb6a5 100644 --- a/plat/host/common/src/host_utils.c +++ b/plat/host/common/src/host_utils.c @@ -136,6 +136,13 @@ void host_util_setup_sysreg_and_boot_manifest(void) { int ret; + /* + * Initialize ID_AA64DFR0_EL1 with PMUVer field to PMUv3p7. + * (ID_AA64DFR0_EL1.PMUVer, bits [11:8] set to 7) + */ + ret = host_util_set_default_sysreg_cb("id_aa64dfr0_el1", + INPLACE(ID_AA64DFR0_EL1_PMUVer, 7UL)); + /* * Initialize ID_AA64MMFR0_EL1 with a physical address * range of 48 bits (PARange bits set to 0b0101) @@ -166,6 +173,13 @@ void host_util_setup_sysreg_and_boot_manifest(void) */ ret = host_util_set_default_sysreg_cb("elr_el2", 0UL); + /* + * Set number of event counters implemented to 31. + * (PMCR_EL0.N, bits [15:11] set to 31) + */ + ret = host_util_set_default_sysreg_cb("pmcr_el0", + INPLACE(PMCR_EL0_N, 31UL)); + /* * Only check the return value of the last callback setup, to detect * if we are out of callback slots. diff --git a/runtime/core/init.c b/runtime/core/init.c index c067d12b..81bdfeb4 100644 --- a/runtime/core/init.c +++ b/runtime/core/init.c @@ -3,7 +3,7 @@ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors. */ -#include +#include #include #include #include @@ -28,7 +28,10 @@ static void rmm_arch_init(void) SPE(write_pmscr_el2(PMSCR_EL2_INIT)); write_cnthctl_el2(CNTHCTL_EL2_INIT); - write_mdcr_el2(MDCR_EL2_INIT); + write_vpidr_el2(read_midr_el1()); + write_mdcr_el2(MDCR_EL2_INIT | + INPLACE(MDCR_EL2_HPMN, + EXTRACT(PMCR_EL0_N, read_pmcr_el0()))); } void rmm_warmboot_main(void) diff --git a/runtime/core/run.c b/runtime/core/run.c index f1369476..64f4b931 100644 --- a/runtime/core/run.c +++ b/runtime/core/run.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -19,7 +20,8 @@ static struct ns_state g_ns_data[MAX_CPUS]; static uint8_t g_sve_data[MAX_CPUS][sizeof(struct sve_state)] - __attribute__((aligned(sizeof(__uint128_t)))); + __aligned(sizeof(__uint128_t)); +static struct pmu_state g_pmu_data[MAX_CPUS]; /* * Initialize the aux data and any buffer pointers to the aux granule memory for @@ -29,10 +31,12 @@ static void init_aux_data(struct rec_aux_data *aux_data, void *rec_aux, unsigned int num_rec_aux) { - aux_data->attest_heap_buf = (uint8_t *)rec_aux; - /* Ensure we have enough aux granules for use by REC */ - assert(num_rec_aux >= REC_HEAP_PAGES); + assert(num_rec_aux >= REC_NUM_PAGES); + + aux_data->attest_heap_buf = (uint8_t *)rec_aux; + aux_data->pmu = (struct pmu_state *)((uint8_t *)rec_aux + + REC_HEAP_SIZE); } /* @@ -69,7 +73,6 @@ static void save_sysreg_state(struct sysreg_state *sysregs) sysregs->elr_el1 = read_elr_el12(); sysregs->spsr_el1 = read_spsr_el12(); sysregs->pmcr_el0 = read_pmcr_el0(); - sysregs->pmuserenr_el0 = read_pmuserenr_el0(); sysregs->tpidrro_el0 = read_tpidrro_el0(); sysregs->tpidr_el0 = read_tpidr_el0(); sysregs->csselr_el1 = read_csselr_el1(); @@ -105,7 +108,7 @@ static void save_sysreg_state(struct sysreg_state *sysregs) sysregs->cntv_cval_el0 = read_cntv_cval_el02(); } -static void save_realm_state(struct rec *rec) +static void save_realm_state(struct rec *rec, struct rmi_rec_exit *rec_exit) { save_sysreg_state(&rec->sysregs); @@ -113,6 +116,15 @@ static void save_realm_state(struct rec *rec) rec->pstate = read_spsr_el2(); gic_save_state(&rec->sysregs.gicstate); + + if (rec->realm_info.pmu_enabled) { + /* Expose PMU Realm state to NS */ + pmu_update_rec_exit(rec_exit); + + /* Save PMU context */ + pmu_save_state(rec->aux_data.pmu, + rec->realm_info.pmu_num_cnts); + } } static void restore_sysreg_state(struct sysreg_state *sysregs) @@ -122,7 +134,6 @@ static void restore_sysreg_state(struct sysreg_state *sysregs) write_elr_el12(sysregs->elr_el1); write_spsr_el12(sysregs->spsr_el1); write_pmcr_el0(sysregs->pmcr_el0); - write_pmuserenr_el0(sysregs->pmuserenr_el0); write_tpidrro_el0(sysregs->tpidrro_el0); write_tpidr_el0(sysregs->tpidr_el0); write_csselr_el1(sysregs->csselr_el1); @@ -166,6 +177,12 @@ static void restore_sysreg_state(struct sysreg_state *sysregs) write_cntv_ctl_el02(sysregs->cntv_ctl_el0); } +static void configure_realm_stage2(struct rec *rec) +{ + write_vtcr_el2(rec->common_sysregs.vtcr_el2); + write_vttbr_el2(rec->common_sysregs.vttbr_el2); +} + static void restore_realm_state(struct rec *rec) { /* @@ -177,21 +194,29 @@ static void restore_realm_state(struct rec *rec) isb(); restore_sysreg_state(&rec->sysregs); + write_elr_el2(rec->pc); write_spsr_el2(rec->pstate); write_hcr_el2(rec->sysregs.hcr_el2); + /* Control trapping of accesses to PMU registers */ + write_mdcr_el2(rec->common_sysregs.mdcr_el2); + gic_restore_state(&rec->sysregs.gicstate); -} -static void configure_realm_stage2(struct rec *rec) -{ - write_vtcr_el2(rec->common_sysregs.vtcr_el2); - write_vttbr_el2(rec->common_sysregs.vttbr_el2); + configure_realm_stage2(rec); + + if (rec->realm_info.pmu_enabled) { + /* Restore PMU context */ + pmu_restore_state(rec->aux_data.pmu, + rec->realm_info.pmu_num_cnts); + } } -static void save_ns_state(struct ns_state *ns_state) +static void save_ns_state(struct rec *rec) { + struct ns_state *ns_state = rec->ns; + save_sysreg_state(&ns_state->sysregs); /* @@ -202,10 +227,17 @@ static void save_ns_state(struct ns_state *ns_state) ns_state->sysregs.cnthctl_el2 = read_cnthctl_el2(); ns_state->icc_sre_el2 = read_icc_sre_el2(); + + if (rec->realm_info.pmu_enabled) { + /* Save PMU context */ + pmu_save_state(ns_state->pmu, rec->realm_info.pmu_num_cnts); + } } -static void restore_ns_state(struct ns_state *ns_state) +static void restore_ns_state(struct rec *rec) { + struct ns_state *ns_state = rec->ns; + restore_sysreg_state(&ns_state->sysregs); /* @@ -216,6 +248,12 @@ static void restore_ns_state(struct ns_state *ns_state) write_cnthctl_el2(ns_state->sysregs.cnthctl_el2); write_icc_sre_el2(ns_state->icc_sre_el2); + + if (rec->realm_info.pmu_enabled) { + /* Restore PMU state */ + pmu_restore_state(ns_state->pmu, + rec->realm_info.pmu_num_cnts); + } } static void activate_events(struct rec *rec) @@ -243,14 +281,18 @@ void rec_run_loop(struct rec *rec, struct rmi_rec_exit *rec_exit) void *rec_aux; unsigned int cpuid = my_cpuid(); + assert(cpuid < MAX_CPUS); assert(rec->ns == NULL); + assert(rec->fpu_ctx.used == false); - assert(cpuid < MAX_CPUS); ns_state = &g_ns_data[cpuid]; - /* ensure SVE/FPU context is cleared */ + /* Ensure SVE/FPU and PMU context is cleared */ assert(ns_state->sve == NULL); assert(ns_state->fpu == NULL); + assert(ns_state->pmu == NULL); + + rec->ns = ns_state; /* Map auxiliary granules */ rec_aux = map_rec_aux(rec->g_aux, rec->num_rec_aux); @@ -270,7 +312,7 @@ void rec_run_loop(struct rec *rec, struct rmi_rec_exit *rec_exit) */ if (!rec->alloc_info.ctx_initialised) { (void)attestation_heap_ctx_init(rec->aux_data.attest_heap_buf, - REC_HEAP_PAGES * SZ_4K); + REC_HEAP_SIZE); rec->alloc_info.ctx_initialised = true; } @@ -280,14 +322,10 @@ void rec_run_loop(struct rec *rec, struct rmi_rec_exit *rec_exit) ns_state->fpu = (struct fpu_state *)&g_sve_data[cpuid]; } - save_ns_state(ns_state); - restore_realm_state(rec); + ns_state->pmu = &g_pmu_data[cpuid]; - /* Prepare for lazy save/restore of FPU/SIMD registers. */ - rec->ns = ns_state; - assert(rec->fpu_ctx.used == false); - - configure_realm_stage2(rec); + save_ns_state(rec); + restore_realm_state(rec); do { /* @@ -335,22 +373,23 @@ void rec_run_loop(struct rec *rec, struct rmi_rec_exit *rec_exit) rec->fpu_ctx.used = false; } + report_timer_state_to_ns(rec_exit); + + save_realm_state(rec, rec_exit); + restore_ns_state(rec); + /* - * Clear FPU/SVE context while exiting + * Clear FPU/SVE and PMU context while exiting */ ns_state->sve = NULL; ns_state->fpu = NULL; + ns_state->pmu = NULL; /* * Clear NS pointer since that struct is local to this function. */ rec->ns = NULL; - report_timer_state_to_ns(rec_exit); - - save_realm_state(rec); - restore_ns_state(ns_state); - /* Undo the heap association */ attestation_heap_ctx_unassign_pe(); /* Unmap auxiliary granules */ diff --git a/runtime/core/sysregs.c b/runtime/core/sysregs.c index c45b4740..940b0b48 100644 --- a/runtime/core/sysregs.c +++ b/runtime/core/sysregs.c @@ -36,30 +36,32 @@ * - Debug architecture version: * set in ID_AA64DFR0_EL1_SET * - Trace unit System registers not implemented - * - PMU is not implemented * - Number of breakpoints: * set in ID_AA64DFR0_EL1_SET + * - PMU Snapshot extension not implemented * - Number of watchpoints: * set in ID_AA64DFR0_EL1_SET + * - Synchronous-exception-based event profiling not implemented * - Number of breakpoints that are context-aware * - Statistical Profiling Extension not implemented * - Armv8.4 Self-hosted Trace Extension not implemented * - Trace Buffer Extension not implemented - * - FEAT_MTPMU not implemented * - Branch Record Buffer Extension not implemented + * - Trace Buffer External Mode not implemented */ #define ID_AA64DFR0_EL1_CLEAR \ MASK(ID_AA64DFR0_EL1_DebugVer) | \ MASK(ID_AA64DFR0_EL1_TraceVer) | \ - MASK(ID_AA64DFR0_EL1_PMUVer) | \ MASK(ID_AA64DFR0_EL1_BRPs) | \ + MASK(ID_AA64DFR0_EL1_PMSS) | \ MASK(ID_AA64DFR0_EL1_WRPs) | \ + MASK(ID_AA64DFR0_EL1_SEBEP) | \ MASK(ID_AA64DFR0_EL1_CTX_CMPS) | \ MASK(ID_AA64DFR0_EL1_PMSVer) | \ MASK(ID_AA64DFR0_EL1_TraceFilt) | \ MASK(ID_AA64DFR0_EL1_TraceBuffer) | \ - MASK(ID_AA64DFR0_EL1_MTPMU) | \ - MASK(ID_AA64DFR0_EL1_BRBE) + MASK(ID_AA64DFR0_EL1_BRBE) | \ + MASK(ID_AA64DFR0_EL1_ExtTrcBuff) /* * Set fields: @@ -67,11 +69,22 @@ * - Number of breakpoints: 2 * - Number of watchpoints: 2 */ -#define ID_AA64DFR0_EL1_SET \ - ID_AA64DFR0_EL1_DebugVer_8 | \ - INPLACE(ID_AA64DFR0_EL1_BRPs, 1UL) | \ +#define ID_AA64DFR0_EL1_SET \ + INPLACE(ID_AA64DFR0_EL1_DebugVer, ID_AA64DFR0_EL1_Debugv8) | \ + INPLACE(ID_AA64DFR0_EL1_BRPs, 1UL) | \ INPLACE(ID_AA64DFR0_EL1_WRPs, 1UL) +/* + * ID_AA64DFR1_EL1: + * + * Cleared fields: + * - Exception-based event profiling not implemented + * - PMU fixed-function instruction counter not implemented + */ +#define ID_AA64DFR1_EL1_CLEAR \ + MASK(ID_AA64DFR1_EL1_EBEP) | \ + MASK(ID_AA64DFR1_EL1_ICNTR) + /* * ID_AA64ISAR1_EL1: * @@ -147,7 +160,7 @@ static bool handle_id_sysreg_trap(struct rec *rec, value = SYSREG_READ_CLEAR_SET(DFR0); break; SYSREG_CASE(DFR1) - value = SYSREG_READ(DFR1); + value = SYSREG_READ_CLEAR(DFR1); break; SYSREG_CASE(ISAR0) value = SYSREG_READ(ISAR0); diff --git a/runtime/rmi/feature.c b/runtime/rmi/feature.c index a5da4131..a5c4a6a8 100644 --- a/runtime/rmi/feature.c +++ b/runtime/rmi/feature.c @@ -9,8 +9,9 @@ #include #include #include +#include -#define RMM_FEATURE_MIN_IPA_SIZE PARANGE_0000_WIDTH +#define RMM_FEATURE_MIN_IPA_SIZE PARANGE_0000_WIDTH static unsigned long get_feature_register_0(void) { @@ -29,10 +30,16 @@ static unsigned long get_feature_register_0(void) feat_reg0 |= INPLACE(RMM_FEATURE_REGISTER_0_HASH_SHA_512, RMI_SUPPORTED); - /* PMU is not supported */ + /* RMM supports PMUv3p7+ */ + assert(read_pmu_version() >= ID_AA64DFR0_EL1_PMUv3p7); + + /* Set support for PMUv3 */ feat_reg0 |= INPLACE(RMM_FEATURE_REGISTER_0_PMU_EN, - RMI_NOT_SUPPORTED); - feat_reg0 |= INPLACE(RMM_FEATURE_REGISTER_0_PMU_NUM_CTRS, 0U); + RMI_SUPPORTED); + + /* Set number of PMU counters available */ + feat_reg0 |= INPLACE(RMM_FEATURE_REGISTER_0_PMU_NUM_CTRS, + EXTRACT(PMCR_EL0_N, read_pmcr_el0())); return feat_reg0; } @@ -63,13 +70,19 @@ static bool validate_feature_register_0(unsigned long value) /* Validate LPA2 flag */ if ((EXTRACT(RMM_FEATURE_REGISTER_0_LPA2, value) == RMI_LPA2) && - !is_feat_lpa2_4k_present()) { + (EXTRACT(RMM_FEATURE_REGISTER_0_LPA2, feat_reg0) == RMI_NO_LPA2)) { return false; } - /* Validate PMU_EN flag */ - if ((EXTRACT(RMM_FEATURE_REGISTER_0_PMU_EN, value) == RMI_SUPPORTED) || - (EXTRACT(RMM_FEATURE_REGISTER_0_PMU_NUM_CTRS, value) != 0U)) { + /* + * Skip validation of RMM_FEATURE_REGISTER_0_PMU_EN flag + * as RMM always assumes that PMUv3p7+ is present. + */ + + /* Validate number of PMU counters if PMUv3 is enabled */ + if ((EXTRACT(RMM_FEATURE_REGISTER_0_PMU_EN, value) == RMI_SUPPORTED) && + (EXTRACT(RMM_FEATURE_REGISTER_0_PMU_NUM_CTRS, value) != + EXTRACT(RMM_FEATURE_REGISTER_0_PMU_NUM_CTRS, feat_reg0))) { return false; } diff --git a/runtime/rmi/realm.c b/runtime/rmi/realm.c index b348e90c..f8f59fc2 100644 --- a/runtime/rmi/realm.c +++ b/runtime/rmi/realm.c @@ -297,7 +297,7 @@ unsigned long smc_realm_create(unsigned long rd_addr, rd->s2_ctx.ipa_bits = requested_ipa_bits(&p); rd->s2_ctx.s2_starting_level = p.rtt_level_start; rd->s2_ctx.num_root_rtts = p.rtt_num_start; - memcpy(&rd->rpv[0], &p.rpv[0], RPV_SIZE); + (void)memcpy(&rd->rpv[0], &p.rpv[0], RPV_SIZE); rd->s2_ctx.vmid = (unsigned int)p.vmid; @@ -315,6 +315,10 @@ unsigned long smc_realm_create(unsigned long rd_addr, rd->algorithm = HASH_ALGO_SHA512; break; } + + rd->pmu_enabled = EXTRACT(RMM_FEATURE_REGISTER_0_PMU_EN, p.features_0); + rd->pmu_num_cnts = EXTRACT(RMM_FEATURE_REGISTER_0_PMU_NUM_CTRS, p.features_0); + realm_params_measure(rd, &p); buffer_unmap(rd); diff --git a/runtime/rmi/rec.c b/runtime/rmi/rec.c index 5f82ad11..4bb4ebeb 100644 --- a/runtime/rmi/rec.c +++ b/runtime/rmi/rec.c @@ -74,11 +74,12 @@ static void rec_params_measure(struct rd *rd, struct rmi_rec_params *rec_params) static void init_rec_sysregs(struct rec *rec, unsigned long mpidr) { /* Set non-zero values only */ - rec->sysregs.pmcr_el0 = PMCR_EL0_RES1; + rec->sysregs.pmcr_el0 = rec->realm_info.pmu_enabled ? + PMCR_EL0_INIT_RESET : PMCR_EL0_INIT; + rec->sysregs.sctlr_el1 = SCTLR_EL1_FLAGS; rec->sysregs.mdscr_el1 = MDSCR_EL1_TDCC_BIT; rec->sysregs.vmpidr_el2 = mpidr | VMPIDR_EL2_RES1; - rec->sysregs.cnthctl_el2 = CNTHCTL_EL2_NO_TRAPS; } @@ -115,12 +116,23 @@ static unsigned long realm_vtcr(struct rd *rd) static void init_common_sysregs(struct rec *rec, struct rd *rd) { + unsigned long mdcr_el2_val = read_mdcr_el2(); + /* Set non-zero values only */ rec->common_sysregs.hcr_el2 = HCR_FLAGS; rec->common_sysregs.vtcr_el2 = realm_vtcr(rd); - rec->common_sysregs.vttbr_el2 = granule_addr(rd->s2_ctx.g_rtt); - rec->common_sysregs.vttbr_el2 &= MASK(TTBRx_EL2_BADDR); - rec->common_sysregs.vttbr_el2 |= INPLACE(VTTBR_EL2_VMID, rd->s2_ctx.vmid); + rec->common_sysregs.vttbr_el2 = (granule_addr(rd->s2_ctx.g_rtt) & + MASK(TTBRx_EL2_BADDR)) | + INPLACE(VTTBR_EL2_VMID, rd->s2_ctx.vmid); + + /* Control trapping of accesses to PMU registers */ + if (rd->pmu_enabled) { + mdcr_el2_val &= ~(MDCR_EL2_TPM_BIT | MDCR_EL2_TPMCR_BIT); + } else { + mdcr_el2_val |= (MDCR_EL2_TPM_BIT | MDCR_EL2_TPMCR_BIT); + } + + rec->common_sysregs.mdcr_el2 = mdcr_el2_val; } static void init_rec_regs(struct rec *rec, @@ -267,6 +279,9 @@ unsigned long smc_rec_create(unsigned long rec_addr, rec->realm_info.g_rtt = rd->s2_ctx.g_rtt; rec->realm_info.g_rd = g_rd; + rec->realm_info.pmu_enabled = rd->pmu_enabled; + rec->realm_info.pmu_num_cnts = rd->pmu_num_cnts; + rec_params_measure(rd, &rec_params); /* diff --git a/runtime/rsi/realm_attest.c b/runtime/rsi/realm_attest.c index 54ddb8e4..8bb3c89d 100644 --- a/runtime/rsi/realm_attest.c +++ b/runtime/rsi/realm_attest.c @@ -186,7 +186,7 @@ unsigned long handle_rsi_attest_token_init(struct rec *rec) rec->token_sign_ctx.state = ATTEST_SIGN_NOT_STARTED; restart = attestation_heap_reinit_pe(rec->aux_data.attest_heap_buf, - REC_HEAP_PAGES * SZ_4K); + REC_HEAP_SIZE); if (restart != 0) { /* There is no provision for this failure so panic */ panic();