1 /*
2 * Copyright 2024 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "fsl_s3mu.h"
9 #include "fsl_ele_base_api.h"
10
11 /*******************************************************************************
12 * Prototypes
13 ******************************************************************************/
14
15 /*******************************************************************************
16 * Definitions
17 ******************************************************************************/
18
19 /*******************************************************************************
20 * Definitions
21 ******************************************************************************/
22
23 /*******************************************************************************
24 * Code
25 ******************************************************************************/
nvm_storage_handle_req_baseapi(S3MU_Type * mu,uint32_t * buf,uint32_t wordCount)26 static status_t nvm_storage_handle_req_baseapi(S3MU_Type *mu, uint32_t *buf, uint32_t wordCount)
27 {
28 return kStatus_Fail;
29 }
30
31 /*!
32 * brief Get response from MU
33 *
34 * This function reads response data from EdgeLock Enclave if available.
35 *
36 * param mu MU peripheral base address
37 * param buf buffer to store read data
38 * param wordCount size of data in words
39 *
40 * return Status kStatus_Success if success, kStatus_Fail if fail
41 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
42 */
ele_mu_get_response_baseapi(S3MU_Type * mu,uint32_t * buf)43 static status_t ele_mu_get_response_baseapi(S3MU_Type *mu, uint32_t *buf)
44 {
45 status_t status = kStatus_Fail;
46 uint32_t rmsg[MSG_RESPONSE_MAX] = {0u};
47 mu_hdr_t *msg = (mu_hdr_t *)rmsg;
48
49 do
50 {
51 status = S3MU_GetResponse(mu, rmsg);
52 if (status != kStatus_Success)
53 {
54 break;
55 }
56
57 if (msg->hdr_byte.tag == MSG_TAG_RESP)
58 {
59 (void)memcpy((void *)buf, (void *)msg, (uint32_t)(msg->hdr_byte.size * sizeof(uint32_t)));
60 break;
61 }
62 else if (msg->hdr_byte.tag == MSG_TAG_CMD)
63 {
64 status = nvm_storage_handle_req_baseapi(mu, rmsg, msg->hdr_byte.size);
65 if (status != kStatus_Success)
66 {
67 break;
68 }
69 }
70 else
71 {
72 return kStatus_Fail;
73 }
74 } while (msg->hdr_byte.tag != MSG_TAG_RESP);
75
76 return status;
77 }
78
79 /*!
80 * brief Ping ELE
81 *
82 * This function Ping EdgeLock Enclave, can be sent at any time to verify ELE is alive.
83 * Additionally, this command reloads the fuse shadow registers and kick the Sentinel active bit.
84 * This active bit must be kicked at least once every day (24 hours).
85 *
86 * param mu MU peripheral base address
87 *
88 * return Status kStatus_Success if success, kStatus_Fail if fail
89 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
90 */
ELE_BaseAPI_Ping(S3MU_Type * mu)91 status_t ELE_BaseAPI_Ping(S3MU_Type *mu)
92 {
93 status_t status = kStatus_Fail;
94 uint32_t tmsg[PING_SIZE] = {0u};
95 uint32_t rmsg[S3MU_RR_COUNT] = {0u};
96
97 /****************** PING ELE message ***********************/
98 tmsg[0] = PING; // PING Command Header
99 /* Send message Security Sub-System */
100 status = S3MU_SendMessage(mu, tmsg, PING_SIZE);
101 if (status != kStatus_Success)
102 {
103 return status;
104 }
105
106 /* Wait for response from Security Sub-System */
107 status = ele_mu_get_response_baseapi(mu, rmsg);
108 if (status != kStatus_Success)
109 {
110 return status;
111 }
112
113 /* Check that response corresponds to the sent command */
114 if (rmsg[0] == PING_RESPONSE_HDR && rmsg[1] == RESPONSE_SUCCESS)
115 {
116 return kStatus_Success;
117 }
118 else
119 {
120 return kStatus_Fail;
121 }
122 }
123
124 /*!
125 * brief Get ELE FW Version
126 *
127 * This function is used to retrieve the Sentinel FW version.
128 *
129 * param mu MU peripheral base address
130 * param EleFwVersion Pointer where ElE firmware version will be stored
131 *
132 * return Status kStatus_Success if success, kStatus_Fail if fail
133 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
134 */
ELE_BaseAPI_GetFwVersion(S3MU_Type * mu,uint32_t * EleFwVersion)135 status_t ELE_BaseAPI_GetFwVersion(S3MU_Type *mu, uint32_t *EleFwVersion)
136 {
137 status_t status = kStatus_Fail;
138 uint32_t tmsg[GET_FW_VERSION_SIZE] = {0u};
139 uint32_t rmsg[S3MU_RR_COUNT] = {0u};
140
141 /****************** Get firmware version ELE message ***********************/
142 tmsg[0] = GET_FW_VERSION; // Get firmware version Command Header
143 /* Send message Security Sub-System */
144 status = S3MU_SendMessage(mu, tmsg, GET_FW_VERSION_SIZE);
145 if (status != kStatus_Success)
146 {
147 return status;
148 }
149
150 /* Wait for response from Security Sub-System */
151 status = ele_mu_get_response_baseapi(mu, rmsg);
152 if (status != kStatus_Success)
153 {
154 return status;
155 }
156
157 /* Check that response corresponds to the sent command */
158 if (rmsg[0] == GET_FW_VERSION_RESPONSE_HDR && rmsg[1] == RESPONSE_SUCCESS)
159 {
160 /* read FW version */
161 *EleFwVersion = rmsg[2];
162 return kStatus_Success;
163 }
164 else
165 {
166 return kStatus_Fail;
167 }
168 }
169
170 /*!
171 * brief Enable APC (Application core)
172 *
173 * This function is used by RTC (real time core) to release APC (Application core) when needed.
174 *
175 * param mu MU peripheral base address
176 *
177 * return Status kStatus_Success if success, kStatus_Fail if fail
178 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
179 */
ELE_BaseAPI_EnableAPC(S3MU_Type * mu)180 status_t ELE_BaseAPI_EnableAPC(S3MU_Type *mu)
181 {
182 status_t status = kStatus_Fail;
183 uint32_t tmsg[ENABLE_APC_SIZE] = {0u};
184 uint32_t rmsg[S3MU_RR_COUNT] = {0u};
185
186 /****************** Enable APC ELE message ***********************/
187 tmsg[0] = ENABLE_APC; // Enable APC Command Header
188 /* Send message Security Sub-System */
189 status = S3MU_SendMessage(mu, tmsg, ENABLE_APC_SIZE);
190 if (status != kStatus_Success)
191 {
192 return status;
193 }
194
195 /* Wait for response from Security Sub-System */
196 status = ele_mu_get_response_baseapi(mu, rmsg);
197 if (status != kStatus_Success)
198 {
199 return status;
200 }
201
202 /* Check that response corresponds to the sent command */
203 if (rmsg[0] == ENABLE_APC_RESPONSE_HDR && rmsg[1] == RESPONSE_SUCCESS)
204 {
205 return kStatus_Success;
206 }
207 else
208 {
209 return kStatus_Fail;
210 }
211 }
212
213 /*!
214 * brief Forward Lifecycle update
215 *
216 * This function is to change chip lifecycle
217 * 0x01U for NXP provisoned
218 * 0x02U for OEM Open
219 * 0x08U for OEM Closed
220 * 0x80U for OEM Locked
221 *
222 * param mu MU peripheral base address
223 * param Lifecycle to switch
224 *
225 * return Status kStatus_Success if success, kStatus_Fail if fail
226 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
227 */
ELE_BaseAPI_ForwardLifecycle(S3MU_Type * mu,uint32_t Lifecycle)228 status_t ELE_BaseAPI_ForwardLifecycle(S3MU_Type *mu, uint32_t Lifecycle)
229 {
230 status_t status = kStatus_Fail;
231 uint32_t tmsg[FORWARD_LIFECYCLE_SIZE] = {0u};
232 uint32_t rmsg[S3MU_RR_COUNT] = {0u};
233
234 /****************** Forward lifecycle ELE message ***********************/
235 tmsg[0] = FORWARD_LIFECYCLE; // Forward lifecycle Command Header
236 tmsg[1] = Lifecycle; // Lifecycle to switch to
237 /* Send message Security Sub-System */
238 status = S3MU_SendMessage(mu, tmsg, FORWARD_LIFECYCLE_SIZE);
239 if (status != kStatus_Success)
240 {
241 return status;
242 }
243
244 /* Wait for response from Security Sub-System */
245 status = ele_mu_get_response_baseapi(mu, rmsg);
246 if (status != kStatus_Success)
247 {
248 return status;
249 }
250
251 /* Check that response corresponds to the sent command */
252 if (rmsg[0] == FORWARD_LIFECYCLE_RESPONSE_HDR && rmsg[1] == RESPONSE_SUCCESS)
253 {
254 return kStatus_Success;
255 }
256 else
257 {
258 return kStatus_Fail;
259 }
260 }
261
262 /*!
263 * brief Start the clock change process
264 *
265 * param mu MU peripheral base address
266 *
267 * return Status kStatus_Success if success, kStatus_Fail if fail
268 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
269 */
ELE_BaseAPI_ClockChangeStart(S3MU_Type * mu)270 status_t ELE_BaseAPI_ClockChangeStart(S3MU_Type *mu)
271 {
272 status_t status = kStatus_Fail;
273 uint32_t tmsg[CLOCK_CHANGE_START_SIZE] = {0u};
274 uint32_t rmsg[S3MU_RR_COUNT] = {0u};
275
276 /****************** Clock change start message ***********************/
277 tmsg[0] = CLOCK_CHANGE_START; // Clock Change Start Command Header
278
279 /* Send message Security Sub-System */
280 status = S3MU_SendMessage(mu, tmsg, CLOCK_CHANGE_START_SIZE);
281 if (status != kStatus_Success)
282 {
283 return status;
284 }
285
286 /* Wait for response from Security Sub-System */
287 status = ele_mu_get_response_baseapi(mu, rmsg);
288 if (status != kStatus_Success)
289 {
290 return status;
291 }
292
293 /* Check that response corresponds to the sent command */
294 if (rmsg[0] == CLOCK_CHANGE_START_RESPONSE_HDR && rmsg[1] == RESPONSE_SUCCESS)
295 {
296 return kStatus_Success;
297 }
298 else
299 {
300 return kStatus_Fail;
301 }
302 }
303
304 /*!
305 * brief Change ELE and/or CM33 clock
306 *
307 * It is valid to pass both parameters at the same time if the SoC supports both.
308 *
309 * param mu MU peripheral base address
310 * param NewClockRateELE the new clock rate for ELE
311 * param NewClockRateCM33 the new clock rate for the CM33 core
312 *
313 * return Status kStatus_Success if success, kStatus_Fail if fail
314 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
315 */
ELE_BaseAPI_ClockChangeFinish(S3MU_Type * mu,uint8_t NewClockRateELE,uint8_t NewClockRateCM33)316 status_t ELE_BaseAPI_ClockChangeFinish(S3MU_Type *mu, uint8_t NewClockRateELE, uint8_t NewClockRateCM33)
317 {
318 status_t status = kStatus_Fail;
319 uint32_t tmsg[CLOCK_CHANGE_FINISH_SIZE] = {0u};
320 uint32_t rmsg[S3MU_RR_COUNT] = {0u};
321
322 /****************** Clock change finish message ***********************/
323 tmsg[0] = CLOCK_CHANGE_FINISH; // Clock Change Finish Command Header
324 tmsg[1] = (uint32_t)NewClockRateCM33 << SHIFT_16 | (uint32_t)NewClockRateELE; // New CM33 and ELE clock rates
325
326 /* Send message Security Sub-System */
327 status = S3MU_SendMessage(mu, tmsg, CLOCK_CHANGE_FINISH_SIZE);
328 if (status != kStatus_Success)
329 {
330 return status;
331 }
332
333 /* Wait for response from Security Sub-System */
334 status = ele_mu_get_response_baseapi(mu, rmsg);
335 if (status != kStatus_Success)
336 {
337 return status;
338 }
339
340 /* Check that response corresponds to the sent command */
341 if (rmsg[0] == CLOCK_CHANGE_FINISH_RESPONSE_HDR && rmsg[1] == RESPONSE_SUCCESS)
342 {
343 return kStatus_Success;
344 }
345 else
346 {
347 return kStatus_Fail;
348 }
349 }
350
351 /*!
352 * brief Start the voltage change process
353 *
354 * param mu MU peripheral base address
355 *
356 * return Status kStatus_Success if success, kStatus_Fail if fail
357 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
358 */
ELE_BaseAPI_VoltageChangeStart(S3MU_Type * mu)359 status_t ELE_BaseAPI_VoltageChangeStart(S3MU_Type *mu)
360 {
361 status_t status = kStatus_Fail;
362 uint32_t tmsg[VOLTAGE_CHANGE_START_SIZE] = {0u};
363 uint32_t rmsg[S3MU_RR_COUNT] = {0u};
364
365 /****************** Voltage change start message ***********************/
366 tmsg[0] = VOLTAGE_CHANGE_START; // Voltage Change Start Command Header
367
368 /* Send message Security Sub-System */
369 status = S3MU_SendMessage(mu, tmsg, VOLTAGE_CHANGE_START_SIZE);
370 if (status != kStatus_Success)
371 {
372 return status;
373 }
374
375 /* Wait for response from Security Sub-System */
376 status = ele_mu_get_response_baseapi(mu, rmsg);
377 if (status != kStatus_Success)
378 {
379 return status;
380 }
381
382 /* Check that response corresponds to the sent command */
383 if ((rmsg[0] == VOLTAGE_CHANGE_START_RESPONSE_HDR) && (rmsg[1] == RESPONSE_SUCCESS))
384 {
385 return kStatus_Success;
386 }
387 else
388 {
389 return kStatus_Fail;
390 }
391 }
392
393 /*!
394 * brief Finish the voltage change process
395 *
396 * param mu MU peripheral base address
397 *
398 * return Status kStatus_Success if success, kStatus_Fail if fail
399 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
400 */
ELE_BaseAPI_VoltageChangeFinish(S3MU_Type * mu)401 status_t ELE_BaseAPI_VoltageChangeFinish(S3MU_Type *mu)
402 {
403 status_t status = kStatus_Fail;
404 uint32_t tmsg[VOLTAGE_CHANGE_FINISH_SIZE] = {0u};
405 uint32_t rmsg[S3MU_RR_COUNT] = {0u};
406
407 /****************** Voltage change finish message ***********************/
408 tmsg[0] = VOLTAGE_CHANGE_FINISH; // Voltage Change finish Command Header
409
410 /* Send message Security Sub-System */
411 status = S3MU_SendMessage(mu, tmsg, VOLTAGE_CHANGE_FINISH_SIZE);
412 if (status != kStatus_Success)
413 {
414 return status;
415 }
416
417 /* Wait for response from Security Sub-System */
418 status = ele_mu_get_response_baseapi(mu, rmsg);
419 if (status != kStatus_Success)
420 {
421 return status;
422 }
423
424 /* Check that response corresponds to the sent command */
425 if ((rmsg[0] == VOLTAGE_CHANGE_FINISH_RESPONSE_HDR) && (rmsg[1] == RESPONSE_SUCCESS))
426 {
427 return kStatus_Success;
428 }
429 else
430 {
431 return kStatus_Fail;
432 }
433 }
434
435 /*!
436 * brief Get ELE FW Status
437 *
438 * This function is used to retrieve the Sentinel FW status.
439 * If value in EleFwStatus is 0 there is no loaded ELE FW, if 1 ELE FW is authenticated and operational.
440 *
441 * param mu MU peripheral base address
442 * param EleFwStatus Pointer where ElE firmware status will be stored
443 *
444 * return Status kStatus_Success if success, kStatus_Fail if fail
445 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
446 */
ELE_BaseAPI_GetFwStatus(S3MU_Type * mu,uint32_t * EleFwStatus)447 status_t ELE_BaseAPI_GetFwStatus(S3MU_Type *mu, uint32_t *EleFwStatus)
448 {
449 status_t status = kStatus_Fail;
450 uint32_t tmsg[GET_FW_STATUS_SIZE] = {0u};
451 uint32_t rmsg[S3MU_RR_COUNT] = {0u};
452
453 /****************** Get firmware status ELE message ***********************/
454 tmsg[0] = GET_FW_STATUS; // Get firmware status Command Header
455 /* Send message Security Sub-System */
456 status = S3MU_SendMessage(mu, tmsg, GET_FW_STATUS_SIZE);
457 if (status != kStatus_Success)
458 {
459 return status;
460 }
461
462 /* Wait for response from Security Sub-System */
463 status = ele_mu_get_response_baseapi(mu, rmsg);
464 if (status != kStatus_Success)
465 {
466 return status;
467 }
468
469 /* Check that response corresponds to the sent command */
470 if (rmsg[0] == GET_FW_STATUS_RESPONSE_HDR && rmsg[1] == RESPONSE_SUCCESS)
471 {
472 /* read FW status */
473 *EleFwStatus = rmsg[2];
474 return kStatus_Success;
475 }
476 else
477 {
478 return kStatus_Fail;
479 }
480 }
481
482 /*!
483 * brief Enable an instance of OTFAD.
484 *
485 * param mu MU peripheral base address
486 * param OtfadID ID of the OTFAD instance to enable - used only if there are
487 * multiple instances on the SoC
488 *
489 * return Status kStatus_Success if success, kStatus_Fail if fail
490 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
491 */
ELE_BaseAPI_EnableOtfad(S3MU_Type * mu,uint8_t OtfadID)492 status_t ELE_BaseAPI_EnableOtfad(S3MU_Type *mu, uint8_t OtfadID)
493 {
494 status_t status = kStatus_Fail;
495 uint32_t tmsg[ENABLE_OTFAD_SIZE] = {0u};
496 uint32_t rmsg[S3MU_RR_COUNT] = {0u};
497
498 /****************** Enable OTFAD message ***********************/
499 tmsg[0] = ENABLE_OTFAD; // Enable OTFAD message Command Header
500 #if defined(FSL_FEATURE_SOC_OTFAD_COUNT) && (FSL_FEATURE_SOC_OTFAD_COUNT > 1)
501 tmsg[1] = (uint32_t)OtfadID; // ID of the OTFAD instance
502 #else
503 (void)OtfadID; /* Prevent an unused variable warning */
504 #endif
505
506 /* Send message Security Sub-System */
507 status = S3MU_SendMessage(mu, tmsg, ENABLE_OTFAD_SIZE);
508 if (status != kStatus_Success)
509 {
510 return status;
511 }
512
513 /* Wait for response from Security Sub-System */
514 status = ele_mu_get_response_baseapi(mu, rmsg);
515 if (status != kStatus_Success)
516 {
517 return status;
518 }
519
520 /* Check that response corresponds to the sent command */
521 if (rmsg[0] == ENABLE_OTFAD_RESPONSE_HDR && rmsg[1] == RESPONSE_SUCCESS)
522 {
523 return kStatus_Success;
524 }
525 else
526 {
527 return kStatus_Fail;
528 }
529 }
530 /*!
531 * brief Release RDC
532 *
533 * This function is used to release specifed RDC to the core identified in this function.
534 * The RDC will be released only if the FW of the core to which is the RDC ownership is going to be
535 * transferred has been properly authenticated and verified.
536 *
537 * param mu MU peripheral base address
538 * param RdcID Resource Domain Control identifier
539 * param CoreID Core identifier
540 *
541 * return Status kStatus_Success if success, kStatus_Fail if fail
542 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
543 */
ELE_BaseAPI_ReleaseRDC(S3MU_Type * mu,uint32_t RdcID,uint32_t CoreID)544 status_t ELE_BaseAPI_ReleaseRDC(S3MU_Type *mu, uint32_t RdcID, uint32_t CoreID)
545 {
546 status_t status = kStatus_Fail;
547 uint32_t tmsg[RELEASE_RDC_SIZE] = {0u};
548 uint32_t rmsg[S3MU_RR_COUNT] = {0u};
549
550 /****************** Release RDC ELE message ***********************/
551 tmsg[0] = RELEASE_RDC; // Release RDC Command Header
552 tmsg[1] = RdcID << SHIFT_8 | CoreID; // RDC_ID | CoreID
553 /* Send message Security Sub-System */
554 status = S3MU_SendMessage(mu, tmsg, RELEASE_RDC_SIZE);
555 if (status != kStatus_Success)
556 {
557 return status;
558 }
559
560 /* Wait for response from Security Sub-System */
561 status = ele_mu_get_response_baseapi(mu, rmsg);
562 if (status != kStatus_Success)
563 {
564 return status;
565 }
566
567 /* Check that response corresponds to the sent command */
568 if (rmsg[0] == RELEASE_RDC_RESPONSE_HDR && rmsg[1] == RESPONSE_SUCCESS)
569 {
570 return kStatus_Success;
571 }
572 else
573 {
574 return kStatus_Fail;
575 }
576 }
577
578 /*!
579 * brief Start the initialization of the RNG context.
580 *
581 * The RNG must be started before using some of the ELE services.
582 *
583 * param mu MU peripheral base address
584 *
585 * return Status kStatus_Success if success, kStatus_Fail if fail
586 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
587 */
ELE_BaseAPI_StartRng(S3MU_Type * mu)588 status_t ELE_BaseAPI_StartRng(S3MU_Type *mu)
589 {
590 status_t status = kStatus_Fail;
591 uint32_t tmsg[START_RNG_SIZE] = {0u};
592 uint32_t rmsg[S3MU_RR_COUNT] = {0u};
593
594 /****************** Start RNG ***********************/
595 tmsg[0] = START_RNG; // Start RNG message Command Header
596
597 /* Send message to Security Sub-System */
598 status = S3MU_SendMessage(mu, tmsg, START_RNG_SIZE);
599 if (status != kStatus_Success)
600 {
601 return status;
602 }
603
604 /* Wait for response from Security Sub-System */
605 status = ele_mu_get_response_baseapi(mu, rmsg);
606 if (status != kStatus_Success)
607 {
608 return status;
609 }
610
611 /* Check that response corresponds to the sent command */
612 if (rmsg[0] == START_RNG_RESPONSE_HDR && rmsg[1] == RESPONSE_SUCCESS)
613 {
614 return kStatus_Success;
615 }
616 else
617 {
618 return kStatus_Fail;
619 }
620 }
621