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