1 /*
2  * Copyright 2018-2021 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_puf.h"
10 #include "fsl_clock.h"
11 #include "fsl_common.h"
12 
13 #if !(defined(FSL_FEATURE_PUF_HAS_NO_RESET) && (FSL_FEATURE_PUF_HAS_NO_RESET > 0))
14 #include "fsl_reset.h"
15 #endif /* FSL_FEATURE_PUF_HAS_NO_RESET */
16 
17 /* Component ID definition, used by tools. */
18 #ifndef FSL_COMPONENT_ID
19 #define FSL_COMPONENT_ID "platform.drivers.puf"
20 #endif
21 
22 /* RT6xx POWER CONTROL bit masks */
23 #if defined(FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL) && (FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL > 0)
24 #define PUF_PWRCTRL_CKDIS_MASK         (0x4U)
25 #define PUF_PWRCTRL_RAMINIT_MASK       (0x8U)
26 #define PUF_PWRCTRL_RAMPSWLARGEMA_MASK (0x10U)
27 #define PUF_PWRCTRL_RAMPSWLARGEMP_MASK (0x20U)
28 #define PUF_PWRCTRL_RAMPSWSMALLMA_MASK (0x40U)
29 #define PUF_PWRCTRL_RAMPSWSMALLMP_MASK (0x80U)
30 #endif
31 
32 #if defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0)
33 #define DEFAULT_CKGATING 0x0u
34 #define PUF_ENABLE_MASK  0xFFFFFFFEu
35 #define PUF_ENABLE_CTRL  0x1u
36 
37 #else
puf_wait_usec(volatile uint32_t usec,uint32_t coreClockFrequencyMHz)38 static void puf_wait_usec(volatile uint32_t usec, uint32_t coreClockFrequencyMHz)
39 {
40     SDK_DelayAtLeastUs(usec, coreClockFrequencyMHz * 1000000U);
41 
42     /* Instead of calling SDK_DelayAtLeastUs() implement delay loop here */
43     // while (usec > 0U)
44     // {
45     //     usec--;
46 
47     //     number of MHz is directly number of core clocks to wait 1 usec.
48     //     the while loop below is actually 4 clocks so divide by 4 for ~1 usec
49     //     volatile uint32_t ticksCount = coreClockFrequencyMHz / 4u + 1u;
50     //     while (0U != ticksCount--)
51     //     {
52     //     }
53     // }
54 }
55 #endif /* defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0) */
56 
puf_waitForInit(PUF_Type * base)57 static status_t puf_waitForInit(PUF_Type *base)
58 {
59     status_t status = kStatus_Fail;
60 
61     /* wait until status register reads non-zero. All zero is not valid. It should be BUSY or OK or ERROR */
62     while (0U == base->STAT)
63     {
64     }
65 
66     /* wait if busy */
67     while ((base->STAT & PUF_STAT_BUSY_MASK) != 0U)
68     {
69     }
70 
71     /* return status */
72     if (0U != (base->STAT & (PUF_STAT_SUCCESS_MASK | PUF_STAT_ERROR_MASK)))
73     {
74         status = kStatus_Success;
75     }
76 
77     return status;
78 }
79 
puf_powerOn(PUF_Type * base,puf_config_t * conf)80 static void puf_powerOn(PUF_Type *base, puf_config_t *conf)
81 {
82 #if defined(FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL) && (FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL > 0)
83     /* RT6xxs */
84     base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK);
85     base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK);
86     base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_RAMINIT_MASK);
87 #elif defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0)
88     /* LPCXpresso55s16 */
89     conf->puf_sram_base->CFG |= PUF_ENABLE_CTRL;
90     while (0U == (PUF_SRAM_CTRL_STATUS_READY_MASK & conf->puf_sram_base->STATUS))
91     {
92     }
93 #else  /* !FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL */
94     /* LPCXpresso55s69 & LPCXpresso54S018 */
95     base->PWRCTRL = PUF_PWRCTRL_RAMON_MASK;
96     while (0U == (PUF_PWRCTRL_RAMSTAT_MASK & base->PWRCTRL))
97     {
98     }
99 #endif /* FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL */
100 }
101 /*!
102  * brief Powercycle PUF
103  *
104  * This function make powercycle of PUF.
105  *
106  * param base PUF peripheral base address
107  * param conf PUF configuration structure
108  * return Status of the powercycle operation.
109  */
PUF_PowerCycle(PUF_Type * base,puf_config_t * conf)110 status_t PUF_PowerCycle(PUF_Type *base, puf_config_t *conf)
111 {
112 #if defined(FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL) && (FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL > 0)
113     /* RT6xxs */
114     uint32_t coreClockFrequencyMHz = conf->coreClockFrequencyHz / 1000000u;
115 
116     base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK); /* disable RAM CK */
117 
118     /* enter ASPS mode */
119     base->PWRCTRL = (PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK); /* SLEEP = 1 */
120     base->PWRCTRL = (PUF_PWRCTRL_RAMINIT_MASK);                           /* enable RAM CK */
121     base->PWRCTRL = (PUF_PWRCTRL_RAMINIT_MASK | PUF_PWRCTRL_RAMPSWLARGEMA_MASK | PUF_PWRCTRL_RAMPSWLARGEMP_MASK |
122                      PUF_PWRCTRL_RAMPSWSMALLMA_MASK | PUF_PWRCTRL_RAMPSWSMALLMP_MASK); /* SLEEP=1, PSW*=1 */
123 
124     /* Wait enough time to discharge fully */
125     puf_wait_usec(conf->dischargeTimeMsec * 1000u, conf->coreClockFrequencyHz / 1000000u);
126 
127     /* write PWRCTRL=0x38. wait time > 1 us */
128     base->PWRCTRL = (PUF_PWRCTRL_RAMINIT_MASK | PUF_PWRCTRL_RAMPSWLARGEMA_MASK |
129                      PUF_PWRCTRL_RAMPSWLARGEMP_MASK); /* SLEEP=1. PSWSMALL*=0. PSWLARGE*=1. */
130     puf_wait_usec(1, coreClockFrequencyMHz);
131 
132     /* write PWRCTRL=0x8. wait time > 1 us */
133     base->PWRCTRL = PUF_PWRCTRL_RAMINIT_MASK; /* SLEEP=1. PSWSMALL*=0. PSWLARGE*=0 */
134     puf_wait_usec(1, coreClockFrequencyMHz);
135 
136     base->PWRCTRL = (PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK);
137     base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK);
138     base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_RAMINIT_MASK);
139 
140     /* Generate INITN low pulse */
141     base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK);
142     base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK);
143     base->PWRCTRL = PUF_PWRCTRL_RAM_ON_MASK;
144 #elif defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0)
145     /* LPCXpresso55s16 */
146     conf->puf_sram_base->CFG &= PUF_ENABLE_MASK;
147 #else
148     /* LPCXpresso55s69 & LPCXpresso54S018 */
149     base->PWRCTRL = 0x0u;
150     while (0U != (PUF_PWRCTRL_RAMSTAT_MASK & base->PWRCTRL))
151     {
152     }
153 
154     /* Wait enough time to discharge fully */
155     puf_wait_usec(conf->dischargeTimeMsec * 1000u, conf->coreClockFrequencyHz / 1000000u);
156 #endif
157 
158 #if !(defined(FSL_FEATURE_PUF_HAS_NO_RESET) && (FSL_FEATURE_PUF_HAS_NO_RESET > 0))
159     /* Reset PUF and reenable power to PUF SRAM */
160     RESET_PeripheralReset(kPUF_RST_SHIFT_RSTn);
161 #endif /* FSL_TEATURE_PUF_HAS_NO_RESET */
162     puf_powerOn(base, conf);
163 
164     return kStatus_Success;
165 }
166 
167 /*!
168  * brief Sets the default configuration of PUF
169  *
170  * This function initialize PUF config structure to default values.
171  *
172  * param conf PUF configuration structure
173  */
PUF_GetDefaultConfig(puf_config_t * conf)174 void PUF_GetDefaultConfig(puf_config_t *conf)
175 {
176 #if defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0)
177     /* LPCXpresso55s16 */
178     conf->puf_sram_base = PUF_SRAM_CTRL;
179 
180     /* Default configuration after reset */
181     conf->CKGATING = DEFAULT_CKGATING; /* PUF SRAM Clock Gating */
182 #endif                                 /* FSL_FEATURE_PUF_HAS_SRAM_CTRL */
183 
184     conf->dischargeTimeMsec    = KEYSTORE_PUF_DISCHARGE_TIME_FIRST_TRY_MS;
185     conf->coreClockFrequencyHz = CLOCK_GetFreq(kCLOCK_CoreSysClk);
186 
187     return;
188 }
189 
190 /*!
191  * brief Initialize PUF
192  *
193  * This function enables power to PUF block and waits until the block initializes.
194  *
195  * param base PUF peripheral base address
196  * param conf PUF configuration structure
197  * return Status of the init operation
198  */
PUF_Init(PUF_Type * base,puf_config_t * conf)199 status_t PUF_Init(PUF_Type *base, puf_config_t *conf)
200 {
201     status_t status = kStatus_Fail;
202 
203 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
204     CLOCK_EnableClock(kCLOCK_Puf);
205 #endif
206 #if !(defined(FSL_FEATURE_PUF_HAS_NO_RESET) && (FSL_FEATURE_PUF_HAS_NO_RESET > 0))
207     /* Reset PUF */
208     RESET_PeripheralReset(kPUF_RST_SHIFT_RSTn);
209 #endif /* FSL_FEATURE_PUF_HAS_NO_RESET */
210 
211 #if defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0)
212     /* Set configuration for SRAM */
213     conf->puf_sram_base->CFG |= PUF_SRAM_CTRL_CFG_CKGATING(conf->CKGATING);
214 
215 #endif /* FSL_FEATURE_PUF_HAS_SRAM_CTRL */
216 
217     /* Enable power to PUF SRAM */
218     puf_powerOn(base, conf);
219 
220     /* Wait for peripheral to become ready */
221     status = puf_waitForInit(base);
222 
223     /* In case of error or enroll or start not allowed, do power-cycle */
224     /* First try with shorter discharge time, if then it also fails try with longer time */
225     /* conf->dischargeTimeMsec    = KEYSTORE_PUF_DISCHARGE_TIME_FIRST_TRY_MS; */
226     if ((status != kStatus_Success) || (0U == (base->ALLOW & (PUF_ALLOW_ALLOWENROLL_MASK | PUF_ALLOW_ALLOWSTART_MASK))))
227     {
228         (void)PUF_PowerCycle(base, conf);
229         status = puf_waitForInit(base);
230     }
231 
232     /* In case of error or enroll or start not allowed, do power-cycle with worst discharge timing */
233     if ((status != kStatus_Success) || (0U == (base->ALLOW & (PUF_ALLOW_ALLOWENROLL_MASK | PUF_ALLOW_ALLOWSTART_MASK))))
234     {
235         conf->dischargeTimeMsec = KEYSTORE_PUF_DISCHARGE_TIME_MAX_MS;
236         (void)PUF_PowerCycle(base, conf);
237         status = puf_waitForInit(base);
238     }
239 
240     return status;
241 }
242 
243 /*!
244  * brief Denitialize PUF
245  *
246  * This function disables power to PUF SRAM and peripheral clock.
247  *
248  * param base PUF peripheral base address
249  * param conf PUF configuration structure
250  */
PUF_Deinit(PUF_Type * base,puf_config_t * conf)251 void PUF_Deinit(PUF_Type *base, puf_config_t *conf)
252 {
253 #if defined(FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL) && (FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL > 0)
254     /* RT6xxs */
255     base->PWRCTRL = (PUF_PWRCTRL_RAM_ON_MASK | PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK); /* disable RAM CK */
256 
257     /* enter ASPS mode */
258     base->PWRCTRL = (PUF_PWRCTRL_CK_DIS_MASK | PUF_PWRCTRL_RAMINIT_MASK); /* SLEEP = 1 */
259     base->PWRCTRL = PUF_PWRCTRL_RAMINIT_MASK;                             /* enable RAM CK */
260     base->PWRCTRL = (PUF_PWRCTRL_RAMINIT_MASK | PUF_PWRCTRL_RAMPSWLARGEMA_MASK | PUF_PWRCTRL_RAMPSWLARGEMP_MASK |
261                      PUF_PWRCTRL_RAMPSWSMALLMA_MASK | PUF_PWRCTRL_RAMPSWSMALLMP_MASK); /* SLEEP=1, PSW*=1 */
262     puf_wait_usec(conf->dischargeTimeMsec * 1000u, conf->coreClockFrequencyHz / 1000000u);
263 #elif defined(FSL_FEATURE_PUF_HAS_SRAM_CTRL) && (FSL_FEATURE_PUF_HAS_SRAM_CTRL > 0)
264     /* LPCXpresso55s16 */
265     conf->puf_sram_base = PUF_SRAM_CTRL;
266     conf->puf_sram_base->CFG &= PUF_ENABLE_MASK;
267 #else /* !FSL_FEATURE_PUF_PWR_HAS_MANUAL_SLEEP_CONTROL */
268     /* LPCXpresso55s69 & LPCXpresso54S018 */
269     base->PWRCTRL = 0x00u;
270     puf_wait_usec(conf->dischargeTimeMsec * 1000u, conf->coreClockFrequencyHz / 1000000u);
271 #endif
272 
273 #if !(defined(FSL_FEATURE_PUF_HAS_NO_RESET) && (FSL_FEATURE_PUF_HAS_NO_RESET > 0))
274     RESET_SetPeripheralReset(kPUF_RST_SHIFT_RSTn);
275 #endif /* FSL_FEATURE_PUF_HAS_NO_RESET */
276 
277 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
278     CLOCK_DisableClock(kCLOCK_Puf);
279 #endif
280 }
281 
282 /*!
283  * brief Enroll PUF
284  *
285  * This function derives a digital fingerprint, generates the corresponding Activation Code (AC)
286  * and returns it to be stored in an NVM or a file. This step needs to be
287  * performed only once for each device. This function may be permanently disallowed by a fuse.
288  *
289  * param base PUF peripheral base address
290  * param[out] activationCode Word aligned address of the resulting activation code.
291  * param activationCodeSize Size of the activationCode buffer in bytes. Shall be 1192 bytes.
292  * return Status of enroll operation.
293  */
PUF_Enroll(PUF_Type * base,uint8_t * activationCode,size_t activationCodeSize)294 status_t PUF_Enroll(PUF_Type *base, uint8_t *activationCode, size_t activationCodeSize)
295 {
296     status_t status                 = kStatus_Fail;
297     uint32_t *activationCodeAligned = NULL;
298     register uint32_t temp32        = 0;
299 
300     /* check that activation code buffer size is at least 1192 bytes */
301     if (activationCodeSize < PUF_ACTIVATION_CODE_SIZE)
302     {
303         return kStatus_InvalidArgument;
304     }
305 
306     /* only work with aligned activationCode */
307     if (0U != (0x3u & (uintptr_t)activationCode))
308     {
309         return kStatus_InvalidArgument;
310     }
311 
312     activationCodeAligned = (uint32_t *)(uintptr_t)activationCode;
313 
314     /* check if ENROLL is allowed */
315     if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWENROLL_MASK))
316     {
317         return kStatus_EnrollNotAllowed;
318     }
319 
320     /* begin */
321     base->CTRL = PUF_CTRL_ENROLL_MASK;
322 
323     /* check status */
324     while (0U == (base->STAT & (PUF_STAT_BUSY_MASK | PUF_STAT_ERROR_MASK)))
325     {
326     }
327 
328     /* read out AC */
329     while (0U != (base->STAT & PUF_STAT_BUSY_MASK))
330     {
331         if (0U != (PUF_STAT_CODEOUTAVAIL_MASK & base->STAT))
332         {
333             temp32 = base->CODEOUTPUT;
334             if (activationCodeSize >= sizeof(uint32_t))
335             {
336                 *activationCodeAligned = temp32;
337                 activationCodeAligned++;
338                 activationCodeSize -= sizeof(uint32_t);
339             }
340         }
341     }
342 
343     if (((base->STAT & PUF_STAT_SUCCESS_MASK) != 0U) && (activationCodeSize == 0U))
344     {
345         status = kStatus_Success;
346     }
347 
348     return status;
349 }
350 
351 /*!
352  * brief Start PUF
353  *
354  * The Activation Code generated during the Enroll operation is used to
355  * reconstruct the digital fingerprint. This needs to be done after every power-up
356  * and reset.
357  *
358  * param base PUF peripheral base address
359  * param activationCode Word aligned address of the input activation code.
360  * param activationCodeSize Size of the activationCode buffer in bytes. Shall be 1192 bytes.
361  * return Status of start operation.
362  */
PUF_Start(PUF_Type * base,const uint8_t * activationCode,size_t activationCodeSize)363 status_t PUF_Start(PUF_Type *base, const uint8_t *activationCode, size_t activationCodeSize)
364 {
365     status_t status                       = kStatus_Fail;
366     const uint32_t *activationCodeAligned = NULL;
367     register uint32_t temp32              = 0;
368 
369     /* check that activation code size is at least 1192 bytes */
370     if (activationCodeSize < 1192U)
371     {
372         return kStatus_InvalidArgument;
373     }
374 
375     /* only work with aligned activationCode */
376     if (0U != (0x3u & (uintptr_t)activationCode))
377     {
378         return kStatus_InvalidArgument;
379     }
380 
381     activationCodeAligned = (const uint32_t *)(uintptr_t)activationCode;
382 
383     /* check if START is allowed */
384     if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWSTART_MASK))
385     {
386         return kStatus_StartNotAllowed;
387     }
388 
389     /* begin */
390     base->CTRL = PUF_CTRL_START_MASK;
391 
392     /* check status */
393     while (0U == (base->STAT & (PUF_STAT_BUSY_MASK | PUF_STAT_ERROR_MASK)))
394     {
395     }
396 
397     /* while busy send AC */
398     while (0U != (base->STAT & PUF_STAT_BUSY_MASK))
399     {
400         if (0U != (PUF_STAT_CODEINREQ_MASK & base->STAT))
401         {
402             if (activationCodeSize >= sizeof(uint32_t))
403             {
404                 temp32 = *activationCodeAligned;
405                 activationCodeAligned++;
406                 activationCodeSize -= sizeof(uint32_t);
407             }
408             base->CODEINPUT = temp32;
409         }
410     }
411 
412     /* get status */
413     if (0U != (base->STAT & PUF_STAT_SUCCESS_MASK))
414     {
415         status = kStatus_Success;
416     }
417 
418     return status;
419 }
420 
421 /*!
422  * brief Set intrinsic key
423  *
424  * The digital fingerprint generated during the Enroll/Start
425  * operations is used to generate a Key Code (KC) that defines a unique intrinsic
426  * key. This KC is returned to be stored in an NVM or a file. This operation
427  * needs to be done only once for each intrinsic key.
428  * Each time a Set Intrinsic Key operation is executed a new unique key is
429  * generated.
430  *
431  * param base PUF peripheral base address
432  * param keyIndex PUF key index register
433  * param keySize Size of the intrinsic key to generate in bytes.
434  * param[out] keyCode Word aligned address of the resulting key code.
435  * param keyCodeSize Size of the keyCode buffer in bytes. Shall be PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize).
436  * return Status of set intrinsic key operation.
437  */
PUF_SetIntrinsicKey(PUF_Type * base,puf_key_index_register_t keyIndex,size_t keySize,uint8_t * keyCode,size_t keyCodeSize)438 status_t PUF_SetIntrinsicKey(
439     PUF_Type *base, puf_key_index_register_t keyIndex, size_t keySize, uint8_t *keyCode, size_t keyCodeSize)
440 {
441     status_t status          = kStatus_Fail;
442     uint32_t *keyCodeAligned = NULL;
443     register uint32_t temp32 = 0;
444 
445     /* check if SET KEY is allowed */
446     if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWSETKEY_MASK))
447     {
448         return kStatus_Fail;
449     }
450 
451     /* only work with aligned keyCode */
452     if (0U != (0x3u & (uintptr_t)keyCode))
453     {
454         return kStatus_InvalidArgument;
455     }
456 
457     /* Check that keySize is in the correct range and that it is multiple of 8 */
458     if ((keySize < (uint32_t)kPUF_KeySizeMin) || (keySize > (uint32_t)kPUF_KeySizeMax) || (0U != (keySize & 0x7U)))
459     {
460         return kStatus_InvalidArgument;
461     }
462 
463     /* check that keyCodeSize is correct for given keySize */
464     if (keyCodeSize < PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize))
465     {
466         return kStatus_InvalidArgument;
467     }
468 
469     if ((uint32_t)keyIndex > (uint32_t)kPUF_KeyIndexMax)
470     {
471         return kStatus_InvalidArgument;
472     }
473 
474     keyCodeAligned = (uint32_t *)(uintptr_t)keyCode;
475 
476     /* program the key size and index */
477     base->KEYSIZE  = keySize >> 3;
478     base->KEYINDEX = (uint32_t)keyIndex;
479 
480     /* begin */
481     base->CTRL = PUF_CTRL_GENERATEKEY_MASK;
482 
483     /* wait till command is accepted */
484     while (0U == (base->STAT & (PUF_STAT_BUSY_MASK | PUF_STAT_ERROR_MASK)))
485     {
486     }
487 
488     /* while busy read KC */
489     while (0U != (base->STAT & PUF_STAT_BUSY_MASK))
490     {
491         if (0U != (PUF_STAT_CODEOUTAVAIL_MASK & base->STAT))
492         {
493             temp32 = base->CODEOUTPUT;
494             if (keyCodeSize >= sizeof(uint32_t))
495             {
496                 *keyCodeAligned = temp32;
497                 keyCodeAligned++;
498                 keyCodeSize -= sizeof(uint32_t);
499             }
500         }
501     }
502 
503     /* get status */
504     if (0U != (base->STAT & PUF_STAT_SUCCESS_MASK))
505     {
506         status = kStatus_Success;
507     }
508 
509     return status;
510 }
511 
512 /*!
513  * brief Set user key
514  *
515  * The digital fingerprint generated during the Enroll/Start
516  * operations and a user key (UK) provided as input are used to
517  * generate a Key Code (KC). This KC is sent returned to be stored
518  * in an NVM or a file. This operation needs to be done only once for each user key.
519  *
520  * param base PUF peripheral base address
521  * param keyIndex PUF key index register
522  * param userKey Word aligned address of input user key.
523  * param userKeySize Size of the input user key in bytes.
524  * param[out] keyCode Word aligned address of the resulting key code.
525  * param keyCodeSize Size of the keyCode buffer in bytes. Shall be PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(userKeySize).
526  * return Status of set user key operation.
527  */
PUF_SetUserKey(PUF_Type * base,puf_key_index_register_t keyIndex,const uint8_t * userKey,size_t userKeySize,uint8_t * keyCode,size_t keyCodeSize)528 status_t PUF_SetUserKey(PUF_Type *base,
529                         puf_key_index_register_t keyIndex,
530                         const uint8_t *userKey,
531                         size_t userKeySize,
532                         uint8_t *keyCode,
533                         size_t keyCodeSize)
534 {
535     status_t status                = kStatus_Fail;
536     uint32_t *keyCodeAligned       = NULL;
537     const uint32_t *userKeyAligned = NULL;
538     register uint32_t temp32       = 0;
539 
540     /* check if SET KEY is allowed */
541     if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWSETKEY_MASK))
542     {
543         return kStatus_Fail;
544     }
545 
546     /* only work with aligned keyCode */
547     if (0U != (0x3u & (uintptr_t)keyCode))
548     {
549         return kStatus_InvalidArgument;
550     }
551 
552     /* Check that userKeySize is in the correct range and that it is multiple of 8 */
553     if ((userKeySize < (uint32_t)kPUF_KeySizeMin) || (userKeySize > (uint32_t)kPUF_KeySizeMax) ||
554         (0U != (userKeySize & 0x7U)))
555     {
556         return kStatus_InvalidArgument;
557     }
558 
559     /* check that keyCodeSize is correct for given userKeySize */
560     if (keyCodeSize < PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(userKeySize))
561     {
562         return kStatus_InvalidArgument;
563     }
564 
565     if ((uint32_t)keyIndex > (uint32_t)kPUF_KeyIndexMax)
566     {
567         return kStatus_InvalidArgument;
568     }
569 
570     keyCodeAligned = (uint32_t *)(uintptr_t)keyCode;
571     userKeyAligned = (const uint32_t *)(uintptr_t)userKey;
572 
573     /* program the key size and index */
574     base->KEYSIZE  = userKeySize >> 3; /* convert to 64-bit blocks */
575     base->KEYINDEX = (uint32_t)keyIndex;
576 
577     /* We have to store the user key on index 0 swaped for HW bus */
578     if (keyIndex == kPUF_KeyIndex_00)
579     {
580         userKeyAligned = userKeyAligned + (userKeySize / sizeof(uint32_t));
581     }
582 
583     /* begin */
584     base->CTRL = PUF_CTRL_SETKEY_MASK;
585 
586     /* wait till command is accepted */
587     while (0U == (base->STAT & (PUF_STAT_BUSY_MASK | PUF_STAT_ERROR_MASK)))
588     {
589     }
590 
591     /* while busy write UK and read KC */
592     while (0U != (base->STAT & PUF_STAT_BUSY_MASK))
593     {
594         if (0U != (PUF_STAT_KEYINREQ_MASK & base->STAT))
595         {
596             if (userKeySize >= sizeof(uint32_t))
597             {
598 #if defined(LPC54S018_SERIES)
599                 if (keyIndex == kPUF_KeyIndex_00)
600                 {
601                     userKeyAligned--;
602                     temp32 = *userKeyAligned;
603                     userKeySize -= sizeof(uint32_t);
604                 }
605 #else
606                 if (keyIndex == kPUF_KeyIndex_00)
607                 {
608                     userKeyAligned--;
609                     temp32 = __REV(*userKeyAligned);
610                     userKeySize--;
611                 }
612 #endif /* defined(LPC54S018_SERIES) */
613                 else if (keyIndex != kPUF_KeyIndex_00)
614                 {
615                     temp32 = *userKeyAligned;
616                     userKeyAligned++;
617                     userKeySize -= sizeof(uint32_t);
618                 }
619                 else
620                 {
621                     /* Intentional empty */
622                 }
623             }
624             base->KEYINPUT = temp32;
625         }
626 
627         if (0U != (PUF_STAT_CODEOUTAVAIL_MASK & base->STAT))
628         {
629             temp32 = base->CODEOUTPUT;
630             if (keyCodeSize >= sizeof(uint32_t))
631             {
632                 *keyCodeAligned = temp32;
633                 keyCodeAligned++;
634                 keyCodeSize -= sizeof(uint32_t);
635             }
636         }
637     }
638 
639     /* get status */
640     if (0U != (base->STAT & PUF_STAT_SUCCESS_MASK))
641     {
642         status = kStatus_Success;
643     }
644 
645     return status;
646 }
647 
puf_getHwKey(PUF_Type * base,const uint8_t * keyCode,size_t keyCodeSize)648 static status_t puf_getHwKey(PUF_Type *base, const uint8_t *keyCode, size_t keyCodeSize)
649 {
650     status_t status          = kStatus_Fail;
651     uint32_t *keyCodeAligned = NULL;
652     register uint32_t temp32 = 0;
653 
654     keyCodeAligned = (uint32_t *)(uintptr_t)keyCode;
655 
656     /* begin */
657     base->CTRL = PUF_CTRL_GETKEY_MASK;
658 
659     /* wait till command is accepted */
660     while (0U == (base->STAT & (PUF_STAT_BUSY_MASK | PUF_STAT_ERROR_MASK)))
661     {
662     }
663 
664     /* while busy send KC, key is reconstructed to HW bus */
665     while (0U != (base->STAT & PUF_STAT_BUSY_MASK))
666     {
667         if (0U != (PUF_STAT_CODEINREQ_MASK & base->STAT))
668         {
669             if (keyCodeSize >= sizeof(uint32_t))
670             {
671                 temp32 = *keyCodeAligned;
672                 keyCodeAligned++;
673                 keyCodeSize -= sizeof(uint32_t);
674             }
675             base->CODEINPUT = temp32;
676         }
677     }
678 
679     /* get status */
680     if (0U != (base->STAT & PUF_STAT_SUCCESS_MASK))
681     {
682         status = kStatus_Success;
683     }
684 
685     return status;
686 }
687 
688 /*!
689  * brief Reconstruct hw bus key from a key code
690  *
691  * The digital fingerprint generated during the Start operation and the KC
692  * generated during a Set Key operation (Set intrinsic key or Set user key) are used to retrieve a stored key. This
693  * operation needs to be done every time a key is needed.
694  * This function accepts only Key Codes created for PUF index register kPUF_KeyIndex_00.
695  * Such a key is output directly to a dedicated hardware bus. The reconstructed key is not exposed to system memory.
696  *
697  * param base PUF peripheral base address
698  * param keyCode Word aligned address of the input key code.
699  * param keyCodeSize Size of the keyCode buffer in bytes. Shall be PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize).
700  * param keySlot key slot to output on hw bus. Parameter is ignored on devices with less than two key slots.
701  * param keyMask key masking value. Shall be random for each POR/reset. Value does not have to be cryptographicaly
702  * secure.
703  * return Status of get key operation.
704  */
PUF_GetHwKey(PUF_Type * base,const uint8_t * keyCode,size_t keyCodeSize,puf_key_slot_t keySlot,uint32_t keyMask)705 status_t PUF_GetHwKey(
706     PUF_Type *base, const uint8_t *keyCode, size_t keyCodeSize, puf_key_slot_t keySlot, uint32_t keyMask)
707 {
708     status_t status = kStatus_Fail;
709     uint32_t keyIndex;
710 
711     /* check if GET KEY is allowed */
712     if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWGETKEY_MASK))
713     {
714         return kStatus_Fail;
715     }
716 
717     /* only work with aligned keyCode */
718     if (0U != (0x3u & (uintptr_t)keyCode))
719     {
720         return kStatus_Fail;
721     }
722 
723     /* check that keyCodeSize is at least PUF_MIN_KEY_CODE_SIZE */
724     if (keyCodeSize < PUF_MIN_KEY_CODE_SIZE)
725     {
726         return kStatus_InvalidArgument;
727     }
728 
729     keyIndex = (uint32_t)(0x0Fu & (uint32_t)keyCode[1]);
730 
731     /* check the Key Code header byte 1. index must be zero for the hw key. */
732     if (kPUF_KeyIndex_00 != (puf_key_index_register_t)keyIndex)
733     {
734         return kStatus_Fail;
735     }
736 
737 #if defined(PUF_KEYMASK_COUNT) && (PUF_KEYMASK_COUNT > 0)
738     volatile uint32_t *keyMask_reg = NULL;
739     uint32_t regVal                = ((uint32_t)2U << ((uint32_t)2U * (uint32_t)keySlot));
740 
741     switch (keySlot)
742     {
743         case kPUF_KeySlot0:
744             keyMask_reg = &base->KEYMASK[0];
745             break;
746 
747         case kPUF_KeySlot1:
748             keyMask_reg = &base->KEYMASK[1];
749             break;
750 #if (PUF_KEYMASK_COUNT > 2)
751         case kPUF_KeySlot2:
752             keyMask_reg = &base->KEYMASK[2];
753             break;
754 
755         case kPUF_KeySlot3:
756             keyMask_reg = &base->KEYMASK[3];
757             break;
758 #endif /* PUF_KEYMASK_COUNT > 2 */
759         default:
760             status = kStatus_InvalidArgument;
761             break;
762     }
763 #endif /* PUF_KEYMASK_COUNT */
764 
765     if (status != kStatus_InvalidArgument)
766     {
767 #if defined(PUF_KEYMASK_COUNT) && (PUF_KEYMASK_COUNT > 0)
768         base->KEYRESET  = regVal;
769         base->KEYENABLE = regVal;
770         *keyMask_reg    = keyMask;
771 #endif /* FSL_FEATURE_PUF_HAS_KEYSLOTS */
772 
773         status = puf_getHwKey(base, keyCode, keyCodeSize);
774 
775 #if defined(FSL_FEATURE_PUF_HAS_SHIFT_STATUS) && (FSL_FEATURE_PUF_HAS_SHIFT_STATUS > 0)
776         size_t keyWords = 0;
777 
778         if (status == kStatus_Success)
779         {
780             /* if the corresponding shift count does not match, return fail anyway */
781             keyWords = ((((size_t)keyCode[3]) * 2U) - 1u) << ((size_t)keySlot << 2U);
782             if (keyWords != ((0x0FUL << ((uint32_t)keySlot << 2U)) & base->SHIFT_STATUS))
783             {
784                 status = kStatus_Fail;
785             }
786         }
787 #elif defined(PUF_IDXBLK_SHIFT_IND_KEY0_MASK) && PUF_IDXBLK_SHIFT_IND_KEY0_MASK
788         size_t keyWords = 0;
789 
790         if (status == kStatus_Success)
791         {
792             /* if the corresponding shift count does not match, return fail anyway */
793             keyWords = ((((size_t)keyCode[3]) * 2U) - 1u) << ((size_t)keySlot << 2U);
794             if (keyWords != ((0x0FUL << ((uint32_t)keySlot << 2U)) & base->IDXBLK_SHIFT))
795             {
796                 status = kStatus_Fail;
797             }
798         }
799 #endif /* FSL_FEATURE_PUF_HAS_SHIFT_STATUS || PUF_IDXBLK_SHIFT_IND_KEY0_MASK */
800     }
801 
802     return status;
803 }
804 
805 /*!
806  * brief Checks if Get Key operation is allowed.
807  *
808  * This function returns true if get key operation is allowed.
809  *
810  * param base PUF peripheral base address
811  * return true if get key operation is allowed
812  */
PUF_IsGetKeyAllowed(PUF_Type * base)813 bool PUF_IsGetKeyAllowed(PUF_Type *base)
814 {
815     /* check if GET KEY is allowed */
816     if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWGETKEY_MASK))
817     {
818         return false;
819     }
820 
821     return true;
822 }
823 
824 /*!
825  * brief Reconstruct key from a key code
826  *
827  * The digital fingerprint generated during the Start operation and the KC
828  * generated during a Set Key operation (Set intrinsic key or Set user key) are used to retrieve a stored key. This
829  * operation needs to be done every time a key is needed.
830  * This function accepts only Key Codes created for PUF index registers kPUF_KeyIndex_01 to kPUF_KeyIndex_15.
831  *
832  * param base PUF peripheral base address
833  * param keyCode Word aligned address of the input key code.
834  * param keyCodeSize Size of the keyCode buffer in bytes. Shall be PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize).
835  * param[out] key Word aligned address of output key.
836  * param keySize Size of the output key in bytes.
837  * return Status of get key operation.
838  */
PUF_GetKey(PUF_Type * base,const uint8_t * keyCode,size_t keyCodeSize,uint8_t * key,size_t keySize)839 status_t PUF_GetKey(PUF_Type *base, const uint8_t *keyCode, size_t keyCodeSize, uint8_t *key, size_t keySize)
840 {
841     status_t status          = kStatus_Fail;
842     uint32_t *keyCodeAligned = NULL;
843     uint32_t *keyAligned     = NULL;
844     uint32_t keyIndex;
845     register uint32_t temp32 = 0;
846 
847     /* check if GET KEY is allowed */
848     if (0x0u == (base->ALLOW & PUF_ALLOW_ALLOWGETKEY_MASK))
849     {
850         return kStatus_Fail;
851     }
852 
853     /* only work with aligned keyCode */
854     if (0U != (0x3u & (uintptr_t)keyCode))
855     {
856         return kStatus_Fail;
857     }
858 
859     /* only work with aligned key */
860     if (0U != (0x3u & (uintptr_t)key))
861     {
862         return kStatus_Fail;
863     }
864 
865     /* check that keyCodeSize is correct for given keySize */
866     if (keyCodeSize < PUF_GET_KEY_CODE_SIZE_FOR_KEY_SIZE(keySize))
867     {
868         return kStatus_InvalidArgument;
869     }
870 
871     keyIndex = (0x0Fu & (uint32_t)keyCode[1]);
872 
873     /* check the Key Code header byte 1. index must be non-zero for the register key. */
874     if (kPUF_KeyIndex_00 == (puf_key_index_register_t)keyIndex)
875     {
876         return kStatus_Fail;
877     }
878 
879     keyCodeAligned = (uint32_t *)(uintptr_t)keyCode;
880     keyAligned     = (uint32_t *)(uintptr_t)key;
881 
882     /* begin */
883     base->CTRL = PUF_CTRL_GETKEY_MASK;
884 
885     /* wait till command is accepted */
886     while (0U == (base->STAT & (PUF_STAT_BUSY_MASK | PUF_STAT_ERROR_MASK)))
887     {
888     }
889 
890     /* while busy send KC, read key */
891     while (0U != (base->STAT & PUF_STAT_BUSY_MASK))
892     {
893         if (0U != (PUF_STAT_CODEINREQ_MASK & base->STAT))
894         {
895             temp32 = 0;
896             if (keyCodeSize >= sizeof(uint32_t))
897             {
898                 temp32 = *keyCodeAligned;
899                 keyCodeAligned++;
900                 keyCodeSize -= sizeof(uint32_t);
901             }
902             base->CODEINPUT = temp32;
903         }
904 
905         if (0U != (PUF_STAT_KEYOUTAVAIL_MASK & base->STAT))
906         {
907             keyIndex = base->KEYOUTINDEX;
908             temp32   = base->KEYOUTPUT;
909             if (keySize >= sizeof(uint32_t))
910             {
911                 *keyAligned = temp32;
912                 keyAligned++;
913                 keySize -= sizeof(uint32_t);
914             }
915         }
916     }
917 
918     /* get status */
919     if ((keyIndex != 0U) && (0U != (base->STAT & PUF_STAT_SUCCESS_MASK)))
920     {
921         status = kStatus_Success;
922     }
923 
924     return status;
925 }
926 
927 /*!
928  * brief Zeroize PUF
929  *
930  * This function clears all PUF internal logic and puts the PUF to error state.
931  *
932  * param base PUF peripheral base address
933  * return Status of the zeroize operation.
934  */
PUF_Zeroize(PUF_Type * base)935 status_t PUF_Zeroize(PUF_Type *base)
936 {
937     status_t status = kStatus_Fail;
938 
939     /* zeroize command is always allowed */
940     base->CTRL = PUF_CTRL_ZEROIZE_MASK;
941 
942     /* check that command is accepted */
943     if ((0U != (base->STAT & PUF_STAT_ERROR_MASK)) && (0U == base->ALLOW))
944     {
945         status = kStatus_Success;
946     }
947 
948     return status;
949 }
950