Skip to content

Commit 5f5213b

Browse files
committed
Fixes for PUF ROT
1 parent 32ceedd commit 5f5213b

File tree

3 files changed

+193
-27
lines changed

3 files changed

+193
-27
lines changed

IDE/XilinxSDK/README.md

Lines changed: 135 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,15 +233,147 @@ Note: To generate a report of a boot.bin use the `bootgen_utility` or after 2022
233233
`bootgen -arch zynqmp -read BOOT.BIN`
234234
235235
236-
# CSU Support
236+
## CSU Support
237+
238+
The Configuration Security Unit (CSU) is a dedicate core that contains security functions like PUF, SHA3, RSA, Tamper Protection. These registers can only be accessed through the PMU, which is a separate dedicated core. If operating from LE2 or lower the calls must be done through the BL31 (TF-A) SIP service to elevate privledges.
239+
240+
Access to most CSU registers can be done by setting the `-DSECURE_ACCESS_VAL=1` build option.
237241
238-
Enabling PMU firmware support for access to the CSU.
239242
In PetaLinux menuconfig under PMU Configuration add compiler flag `-DSECURE_ACCESS_VAL=1`.
243+
240244
```sh
241245
petalinux-build -c pmufw
242-
petalinux-build
243246
```
244247

248+
### CSU PUF
249+
250+
The PUF (Physically Unclonable Function) provides a way to generate a unique key for encryption specific to the device. It is useful for wrapping other keys to pair/bind them and allows external storage of the encrypted key.
251+
252+
This feature is enabled with `CFLAGS_EXTRA+=-DCSU_PUF_ROT`.
253+
254+
For PUF functionality a patch must be applied to the PMUFW to enable access to the PUF registers. See `pm_mmio_access.c` patch below:
255+
256+
```
257+
+ /* CSU PUF Registers */
258+
+ {
259+
+ .startAddr = ( ( CSU_BASEADDR ) + 0X00004000 ),
260+
+ .endAddr = ( ( CSU_BASEADDR ) + 0X00004018 ),
261+
+ .access = MMIO_ACCESS_RW(IPI_PMU_0_IER_APU_MASK |
262+
+ IPI_PMU_0_IER_RPU_0_MASK |
263+
+ IPI_PMU_0_IER_RPU_1_MASK),
264+
+ },
265+
```
266+
267+
Example PUF Generation Output:
268+
269+
```
270+
wolfBoot Secure Boot
271+
Current EL: 2
272+
QSPI Init: Ref=300MHz, Div=8, Bus=37500000, IO=DMA
273+
Read FlashID Lower: Ret 0, 20 BB 22
274+
Read FlashID Upper: Ret 0, 20 BB 22
275+
PMUFW Ver: 1.1
276+
CSU ID 0x24738093, Ver 0x00000003
277+
Enabling JTAG
278+
JTAG Attached: status 0x3
279+
CSU Puf Register
280+
Ret 0, SyndromeSz 560, CHASH 0xA014DD88, AUX 0x00408A64
281+
462273FBECB98600E3D099415B30F1AF3DD6B29369102847EC61B708AB37AF2A6999596BC9071F84773142631BA2C1109C14FACC156B7343FB8436CE06292DB95B4C1941E6DC8F982404462DEFB91792076EC428D1C0C8A10F271E3B67F652F562885384B97717B0AA3B8B24CC0AD54D1641860355C343D0FE38E1F6D6F4289C38AEC5EFD1046C736423EF881DE0A04F64165B9D275E5050D91F3EBD9241FE67D55BEA336E46B174112F86361FB2AA78197C6BF5812533E4EC1E88BC7125366C5E8BE8B70483FE5FC144B9F608D72964690D6DE0E8E8B65C23D2B9ED8262DF77AC4E2EE67ABF18DC2EC452B0731B0E229CAD555BC61CF0FE26066F1E54C33C7DC7C86DC56BFFF391689F937CD3C565D4B28D68C74793562B4938D6FE5667644F247CEFCCC926A57B54048A4986E8AC9F1B7D673CC14C2CC5DDD4A548986BF925B938FF92D6F7D3A2CD1ACD3943C6A35CF9CFFD8A786682032D3826CFDBAD38FDCBFD2B3480A933CAAEB391685E58A0BBDECDF9B69A5D685AE0D93BAC6B55E9D447565FBFF68E35F12B779EBC5918E0A5CD3CE00C7B5AF833A33CACD0F871A2FB89218BC2F1F02F0B68CB65F9B122D5B5D72116F1F6ED111B87DEB7E1BC4873E5889C2C6915CD362B75DA211264CF66F093C368F37EC54721AAFA6313C5892514011CE9BFDD72C51FDEA7320377692A1AF8FD0D563A66E465AA9AD51BF91B2A5CE6178E517032D3786B1F714681339C2286BBE5E71B7334F923FABBFBEC382E2EF6880471BB13956
282+
```
283+
284+
### CSU JTAG Enable
285+
286+
When RSA authentication is enabled the JTAG feature is disabled in the PMU. To re-enable it (assuming eFuse allows it) build with `CFLAGS_EXTRA+=-DDEBUG_CSU=2` and apply the PMUFW patches below.
287+
288+
To patch the PMUFW from PetaLinux use the following steps (for 2022.1 or later):
289+
290+
Based on instructions from: https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/2587197506/Zynq+UltraScale+MPSoC+JTAG+Enable+in+U-Boot
291+
292+
`pim/project-spec/meta-user/recipes-bsp/embeddedsw/pmu-firmware_%.bbappend`:
293+
294+
```
295+
# Patch for PMUFW
296+
297+
SRC_URI_append = " file://0001-csu-regs.patch"
298+
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
299+
```
300+
301+
`pim/project-spec/meta-user/recipes-bsp/embeddedsw/files/0001-csu-regs.patch`:
302+
```
303+
diff --git a/lib/sw_apps/zynqmp_pmufw/src/pm_mmio_access.c b/lib/sw_apps/zynqmp_pmufw/src/pm_mmio_access.c
304+
index 73066576a5..ce9490916d 100644
305+
--- a/lib/sw_apps/zynqmp_pmufw/src/pm_mmio_access.c
306+
+++ b/lib/sw_apps/zynqmp_pmufw/src/pm_mmio_access.c
307+
@@ -99,6 +99,22 @@ static const PmAccessRegion pmAccessTable[] = {
308+
IPI_PMU_0_IER_RPU_1_MASK),
309+
},
310+
311+
+ /* WOLF: Adding DBG_LPD_CTRL and RST_LPD_DBG to support JTAG Enable in u-boot */
312+
+ {
313+
+ .startAddr = CRL_APB_DBG_LPD_CTRL,
314+
+ .endAddr = CRL_APB_DBG_LPD_CTRL,
315+
+ .access = MMIO_ACCESS_RW(IPI_PMU_0_IER_APU_MASK |
316+
+ IPI_PMU_0_IER_RPU_0_MASK |
317+
+ IPI_PMU_0_IER_RPU_1_MASK),
318+
+ },
319+
+ {
320+
+ .startAddr = CRL_APB_RST_LPD_DBG,
321+
+ .endAddr = CRL_APB_RST_LPD_DBG,
322+
+ .access = MMIO_ACCESS_RW(IPI_PMU_0_IER_APU_MASK |
323+
+ IPI_PMU_0_IER_RPU_0_MASK |
324+
+ IPI_PMU_0_IER_RPU_1_MASK),
325+
+ },
326+
+
327+
/* PMU's global Power Status register*/
328+
{
329+
.startAddr = PMU_GLOBAL_PWR_STATE,
330+
@@ -415,15 +431,24 @@ static const PmAccessRegion pmAccessTable[] = {
331+
IPI_PMU_0_IER_RPU_1_MASK),
332+
},
333+
334+
+ /* WOLF: separate CSU_JTAG_CHAIN_CFG so it can be made RW */
335+
/* CSU ier register*/
336+
{
337+
.startAddr = CSU_IER,
338+
- .endAddr = CSU_JTAG_CHAIN_CFG,
339+
+ .endAddr = CSU_IDR,
340+
.access = MMIO_ACCESS_WO(IPI_PMU_0_IER_APU_MASK |
341+
IPI_PMU_0_IER_RPU_0_MASK |
342+
IPI_PMU_0_IER_RPU_1_MASK),
343+
},
344+
345+
+ {
346+
+ .startAddr = CSU_JTAG_CHAIN_CFG,
347+
+ .endAddr = CSU_JTAG_CHAIN_CFG,
348+
+ .access = MMIO_ACCESS_RW(IPI_PMU_0_IER_APU_MASK |
349+
+ IPI_PMU_0_IER_RPU_0_MASK |
350+
+ IPI_PMU_0_IER_RPU_1_MASK),
351+
+ },
352+
+
353+
/* CSU idr register*/
354+
{
355+
.startAddr = CSU_IDR,
356+
@@ -504,6 +529,15 @@ static const PmAccessRegion pmAccessTable[] = {
357+
IPI_PMU_0_IER_RPU_1_MASK),
358+
},
359+
360+
+ /* CSU PUF Registers */
361+
+ {
362+
+ .startAddr = ( ( CSU_BASEADDR ) + 0X00004000 ),
363+
+ .endAddr = ( ( CSU_BASEADDR ) + 0X00004018 ),
364+
+ .access = MMIO_ACCESS_RW(IPI_PMU_0_IER_APU_MASK |
365+
+ IPI_PMU_0_IER_RPU_0_MASK |
366+
+ IPI_PMU_0_IER_RPU_1_MASK),
367+
+ },
368+
+
369+
/*CSU tamper-status register */
370+
{
371+
.startAddr = CSU_TAMPER_STATUS,
372+
```
373+
374+
Then rebuild PMUFW: `petalinux-build -c pmufw`
375+
376+
245377
## Post Quantum
246378

247379
### PQ XMSS

hal/zynq.c

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -288,30 +288,59 @@ void wc_Sha3_384_Free(wc_Sha3* sha)
288288
#endif
289289

290290
/* CSU PUF */
291-
#define PUF_REG_TIMEOUT 500000
291+
#ifdef CSU_PUF_ROT
292+
#define CSU_PUF_SYNDROME_WORDS 386
293+
#ifndef CSU_PUF_REG_TIMEOUT
294+
#define CSU_PUF_REG_TIMEOUT 500000
295+
#endif
296+
297+
static int csu_puf_wait_word(uint32_t* puf_status)
298+
{
299+
int ret = -1; /* timeout */
300+
uint32_t timeout = 0;
301+
302+
while (++timeout < CSU_PUF_REG_TIMEOUT) {
303+
*puf_status = pmu_mmio_read(CSU_PUF_STATUS);
304+
if ((*puf_status & CSU_PUF_STATUS_SYN_WRD_RDY_MASK) != 0) {
305+
ret = 0;
306+
break;
307+
}
308+
}
309+
return ret;
310+
}
311+
292312
int csu_puf_register(uint32_t* syndrome, uint32_t* syndromeSz, uint32_t* chash,
293313
uint32_t* aux)
294314
{
295315
int ret;
296-
uint32_t puf_status, timeout = 0, idx = 0;
316+
uint32_t reg32, puf_status = 0, idx = 0;
297317

298318
#if defined(DEBUG_CSU) && DEBUG_CSU >= 1
299319
wolfBoot_printf("CSU Puf Register\n");
300320
#endif
301321

302-
pmu_mmio_write(CSU_PUF_CFG0, CSU_PUF_CFG0_INIT);
303-
pmu_mmio_write(CSU_PUF_CFG1, CSU_PUF_CFG1_INIT);
304-
pmu_mmio_write(CSU_PUF_SHUTTER, CSU_PUF_SHUTTER_INIT);
305-
pmu_mmio_write(CSU_PUF_CMD, CSU_PUF_CMD_REGISTRATION);
306-
while (1) {
307-
/* Wait for PUF status done */
308-
while (((puf_status = pmu_mmio_read(CSU_PUF_STATUS))
309-
& CSU_PUF_STATUS_SYN_WRD_RDY_MASK) == 0
310-
&& ++timeout < PUF_REG_TIMEOUT);
311-
if (timeout == PUF_REG_TIMEOUT) {
312-
ret = -1; /* timeout */
322+
/* try a read from register to make sure PMU has permission */
323+
reg32 = pmu_mmio_read(CSU_PUF_SHUTTER);
324+
if (reg32 == 0) {
325+
wolfBoot_printf("PMUFW PUF Register access not enabled in "
326+
"pm_mmio_access pmAccessTable!\n");
327+
return -1;
328+
}
329+
330+
ret = pmu_mmio_write(CSU_PUF_CFG0, CSU_PUF_CFG0_INIT);
331+
if (ret == 0)
332+
ret = pmu_mmio_write(CSU_PUF_CFG1, CSU_PUF_CFG1_INIT);
333+
if (ret == 0)
334+
ret = pmu_mmio_write(CSU_PUF_SHUTTER, CSU_PUF_SHUTTER_INIT);
335+
if (ret == 0)
336+
ret = pmu_mmio_write(CSU_PUF_CMD, CSU_PUF_CMD_REGISTRATION);
337+
while (ret == 0) {
338+
/* wait for PUF word ready */
339+
puf_status = 0;
340+
ret = csu_puf_wait_word(&puf_status);
341+
if (ret != 0)
313342
break;
314-
}
343+
315344
if ((idx * 4) > *syndromeSz) {
316345
ret = -2; /* overrun */
317346
break;
@@ -341,14 +370,16 @@ int csu_puf_register(uint32_t* syndrome, uint32_t* syndromeSz, uint32_t* chash,
341370

342371
return ret;
343372
}
373+
#endif /* CSU_PUF_ROT */
344374

345-
#define CSU_PUF_SYNDROME_WORDS 386
346375
int csu_init(void)
347376
{
348-
int ret;
377+
int ret = 0;
378+
#ifdef CSU_PUF_ROT
349379
uint32_t syndrome[CSU_PUF_SYNDROME_WORDS];
350380
uint32_t syndromeSz = (uint32_t)sizeof(syndrome);
351381
uint32_t chash=0, aux=0;
382+
#endif
352383
uint32_t reg1 = pmu_mmio_read(CSU_IDCODE);
353384
uint32_t reg2 = pmu_mmio_read(CSU_VERSION);
354385

@@ -371,7 +402,9 @@ int csu_init(void)
371402
hal_delay_ms(500); /* give time for debugger to break */
372403
#endif
373404

405+
#ifdef CSU_PUF_ROT
374406
ret = csu_puf_register(syndrome, &syndromeSz, &chash, &aux);
407+
#endif
375408

376409
return ret;
377410
}

hal/zynq.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@
477477
#define CSU_PUF_CFG1 (CSU_BASE + 0x4008U)
478478
#define CSU_PUF_SHUTTER (CSU_BASE + 0x400CU)
479479
#define CSU_PUF_STATUS (CSU_BASE + 0x4010U)
480+
#define CSU_PUF_DBG (CSU_BASE + 0x4014U)
480481
#define CSU_PUF_WORD (CSU_BASE + 0x4018U)
481482

482483
#define CSU_PUF_CMD_CLEAR 0x6 /* Clear PUF status */
@@ -485,14 +486,14 @@
485486
#define CSU_PUF_CMD_REGISTRATION 0x1 /* Key registration */
486487

487488
#define CSU_PUF_CFG0_INIT 0x2
488-
#define CSU_PUF_CFG1_INIT 0x0C230090 /* 0x00080080 */
489-
#define CSU_PUF_SHUTTER_INIT 0x0100005E /* 0x01000100 */
490-
491-
#define CSU_PUF_STATUS_OVERFLOW_MASK 0x30000000 /* Overflow, if bits are not 0. Reduce SHUT[SOPEN] value. */
492-
#define CSU_PUF_STATUS_AUX_MASK 0x0FFFFFF0 /* During provisioning, auxiliary sundrome bits are stored here and must be written to the eFuse or boot image. */
493-
#define CSU_PUF_STATUS_KEY_RDY_MASK 0x00000008
494-
#define CSU_PUF_STATUS_KEY_ZERO_MASK 0x00000002 /* Indicates that the PUF key has been zeroized */
495-
#define CSU_PUF_STATUS_SYN_WRD_RDY_MASK 0x00000001 /* Indicates a syndrome word is ready in the PUF_WORD register. */
489+
#define CSU_PUF_CFG1_INIT 0x0C230090U /* 4K */
490+
#define CSU_PUF_SHUTTER_INIT 0x00100005E
491+
492+
#define CSU_PUF_STATUS_OVERFLOW_MASK (0x3U << 28) /* Overflow, if bits are not 0. Reduce SHUT[SOPEN] value. */
493+
#define CSU_PUF_STATUS_AUX_MASK (0xFFFFFFU << 4) /* During provisioning, auxiliary sundrome bits are stored here and must be written to the eFuse or boot image. */
494+
#define CSU_PUF_STATUS_KEY_RDY_MASK (0x1U << 3) /* Indicates that the key is ready */
495+
#define CSU_PUF_STATUS_KEY_ZERO_MASK (0x1U << 1) /* Indicates that the PUF key has been zeroized */
496+
#define CSU_PUF_STATUS_SYN_WRD_RDY_MASK (0x1U << 0) /* Indicates a syndrome word is ready in the PUF_WORD register */
496497

497498
/* SHA3 */
498499
#define CSU_SHA_START (CSU_BASE + 0x2000U)

0 commit comments

Comments
 (0)