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