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