diff --git a/IDE/XilinxSDK/README.md b/IDE/XilinxSDK/README.md index 42b92f9ee5..7bb11eda83 100644 --- a/IDE/XilinxSDK/README.md +++ b/IDE/XilinxSDK/README.md @@ -78,16 +78,7 @@ Note: If not using Position Independent Code (PIC) the linker script `ldscript.l ## Zynq UltraScale+ ARMv8 Crypto Extensions -To enable ARM assembly speedups for SHA: - -1) Add these build symbols: - -``` -WOLFSSL_ARMASM -WOLFSSL_ARMASM_INLINE -``` - -2) Add these compiler misc flags: `-mcpu=generic+crypto -mstrict-align -DWOLFSSL_AARCH64_NO_SQRMLSH` +By default the ARM assembly speedups for SHA will be enabled. This uses inline assembly in wolfcrypt/src/port/arm/ and the armb8 crypto extensions. To disable set `NO_ARM_ASM=1`. ## Generate signing key @@ -154,7 +145,7 @@ the_ROM_image: } ``` -You can also use exception level 3 or 1 depending on your needs. +You can use exception level 3, 2 or 1 depending on your needs. See hal/zynq.h options EL3_SECURE, EL2_HYPERVISOR and EL1_NONSECURE for enabled/disabling entry support for each. Default is support for EL2. From the workspace root: @@ -208,13 +199,12 @@ Hello World Successfully ran Hello World application ``` - ### Adding RSA Authentication 1. Generate keys: - * `bootgen.exe -generate_keys auth pem -arch zynqmp -image boot.bif` + * `bootgen.exe -generate_keys auth pem -arch zynqmp -image boot_auth.bif` 2. Create hash for primary key: - * `bootgen.exe -image boot.bif -arch zynqmp -w -o i BOOT.BIN -efuseppkbits ppkf_hash.txt` + * `bootgen.exe -image boot_auth.bif -arch zynqmp -w -o i BOOT.BIN -efuseppkbits ppkf_hash.txt` 3. Import example project for programming eFuses: * New BSP project (program efuses , ZCU102_hw_platform, standalone, CPU: PSU_cortexa53_0) * Goto Xilinx Board Support Packet Settings. @@ -224,7 +214,7 @@ Successfully ran Hello World application 4. Edit `xilskey_efuseps_zynqmp_input.h` * 433 `#define XSK_EFUSEPS_WRITE_PPK0_HASH TRUE` * 453 `#define XSK_EFUSEPS_PPK0_IS_SHA3 TRUE` - * 454 `#define XSK_EFUSEPS_PPK0_HASH "0000000000000000000000000000000000000000000000000000000000000000" /* from ppkf_hash.txt */`` + * 454 `#define XSK_EFUSEPS_PPK0_HASH "0000000000000000000000000000000000000000000000000000000000000000" /* from ppkf_hash.txt */` 5. Update boot.bif (see boot_auth.bif) ``` @@ -235,11 +225,199 @@ Successfully ran Hello World application ``` 6. Build “boot.bin” image: - * `bootgen -image boot.bif -arch zynqmp -o i BOOT.BIN -w` + * `bootgen -image boot_auth.bif -arch zynqmp -o i BOOT.BIN -w` + +Note: During testing add `[fsbl_config] bh_auth_enable` to allow skipping of the eFuse check of the PPK hash. In production the RSA_EN eFuses must be blown to force checking of the PPK hash. Note: To generate a report of a boot.bin use the `bootgen_utility` or after 2022.1 use `bootgen -read`: `bootgen -arch zynqmp -read BOOT.BIN` + +## CSU Support + +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. + +Access to most CSU registers can be done by setting the `-DSECURE_ACCESS_VAL=1` build option. + +In PetaLinux menuconfig under PMU Configuration add compiler flag `-DSECURE_ACCESS_VAL=1`. + +```sh +petalinux-build -c pmufw +``` + +### CSU PUF + +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. + +This feature is enabled with `CFLAGS_EXTRA+=-DCSU_PUF_ROT`. + +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: + +``` ++ /* CSU PUF Registers */ ++ { ++ .startAddr = ( ( CSU_BASEADDR ) + 0X00004000 ), ++ .endAddr = ( ( CSU_BASEADDR ) + 0X00004018 ), ++ .access = MMIO_ACCESS_RW(IPI_PMU_0_IER_APU_MASK | ++ IPI_PMU_0_IER_RPU_0_MASK | ++ IPI_PMU_0_IER_RPU_1_MASK), ++ }, +``` + +Example PUF Generation Output: + +``` +wolfBoot Secure Boot +Current EL: 2 +QSPI Init: Ref=300MHz, Div=8, Bus=37500000, IO=DMA +Read FlashID Lower: Ret 0, 20 BB 22 +Read FlashID Upper: Ret 0, 20 BB 22 +PMUFW Ver: 1.1 +CSU ID 0x24738093, Ver 0x00000003 +PUF Status 0x00000002 +eFuse SEC_CTRL 0x00000000 +eFuse PUF CHASH 0x00000000, AUX 0x00000000 +CSU Puf Register +Ret 0, Syndrome 1544, CHASH 0x9B7A8C30, AUX 0x005AE021 +4662F39BEC998700E2D299E15B30F1AF563FC596A3854ACE05FDA4FBC2AD32DF9B66E2081A55D8CA0CB84B88735B005548C0671BD561AE7A9FBB266E228368F6D1FD916C8D172572094E210826106B8C80AB1E8910647283DB22076560FC5E10C02C614F4EF80001B218501AD9D07580C2DB47E487940DB24615509EBE85B037AB2FCDE820661EAB45C345863735F64689AECCEAE783DC413052E615B231931E265EC00C15D8FCD2D83E9F8FC836178C0415587E683D48A7ADADC1B53E17743859CA5984A314D1CC85AF58226376E705AC6C2973ACCE05FF2263DBE951A2D0FFD9D218C57F1D1398640E5A3D03BB9478530035952642C40258AFEB196F0A6D130BC8C2E064C622AC9FA0827BBFCF35FCBAFC9593085D1D296F8446C3550784DECF964B4A65249E9A002A7CEE9886DBB7F33DC3A7404C66497218FF7762E4C81B048986BF9257968FF92D6F7D1AACB1A8CDE48E8ECDD8B7A74C3C16FF10FD00D119E3B5F4DB19854AF60C2B063CB26A3740FC8658425EB44F27B52CDD6C1A16E3C45394BA9629B0A8A0410979CA0ED488E787F36B4BC05E1CEBD8F5CFF6DAF3D3F8B885E6F0A616675DA0B748F3C4E334545920C3062113230741795AA97D4A32B7E1BC4953E588902C7915CD362B75DA33BB941B523932B172589E27759A924A857CD66EE0E02BE697188776E4A646F7A73203E769285BF9FD09562A67CC67E2EB6CC7D8F15C138991AC177030D9057750A70E0C4F6144A8412F436A8B952597D664BADF3997DC0249DB4ABF6355DEB09B7A8C300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009B7A8C30005AE021 +CSU Register PUF 0: 281ms +Regen: PUF Status 0x05AE0218 +CSU Regen PUF 0: 8ms +Red Key 32 +64F03AFD7D0C70D2591CDF34305F7B8A5BA4593C0A0E1B8C5ECDFF9F5900192C +Black IV 16 +D142AC7C560F158BA95A213100000000 +Black Key 32 +2599B8619240E98E264A0CE3CD42C58A9E3457F1982D1DEEE1FC75A1A1284C72 +``` + +Example .bif that includes the PUF helper data and black key/iv. This enables the CSU boot ROM to load up the black AES key for use with the CSU AES engine. + +``` +the_ROM_image: +{ + // Boot Header Authentication Enable + [fsbl_config] a53_x64, bh_auth_enable, puf4kmode, shutter=0x0100005E, pufhd_bh + [keysrc_encryption] bh_blk_key + [puf_file] helperdata.txt + [bh_key_iv] black_iv.txt + [bh_keyfile] black_key.txt + + // Use the primary public key 0 and secondary public key id 0 + [auth_params] ppk_select=0; spk_id=0x00000000 + + // primary and secondary secret (private) keys + [pskfile] pskf.pem + [sskfile] sskf.pem + + [bootloader, authentication=rsa, encryption=aes, destination_cpu=a53-0] zynqmp_fsbl.elf + [destination_cpu=pmu, authentication=rsa] pmufw.elf + [destination_device=pl, authentication=rsa] system.bit + [destination_cpu=a53-0, authentication=rsa, exception_level=el-3, trustzone] bl31.elf + [destination_cpu=a53-0, authentication=rsa, load=0x00100000] system.dtb + [destination_cpu=a53-0, authentication=rsa, exception_level=el-2] wolfboot.elf + [destination_cpu=a53-0, partition_owner=uboot, offset=0x800000] hello_world_v1_signed.bin +} +``` + +Generated BOOT.BIN using: `bootgen -image bootgen.bif -arch zynqmp -o BOOT.BIN -w -p xzcu9eg` + +This will create an encryption key file `zynqmp_fsbl.nky`. + + +### CSU JTAG Enable + +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. + +To patch the PMUFW from PetaLinux use the following steps (for 2022.1 or later): + +Based on instructions from: https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/2587197506/Zynq+UltraScale+MPSoC+JTAG+Enable+in+U-Boot + +`pim/project-spec/meta-user/recipes-bsp/embeddedsw/pmu-firmware_%.bbappend`: + +``` +# Patch for PMUFW + +SRC_URI_append = " file://0001-csu-regs.patch" +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" +``` + +`pim/project-spec/meta-user/recipes-bsp/embeddedsw/files/0001-csu-regs.patch`: +``` +diff --git a/lib/sw_apps/zynqmp_pmufw/src/pm_mmio_access.c b/lib/sw_apps/zynqmp_pmufw/src/pm_mmio_access.c +index 73066576a5..ce9490916d 100644 +--- a/lib/sw_apps/zynqmp_pmufw/src/pm_mmio_access.c ++++ b/lib/sw_apps/zynqmp_pmufw/src/pm_mmio_access.c +@@ -99,6 +99,22 @@ static const PmAccessRegion pmAccessTable[] = { + IPI_PMU_0_IER_RPU_1_MASK), + }, + ++ /* WOLF: Adding DBG_LPD_CTRL and RST_LPD_DBG to support JTAG Enable in u-boot */ ++ { ++ .startAddr = CRL_APB_DBG_LPD_CTRL, ++ .endAddr = CRL_APB_DBG_LPD_CTRL, ++ .access = MMIO_ACCESS_RW(IPI_PMU_0_IER_APU_MASK | ++ IPI_PMU_0_IER_RPU_0_MASK | ++ IPI_PMU_0_IER_RPU_1_MASK), ++ }, ++ { ++ .startAddr = CRL_APB_RST_LPD_DBG, ++ .endAddr = CRL_APB_RST_LPD_DBG, ++ .access = MMIO_ACCESS_RW(IPI_PMU_0_IER_APU_MASK | ++ IPI_PMU_0_IER_RPU_0_MASK | ++ IPI_PMU_0_IER_RPU_1_MASK), ++ }, ++ + /* PMU's global Power Status register*/ + { + .startAddr = PMU_GLOBAL_PWR_STATE, +@@ -415,15 +431,24 @@ static const PmAccessRegion pmAccessTable[] = { + IPI_PMU_0_IER_RPU_1_MASK), + }, + ++ /* WOLF: separate CSU_JTAG_CHAIN_CFG so it can be made RW */ + /* CSU ier register*/ + { + .startAddr = CSU_IER, +- .endAddr = CSU_JTAG_CHAIN_CFG, ++ .endAddr = CSU_IDR, + .access = MMIO_ACCESS_WO(IPI_PMU_0_IER_APU_MASK | + IPI_PMU_0_IER_RPU_0_MASK | + IPI_PMU_0_IER_RPU_1_MASK), + }, + ++ { ++ .startAddr = CSU_JTAG_CHAIN_CFG, ++ .endAddr = CSU_JTAG_CHAIN_CFG, ++ .access = MMIO_ACCESS_RW(IPI_PMU_0_IER_APU_MASK | ++ IPI_PMU_0_IER_RPU_0_MASK | ++ IPI_PMU_0_IER_RPU_1_MASK), ++ }, ++ + /* CSU idr register*/ + { + .startAddr = CSU_IDR, +@@ -504,6 +529,15 @@ static const PmAccessRegion pmAccessTable[] = { + IPI_PMU_0_IER_RPU_1_MASK), + }, + ++ /* CSU PUF Registers */ ++ { ++ .startAddr = ( ( CSU_BASEADDR ) + 0X00004000 ), ++ .endAddr = ( ( CSU_BASEADDR ) + 0X00004018 ), ++ .access = MMIO_ACCESS_RW(IPI_PMU_0_IER_APU_MASK | ++ IPI_PMU_0_IER_RPU_0_MASK | ++ IPI_PMU_0_IER_RPU_1_MASK), ++ }, ++ + /*CSU tamper-status register */ + { + .startAddr = CSU_TAMPER_STATUS, +``` + +Then rebuild PMUFW: `petalinux-build -c pmufw` + + ## Post Quantum ### PQ XMSS diff --git a/arch.mk b/arch.mk index ac620a0f75..0e74a91744 100644 --- a/arch.mk +++ b/arch.mk @@ -75,6 +75,12 @@ ifeq ($(ARCH),AARCH64) # Support detection and skip of U-Boot legacy header */ CFLAGS+=-DWOLFBOOT_UBOOT_LEGACY CFLAGS+=-DWOLFBOOT_DUALBOOT + + ifeq ($(HW_SHA3),1) + # Use HAL for hash (see zynqmp.c) + HASH_HAL=1 + CFLAGS+=-DWOLFBOOT_ZYNQMP_CSU + endif else ifeq ($(TARGET),nxp_ls1028a) ARCH_FLAGS=-mcpu=cortex-a72+crypto -march=armv8-a+crypto -mtune=cortex-a72 diff --git a/config/examples/zynqmp.config b/config/examples/zynqmp.config index dd81067ee4..d04a233fc6 100644 --- a/config/examples/zynqmp.config +++ b/config/examples/zynqmp.config @@ -8,6 +8,13 @@ SIGN?=RSA4096 HASH?=SHA3 IMAGE_HEADER_SIZE?=1024 +# Hashing Option +# 1. ARMv8+Crypto Assembly: HW_SHA3=0 and NO_ARM_ASM=0 (default) +# 2. CSU SHA3 hardware acceleration HW_SHA3=1 and NO_ARM_ASM=1 +# 3. C Only HW_SHA3=0 and NO_ARM_ASM=1 +NO_ARM_ASM?=0 +HW_SHA3?=0 + # XMSS/XMSS^MT is a post-quantum, stateful, hash-based signature scheme. # Use the helper script `tools/xmss/xmss_siglen.sh` # to calculate your signature length given an xmss parameter string. @@ -36,14 +43,13 @@ CFLAGS_EXTRA+=-DDEBUG_ZYNQ=1 VTOR?=1 CORTEX_M0?=0 NO_ASM?=0 -NO_ARM_ASM?=0 ALLOW_DOWNGRADE?=0 NVM_FLASH_WRITEONCE?=0 V?=0 SPMATH?=1 RAM_CODE?=0 DUALBANK_SWAP?=0 -PKA?=1 +PKA?=0 WOLFTPM?=0 EXT_FLASH?=1 SPI_FLASH?=0 diff --git a/docs/Targets.md b/docs/Targets.md index 7cd79bef23..0a50cd9c40 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -19,7 +19,7 @@ This README describes configuration of supported targets. * [NXP LPC54xxx](#nxp-lpc54xxx) * [NXP LS1028A](#nxp-ls1028a) * [NXP MCXA153](#nxp-mcxa153) -* [NXP MCXW716C](#nxp-mcxw716c) +* [NXP MCXW716](#nxp-mcxw716) * [NXP P1021 PPC](#nxp-qoriq-p1021-ppc) * [NXP T1024 PPC](#nxp-qoriq-t1024-ppc) * [NXP T2080 PPC](#nxp-qoriq-t2080-ppc) @@ -1296,7 +1296,7 @@ My board version is: 0xA020D3 Trying partition 0 at 0x140000 Boot partition: 0x140000 (size 14901760, version 0x1) .... -```` +``` Note: Now, integrity-check takes 2 - 3 minutes to complete before running Linux kernel. o Kernel panic after wolfboot message @@ -1399,38 +1399,6 @@ qemu-system-aarch64 -machine xlnx-zcu102 -cpu cortex-a53 -serial stdio -display ``` -### Testing with qemu-system-aarch64 - -* Build wolfboot using the example configuration (RSA4096, SHA3) - -``` -cp config/examples/raspi3.config .config -make clean -make wolfboot.bin CROSS_COMPILE=aarch64-linux-gnu- -``` - -* Sign Linux kernel image -``` -make keytools -./tools/keytools/sign --rsa4096 --sha3 Image wolfboot_signing_private_key.der 1 -``` - -* Compose the image - -``` -tools/bin-assemble/bin-assemble wolfboot_linux_raspi.bin 0x0 wolfboot.bin \ - 0xc0000 Image_v1_signed.bin -dd if=bcm2710-rpi-3-b.dtb of=wolfboot_linux_raspi.bin bs=1 seek=128K conv=notrunc -``` - -* Test boot using qemu - -``` -qemu-system-aarch64 -M raspi3b -m 1024 -serial stdio -kernel wolfboot_linux_raspi.bin -cpu cortex-a53 -``` - - - #### Signing Zynq `tools/keytools/sign --rsa4096 --sha3 /srv/linux-rpi4/vmlinux.bin wolfboot_signing_private_key.der 1` diff --git a/hal/zynq.c b/hal/zynq.c index 3d1e95b0a4..b73ecb6172 100644 --- a/hal/zynq.c +++ b/hal/zynq.c @@ -71,6 +71,8 @@ typedef struct QspiDev { } QspiDev_t; static QspiDev_t mDev; +static uint32_t pmuVer; +#define PMUFW_MIN_VER 0x10001 /* v1.1*/ /* forward declarations */ static int qspi_wait_ready(QspiDev_t* dev); @@ -82,6 +84,10 @@ static int test_ext_flash(QspiDev_t* dev); /* asm function */ extern void flush_dcache_range(unsigned long start, unsigned long stop); +extern unsigned int current_el(void); + +void hal_delay_ms(uint64_t ms); +uint64_t hal_timer_ms(void); #ifdef DEBUG_UART void uart_init(void) @@ -131,18 +137,547 @@ void uart_write(const char* buf, uint32_t sz) } #endif /* DEBUG_UART */ +/* This struct defines the way the registers are stored on the stack during an + * exception. */ +struct pt_regs { + uint64_t elr; + uint64_t regs[8]; +}; + +/* + * void smc_call(arg0, arg1...arg7) + * + * issue the secure monitor call + * + * x0~x7: input arguments + * x0~x3: output arguments + */ +static void smc_call(struct pt_regs *args) +{ + asm volatile( + "ldr x0, %0\n" + "ldr x1, %1\n" + "ldr x2, %2\n" + "ldr x3, %3\n" + "ldr x4, %4\n" + "ldr x5, %5\n" + "ldr x6, %6\n" + "smc #0\n" + "str x0, %0\n" + "str x1, %1\n" + "str x2, %2\n" + "str x3, %3\n" + : "+m" (args->regs[0]), "+m" (args->regs[1]), + "+m" (args->regs[2]), "+m" (args->regs[3]) + : "m" (args->regs[4]), "m" (args->regs[5]), + "m" (args->regs[6]) + : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", + "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17"); +} + +#define PM_ARGS_CNT 8 +#define PM_SIP_SVC 0xC2000000 +#define PM_GET_API_VERSION 0x01 +#define PM_SECURE_SHA 0x1A +#define PM_SECURE_RSA 0x1B +#define PM_MMIO_WRITE 0x13 +#define PM_MMIO_READ 0x14 + +/* AES */ +/* requires PMU built with -DENABLE_SECURE_VAL=1 */ +#define PM_SECURE_AES 0x2F +typedef struct pmu_aes { + uint64_t src; /* source address */ + uint64_t iv; /* initialization vector address */ + uint64_t key; /* key address */ + uint64_t dst; /* destination address */ + uint64_t size; /* size */ + uint64_t op; /* operation: 0=Decrypt, 1=Encrypt */ + uint64_t keySrc; /* key source 0=KUP, 1=Device Key, 2=Use PUF (do regen) */ +} pmu_aes; + +/* EFUSE */ +/* requires PMU built with -DENABLE_EFUSE_ACCESS=1 */ +#define PM_EFUSE_ACCESS 0x35 +typedef struct pmu_efuse { + uint64_t src; /* adress of data buffer */ + uint32_t size; /* size in words */ + uint32_t offset; /* offset */ + uint32_t flag; /* 0: to read efuse, 1: to write efuse */ + uint32_t pufUserFuse;/* 0: PUF HD, 1: eFuses for User Data */ +} pmu_efuse; + +/* Secure Monitor Call (SMC) to BL31 Silicon Provider (SIP) service, + * which is the PMU Firmware */ +static int pmu_request(uint32_t api_id, + uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t *ret_payload) +{ + struct pt_regs regs; + + regs.regs[0] = PM_SIP_SVC | api_id; + regs.regs[1] = ((uint64_t)arg1 << 32) | arg0; + regs.regs[2] = ((uint64_t)arg3 << 32) | arg2; + + smc_call(®s); + + if (ret_payload != NULL) { + ret_payload[0] = (uint32_t)(regs.regs[0]); + ret_payload[1] = (uint32_t)(regs.regs[0] >> 32); + ret_payload[2] = (uint32_t)(regs.regs[1]); + ret_payload[3] = (uint32_t)(regs.regs[1] >> 32); + ret_payload[4] = (uint32_t)(regs.regs[2]); + ret_payload[5] = (uint32_t)(regs.regs[2] >> 32); + ret_payload[6] = (uint32_t)(regs.regs[3]); + ret_payload[7] = (uint32_t)(regs.regs[3] >> 32); + } + return (ret_payload != NULL) ? ret_payload[0] : 0; +} + + +uint32_t pmu_get_version(void) +{ + uint32_t ret_payload[PM_ARGS_CNT]; + memset(ret_payload, 0, sizeof(ret_payload)); + pmu_request(PM_GET_API_VERSION, 0, 0, 0, 0, ret_payload); + return ret_payload[1]; +} + +/* Aligned data buffer for DMA */ +#define EFUSE_MAX_BUFSZ (sizeof(pmu_efuse) + 48 /* SHA3-384 Digest */) +static uint8_t XALIGNED(32) efuseBuf[EFUSE_MAX_BUFSZ]; + +uint32_t pmu_efuse_read(uint32_t offset, uint32_t* data, uint32_t size) +{ + pmu_efuse* efuseCmd = (pmu_efuse*)efuseBuf; + uint8_t* efuseData = (efuseBuf + sizeof(pmu_efuse)); + uint64_t efuseCmdPtr = (uint64_t)efuseCmd; + uint32_t ret_payload[PM_ARGS_CNT]; + memset(ret_payload, 0, sizeof(ret_payload)); + memset(efuseBuf, 0, sizeof(efuseBuf)); + efuseCmd->src = (uint64_t)efuseData; + efuseCmd->offset = (offset & 0xFF); /* offset is only the last 0xFF bits */ + efuseCmd->size = (size/sizeof(uint32_t)); /* number of 32-bit words */ + pmu_request(PM_EFUSE_ACCESS, (efuseCmdPtr >> 32), (efuseCmdPtr & 0xFFFFFFFF), + 0, 0, ret_payload); + memcpy(data, efuseData, size); + return ret_payload[0]; /* 0=Success, 30=No Access */ +} + +uint32_t pmu_mmio_read(uint32_t addr) +{ + uint32_t ret_payload[PM_ARGS_CNT]; + memset(ret_payload, 0, sizeof(ret_payload)); + pmu_request(PM_MMIO_READ, addr, 0, 0, 0, ret_payload); + return ret_payload[1]; +} + +uint32_t pmu_mmio_writemask(uint32_t addr, uint32_t mask, uint32_t val) +{ + uint32_t ret_payload[PM_ARGS_CNT]; + memset(ret_payload, 0, sizeof(ret_payload)); + pmu_request(PM_MMIO_WRITE, addr, mask, val, 0, ret_payload); + return ret_payload[0]; /* 0=Success, 30=No Access */ +} + +uint32_t pmu_mmio_write(uint32_t addr, uint32_t val) +{ + return pmu_mmio_writemask(addr, 0xFFFFFFFF, val); +} + +int pmu_mmio_wait(uint32_t addr, uint32_t wait_mask, uint32_t wait_val, + uint32_t tries) +{ + uint32_t regval, timeout = 0; + while ((((regval = pmu_mmio_read(addr)) & wait_mask) != wait_val) + && ++timeout < tries); + return (timeout < tries) ? 0 : -1; +} + +#ifdef WOLFBOOT_ZYNQMP_CSU + +#ifdef WOLFBOOT_HASH_SHA3_384 +#include +#define XSECURE_SHA3_INIT 1U +#define XSECURE_SHA3_UPDATE 2U +#define XSECURE_SHA3_FINAL 4U +static uint32_t csu_sha3(uint64_t addr, uint32_t sz, uint32_t flags) +{ + uint32_t ret_payload[PM_ARGS_CNT]; + memset(ret_payload, 0, sizeof(ret_payload)); + pmu_request(PM_SECURE_SHA, (addr >> 32), (addr & 0xFFFFFFFF), sz, flags, + ret_payload); + return ret_payload[0]; +} + +int wc_InitSha3_384(wc_Sha3* sha, void* heap, int devId) +{ + (void)sha; + (void)heap; + (void)devId; + return csu_sha3(0, 0, XSECURE_SHA3_INIT); +} +int wc_Sha3_384_Update(wc_Sha3* sha, const byte* data, word32 len) +{ + (void)sha; + flush_dcache_range( + (unsigned long)data, + (unsigned long)data + len); + return csu_sha3((uint64_t)data, len, XSECURE_SHA3_UPDATE); +} +int wc_Sha3_384_Final(wc_Sha3* sha, byte* out) +{ + (void)sha; + flush_dcache_range( + (unsigned long)out, + (unsigned long)out + WC_SHA3_384_DIGEST_SIZE); + return csu_sha3((uint64_t)out, 0, XSECURE_SHA3_FINAL); +} +void wc_Sha3_384_Free(wc_Sha3* sha) +{ + (void)sha; +} +#else +# error HW_SHA3=1 only supported with HASH=SHA3 +#endif + +/* CSU PUF */ +#ifdef CSU_PUF_ROT +/* 1544 bytes is fixed size for boot header used by CSU ROM */ +#define CSU_PUF_SYNDROME_WORDS 386 +#ifndef CSU_PUF_REG_TRIES +#define CSU_PUF_REG_TRIES 500000 +#endif + +int csu_puf_register(uint32_t* syndrome, uint32_t* chash, uint32_t* aux) +{ + int ret; + uint32_t reg32, puf_status = 0, idx = 0; + +#if defined(DEBUG_CSU) && DEBUG_CSU >= 1 + wolfBoot_printf("CSU Puf Register\n"); +#endif + + /* try a read from register to make sure PMU has permission */ + reg32 = pmu_mmio_read(CSU_PUF_SHUTTER); + if (reg32 == 0) { + wolfBoot_printf("PMUFW PUF Register access not enabled in " + "pm_mmio_access pmAccessTable!\n"); + return -1; + } + + ret = pmu_mmio_write(CSU_PUF_CFG0, CSU_PUF_CFG0_INIT); + if (ret == 0) + ret = pmu_mmio_write(CSU_PUF_CFG1, CSU_PUF_CFG1_INIT); + if (ret == 0) + ret = pmu_mmio_write(CSU_PUF_SHUTTER, CSU_PUF_SHUTTER_INIT); + if (ret == 0) + ret = pmu_mmio_write(CSU_PUF_CMD, CSU_PUF_CMD_REGISTRATION); + while (ret == 0) { + /* wait for PUF word ready */ + ret = pmu_mmio_wait(CSU_PUF_STATUS, + CSU_PUF_STATUS_SYN_WRD_RDY_MASK, + CSU_PUF_STATUS_SYN_WRD_RDY_MASK, + CSU_PUF_REG_TRIES); + if (ret != 0) + break; + + if ((idx > CSU_PUF_SYNDROME_WORDS-2) /* room for chash and aux */) { + ret = -2; /* overrun */ + break; + } + + puf_status = pmu_mmio_read(CSU_PUF_STATUS); + /* Read in the syndrome */ + syndrome[idx++] = pmu_mmio_read(CSU_PUF_WORD); + if (puf_status & CSU_PUF_STATUS_KEY_RDY_MASK) { + *chash = pmu_mmio_read(CSU_PUF_WORD); + syndrome[CSU_PUF_SYNDROME_WORDS-2] = *chash; + *aux = (puf_status & CSU_PUF_STATUS_AUX_MASK) >> 4; + syndrome[CSU_PUF_SYNDROME_WORDS-1] = *aux; + ret = 0; + break; + } + } + +#if defined(DEBUG_CSU) && DEBUG_CSU >= 1 + wolfBoot_printf("Ret %d, Syndrome %d, CHASH 0x%08x, AUX 0x%08x\n", + ret, (CSU_PUF_SYNDROME_WORDS*4), *chash, *aux); + for (idx=0; idx> 32)); + if (ret == 0) + ret = pmu_mmio_write(CSUDMA_SIZE(ch), (sz | flags)); + return ret; +} + +static int csu_aes_reset(void) +{ + /* Reset AES (set and clear) */ + int ret = pmu_mmio_write(CSU_AES_RESET, 1); + if (ret == 0) + ret = pmu_mmio_write(CSU_AES_RESET, 0); + return ret; +} + +static int csu_dma_config(int ch, int doSwap) +{ + int ret = 0; + uint32_t regs, reg; + regs = reg = pmu_mmio_read(CSUDMA_CTRL(ch)); + if (doSwap) + reg |= CSUDMA_CTRL_ENDIANNESS; + else + reg &= ~CSUDMA_CTRL_ENDIANNESS; + if (regs != reg) + ret = pmu_mmio_write(CSUDMA_CTRL(ch), reg); + return ret; +} + +/* AES GCM Encrypt or Decrypt with Device Key setup by CSU ROM */ +/* Output must also have room for updated IV at end */ +#define AES_GCM_TAG_SZ 12 +int csu_aes(int enc, const uint8_t* iv, const uint8_t* in, uint8_t* out, uint32_t sz) +{ + int ret; + uint32_t reg; + + /* Flush data cache for variables used */ + flush_dcache_range((unsigned long)iv, (unsigned long)iv + AES_GCM_TAG_SZ); + flush_dcache_range((unsigned long)in, (unsigned long)in); + flush_dcache_range((unsigned long)out, (unsigned long)out + AES_GCM_TAG_SZ); + + /* Configure SSS for DMA <-> AES */ + ret = pmu_mmio_write(CSU_SSS_CFG, + (CSU_SSS_CFG_AES(CSU_SSS_CFG_SRC_DMA) | + CSU_SSS_CFG_DMA(CSU_SSS_CFG_SRC_AES))); + /* Reset AES (set and clear) */ + if (ret == 0) + ret = csu_aes_reset(); + /* Setup AES GCM Key (use device key) */ + if (ret == 0) + ret = pmu_mmio_write(CSU_AES_KEY_SRC, CSU_AES_KEY_SRC_DEVICE_KEY); + /* Trigger key load */ + if (ret == 0) + ret = pmu_mmio_write(CSU_AES_KEY_LOAD, 1); + /* Wait till key init done */ + if (ret == 0) + ret = pmu_mmio_wait(CSU_AES_STATUS, CSU_AES_STATUS_KEY_INIT_DONE, + CSU_AES_STATUS_KEY_INIT_DONE, CSU_AES_TIMEOUT); + /* Enable DMA byte swapping */ + if (ret == 0) + ret = csu_dma_config(CSUDMA_CH_SRC, 1); + if (ret == 0) + ret = csu_dma_config(CSUDMA_CH_DST, 1); + /* Set encrypt or decrypt */ + if (ret == 0) + ret = pmu_mmio_write(CSU_AES_CFG, enc); + /* Issue start and wait for DMA IV and data */ + if (ret == 0) + ret = pmu_mmio_write(CSU_AES_START_MSG, 1); + /* Send IV with byte swap (not last) */ + if (ret == 0) + ret = csu_dma_transfer(CSUDMA_CH_SRC, + (uintptr_t)iv, AES_GCM_TAG_SZ, 0); + /* wait for IV to send and cear interrupt */ + if (ret == 0) + ret = csu_dma_wait_done(CSUDMA_CH_SRC); + /* Setup data to recieve */ + if (ret == 0) + ret = csu_dma_transfer(CSUDMA_CH_DST, + (uintptr_t)out, sz + AES_GCM_TAG_SZ, 0); + /* Send data */ + if (ret == 0) + ret = csu_dma_transfer(CSUDMA_CH_SRC, + (uintptr_t)in, sz, CSUDMA_SIZE_LAST_WORD); + /* Wait for DMA to complete and clear */ + if (ret == 0) + ret = csu_dma_wait_done(CSUDMA_CH_SRC); + if (ret == 0) + ret = csu_dma_wait_done(CSUDMA_CH_DST); + /* Disable DMA byte swapping */ + if (ret == 0) + ret = csu_dma_config(CSUDMA_CH_SRC, 0); + if (ret == 0) + ret = csu_dma_config(CSUDMA_CH_DST, 0); + /* Wait for AES done */ + if (ret == 0) + ret = pmu_mmio_wait(CSU_AES_STATUS, CSU_AES_STATUS_BUSY, + 0, CSU_AES_TIMEOUT); + return ret; +} + +/* zero the kup and expanded key */ +int csu_aes_key_zero(void) +{ + int ret; + uint32_t reg = pmu_mmio_read(CSU_AES_KEY_CLEAR); + ret = pmu_mmio_write(CSU_AES_KEY_CLEAR, + (reg | CSU_AES_KEY_CLEAR_KUP | CSU_AES_KEY_CLEAR_EXP)); + if (ret == 0) { + ret = pmu_mmio_wait(CSU_AES_STATUS, + (CSU_AES_STATUS_AES_KEY_ZEROED | CSU_AES_STATUS_KUP_ZEROED), + (CSU_AES_STATUS_AES_KEY_ZEROED | CSU_AES_STATUS_KUP_ZEROED), + CSU_AES_TIMEOUT); + } + return ret; +} + +int csu_init(void) +{ + int ret = 0; +#ifdef CSU_PUF_ROT + #if 0 + uint32_t syndrome[CSU_PUF_SYNDROME_WORDS]; + uint32_t chash=0, aux=0; + #if defined(DEBUG_CSU) && DEBUG_CSU >= 1 + uint32_t idx; + #endif + #endif +#endif + uint32_t reg1 = pmu_mmio_read(CSU_IDCODE); + uint32_t reg2 = pmu_mmio_read(CSU_VERSION); + uint64_t ms; + + wolfBoot_printf("CSU ID 0x%08x, Ver 0x%08x\n", + reg1, reg2 & CSU_VERSION_MASK); + +#ifdef DEBUG_CSU + /* Enable JTAG */ + wolfBoot_printf("Enabling JTAG\n"); + pmu_mmio_write(CSU_JTAG_SEC, 0x3F); + pmu_mmio_write(CSU_JTAG_DAP_CFG, 0xFF); + pmu_mmio_write(CSU_JTAG_CHAIN_CFG, 0x3); + pmu_mmio_write(CRL_APB_DBG_LPD_CTRL, 0x01002002); + pmu_mmio_write(CRL_APB_RST_LPD_DBG, 0x0); + pmu_mmio_write(CSU_PCAP_PROG, 0x1); + + /* Wait until JTAG is attached */ + while ((reg1 = pmu_mmio_read(CSU_JTAG_CHAIN_STATUS)) == 0); + wolfBoot_printf("JTAG Attached: status 0x%x\n", reg1); + hal_delay_ms(500); /* give time for debugger to break */ +#endif + +#ifdef CSU_PUF_ROT + reg1 = pmu_mmio_read(CSU_PUF_STATUS); + wolfBoot_printf("PUF Status 0x%08x\n", reg1); + + /* Read eFuse SEC ctrl bits */ + pmu_efuse_read(ZYNQMP_EFUSE_SEC_CTRL, ®1, sizeof(reg1)); + wolfBoot_printf("eFuse SEC_CTRL 0x%08x\n", reg1); + + /* Read eFUSE helper data */ + pmu_efuse_read(ZYNQMP_EFUSE_PUF_CHASH, ®1, sizeof(reg1)); + pmu_efuse_read(ZYNQMP_EFUSE_PUF_AUX, ®2, sizeof(reg2)); + wolfBoot_printf("eFuse PUF CHASH 0x%08x, AUX 0x%08x\n", reg1, reg2); + + /* CSU PUF only supported with eFuses */ + /* Keeping code for reference in future generations like Versal */ + /* Red (sensitive key), Black (protected key), Grey (unknown) */ + #if 0 + memset(syndrome, 0, sizeof(syndrome)); + ms = hal_timer_ms(); + ret = csu_puf_register(syndrome, &chash, &aux); + wolfBoot_printf("CSU Register PUF %d: %dms\n", ret, hal_timer_ms() - ms); + + if (ret == 0) { + ms = hal_timer_ms(); + /* regenerate - load kek */ + ret = csu_puf_regeneration(syndrome, chash, aux); + wolfBoot_printf("CSU Regen PUF %d: %dms\n", ret, hal_timer_ms() - ms); + } + if (ret == 0) { + /* Use CSU ROM device key and IV to encrypt the red key */ + /* Possible PUF syndrome location 0xFFC30000 */ + #if defined(DEBUG_CSU) && DEBUG_CSU >= 1 + wolfBoot_printf("Red Key %d\n", sizeof(redKey)); + for (idx=0; idx= 1 + wolfBoot_printf("Black Key %d\n", KEY_WRAP_SZ); + for (idx=0; idx 0) { memset(&msgs[msgCnt], 0, sizeof(XQspiPsu_Msg)); - msgs[msgCnt].ByteCount = dummySz; + msgs[msgCnt].ByteCount = dummySz; /* not used */ msgs[msgCnt].BusWidth = busWidth; msgCnt++; } @@ -406,8 +941,11 @@ static int qspi_cs(QspiDev_t* pDev, int csAssert) reg_genfifo |= GQSPI_GEN_FIFO_MODE_SPI; if (csAssert) { reg_genfifo |= (pDev->cs & GQSPI_GEN_FIFO_CS_MASK); + reg_genfifo |= GQSPI_GEN_FIFO_IMM(GQSPI_CS_ASSERT_CLOCKS); + } + else { + reg_genfifo |= GQSPI_GEN_FIFO_IMM(GQSPI_CS_DEASSERT_CLOCKS); } - reg_genfifo |= GQSPI_GEN_FIFO_IMM(GQSPI_CS_ASSERT_CLOCKS); return qspi_gen_fifo_write(reg_genfifo); } @@ -418,11 +956,11 @@ static uint32_t qspi_calc_exp(uint32_t xferSz, uint32_t* reg_genfifo) if (xferSz > GQSPI_GEN_FIFO_IMM_MASK) { /* Use exponent mode (DMA max is 2^28) */ for (expval=28; expval>=8; expval--) { - /* find highest bit set */ - if (xferSz & (1 << expval)) { + /* find highest value */ + if (xferSz >= (1UL << expval)) { *reg_genfifo |= GQSPI_GEN_FIFO_EXP_MASK; *reg_genfifo |= GQSPI_GEN_FIFO_IMM(expval); /* IMM=exponent */ - xferSz = (1 << expval); + xferSz = (1UL << expval); break; } } @@ -541,13 +1079,22 @@ static int qspi_transfer(QspiDev_t* pDev, xferSz = qspi_calc_exp(xferSz, ®_genfifo); } - GQSPIDMA_DST = (unsigned long)dmarxptr; + GQSPIDMA_DST = ((uintptr_t)dmarxptr & 0xFFFFFFFF); + GQSPIDMA_DST_MSB = ((uintptr_t)dmarxptr >> 32); GQSPIDMA_SIZE = xferSz; GQSPIDMA_IER = GQSPIDMA_ISR_DONE; /* enable DMA done interrupt */ flush_dcache_range((unsigned long)dmarxptr, (unsigned long)dmarxptr + xferSz); #endif +#if defined(DEBUG_ZYNQ) && DEBUG_ZYNQ >= 2 + #ifndef GQSPI_MODE_IO + wolfBoot_printf("DMA: ptr %p, xferSz %d\n", dmarxptr, xferSz); + #else + wolfBoot_printf("IO: ptr %p, xferSz %d\n", rxData, xferSz); + #endif +#endif + /* Submit general FIFO operation */ ret = qspi_gen_fifo_write(reg_genfifo); if (ret != GQSPI_CODE_SUCCESS) { @@ -801,7 +1348,7 @@ static int qspi_exit_4byte_addr(QspiDev_t* dev) #endif /* QSPI functions */ -void qspi_init(uint32_t cpu_clock, uint32_t flash_freq) +void qspi_init(void) { int ret; uint32_t reg_cfg, reg_isr; @@ -814,9 +1361,6 @@ void qspi_init(uint32_t cpu_clock, uint32_t flash_freq) XQspiPsu_Config *QspiConfig; #endif - (void)cpu_clock; - (void)flash_freq; - memset(&mDev, 0, sizeof(mDev)); #ifdef USE_XQSPIPSU @@ -865,6 +1409,7 @@ void qspi_init(uint32_t cpu_clock, uint32_t flash_freq) GQSPI_ISR = (reg_isr | GQSPI_ISR_WR_TO_CLR_MASK); /* Clear poll timeout counter interrupt */ reg_cfg = GQSPIDMA_ISR; GQSPIDMA_ISR = reg_cfg; /* clear all active interrupts */ + GQSPI_IER = GQSPI_IXR_GEN_FIFO_EMPTY; GQSPI_IDR = GQSPI_IXR_ALL_MASK; /* disable interrupts */ GQSPIDMA_IDR = GQSPIDMA_ISR_ALL_MASK; @@ -873,7 +1418,7 @@ void qspi_init(uint32_t cpu_clock, uint32_t flash_freq) /* Initialize clock divisor, write protect hold and start mode */ #ifdef GQSPI_MODE_IO reg_cfg = GQSPI_CFG_MODE_EN_IO; /* Use I/O Transfer Mode */ - reg_cfg |= GQSPI_CFG_START_GEN_FIFO; /* Auto start GFIFO cmd execution */ + reg_cfg |= GQSPI_CFG_START_GEN_FIFO; /* Trigger GFIFO commands to start */ #else reg_cfg = GQSPI_CFG_MODE_EN_DMA; /* Use DMA Transfer Mode */ #endif @@ -900,7 +1445,13 @@ void qspi_init(uint32_t cpu_clock, uint32_t flash_freq) * The generic controller should be in clock loopback mode and the clock * tap delay enabled, but the data tap delay disabled. */ /* For EL2 or lower must use IOCTL_SET_TAPDELAY_BYPASS ARG1=2, ARG2=0 */ - IOU_TAPDLY_BYPASS = 0; + if (current_el() <= 2) { + reg_cfg = 0; + pmu_request(PM_MMIO_WRITE, IOU_TAPDLY_BYPASS_ADDR, 0x7, reg_cfg, 0, NULL); + } + else { + IOU_TAPDLY_BYPASS = 0; + } GQSPI_LPBK_DLY_ADJ = GQSPI_LPBK_DLY_ADJ_USE_LPBK; GQSPI_DATA_DLY_ADJ = 0; #endif @@ -913,6 +1464,7 @@ void qspi_init(uint32_t cpu_clock, uint32_t flash_freq) /* Reset DMA */ GQSPIDMA_CTRL = GQSPIDMA_CTRL_DEF; GQSPIDMA_CTRL2 = GQSPIDMA_CTRL2_DEF; + GQSPIDMA_IER = GQSPIDMA_ISR_ALL_MASK; GQSPI_EN = 1; /* Enable Device */ #endif /* USE_QNX */ @@ -957,8 +1509,8 @@ void qspi_init(uint32_t cpu_clock, uint32_t flash_freq) /* Slave Select */ mDev.mode = GQSPI_QSPI_MODE; #if GQPI_USE_DUAL_PARALLEL == 1 - mDev.bus = GQSPI_GEN_FIFO_BUS_BOTH; - mDev.cs = GQSPI_GEN_FIFO_CS_BOTH; + mDev.bus = GQSPI_GEN_FIFO_BUS_BOTH; /* GQSPI_GEN_FIFO_BUS_LOW or GQSPI_GEN_FIFO_BUS_UP */ + mDev.cs = GQSPI_GEN_FIFO_CS_BOTH; /* GQSPI_GEN_FIFO_CS_LOWER or GQSPI_GEN_FIFO_CS_UPPER */ mDev.stripe = GQSPI_GEN_FIFO_STRIPE; #endif @@ -974,7 +1526,20 @@ void qspi_init(uint32_t cpu_clock, uint32_t flash_freq) #endif } -#if 0 +void hal_delay_ms(uint64_t ms) +{ + uint64_t start = hal_timer_ms(); + uint64_t end = start + ms; + + while (1) { + uint64_t cur = hal_timer_ms(); + /* check for timer rollover or expiration */ + if (cur < start || cur >= end) { + break; + } + } +} + uint64_t hal_timer_ms(void) { uint64_t val; @@ -986,25 +1551,33 @@ uint64_t hal_timer_ms(void) val /= cntfrq; return val; } -#endif /* public HAL functions */ void hal_init(void) { - uint32_t cpu_freq = 0; + uint32_t reg; const char* bootMsg = "\nwolfBoot Secure Boot\n"; #ifdef DEBUG_UART uart_init(); #endif wolfBoot_printf(bootMsg); + wolfBoot_printf("Current EL: %d\n", current_el()); -#if 0 - /* This is only allowed for EL-3 */ - asm volatile("msr cntfrq_el0, %0" : : "r" (cpu_freq) : "memory"); -#endif + qspi_init(); - qspi_init(cpu_freq, 0); + pmuVer = pmu_get_version(); + wolfBoot_printf("PMUFW Ver: %d.%d\n", + (int)(pmuVer >> 16), (int)(pmuVer & 0xFFFF)); + +#ifdef WOLFBOOT_ZYNQMP_CSU + if (pmuVer >= PMUFW_MIN_VER) { + csu_init(); + } + else { + wolfBoot_printf("Skipping CSU Init (PMUFW not found)\n"); + } +#endif } void hal_prepare_boot(void) diff --git a/hal/zynq.h b/hal/zynq.h index 63669260d4..c86ba93dbf 100644 --- a/hal/zynq.h +++ b/hal/zynq.h @@ -100,16 +100,17 @@ #define GQSPIDMA_IMR (*((volatile uint32_t*)(QSPI_BASE + 0x820))) /* DST DMA interrupt mask */ #define GQSPIDMA_CTRL2 (*((volatile uint32_t*)(QSPI_BASE + 0x824))) /* General DST DMA control register 2 */ -#define GQSPI_LPBK_DLY_ADJ_USE_LPBK (1UL << 5) -#define GQSPI_LPBK_DLY_ADJ_DIV0(x) (((x) & 0x7) << 0) -#define GQSPI_LPBK_DLY_ADJ_DLY1(x) (((x) & 0x3) << 3) +#define GQSPI_LPBK_DLY_ADJ_USE_LPBK (1UL << 5) +#define GQSPI_LPBK_DLY_ADJ_DIV0(x) (((x) & 0x7) << 0) +#define GQSPI_LPBK_DLY_ADJ_DLY1(x) (((x) & 0x3) << 3) #define GQSPI_DATA_DLY_ADJ_USE_DATA_DLY (1UL << 31) #define GQSPI_DATA_DLY_ADJ_DATA_DLY_ADJ(x) (((x) & 0x7) << 28) /* GQSPI Registers */ /* GQSPI_CFG: Configuration registers */ -#define GQSPI_CFG_CLK_POL (1UL << 1) /* Clock polarity outside QSPI word: 0: QSPI clock is quiescent low, 1: QSPI clock is quiescent high */ -#define GQSPI_CFG_CLK_PH (1UL << 2) /* Clock phase: 1: the QSPI clock is inactive outside the word, 0: the QSPI clock is active outside the word */ +/* Clock Phase and Polarity. Only mode 3 and 0 are support (11b or 00b) */ +#define GQSPI_CFG_CLK_POL (1UL << 1) /* Clock polarity: 1: QSPI clock is quiescent high, 0: QSPI clock is quiescent low, */ +#define GQSPI_CFG_CLK_PH (1UL << 2) /* Clock phase: 1: QSPI clock is inactive outside the word, 0: QSPI clock is active outside the word */ /* 000: divide by 2, 001: divide by 4, 010: divide by 8, 011: divide by 16, 100: divide by 32, 101: divide by 64, 110: divide by 128, 111: divide by 256 */ @@ -139,8 +140,8 @@ #define GQSPI_IXR_ALL_MASK (GQSPI_IXR_POLL_TIME_EXPIRE | GQSPI_IXR_TX_FIFO_NOT_FULL | \ GQSPI_IXR_TX_FIFO_FULL | GQSPI_IXR_RX_FIFO_NOT_EMPTY | GQSPI_IXR_RX_FIFO_FULL | \ - GQSPI_IXR_GEN_FIFO_EMPTY | GQSPI_IXR_TX_FIFO_EMPTY | GQSPI_IXR_GEN_FIFO_NOT_FULL | \ - GQSPI_IXR_GEN_FIFO_FULL | GQSPI_IXR_RX_FIFO_EMPTY) + GQSPI_IXR_TX_FIFO_EMPTY | GQSPI_IXR_GEN_FIFO_NOT_FULL | GQSPI_IXR_GEN_FIFO_FULL | \ + GQSPI_IXR_RX_FIFO_EMPTY) #define GQSPI_ISR_WR_TO_CLR_MASK 0x00000002U /* GQSPI_GEN_FIFO: FIFO data register */ @@ -175,7 +176,7 @@ #define GQSPI_FIFO_CTRL_RST_RX_FIFO (1UL << 2) /* GQSPIDMA_CTRL */ -#define GQSPIDMA_CTRL_DEF 0x803FFA00UL +#define GQSPIDMA_CTRL_DEF 0x403FFA00UL #define GQSPIDMA_CTRL2_DEF 0x081BFFF8UL /* GQSPIDMA_STS */ @@ -187,14 +188,15 @@ #define GQSPIDMA_ISR_ALL_MASK 0xFEU /* QSPI Configuration (bare-metal only) */ - #ifndef GQSPI_CLK_REF #define GQSPI_CLK_REF 125000000 /* QSPI Reference Clock */ #endif #ifndef GQSPI_CLK_DIV #define GQSPI_CLK_DIV 2 /* (QSPI_REF_CLK (125MHZ) / (2 << DIV) = BUS): 0=DIV2, 1=DIV4, 2=DIV8 */ #endif -#define GQSPI_CS_ASSERT_CLOCKS 5 /* CS Setup Time (tCSS) - num of clock cycles foes in IMM */ +#define GQSPI_CS_ASSERT_CLOCKS 5 /* CS Setup Time (tCSS) */ +#define GQSPI_CS_DEASSERT_CLOCKS 4 /* CS Hold Time */ + #define GQSPI_FIFO_WORD_SZ 4 #define QQSPI_DMA_ALIGN 64 /* L1 cache size */ #ifndef GQSPI_DMA_TMPSZ @@ -286,20 +288,22 @@ /* eFUSE support */ #define ZYNQMP_EFUSE_BASE 0xFFCC0000 -#define ZYNQMP_EFUSE_STATUS (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x0008))) -#define ZYNQMP_EFUSE_SEC_CTRL (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x1058))) -#define ZYNQMP_EFUSE_PPK0_0 (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x10A0))) -#define ZYNQMP_EFUSE_PPK0_1 (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x10A4))) -#define ZYNQMP_EFUSE_PPK0_2 (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x10A8))) -#define ZYNQMP_EFUSE_PPK0_3 (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x10AC))) -#define ZYNQMP_EFUSE_PPK0_4 (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x10B0))) -#define ZYNQMP_EFUSE_PPK0_5 (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x10B4))) -#define ZYNQMP_EFUSE_PPK0_6 (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x10B8))) -#define ZYNQMP_EFUSE_PPK0_7 (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x10BC))) -#define ZYNQMP_EFUSE_PPK0_8 (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x10C0))) -#define ZYNQMP_EFUSE_PPK0_9 (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x10C4))) -#define ZYNQMP_EFUSE_PPK0_10 (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x10C8))) -#define ZYNQMP_EFUSE_PPK0_11 (*((volatile uint32_t*)(ZYNQMP_EFUSE_BASE + 0x10CC))) +#define ZYNQMP_EFUSE_STATUS (ZYNQMP_EFUSE_BASE + 0x0008) +#define ZYNQMP_EFUSE_PUF_CHASH (ZYNQMP_EFUSE_BASE + 0x1050) +#define ZYNQMP_EFUSE_PUF_AUX (ZYNQMP_EFUSE_BASE + 0x1054) +#define ZYNQMP_EFUSE_SEC_CTRL (ZYNQMP_EFUSE_BASE + 0x1058) +#define ZYNQMP_EFUSE_PPK0_0 (ZYNQMP_EFUSE_BASE + 0x10A0) +#define ZYNQMP_EFUSE_PPK0_1 (ZYNQMP_EFUSE_BASE + 0x10A4) +#define ZYNQMP_EFUSE_PPK0_2 (ZYNQMP_EFUSE_BASE + 0x10A8) +#define ZYNQMP_EFUSE_PPK0_3 (ZYNQMP_EFUSE_BASE + 0x10AC) +#define ZYNQMP_EFUSE_PPK0_4 (ZYNQMP_EFUSE_BASE + 0x10B0) +#define ZYNQMP_EFUSE_PPK0_5 (ZYNQMP_EFUSE_BASE + 0x10B4) +#define ZYNQMP_EFUSE_PPK0_6 (ZYNQMP_EFUSE_BASE + 0x10B8) +#define ZYNQMP_EFUSE_PPK0_7 (ZYNQMP_EFUSE_BASE + 0x10BC) +#define ZYNQMP_EFUSE_PPK0_8 (ZYNQMP_EFUSE_BASE + 0x10C0) +#define ZYNQMP_EFUSE_PPK0_9 (ZYNQMP_EFUSE_BASE + 0x10C4) +#define ZYNQMP_EFUSE_PPK0_10 (ZYNQMP_EFUSE_BASE + 0x10C8) +#define ZYNQMP_EFUSE_PPK0_11 (ZYNQMP_EFUSE_BASE + 0x10CC) /* eFUSE STATUS Registers */ #define ZYNQMP_EFUSE_STATUS_CACHE_DONE (1UL << 5) @@ -380,4 +384,195 @@ #define GICC_BASE 0xF9020000 +/* Clock - Full Power Domain */ +#define CRL_APB_BASE 0xFF5E0000UL +#define QSPI_REF_CTRL (*((volatile uint32_t*)(CRL_APB_BASE + 0x68))) + +#define QSPI_REF_CTRL_SRCSEL_MASK 0x7 +#define QSPI_REF_CTRL_SRCSEL(n) ((n) & QSPI_REF_CTRL_SRCSEL_MASK) +#define QSPI_REF_CTRL_SRCSEL_IOPLL QSPI_REF_CTRL_SRCSEL(0) +#define QSPI_REF_CTRL_SRCSEL_RPLL QSPI_REF_CTRL_SRCSEL(2) +#define QSPI_REF_CTRL_SRCSEL_DPLL QSPI_REF_CTRL_SRCSEL(3) /* DPLL_CLK_TO_LPD */ + +#define QSPI_REF_CTRL_DIVISOR0_MASK (0x3F << 8) +#define QSPI_REF_CTRL_DIVISOR0(n) (((n) << 8) & QSPI_REF_CTRL_DIVISOR0_MASK) + +#define QSPI_REF_CTRL_DIVISOR1_MASK (0x3F << 16) +#define QSPI_REF_CTRL_DIVISOR1(n) (((n) << 16) & QSPI_REF_CTRL_DIVISOR0_MASK) + + +/* Configuration Security Unit (CSU) */ +/* Triple-Dedundant MicroBlaze processor */ +/* 128 KB CSU ROM (immutable) */ +/* 32 KB CSU RAM (with ECC) */ +/* Internal clock source */ +/* CSU must be called through PMUFW. */ +/* PMUFW must be built with SECURE_ACCESS_VAL=1 */ +#define CSU_BASE 0xFFCA0000UL + +#define CSU_STATUS (CSU_BASE + 0x0000U) +#define CSU_STATUS_BOOT_ENC (1 << 1) +#define CSU_STATUS_BOOT_AUTH (1 << 0) + +/* See JTAG IDCODE in TRM */ +#define CSU_IDCODE (CSU_BASE + 0x0040U) +/* 2473_8093h=ZU9EG */ +/* 1471_1093h=ZU2CG/EG */ + +#define CSU_VERSION (CSU_BASE + 0x0044U) +/* 0: XCZU9EG-ES1, + * 1: XCZU3EG-ES1, XCZU15EG-ES1, + * 2: XCZU7EV-ES1, XCZU9EG-ES2, XCZU19EG-ES1, + * 3: All devices as of October 2017 (Production Level) */ +#define CSU_VERSION_MASK 0xF + +#define CSU_TAMPER_STATUS (CSU_BASE + 0x5000U) +#define CSU_TAMPER_TRIG (CSU_BASE + 0x0014U) /* set =1 to trigger tamber event for testing */ + +/* SSS - Secure Stream Switch */ +#define CSU_SSS_CFG (CSU_BASE + 0x0008U) +#define CSU_SSS_CFG_PCAP_MASK 0x0000000FU +#define CSU_SSS_CFG_PCAP(n) (((n) << 0) & CSU_SSS_CFG_PCAP_MASK) +#define CSU_SSS_CFG_DMA_MASK 0x000000F0U +#define CSU_SSS_CFG_DMA(n) (((n) << 4) & CSU_SSS_CFG_DMA_MASK) +#define CSU_SSS_CFG_AES_MASK 0x00000F00U +#define CSU_SSS_CFG_AES(n) (((n) << 8) & CSU_SSS_CFG_AES_MASK) +#define CSU_SSS_CFG_SHA_MASK 0x0000F000U +#define CSU_SSS_CFG_SHA(n) (((n) << 12) & CSU_SSS_CFG_SHA_MASK) +/* Data Sources */ +#define CSU_SSS_CFG_SRC_NONE 0x0 +#define CSU_SSS_CFG_SRC_PCAP 0x3 /* Processor Configuration Access Port */ +#define CSU_SSS_CFG_SRC_DMA 0x5 +#define CSU_SSS_CFG_SRC_AES 0xA + +/* AES-GCM 256-bit */ +#define CSU_AES_STATUS (CSU_BASE + 0x1000U) +#define CSU_AES_KEY_SRC (CSU_BASE + 0x1004U) /* AES key source selection */ +#define CSU_AES_KEY_LOAD (CSU_BASE + 0x1008U) /* Loads the key selected by AES_KEY_SRC into the AES (self clearing) */ +#define CSU_AES_START_MSG (CSU_BASE + 0x100CU) /* Starts the decryption process. The IV must be loaded before the AES will decrypt a payload (self clearing) */ +#define CSU_AES_RESET (CSU_BASE + 0x1010U) +#define CSU_AES_KEY_CLEAR (CSU_BASE + 0x1014U) +#define CSU_AES_CFG (CSU_BASE + 0x1018U) /* 0=Dec, 1=Enc */ +#define CSU_AES_KUP_WR (CSU_BASE + 0x101CU) +#define CSU_AES_KUP (CSU_BASE + 0x1020U) /* 32 bytes - through 0x40 */ +#define CSU_AES_IV (CSU_BASE + 0x1040U) /* 16 bytes - through 0x50 */ + +#define CSU_AES_STATUS_OKR_ZEROED (1 << 11) +#define CSU_AES_STATUS_BOOT_ZEROED (1 << 10) +#define CSU_AES_STATUS_KUP_ZEROED (1 << 9) +#define CSU_AES_STATUS_AES_KEY_ZEROED (1 << 8) +#define CSU_AES_STATUS_KEY_INIT_DONE (1 << 4) +#define CSU_AES_STATUS_GCM_TAG_PASS (1 << 3) +#define CSU_AES_STATUS_DONE (1 << 2) +#define CSU_AES_STATUS_READY (1 << 1) +#define CSU_AES_STATUS_BUSY (1 << 0) + +#define CSU_AES_KEY_SRC_DEVICE_KEY 1 /* Device key is selected and locked by the CSU ROM during boot */ +#define CSU_AES_KEY_SRC_KUP 0 /* User provided key source */ + +#define CSU_AES_KEY_CLEAR_KUP (1 << 1) /* Zeroize KUP key */ +#define CSU_AES_KEY_CLEAR_EXP (1 << 0) /* Zeroize expanded key */ + +#define CSU_AES_CFG_DEC 0 +#define CSU_AES_CFG_ENC 1 + + +/* PUF */ +#define CSU_PUF_CMD (CSU_BASE + 0x4000U) +#define CSU_PUF_CFG0 (CSU_BASE + 0x4004U) +#define CSU_PUF_CFG1 (CSU_BASE + 0x4008U) +#define CSU_PUF_SHUTTER (CSU_BASE + 0x400CU) +#define CSU_PUF_STATUS (CSU_BASE + 0x4010U) +#define CSU_PUF_DBG (CSU_BASE + 0x4014U) +#define CSU_PUF_WORD (CSU_BASE + 0x4018U) + +#define CSU_PUF_CMD_CLEAR 0x6 /* Clear PUF status */ +#define CSU_PUF_CMD_STATUS 0x5 /* Read out regeneration status */ +#define CSU_PUF_CMD_REGENERATION 0x4 /* Key regeneration */ +#define CSU_PUF_CMD_REGISTRATION 0x1 /* Key registration */ + +#define CSU_PUF_CFG0_INIT 0x2 +#define CSU_PUF_CFG1_INIT 0x0C230090U /* 4K */ +#define CSU_PUF_SHUTTER_INIT 0x00100005E + +#define CSU_PUF_STATUS_OVERFLOW_MASK (0x3U << 28) /* Overflow, if bits are not 0. Reduce SHUT[SOPEN] value. */ +#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. */ +#define CSU_PUF_STATUS_KEY_RDY_MASK (0x1U << 3) /* Indicates that the key is ready */ +#define CSU_PUF_STATUS_KEY_ZERO_MASK (0x1U << 1) /* Indicates that the PUF key has been zeroized */ +#define CSU_PUF_STATUS_SYN_WRD_RDY_MASK (0x1U << 0) /* Indicates a syndrome word is ready in the PUF_WORD register */ + +/* SHA3 */ +#define CSU_SHA_START (CSU_BASE + 0x2000U) +#define CSU_SHA_RESET (CSU_BASE + 0x2004U) +#define CSU_SHA_DONE (CSU_BASE + 0x2008U) +#define CSU_SHA_DIGEST (CSU_BASE + 0x2010U) /* 48 bytes (through 0x40) */ +#define CSU_SHA_START (CSU_BASE + 0x2000U) +#define CSU_SHA_START (CSU_BASE + 0x2000U) + +/* CSU DMA */ +/* Addresses and sizes must be word aligned last two bits = 0 */ +/* 128 x 32-bit data FIFO for each channel (two channels) */ +#define CSUDMA_BASE(ch) (0xFFC80000UL + (((ch) & 0x1) * 0x800)) +#define CSUDMA_ADDR(ch) (CSUDMA_BASE(ch) + 0x0000U) /* Mem address (lower 32-bits) */ +#define CSUDMA_ADDR_MSB(ch) (CSUDMA_BASE(ch) + 0x0028U) /* (upper 17 bits) */ +#define CSUDMA_SIZE(ch) (CSUDMA_BASE(ch) + 0x0004U) /* DMA transfer payload size */ +#define CSUDMA_STS(ch) (CSUDMA_BASE(ch) + 0x0008U) +#define CSUDMA_CTRL(ch) (CSUDMA_BASE(ch) + 0x000CU) +#define CSUDMA_CTRL2(ch) (CSUDMA_BASE(ch) + 0x0024U) +#define CSUDMA_CRC(ch) (CSUDMA_BASE(ch) + 0x0010U) +#define CSUDMA_ISTS(ch) (CSUDMA_BASE(ch) + 0x0014U) +#define CSUDMA_IEN(ch) (CSUDMA_BASE(ch) + 0x0018U) +#define CSUDMA_IDIS(ch) (CSUDMA_BASE(ch) + 0x001CU) +#define CSUDMA_IMASK(ch) (CSUDMA_BASE(ch) + 0x0020U) + +#define CSUDMA_SIZE_LAST_WORD (1 << 0) + +#define CSUDMA_STS_DONE_CNT (0x07 << 13) +#define CSUDMA_STS_SRC_FIFO_LEVEL (0xFF << 5) +#define CSUDMA_STS_RD_OUTSTANDING (0x0F << 1) +#define CSUDMA_STS_BUSY (0x01 << 0) + +#define CSUDMA_CTRL_FIFO_THRESH_MASK (0xF << 2) +#define CSUDMA_CTRL_FIFO_THRESH(n) (((n) << 2) & CSUDMA_CTRL_FIFO_THRESH_MASK) +#define CSUDMA_CTRL_TIMEOUT_VAL_MASK (0xFFF << 10) +#define CSUDMA_CTRL_TIMEOUT_VAL(n) (((n) << 10) & CSUDMA_CTRL_TIMEOUT_VAL_MASK) +#define CSUDMA_CTRL_ENDIANNESS (1 << 23) +#define CSUDMA_CTRL_AXI_BRST_TYPE (1 << 22) + +#define CSUDMA_CTRL2_ARCACHE_MASK (0x7 << 24) +#define CSUDMA_CTRL2_ARCACHE(n) (((n) << 24) & CSUDMA_CTRL2_ARCACHE_MASK) +#define CSUDMA_CTRL2_ROUTE_BIT (1 << 23) +#define CSUDMA_CTRL2_TIMEOUT_EN (1 << 22) +#define CSUDMA_CTRL2_TIMEOUT_PRE_MASK (0xFFF << 4) +#define CSUDMA_CTRL2_TIMEOUT_PRE(n) (((n) << 4) & CSUDMA_CTRL2_TIMEOUT_PRE_MASK) +#define CSUDMA_CTRL2_MAX_OUTS_CMDS_MASK (0xF << 0) +#define CSUDMA_CTRL2_MAX_OUTS_CMDS(n) (((n) << 0) & CSUDMA_CTRL2_MAX_OUTS_CMDS_MASK) + +#define CSUDMA_ISR_INVALID_APB (1 << 6) +#define CSUDMA_ISR_THRESH_HIT (1 << 5) +#define CSUDMA_ISR_TIMEOUT_MEM (1 << 4) +#define CSUDMA_ISR_TIMEOUT_STRM (1 << 3) +#define CSUDMA_ISR_AXI_RDERR (1 << 2) +#define CSUDMA_ISR_DONE (1 << 1) +#define CSUDMA_ISR_MEM_DONE (1 << 0) + +/* CSU DMA Channels */ +#define CSUDMA_CH_SRC 0 +#define CSUDMA_CH_DST 1 + +/* CSU JTAG */ +#define CSU_JTAG_CHAIN_CFG (CSU_BASE + 0x0030U) +#define CSU_JTAG_CHAIN_STATUS (CSU_BASE + 0x0034U) +#define CSU_JTAG_SEC (CSU_BASE + 0x0038U) +#define CSU_JTAG_DAP_CFG (CSU_BASE + 0x003CU) + +#define CSU_PCAP_PROG (CSU_BASE + 0x3000U) + +/* Clock and Reset Control */ +#define CRL_APB_BASE 0xFF5E0000UL +#define CRL_APB_DBG_LPD_CTRL (CRL_APB_BASE + 0x00B0U) +#define CRL_APB_RST_LPD_DBG (CRL_APB_BASE + 0x0240U) + + + #endif /* _ZYNQMP_H_ */ diff --git a/options.mk b/options.mk index 5615526215..cb62b9228f 100644 --- a/options.mk +++ b/options.mk @@ -748,7 +748,9 @@ ifeq ($(WOLFBOOT_NO_PARTITIONS),1) endif ifeq ($(HASH),SHA3) - WOLFCRYPT_OBJS+=./lib/wolfssl/wolfcrypt/src/sha3.o + ifeq ($(HASH_HAL),) + WOLFCRYPT_OBJS+=./lib/wolfssl/wolfcrypt/src/sha3.o + endif CFLAGS+=-D"WOLFBOOT_HASH_SHA3_384" SIGN_OPTIONS+=--sha3 endif diff --git a/src/boot_aarch64.c b/src/boot_aarch64.c index f36690a4ad..9487f84a60 100644 --- a/src/boot_aarch64.c +++ b/src/boot_aarch64.c @@ -37,6 +37,13 @@ extern unsigned int _end_data; extern void main(void); extern void gicv2_init_secure(void); +unsigned int current_el(void) +{ + unsigned long el; + asm volatile("mrs %0, CurrentEL" : "=r" (el) : : "cc"); + return (unsigned int)((el >> 2) & 0x3U); +} + void boot_entry_C(void) { register unsigned int *dst, *src; diff --git a/src/tpm.c b/src/tpm.c index 97d65d8f66..c05e6969b8 100644 --- a/src/tpm.c +++ b/src/tpm.c @@ -1245,8 +1245,8 @@ void wolfBoot_tpm2_deinit(void) TPMA_SESSION_continueSession)); if (rc == 0) { /* Change platform auth to random value, to prevent application - * from being able to use platform hierarchy. This is defined in - * section 10 of the TCG PC Client Platform specification. */ + * from being able to use platform hierarchy. This is defined in + * section 10 of the TCG PC Client Platform specification. */ rc = wolfTPM2_ChangePlatformAuth(&wolftpm_dev, &wolftpm_session); } if (rc != 0) {