blob: 79ba4cdebed8cf3560bdabc4b388aa88ed53b54d [file] [log] [blame]
Miklos Balint386b8b52017-11-29 13:12:32 +00001/*
2 * Copyright (c) 2017, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8/* This file contains the apis exported by the SPM to tfm core */
9
10#include <stdio.h>
11#include "spm_db.h"
12#include "spm_api.h"
13#include "mpu_armv8m_drv.h"
14#include "region_defs.h"
15#include "secure_fw/core/tfm_core.h"
16
17struct spm_service_db_t g_spm_service_db = {0,};
18
19#define MPU_REGION_VENEERS 0
20#define MPU_REGION_TFM_UNPRIV_CODE 1
21#define MPU_REGION_TFM_UNPRIV_DATA 2
22#define MPU_REGION_NS_DATA 3
23#define SERVICE_REGION_RO 4
24#define SERVICE_REGION_RW_STACK 5
25#define SERVICE_REGION_PERIPH 6
26#define SERVICE_REGION_SHARE 7
27
28/* This should move to platform retarget */
29struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
30
31typedef enum {
32 TFM_INIT_FAILURE,
33} ss_error_type_t;
34
35/*
36 * This function is called when a secure service causes an error.
37 */
38static void tfm_spm_service_err_handler(
39 uint32_t ss_id, ss_error_type_t err_type, int32_t err_code)
40{
41 /*
42 * FixMe: error handling to be added. E.g. service info to be updated with
43 * init failed so that calls to the service are rejected
44 */
45#ifdef TFM_CORE_DEBUG
46 if (err_type == TFM_INIT_FAILURE) {
47 printf("Service init failed for service id 0x%08X\r\n", ss_id);
48 } else {
49 printf("Unknown service error %d for service id 0x%08X\r\n",
50 err_type,
51 ss_id);
52 }
53#endif
54}
55
56enum spm_err_t tfm_spm_db_init(void)
57{
58 /* This function initialises service db */
59 g_spm_service_db.is_init = 1;
60
61 g_spm_service_db.services_count =
62 create_user_service_db(&g_spm_service_db, SPM_MAX_SERVICES);
63
64 return SPM_ERR_OK;
65}
66
67#if TFM_LVL != 1
68REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
69REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
70REGION_DECLARE(Image$$, TFM_UNPRIV_RO_DATA, $$RW$$Base);
71REGION_DECLARE(Image$$, TFM_UNPRIV_RO_DATA, $$ZI$$Limit);
72REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
73REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
74
75enum spm_err_t tfm_spm_mpu_init(void)
76{
77 mpu_armv8m_clean(&dev_mpu_s);
78
79 struct mpu_armv8m_region_cfg_t region_cfg;
80
81 /* Veneer region */
82 region_cfg.region_nr = MPU_REGION_VENEERS;
83 region_cfg.region_base = CMSE_VENEER_REGION_START;
84 region_cfg.region_limit = CMSE_VENEER_REGION_LIMIT;
85 region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
86 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
87 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
88 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
89
90 /* TFM Core unprivileged code region */
91 region_cfg.region_nr = MPU_REGION_TFM_UNPRIV_CODE;
92 region_cfg.region_base =
93 (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
94 region_cfg.region_limit =
95 (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
96 region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
97 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
98 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
99 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
100
101 /* TFM Core unprivileged data region */
102 region_cfg.region_nr = MPU_REGION_TFM_UNPRIV_DATA;
103 region_cfg.region_base =
104 (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_RO_DATA, $$RW$$Base);
105 region_cfg.region_limit =
106 (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_RO_DATA, $$ZI$$Limit);
107 region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
108 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
109 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
110 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
111
112 /* TFM Core unprivileged non-secure data region */
113 region_cfg.region_nr = MPU_REGION_NS_DATA;
114 region_cfg.region_base = NS_DATA_START;
115 region_cfg.region_limit = NS_DATA_LIMIT;
116 region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
117 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
118 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
119 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
120
121 mpu_armv8m_enable(&dev_mpu_s, 1, 1);
122
123 return SPM_ERR_OK;
124}
125
126enum spm_err_t tfm_spm_set_share_region(enum tfm_buffer_share_region_e share)
127{
128 enum spm_err_t res = SPM_ERR_INVALID_CONFIG;
129 uint32_t scratch_base =
130 (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
131 uint32_t scratch_limit =
132 (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
133
134 mpu_armv8m_disable(&dev_mpu_s);
135
136 if (share == TFM_BUFFER_SHARE_DISABLE) {
137 mpu_armv8m_region_disable(&dev_mpu_s, SERVICE_REGION_SHARE);
138 } else {
139 struct mpu_armv8m_region_cfg_t region_cfg;
140
141 region_cfg.region_nr = SERVICE_REGION_SHARE;
142 region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
143 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
144 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
145 switch (share) {
146 case TFM_BUFFER_SHARE_SCRATCH:
147 /* Use scratch area for service-to-service data sharing */
148 region_cfg.region_base = scratch_base;
149 region_cfg.region_limit = scratch_limit;
150 res = SPM_ERR_OK;
151 break;
152 case TFM_BUFFER_SHARE_NS_CODE:
153 region_cfg.region_base = NS_CODE_START;
154 region_cfg.region_limit = NS_CODE_LIMIT;
155 /* Only allow read access to NS code region and keep
156 * exec.never attribute
157 */
158 region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
159 res = SPM_ERR_OK;
160 break;
161 default:
162 res = SPM_ERR_INVALID_CONFIG;
163 break;
164 }
165 if (res == SPM_ERR_OK) {
166 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
167 }
168 }
169 mpu_armv8m_enable(&dev_mpu_s, 1, 1);
170
171 return res;
172}
173#endif
174
175enum spm_err_t tfm_spm_service_init(void)
176{
177 struct spm_service_region_t *serv;
178 int32_t fail_cnt = 0;
179 uint32_t i;
180
181 /* Call the init function for each service */
182 /* FixMe: This implementation only fits level 1 isolation.
183 * On higher levels MPU (and PPC) configuration need to be in place to have
184 * proper isolation during init.
185 */
186 for (i = 0; i < g_spm_service_db.services_count; ++i) {
187 serv = &g_spm_service_db.services[i];
188 if (serv->periph_start) {
189 ppc_configure_to_secure(serv->periph_ppc_bank,
190 serv->periph_ppc_loc);
191 }
192 if (serv->service_init != 0) {
193 int32_t ret = serv->service_init();
194
195 if (ret != 0) {
196 tfm_spm_service_err_handler(serv->service_id,
197 TFM_INIT_FAILURE, ret);
198 fail_cnt++;
199 }
200 }
201 }
202
203 if (fail_cnt == 0) {
204 return SPM_ERR_OK;
205 } else {
206 return SPM_ERR_SERV_NOT_AVAILABLE;
207 }
208}
209
210#if TFM_LVL != 1
211enum spm_err_t tfm_spm_service_sandbox_config(uint32_t service_id)
212{
213 /* This function takes a service id and enables the
214 * SPM partition for that service
215 */
216
217 struct spm_service_region_t *serv;
218 struct mpu_armv8m_region_cfg_t region_cfg;
219
220 if (!g_spm_service_db.is_init) {
221 return SPM_ERR_SERV_DB_NOT_INIT;
222 }
223
224 /*brute force id*/
225 serv = &g_spm_service_db.services[SERVICE_ID_GET(service_id)];
226
227 mpu_armv8m_disable(&dev_mpu_s);
228
229 /* Configure Regions */
230
231 /* RO region*/
232 region_cfg.region_nr = SERVICE_REGION_RO;
233 region_cfg.region_base = serv->ro_start;
234 region_cfg.region_limit = serv->ro_limit;
235 region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
236 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
237 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
238
239 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
240
241 /* RW, ZI and stack as one region*/
242 region_cfg.region_nr = SERVICE_REGION_RW_STACK;
243 region_cfg.region_base = serv->rw_start;
244 region_cfg.region_limit = serv->stack_top;
245 region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
246 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
247 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
248
249 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
250
251 if (serv->periph_start) {
252 /* Peripheral */
253 region_cfg.region_nr = SERVICE_REGION_PERIPH;
254 region_cfg.region_base = serv->periph_start;
255 region_cfg.region_limit = serv->periph_limit;
256 region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
257 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
258 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
259 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
260
261 ppc_en_secure_unpriv(serv->periph_ppc_bank, serv->periph_ppc_loc);
262 }
263
264 mpu_armv8m_enable(&dev_mpu_s, 1, 1);
265
266#ifndef UNPRIV_JUMP_TO_NS
267 /* FixMe: if jump_to_ns_code() from unprivileged is solved,
268 * this code can be removed
269 */
270 /* Initialization is done, set thread mode to unprivileged.
271 */
272 CONTROL_Type ctrl;
273
274 ctrl.w = __get_CONTROL();
275 ctrl.b.nPRIV = 1;
276 __set_CONTROL(ctrl.w);
277 __DSB();
278 __ISB();
279#endif
280
281 return SPM_ERR_OK;
282}
283
284enum spm_err_t tfm_spm_service_sandbox_deconfig(uint32_t service_id)
285{
286 /* This function takes a service id and disables the
287 * SPM partition for that service
288 */
289
290#ifndef UNPRIV_JUMP_TO_NS
291 /* FixMe: if jump_to_ns_code() from unprivileged is solved,
292 * this code can be removed
293 */
294 CONTROL_Type ctrl;
295
296 ctrl.w = __get_CONTROL();
297 ctrl.b.nPRIV = 0;
298 __set_CONTROL(ctrl.w);
299 __DSB();
300 __ISB();
301#endif
302
303 struct spm_service_region_t *serv;
304
305 serv = &g_spm_service_db.services[SERVICE_ID_GET(service_id)];
306
307 if (serv->periph_start) {
308 /* Peripheral */
309 ppc_clr_secure_unpriv(serv->periph_ppc_bank, serv->periph_ppc_loc);
310 }
311
312 mpu_armv8m_disable(&dev_mpu_s);
313 mpu_armv8m_region_disable(&dev_mpu_s, SERVICE_REGION_RO);
314 mpu_armv8m_region_disable(&dev_mpu_s, SERVICE_REGION_RW_STACK);
315 mpu_armv8m_region_disable(&dev_mpu_s, SERVICE_REGION_PERIPH);
316 mpu_armv8m_region_disable(&dev_mpu_s, SERVICE_REGION_SHARE);
317 mpu_armv8m_enable(&dev_mpu_s, 1, 1);
318
319 return SPM_ERR_OK;
320}
321
322uint32_t tfm_spm_service_get_stack(uint32_t service_id)
323{
324 return g_spm_service_db.services[SERVICE_ID_GET(service_id)].stack_ptr;
325}
326
327uint32_t tfm_spm_service_get_stack_bottom(uint32_t service_id)
328{
329 return g_spm_service_db.services[SERVICE_ID_GET(service_id)].stack_bottom;
330}
331
332uint32_t tfm_spm_service_get_stack_top(uint32_t service_id)
333{
334 return g_spm_service_db.services[SERVICE_ID_GET(service_id)].stack_top;
335}
336
337void tfm_spm_service_set_stack(uint32_t service_id, uint32_t stack_ptr)
338{
339 g_spm_service_db.services[SERVICE_ID_GET(service_id)].stack_ptr = stack_ptr;
340}
341#endif