1 /* 2 * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <stdbool.h> 8 9 #include <arch.h> 10 #include <arch_features.h> 11 #include <arch_helpers.h> 12 #include <lib/el3_runtime/pubsub.h> 13 #include <lib/extensions/spe.h> 14 15 #include <plat/common/platform.h> 16 17 typedef struct spe_ctx { 18 u_register_t pmblimitr_el1; 19 } spe_ctx_t; 20 21 static struct spe_ctx spe_ctxs[PLATFORM_CORE_COUNT]; 22 23 static inline void psb_csync(void) 24 { 25 /* 26 * The assembler does not yet understand the psb csync mnemonic 27 * so use the equivalent hint instruction. 28 */ 29 __asm__ volatile("hint #17"); 30 } 31 32 void spe_enable(cpu_context_t *ctx) 33 { 34 el3_state_t *state = get_el3state_ctx(ctx); 35 u_register_t mdcr_el3_val = read_ctx_reg(state, CTX_MDCR_EL3); 36 37 /* 38 * MDCR_EL3.NSPB (ARM v8.2): SPE enabled in Non-secure state 39 * and disabled in secure state. Accesses to SPE registers at 40 * S-EL1 generate trap exceptions to EL3. 41 * 42 * MDCR_EL3.NSPBE: Profiling Buffer uses Non-secure Virtual Addresses. 43 * When FEAT_RME is not implemented, this field is RES0. 44 * 45 * MDCR_EL3.EnPMSN (ARM v8.7): Do not trap access to PMSNEVFR_EL1 46 * register at NS-EL1 or NS-EL2 to EL3 if FEAT_SPEv1p2 is implemented. 47 * Setting this bit to 1 doesn't have any effect on it when 48 * FEAT_SPEv1p2 not implemented. 49 */ 50 mdcr_el3_val |= MDCR_NSPB(MDCR_NSPB_EL1) | MDCR_EnPMSN_BIT; 51 mdcr_el3_val &= ~(MDCR_NSPBE_BIT); 52 write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3_val); 53 } 54 55 void spe_disable(cpu_context_t *ctx) 56 { 57 el3_state_t *state = get_el3state_ctx(ctx); 58 u_register_t mdcr_el3_val = read_ctx_reg(state, CTX_MDCR_EL3); 59 60 /* 61 * MDCR_EL3.NSPB: Clear these bits to disable SPE feature, as it was enabled 62 * for Non-secure state only. After clearing these bits Secure state owns 63 * the Profiling Buffer and accesses to Statistical Profiling and Profiling 64 * Buffer control registers at EL2 and EL1 generate Trap exceptions to EL3 65 * 66 * MDCR_EL3.NSPBE: Don't care as it was cleared during spe_enable and setting 67 * this to 1 does not make sense as NSPBE{1} and NSPB{0b0x} is RESERVED. 68 * 69 * MDCR_EL3.EnPMSN (ARM v8.7): Clear the bit to trap access of PMSNEVFR_EL1 70 * from EL2/EL1 to EL3. 71 */ 72 mdcr_el3_val &= ~(MDCR_NSPB(MDCR_NSPB_EL1) | MDCR_EnPMSN_BIT); 73 write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3_val); 74 } 75 76 void spe_init_el2_unused(void) 77 { 78 uint64_t v; 79 80 /* 81 * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical 82 * profiling controls to EL2. 83 * 84 * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure 85 * state. Accesses to profiling buffer controls at 86 * Non-secure EL1 are not trapped to EL2. 87 */ 88 v = read_mdcr_el2(); 89 v &= ~MDCR_EL2_TPMS; 90 v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1); 91 write_mdcr_el2(v); 92 } 93 94 void spe_stop(void) 95 { 96 uint64_t v; 97 98 /* Drain buffered data */ 99 psb_csync(); 100 dsbnsh(); 101 102 /* Disable profiling buffer */ 103 v = read_pmblimitr_el1(); 104 v &= ~(1ULL << 0); 105 write_pmblimitr_el1(v); 106 isb(); 107 } 108 109 static void *spe_drain_buffers_hook(const void *arg) 110 { 111 if (!is_feat_spe_supported()) 112 return (void *)-1; 113 114 /* Drain buffered data */ 115 psb_csync(); 116 dsbnsh(); 117 118 return (void *)0; 119 } 120 121 static void *spe_context_save(const void *arg) 122 { 123 unsigned int core_pos; 124 struct spe_ctx *ctx; 125 126 if (is_feat_spe_supported()) { 127 core_pos = plat_my_core_pos(); 128 ctx = &spe_ctxs[core_pos]; 129 ctx->pmblimitr_el1 = read_pmblimitr_el1(); 130 } 131 132 return NULL; 133 } 134 135 static void *spe_context_restore(const void *arg) 136 { 137 unsigned int core_pos; 138 struct spe_ctx *ctx; 139 140 if (is_feat_spe_supported()) { 141 core_pos = plat_my_core_pos(); 142 ctx = &spe_ctxs[core_pos]; 143 write_pmblimitr_el1(ctx->pmblimitr_el1); 144 } 145 146 return NULL; 147 } 148 149 SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook); 150 151 SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, spe_context_save); 152 SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, spe_context_restore); 153