TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tfm_irq_test_service_1.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <stddef.h>
9 #include "tfm_api.h"
10 #include "tfm_veneers.h"
11 #include "tfm_secure_api.h"
12 #include "tfm/tfm_spm_services.h"
13 #include "core_test_defs.h"
14 #include "psa/service.h"
15 #include "psa_manifest/pid.h"
17 #include "tfm_plat_test.h"
18 
19 #define IRQ_TEST_TOOL_CODE_LOCATION(name)
20 
21 static enum irq_test_scenario_t current_scenario = IRQ_TEST_SCENARIO_NONE;
22 static struct irq_test_execution_data_t *current_execution_data;
23 
24 #ifdef TFM_PSA_API
25 static psa_handle_t execute_msg_handle = -1;
26 #endif
27 
34 static void halt_test_execution(void)
35 {
36  while (1) {
37  ; /* Test fail */
38  }
39 }
40 
44 static void stop_timer(void)
45 {
46  IRQ_TEST_TOOL_CODE_LOCATION(stop_secure_timer);
47  tfm_plat_test_secure_timer_stop();
48 }
49 
51  enum irq_test_scenario_t irq_test_scenario,
52  struct irq_test_execution_data_t *execution_data)
53 {
54  current_scenario = irq_test_scenario;
55  current_execution_data = execution_data;
56 
57  current_execution_data->timer0_triggered = 0;
58 
59  switch (irq_test_scenario) {
61  break; /* uninitialised scenario */
66  tfm_plat_test_secure_timer_start();
67  break;
69  /* Do nothing */
70  break;
71  default:
73  }
74 
76 }
77 
79  struct psa_invec *in_vec, size_t in_len,
80  struct psa_outvec *out_vec, size_t out_len)
81 {
82  enum irq_test_scenario_t irq_test_scenario =
83  (enum irq_test_scenario_t) *(uint32_t *)in_vec[0].base;
84  psa_signal_t signals = 0;
85 
86  if (irq_test_scenario != current_scenario) {
88  }
89 
90  switch (irq_test_scenario) {
95  /* nothing to do*/
96  break;
98  if (current_execution_data->timer0_triggered) {
100  }
101  while (!current_execution_data->timer0_triggered) {
102  /* Wait for the timer to be triggered */
103  ;
104  }
105  break;
106  case IRQ_TEST_SCENARIO_4:
107  if (current_execution_data->timer0_triggered) {
109  }
110  while ((signals & SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ) == 0) {
111  signals = psa_wait(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ,
112  PSA_BLOCK);
113  }
114  if (!current_execution_data->timer0_triggered) {
116  }
117  psa_eoi(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ);
118  break;
119  case IRQ_TEST_SCENARIO_5:
120  /* nothing to do*/
121  break;
122  default:
124  }
125 
127 }
128 
130  struct psa_invec *in_vec, size_t in_len,
131  struct psa_outvec *out_vec, size_t out_len)
132 {
133  enum irq_test_scenario_t irq_test_scenario;
134  struct irq_test_execution_data_t *execution_data;
135 
136  if ((in_len != 2) || (out_len != 0)) {
138  }
139 
140  if ((in_vec[0].len != sizeof(uint32_t)) ||
141  (in_vec[1].len != sizeof(struct irq_test_execution_data_t *))) {
143  }
144 
145  irq_test_scenario =
146  (enum irq_test_scenario_t) *(uint32_t *)in_vec[0].base;
147 
148  execution_data =
149  *(struct irq_test_execution_data_t **)in_vec[1].base;
150 
151  return spm_irq_test_1_prepare_test_scenario_internal(irq_test_scenario,
152  execution_data);
153 }
154 
155 #ifndef TFM_PSA_API
156 
158 {
159  stop_timer();
160 
161  if ((current_execution_data == NULL) ||
162  (current_execution_data->timer0_triggered != 0)) {
163  halt_test_execution();
164  }
165 
166  current_execution_data->timer0_triggered = 1;
167 
168  switch (current_scenario) {
171  break;
172  case IRQ_TEST_SCENARIO_1:
173  case IRQ_TEST_SCENARIO_2:
174  case IRQ_TEST_SCENARIO_3:
176  break;
177  case IRQ_TEST_SCENARIO_4:
178  /* nothing to do*/
179  break;
180  case IRQ_TEST_SCENARIO_5:
181  halt_test_execution();
182  /* No secure interrups are used in this scenario */
183  break;
184  default:
185  halt_test_execution();
186  break;
187  }
188 
189  __asm("DSB");
190 }
191 
192 #else /* TFM_PSA_API */
193 
194 typedef psa_status_t (*irq_test_1_func_t)(psa_msg_t *msg);
195 
196 static void spm_irq_test_1_signal_handle(psa_signal_t signal,
197  irq_test_1_func_t pfn)
198 {
199  psa_msg_t msg;
200  psa_status_t status;
201 
202  status = psa_get(signal, &msg);
203  if (status) {
204  return;
205  }
206 
207  switch (msg.type) {
208  case PSA_IPC_CONNECT:
210  break;
211  case PSA_IPC_CALL:
212  status = pfn(&msg);
213  psa_reply(msg.handle, status);
214  break;
215  case PSA_IPC_DISCONNECT:
217  break;
218  default:
219  break;
220  }
221 }
222 
223 void TIMER_0_isr_ipc(void)
224 {
225  current_execution_data->timer0_triggered = 1;
226 
227  stop_timer();
228 
229  switch (current_scenario) {
232  break;
233  case IRQ_TEST_SCENARIO_1:
234  case IRQ_TEST_SCENARIO_2:
236  break;
237  case IRQ_TEST_SCENARIO_3:
238  /* execute_msg_handle have to be valid at this point */
239  if (execute_msg_handle <= 0) {
240  halt_test_execution();
241  }
242  /* reply to the execute message, to unblock NS side */
243  psa_reply(execute_msg_handle, CORE_TEST_ERRNO_SUCCESS);
244  execute_msg_handle = -1;
246  break;
247  case IRQ_TEST_SCENARIO_4:
248  /* This case should never be executed as in this scenario the 'execute
249  * function does the psa wait, and calls psa_eoi immediately'. So when
250  * execution gets to the psa_wait in the main loop, the IRQ signal is
251  * unset.
252  */
253  halt_test_execution();
254  break;
255  case IRQ_TEST_SCENARIO_5:
256  /* No secure interrups are used in this scenario */
257  halt_test_execution();
258  break;
259  default:
260  halt_test_execution();
261  break;
262  }
263 }
264 
265 static psa_status_t spm_irq_test_1_wrap_prepare_test_scenario(psa_msg_t *msg)
266 {
267  uint32_t irq_test_scenario;
268  struct irq_test_execution_data_t *execution_data;
269  size_t num;
270 
271  if ((msg->in_size[0] != sizeof(uint32_t)) ||
272  (msg->in_size[1] != sizeof(struct irq_test_execution_data_t *))) {
274  }
275 
276 
277  num = psa_read(msg->handle, 0, &irq_test_scenario, sizeof(uint32_t));
278  if (num != msg->in_size[0]) {
280  }
281 
282  num = psa_read(msg->handle, 1, &execution_data,
283  sizeof(struct irq_test_execution_data_t *));
284  if (num != msg->in_size[1]) {
286  }
287 
289  irq_test_scenario,
290  execution_data);
291 }
292 
293 static void spm_irq_test_1_execute_test_scenario_ipc_call(psa_msg_t *msg)
294 {
295  size_t num;
296  uint32_t irq_test_scenario;
297  psa_signal_t signals = 0;
298 
299  num = psa_read(msg->handle, 0, &irq_test_scenario, sizeof(uint32_t));
300  if ((num != msg->in_size[0]) ||
301  (irq_test_scenario != current_scenario)) {
303  return;
304  }
305 
306  switch (irq_test_scenario) {
309  return;
310  case IRQ_TEST_SCENARIO_1:
311  case IRQ_TEST_SCENARIO_2:
312  case IRQ_TEST_SCENARIO_5:
313  /* nothing to do, return success */
315  return;
316  case IRQ_TEST_SCENARIO_3:
317  if (current_execution_data->timer0_triggered) {
319  return;
320  }
321  /* We need the ISR to be able to run. So we do a wait to let
322  * it run and set timer0_triggered. This message will be replied
323  * from the ISR, so the NS side remains blocked for now. To be able
324  * to reply, we also save the handle of the message.
325  */
326  if (execute_msg_handle > 0) {
327  /* execute_msg_handle should be uninitialised at this point */
329  return;
330  }
331  execute_msg_handle = msg->handle;
332  while (!(signals & SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ)) {
333  signals = psa_wait(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ,
334  PSA_BLOCK);
335  }
336  return;
337  case IRQ_TEST_SCENARIO_4:
338  while (!(signals & SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ)) {
339  signals = psa_wait(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ,
340  PSA_BLOCK);
341  }
342  /* There is no need to call the ISR in this scenario, so we can
343  * clear the IRQ signal
344  */
345  stop_timer();
346  psa_eoi(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ);
348  break;
349  default:
351  return;
352  }
353 }
354 
355 static void spm_irq_test_1_execute_test_scenario_ipc(psa_signal_t signal)
356 {
357  psa_msg_t msg;
358  psa_status_t status;
359 
360  status = psa_get(signal, &msg);
361  if (status) {
362  return;
363  }
364 
367  }
368 
369  switch (msg.type) {
370  case PSA_IPC_CONNECT:
372  break;
373  case PSA_IPC_CALL:
374  spm_irq_test_1_execute_test_scenario_ipc_call(&msg);
375  break;
376  case PSA_IPC_DISCONNECT:
378  break;
379  default:
380  break;
381  }
382 }
383 #endif /* TFM_PSA_API */
384 
385 int32_t tfm_irq_test_1_init(void)
386 {
387  tfm_enable_irq(SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ);
388 #ifdef TFM_PSA_API
389  psa_signal_t signals = 0;
390 
391  while (1) {
392  signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
393  if (signals & SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ) {
394  TIMER_0_isr_ipc();
396  spm_irq_test_1_signal_handle(
397  SPM_CORE_IRQ_TEST_1_PREPARE_TEST_SCENARIO_SIGNAL,
398  spm_irq_test_1_wrap_prepare_test_scenario);
400  spm_irq_test_1_execute_test_scenario_ipc(
401  SPM_CORE_IRQ_TEST_1_EXECUTE_TEST_SCENARIO_SIGNAL);
402  } else {
403  ; /* do nothing */
404  }
405  }
406 #else
407  return TFM_SUCCESS;
408 #endif /* TFM_PSA_API */
409 }
uint32_t psa_signal_t
Definition: service.h:50
#define SPM_CORE_IRQ_TEST_1_PREPARE_TEST_SCENARIO_SIGNAL
#define PSA_BLOCK
Definition: service.h:31
int32_t type
Definition: service.h:56
#define PSA_SUCCESS
Definition: crypto_values.h:35
#define SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ
int32_t tfm_irq_test_1_init(void)
int32_t spm_irq_test_1_prepare_test_scenario_internal(enum irq_test_scenario_t irq_test_scenario, struct irq_test_execution_data_t *execution_data)
int32_t spm_irq_test_1_execute_test_scenario(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len)
#define IRQ_TEST_TOOL_CODE_LOCATION(name)
void tfm_enable_irq(psa_signal_t irq_signal)
Definition: arch.c:51
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
#define SPM_CORE_IRQ_TEST_1_EXECUTE_TEST_SCENARIO_SIGNAL
psa_handle_t handle
Definition: service.h:61
irq_test_scenario_t
void SPM_CORE_IRQ_TEST_1_SIGNAL_TIMER_0_IRQ_isr(void)
#define PSA_IPC_DISCONNECT
Definition: service.h:47
uint32_t spm_irq_test_1_prepare_test_scenario(struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec, size_t out_len)
#define PSA_WAIT_ANY
Definition: service.h:36
size_t in_size[PSA_MAX_IOVEC]
Definition: service.h:70
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
int32_t psa_handle_t
Definition: client.h:61
void psa_eoi(psa_signal_t irq_signal)
Inform the SPM that an interrupt has been handled (end of interrupt).
Definition: psa_service.c:91
#define PSA_IPC_CONNECT
Definition: service.h:45
#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
volatile int32_t timer0_triggered