TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tfm_ipc_client_test.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 <stdio.h>
9 #include <assert.h>
10 #include "psa/client.h"
11 #include "psa/service.h"
13 #include "utilities.h"
14 #include "psa_manifest/sid.h"
15 
16 /* Define the return status */
17 #define IPC_SP_TEST_SUCCESS (1)
18 #define IPC_SP_TEST_FAILED (-1)
19 
20 /*
21  * The bit corresponding to service signal indicates whether
22  * the service is in use.
23  */
24 uint32_t service_in_use = 0;
25 
26 /*
27  * Create a global const data, so that it is stored in code
28  * section which is read only.
29  */
30 char const client_data_read_only = 'A';
31 
32 /*
33  * Fixme: Temporarily implement abort as infinite loop,
34  * will replace it later.
35  */
36 static void tfm_abort(void)
37 {
38  while (1)
39  ;
40 }
41 
42 #ifdef TFM_IPC_ISOLATION_2_TEST_READ_ONLY_MEM
43 static int ipc_isolation_2_psa_access_app_readonly_memory(void)
44 {
45  psa_handle_t handle;
46  psa_status_t status;
47  char const *client_data_p = &client_data_read_only;
48  struct psa_invec invecs[1] = {{&client_data_p, sizeof(client_data_p)}};
49 
52 
53  if (handle <= 0) {
54  return IPC_SP_TEST_FAILED;
55  }
56 
57  status = psa_call(handle, PSA_IPC_CALL, invecs, 1, NULL, 0);
58 
59  /* The system should panic before here. */
60  psa_close(handle);
61  return IPC_SP_TEST_FAILED;
62 }
63 #endif
64 
65 static int ipc_isolation_2_psa_access_app_memory(void)
66 {
67  psa_handle_t handle;
68  psa_status_t status;
69  int32_t result = IPC_SP_TEST_FAILED;
70  char client_data = 'A';
71  char *client_data_p = &client_data;
72  struct psa_invec invecs[1] = {{&client_data_p, sizeof(client_data_p)}};
73 
76 
77  if (handle <= 0) {
78  return result;
79  }
80 
81  status = psa_call(handle, PSA_IPC_CALL, invecs, 1, NULL, 0);
82 
83  if ((client_data == 'B') && (status >= 0)) {
84  result = IPC_SP_TEST_SUCCESS;
85  }
86 
87  psa_close(handle);
88  return result;
89 }
90 
91 static int ipc_client_base_test(void)
92 {
93  psa_handle_t handle;
94  psa_status_t status;
95  int32_t result = IPC_SP_TEST_FAILED;
96  char str1[] = "123";
97  char str2[] = "456";
98  char str3[32], str4[32];
99  struct psa_invec invecs[2] = {{str1, sizeof(str1)/sizeof(char)},
100  {str2, sizeof(str2)/sizeof(char)}};
101  struct psa_outvec outvecs[2] = {{str3, sizeof(str3)/sizeof(char)},
102  {str4, sizeof(str4)/sizeof(char)}};
103 
106  if (handle <= 0) {
107  return result;
108  }
109 
110  status = psa_call(handle, PSA_IPC_CALL, invecs, 2, outvecs, 2);
111  if (status >= 0) {
112  result = IPC_SP_TEST_SUCCESS;
113  }
114 
115  psa_close(handle);
116  return result;
117 }
118 
119 #ifdef TFM_IPC_ISOLATION_2_APP_ACCESS_PSA_MEM
120 static int ipc_client_app_access_psa_mem_test(void)
121 {
122  psa_handle_t handle;
123  psa_status_t status;
124  uint8_t *outvec_data[1] = {0};
125  struct psa_outvec outvecs[1] = {{outvec_data, sizeof(outvec_data[0])}};
126 
129 
130  if (handle <= 0) {
131  return IPC_SP_TEST_FAILED;
132  }
133 
134  status = psa_call(handle, PSA_IPC_CALL, NULL, 0, outvecs, 1);
135  if (status >= 0) {
136  /*
137  * outvecs should contain the pointer pointed to ipc service parition
138  * memory. Read the pointed memory should cause panic.
139  */
140  uint8_t *psa_data_p = outvec_data[0];
141  if (psa_data_p) {
142  (*psa_data_p)++;
143  }
144  }
145 
146  /* The system should panic before here. */
147  psa_close(handle);
148  return IPC_SP_TEST_FAILED;
149 }
150 #endif
151 
152 #ifdef TFM_IPC_ISOLATION_2_MEM_CHECK
153 static int ipc_client_mem_check_test(void)
154 {
155  psa_handle_t handle;
156  psa_status_t status;
157  uint8_t *outvec_data[1] = {0};
158  struct psa_outvec outvecs[1] = {{outvec_data, sizeof(outvec_data[0])}};
159  struct psa_invec invecs[1] = {{NULL, 0}};
160 
163 
164  if (handle <= 0) {
165  return IPC_SP_TEST_FAILED;
166  }
167 
168  status = psa_call(handle, PSA_IPC_CALL, NULL, 0, outvecs, 1);
169  if (status >= 0) {
170  /*
171  * outvecs should contain the pointer pointed to ipc service parition
172  * memory. In psa_call, it checks whether the target partition has the
173  * access right to the invecs indicated memory. If no, the system will
174  * panic.
175  */
176  uint8_t *psa_data_p = outvec_data[0];
177  if (psa_data_p) {
178  invecs[0].base = psa_data_p;
179  invecs[0].len = sizeof(psa_data_p);
180  psa_call(handle, PSA_IPC_CALL, invecs, 1, NULL, 0);
181  }
182  }
183 
184  /* The system should panic before here. */
185  psa_close(handle);
186  return IPC_SP_TEST_FAILED;
187 }
188 #endif
189 
190 static void ipc_client_handle_ser_req(psa_msg_t msg, uint32_t signals,
191  int (*fn)(void))
192 {
193  psa_status_t r;
194  int32_t ret;
195 
196  switch (msg.type) {
197  case PSA_IPC_CONNECT:
198  if (service_in_use & signals) {
200  } else {
201  service_in_use |= signals;
202  r = PSA_SUCCESS;
203  }
204  psa_reply(msg.handle, r);
205  break;
206  case PSA_IPC_CALL:
207  ret = (*fn)();
208  if (msg.out_size[0] != 0) {
209  psa_write(msg.handle, 0, &ret, sizeof(ret));
210  }
212  break;
213  case PSA_IPC_DISCONNECT:
214  assert((service_in_use & signals) != 0);
215  service_in_use &= ~(signals);
217  break;
218  default:
219  /* cannot get here? [broken SPM]. TODO*/
220  tfm_abort();
221  break;
222  }
223 }
224 
226 {
227  psa_msg_t msg;
228  uint32_t signals = 0;
229 
230  while (1) {
231  signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
232  psa_get(signals, &msg);
233  if ((signals & IPC_CLIENT_TEST_BASIC_SIGNAL)) {
234  ipc_client_handle_ser_req(msg, IPC_CLIENT_TEST_BASIC_SIGNAL,
235  &ipc_client_base_test);
236  } else if (signals & IPC_CLIENT_TEST_PSA_ACCESS_APP_MEM_SIGNAL) {
237  ipc_client_handle_ser_req(msg,
238  IPC_CLIENT_TEST_PSA_ACCESS_APP_MEM_SIGNAL,
239  &ipc_isolation_2_psa_access_app_memory);
240 #ifdef TFM_IPC_ISOLATION_2_TEST_READ_ONLY_MEM
241  } else if (signals &
243  ipc_client_handle_ser_req(msg,
244  IPC_CLIENT_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SIGNAL,
245  &ipc_isolation_2_psa_access_app_readonly_memory);
246 #endif
247 #ifdef TFM_IPC_ISOLATION_2_APP_ACCESS_PSA_MEM
248  } else if (signals & IPC_CLIENT_TEST_APP_ACCESS_PSA_MEM_SIGNAL) {
249  ipc_client_handle_ser_req(msg,
250  IPC_CLIENT_TEST_APP_ACCESS_PSA_MEM_SIGNAL,
251  &ipc_client_app_access_psa_mem_test);
252 #endif
253 #ifdef TFM_IPC_ISOLATION_2_MEM_CHECK
254  } else if (signals & IPC_CLIENT_TEST_MEM_CHECK_SIGNAL) {
255  ipc_client_handle_ser_req(msg, IPC_CLIENT_TEST_MEM_CHECK_SIGNAL,
256  &ipc_client_mem_check_test);
257 #endif
258  } else {
259  /* Should not go here. */
260  tfm_abort();
261  }
262  }
263 }
#define IPC_SERVICE_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SID
Definition: sid.h:104
#define PSA_BLOCK
Definition: service.h:31
#define IPC_CLIENT_TEST_BASIC_SIGNAL
int32_t type
Definition: service.h:56
#define PSA_SUCCESS
Definition: crypto_values.h:35
size_t len
Definition: client.h:68
void psa_close(psa_handle_t handle)
Close a connection to an RoT Service.
Definition: psa_client.c:63
#define IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM_SID
Definition: sid.h:106
#define IPC_SERVICE_TEST_PSA_ACCESS_APP_MEM_SID
Definition: sid.h:102
char const client_data_read_only
psa_handle_t handle
Definition: service.h:61
#define IPC_CLIENT_TEST_PSA_ACCESS_APP_MEM_SIGNAL
psa_handle_t psa_connect(uint32_t sid, uint32_t version)
Connect to an RoT Service by its SID.
Definition: psa_client.c:30
#define PSA_IPC_DISCONNECT
Definition: service.h:47
#define IPC_CLIENT_TEST_APP_ACCESS_PSA_MEM_SIGNAL
#define IPC_SERVICE_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_VERSION
Definition: sid.h:105
#define IPC_SERVICE_TEST_APP_ACCESS_PSA_MEM_VERSION
Definition: sid.h:107
#define PSA_WAIT_ANY
Definition: service.h:36
uint32_t service_in_use
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
#define IPC_CLIENT_TEST_PSA_ACCESS_APP_READ_ONLY_MEM_SIGNAL
#define IPC_SP_TEST_FAILED
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
#define IPC_CLIENT_TEST_MEM_CHECK_SIGNAL
#define PSA_ERROR_CONNECTION_REFUSED
Definition: error.h:33
#define IPC_SERVICE_TEST_BASIC_SID
Definition: sid.h:100
int32_t psa_handle_t
Definition: client.h:61
#define PSA_IPC_CONNECT
Definition: service.h:45
#define IPC_SERVICE_TEST_PSA_ACCESS_APP_MEM_VERSION
Definition: sid.h:103
size_t out_size[PSA_MAX_IOVEC]
Definition: service.h:73
#define IPC_SP_TEST_SUCCESS
#define IPC_SERVICE_TEST_BASIC_VERSION
Definition: sid.h:101
#define PSA_IPC_CALL
Definition: client.h:59
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
psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len, psa_outvec *out_vec, size_t out_len)
Call an RoT Service on an established connection.
Definition: psa_client.c:47
void ipc_client_test_main(void)