TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
platform_sp.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "platform_sp.h"
9 
10 #include "tfm_platform_system.h"
11 #include "tfm_plat_nv_counters.h"
12 #include "tfm/tfm_spm_services.h"
13 #include "tfm_secure_api.h"
14 #include "psa_manifest/pid.h"
15 
16 #define NV_COUNTER_ID_SIZE sizeof(enum tfm_nv_counter_t)
17 #define NV_COUNTER_MAP_SIZE 3
18 
19 /* Access map using NVCOUNTER_IDX -> tfm_partition-id key-value pairs */
20 static const int32_t nv_counter_access_map[NV_COUNTER_MAP_SIZE] = {
21  [PLAT_NV_COUNTER_0] = TFM_SP_PS,
22  [PLAT_NV_COUNTER_1] = TFM_SP_PS,
23  [PLAT_NV_COUNTER_2] = TFM_SP_PS
24  };
25 
26 #ifdef TFM_PSA_API
28 #include "psa/client.h"
29 #include "psa/service.h"
30 #include "region_defs.h"
31 
32 #define INPUT_BUFFER_SIZE 64
33 #define OUTPUT_BUFFER_SIZE 64
34 
35 typedef enum tfm_platform_err_t (*plat_func_t)(const psa_msg_t *msg);
36 #endif
37 
38 /*
39  * \brief Verifies ownership of a nv_counter resource to a partition id.
40  *
41  * \param[in] nv_counter_no Number of nv_counter as assigned in platform.
42  *
43  * \return true if the calling partition is allowed to access this counter id
44  */
45 
46 static bool nv_counter_access_grant(int32_t client_id,
47  enum tfm_nv_counter_t nv_counter_no)
48 {
49  int32_t req_id;
50 
51  /* Boundary check the input argument */
52  if (nv_counter_no >= NV_COUNTER_MAP_SIZE ||
53  (int32_t)nv_counter_no < 0 || nv_counter_no >= PLAT_NV_COUNTER_MAX) {
54  return false;
55  }
56 
57  req_id = nv_counter_access_map[nv_counter_no];
58 
59  /* NV Counters are indexed from 0 and incremented. A gap in the platform
60  * counter sequence is assigned a zero( invalid ) partition id
61  */
62  if (client_id == req_id && req_id != 0) {
63  return true;
64  }
65  return false;
66 }
67 
69 {
70  /* Check if SPM allows the system reset */
71 
72  if (tfm_spm_request_reset_vote() != 0) {
74  }
75 
76  /* FIXME: The system reset functionality is only supported in isolation
77  * level 1.
78  */
79 
80  tfm_platform_hal_system_reset();
81 
83 }
84 
85 #ifndef TFM_PSA_API
86 
88 platform_sp_ioctl(psa_invec *in_vec, uint32_t num_invec,
89  psa_outvec *out_vec, uint32_t num_outvec)
90 {
91  void *input, *output;
93 
94  if ((num_invec < 1) || (num_invec > 2) ||
95  (num_outvec > 1) ||
96  (in_vec[0].base == NULL) ||
97  (in_vec[0].len != sizeof(tfm_platform_ioctl_req_t))) {
99  }
100 
101  input = (num_invec == 1) ? NULL : &in_vec[1];
102  output = out_vec;
103  request = *((tfm_platform_ioctl_req_t *)in_vec[0].base);
104 
105  return tfm_platform_hal_ioctl(request, input, output);
106 }
107 
109 platform_sp_nv_counter_read(psa_invec *in_vec, uint32_t num_invec,
110  psa_outvec *out_vec, uint32_t num_outvec)
111 {
112  enum tfm_plat_err_t err;
113  enum tfm_nv_counter_t counter_id;
114  uint32_t counter_size;
115  int32_t status, client_id;
116 
117  if (in_vec[0].len != NV_COUNTER_ID_SIZE ||
118  num_invec != 1 || num_outvec != 1) {
120  }
121  counter_id = *((enum tfm_nv_counter_t *)in_vec[0].base);
122  counter_size = out_vec[0].len;
123 
124  status = tfm_core_get_caller_client_id(&client_id);
125  if (status != (int32_t)TFM_SUCCESS) {
127  }
128 
129  if (!nv_counter_access_grant(client_id, counter_id)) {
131  }
132  err = tfm_plat_read_nv_counter(counter_id, counter_size,
133  (uint8_t *)out_vec[0].base);
134  if (err != TFM_PLAT_ERR_SUCCESS) {
136  }
137 
139 }
140 
142 platform_sp_nv_counter_increment(psa_invec *in_vec, uint32_t num_invec,
143  psa_outvec *out_vec, uint32_t num_outvec)
144 {
145  enum tfm_plat_err_t err;
146  enum tfm_nv_counter_t counter_id;
147  int32_t client_id, status;
148 
149  if (in_vec[0].len != NV_COUNTER_ID_SIZE ||
150  num_invec != 1 || num_outvec != 0) {
152  }
153 
154  status = tfm_core_get_caller_client_id(&client_id);
155  if (status != (int32_t)TFM_SUCCESS) {
157  }
158 
159  counter_id = *((enum tfm_nv_counter_t *)in_vec[0].base);
160 
161  if (!nv_counter_access_grant(client_id, counter_id)) {
163  }
164  err = tfm_plat_increment_nv_counter(counter_id);
165  if (err != TFM_PLAT_ERR_SUCCESS) {
167  }
168 
170 }
171 
172 #else /* TFM_PSA_API */
173 
174 static enum tfm_platform_err_t
175 platform_sp_system_reset_ipc(const psa_msg_t *msg)
176 {
177  (void)msg; /* unused parameter */
178 
179  return platform_sp_system_reset();
180 }
181 
182 static enum tfm_platform_err_t
183 platform_sp_nv_counter_ipc(const psa_msg_t *msg)
184 {
185  enum tfm_plat_err_t err = TFM_PLAT_ERR_SYSTEM_ERR;
186  size_t in_len = PSA_MAX_IOVEC, out_len = PSA_MAX_IOVEC, num = 0;
187 
188  enum tfm_nv_counter_t counter_id;
189  uint8_t counter_val = 0;
190 
191  /* Check the number of in_vec filled */
192  while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
193  in_len--;
194  }
195 
196  /* Check the number of out_vec filled */
197  while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
198  out_len--;
199  }
200  switch (msg->type) {
202  if (msg->in_size[0] != NV_COUNTER_ID_SIZE ||
203  in_len != 1 || out_len != 0) {
205  }
206 
207  num = psa_read(msg->handle, 0, &counter_id, msg->in_size[0]);
208 
209  if (num != msg->in_size[0]) {
211  }
212 
213  if (!nv_counter_access_grant(msg->client_id, counter_id)) {
215  }
216 
217  err = tfm_plat_increment_nv_counter(counter_id);
218  break;
220  num = psa_read(msg->handle, 0, &counter_id, msg->in_size[0]);
221 
222  if (msg->in_size[0] != NV_COUNTER_ID_SIZE ||
223  in_len != 1 || out_len != 1) {
225  }
226 
227  if (!nv_counter_access_grant(msg->client_id, counter_id)) {
229  }
230 
231  err = tfm_plat_read_nv_counter(counter_id, msg->out_size[0],
232  &counter_val);
233 
234  if (err != TFM_PLAT_ERR_SUCCESS) {
236  }
237  psa_write(msg->handle, 0, &counter_val, msg->out_size[0]);
238  break;
239  default:
241  break;
242  }
243 
244  if (err != TFM_PLAT_ERR_SUCCESS) {
246  }
248 }
249 
250 static enum tfm_platform_err_t
251 platform_sp_ioctl_ipc(const psa_msg_t *msg)
252 {
253  void *input = NULL;
254  void *output = NULL;
255  psa_invec invec = {0};
256  psa_outvec outvec = {0};
257  uint8_t input_buffer[INPUT_BUFFER_SIZE] = {0};
258  uint8_t output_buffer[OUTPUT_BUFFER_SIZE] = {0};
259  tfm_platform_ioctl_req_t request = 0;
261  int num = 0;
262  uint32_t in_len = PSA_MAX_IOVEC;
263  uint32_t out_len = PSA_MAX_IOVEC;
264 
265  while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
266  in_len--;
267  }
268 
269  while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
270  out_len--;
271  }
272 
273  if ((in_len < 1) || (in_len > 2) ||
274  (out_len > 1)) {
276  }
277 
278  num = psa_read(msg->handle, 0, &request, sizeof(request));
279  if (num != sizeof(request)) {
281  }
282 
283  if (in_len > 1) {
284  if (msg->in_size[1] > INPUT_BUFFER_SIZE) {
286  }
287  num = psa_read(msg->handle, 1, &input_buffer, msg->in_size[1]);
288  if (num != msg->in_size[1]) {
290  }
291  invec.base = input_buffer;
292  invec.len = msg->in_size[1];
293  input = &invec;
294  }
295 
296  if (out_len > 0) {
297  if (msg->out_size[0] > OUTPUT_BUFFER_SIZE) {
299  }
300  outvec.base = output_buffer;
301  outvec.len = msg->out_size[0];
302  output = &outvec;
303  }
304 
305  ret = tfm_platform_hal_ioctl(request, input, output);
306 
307  if (output != NULL) {
308  psa_write(msg->handle, 0, outvec.base, outvec.len);
309  }
310 
311  return ret;
312 }
313 
314 static void platform_signal_handle(psa_signal_t signal, plat_func_t pfn)
315 {
316  psa_msg_t msg;
317  psa_status_t status;
318 
319  status = psa_get(signal, &msg);
320  switch (msg.type) {
321  case PSA_IPC_CONNECT:
323  break;
324  case PSA_IPC_CALL:
327  status = (psa_status_t)pfn(&msg);
328  psa_reply(msg.handle, status);
329  break;
330  case PSA_IPC_DISCONNECT:
332  break;
333  default:
334  psa_panic();
335  }
336 }
337 
338 #endif /* TFM_PSA_API */
339 
341 {
342  /* Initialise the non-volatile counters */
343  enum tfm_plat_err_t err;
344  err = tfm_plat_init_nv_counter();
345  if (err != TFM_PLAT_ERR_SUCCESS) {
346 #ifdef TFM_PSA_API
347  psa_panic();
348 #else
350 #endif
351  }
352 #ifdef TFM_PSA_API
353  psa_signal_t signals = 0;
354 
355  while (1) {
356  signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
357  if (signals & TFM_SP_PLATFORM_SYSTEM_RESET_SIGNAL) {
358  platform_signal_handle(TFM_SP_PLATFORM_SYSTEM_RESET_SIGNAL,
359  platform_sp_system_reset_ipc);
360  } else if (signals & TFM_SP_PLATFORM_IOCTL_SIGNAL) {
361  platform_signal_handle(TFM_SP_PLATFORM_IOCTL_SIGNAL,
362  platform_sp_ioctl_ipc);
363  } else if (signals & TFM_SP_PLATFORM_NV_COUNTER_SIGNAL) {
364  platform_signal_handle(TFM_SP_PLATFORM_NV_COUNTER_SIGNAL,
365  platform_sp_nv_counter_ipc);
366  } else {
367  psa_panic();
368  }
369  }
370 
371 #else
373 #endif /* TFM_PSA_API */
374 }
#define NV_COUNTER_MAP_SIZE
Definition: platform_sp.c:17
uint32_t psa_signal_t
Definition: service.h:50
void * base
Definition: client.h:75
enum tfm_platform_err_t platform_sp_nv_counter_read(psa_invec *in_vec, uint32_t num_invec, psa_outvec *out_vec, uint32_t num_outvec)
Definition: platform_sp.c:109
#define PSA_BLOCK
Definition: service.h:31
int32_t type
Definition: service.h:56
#define PSA_SUCCESS
Definition: crypto_values.h:35
#define NV_COUNTER_ID_SIZE
Definition: platform_sp.c:16
#define TFM_SP_PLATFORM_NV_COUNTER_SIGNAL
Definition: tfm_platform.h:19
int32_t tfm_platform_ioctl_req_t
size_t len
Definition: client.h:68
enum tfm_platform_err_t platform_sp_system_reset(void)
Resets the system.
Definition: platform_sp.c:68
enum tfm_platform_err_t platform_sp_nv_counter_increment(psa_invec *in_vec, uint32_t num_invec, psa_outvec *out_vec, uint32_t num_outvec)
Definition: platform_sp.c:142
#define TFM_PLATFORM_API_ID_NV_INCREMENT
int32_t client_id
Definition: service.h:64
#define TFM_PLATFORM_API_ID_NV_READ
#define TFM_SP_PS
Definition: pid.h:17
size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx, void *buffer, size_t num_bytes)
Read a message parameter or part of a message parameter from a client input vector.
Definition: psa_service.c:40
psa_handle_t handle
Definition: service.h:61
enum tfm_platform_err_t platform_sp_ioctl(psa_invec *in_vec, uint32_t num_invec, psa_outvec *out_vec, uint32_t num_outvec)
Definition: platform_sp.c:88
#define PSA_MAX_IOVEC
Definition: client.h:54
#define PSA_IPC_DISCONNECT
Definition: service.h:47
#define TFM_SP_PLATFORM_IOCTL_SIGNAL
Definition: tfm_platform.h:18
int32_t tfm_spm_request_reset_vote(void)
Request a vote from SPM on a system reset.
Definition: arch.c:45
#define PSA_ERROR_PROGRAMMER_ERROR
Definition: error.h:32
enum tfm_platform_err_t platform_sp_init(void)
Initializes the secure partition.
Definition: platform_sp.c:340
#define PSA_WAIT_ANY
Definition: service.h:36
void psa_panic(void)
Terminate execution within the calling Secure Partition and will not return.
Definition: psa_service.c:99
size_t in_size[PSA_MAX_IOVEC]
Definition: service.h:70
int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id)
Definition: arch.c:28
void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx, const void *buffer, size_t num_bytes)
Write a message response to a client output vector.
Definition: psa_service.c:58
void psa_reply(psa_handle_t msg_handle, psa_status_t status)
Complete handling of a specific message and unblock the client.
Definition: psa_service.c:67
psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout)
Return the Secure Partition interrupt signals that have been asserted from a subset of signals provid...
Definition: psa_service.c:15
size_t len
Definition: client.h:76
#define PSA_IPC_CONNECT
Definition: service.h:45
size_t out_size[PSA_MAX_IOVEC]
Definition: service.h:73
#define PSA_IPC_CALL
Definition: client.h:59
tfm_platform_err_t
Platform service error types.
const void * base
Definition: client.h:67
psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg)
Retrieve the message which corresponds to a given RoT Service signal and remove the message from the ...
Definition: psa_service.c:24
int32_t psa_status_t
Function return status.
Definition: crypto_types.h:43
#define TFM_SP_PLATFORM_SYSTEM_RESET_SIGNAL
Definition: tfm_platform.h:17