1 /*
2 * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
3 * Copyright (c) 2021, NVIDIA Corporation. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <assert.h>
9 #include <string.h>
10
11 #include <arch.h>
12 #include <arch_helpers.h>
13 #include <context.h>
14 #include <common/debug.h>
15 #include <lib/el3_runtime/context_mgmt.h>
16 #include <lib/xlat_tables/xlat_tables_v2.h>
17 #include <lib/utils.h>
18 #include <platform_def.h>
19 #include <plat/common/common_def.h>
20 #include <plat/common/platform.h>
21 #include <services/ffa_svc.h>
22
23 #include "spm_common.h"
24 #include "spm_shim_private.h"
25 #include "spmc.h"
26
27 /*
28 * We need to choose one execution context from all those available for a S-EL0
29 * SP. This execution context will be used subsequently irrespective of which
30 * physical CPU the SP runs on. The index of this context is chosen during setup
31 * on the primary cpu and stored in this variable for subsequent usage.
32 */
33 static unsigned int sel0_sp_ec_index = 0;
34
get_ec_index(sp_desc_t * sp)35 unsigned int get_ec_index(sp_desc_t *sp)
36 {
37 return (sp->runtime_el == EL0) ? sel0_sp_ec_index : plat_my_core_pos();
38 }
39
40 /* Setup context of a EL0 MM Secure Partition */
spmc_el0_sp_setup(sp_desc_t * sp,entry_point_info_t * ep_info)41 void spmc_el0_sp_setup(sp_desc_t *sp, entry_point_info_t *ep_info)
42 {
43 cpu_context_t *ctx;
44
45 /*
46 * Choose the linear of the primary core as the index of the S-EL0 SP
47 * execution context.
48 */
49 sel0_sp_ec_index = plat_my_core_pos();
50 ctx = &sp->ec[sel0_sp_ec_index].cpu_ctx;
51
52 init_xlat_tables_ctx(sp->xlat_ctx_handle);
53
54 /*
55 * MMU-related registers
56 * ---------------------
57 */
58 xlat_ctx_t *xlat_ctx = sp->xlat_ctx_handle;
59
60 uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX];
61
62 setup_mmu_cfg((uint64_t *)&mmu_cfg_params, 0, xlat_ctx->base_table,
63 xlat_ctx->pa_max_address, xlat_ctx->va_max_address,
64 EL1_EL0_REGIME);
65
66 write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_MAIR_EL1,
67 mmu_cfg_params[MMU_CFG_MAIR]);
68
69 write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TCR_EL1,
70 mmu_cfg_params[MMU_CFG_TCR]);
71
72 write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TTBR0_EL1,
73 mmu_cfg_params[MMU_CFG_TTBR0]);
74
75 /* Setup SCTLR_EL1 */
76 u_register_t sctlr_el1 = read_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1);
77
78 sctlr_el1 |=
79 /*SCTLR_EL1_RES1 |*/
80 /* Don't trap DC CVAU, DC CIVAC, DC CVAC, DC CVAP, or IC IVAU */
81 SCTLR_UCI_BIT |
82 /* RW regions at xlat regime EL1&0 are forced to be XN. */
83 SCTLR_WXN_BIT |
84 /* Don't trap to EL1 execution of WFI or WFE at EL0. */
85 SCTLR_NTWI_BIT | SCTLR_NTWE_BIT |
86 /* Don't trap to EL1 accesses to CTR_EL0 from EL0. */
87 SCTLR_UCT_BIT |
88 /* Don't trap to EL1 execution of DZ ZVA at EL0. */
89 SCTLR_DZE_BIT |
90 /* Enable SP Alignment check for EL0 */
91 SCTLR_SA0_BIT |
92 /* Don't change PSTATE.PAN on taking an exception to EL1 */
93 SCTLR_SPAN_BIT |
94 /* Allow cacheable data and instr. accesses to normal memory. */
95 SCTLR_C_BIT | SCTLR_I_BIT |
96 /* Enable MMU. */
97 SCTLR_M_BIT
98 ;
99
100 sctlr_el1 &= ~(
101 /* Explicit data accesses at EL0 are little-endian. */
102 SCTLR_E0E_BIT |
103 /*
104 * Alignment fault checking disabled when at EL1 and EL0 as
105 * the UEFI spec permits unaligned accesses.
106 */
107 SCTLR_A_BIT |
108 /* Accesses to DAIF from EL0 are trapped to EL1. */
109 SCTLR_UMA_BIT
110 );
111
112 write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1);
113
114 /*
115 * Setup other system registers
116 * ----------------------------
117 */
118
119 /* Shim Exception Vector Base Address */
120 write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_VBAR_EL1,
121 SPM_SHIM_EXCEPTIONS_PTR);
122
123 write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_CNTKCTL_EL1,
124 EL0PTEN_BIT | EL0VTEN_BIT | EL0PCTEN_BIT | EL0VCTEN_BIT);
125
126 /*
127 * FPEN: Allow the Secure Partition to access FP/SIMD registers.
128 * Note that SPM will not do any saving/restoring of these registers on
129 * behalf of the SP. This falls under the SP's responsibility.
130 * TTA: Enable access to trace registers.
131 * ZEN (v8.2): Trap SVE instructions and access to SVE registers.
132 */
133 write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_CPACR_EL1,
134 CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE));
135
136 sp->xlat_ctx_handle->xlat_regime =
137 EL1_EL0_REGIME;
138
139 /* This region contains the exception vectors used at S-EL1. */
140 mmap_region_t sel1_exception_vectors =
141 MAP_REGION_FLAT(SPM_SHIM_EXCEPTIONS_START,
142 SPM_SHIM_EXCEPTIONS_SIZE,
143 MT_CODE | MT_SECURE | MT_PRIVILEGED);
144 mmap_add_region_ctx(sp->xlat_ctx_handle,
145 &sel1_exception_vectors);
146
147 /*
148 * Save the stack base in SP_EL0 so that there is a C runtime upon the
149 * first ERET into the StMM SP.
150 */
151 write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_SP_EL0,
152 sp->sp_stack_base + sp->sp_stack_size);
153
154 }
155
156 /* SEL1 partition specific initialisation. */
spmc_el1_sp_setup(sp_desc_t * sp,entry_point_info_t * ep_info)157 void spmc_el1_sp_setup(sp_desc_t *sp, entry_point_info_t *ep_info)
158 {
159 /* Sanity check input arguments */
160 assert(NULL != sp);
161 assert(NULL != ep_info);
162
163 /*
164 * Lets just zero the general purpose registers for now. This would be a
165 * good time to let the platform enforce its own boot protocol.
166 */
167 zeromem(&ep_info->args, sizeof(ep_info->args));
168
169 /*
170 * Check whether setup is being performed for the primary or a secondary
171 * execution context. In the latter case, indicate to the SP that this
172 * is a warm boot.
173 * TODO: This check would need to be reworked if the same entry point is
174 * used for both primary and secondary initialisation.
175 */
176 if (sp->secondary_ep) {
177 /*
178 * Sanity check that the secondary entry point is still what was
179 * originally set.
180 */
181 assert (sp->secondary_ep == ep_info->pc);
182
183 write_ctx_reg(get_gpregs_ctx(&sp->ec[get_ec_index(sp)].cpu_ctx),
184 CTX_GPREG_X0,
185 FFA_WB_TYPE_S2RAM);
186 }
187 }
188
189 /* Common initialisation for all SPs. */
spmc_sp_common_setup(sp_desc_t * sp,entry_point_info_t * ep_info)190 void spmc_sp_common_setup(sp_desc_t *sp, entry_point_info_t *ep_info)
191 {
192 cpu_context_t *cpu_ctx;
193
194 /* Assign FFA Partition ID if not already assigned */
195 if (sp->sp_id == INV_SP_ID)
196 sp->sp_id = FFA_SP_ID_BASE + ACTIVE_SP_DESC_INDEX;
197
198 /*
199 * The initialisation of the SPSR in the ep_info should ideally be done
200 * in the EL specific initialisation routines above. However,
201 * cm_context_setup() needs this information to initialise system
202 * registers correctly. So, lets do this here.
203 */
204 if (sp->runtime_el == EL0)
205 /* Setup Secure Partition SPSR for S-EL0 SP*/
206 ep_info->spsr = SPSR_64(MODE_EL0, MODE_SP_EL0,
207 DISABLE_ALL_EXCEPTIONS);
208 else
209 /* Setup Secure Partition SPSR for S-EL1 SP */
210 ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
211 DISABLE_ALL_EXCEPTIONS);
212
213 /*
214 * Initialise the SP context based upon the entrypoint information
215 * collected so far. We are assuming that the index of the execution
216 * context used for both S-EL0 and S-EL1 SPs is the linear index of the
217 * primary cpu. This index was saved in spmc_el0_sp_setup() as well.
218 */
219 cpu_ctx = &sp->ec[plat_my_core_pos()].cpu_ctx;
220 cm_setup_context(cpu_ctx, ep_info);
221 }
222