1 /***************************************************************************//**
2 * @file
3 * @brief SE Mailbox API
4 *******************************************************************************
5 * # License
6 * <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
7 *******************************************************************************
8 *
9 * SPDX-License-Identifier: Zlib
10 *
11 * The licensor of this software is Silicon Laboratories Inc.
12 *
13 * This software is provided 'as-is', without any express or implied
14 * warranty. In no event will the authors be held liable for any damages
15 * arising from the use of this software.
16 *
17 * Permission is granted to anyone to use this software for any purpose,
18 * including commercial applications, and to alter it and redistribute it
19 * freely, subject to the following restrictions:
20 *
21 * 1. The origin of this software must not be misrepresented; you must not
22 * claim that you wrote the original software. If you use this software
23 * in a product, an acknowledgment in the product documentation would be
24 * appreciated but is not required.
25 * 2. Altered source versions must be plainly marked as such, and must not be
26 * misrepresented as being the original software.
27 * 3. This notice may not be removed or altered from any source distribution.
28 *
29 ******************************************************************************/
30
31 #include "sli_se_manager_mailbox.h"
32
33 #if defined(SLI_SE_MAILBOX_HOST_SYSTEM) || defined(SEMAILBOX_PRESENT) || defined(CRYPTOACC_PRESENT)
34
35 #if !defined(SLI_SE_MAILBOX_HOST_SYSTEM)
36
37 #if defined(CRYPTOACC_PRESENT)
38 #include "sl_core.h"
39 #endif
40
41 #include "sl_assert.h"
42
43 #endif
44
45 /***************************************************************************//**
46 * @addtogroup se
47 * @{
48 ******************************************************************************/
49
50 /*******************************************************************************
51 ****************************** DEFINES ***********************************
52 ******************************************************************************/
53 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
54
55 #if defined(CRYPTOACC_PRESENT)
56
57 /// Signal that OTP version is incorporated into the status field of the output
58 #define SE_VSE_REPLY_STATUS_OTP_VERSION_SET (1 << 21)
59 /// Mask defining the region of the status field that contains the OTP version
60 /// number.
61 #define SE_VSE_REPLY_STATUS_OTP_VERSION_MASK (0xFF000000UL)
62 /// Shift to insert a number into the otp version part of the status field
63 #define SE_VSE_REPLY_STATUS_OTP_VERSION_SHIFT (24)
64
65 /* Size of VSE Mailbox instance.
66 There are two instances, input and output. */
67 #define ROOT_MAILBOX_SIZE (512UL)
68
69 /* Base addresses of the VSE Input and Output Mailbox data structures.
70 (Must be stored in a RAM area which is not used by the VSE)
71 We use the upper 1KB of FRC RAM for the VSE mailboxes. */
72 #define ROOT_MAILBOX_OUTPUT_S_BASE (RDMEM_FRCRAM_S_MEM_END + 1 - ROOT_MAILBOX_SIZE)
73 #define ROOT_MAILBOX_INPUT_S_BASE (ROOT_MAILBOX_OUTPUT_S_BASE - ROOT_MAILBOX_SIZE)
74
75 // SL_TRUSTZONE_PERIPHERAL_AHBRADIO_S is defined in sl_trustzone_secure_config.h
76 #if ((defined(SL_TRUSTZONE_SECURE) && !defined(SL_TRUSTZONE_PERIPHERAL_AHBRADIO_S)) \
77 || (defined(SL_TRUSTZONE_PERIPHERAL_AHBRADIO_S) && SL_TRUSTZONE_PERIPHERAL_AHBRADIO_S))
78
79 #define RDMEM_FRCRAM_MEM_BASE RDMEM_FRCRAM_S_MEM_BASE
80
81 #define ROOT_MAILBOX_OUTPUT_BASE SYSCFG->ROOTDATA1;
82 #define ROOT_MAILBOX_OUTPUT_BASE_EXPECTED ROOT_MAILBOX_OUTPUT_S_BASE
83 #else
84 #define RDMEM_FRCRAM_MEM_BASE RDMEM_FRCRAM_NS_MEM_BASE
85
86 // VSE will always output the secure address, if NS is desired, caculate the NS address.
87 #define ROOT_MAILBOX_OUTPUT_BASE (SYSCFG->ROOTDATA1 - RDMEM_FRCRAM_S_MEM_BASE + RDMEM_FRCRAM_NS_MEM_BASE);
88 #define ROOT_MAILBOX_OUTPUT_BASE_EXPECTED (RDMEM_FRCRAM_NS_MEM_END + 1 - ROOT_MAILBOX_SIZE)
89 #endif
90 #define ROOT_MAILBOX_INPUT_BASE (ROOT_MAILBOX_OUTPUT_BASE_EXPECTED - ROOT_MAILBOX_SIZE)
91
92 /* Position of parameter number field in VSE Input Mailbox LENGTH field.*/
93 #define ROOT_MB_LENGTH_PARAM_NUM_SHIFT (24)
94
95 /* Done flag indicating that the VSE Mailbox handler has completed
96 processing the mailbox command. */
97 #define ROOT_MB_DONE (1 << 23)
98
99 /* VSE Configuration Status bits mask */
100 #define ROOT_MB_OUTPUT_STATUS_CONFIG_BITS_MASK (0xFFFF)
101
102 #endif // #if defined(CRYPTOACC_PRESENT)
103 /** @endcond */
104
105 /*******************************************************************************
106 ****************************** TYPEDEFS ***********************************
107 ******************************************************************************/
108 #if defined(CRYPTOACC_PRESENT)
109 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
110 // VSE Input Mailbox structure
111 typedef struct {
112 volatile uint32_t magic;
113 volatile uint32_t command;
114 volatile uint32_t length;
115 volatile uint32_t data[0];
116 } root_mailbox_input_t;
117
118 // VSE Output Mailbox structure
119 typedef struct {
120 volatile uint32_t magic;
121 volatile uint32_t version;
122 volatile uint32_t status;
123 volatile uint32_t command;
124 volatile uint32_t length;
125 volatile uint32_t data[0];
126 } root_mailbox_output_t;
127 /** @endcond */
128
129 #endif // #if defined(CRYPTOACC_PRESENT)
130
131 /*******************************************************************************
132 ************************** STATIC FUNCTIONS *******************************
133 ******************************************************************************/
134
135 #if defined(SEMAILBOX_PRESENT)
136 /***************************************************************************//**
137 * @brief
138 * Write to FIFO
139 *
140 * @param value
141 * Value to write to FIFO
142 ******************************************************************************/
143 #if defined(_SEMAILBOX_FIFO_RESETVALUE)
write_to_fifo(uint32_t value)144 __STATIC_INLINE void write_to_fifo(uint32_t value)
145 {
146 SEMAILBOX_HOST->FIFO = value;
147 }
148 #else
write_to_fifo(uint32_t value)149 __STATIC_INLINE void write_to_fifo(uint32_t value)
150 {
151 SEMAILBOX_HOST->FIFO[0].DATA = value;
152 }
153 #endif
154
155 #elif defined(CRYPTOACC_PRESENT)
156
157 /***************************************************************************//**
158 * @brief
159 * Return a pointer to the root mailbox output
160 *
161 * @return root_mailbox_output_t pointer
162 ******************************************************************************/
get_root_mailbox_output(void)163 static root_mailbox_output_t* get_root_mailbox_output(void)
164 {
165 // Setup pointer to the VSE Output Mailbox data structure
166 // (must be stored in a RAM area which is not used by the VSE)
167 bool sys_cfg_clk_enabled = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) != 0);
168 CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
169 root_mailbox_output_t *mailbox_output = (root_mailbox_output_t *) ROOT_MAILBOX_OUTPUT_BASE;
170 if (!sys_cfg_clk_enabled) {
171 CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
172 }
173 return mailbox_output;
174 }
175
176 /***************************************************************************//**
177 * @brief
178 * Check whether the running command has completed.
179 *
180 * @details
181 * This function polls the SE-to-host mailbox interrupt flag.
182 *
183 * @return True if a command has completed and the result is available
184 ******************************************************************************/
vse_is_command_completed(root_mailbox_output_t * root_mailbox_output)185 static bool vse_is_command_completed(root_mailbox_output_t *root_mailbox_output)
186 {
187 // First verify that the response is ok
188 if (!sli_vse_mailbox_is_output_valid()) {
189 return false;
190 }
191
192 // Check status MB_DONE flag of the mailbox
193 return ((root_mailbox_output->status & ROOT_MB_DONE) == ROOT_MB_DONE);
194 }
195 #endif // SEMAILBOX_PRESENT
196
197 /*******************************************************************************
198 ************************** GLOBAL FUNCTIONS *******************************
199 ******************************************************************************/
200
201 /***************************************************************************//**
202 * @brief
203 * Add input data to a mailbox command
204 ******************************************************************************/
sli_se_mailbox_command_add_input(sli_se_mailbox_command_t * command,sli_se_datatransfer_t * data)205 void sli_se_mailbox_command_add_input(sli_se_mailbox_command_t *command, sli_se_datatransfer_t *data)
206 {
207 if (command->data_in == NULL) {
208 command->data_in = data;
209 } else {
210 sli_se_datatransfer_t *next = command->data_in;
211 while (next->next != (void*)SLI_SE_DATATRANSFER_STOP) {
212 next = (sli_se_datatransfer_t*)next->next;
213 }
214 next->next = data;
215 }
216 }
217
218 /***************************************************************************//**
219 * @brief
220 * Add output data to a mailbox command
221 ******************************************************************************/
sli_se_mailbox_command_add_output(sli_se_mailbox_command_t * command,sli_se_datatransfer_t * data)222 void sli_se_mailbox_command_add_output(sli_se_mailbox_command_t *command, sli_se_datatransfer_t *data)
223 {
224 if (command->data_out == NULL) {
225 command->data_out = data;
226 } else {
227 sli_se_datatransfer_t *next = command->data_out;
228 while (next->next != (void*)SLI_SE_DATATRANSFER_STOP) {
229 next = (sli_se_datatransfer_t*)next->next;
230 }
231 next->next = data;
232 }
233 }
234
235 /***************************************************************************//**
236 * @brief
237 * Add a parameter to a mailbox command
238 ******************************************************************************/
sli_se_mailbox_command_add_parameter(sli_se_mailbox_command_t * command,uint32_t parameter)239 void sli_se_mailbox_command_add_parameter(sli_se_mailbox_command_t *command, uint32_t parameter)
240 {
241 if (command->num_parameters >= SLI_SE_COMMAND_MAX_PARAMETERS) {
242 EFM_ASSERT(command->num_parameters < SLI_SE_COMMAND_MAX_PARAMETERS);
243 return;
244 }
245
246 command->parameters[command->num_parameters] = parameter;
247 command->num_parameters += 1;
248 }
249
250 #if !defined(SLI_SE_MAILBOX_HOST_SYSTEM)
251
252 /***************************************************************************//**
253 * @brief
254 * Execute a command on the SE by writing the command to SEMAILBOX->FIFO
255 ******************************************************************************/
sli_se_mailbox_execute_command(sli_se_mailbox_command_t * command)256 void sli_se_mailbox_execute_command(sli_se_mailbox_command_t *command)
257 {
258 // Don't overflow our struct
259 if (command->num_parameters > SLI_SE_COMMAND_MAX_PARAMETERS) {
260 EFM_ASSERT(command->num_parameters <= SLI_SE_COMMAND_MAX_PARAMETERS);
261 return;
262 }
263
264 #if defined(SEMAILBOX_PRESENT)
265
266 // Wait for room available in the mailbox
267 while (!(SEMAILBOX_HOST->TX_STATUS & SEMAILBOX_TX_STATUS_TXINT)) {
268 }
269
270 #if (_SILICON_LABS_32B_SERIES == 3)
271 // Write header (including message size) to start transaction
272 SEMAILBOX_HOST->TX_HEADER = sizeof(uint32_t) * (5 + command->num_parameters);
273 // Write a 32-bit word to the FIFO ( potentially used as command handle )
274 write_to_fifo(0);
275 #else
276 // Write header (including message size) to start transaction
277 SEMAILBOX_HOST->TX_HEADER = sizeof(uint32_t) * (4 + command->num_parameters);
278 #endif
279
280 // Write command into FIFO
281 write_to_fifo(command->command);
282
283 // Write DMA descriptors into FIFO
284 write_to_fifo((uint32_t)command->data_in);
285 write_to_fifo((uint32_t)command->data_out);
286
287 // Write applicable parameters into FIFO
288 for (size_t i = 0; i < command->num_parameters; i++) {
289 write_to_fifo(command->parameters[i]);
290 }
291
292 #elif defined(CRYPTOACC_PRESENT)
293 // Prepare the VSE Mailbox within a critical section to prevent
294 // the process from getting interrupted. At this point, the only option
295 // we have is to go through a reset, so it is safe to enter the critical section.
296 (void)CORE_EnterCritical();
297
298 // Setup pointer to the VSE Mailbox Input data structure
299 // (must be stored in a RAM area which is not used by the VSE)
300 root_mailbox_input_t *mailbox_input = (root_mailbox_input_t*)ROOT_MAILBOX_INPUT_BASE;
301 uint32_t *mailbox_data;
302 unsigned int mailbox_dataLen, inDataLen, i;
303 sli_se_datatransfer_t *inDataDesc;
304 uint32_t *inData;
305 uint32_t checksum;
306 bool sysCfgClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) != 0);
307 CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
308
309 // Store the secure memory base addresses for VSE to be able to read from the address
310 // Set base of Mailbox Input data structure in SYSCFG register in order
311 // for VSE to find it.
312 SYSCFG->ROOTDATA0 = ROOT_MAILBOX_INPUT_S_BASE;
313 // Set base of Mailbox Output data structure in SYSCFG register in order
314 // for VSE to know where to write output data.
315 // Write command into FIFO
316 SYSCFG->ROOTDATA1 = ROOT_MAILBOX_OUTPUT_S_BASE;
317
318 if (!sysCfgClkWasEnabled) {
319 CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
320 }
321
322 mailbox_input->magic = SLI_SE_RESPONSE_MAILBOX_VALID;
323 mailbox_input->command = command->command;
324
325 // Write applicable parameters into Mailbox DATA array
326 mailbox_data = (uint32_t*) mailbox_input->data;
327 for (mailbox_dataLen = 0; mailbox_dataLen < command->num_parameters; mailbox_dataLen++) {
328 mailbox_data[mailbox_dataLen] = command->parameters[mailbox_dataLen];
329 }
330
331 // Write input data into Mailbox DATA array
332 inDataLen = 0;
333 for (inDataDesc = command->data_in; inDataDesc; inDataDesc = (sli_se_datatransfer_t*) inDataDesc->next) {
334 inData = (uint32_t*) inDataDesc->data;
335 for (i = 0; i < (inDataDesc->length & SLI_SE_DATATRANSFER_LENGTH_MASK) / sizeof(uint32_t); i++) {
336 // Make sure we do not overflow the input mailbox.
337 EFM_ASSERT(mailbox_dataLen < ROOT_MAILBOX_SIZE);
338 mailbox_data[mailbox_dataLen++] = inData[i];
339 inDataLen++;
340 }
341 if (inDataDesc->next == (void*)SLI_SE_DATATRANSFER_STOP) {
342 break;
343 }
344 }
345
346 // Write number of parameters and data words to 'length' field of mailbox.
347 mailbox_input->length =
348 inDataLen | (command->num_parameters << ROOT_MB_LENGTH_PARAM_NUM_SHIFT);
349
350 // Calculate checksum using bitwise XOR over the all words in the mailbox
351 // data structure, minus the CHECKSUM word (32bit = 4bytes ) at the end.
352 checksum = mailbox_input->magic;
353 checksum ^= mailbox_input->command;
354 checksum ^= mailbox_input->length;
355 for (i = 0; i < mailbox_dataLen; i++) {
356 checksum ^= mailbox_data[i];
357 }
358
359 // Finally, write the calculated checksum to mailbox checksum field
360 mailbox_data[mailbox_dataLen] = checksum;
361
362 __NVIC_SystemReset();
363
364 #endif // #if defined(SEMAILBOX_PRESENT)
365 }
366 #endif // #if !defined(SLI_SE_MAILBOX_HOST_SYSTEM)
367
368 #if defined(CRYPTOACC_PRESENT)
369
370 /***************************************************************************//**
371 * @brief
372 * Get current SE version
373 ******************************************************************************/
sli_vse_mailbox_get_version(uint32_t * version)374 sli_se_mailbox_response_t sli_vse_mailbox_get_version(uint32_t *version)
375 {
376 root_mailbox_output_t *root_mailbox_output = get_root_mailbox_output();
377
378 if (version == NULL) {
379 return SLI_SE_RESPONSE_INVALID_PARAMETER;
380 }
381
382 // First verify that the response is ok.
383 if (!sli_vse_mailbox_is_output_valid()) {
384 return SLI_SE_RESPONSE_MAILBOX_INVALID;
385 }
386
387 // Return the 'version' from the Output Mailbox
388 *version = root_mailbox_output->version;
389
390 return SLI_SE_RESPONSE_OK;
391 }
392
393 /***************************************************************************//**
394 * @brief
395 * Get VSE configuration and status bits
396 ******************************************************************************/
sli_vse_mailbox_get_cfg_status(uint32_t * cfg_status)397 sli_se_mailbox_response_t sli_vse_mailbox_get_cfg_status(uint32_t *cfg_status)
398 {
399 if (cfg_status == NULL) {
400 return SLI_SE_RESPONSE_INVALID_PARAMETER;
401 }
402
403 root_mailbox_output_t *root_mailbox_output = get_root_mailbox_output();
404
405 // First verify that the response is ok.
406 if (!sli_vse_mailbox_is_output_valid()) {
407 return SLI_SE_RESPONSE_MAILBOX_INVALID;
408 }
409
410 // Return the configuration status bits
411 *cfg_status = root_mailbox_output->status & ROOT_MB_OUTPUT_STATUS_CONFIG_BITS_MASK;
412
413 return SLI_SE_RESPONSE_OK;
414 }
415
416 /***************************************************************************//**
417 * @brief
418 * Get the version number of the OTP from the status field of the output
419 * mailbox
420 ******************************************************************************/
sli_vse_mailbox_get_otp_version(uint32_t * otp_version)421 sli_se_mailbox_response_t sli_vse_mailbox_get_otp_version(uint32_t *otp_version)
422 {
423 if (otp_version == NULL) {
424 return SLI_SE_RESPONSE_INVALID_PARAMETER;
425 }
426
427 root_mailbox_output_t *root_mailbox_output = get_root_mailbox_output();
428
429 // First verify that the response is ok.
430 if (!sli_vse_mailbox_is_output_valid()) {
431 return SLI_SE_RESPONSE_MAILBOX_INVALID;
432 }
433
434 bool is_otp_version_set = root_mailbox_output->status & SE_VSE_REPLY_STATUS_OTP_VERSION_SET;
435 if (is_otp_version_set) {
436 // Return the OTP version from the status field.
437 *otp_version = (root_mailbox_output->status & SE_VSE_REPLY_STATUS_OTP_VERSION_MASK) >> SE_VSE_REPLY_STATUS_OTP_VERSION_SHIFT;
438 } else {
439 return SLI_SE_RESPONSE_INVALID_COMMAND;
440 }
441
442 return SLI_SE_RESPONSE_OK;
443 }
444
445 /***************************************************************************//**
446 * @brief
447 * Read the previously executed command.
448 ******************************************************************************/
sli_vse_mailbox_read_executed_command(void)449 uint32_t sli_vse_mailbox_read_executed_command(void)
450 {
451 root_mailbox_output_t *root_mailbox_output = get_root_mailbox_output();
452
453 // First verify that the Output Mailbox includes a valid response.
454 if (!vse_is_command_completed(root_mailbox_output)) {
455 return SLI_SE_RESPONSE_MAILBOX_INVALID;
456 }
457
458 return root_mailbox_output->command;
459 }
460
461 /***************************************************************************//**
462 * @brief
463 * Read the status of the previously executed command.
464 *
465 * @details
466 * This function reads the status of the previously executed command.
467 *
468 * @return
469 * One of the SE_RESPONSE return codes:
470 * SLI_SE_RESPONSE_OK when the command was executed successfully or a signature
471 * was successfully verified,
472 * SLI_SE_RESPONSE_INVALID_COMMAND when the command ID was not recognized,
473 * SE_RESPONSE_AUTHORIZATION_ERROR when the command is not authorized,
474 * SE_RESPONSE_INVALID_SIGNATURE when signature verification failed,
475 * SE_RESPONSE_BUS_ERROR when a bus error was thrown during the command, e.g.
476 * because of conflicting Secure/Non-Secure memory accesses,
477 * SE_RESPONSE_CRYPTO_ERROR on an internal SE failure, or
478 * SLI_SE_RESPONSE_INVALID_PARAMETER when an invalid parameter was passed
479 * SLI_SE_RESPONSE_MAILBOX_INVALID when the mailbox content is invalid
480 ******************************************************************************/
sli_se_mailbox_read_response(void)481 sli_se_mailbox_response_t sli_se_mailbox_read_response(void)
482 {
483 root_mailbox_output_t *root_mailbox_output = get_root_mailbox_output();
484
485 // First verify that the Output Mailbox includes a valid response.
486 if (!vse_is_command_completed(root_mailbox_output)) {
487 return SLI_SE_RESPONSE_MAILBOX_INVALID;
488 }
489
490 return (sli_se_mailbox_response_t)(root_mailbox_output->status & SLI_SE_RESPONSE_MASK);
491 }
492
493 /***************************************************************************//**
494 * @brief
495 * Acknowledge and get status and output data of a completed command.
496 *
497 * @details
498 * This function acknowledges and gets the status and output data of a
499 * completed mailbox command.
500 * The mailbox command is acknowledged by inverting all bits in the checksum
501 * (XOR with 0xFFFFFFFF).
502 * The output data is copied into the linked list of output buffers pointed
503 * to in the given command data structure.
504 *
505 * @param[in] command
506 * Pointer to an SE command structure.
507 *
508 * @return
509 * One of the SE_RESPONSE return codes.
510 * @retval SLI_SE_RESPONSE_OK when the command was executed successfully or a
511 * signature was successfully verified,
512 * @retval SLI_SE_RESPONSE_INVALID_COMMAND when the command ID was not recognized,
513 * @retval SE_RESPONSE_AUTHORIZATION_ERROR when the command is not authorized,
514 * @retval SE_RESPONSE_INVALID_SIGNATURE when signature verification failed,
515 * @retval SE_RESPONSE_BUS_ERROR when a bus error was thrown during the command,
516 * e.g. because of conflicting Secure/Non-Secure
517 * memory accesses,
518 * @retval SE_RESPONSE_CRYPTO_ERROR on an internal SE failure, or
519 * @retval SLI_SE_RESPONSE_INVALID_PARAMETER when an invalid parameter was passed
520 * @retval SLI_SE_RESPONSE_MAILBOX_INVALID when mailbox command not done or invalid
521 ******************************************************************************/
sli_vse_mailbox_ack_command(sli_se_mailbox_command_t * command)522 sli_se_mailbox_response_t sli_vse_mailbox_ack_command(sli_se_mailbox_command_t *command)
523 {
524 // Setup pointer to the VSE Output Mailbox data structure
525 // (must be stored in a RAM area which is not used by the VSE)
526 root_mailbox_output_t *root_mailbox_output = get_root_mailbox_output();
527
528 uint32_t *mbData = (uint32_t*) root_mailbox_output->data;
529 sli_se_datatransfer_t *outDataDesc = command->data_out;
530 unsigned int outDataLen, outDataCnt, i, outDescLen;
531 uint32_t *outData;
532
533 // First verify that the Output Mailbox includes a valid response.
534 if (!vse_is_command_completed(root_mailbox_output)) {
535 return SLI_SE_RESPONSE_MAILBOX_INVALID;
536 }
537
538 // Get output data length
539 outDataLen = root_mailbox_output->length;
540
541 // Acknowledge the output mailbox response by invalidating checksum
542 mbData[outDataLen] ^= 0xFFFFFFFFUL;
543
544 // Check command status code
545 if ((root_mailbox_output->status & SLI_SE_RESPONSE_MASK) != SLI_SE_RESPONSE_OK) {
546 return root_mailbox_output->status & SLI_SE_RESPONSE_MASK;
547 }
548
549 // Copy data from the Output Mailbox to the linked list of output
550 // buffers provided by the user
551 outDataCnt = 0;
552 while (outDataDesc && (outDataCnt < outDataLen)) {
553 outData = (uint32_t*) outDataDesc->data;
554 outDescLen =
555 (outDataDesc->length & SLI_SE_DATATRANSFER_LENGTH_MASK) / sizeof(uint32_t);
556 for (i = 0; (i < outDescLen) && (outDataCnt < outDataLen); i++) {
557 outData[i] = mbData[outDataCnt++];
558 }
559 // If we have reached the end of a buffer, go to next buffer descriptor
560 if (i == outDescLen) {
561 outDataDesc = (sli_se_datatransfer_t*)
562 ((uint32_t)outDataDesc->next & ~SLI_SE_DATATRANSFER_STOP);
563 }
564 }
565
566 // Check if the output data list is too small to copy all output data in
567 // mailbox.
568 if ((outDataDesc == 0) && (outDataCnt < outDataLen)) {
569 return SLI_SE_RESPONSE_INVALID_PARAMETER;
570 }
571
572 return SLI_SE_RESPONSE_OK;
573 }
574
575 /***************************************************************************//**
576 * @brief
577 * Check whether the VSE Output Mailbox is valid.
578 *
579 * @return True if the VSE Output Mailbox is valid (magic and checksum OK)
580 ******************************************************************************/
sli_vse_mailbox_is_output_valid(void)581 bool sli_vse_mailbox_is_output_valid(void)
582 {
583 root_mailbox_output_t *root_mailbox_output = get_root_mailbox_output();
584 uint32_t *mb_ptr32 = (uint32_t*) root_mailbox_output;
585 uint32_t checksum;
586 unsigned int mb_len, cnt;
587
588 if ((uint32_t)root_mailbox_output > ROOT_MAILBOX_OUTPUT_BASE_EXPECTED
589 || (uint32_t)root_mailbox_output < RDMEM_FRCRAM_MEM_BASE) {
590 return false;
591 }
592
593 // Verify magic word of mailbox
594 if (root_mailbox_output->magic != SLI_SE_RESPONSE_MAILBOX_VALID) {
595 return false;
596 }
597
598 // Get length of mailbox
599 mb_len = sizeof(root_mailbox_output_t) / sizeof(uint32_t) + root_mailbox_output->length;
600 if (mb_len >= ROOT_MAILBOX_SIZE) {
601 return false;
602 }
603 // Calculate checksum using bitwise XOR over all words in the mailbox
604 // data structure, minus the CHECKSUM word at the end.
605 for (checksum = 0, cnt = 0; cnt < mb_len; cnt++) {
606 checksum ^= mb_ptr32[cnt];
607 }
608
609 // Verify that the calculated checksum is equal to the mailbox checksum.
610 return (mb_ptr32[mb_len] == checksum);
611 }
612
613 #endif // #if defined(CRYPTOACC_PRESENT)
614
615 /** @} (end addtogroup se) */
616
617 #endif /* defined(SEMAILBOX_PRESENT) || defined(CRYPTOACC_PRESENT) */
618