1 /*
2 * Copyright 2018 - 2021 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "fsl_prince.h"
9
10 /*******************************************************************************
11 * Definitions
12 ******************************************************************************/
13 /* Component ID definition, used by tools. */
14
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.prince"
17 #endif
18
19 /*******************************************************************************
20 * Variables
21 ******************************************************************************/
22
23 /*******************************************************************************
24 * Code
25 ******************************************************************************/
26 #if !defined(FSL_PRINCE_DRIVER_LPC55S3x)
PRINCE_CheckerAlgorithm(uint32_t address,uint32_t length,prince_flags_t flag,flash_config_t * flash_context)27 static secure_bool_t PRINCE_CheckerAlgorithm(uint32_t address,
28 uint32_t length,
29 prince_flags_t flag,
30 flash_config_t *flash_context)
31 {
32 uint32_t temp_base = 0, temp_sr = 0, region_index = 0, contiguous_start_index = 0, contiguous_end_index = 32;
33 secure_bool_t is_prince_region_contiguous = kSECURE_TRUE;
34 uint8_t prince_iv_code[FLASH_FFR_IV_CODE_SIZE] = {0};
35
36 if (address >= flash_context->ffrConfig.ffrBlockBase)
37 {
38 /* If it is not in flash region, return true to allow erase/write operation. */
39 return kSECURE_TRUE;
40 }
41
42 /* Iterate for all PRINCE regions */
43 for (region_index = (uint32_t)kPRINCE_Region0; region_index <= (uint32_t)kPRINCE_Region2; region_index++)
44 {
45 contiguous_start_index = 0;
46 contiguous_end_index = 32;
47 switch (region_index)
48 {
49 case (uint32_t)kPRINCE_Region0:
50 temp_base = PRINCE->BASE_ADDR0;
51 temp_sr = PRINCE->SR_ENABLE0;
52 break;
53
54 case (uint32_t)kPRINCE_Region1:
55 temp_base = PRINCE->BASE_ADDR1;
56 temp_sr = PRINCE->SR_ENABLE1;
57 break;
58
59 case (uint32_t)kPRINCE_Region2:
60 temp_base = PRINCE->BASE_ADDR2;
61 temp_sr = PRINCE->SR_ENABLE2;
62 break;
63
64 default:
65 /* All the cases have been listed above, the default clause should not be reached. */
66 break;
67 }
68
69 if (((address >= temp_base) &&
70 ((address + length) < (temp_base + (FSL_PRINCE_DRIVER_SUBREGION_SIZE_IN_KB * 32U * 1024U)))) &&
71 (temp_sr != 0U))
72 {
73 /* Check if the mask is contiguous */
74 secure_bool_t first_set_bit_found = kSECURE_FALSE;
75 secure_bool_t contiguous_end_found = kSECURE_FALSE;
76 for (uint32_t i = 0; i < 32U; i++)
77 {
78 if (0U != (temp_sr & (1UL << i)))
79 {
80 if (kSECURE_FALSE == first_set_bit_found)
81 {
82 first_set_bit_found = kSECURE_TRUE;
83 contiguous_start_index = i;
84 }
85 if (kSECURE_TRUE == contiguous_end_found)
86 {
87 is_prince_region_contiguous = kSECURE_FALSE;
88 break;
89 }
90 }
91 else
92 {
93 if ((kSECURE_TRUE == first_set_bit_found) && (kSECURE_FALSE == contiguous_end_found))
94 {
95 contiguous_end_found = kSECURE_TRUE;
96 contiguous_end_index = i;
97 }
98 }
99 }
100 }
101 else
102 {
103 continue; /* No encryption enabled, continue with the next region checking. */
104 }
105
106 /* Check if the provided memory range covers all addresses defined in the SR mask */
107 if ((kSECURE_TRUE == is_prince_region_contiguous) &&
108 ((address <= (temp_base + (contiguous_start_index * FSL_PRINCE_DRIVER_SUBREGION_SIZE_IN_KB * 1024U)))) &&
109 (((address + length) >=
110 (temp_base + (contiguous_end_index * FSL_PRINCE_DRIVER_SUBREGION_SIZE_IN_KB * 1024U)))))
111 {
112 /* In case of erase operation, invalidate the old PRINCE IV by regenerating the new one */
113 if (kPRINCE_Flag_EraseCheck == flag)
114 {
115 /* Re-generate the PRINCE IV in case of erase operation */
116
117 /* Generate new IV code for the PRINCE region and store the new IV into the respective FFRs */
118 if (kStatus_Success ==
119 PRINCE_GenNewIV((prince_region_t)region_index, &prince_iv_code[0], true, flash_context))
120 {
121 /* Store the new IV for the PRINCE region into PRINCE registers. */
122 if (kStatus_Success == PRINCE_LoadIV((prince_region_t)region_index, &prince_iv_code[0]))
123 {
124 /* Encryption is enabled, all subregions are to be erased/written at once, IV successfully
125 * regenerated, return true to allow erase operation. */
126 return kSECURE_TRUE;
127 }
128 }
129 /* Encryption is enabled, all subregions are to be erased/written at once but IV has not been correctly
130 * regenerated, return false to disable erase operation. */
131 return kSECURE_FALSE;
132 }
133
134 /* Encryption is enabled and all subregions are to be erased/written at once, return true to allow
135 * erase/write operation. */
136 return kSECURE_TRUE;
137 }
138 /* The provided memory range does not cover all addresses defined in the SR mask. */
139 else
140 {
141 /* Is the provided memory range outside the addresses defined by the SR mask? */
142 if ((kSECURE_TRUE == is_prince_region_contiguous) &&
143 ((((address + length) <=
144 (temp_base + (contiguous_start_index * FSL_PRINCE_DRIVER_SUBREGION_SIZE_IN_KB * 1024U)))) ||
145 ((address >= (temp_base + (contiguous_end_index * FSL_PRINCE_DRIVER_SUBREGION_SIZE_IN_KB * 1024U))))))
146 {
147 /* No encryption enabled for the provided memory range, true could be returned to allow erase/write
148 operation, but due to the same base address for all three prince regions on Niobe4Mini we should
149 continue with other regions (SR mask) checking. */
150 continue;
151 }
152 else
153 {
154 /* Encryption is enabled but not all subregions are to be erased/written at once, return false to
155 * disable erase/write operation. */
156 return kSECURE_FALSE;
157 }
158 }
159 }
160 return kSECURE_TRUE;
161 }
162 #endif /* !defined(FSL_PRINCE_DRIVER_LPC55S3x) */
163
164 #if !defined(FSL_PRINCE_DRIVER_LPC55S3x)
165 /*!
166 * @brief Generate new IV code.
167 *
168 * This function generates new IV code and stores it into the persistent memory.
169 * Ensure about 800 bytes free space on the stack when calling this routine with the store parameter set to true!
170 *
171 * @param region PRINCE region index.
172 * @param iv_code IV code pointer used for storing the newly generated 52 bytes long IV code.
173 * @param store flag to allow storing the newly generated IV code into the persistent memory (FFR).
174 * @param flash_context pointer to the flash driver context structure.
175 *
176 * @return kStatus_Success upon success
177 * @return kStatus_Fail otherwise, kStatus_Fail is also returned if the key code for the particular
178 * PRINCE region is not present in the keystore (though new IV code has been provided)
179 */
PRINCE_GenNewIV(prince_region_t region,uint8_t * iv_code,bool store,flash_config_t * flash_context)180 status_t PRINCE_GenNewIV(prince_region_t region, uint8_t *iv_code, bool store, flash_config_t *flash_context)
181 {
182 status_t status = kStatus_Fail;
183 uint8_t prince_iv_code[FLASH_FFR_IV_CODE_SIZE] = {0};
184 uint8_t tempBuffer[FLASH_FFR_MAX_PAGE_SIZE] = {0};
185
186 /* Make sure PUF is started to allow key and IV code decryption and generation */
187 if (true != PUF_IsGetKeyAllowed(PUF))
188 {
189 return status;
190 }
191
192 /* Generate new IV code for the PRINCE region */
193 status =
194 PUF_SetIntrinsicKey(PUF, (puf_key_index_register_t)(uint32_t)((uint32_t)kPUF_KeyIndex_02 + (uint32_t)region), 8,
195 &prince_iv_code[0], FLASH_FFR_IV_CODE_SIZE);
196 if ((kStatus_Success == status) && (true == store))
197 {
198 /* Store the new IV code for the PRINCE region into the respective FFRs. */
199 /* Create a new version of "Customer Field Programmable" (CFP) page. */
200 if ((int32_t)kStatus_FLASH_Success ==
201 FFR_GetCustomerInfieldData(flash_context, (uint8_t *)tempBuffer, 0, FLASH_FFR_MAX_PAGE_SIZE))
202 {
203 /* Set the IV code in the page */
204 (void)memcpy(&tempBuffer[offsetof(cfpa_cfg_info_t, ivCodePrinceRegion) +
205 (((uint32_t)region * sizeof(cfpa_cfg_iv_code_t))) + 4U],
206 &prince_iv_code[0], FLASH_FFR_IV_CODE_SIZE);
207
208 uint32_t *p32 = (uint32_t *)(uint32_t)tempBuffer;
209 uint32_t version = p32[1];
210 if (version == 0xFFFFFFFFu)
211 {
212 return kStatus_Fail;
213 }
214 version++;
215 p32[1] = version;
216
217 /* Program the page and enable firewall for "Customer field area" */
218 if ((int32_t)kStatus_FLASH_Success ==
219 FFR_InfieldPageWrite(flash_context, (uint8_t *)tempBuffer, FLASH_FFR_MAX_PAGE_SIZE))
220 {
221 status = kStatus_Success;
222 }
223 else
224 {
225 status = kStatus_Fail;
226 }
227 }
228 }
229 if (status == kStatus_Success)
230 {
231 /* Pass the new IV code */
232 (void)memcpy(iv_code, &prince_iv_code[0], FLASH_FFR_IV_CODE_SIZE);
233 }
234
235 return status;
236 }
237 #endif /* !defined(FSL_PRINCE_DRIVER_LPC55S3x) */
238
239 #if !defined(FSL_PRINCE_DRIVER_LPC55S3x)
240 /*!
241 * @brief Load IV code.
242 *
243 * This function enables IV code loading into the PRINCE bus encryption engine.
244 *
245 * @param region PRINCE region index.
246 * @param iv_code IV code pointer used for passing the IV code.
247 *
248 * @return kStatus_Success upon success
249 * @return kStatus_Fail otherwise
250 */
PRINCE_LoadIV(prince_region_t region,uint8_t * iv_code)251 status_t PRINCE_LoadIV(prince_region_t region, uint8_t *iv_code)
252 {
253 status_t status = kStatus_Fail;
254 uint32_t keyIndex = (0x0Fu & (uint32_t)iv_code[1]);
255 uint8_t prince_iv[8] = {0};
256
257 /* Make sure PUF is started to allow key and IV code decryption and generation */
258 if (true != PUF_IsGetKeyAllowed(PUF))
259 {
260 return kStatus_Fail;
261 }
262
263 /* Check if region number matches the PUF index value */
264 if (((uint32_t)kPUF_KeyIndex_02 + (uint32_t)region) == (uint32_t)keyIndex)
265 {
266 /* Decrypt the IV */
267 if (kStatus_Success == PUF_GetKey(PUF, iv_code, FLASH_FFR_IV_CODE_SIZE, &prince_iv[0], 8))
268 {
269 /* Store the new IV for the PRINCE region into PRINCE registers. */
270 (void)PRINCE_SetRegionIV(PRINCE, (prince_region_t)region, prince_iv);
271 status = kStatus_Success;
272 }
273 }
274
275 return status;
276 }
277 #endif /* !defined(FSL_PRINCE_DRIVER_LPC55S3x) */
278
279 #if !defined(FSL_PRINCE_DRIVER_LPC55S3x)
280 /*!
281 * @brief Allow encryption/decryption for specified address range.
282 *
283 * This function sets the encryption/decryption for specified address range.
284 * The SR mask value for the selected Prince region is calculated from provided
285 * start_address and length parameters. This calculated value is OR'ed with the
286 * actual SR mask value and stored into the PRINCE SR_ENABLE register and also
287 * into the persistent memory (FFR) to be used after the device reset. It is
288 * possible to define several nonadjacent encrypted areas within one Prince
289 * region when calling this function repeatedly. If the length parameter is set
290 * to 0, the SR mask value is set to 0 and thus the encryption/decryption for
291 * the whole selected Prince region is disabled.
292 * Ensure about 800 bytes free space on the stack when calling this routine!
293 *
294 * @param region PRINCE region index.
295 * @param start_address start address of the area to be encrypted/decrypted.
296 * @param length length of the area to be encrypted/decrypted.
297 * @param flash_context pointer to the flash driver context structure.
298 * @param regenerate_iv flag to allow IV code regenerating, storing into
299 * the persistent memory (FFR) and loading into the PRINCE engine
300 *
301 * @return kStatus_Success upon success
302 * @return kStatus_Fail otherwise
303 */
PRINCE_SetEncryptForAddressRange(prince_region_t region,uint32_t start_address,uint32_t length,flash_config_t * flash_context,bool regenerate_iv)304 status_t PRINCE_SetEncryptForAddressRange(
305 prince_region_t region, uint32_t start_address, uint32_t length, flash_config_t *flash_context, bool regenerate_iv)
306 {
307 status_t status = kStatus_Fail;
308 uint32_t srEnableRegister = 0;
309 uint32_t alignedStartAddress;
310 uint32_t prince_base_addr_ffr_word = 0;
311 uint32_t end_address = start_address + length;
312 uint32_t prince_region_base_address = 0;
313 uint8_t tempBuffer[FLASH_FFR_MAX_PAGE_SIZE] = {0};
314
315 /* Check input parameters. */
316 if (NULL == flash_context)
317 {
318 return kStatus_Fail;
319 }
320
321 /* Check the address range, region borders crossing. */
322 #if (defined(FSL_PRINCE_DRIVER_LPC55S0x)) || (defined(FSL_PRINCE_DRIVER_LPC55S1x)) || \
323 (defined(FSL_PRINCE_DRIVER_LPC55S2x)) || (defined(FSL_PRINCE_DRIVER_LPC55S3x))
324 if ((start_address > FSL_PRINCE_DRIVER_MAX_FLASH_ADDR) ||
325 ((start_address < FSL_PRINCE_DRIVER_MAX_FLASH_ADDR) && (end_address > FSL_PRINCE_DRIVER_MAX_FLASH_ADDR)))
326 {
327 return kStatus_Fail;
328 }
329 #endif
330 #if (defined(FSL_PRINCE_DRIVER_LPC55S6x))
331 if ((start_address > FSL_PRINCE_DRIVER_MAX_FLASH_ADDR) ||
332 ((start_address < 0x40000U) && (end_address > 0x40000U)) ||
333 ((start_address < 0x80000U) && (end_address > 0x80000U)) ||
334 ((start_address < FSL_PRINCE_DRIVER_MAX_FLASH_ADDR) && (end_address > FSL_PRINCE_DRIVER_MAX_FLASH_ADDR)))
335 {
336 return kStatus_Fail;
337 }
338 #endif
339
340 if (true == regenerate_iv)
341 {
342 uint8_t prince_iv_code[FLASH_FFR_IV_CODE_SIZE] = {0};
343
344 /* Generate new IV code for the PRINCE region and store the new IV into the respective FFRs */
345 status = PRINCE_GenNewIV((prince_region_t)region, &prince_iv_code[0], true, flash_context);
346 if (kStatus_Success != status)
347 {
348 return kStatus_Fail;
349 }
350
351 /* Store the new IV for the PRINCE region into PRINCE registers. */
352 status = PRINCE_LoadIV((prince_region_t)region, &prince_iv_code[0]);
353 if (kStatus_Success != status)
354 {
355 return kStatus_Fail;
356 }
357 }
358
359 alignedStartAddress = ALIGN_DOWN(start_address, (int32_t)FSL_PRINCE_DRIVER_SUBREGION_SIZE_IN_KB * 1024);
360
361 uint32_t subregion = alignedStartAddress / (FSL_PRINCE_DRIVER_SUBREGION_SIZE_IN_KB * 1024U);
362 if (subregion < (32U))
363 {
364 /* PRINCE_Region0 */
365 prince_region_base_address = 0;
366 }
367 else if (subregion < (64U))
368 {
369 /* PRINCE_Region1 */
370 subregion = subregion - 32U;
371 prince_region_base_address = 0x40000;
372 }
373 else
374 {
375 /* PRINCE_Region2 */
376 subregion = subregion - 64U;
377 prince_region_base_address = 0x80000;
378 }
379
380 /* If length > 0 then srEnableRegister mask is set based on the alignedStartAddress and the length.
381 If the length is 0, srEnableRegister should be kept 0 (no subregion enabled). */
382 if (length != 0U)
383 {
384 srEnableRegister = (1UL << subregion);
385 alignedStartAddress += (FSL_PRINCE_DRIVER_SUBREGION_SIZE_IN_KB * 1024U);
386
387 while (alignedStartAddress < (start_address + length))
388 {
389 subregion++;
390 srEnableRegister |= (1UL << subregion);
391 alignedStartAddress += (FSL_PRINCE_DRIVER_SUBREGION_SIZE_IN_KB * 1024U);
392 }
393
394 uint32_t srEnableRegisterActual = 0;
395 (void)PRINCE_GetRegionSREnable(PRINCE, (prince_region_t)region, &srEnableRegisterActual);
396 srEnableRegister |= srEnableRegisterActual;
397 }
398
399 /* Store BASE_ADDR into PRINCE register before storing the SR to avoid en/decryption triggering
400 from addresses being defined by current BASE_ADDR register content (could be 0 and the decryption
401 of actually executed code can be started causing the hardfault then). */
402 status = PRINCE_SetRegionBaseAddress(PRINCE, (prince_region_t)region, prince_region_base_address);
403 if (kStatus_Success != status)
404 {
405 return status;
406 }
407
408 /* Store SR into PRINCE register */
409 status = PRINCE_SetRegionSREnable(PRINCE, (prince_region_t)region, srEnableRegister);
410 if (kStatus_Success != status)
411 {
412 return status;
413 }
414
415 /* Store SR and BASE_ADDR into CMPA FFR */
416 if (kStatus_Success == FFR_GetCustomerData(flash_context, (uint8_t *)&tempBuffer, 0, FLASH_FFR_MAX_PAGE_SIZE))
417 {
418 /* Set the PRINCE_SR_X in the page */
419 (void)memcpy((uint32_t *)(uintptr_t)&tempBuffer[offsetof(cmpa_cfg_info_t, princeSr) +
420 ((uint32_t)region * sizeof(uint32_t))],
421 &srEnableRegister, sizeof(uint32_t));
422 /* Set the ADDRX_PRG in the page */
423 (void)memcpy(&prince_base_addr_ffr_word,
424 (const uint32_t *)(uintptr_t)&tempBuffer[offsetof(cmpa_cfg_info_t, princeBaseAddr)],
425 sizeof(uint32_t));
426 prince_base_addr_ffr_word &=
427 ~(((uint32_t)FLASH_CMPA_PRINCE_BASE_ADDR_ADDR0_PRG_MASK) << ((uint32_t)region * 4U));
428 prince_base_addr_ffr_word |= (((prince_region_base_address >> PRINCE_BASE_ADDR0_ADDR_PRG_SHIFT) &
429 FLASH_CMPA_PRINCE_BASE_ADDR_ADDR0_PRG_MASK)
430 << ((uint32_t)region * 4U));
431 (void)memcpy((uint32_t *)(uintptr_t)&tempBuffer[offsetof(cmpa_cfg_info_t, princeBaseAddr)],
432 &prince_base_addr_ffr_word, sizeof(uint32_t));
433
434 /* Program the CMPA page, set seal_part parameter to false (used during development to avoid sealing the
435 * part)
436 */
437 status = FFR_CustFactoryPageWrite(flash_context, (uint8_t *)tempBuffer, false);
438 }
439
440 return status;
441 }
442 #endif /* !defined(FSL_PRINCE_DRIVER_LPC55S3x) */
443
444 /*!
445 * @brief Gets the PRINCE Sub-Region Enable register.
446 *
447 * This function gets PRINCE SR_ENABLE register.
448 *
449 * @param base PRINCE peripheral address.
450 * @param region PRINCE region index.
451 * @param sr_enable Sub-Region Enable register pointer.
452 *
453 * @return kStatus_Success upon success
454 * @return kStatus_InvalidArgument
455 */
PRINCE_GetRegionSREnable(PRINCE_Type * base,prince_region_t region,uint32_t * sr_enable)456 status_t PRINCE_GetRegionSREnable(PRINCE_Type *base, prince_region_t region, uint32_t *sr_enable)
457 {
458 status_t status = kStatus_Success;
459
460 switch (region)
461 {
462 case kPRINCE_Region0:
463 *sr_enable = base->SR_ENABLE0;
464 break;
465
466 case kPRINCE_Region1:
467 *sr_enable = base->SR_ENABLE1;
468 break;
469
470 case kPRINCE_Region2:
471 *sr_enable = base->SR_ENABLE2;
472 break;
473
474 default:
475 status = kStatus_InvalidArgument;
476 break;
477 }
478
479 return status;
480 }
481
482 /*!
483 * @brief Gets the PRINCE region base address register.
484 *
485 * This function gets PRINCE BASE_ADDR register.
486 *
487 * @param base PRINCE peripheral address.
488 * @param region PRINCE region index.
489 * @param region_base_addr Region base address pointer.
490 *
491 * @return kStatus_Success upon success
492 * @return kStatus_InvalidArgument
493 */
PRINCE_GetRegionBaseAddress(PRINCE_Type * base,prince_region_t region,uint32_t * region_base_addr)494 status_t PRINCE_GetRegionBaseAddress(PRINCE_Type *base, prince_region_t region, uint32_t *region_base_addr)
495 {
496 status_t status = kStatus_Success;
497
498 switch (region)
499 {
500 case kPRINCE_Region0:
501 *region_base_addr = base->BASE_ADDR0;
502 break;
503
504 case kPRINCE_Region1:
505 *region_base_addr = base->BASE_ADDR1;
506 break;
507
508 case kPRINCE_Region2:
509 *region_base_addr = base->BASE_ADDR2;
510 break;
511
512 default:
513 status = kStatus_InvalidArgument;
514 break;
515 }
516
517 return status;
518 }
519
520 /*!
521 * @brief Sets the PRINCE region IV.
522 *
523 * This function sets specified AES IV for the given region.
524 *
525 * @param base PRINCE peripheral address.
526 * @param region Selection of the PRINCE region to be configured.
527 * @param iv 64-bit AES IV in little-endian byte order.
528 *
529 * @return kStatus_Success upon success
530 * @return kStatus_InvalidArgument
531 */
PRINCE_SetRegionIV(PRINCE_Type * base,prince_region_t region,const uint8_t iv[8])532 status_t PRINCE_SetRegionIV(PRINCE_Type *base, prince_region_t region, const uint8_t iv[8])
533 {
534 status_t status = kStatus_Fail;
535 volatile uint32_t *IVMsb_reg = NULL;
536 volatile uint32_t *IVLsb_reg = NULL;
537
538 switch (region)
539 {
540 case kPRINCE_Region0:
541 IVLsb_reg = &base->IV_LSB0;
542 IVMsb_reg = &base->IV_MSB0;
543 break;
544
545 case kPRINCE_Region1:
546 IVLsb_reg = &base->IV_LSB1;
547 IVMsb_reg = &base->IV_MSB1;
548 break;
549
550 case kPRINCE_Region2:
551 IVLsb_reg = &base->IV_LSB2;
552 IVMsb_reg = &base->IV_MSB2;
553 break;
554
555 default:
556 status = kStatus_InvalidArgument;
557 break;
558 }
559
560 if (status != kStatus_InvalidArgument)
561 {
562 *IVLsb_reg = ((uint32_t *)(uintptr_t)iv)[0];
563 *IVMsb_reg = ((uint32_t *)(uintptr_t)iv)[1];
564 status = kStatus_Success;
565 }
566
567 return status;
568 }
569
570 /*!
571 * @brief Sets the PRINCE region base address.
572 *
573 * This function configures PRINCE region base address.
574 *
575 * @param base PRINCE peripheral address.
576 * @param region Selection of the PRINCE region to be configured.
577 * @param region_base_addr Base Address for region.
578 *
579 * @return kStatus_Success upon success
580 * @return kStatus_InvalidArgument
581 */
PRINCE_SetRegionBaseAddress(PRINCE_Type * base,prince_region_t region,uint32_t region_base_addr)582 status_t PRINCE_SetRegionBaseAddress(PRINCE_Type *base, prince_region_t region, uint32_t region_base_addr)
583 {
584 status_t status = kStatus_Success;
585
586 /* Check input parameters. */
587 #if (defined(FSL_PRINCE_DRIVER_LPC55S0x)) || (defined(FSL_PRINCE_DRIVER_LPC55S1x)) || \
588 (defined(FSL_PRINCE_DRIVER_LPC55S2x)) || (defined(FSL_PRINCE_DRIVER_LPC55S3x))
589 if (region_base_addr > 0U)
590 {
591 return kStatus_InvalidArgument;
592 }
593 #endif
594 #if (defined(FSL_PRINCE_DRIVER_LPC55S6x))
595 if (region_base_addr > 0x80000U)
596 {
597 return kStatus_InvalidArgument;
598 }
599 #endif
600
601 switch (region)
602 {
603 case kPRINCE_Region0:
604 base->BASE_ADDR0 = region_base_addr;
605 break;
606
607 case kPRINCE_Region1:
608 base->BASE_ADDR1 = region_base_addr;
609 break;
610
611 case kPRINCE_Region2:
612 base->BASE_ADDR2 = region_base_addr;
613 break;
614
615 default:
616 status = kStatus_InvalidArgument;
617 break;
618 }
619
620 return status;
621 }
622
623 /*!
624 * @brief Sets the PRINCE Sub-Region Enable register.
625 *
626 * This function configures PRINCE SR_ENABLE register.
627 *
628 * @param base PRINCE peripheral address.
629 * @param region Selection of the PRINCE region to be configured.
630 * @param sr_enable Sub-Region Enable register value.
631 *
632 * @return kStatus_Success upon success
633 * @return kStatus_InvalidArgument
634 */
PRINCE_SetRegionSREnable(PRINCE_Type * base,prince_region_t region,uint32_t sr_enable)635 status_t PRINCE_SetRegionSREnable(PRINCE_Type *base, prince_region_t region, uint32_t sr_enable)
636 {
637 status_t status = kStatus_Success;
638
639 switch (region)
640 {
641 case kPRINCE_Region0:
642 base->SR_ENABLE0 = sr_enable;
643 break;
644
645 case kPRINCE_Region1:
646 base->SR_ENABLE1 = sr_enable;
647 break;
648
649 case kPRINCE_Region2:
650 base->SR_ENABLE2 = sr_enable;
651 break;
652
653 default:
654 status = kStatus_InvalidArgument;
655 break;
656 }
657
658 return status;
659 }
660
661 #if !defined(FSL_PRINCE_DRIVER_LPC55S3x)
662 /*!
663 * @brief Erases the flash sectors encompassed by parameters passed into function.
664 *
665 * This function erases the appropriate number of flash sectors based on the
666 * desired start address and length. It deals with the flash erase function
667 * complenentary to the standard erase API of the IAP1 driver. This implementation
668 * additionally checks if the whole encrypted PRINCE subregions are erased at once
669 * to avoid secrets revealing. The checker implementation is limited to one contiguous
670 * PRINCE-controlled memory area.
671 *
672 * @param config The pointer to the flash driver context structure.
673 * @param start The start address of the desired flash memory to be erased.
674 * The start address needs to be prince-sburegion-aligned.
675 * @param lengthInBytes The length, given in bytes (not words or long-words)
676 * to be erased. Must be prince-sburegion-size-aligned.
677 * @param key The value used to validate all flash erase APIs.
678 *
679 * @return #kStatus_FLASH_Success API was executed successfully.
680 * @return #kStatus_FLASH_InvalidArgument An invalid argument is provided.
681 * @return #kStatus_FLASH_AlignmentError The parameter is not aligned with the specified baseline.
682 * @return #kStatus_FLASH_AddressError The address is out of range.
683 * @return #kStatus_FLASH_EraseKeyError The API erase key is invalid.
684 * @return #kStatus_FLASH_CommandFailure Run-time error during the command execution.
685 * @return #kStatus_FLASH_CommandNotSupported Flash API is not supported.
686 * @return #kStatus_FLASH_EccError A correctable or uncorrectable error during command execution.
687 * @return #kStatus_FLASH_EncryptedRegionsEraseNotDoneAtOnce Encrypted flash subregions are not erased at once.
688 */
PRINCE_FlashEraseWithChecker(flash_config_t * config,uint32_t start,uint32_t lengthInBytes,uint32_t key)689 status_t PRINCE_FlashEraseWithChecker(flash_config_t *config, uint32_t start, uint32_t lengthInBytes, uint32_t key)
690 {
691 /* Check input parameters. */
692 if (NULL == config)
693 {
694 return kStatus_Fail;
695 }
696 /* Check that the whole encrypted region is erased at once. */
697 if (kSECURE_TRUE != PRINCE_CheckerAlgorithm(start, lengthInBytes, kPRINCE_Flag_EraseCheck, config))
698 {
699 return (int32_t)kStatus_FLASH_EncryptedRegionsEraseNotDoneAtOnce;
700 }
701 return FLASH_Erase(config, start, lengthInBytes, key);
702 }
703
704 /*!
705 * @brief Programs flash with data at locations passed in through parameters.
706 *
707 * This function programs the flash memory with the desired data for a given
708 * flash area as determined by the start address and the length. It deals with the
709 * flash program function complenentary to the standard program API of the IAP1 driver.
710 * This implementation additionally checks if the whole PRINCE subregions are
711 * programmed at once to avoid secrets revealing. The checker implementation is limited
712 * to one contiguous PRINCE-controlled memory area.
713 *
714 * @param config The pointer to the flash driver context structure.
715 * @param start The start address of the desired flash memory to be programmed. Must be
716 * prince-sburegion-aligned.
717 * @param src A pointer to the source buffer of data that is to be programmed
718 * into the flash.
719 * @param lengthInBytes The length, given in bytes (not words or long-words),
720 * to be programmed. Must be prince-sburegion-size-aligned.
721 *
722 * @return #kStatus_FLASH_Success API was executed successfully.
723 * @return #kStatus_FLASH_InvalidArgument An invalid argument is provided.
724 * @return #kStatus_FLASH_AlignmentError Parameter is not aligned with the specified baseline.
725 * @return #kStatus_FLASH_AddressError Address is out of range.
726 * @return #kStatus_FLASH_AccessError Invalid instruction codes and out-of bounds addresses.
727 * @return #kStatus_FLASH_CommandFailure Run-time error during the command execution.
728 * @return #kStatus_FLASH_CommandFailure Run-time error during the command execution.
729 * @return #kStatus_FLASH_CommandNotSupported Flash API is not supported.
730 * @return #kStatus_FLASH_EccError A correctable or uncorrectable error during command execution.
731 * @return #kStatus_FLASH_SizeError Encrypted flash subregions are not programmed at once.
732 */
PRINCE_FlashProgramWithChecker(flash_config_t * config,uint32_t start,uint8_t * src,uint32_t lengthInBytes)733 status_t PRINCE_FlashProgramWithChecker(flash_config_t *config, uint32_t start, uint8_t *src, uint32_t lengthInBytes)
734 {
735 /* Check input parameters. */
736 if (NULL == config)
737 {
738 return kStatus_Fail;
739 }
740 /* Check that the whole encrypted subregions will be writen at once. */
741 if (kSECURE_TRUE != PRINCE_CheckerAlgorithm(start, lengthInBytes, kPRINCE_Flag_WriteCheck, config))
742 {
743 return (int32_t)kStatus_FLASH_SizeError;
744 }
745 return FLASH_Program(config, start, src, lengthInBytes);
746 }
747 #endif /* !defined(FSL_PRINCE_DRIVER_LPC55S3x) */
748
749 #if defined(FSL_PRINCE_DRIVER_LPC55S3x)
750 static status_t PRINCE_CSS_generate_random(uint8_t *output, size_t outputByteLen);
751 static status_t PRINCE_CSS_check_key(uint8_t keyIdx, mcuxClCss_KeyProp_t *pKeyProp);
752 static status_t PRINCE_CSS_gen_iv_key(void);
753 static status_t PRINCE_CSS_enable(void);
754 static status_t PRINCE_CSS_calculate_iv(uint32_t *IvReg);
755
756 /*!
757 * @brief Configures PRINCE setting.
758 *
759 * This function does the initial PRINCE configuration via ROM IAP API call.
760 * PRINCE_SR_x configuration for each region configuration is stored into FFR (CMPA).
761 * PRINCE IV erase counters (MCTR_INT_IV_CTRx) in CFPA are updated accordingly.
762 *
763 * Note: This function is expected to be called once in the device lifetime,
764 * typically during the initial device provisioning, since it is programming the CMPA pages in PFR flash.
765 *
766 * @param coreCtx The pointer to the ROM API driver context structure.
767 * @param config The pointer to the PRINCE driver configuration structure.
768 *
769 * @retval #kStatus_Success
770 * @retval #kStatus_CommandUnsupported
771 * @retval #kStatus_InvalidArgument
772 * @retval #kStatus_FLASH_ModifyProtectedAreaDisallowed
773 * @retval #kStatusMemoryRangeInvalid
774 * @retval #kStatus_Fail
775 * @retval #kStatus_OutOfRange
776 * @retval #kStatus_SPI_BaudrateNotSupport
777 */
PRINCE_Configure(api_core_context_t * coreCtx,prince_prot_region_arg_t * config)778 status_t PRINCE_Configure(api_core_context_t *coreCtx, prince_prot_region_arg_t *config)
779 {
780 /* Enable CSS and check keys */
781 if (kStatus_Success != PRINCE_CSS_enable())
782 {
783 return kStatus_Fail;
784 }
785
786 return MEM_Config(coreCtx, (uint32_t *)config, kMemoryInternal);
787 }
788
789 /*!
790 * @brief Configures PRINCE setting.
791 *
792 * This function is used to re-configure PRINCE IP based on configuration stored in FFR.
793 * This function also needs to be called after wake up from power-down mode to regenerate IV
794 * encryption key in CSS key store whose presence is necessary for correct PRINCE operation
795 * during erase and write operations to encrypted regions of internal flash memory
796 * (dependency for correct operation of MEM_Erase() and MEM_Write() after wake up from power-down mode).
797 *
798 * @param coreCtx The pointer to the ROM API driver context structure.
799 *
800 * @retval #kStatus_Success
801 * @retval #kStatus_Fail
802 */
PRINCE_Reconfigure(api_core_context_t * coreCtx)803 status_t PRINCE_Reconfigure(api_core_context_t *coreCtx)
804 {
805 status_t status = kStatus_Fail;
806 uint64_t princeMask;
807 uint32_t IvReg[4] = {0};
808 uint32_t ivEraseCounter[3];
809 uint32_t srEnable[3];
810 uint32_t uuid[4];
811 flash_config_t flash_config;
812 uint32_t lockWord;
813 uint8_t lock[3];
814
815 /* Enable CSS and check keys */
816 status = PRINCE_CSS_enable();
817 if (kStatus_Success != status)
818 {
819 return kStatus_Fail;
820 }
821
822 /* Set PRINCE mask value. */
823 status = PRINCE_CSS_generate_random((uint8_t *)&princeMask, sizeof(princeMask));
824 if (kStatus_Success != status)
825 {
826 return kStatus_Fail;
827 }
828 PRINCE_SetMask(PRINCE, princeMask);
829
830 /* Clean up Flash driver structure and Init*/
831 memset(&flash_config, 0, sizeof(flash_config_t));
832 if (FLASH_Init(&flash_config) != kStatus_Success)
833 {
834 return kStatus_Fail;
835 }
836
837 /* FFR Init */
838 if (FFR_Init(&flash_config) != kStatus_Success)
839 {
840 return kStatus_Fail;
841 }
842
843 /* Get UUID from FFR */
844 status = FFR_GetUUID(&flash_config, (uint8_t *)uuid);
845 if (kStatus_Success != status)
846 {
847 return kStatus_Fail;
848 }
849
850 /* Check version of CFPA scratch first */
851 uint32_t cfpaScratchVer = 0u;
852 memcpy(&cfpaScratchVer, (void *)(CFPA_SCRATCH_VER), sizeof(uint32_t));
853
854 /* Get CFPA version using FFR ROM API */
855 uint32_t cfpaVer = 0u;
856 if (kStatus_Success !=
857 FFR_GetCustomerInfieldData(&flash_config, (uint8_t *)&cfpaVer, CFPA_VER_OFFSET, sizeof(uint32_t)))
858 {
859 status = kStatus_Fail;
860 return status;
861 }
862
863 /* Compare the version of CFPA scratch and version of CFPA returned by ROM API */
864 if (cfpaScratchVer > cfpaVer)
865 {
866 /* Get PRINCE_IV_CTRs from CFPA scratch */
867 memcpy(&ivEraseCounter, (void *)CFPA_SCRATCH_IV, sizeof(uint32_t) * PRINCE_REGION_COUNT);
868 }
869 else
870 {
871 /* Get PRINCE_IV_CTRs IVs from CFPA ping/pong page */
872 status = FFR_GetCustomerInfieldData(&flash_config, (uint8_t *)ivEraseCounter, CFPA_PRINCE_IV_OFFSET,
873 sizeof(uint32_t) * PRINCE_REGION_COUNT);
874 if (kStatus_Success != status)
875 {
876 return kStatus_Fail;
877 }
878 }
879
880 /* Get PRINCE sub-region enable word from FFR */
881 status = FFR_GetCustomerData(&flash_config, (uint8_t *)srEnable, CMPA_PRINCE_SR_OFFSET,
882 sizeof(uint32_t) * PRINCE_REGION_COUNT);
883 if (kStatus_Success != status)
884 {
885 return kStatus_Fail;
886 }
887
888 /* Get PRINCE lock setting from FFR */
889 status = FFR_GetCustomerData(&flash_config, (uint8_t *)&lockWord, CMPA_PRINCE_LOCK_OFFSET, sizeof(uint32_t));
890 if (kStatus_Success != status)
891 {
892 return kStatus_Fail;
893 }
894
895 lock[0] = (lockWord & PRINCE_BASE_ADDR_LOCK_REG0_MASK) >> PRINCE_BASE_ADDR_LOCK_REG0_SHIFT;
896 lock[1] = (lockWord & PRINCE_BASE_ADDR_LOCK_REG1_MASK) >> PRINCE_BASE_ADDR_LOCK_REG1_SHIFT;
897 lock[2] = (lockWord & PRINCE_BASE_ADDR_LOCK_REG2_MASK) >> PRINCE_BASE_ADDR_LOCK_REG2_SHIFT;
898
899 /* Iterate for all internal PRINCE regions */
900 for (prince_region_t region = kPRINCE_Region0; region <= kPRINCE_Region2; region++)
901 {
902 /* Set region base address. Should be always 0x0 on LPC55S36 */
903 status = PRINCE_SetRegionBaseAddress(PRINCE, (prince_region_t)region, 0x0u);
904 if (kStatus_Success != status)
905 {
906 return kStatus_Fail;
907 }
908
909 status = PRINCE_SetRegionSREnable(PRINCE, region, srEnable[region]);
910 if (kStatus_Success != status)
911 {
912 return kStatus_Fail;
913 }
914
915 /* Prepare ivSeed for current region */
916 IvReg[0] = uuid[0];
917 IvReg[1] = uuid[1];
918 IvReg[2] = uuid[2] ^ region;
919 IvReg[3] = ivEraseCounter[region];
920
921 /* Calculate IV as IvReg = AES_ECB_ENC(DUK_derived_key, {ctx_erase_counter, ctx_id}) */
922 status = PRINCE_CSS_calculate_iv(IvReg);
923 if (status != kStatus_Success)
924 {
925 return kStatus_Fail;
926 }
927
928 /* Load IV into PRINCE registers */
929 status = PRINCE_SetRegionIV(PRINCE, (prince_region_t)region, (uint8_t *)IvReg);
930 if (status != kStatus_Success)
931 {
932 return kStatus_Fail;
933 }
934
935 /* Lock region if required */
936 if ((lock[region] == 0x1u) || (lock[region] == 0x2u) || (lock[region] == 0x3u))
937 {
938 PRINCE_SetLock(PRINCE, (kPRINCE_Region0Lock << region));
939 }
940 }
941
942 /* Break the main loop in case that error occured during PRINCE configuration */
943 if (status != kStatus_Success)
944 {
945 return kStatus_Fail;
946 }
947
948 /* When ENC_ENABLE is set, reading from PRINCE-encrypted regions is disabled. */
949 /* For LPC55S36, the ENC_ENABLE is self-cleared after programming memory. */
950 PRINCE_EncryptDisable(PRINCE);
951 return status;
952 }
953
PRINCE_CSS_generate_random(uint8_t * output,size_t outputByteLen)954 static status_t PRINCE_CSS_generate_random(uint8_t *output, size_t outputByteLen)
955 {
956 status_t status = kStatus_Fail;
957
958 // PRNG needs to be initialized; this can be done by calling mcuxClCss_KeyDelete_Async
959 // (delete any key slot, can be empty)
960 MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_KeyDelete_Async(18));
961 // mcuxClCss_KeyDelete_Async is a flow-protected function: Check the protection token and the return value
962 if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_KeyDelete_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
963 return kStatus_Fail; // Expect that no error occurred, meaning that the mcuxClCss_KeyDelete_Async operation was
964 // started.
965 MCUX_CSSL_FP_FUNCTION_CALL_END();
966
967 // Wait for operation to finish
968 MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_WaitForOperation(MCUXCLCSS_ERROR_FLAGS_CLEAR));
969 // mcuxClCss_WaitForOperation is a flow-protected function: Check the protection token and the return value
970 if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
971 return kStatus_Fail; // Expect that no error occurred, meaning that the mcuxClCss_WaitForOperation operation was
972 // started.
973 MCUX_CSSL_FP_FUNCTION_CALL_END();
974
975 MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_Prng_GetRandom(output, outputByteLen));
976 if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Prng_GetRandom) != token) || (MCUXCLCSS_STATUS_OK != result))
977 return kStatus_Fail;
978 MCUX_CSSL_FP_FUNCTION_CALL_END();
979
980 status = kStatus_Success;
981 return status;
982 }
983
PRINCE_CSS_check_key(uint8_t keyIdx,mcuxClCss_KeyProp_t * pKeyProp)984 static status_t PRINCE_CSS_check_key(uint8_t keyIdx, mcuxClCss_KeyProp_t *pKeyProp)
985 {
986 /* Check if CSS required keys are available in CSS keystore */
987 MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token,
988 mcuxClCss_GetKeyProperties(keyIdx, pKeyProp)); // Get key propertis from the CSS.
989 // mcuxClCss_GetKeyProperties is a flow-protected function: Check the protection token and the return value
990 if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_GetKeyProperties) != token) || (MCUXCLCSS_STATUS_OK != result))
991 return kStatus_Fail;
992 MCUX_CSSL_FP_FUNCTION_CALL_END();
993
994 return kStatus_Success;
995 }
996
PRINCE_CSS_gen_iv_key(void)997 static status_t PRINCE_CSS_gen_iv_key(void)
998 {
999 /* The NXP_DIE_MEM_IV_ENC_SK is not loaded and needs to be regenerated (power-down wakeup) */
1000 /* Set KDF mask and key properties for NXP_DIE_MEM_IV_ENC_SK */
1001 SYSCON->CSS_KDF_MASK = SYSCON_CSS_KDF_MASK;
1002 static const uint32_t ddata2[3] = {0x62032504, 0x72f04280, 0x87a2bbae};
1003 mcuxClCss_KeyProp_t keyProp;
1004 /* Set key properties in structure */
1005 keyProp.word.value = CSS_CSS_KS2_ks2_uaes_MASK | CSS_CSS_KS2_ks2_fgp_MASK | CSS_CSS_KS2_ks2_kact_MASK;
1006 status_t status = kStatus_Fail;
1007
1008 /* Generate the key using CKDF */
1009 MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(
1010 result, token,
1011 mcuxClCss_Ckdf_Sp800108_Async((mcuxClCss_KeyIndex_t)0, (mcuxClCss_KeyIndex_t)NXP_DIE_MEM_IV_ENC_SK, keyProp,
1012 (uint8_t const *)ddata2));
1013 if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Ckdf_Sp800108_Async) != token) && (MCUXCLCSS_STATUS_OK != result))
1014 {
1015 return kStatus_Fail;
1016 }
1017 MCUX_CSSL_FP_FUNCTION_CALL_END();
1018
1019 /* Wait for CKDF to finish */
1020 MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_WaitForOperation(MCUXCLCSS_ERROR_FLAGS_CLEAR));
1021 if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) == token) && (MCUXCLCSS_STATUS_OK == result))
1022 {
1023 status = kStatus_Success;
1024 }
1025 MCUX_CSSL_FP_FUNCTION_CALL_END();
1026
1027 return status;
1028 }
1029
PRINCE_CSS_enable(void)1030 static status_t PRINCE_CSS_enable(void)
1031 {
1032 mcuxClCss_KeyProp_t key_properties;
1033 status_t status = kStatus_Fail;
1034
1035 /* Enable CSS and related clocks */
1036 status = CSS_PowerDownWakeupInit(CSS);
1037 if (status != kStatus_Success)
1038 {
1039 return kStatus_Fail;
1040 }
1041
1042 /* Check if MEM_ENC_SK key is available in CSS keystore */
1043 status = PRINCE_CSS_check_key(NXP_DIE_MEM_ENC_SK, &key_properties);
1044 if (status != kStatus_Success || key_properties.bits.kactv != 1u)
1045 {
1046 return kStatus_Fail;
1047 }
1048
1049 /* Check if MEM_IV_ENC_SK key is available in CSS keystore */
1050 status = PRINCE_CSS_check_key(NXP_DIE_MEM_IV_ENC_SK, &key_properties);
1051 if (status != kStatus_Success || key_properties.bits.kactv != 1u)
1052 {
1053 return PRINCE_CSS_gen_iv_key();
1054 }
1055
1056 return kStatus_Success;
1057 }
1058
PRINCE_CSS_calculate_iv(uint32_t * IvReg)1059 static status_t PRINCE_CSS_calculate_iv(uint32_t *IvReg)
1060 {
1061 mcuxClCss_CipherOption_t cipherOptions = {0};
1062 status_t status = kStatus_Fail;
1063
1064 /* Configure CSS for AES ECB-128, using NXP_DIE_MEM_IV_ENC_SK key */
1065 cipherOptions.bits.cphmde = MCUXCLCSS_CIPHERPARAM_ALGORITHM_AES_ECB;
1066 cipherOptions.bits.dcrpt = MCUXCLCSS_CIPHER_ENCRYPT;
1067 cipherOptions.bits.extkey = MCUXCLCSS_CIPHER_INTERNAL_KEY;
1068
1069 do
1070 {
1071 /* Calculate IV as IvReg = AES_ECB_ENC(NXP_DIE_MEM_IV_ENC_SK, ivSeed[127:0]) */
1072 /* ivSeed[127:0] = {UUID[96:0] ^ regionNumber[1:0], ivEraseCounter[31:0]} */
1073 MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(
1074 result, token,
1075 mcuxClCss_Cipher_Async(cipherOptions, (mcuxClCss_KeyIndex_t)NXP_DIE_MEM_IV_ENC_SK, NULL,
1076 MCUXCLCSS_CIPHER_KEY_SIZE_AES_128, (uint8_t *)IvReg, MCUXCLCSS_CIPHER_BLOCK_SIZE_AES,
1077 NULL, (uint8_t *)IvReg));
1078 if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Cipher_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
1079 break;
1080 MCUX_CSSL_FP_FUNCTION_CALL_END();
1081
1082 MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(
1083 result, token,
1084 mcuxClCss_WaitForOperation(
1085 MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_Enable_Async operation to complete.
1086 // mcuxClCss_WaitForOperation is a flow-protected function: Check the protection token and the return value
1087 if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) == token) && (MCUXCLCSS_STATUS_OK == result))
1088 {
1089 status = kStatus_Success;
1090 }
1091 MCUX_CSSL_FP_FUNCTION_CALL_END();
1092 } while (0);
1093
1094 return status;
1095 }
1096 #endif /* defined(FSL_PRINCE_DRIVER_LPC55S3x) */
1097