1 /***************************************************************************//**
2  * @file
3  * @brief Secure Element API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 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 "em_se.h"
32 
33 #if defined(SLI_EM_SE_HOST) || defined(SEMAILBOX_PRESENT) || defined(CRYPTOACC_PRESENT)
34 
35 #if defined(SEMAILBOX_PRESENT) || defined(CRYPTOACC_PRESENT)
36 
37 #include "sl_core.h"
38 #include "sl_assert.h"
39 
40 #endif
41 
42 /***************************************************************************//**
43  * @addtogroup se
44  * @{
45  ******************************************************************************/
46 
47 /*******************************************************************************
48  ******************************   DEFINES    ***********************************
49  ******************************************************************************/
50 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
51 /* OTP initialization structure defines. */
52 #define SE_OTP_MCU_SETTINGS_FLAG_SECURE_BOOT_ENABLE (1 << 16)
53 #define SE_OTP_MCU_SETTINGS_FLAG_SECURE_BOOT_VERIFY_CERTIFICATE (1 << 17)
54 #define SE_OTP_MCU_SETTINGS_FLAG_SECURE_BOOT_ANTI_ROLLBACK (1 << 18)
55 #define SE_OTP_MCU_SETTINGS_FLAG_SECURE_BOOT_PAGE_LOCK_NARROW (1 << 19)
56 #define SE_OTP_MCU_SETTINGS_FLAG_SECURE_BOOT_PAGE_LOCK_FULL (1 << 20)
57 
58 #if defined(CRYPTOACC_PRESENT)
59 
60 /// Signal that OTP version is incorporated into the status field of the output
61 #define SE_VSE_REPLY_STATUS_OTP_VERSION_SET (1 << 21)
62 /// Mask defining the region of the status field that contains the OTP version
63 /// number.
64 #define SE_VSE_REPLY_STATUS_OTP_VERSION_MASK (0xFF000000UL)
65 /// Shift to insert a number into the otp version part of the status field
66 #define SE_VSE_REPLY_STATUS_OTP_VERSION_SHIFT (24)
67 
68 /* Size of VSE Mailbox instance.
69    There are two instances, input and output. */
70 #define ROOT_MAILBOX_SIZE  (512UL)
71 
72 /* Base addresses of the VSE Input and Output Mailbox data structures.
73    (Must be stored in a RAM area which is not used by the VSE)
74    We use the upper 1KB of FRC RAM for the VSE mailboxes. */
75 #define ROOT_MAILBOX_OUTPUT_S_BASE (RDMEM_FRCRAM_S_MEM_END + 1 - ROOT_MAILBOX_SIZE)
76 #define ROOT_MAILBOX_INPUT_S_BASE  (ROOT_MAILBOX_OUTPUT_S_BASE - ROOT_MAILBOX_SIZE)
77 
78 // SL_TRUSTZONE_PERIPHERAL_AHBRADIO_S is defined in sl_trustzone_secure_config.h
79 #if ((defined(SL_TRUSTZONE_SECURE) && !defined(SL_TRUSTZONE_PERIPHERAL_AHBRADIO_S)) \
80   || (defined(SL_TRUSTZONE_PERIPHERAL_AHBRADIO_S) && SL_TRUSTZONE_PERIPHERAL_AHBRADIO_S))
81 
82 #define RDMEM_FRCRAM_MEM_BASE RDMEM_FRCRAM_S_MEM_BASE
83 
84 #define ROOT_MAILBOX_OUTPUT_BASE SYSCFG->ROOTDATA1;
85 #define ROOT_MAILBOX_OUTPUT_BASE_EXPECTED ROOT_MAILBOX_OUTPUT_S_BASE
86 #else
87 #define RDMEM_FRCRAM_MEM_BASE RDMEM_FRCRAM_NS_MEM_BASE
88 
89 // VSE will always output the secure address, if NS is desired, caculate the NS address.
90 #define ROOT_MAILBOX_OUTPUT_BASE (SYSCFG->ROOTDATA1 - RDMEM_FRCRAM_S_MEM_BASE + RDMEM_FRCRAM_NS_MEM_BASE);
91 #define ROOT_MAILBOX_OUTPUT_BASE_EXPECTED (RDMEM_FRCRAM_NS_MEM_END + 1 - ROOT_MAILBOX_SIZE)
92 #endif
93 #define ROOT_MAILBOX_INPUT_BASE  (ROOT_MAILBOX_OUTPUT_BASE_EXPECTED - ROOT_MAILBOX_SIZE)
94 
95 /* Position of parameter number field in VSE Input Mailbox LENGTH field.*/
96 #define ROOT_MB_LENGTH_PARAM_NUM_SHIFT (24)
97 
98 /* Done flag indicating that the VSE Mailbox handler has completed
99    processing the mailbox command. */
100 #define ROOT_MB_DONE  (1 << 23)
101 
102 /* VSE Configuration Status bits mask */
103 #define ROOT_MB_OUTPUT_STATUS_CONFIG_BITS_MASK  (0xFFFF)
104 
105 #endif // #if defined(CRYPTOACC_PRESENT)
106 /** @endcond */
107 
108 /*******************************************************************************
109  ******************************   TYPEDEFS   ***********************************
110  ******************************************************************************/
111 #if defined(CRYPTOACC_PRESENT)
112 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
113 // VSE Input Mailbox structure
114 typedef struct {
115   volatile uint32_t magic;
116   volatile uint32_t command;
117   volatile uint32_t length;
118   volatile uint32_t data[0];
119 } root_InputMailbox_t;
120 
121 // VSE Output Mailbox structure
122 typedef struct {
123   volatile uint32_t magic;
124   volatile uint32_t version;
125   volatile uint32_t status;
126   volatile uint32_t command;
127   volatile uint32_t length;
128   volatile uint32_t data[0];
129 } root_OutputMailbox_t;
130 /** @endcond */
131 
132 #endif // #if defined(CRYPTOACC_PRESENT)
133 
134 /*******************************************************************************
135  **************************   STATIC FUNCTIONS   *******************************
136  ******************************************************************************/
137 
138 #if defined(SEMAILBOX_PRESENT)
139 /***************************************************************************//**
140  * @brief
141  *   Write to FIFO
142  *
143  * @param value
144  *   Value to write to FIFO
145  ******************************************************************************/
146 #if defined(_SEMAILBOX_FIFO_RESETVALUE)
writeToFifo(uint32_t value)147 __STATIC_INLINE void writeToFifo(uint32_t value)
148 {
149   SEMAILBOX_HOST->FIFO = value;
150 }
151 #else
writeToFifo(uint32_t value)152 __STATIC_INLINE void writeToFifo(uint32_t value)
153 {
154   SEMAILBOX_HOST->FIFO[0].DATA = value;
155 }
156 #endif
157 
158 #endif // SEMAILBOX_PRESENT
159 
160 /*******************************************************************************
161  **************************   GLOBAL FUNCTIONS   *******************************
162  ******************************************************************************/
163 
164 /***************************************************************************//**
165  * @brief
166  *   Add input data to a command
167  *
168  * @details
169  *   This function adds a buffer of input data to the given SE command structure
170  *   The buffer gets appended by reference at the end of the list of already
171  *   added buffers.
172  *
173  * @note
174  *   Note that this function does not copy either the data buffer or the buffer
175  *   structure, so make sure to keep the data object in scope until the command
176  *   has been executed by the secure element.
177  *
178  * @param[in]  command
179  *   Pointer to an SE command structure.
180  *
181  * @param[in]  data
182  *   Pointer to a data transfer structure.
183  ******************************************************************************/
SE_addDataInput(SE_Command_t * command,SE_DataTransfer_t * data)184 void SE_addDataInput(SE_Command_t *command, SE_DataTransfer_t *data)
185 {
186   if (command->data_in == NULL) {
187     command->data_in = data;
188   } else {
189     SE_DataTransfer_t *next = command->data_in;
190     while (next->next != (void*)SE_DATATRANSFER_STOP) {
191       next = (SE_DataTransfer_t*)next->next;
192     }
193     next->next = data;
194   }
195 }
196 
197 /***************************************************************************//**
198  * @brief
199  *   Add output data to a command
200  *
201  * @details
202  *   This function adds a buffer of output data to the given command structure
203  *   The buffer gets appended by reference at the end of the list of already
204  *   added buffers.
205  *
206  * @note
207  *   Note that this function does not copy either the data buffer or the buffer
208  *   structure, so make sure to keep the data object in scope until the command
209  *   has been executed by the secure element.
210  *
211  * @param[in]  command
212  *   Pointer to an SE command structure.
213  *
214  * @param[in]  data
215  *   Pointer to a data transfer structure.
216  ******************************************************************************/
SE_addDataOutput(SE_Command_t * command,SE_DataTransfer_t * data)217 void SE_addDataOutput(SE_Command_t *command,
218                       SE_DataTransfer_t *data)
219 {
220   if (command->data_out == NULL) {
221     command->data_out = data;
222   } else {
223     SE_DataTransfer_t *next = command->data_out;
224     while (next->next != (void*)SE_DATATRANSFER_STOP) {
225       next = (SE_DataTransfer_t*)next->next;
226     }
227     next->next = data;
228   }
229 }
230 
231 /***************************************************************************//**
232  * @brief
233  *   Add a parameter to a command
234  *
235  * @details
236  *   This function adds a parameter word to the passed command.
237  *
238  * @note
239  *   Make sure to not exceed @ref SE_MAX_PARAMETERS.
240  *
241  * @param[in]  command
242  *   Pointer to a filled-out SE command structure.
243  * @param[in]  parameter
244  *   Parameter to add.
245  ******************************************************************************/
SE_addParameter(SE_Command_t * command,uint32_t parameter)246 void SE_addParameter(SE_Command_t *command, uint32_t parameter)
247 {
248   if (command->num_parameters >= SE_MAX_PARAMETERS) {
249     EFM_ASSERT(command->num_parameters < SE_MAX_PARAMETERS);
250     return;
251   }
252 
253   command->parameters[command->num_parameters] = parameter;
254   command->num_parameters += 1;
255 }
256 
257 #if !defined(SLI_EM_SE_HOST)
258 /***************************************************************************//**
259  * @brief
260  *   Execute the passed command
261  *
262  * @details
263  *   This function starts the execution of the passed command by the secure
264  *   element. When started, wait for the RXINT interrupt flag, or call
265  *   @ref SE_waitCommandCompletion to busy-wait. After completion, you have to
266  *   call @ref SE_readCommandResponse to get the command's execution status.
267  *
268  * @param[in]  command
269  *   Pointer to a filled-out SE command structure.
270  ******************************************************************************/
SE_executeCommand(SE_Command_t * command)271 void SE_executeCommand(SE_Command_t *command)
272 {
273   // Don't overflow our struct
274   if (command->num_parameters > SE_MAX_PARAMETERS) {
275     EFM_ASSERT(command->num_parameters <= SE_MAX_PARAMETERS);
276     return;
277   }
278 
279 #if defined(SEMAILBOX_PRESENT)
280 
281   // Wait for room available in the mailbox
282   while (!(SEMAILBOX_HOST->TX_STATUS & SEMAILBOX_TX_STATUS_TXINT)) {
283   }
284 
285   #if (_SILICON_LABS_32B_SERIES == 3)
286   // Write header (including message size) to start transaction
287   SEMAILBOX_HOST->TX_HEADER = sizeof(uint32_t) * (5 + command->num_parameters);
288   // Write a 32-bit word to the FIFO ( potentially used as command handle )
289   writeToFifo(0);
290   #else
291   // Write header (including message size) to start transaction
292   SEMAILBOX_HOST->TX_HEADER = sizeof(uint32_t) * (4 + command->num_parameters);
293   #endif
294 
295   // Write command into FIFO
296   writeToFifo(command->command);
297 
298   // Write DMA descriptors into FIFO
299   writeToFifo((uint32_t)command->data_in);
300   writeToFifo((uint32_t)command->data_out);
301 
302   // Write applicable parameters into FIFO
303   for (size_t i = 0; i < command->num_parameters; i++) {
304     writeToFifo(command->parameters[i]);
305   }
306 
307 #elif defined(CRYPTOACC_PRESENT)
308   // Prepare the VSE Mailbox within a critical section to prevent
309   // the process from getting interrupted. At this point, the only option
310   // we have is to go through a reset, so it is safe to enter the critical section.
311   (void)CORE_EnterCritical();
312 
313   // Setup pointer to the VSE Mailbox Input data structure
314   // (must be stored in a RAM area which is not used by the VSE)
315   root_InputMailbox_t *rootInMb = (root_InputMailbox_t*)ROOT_MAILBOX_INPUT_BASE;
316   uint32_t *mbData;
317   unsigned int mbDataLen, inDataLen, i;
318   SE_DataTransfer_t *inDataDesc;
319   uint32_t *inData;
320   uint32_t checksum;
321   bool sysCfgClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) != 0);
322   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
323 
324   // Store the secure memory base addresses for VSE to be able to read from the address
325   // Set base of Mailbox Input data structure in SYSCFG register in order
326   // for VSE to find it.
327   SYSCFG->ROOTDATA0 = ROOT_MAILBOX_INPUT_S_BASE;
328   // Set base of Mailbox Output data structure in SYSCFG register in order
329   // for VSE to know where to write output data.
330   // Write command into FIFO
331   SYSCFG->ROOTDATA1 = ROOT_MAILBOX_OUTPUT_S_BASE;
332 
333   if (!sysCfgClkWasEnabled) {
334     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
335   }
336 
337   rootInMb->magic   = SE_RESPONSE_MAILBOX_VALID;
338   rootInMb->command = command->command;
339 
340   // Write applicable parameters into Mailbox DATA array
341   mbData = (uint32_t*) rootInMb->data;
342   for (mbDataLen = 0; mbDataLen < command->num_parameters; mbDataLen++) {
343     mbData[mbDataLen] = command->parameters[mbDataLen];
344   }
345 
346   // Write input data into Mailbox DATA array
347   inDataLen = 0;
348   for (inDataDesc = command->data_in; inDataDesc; inDataDesc = (SE_DataTransfer_t*) inDataDesc->next) {
349     inData = (uint32_t*) inDataDesc->data;
350     for (i = 0; i < (inDataDesc->length & SE_DATATRANSFER_LENGTH_MASK) / sizeof(uint32_t); i++) {
351       // Make sure we do not overflow the input mailbox.
352       EFM_ASSERT(mbDataLen < ROOT_MAILBOX_SIZE);
353       mbData[mbDataLen++] = inData[i];
354       inDataLen++;
355     }
356     if (inDataDesc->next == (void*)SE_DATATRANSFER_STOP) {
357       break;
358     }
359   }
360 
361   // Write number of parameters and data words to 'length' field of mailbox.
362   rootInMb->length =
363     inDataLen | (command->num_parameters << ROOT_MB_LENGTH_PARAM_NUM_SHIFT);
364 
365   // Calculate checksum using bitwise XOR over the all words in the mailbox
366   // data structure, minus the CHECKSUM word (32bit = 4bytes ) at the end.
367   checksum = rootInMb->magic;
368   checksum ^= rootInMb->command;
369   checksum ^= rootInMb->length;
370   for (i = 0; i < mbDataLen; i++) {
371     checksum ^= mbData[i];
372   }
373 
374   // Finally, write the calculated checksum to mailbox checksum field
375   mbData[mbDataLen] = checksum;
376 
377   __NVIC_SystemReset();
378 
379 #endif // #if defined(SEMAILBOX_PRESENT)
380 }
381 
382 #endif // #if !defined(SLI_EM_SE_HOST)
383 
384 #if defined(CRYPTOACC_PRESENT)
385 /***************************************************************************//**
386  * @brief
387  *   Check whether the VSE Output Mailbox is valid.
388  *
389  * @return True if the VSE Output Mailbox is valid (magic and checksum OK)
390  ******************************************************************************/
rootIsOutputMailboxValid(void)391 bool rootIsOutputMailboxValid(void)
392 {
393   // Setup pointer to the VSE Output Mailbox data structure
394   // (must be stored in a RAM area which is not used by the VSE)
395   bool sysCfgClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) != 0);
396   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
397   root_OutputMailbox_t *rootOutMb = (root_OutputMailbox_t *) ROOT_MAILBOX_OUTPUT_BASE;
398   if ((uint32_t)rootOutMb > ROOT_MAILBOX_OUTPUT_BASE_EXPECTED
399       || (uint32_t)rootOutMb < RDMEM_FRCRAM_MEM_BASE) {
400     return false;
401   }
402 
403   if (!sysCfgClkWasEnabled) {
404     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
405   }
406 
407   uint32_t *mbPtr = (uint32_t*) rootOutMb;
408   uint32_t checksum;
409   unsigned int mbLen, cnt;
410 
411   // Verify magic word of mailbox
412   if (rootOutMb->magic != SE_RESPONSE_MAILBOX_VALID) {
413     return false;
414   }
415 
416   // Get length of mailbox
417   mbLen = sizeof(root_OutputMailbox_t) / sizeof(uint32_t) + rootOutMb->length;
418   if (mbLen >= ROOT_MAILBOX_SIZE) {
419     return false;
420   }
421   // Calculate checksum using bitwise XOR over all words in the mailbox
422   // data structure, minus the CHECKSUM word at the end.
423   for (checksum = 0, cnt = 0; cnt < mbLen; cnt++) {
424     checksum ^= mbPtr[cnt];
425   }
426 
427   // Verify that the calculated checksum is equal to the mailbox checksum.
428   return (mbPtr[mbLen] == checksum);
429 }
430 
431 /***************************************************************************//**
432  * @brief
433  *   Get current SE version
434  *
435  * @details
436  *   This function returns the current VSE version
437  *
438  * @param[in]  version
439  *   Pointer to location where to copy the version of VSE to.
440  *
441  * @return
442  *   One of the SE_RESPONSE return codes:
443  *   SE_RESPONSE_OK when the command was executed successfully
444  *   SE_RESPONSE_INVALID_PARAMETER when an invalid parameter was passed
445  *   SE_RESPONSE_MAILBOX_INVALID when the mailbox content is invalid
446  ******************************************************************************/
SE_getVersion(uint32_t * version)447 SE_Response_t SE_getVersion(uint32_t *version)
448 {
449   bool sysCfgClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) != 0);
450   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
451   root_OutputMailbox_t *rootOutMb = (root_OutputMailbox_t *) ROOT_MAILBOX_OUTPUT_BASE;
452   if (!sysCfgClkWasEnabled) {
453     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
454   }
455 
456   if (version == NULL) {
457     return SE_RESPONSE_INVALID_PARAMETER;
458   }
459 
460   // First verify that the response is ok.
461   if (!rootIsOutputMailboxValid()) {
462     return SE_RESPONSE_MAILBOX_INVALID;
463   }
464 
465   // Return the 'version' from the Output Mailbox
466   *version = rootOutMb->version;
467 
468   return SE_RESPONSE_OK;
469 }
470 
471 /***************************************************************************//**
472  * @brief
473  *   Get VSE configuration and status bits
474  *
475  * @details
476  *   This function returns the current VSE configuration and status bits.
477  *   The following list explains what the different bits in cfgStatus indicate.
478  *   A bit value of 1 means enabled, while 0 means disabled:
479  *    * [0]: Secure boot
480  *    * [1]: Verify secure boot certificate
481  *    * [2]: Anti-rollback
482  *    * [3]: Narrow page lock
483  *    * [4]: Full page lock
484  *   The following status bits can be read with VSE versions
485  *   higher than 1.2.2.
486  *    * [10]: Debug port lock
487  *    * [11]: Device erase enabled
488  *    * [12]: Secure debug enabled
489  *    * [15]: Debug port register state, 1 if the debug port is locked.
490  *
491  * @param[out]  cfgStatus
492  *   Pointer to location to copy Configuration Status bits into.
493  *
494  * @note
495  *   This function will check that the mailbox content is valid before
496  *   reading the status bits. If the command response has already been read
497  *   with a call to @ref SE_ackCommand(), the validity check will fail, and
498  *   the config status bits cannot be read before a reset has occurred.
499  *
500  * @return
501  *   One of the SE_RESPONSE return codes:
502  *   SE_RESPONSE_OK when the command was executed successfully
503  *   SE_RESPONSE_INVALID_PARAMETER when an invalid parameter was passed
504  *   SE_RESPONSE_MAILBOX_INVALID when the mailbox content is invalid
505  ******************************************************************************/
SE_getConfigStatusBits(uint32_t * cfgStatus)506 SE_Response_t SE_getConfigStatusBits(uint32_t *cfgStatus)
507 {
508   bool sysCfgClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) != 0);
509   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
510   root_OutputMailbox_t *rootOutMb = (root_OutputMailbox_t *) ROOT_MAILBOX_OUTPUT_BASE;
511   if (!sysCfgClkWasEnabled) {
512     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
513   }
514 
515   if (cfgStatus == NULL) {
516     return SE_RESPONSE_INVALID_PARAMETER;
517   }
518 
519   // First verify that the response is ok.
520   if (!rootIsOutputMailboxValid()) {
521     return SE_RESPONSE_MAILBOX_INVALID;
522   }
523 
524   // Return the configuration status bits
525   *cfgStatus = rootOutMb->status & ROOT_MB_OUTPUT_STATUS_CONFIG_BITS_MASK;
526 
527   return SE_RESPONSE_OK;
528 }
529 
530 /***************************************************************************//**
531  * @brief
532  *  Get the version number of the OTP from the status field of the output
533  *  mailbox
534  * @details
535  *  This function checks if the OTP version number flag is set in the output
536  *  mailbox. If it is, the version number is writen to @ref otpVersion pointer
537  *  location. If not, it returns error response.
538  *
539  * @param[out] otpVersion
540  *  Pointer to location to copy OTP version number into.
541  * @return
542  *  One of the SE_RESPONSE return codes.
543  * @retval SE_RESPONSE_OK when the command was executed successfully
544  ******************************************************************************/
SE_getOTPVersion(uint32_t * otpVersion)545 SE_Response_t SE_getOTPVersion(uint32_t *otpVersion)
546 {
547   bool sysCfgClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) != 0);
548   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
549   root_OutputMailbox_t *rootOutMb = (root_OutputMailbox_t *) ROOT_MAILBOX_OUTPUT_BASE;
550   if (!sysCfgClkWasEnabled) {
551     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
552   }
553 
554   if (otpVersion == NULL) {
555     return SE_RESPONSE_INVALID_PARAMETER;
556   }
557 
558   // First verify that the response is ok.
559   if (!rootIsOutputMailboxValid()) {
560     return SE_RESPONSE_MAILBOX_INVALID;
561   }
562 
563   bool isOTPVersionSet = rootOutMb->status & SE_VSE_REPLY_STATUS_OTP_VERSION_SET;
564   if (isOTPVersionSet) {
565     // Return the OTP version from the status field.
566     *otpVersion = (rootOutMb->status & SE_VSE_REPLY_STATUS_OTP_VERSION_MASK) >> SE_VSE_REPLY_STATUS_OTP_VERSION_SHIFT;
567   } else {
568     return SE_RESPONSE_INVALID_COMMAND;
569   }
570 
571   return SE_RESPONSE_OK;
572 }
573 
574 /***************************************************************************//**
575  * @brief
576  *   Check whether the running command has completed.
577  *
578  * @details
579  *   This function polls the SE-to-host mailbox interrupt flag.
580  *
581  * @return True if a command has completed and the result is available
582  ******************************************************************************/
SE_isCommandCompleted(void)583 bool SE_isCommandCompleted(void)
584 {
585   bool sysCfgClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) != 0);
586   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
587   root_OutputMailbox_t *rootOutMb = (root_OutputMailbox_t *) ROOT_MAILBOX_OUTPUT_BASE;
588   if (!sysCfgClkWasEnabled) {
589     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
590   }
591 
592   // First verify that the response is ok
593   if (!rootIsOutputMailboxValid()) {
594     return false;
595   }
596 
597   // Check status MB_DONE flag of the mailbox
598   return ((rootOutMb->status & ROOT_MB_DONE) == ROOT_MB_DONE);
599 }
600 
601 /***************************************************************************//**
602  * @brief
603  *   Read the previously executed command.
604  *
605  * @details
606  *   This function reads the previously executed command.
607  *
608  * @return
609  *   One of the SE command words.
610  *   SE_RESPONSE_MAILBOX_INVALID when the mailbox content is invalid.
611  ******************************************************************************/
SE_readExecutedCommand(void)612 uint32_t SE_readExecutedCommand(void)
613 {
614   bool sysCfgClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) != 0);
615   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
616   root_OutputMailbox_t *rootOutMb = (root_OutputMailbox_t *) ROOT_MAILBOX_OUTPUT_BASE;
617   if (!sysCfgClkWasEnabled) {
618     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
619   }
620 
621   // First verify that the Output Mailbox includes a valid response.
622   if (!SE_isCommandCompleted()) {
623     return SE_RESPONSE_MAILBOX_INVALID;
624   }
625 
626   return rootOutMb->command;
627 }
628 
629 /***************************************************************************//**
630  * @brief
631  *   Read the status of the previously executed command.
632  *
633  * @details
634  *   This function reads the status of the previously executed command.
635  *
636  * @return
637  *   One of the SE_RESPONSE return codes:
638  *   SE_RESPONSE_OK when the command was executed successfully or a signature
639  *   was successfully verified,
640  *   SE_RESPONSE_INVALID_COMMAND when the command ID was not recognized,
641  *   SE_RESPONSE_AUTHORIZATION_ERROR when the command is not authorized,
642  *   SE_RESPONSE_INVALID_SIGNATURE when signature verification failed,
643  *   SE_RESPONSE_BUS_ERROR when a bus error was thrown during the command, e.g.
644  *   because of conflicting Secure/Non-Secure memory accesses,
645  *   SE_RESPONSE_CRYPTO_ERROR on an internal SE failure, or
646  *   SE_RESPONSE_INVALID_PARAMETER when an invalid parameter was passed
647  *   SE_RESPONSE_MAILBOX_INVALID when the mailbox content is invalid
648  ******************************************************************************/
SE_readCommandResponse(void)649 SE_Response_t SE_readCommandResponse(void)
650 {
651   bool sysCfgClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) != 0);
652   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
653   root_OutputMailbox_t *rootOutMb = (root_OutputMailbox_t *) ROOT_MAILBOX_OUTPUT_BASE;
654   if (!sysCfgClkWasEnabled) {
655     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
656   }
657 
658   // First verify that the Output Mailbox includes a valid response.
659   if (!SE_isCommandCompleted()) {
660     return SE_RESPONSE_MAILBOX_INVALID;
661   }
662 
663   return (SE_Response_t)(rootOutMb->status & SE_RESPONSE_MASK);
664 }
665 
666 /***************************************************************************//**
667  * @brief
668  *   Acknowledge and get status and output data of a completed command.
669  *
670  * @details
671  *   This function acknowledges and gets the status and output data of a
672  *   completed mailbox command.
673  *   The mailbox command is acknowledged by inverting all bits in the checksum
674  *   (XOR with 0xFFFFFFFF).
675  *   The output data is copied into the linked list of output buffers pointed
676  *   to in the given command data structure.
677  *
678  * @param[in]  command
679  *   Pointer to an SE command structure.
680  *
681  * @return
682  *   One of the SE_RESPONSE return codes.
683  * @retval SE_RESPONSE_OK when the command was executed successfully or a
684  *                        signature was successfully verified,
685  * @retval SE_RESPONSE_INVALID_COMMAND when the command ID was not recognized,
686  * @retval SE_RESPONSE_AUTHORIZATION_ERROR when the command is not authorized,
687  * @retval SE_RESPONSE_INVALID_SIGNATURE when signature verification failed,
688  * @retval SE_RESPONSE_BUS_ERROR when a bus error was thrown during the command,
689  *                               e.g. because of conflicting Secure/Non-Secure
690  *                               memory accesses,
691  * @retval SE_RESPONSE_CRYPTO_ERROR on an internal SE failure, or
692  * @retval SE_RESPONSE_INVALID_PARAMETER when an invalid parameter was passed
693  * @retval SE_RESPONSE_MAILBOX_INVALID when mailbox command not done or invalid
694  ******************************************************************************/
SE_ackCommand(SE_Command_t * command)695 SE_Response_t SE_ackCommand(SE_Command_t *command)
696 {
697   // Setup pointer to the VSE Output Mailbox data structure
698   // (must be stored in a RAM area which is not used by the VSE)
699   bool sysCfgClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) != 0);
700   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
701   root_OutputMailbox_t *rootOutMb = (root_OutputMailbox_t *) ROOT_MAILBOX_OUTPUT_BASE;
702   if (!sysCfgClkWasEnabled) {
703     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
704   }
705   uint32_t *mbData = (uint32_t*) rootOutMb->data;
706   SE_DataTransfer_t *outDataDesc = command->data_out;
707   unsigned int outDataLen, outDataCnt, i, outDescLen;
708   uint32_t *outData;
709 
710   // First verify that the Output Mailbox includes a valid response.
711   if (!SE_isCommandCompleted()) {
712     return SE_RESPONSE_MAILBOX_INVALID;
713   }
714 
715   // Get output data length
716   outDataLen = rootOutMb->length;
717 
718   // Acknowledge the output mailbox response by invalidating checksum
719   mbData[outDataLen] ^= 0xFFFFFFFFUL;
720 
721   // Check command status code
722   if ((rootOutMb->status & SE_RESPONSE_MASK) != SE_RESPONSE_OK) {
723     return rootOutMb->status & SE_RESPONSE_MASK;
724   }
725 
726   // Copy data from the Output Mailbox to the linked list of output
727   // buffers provided by the user
728   outDataCnt = 0;
729   while (outDataDesc && (outDataCnt < outDataLen)) {
730     outData = (uint32_t*) outDataDesc->data;
731     outDescLen =
732       (outDataDesc->length & SE_DATATRANSFER_LENGTH_MASK) / sizeof(uint32_t);
733     for (i = 0; (i < outDescLen) && (outDataCnt < outDataLen); i++) {
734       outData[i] = mbData[outDataCnt++];
735     }
736     // If we have reached the end of a buffer, go to next buffer descriptor
737     if (i == outDescLen) {
738       outDataDesc = (SE_DataTransfer_t*)
739                     ((uint32_t)outDataDesc->next & ~SE_DATATRANSFER_STOP);
740     }
741   }
742 
743   // Check if the output data list is too small to copy all output data in
744   // mailbox.
745   if ((outDataDesc == 0) && (outDataCnt < outDataLen)) {
746     return SE_RESPONSE_INVALID_PARAMETER;
747   }
748 
749   return SE_RESPONSE_OK;
750 }
751 
752 #endif // #if defined(CRYPTOACC_PRESENT)
753 
754 /*******************************************************************************
755  *****************************   DEPRECATED    *********************************
756  ******************************************************************************/
757 
758 /***************************************************************************//**
759  * @addtogroup se_deprecated
760  *
761  * @{
762  ******************************************************************************/
763 
764 /*******************************************************************************
765 *  The following functions have been deprecated and will be removed in a future
766 *  version of emlib. All high-level functionality have been moved to the SE
767 *  manager.
768 *******************************************************************************/
769 
770 #if !defined(SLI_EM_SE_HOST)
771 #if defined(SEMAILBOX_PRESENT)
772 
773 /***************************************************************************//**
774  * @brief
775  * @deprecated
776  *   This function has been moved to the SE manager, and will be removed in a
777  *   future version of emlib.
778  *
779  *   Read pubkey or pubkey signature.
780  *
781  * @details
782  *   Read out a public key stored in the SE, or its signature. The command can
783  *   be used to read:
784  *   * SE_KEY_TYPE_BOOT
785  *   * SE_KEY_TYPE_AUTH
786  *
787  * @param[in] key_type
788  *   ID of key type to read.
789  *
790  * @param[out] pubkey
791  *   Pointer to a buffer to contain the returned public key.
792  *   Must be word aligned and have a length of 64 bytes.
793  *
794  * @param[in] numBytes
795  *   Length of pubkey buffer (64 bytes).
796  *
797  * @param[in] signature
798  *   If true, the function will return the signature programmed for the
799  *   specified public key instead of the public key itself.
800  *
801  * @return
802  *   One of the SE_RESPONSE return codes.
803  * @retval SE_RESPONSE_OK when the command was executed successfully
804  * @retval SE_RESPONSE_TEST_FAILED when the pubkey is not set
805  * @retval SE_RESPONSE_INVALID_PARAMETER when an invalid type is passed
806  ******************************************************************************/
SE_readPubkey(uint32_t key_type,void * pubkey,uint32_t numBytes,bool signature)807 SE_Response_t SE_readPubkey(uint32_t key_type, void *pubkey, uint32_t numBytes, bool signature)
808 {
809   EFM_ASSERT((key_type == SE_KEY_TYPE_BOOT)
810              || (key_type == SE_KEY_TYPE_AUTH));
811 
812   EFM_ASSERT(numBytes == 64);
813   EFM_ASSERT(!((size_t)pubkey & 3U));
814 
815   // SE command structures
816   uint32_t commandWord =
817     (signature) ? SE_COMMAND_READ_PUBKEY_SIGNATURE : SE_COMMAND_READ_PUBKEY;
818   SE_Command_t command = SE_COMMAND_DEFAULT(commandWord | key_type);
819 
820   SE_DataTransfer_t pubkeyData = SE_DATATRANSFER_DEFAULT(pubkey, numBytes);
821   SE_addDataOutput(&command, &pubkeyData);
822 
823   SE_executeCommand(&command);
824   SE_Response_t res = SE_readCommandResponse();
825   return res;
826 }
827 
828 #endif // #if defined(SEMAILBOX_PRESENT)
829 #endif // #if !defined(SLI_EM_SE_HOST)
830 
831 /** @} (end addtogroup deprecated_se) */
832 /** @} (end addtogroup se) */
833 
834 #endif /* defined(SEMAILBOX_PRESENT) || defined(CRYPTOACC_PRESENT) */
835