xref: /rk3399_ARM-atf/lib/extensions/trbe/trbe.c (revision 35b2bbf4942689fd52fa741ac7d93bc7f1d4c230)
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  */
trbe_enable_ns(cpu_context_t * ctx)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 
trbe_disable_all(cpu_context_t * ctx,bool ns)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 
trbe_disable_ns(cpu_context_t * ctx)72 void trbe_disable_ns(cpu_context_t *ctx)
73 {
74 	trbe_disable_all(ctx, true);
75 }
76 
trbe_disable_secure(cpu_context_t * ctx)77 void trbe_disable_secure(cpu_context_t *ctx)
78 {
79 	trbe_disable_all(ctx, false);
80 }
81 
trbe_disable_realm(cpu_context_t * ctx)82 void trbe_disable_realm(cpu_context_t *ctx)
83 {
84 	trbe_disable_all(ctx, false);
85 }
86 
87 
trbe_init_el2_unused(void)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