1 /*
2  * Copyright (c) 2021-2024, Arm Limited. All rights reserved.
3  * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon
4  * company) or an affiliate of Cypress Semiconductor Corporation. All rights
5  * reserved.
6  *
7  * SPDX-License-Identifier: BSD-3-Clause
8  *
9  */
10 
11 #include "tfm_nspm.h"
12 #include "tfm_ns_ctx.h"
13 #include "tfm_ns_client_ext.h"
14 #include "utilities.h"
15 #include "tfm_arch.h"
16 #include "tfm_hal_platform.h"
17 
18 #define DEFAULT_NS_CLIENT_ID ((int32_t)-1)
19 
20 struct client_id_region_t {
21     int32_t base;
22     int32_t limit;
23 };
24 
25 static struct client_id_region_t client_id_regions;
26 
tz_ns_agent_register_client_id_range(int32_t client_id_base,int32_t client_id_limit)27 void tz_ns_agent_register_client_id_range(int32_t client_id_base,
28                                        int32_t client_id_limit)
29 {
30     client_id_regions.base = client_id_base;
31     client_id_regions.limit = client_id_limit;
32 }
33 
tz_ns_agent_client_id_translate(int32_t client_id_in,int32_t * client_id_out)34 static int32_t tz_ns_agent_client_id_translate(int32_t client_id_in, int32_t *client_id_out)
35 {
36     int32_t base, limit;
37     int32_t min_client_id;
38 
39     if (client_id_out == NULL) {
40         return -1;
41     }
42     if (client_id_in >= 0) {
43         return -1;
44     }
45 
46     base = client_id_regions.base;
47     limit = client_id_regions.limit;
48 
49     /*
50      * client_id_range = limit - base + 1
51      * min_client_id = -client_id_range
52      *
53      * However client_id_range cannot be calculated directly, because if
54      * base = INT32_MIN and limit = -1 then
55      * client_id_range becomes INT32_MAX + 1 because
56      * abs(INT32_MIN) = abs(INT32_MAX) + 1 and that causes overflow. So
57      * min_client_id is calculated directly, with a reordered expression:
58      * min_client_id = -(limit - base + 1) ==
59      *                 -limit + base -1 ==
60      *                 -(limit - base) -1
61      */
62     min_client_id = -1 * (limit - base) - 1;
63 
64     if (client_id_in < min_client_id) {
65         return -1;
66     }
67 
68     /*
69      * 1 is added before client_id_in, so that no underflow happens even if
70      * limit + client_id_in == INT32_MIN - 1
71      */
72     *client_id_out = (limit + 1) + client_id_in;
73     return 0;
74 }
75 
tfm_nspm_get_current_client_id(void)76 int32_t tfm_nspm_get_current_client_id(void)
77 {
78     int32_t input_client_id, translated_client_id;
79 
80 #ifdef TFM_NS_MANAGE_NSID
81     input_client_id = get_nsid_from_active_ns_ctx();
82 #else
83     input_client_id = DEFAULT_NS_CLIENT_ID;
84 #endif
85     if (tz_ns_agent_client_id_translate(input_client_id, &translated_client_id) != 0) {
86         return TFM_NS_CLIENT_INVALID_ID;
87     }
88     return translated_client_id;
89 }
90 
tfm_nspm_ctx_init(void)91 void tfm_nspm_ctx_init(void)
92 {
93 #ifdef TFM_PARTITION_NS_AGENT_TZ
94     /* SCB_NS.VTOR points to the Non-secure vector table base address */
95     SCB_NS->VTOR = tfm_hal_get_ns_VTOR();
96 
97     /* Setups Main stack pointer of the non-secure code */
98     __TZ_set_MSP_NS(tfm_hal_get_ns_MSP());
99 #endif
100 
101 #ifdef TFM_NS_MANAGE_NSID
102     if (!init_ns_ctx()) {
103         tfm_core_panic();
104     }
105 #endif
106 }
107