feat(pmu): add PMU support for Realms

This patch adds support for using PMU in Realms.
It adds 'bool pmu_enabled' and 'unsigned int pmu_num_cnts'
variables in 'struct rd' and 'struct rec.realm_info'.

Signed-off-by: AlexeiFedorov <Alexei.Fedorov@arm.com>
Change-Id: I13aad600a0215ba66d25be12ede5f4b86e6b018a
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index efe5625..7b9b2ed 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -16,9 +16,9 @@
               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("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 5346395..1ff2b9e 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 @@
 	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 bb0367e..8afba1a 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_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 cc46639..6d898fe 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_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_RES1		PMCR_EL0_LC_BIT
-
+#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 23fe6c0..8efed1e 100644
--- a/lib/arch/include/arch_features.h
+++ b/lib/arch/include/arch_features.h
@@ -51,7 +51,7 @@
 
 /*
  * 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 @@
 		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 805e488..2338604 100644
--- a/lib/arch/include/arch_helpers.h
+++ b/lib/arch/include/arch_helpers.h
@@ -186,7 +186,85 @@
 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_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_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(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 0000000..5d1588d
--- /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 <arch_helpers.h>
+#include <utils_def.h>
+
+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 0000000..53c6f6b
--- /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 <arch_features.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <pmu.h>
+#include <smc-rmi.h>
+
+/* 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 24c0202..cd1ec79 100644
--- a/lib/realm/include/realm.h
+++ b/lib/realm/include/realm.h
@@ -72,6 +72,12 @@
 	/* 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 457226d..c1677e4 100644
--- a/lib/realm/include/rec.h
+++ b/lib/realm/include/rec.h
@@ -13,6 +13,7 @@
 #include <fpu_helpers.h>
 #include <gic.h>
 #include <memory_alloc.h>
+#include <pmu.h>
 #include <ripas.h>
 #include <sizes.h>
 #include <smc-rmi.h>
@@ -29,7 +30,6 @@
 	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 @@
 	unsigned long vttbr_el2;
 	unsigned long vtcr_el2;
 	unsigned long hcr_el2;
+	unsigned long mdcr_el2;
 };
 
 /*
@@ -96,25 +97,27 @@
 	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 @@
 		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 @@
 		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 678036b..6c6268b 100644
--- a/lib/smc/include/smc-rmi.h
+++ b/lib/smc/include/smc-rmi.h
@@ -429,7 +429,16 @@
 			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 @@
 	/* 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 4750dac..9b594c2 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_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 f16a6ad..fa76307 100644
--- a/lib/timers/src/timers.c
+++ b/lib/timers/src/timers.c
@@ -58,7 +58,7 @@
 
 	/*
 	 * 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.
 	 */