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