1 /* 2 * Copyright (c) 2021-2025, Arm Limited. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arch.h> 8 #include <arch_features.h> 9 #include <arch_helpers.h> 10 #include <lib/extensions/trbe.h> 11 12 13 /* 14 * TRBE is an unusual feature. Its enable is split into two: 15 * - (NSTBE, NSTB[0]) - the security state bits - determines which security 16 * state owns the trace buffer. 17 * - NSTB[1] - the enable bit - determines if the security state that owns the 18 * buffer may access TRBE registers. 19 * 20 * There is a secondary id register TRBIDR_EL1 that is more granular than 21 * ID_AA64DFR0_EL1. When a security state owns the buffer, TRBIDR_EL1.P will 22 * report that TRBE programming is allowed. This means that the usual assumption 23 * that leaving all bits to a default of zero will disable the feature may not 24 * work correctly. To correctly disable TRBE, the current security state must NOT 25 * own the buffer, irrespective of the enable bit. Then, to play nicely with 26 * SMCCC_ARCH_FEATURE_AVAILABILITY, the enable bit should correspond to the 27 * enable status. The feature is architected this way to allow for lazy context 28 * switching of the buffer - a world can be made owner of the buffer (with 29 * TRBIDR_EL1.P reporting full access) without giving it access to the registers 30 * (by trapping to EL3). Then context switching can be deferred until a world 31 * tries to use TRBE at which point access can be given and the trapping 32 * instruction repeated. 33 * 34 * This can be simplified to the following rules: 35 * 1. To enable TRBE for world X: 36 * * world X owns the buffer ((NSTBE, NSTB[0]) == SCR_EL3.{NSE, NS}) 37 * * trapping disabled (NSTB[0] == 1) 38 * 2. To disable TRBE for world X: 39 * * world X does not own the buffer ((NSTBE, NSTB[0]) != SCR_EL3.{NSE, NS}) 40 * * trapping enabled (NSTB[0] == 0) 41 */ 42 void trbe_enable_ns(cpu_context_t *ctx) 43 { 44 el3_state_t *state = get_el3state_ctx(ctx); 45 u_register_t mdcr_el3_val = read_ctx_reg(state, CTX_MDCR_EL3); 46 47 mdcr_el3_val |= MDCR_NSTB_EN_BIT | MDCR_NSTB_SS_BIT; 48 mdcr_el3_val &= ~(MDCR_NSTBE_BIT); 49 50 write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3_val); 51 } 52 53 static void trbe_disable_all(cpu_context_t *ctx, bool ns) 54 { 55 el3_state_t *state = get_el3state_ctx(ctx); 56 u_register_t mdcr_el3_val = read_ctx_reg(state, CTX_MDCR_EL3); 57 58 mdcr_el3_val &= ~MDCR_NSTB_EN_BIT; 59 mdcr_el3_val &= ~MDCR_NSTBE_BIT; 60 61 /* make NS owner, except when NS is running */ 62 if (ns) { 63 mdcr_el3_val &= ~MDCR_NSTB_SS_BIT; 64 } else { 65 mdcr_el3_val |= MDCR_NSTB_SS_BIT; 66 } 67 68 write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3_val); 69 } 70 71 72 void trbe_disable_ns(cpu_context_t *ctx) 73 { 74 trbe_disable_all(ctx, true); 75 } 76 77 void trbe_disable_secure(cpu_context_t *ctx) 78 { 79 trbe_disable_all(ctx, false); 80 } 81 82 void trbe_disable_realm(cpu_context_t *ctx) 83 { 84 trbe_disable_all(ctx, false); 85 } 86 87 88 void trbe_init_el2_unused(void) 89 { 90 /* 91 * MDCR_EL2.E2TB: Set to zero so that the trace Buffer 92 * owning exception level is NS-EL1 and, tracing is 93 * prohibited at NS-EL2. These bits are RES0 when 94 * FEAT_TRBE is not implemented. 95 */ 96 write_mdcr_el2(read_mdcr_el2() & ~MDCR_EL2_E2TB(MDCR_EL2_E2TB_EL1)); 97 } 98