blob: af4f4bde9301743a0d4c3005815c90fb98bb91c2 [file] [log] [blame]
Miklos Balint386b8b52017-11-29 13:12:32 +00001/*
Mate Toth-Pal65291f32018-02-23 14:35:22 +01002 * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
Miklos Balint386b8b52017-11-29 13:12:32 +00003 *
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>
Miklos Balint386b8b52017-11-29 13:12:32 +000011#include "spm_api.h"
Mate Toth-Pal65291f32018-02-23 14:35:22 +010012#include "spm_db.h"
13#include "tfm_api.h"
Miklos Balint386b8b52017-11-29 13:12:32 +000014#include "mpu_armv8m_drv.h"
15#include "region_defs.h"
16#include "secure_fw/core/tfm_core.h"
17
18struct spm_service_db_t g_spm_service_db = {0,};
19
20#define MPU_REGION_VENEERS 0
21#define MPU_REGION_TFM_UNPRIV_CODE 1
22#define MPU_REGION_TFM_UNPRIV_DATA 2
23#define MPU_REGION_NS_DATA 3
24#define SERVICE_REGION_RO 4
25#define SERVICE_REGION_RW_STACK 5
26#define SERVICE_REGION_PERIPH 6
27#define SERVICE_REGION_SHARE 7
28
29/* This should move to platform retarget */
30struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
31
32typedef enum {
33 TFM_INIT_FAILURE,
34} ss_error_type_t;
35
36/*
37 * This function is called when a secure service causes an error.
Mate Toth-Pal65291f32018-02-23 14:35:22 +010038 * In case of an error in the error handling, a non-zero value have to be
39 * returned.
Miklos Balint386b8b52017-11-29 13:12:32 +000040 */
41static void tfm_spm_service_err_handler(
Mate Toth-Pal65291f32018-02-23 14:35:22 +010042 struct spm_service_region_t *service,
43 ss_error_type_t err_type,
44 int32_t err_code)
Miklos Balint386b8b52017-11-29 13:12:32 +000045{
Miklos Balint386b8b52017-11-29 13:12:32 +000046#ifdef TFM_CORE_DEBUG
47 if (err_type == TFM_INIT_FAILURE) {
Mate Toth-Pal65291f32018-02-23 14:35:22 +010048 printf("Service init failed for service id 0x%08X\r\n",
49 service->service_id);
Miklos Balint386b8b52017-11-29 13:12:32 +000050 } else {
51 printf("Unknown service error %d for service id 0x%08X\r\n",
Mate Toth-Pal65291f32018-02-23 14:35:22 +010052 err_type, service->service_id);
Miklos Balint386b8b52017-11-29 13:12:32 +000053 }
54#endif
Mate Toth-Pal65291f32018-02-23 14:35:22 +010055 tfm_spm_service_set_state(service->service_id, SPM_PART_STATE_CLOSED);
Miklos Balint386b8b52017-11-29 13:12:32 +000056}
57
58enum spm_err_t tfm_spm_db_init(void)
59{
60 /* This function initialises service db */
61 g_spm_service_db.is_init = 1;
Mate Toth-Pal65291f32018-02-23 14:35:22 +010062 g_spm_service_db.running_service_id = INVALID_PARITION_ID;
Miklos Balint386b8b52017-11-29 13:12:32 +000063
64 g_spm_service_db.services_count =
65 create_user_service_db(&g_spm_service_db, SPM_MAX_SERVICES);
66
67 return SPM_ERR_OK;
68}
69
70#if TFM_LVL != 1
71REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
72REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
73REGION_DECLARE(Image$$, TFM_UNPRIV_RO_DATA, $$RW$$Base);
74REGION_DECLARE(Image$$, TFM_UNPRIV_RO_DATA, $$ZI$$Limit);
75REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
76REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
77
78enum spm_err_t tfm_spm_mpu_init(void)
79{
80 mpu_armv8m_clean(&dev_mpu_s);
81
82 struct mpu_armv8m_region_cfg_t region_cfg;
83
84 /* Veneer region */
85 region_cfg.region_nr = MPU_REGION_VENEERS;
86 region_cfg.region_base = CMSE_VENEER_REGION_START;
87 region_cfg.region_limit = CMSE_VENEER_REGION_LIMIT;
88 region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
89 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
90 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
91 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
92
93 /* TFM Core unprivileged code region */
94 region_cfg.region_nr = MPU_REGION_TFM_UNPRIV_CODE;
95 region_cfg.region_base =
96 (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
97 region_cfg.region_limit =
98 (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
99 region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
100 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
101 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
102 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
103
104 /* TFM Core unprivileged data region */
105 region_cfg.region_nr = MPU_REGION_TFM_UNPRIV_DATA;
106 region_cfg.region_base =
107 (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_RO_DATA, $$RW$$Base);
108 region_cfg.region_limit =
109 (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_RO_DATA, $$ZI$$Limit);
110 region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
111 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
112 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
113 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
114
115 /* TFM Core unprivileged non-secure data region */
116 region_cfg.region_nr = MPU_REGION_NS_DATA;
117 region_cfg.region_base = NS_DATA_START;
118 region_cfg.region_limit = NS_DATA_LIMIT;
119 region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
120 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
121 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
122 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
123
124 mpu_armv8m_enable(&dev_mpu_s, 1, 1);
125
126 return SPM_ERR_OK;
127}
128
Mate Toth-Pal65291f32018-02-23 14:35:22 +0100129/**
130 * Set share region to which the service needs access
131 */
132static enum spm_err_t tfm_spm_set_share_region(
133 enum tfm_buffer_share_region_e share)
Miklos Balint386b8b52017-11-29 13:12:32 +0000134{
135 enum spm_err_t res = SPM_ERR_INVALID_CONFIG;
136 uint32_t scratch_base =
137 (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
138 uint32_t scratch_limit =
139 (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
140
141 mpu_armv8m_disable(&dev_mpu_s);
142
143 if (share == TFM_BUFFER_SHARE_DISABLE) {
144 mpu_armv8m_region_disable(&dev_mpu_s, SERVICE_REGION_SHARE);
145 } else {
146 struct mpu_armv8m_region_cfg_t region_cfg;
147
148 region_cfg.region_nr = SERVICE_REGION_SHARE;
149 region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
150 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
151 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
152 switch (share) {
153 case TFM_BUFFER_SHARE_SCRATCH:
154 /* Use scratch area for service-to-service data sharing */
155 region_cfg.region_base = scratch_base;
156 region_cfg.region_limit = scratch_limit;
157 res = SPM_ERR_OK;
158 break;
159 case TFM_BUFFER_SHARE_NS_CODE:
160 region_cfg.region_base = NS_CODE_START;
161 region_cfg.region_limit = NS_CODE_LIMIT;
162 /* Only allow read access to NS code region and keep
163 * exec.never attribute
164 */
165 region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
166 res = SPM_ERR_OK;
167 break;
168 default:
169 res = SPM_ERR_INVALID_CONFIG;
170 break;
171 }
172 if (res == SPM_ERR_OK) {
173 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
174 }
175 }
176 mpu_armv8m_enable(&dev_mpu_s, 1, 1);
177
178 return res;
179}
180#endif
181
182enum spm_err_t tfm_spm_service_init(void)
183{
184 struct spm_service_region_t *serv;
185 int32_t fail_cnt = 0;
186 uint32_t i;
187
188 /* Call the init function for each service */
189 /* FixMe: This implementation only fits level 1 isolation.
190 * On higher levels MPU (and PPC) configuration need to be in place to have
191 * proper isolation during init.
192 */
193 for (i = 0; i < g_spm_service_db.services_count; ++i) {
194 serv = &g_spm_service_db.services[i];
195 if (serv->periph_start) {
196 ppc_configure_to_secure(serv->periph_ppc_bank,
197 serv->periph_ppc_loc);
198 }
Mate Toth-Pal65291f32018-02-23 14:35:22 +0100199 if (serv->service_init == NULL) {
200 tfm_spm_service_set_state(serv->service_id, SPM_PART_STATE_IDLE);
201 } else {
Miklos Balint386b8b52017-11-29 13:12:32 +0000202 int32_t ret = serv->service_init();
203
Mate Toth-Pal65291f32018-02-23 14:35:22 +0100204 if (ret == TFM_SUCCESS) {
205 tfm_spm_service_set_state(
206 serv->service_id, SPM_PART_STATE_IDLE);
207 } else {
208 tfm_spm_service_err_handler(serv, TFM_INIT_FAILURE, ret);
Miklos Balint386b8b52017-11-29 13:12:32 +0000209 fail_cnt++;
210 }
211 }
212 }
213
214 if (fail_cnt == 0) {
215 return SPM_ERR_OK;
216 } else {
217 return SPM_ERR_SERV_NOT_AVAILABLE;
218 }
219}
220
221#if TFM_LVL != 1
222enum spm_err_t tfm_spm_service_sandbox_config(uint32_t service_id)
223{
224 /* This function takes a service id and enables the
225 * SPM partition for that service
226 */
227
228 struct spm_service_region_t *serv;
229 struct mpu_armv8m_region_cfg_t region_cfg;
230
231 if (!g_spm_service_db.is_init) {
232 return SPM_ERR_SERV_DB_NOT_INIT;
233 }
234
235 /*brute force id*/
236 serv = &g_spm_service_db.services[SERVICE_ID_GET(service_id)];
237
238 mpu_armv8m_disable(&dev_mpu_s);
239
240 /* Configure Regions */
241
242 /* RO region*/
243 region_cfg.region_nr = SERVICE_REGION_RO;
244 region_cfg.region_base = serv->ro_start;
245 region_cfg.region_limit = serv->ro_limit;
246 region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
247 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
248 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
249
250 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
251
252 /* RW, ZI and stack as one region*/
253 region_cfg.region_nr = SERVICE_REGION_RW_STACK;
254 region_cfg.region_base = serv->rw_start;
255 region_cfg.region_limit = serv->stack_top;
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
260 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
261
262 if (serv->periph_start) {
263 /* Peripheral */
264 region_cfg.region_nr = SERVICE_REGION_PERIPH;
265 region_cfg.region_base = serv->periph_start;
266 region_cfg.region_limit = serv->periph_limit;
267 region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
268 region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
269 region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
270 mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
271
272 ppc_en_secure_unpriv(serv->periph_ppc_bank, serv->periph_ppc_loc);
273 }
274
275 mpu_armv8m_enable(&dev_mpu_s, 1, 1);
276
277#ifndef UNPRIV_JUMP_TO_NS
278 /* FixMe: if jump_to_ns_code() from unprivileged is solved,
279 * this code can be removed
280 */
281 /* Initialization is done, set thread mode to unprivileged.
282 */
283 CONTROL_Type ctrl;
284
285 ctrl.w = __get_CONTROL();
286 ctrl.b.nPRIV = 1;
287 __set_CONTROL(ctrl.w);
288 __DSB();
289 __ISB();
290#endif
291
292 return SPM_ERR_OK;
293}
294
295enum spm_err_t tfm_spm_service_sandbox_deconfig(uint32_t service_id)
296{
297 /* This function takes a service id and disables the
298 * SPM partition for that service
299 */
300
301#ifndef UNPRIV_JUMP_TO_NS
302 /* FixMe: if jump_to_ns_code() from unprivileged is solved,
303 * this code can be removed
304 */
305 CONTROL_Type ctrl;
306
307 ctrl.w = __get_CONTROL();
308 ctrl.b.nPRIV = 0;
309 __set_CONTROL(ctrl.w);
310 __DSB();
311 __ISB();
312#endif
313
314 struct spm_service_region_t *serv;
315
316 serv = &g_spm_service_db.services[SERVICE_ID_GET(service_id)];
317
318 if (serv->periph_start) {
319 /* Peripheral */
320 ppc_clr_secure_unpriv(serv->periph_ppc_bank, serv->periph_ppc_loc);
321 }
322
323 mpu_armv8m_disable(&dev_mpu_s);
324 mpu_armv8m_region_disable(&dev_mpu_s, SERVICE_REGION_RO);
325 mpu_armv8m_region_disable(&dev_mpu_s, SERVICE_REGION_RW_STACK);
326 mpu_armv8m_region_disable(&dev_mpu_s, SERVICE_REGION_PERIPH);
327 mpu_armv8m_region_disable(&dev_mpu_s, SERVICE_REGION_SHARE);
328 mpu_armv8m_enable(&dev_mpu_s, 1, 1);
329
330 return SPM_ERR_OK;
331}
332
333uint32_t tfm_spm_service_get_stack(uint32_t service_id)
334{
335 return g_spm_service_db.services[SERVICE_ID_GET(service_id)].stack_ptr;
336}
337
338uint32_t tfm_spm_service_get_stack_bottom(uint32_t service_id)
339{
340 return g_spm_service_db.services[SERVICE_ID_GET(service_id)].stack_bottom;
341}
342
343uint32_t tfm_spm_service_get_stack_top(uint32_t service_id)
344{
345 return g_spm_service_db.services[SERVICE_ID_GET(service_id)].stack_top;
346}
347
348void tfm_spm_service_set_stack(uint32_t service_id, uint32_t stack_ptr)
349{
350 g_spm_service_db.services[SERVICE_ID_GET(service_id)].stack_ptr = stack_ptr;
351}
352#endif
Mate Toth-Pal65291f32018-02-23 14:35:22 +0100353
354uint32_t tfm_spm_service_get_state(uint32_t service_id)
355{
356 return g_spm_service_db.services[SERVICE_ID_GET(service_id)].
357 service_state;
358}
359
360uint32_t tfm_spm_service_get_caller_service_id(uint32_t service_id)
361{
362 return g_spm_service_db.services[SERVICE_ID_GET(service_id)].
363 caller_service_id;
364}
365
366uint32_t tfm_spm_service_get_orig_psp(uint32_t service_id)
367{
368 return g_spm_service_db.services[SERVICE_ID_GET(service_id)].orig_psp;
369}
370
371uint32_t tfm_spm_service_get_orig_psplim(uint32_t service_id)
372{
373 return g_spm_service_db.services[SERVICE_ID_GET(service_id)].orig_psplim;
374}
375
376uint32_t tfm_spm_service_get_orig_lr(uint32_t service_id)
377{
378 return g_spm_service_db.services[SERVICE_ID_GET(service_id)].orig_lr;
379}
380
381uint32_t tfm_spm_service_get_share(uint32_t service_id)
382{
383 return g_spm_service_db.services[SERVICE_ID_GET(service_id)].share;
384}
385
386void tfm_spm_service_set_state(uint32_t service_id, uint32_t state)
387{
388 g_spm_service_db.services[SERVICE_ID_GET(service_id)].service_state = state;
389 if (state == SPM_PART_STATE_RUNNING) {
390 g_spm_service_db.running_service_id = service_id;
391 }
392}
393
394void tfm_spm_service_set_caller_service_id(uint32_t service_id,
395 uint32_t caller_service_id)
396{
397 g_spm_service_db.services[SERVICE_ID_GET(service_id)].caller_service_id =
398 caller_service_id;
399}
400
401void tfm_spm_service_set_orig_psp(uint32_t service_id, uint32_t orig_psp)
402{
403 g_spm_service_db.services[SERVICE_ID_GET(service_id)].orig_psp = orig_psp;
404}
405
406void tfm_spm_service_set_orig_psplim(uint32_t service_id, uint32_t orig_psplim)
407{
408 g_spm_service_db.services[SERVICE_ID_GET(service_id)].orig_psplim =
409 orig_psplim;
410}
411
412void tfm_spm_service_set_orig_lr(uint32_t service_id, uint32_t orig_lr)
413{
414 g_spm_service_db.services[SERVICE_ID_GET(service_id)].orig_lr = orig_lr;
415}
416
417enum spm_err_t tfm_spm_service_set_share(uint32_t service_id, uint32_t share)
418{
419 enum spm_err_t ret = SPM_ERR_OK;
420
421#if TFM_LVL != 1
422 /* Only need to set configuration on levels higher than 1 */
423 ret = tfm_spm_set_share_region(share);
424#endif
425
426 if (ret == SPM_ERR_OK) {
427 g_spm_service_db.services[SERVICE_ID_GET(service_id)].share = share;
428 }
429 return ret;
430}
431
432uint32_t tfm_spm_service_get_running_service_id(void)
433{
434 return g_spm_service_db.running_service_id;
435}
436
437void tfm_spm_service_cleanup_context(uint32_t service_id)
438{
439 struct spm_service_region_t *service =
440 &g_spm_service_db.services[SERVICE_ID_GET(service_id)];
441 service->service_state = 0;
442 service->caller_service_id = 0;
443 service->orig_psp = 0;
444 service->orig_psplim = 0;
445 service->orig_lr = 0;
446 service->share = 0;
447}