1 /* 2 * Copyright (c) 2017-2023, 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 psb_csync(void)15static inline void psb_csync(void) 16 { 17 /* 18 * The assembler does not yet understand the psb csync mnemonic 19 * so use the equivalent hint instruction. 20 */ 21 __asm__ volatile("hint #17"); 22 } 23 spe_init_el3(void)24void spe_init_el3(void) 25 { 26 uint64_t v; 27 28 /* 29 * MDCR_EL3.NSPB (ARM v8.2): SPE enabled in Non-secure state 30 * and disabled in secure state. Accesses to SPE registers at 31 * S-EL1 generate trap exceptions to EL3. 32 * 33 * MDCR_EL3.NSPBE: Profiling Buffer uses Non-secure Virtual Addresses. 34 * When FEAT_RME is not implemented, this field is RES0. 35 * 36 * MDCR_EL3.EnPMSN (ARM v8.7): Do not trap access to PMSNEVFR_EL1 37 * register at NS-EL1 or NS-EL2 to EL3 if FEAT_SPEv1p2 is implemented. 38 * Setting this bit to 1 doesn't have any effect on it when 39 * FEAT_SPEv1p2 not implemented. 40 */ 41 v = read_mdcr_el3(); 42 v |= MDCR_NSPB(MDCR_NSPB_EL1) | MDCR_EnPMSN_BIT; 43 v &= ~(MDCR_NSPBE_BIT); 44 write_mdcr_el3(v); 45 } 46 spe_init_el2_unused(void)47void spe_init_el2_unused(void) 48 { 49 uint64_t v; 50 51 /* 52 * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical 53 * profiling controls to EL2. 54 * 55 * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure 56 * state. Accesses to profiling buffer controls at 57 * Non-secure EL1 are not trapped to EL2. 58 */ 59 v = read_mdcr_el2(); 60 v &= ~MDCR_EL2_TPMS; 61 v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1); 62 write_mdcr_el2(v); 63 } 64 spe_disable(void)65void spe_disable(void) 66 { 67 uint64_t v; 68 69 /* Drain buffered data */ 70 psb_csync(); 71 dsbnsh(); 72 73 /* Disable profiling buffer */ 74 v = read_pmblimitr_el1(); 75 v &= ~(1ULL << 0); 76 write_pmblimitr_el1(v); 77 isb(); 78 } 79 spe_drain_buffers_hook(const void * arg)80static void *spe_drain_buffers_hook(const void *arg) 81 { 82 if (!is_feat_spe_supported()) 83 return (void *)-1; 84 85 /* Drain buffered data */ 86 psb_csync(); 87 dsbnsh(); 88 89 return (void *)0; 90 } 91 92 SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook); 93