diff --git a/.gitignore b/.gitignore index 2aaee003f..501300138 100644 --- a/.gitignore +++ b/.gitignore @@ -56,10 +56,7 @@ src/rsa2048_pub_key.c src/rsa4096_pub_key.c # keygen binaries -tools/ed25519/ed25519_sign -tools/ed25519/ed25519_keygen -tools/ecc256/ecc256_sign -tools/ecc256/ecc256_keygen +tools/keytools/sign # Vim swap files .*.swp @@ -84,3 +81,6 @@ config/*.ld # Generated confiuguration file .config +.vs +*.filters +*.user diff --git a/IDE/XilinxSDK/.cproject b/IDE/XilinxSDK/.cproject new file mode 100644 index 000000000..8d82f4555 --- /dev/null +++ b/IDE/XilinxSDK/.cproject @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/IDE/XilinxSDK/.project b/IDE/XilinxSDK/.project new file mode 100644 index 000000000..ec014f0bc --- /dev/null +++ b/IDE/XilinxSDK/.project @@ -0,0 +1,26 @@ + + + efuse_wolfboot + Created by SDK v2018.2. standalone_bsp_0 - psu_cortexa53_0 + + standalone_bsp_0 + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/IDE/XilinxSDK/README.md b/IDE/XilinxSDK/README.md new file mode 100644 index 000000000..0f7affdd4 --- /dev/null +++ b/IDE/XilinxSDK/README.md @@ -0,0 +1,73 @@ +# Xilinx SDK wolfBoot Project + +To use this example project: +1. Copy `.cproject` and `.project` into the wolfBoot root. +2. From the Xilinx SDK Import wolfBoot using "Import" -> "Existing Projects into Workspace". + +## wolfBoot Configuration + +A build settings template for Zynq UltraScale+ can be found here `./config/examples/zynqmp.config`. This file can be copied to wolfBoot root as `.config` for building from the command line. These template settings are also in this `.cproject` as preprocessor macros. These settings are loaded into the `target.h.in` template by the wolfBoot `make`. If not using the built-in make then the following defines will need to be manually created in `target.h`: + +``` +#define WOLFBOOT_SECTOR_SIZE 0x20000 +#define WOLFBOOT_PARTITION_BOOT_ADDRESS 0x800000 +#define WOLFBOOT_LOAD_ADDRESS 0x10000000 +#define WOLFBOOT_PARTITION_SIZE 0x2A00000 +#define WOLFBOOT_PARTITION_UPDATE_ADDRESS 0x3A00000 +#define WOLFBOOT_PARTITION_SWAP_ADDRESS 0x63E0000 + +#define WOLFBOOT_DTS_BOOT_ADDRESS 0x7E0000 +#define WOLFBOOT_DTS_UPDATE_ADDRESS 0x39E0000 +#define WOLFBOOT_LOAD_DTS_ADDRESS 0x11800000 +``` + +Note: If not using Position Independent Code (PIC) the linker script `ldscript.ld` must have the start address offset to match the `WOLFBOOT_LOAD_ADDRESS`. + +## Signing Example + +```sh +python3 ./tools/keytools/sign.py --rsa4096 --sha3 ../helloworld/Debug/helloworld.elf ./rsa4096.der 1 +``` + +## Bootgen + +Xilinx uses a `bootgen` tool for generating a boot binary image that has Xilinx headers, which the FSBL (First Stage Boot Loader) understands. See the `boot.bif` and `boot_auth.bif` as examples. + +* Use "partition_owner=uboot" to prevent a partition from being loaded into RAM. +* Use "offset=" option to place the application into a specific location in flash. +* Use "load=" option to have FSBL load into specific location in RAM. + +### Adding RSA Authentication + +1. Generate keys: + * `bootgen.exe -generate_keys auth pem -arch zynqmp -image boot.bif` +2. Create hash for primary key: + * `bootgen.exe -image boot.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. + * Scroll down to Supported Libraries and Check the xiskey libray + * In the system.mss pane, scroll down to Libraries and click Import Examples. + * Check the xilskey_esfuseps_zynqmp_example +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 */`` +5. Update boot.bif (see boot_auth.bif) + + ``` + [auth_params] ppk_select=0; spk_id=0x00000000 + [pskfile] pskf.pem + [sskfile] sskf.pem + authentication=rsa + ``` + +6. Build “boot.bin” image: + * `bootgen.exe -image boot.bif -arch zynqmp -o i BOOT.BIN -w` + +Note: To generate a report of a boot.bin use the `bootgen_utility`: +`bootgen_utility -arch zynqmp -bin boot.bin -out boot.bin.txt` + +### References: +* [ZAPP1319](https://www.xilinx.com/support/documentation/application_notes/xapp1319-zynq-usp-prog-nvm.pdf): Programming BBRAM and eFUSEs +* [UG1283](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_2/ug1283-bootgen-user-guide.pdf): Bootgen User Guide diff --git a/IDE/XilinxSDK/boot.bif b/IDE/XilinxSDK/boot.bif new file mode 100644 index 000000000..5d487fe45 --- /dev/null +++ b/IDE/XilinxSDK/boot.bif @@ -0,0 +1,11 @@ +// Boot BIF example for wolfBoot with signed Hello World +// Note: "partition_owner=uboot" prevents partition from being loaded to RAM +the_ROM_image: +{ + [bootloader, destination_cpu=a53-0] zynqmp_fsbl.elf + [destination_cpu=pmu] pmufw.elf + [destination_device=pl] system.bit + [destination_cpu=a53-0, exception_level=el-3, trustzone] bl31.elf + [destination_cpu=a53-0, exception_level=el-2] wolfboot.elf + [destination_cpu=a53-0, offset=0x800000, partition_owner=uboot] helloworld_v1_signed.bin +} diff --git a/IDE/XilinxSDK/boot_auth.bif b/IDE/XilinxSDK/boot_auth.bif new file mode 100644 index 000000000..0f32e829e --- /dev/null +++ b/IDE/XilinxSDK/boot_auth.bif @@ -0,0 +1,29 @@ +// Boot BIF example with Xilinx Secure Boot authentication and wolfBoot +the_ROM_image: +{ + // Boot Header Authentication Enable + [fsbl_config] bh_auth_enable + + // 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, destination_cpu=a53-0, authentication=rsa] zynqmp_fsbl.elf + [destination_cpu=pmu, authentication=rsa] pmufw.elf + [destination_device=pl, authentication=rsa] system.bit + [destination_cpu=a53-0, exception_level=el-3, trustzone, authentication=rsa] bl31.elf + [destination_cpu=a53-0, authentication=rsa, load=0x11800000] system.dtb + + // ARM Device Tree (loaded to RAM at 0x11800000 by wolfBoot) + [ destination_cpu=a53-0, authentication=rsa, offset=0x007E0000, partition_owner=uboot] system.dtb + + // Second Stage wolfBoot Bootloader (in RAM at 0x0) + [destination_cpu=a53-0, exception_level=el-2, authentication=rsa] wolfboot.elf + + // Kernel / Application (load to RAM at 0x10000000 by wolfBoot) + // Using partition_owner=uboot prevents FSBL from loading to RAM + [destination_cpu=a53-0, offset=0x800000, partition_owner=uboot] kernel.ui +} diff --git a/Makefile b/Makefile index c235c70a8..7e3c10c65 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ OBJS:= \ ./src/libwolfboot.o WOLFCRYPT_OBJS:= PUBLIC_KEY_OBJS:= +UPDATE_OBJS:= ifeq ($(SIGN),RSA4096) SPMATH=0 @@ -56,7 +57,7 @@ ifeq ($(SIGN),ED25519) ./lib/wolfssl/wolfcrypt/src/wolfmath.o \ ./lib/wolfssl/wolfcrypt/src/fe_low_mem.o PUBLIC_KEY_OBJS=./src/ed25519_pub_key.o - CFLAGS+=-DWOLFBOOT_SIGN_ED25519 -nostdlib -DWOLFSSL_STATIC_MEMORY \ + CFLAGS+=-DWOLFBOOT_SIGN_ED25519 -nostdlib \ -Wstack-usage=1024 LDFLAGS+=-nostdlib endif @@ -119,6 +120,9 @@ endif ifeq ($(EXT_FLASH),1) CFLAGS+= -DEXT_FLASH=1 -DPART_UPDATE_EXT=1 -DPART_SWAP_EXT=1 + ifeq ($(NO_XIP),1) + CFLAGS+=-DPART_BOOT_EXT=1 + endif endif ifeq ($(ALLOW_DOWNGRADE),1) @@ -151,6 +155,7 @@ ifeq ($(PKA),1) endif OBJS+=$(PUBLIC_KEY_OBJS) +OBJS+=$(UPDATE_OBJS) ifeq ($(WOLFTPM),1) OBJS += lib/wolfTPM/src/tpm2.o \ @@ -181,7 +186,7 @@ wolfboot.hex: wolfboot.elf align: wolfboot-align.bin -.bootloader-partition-size: FORCE +.bootloader-partition-size: @printf "%d" $(WOLFBOOT_PARTITION_BOOT_ADDRESS) > .wolfboot-offset @printf "%d" $(ARCH_FLASH_OFFSET) > .wolfboot-arch-offset @expr `cat .wolfboot-offset` - `cat .wolfboot-arch-offset` > .bootloader-partition-size @@ -202,7 +207,7 @@ test-app/image.bin: wolfboot-align.bin standalone: @make -C test-app TARGET=$(TARGET) EXT_FLASH=$(EXT_FLASH) SPI_FLASH=$(SPI_FLASH) ARCH=$(ARCH) \ - V=$(V) RAM_CODE=$(RAM_CODE) WOLFBOOT_VERSION=$(WOLFBOOT_VERSION)\ + NO_XIP=$(NO_XIP) V=$(V) RAM_CODE=$(RAM_CODE) WOLFBOOT_VERSION=$(WOLFBOOT_VERSION)\ MCUXPRESSO=$(MCUXPRESSO) MCUXPRESSO_CPU=$(MCUXPRESSO_CPU) MCUXPRESSO_DRIVERS=$(MCUXPRESSO_DRIVERS) \ MCUXPRESSO_CMSIS=$(MCUXPRESSO_CMSIS) NVM_FLASH_WRITEONCE=$(NVM_FLASH_WRITEONCE) \ FREEDOM_E_SDK=$(FREEDOM_E_SDK) standalone @@ -223,9 +228,18 @@ rsa2048.der: rsa4096.der: @python3 tools/keytools/keygen.py $(KEYGEN_OPTIONS) src/rsa4096_pub_key.c +keytools: + @make -C tools/keytools + factory.bin: $(BOOT_IMG) wolfboot-align.bin $(PRIVATE_KEY) @echo "\t[SIGN] $(BOOT_IMG)" +ifneq ("$(wildcard ./tools/keytools/sign)","") + @echo "\n./tools/keytools/sign $(SIGN_OPTIONS) $(BOOT_IMG) $(PRIVATE_KEY) 1" + $(Q)./tools/keytools/sign $(SIGN_OPTIONS) $(BOOT_IMG) $(PRIVATE_KEY) 1 +else + @echo "\npython3 tools/keytools/sign.py $(SIGN_OPTIONS) $(BOOT_IMG) $(PRIVATE_KEY) 1" $(Q)python3 tools/keytools/sign.py $(SIGN_OPTIONS) $(BOOT_IMG) $(PRIVATE_KEY) 1 +endif @echo "\t[MERGE] $@" @cat wolfboot-align.bin test-app/image_v1_signed.bin > $@ @@ -255,6 +269,7 @@ clean: distclean: clean @rm -f *.pem *.der tags ./src/ed25519_pub_key.c ./src/ecc256_pub_key.c ./src/rsa2048_pub_key.c include/target.h + @make -C tools/keytools clean include/target.h: include/target.h.in FORCE @cat include/target.h.in | \ @@ -262,7 +277,11 @@ include/target.h: include/target.h.in FORCE sed -e "s/##WOLFBOOT_SECTOR_SIZE##/$(WOLFBOOT_SECTOR_SIZE)/g" | \ sed -e "s/##WOLFBOOT_PARTITION_BOOT_ADDRESS##/$(WOLFBOOT_PARTITION_BOOT_ADDRESS)/g" | \ sed -e "s/##WOLFBOOT_PARTITION_UPDATE_ADDRESS##/$(WOLFBOOT_PARTITION_UPDATE_ADDRESS)/g" | \ - sed -e "s/##WOLFBOOT_PARTITION_SWAP_ADDRESS##/$(WOLFBOOT_PARTITION_SWAP_ADDRESS)/g" \ + sed -e "s/##WOLFBOOT_PARTITION_SWAP_ADDRESS##/$(WOLFBOOT_PARTITION_SWAP_ADDRESS)/g" | \ + sed -e "s/##WOLFBOOT_DTS_BOOT_ADDRESS##/$(WOLFBOOT_DTS_BOOT_ADDRESS)/g" | \ + sed -e "s/##WOLFBOOT_DTS_UPDATE_ADDRESS##/$(WOLFBOOT_DTS_UPDATE_ADDRESS)/g" | \ + sed -e "s/##WOLFBOOT_LOAD_ADDRESS##/$(WOLFBOOT_LOAD_ADDRESS)/g" | \ + sed -e "s/##WOLFBOOT_LOAD_DTS_ADDRESS##/$(WOLFBOOT_LOAD_DTS_ADDRESS)/g" \ > $@ config: FORCE diff --git a/README.md b/README.md index a5fc3ebcb..eb8077d5b 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ microcontrollers will be added later. Relocating the interrupt vector can be dis - Change the entry point of the firmware image to account for bootloader presence - Equip the application with the [wolfBoot library](docs/API.md) to interact with the bootloader - [Configure and compile](docs/compile.md) a bootable image with a single "make" command + - For help signing firmware see [wolfBoot Signing](docs/Signing.md) ### Examples provided @@ -101,23 +102,19 @@ Traceback (most recent call last): AttributeError: 'EccPrivate' object has no attribute 'sign_raw' ``` -You need to install the latest wolfcrypt-pi here: https://github.com/wolfSSL/wolfcrypt-py +You need to install the latest wolfcrypt-py here: https://github.com/wolfSSL/wolfcrypt-py Use `pip3 install wolfcrypt`. -Make sure the wolfSSL library has been built with: -```sh - -``` -To install based on a local wolfSSL installation use: +Or to install based on a local wolfSSL installation use: ```sh -cd youwolfssldir -./configure --enable-keygen --enable-rsa --enable-ecc --enable-ed25519 CFLAGS="-DWOLFSSL_PUBLIC_MP" +cd wolfssl +./configure --enable-keygen --enable-rsa --enable-ecc --enable-ed25519 --enable-des3 CFLAGS="-DFP_MAX_BITS=8192 -DWOLFSSL_PUBLIC_MP" make sudo make install -cd yourwolfcryptpydir +cd wolfcrypt-py USE_LOCAL_WOLFSSL=/usr/local pip3 install . ``` diff --git a/arch.mk b/arch.mk index 1d1237765..0be09893c 100644 --- a/arch.mk +++ b/arch.mk @@ -1,5 +1,7 @@ ## CPU Architecture selection via $ARCH +UPDATE_OBJS:=./src/update_flash.o + # check for FASTMATH or SP_MATH ifeq ($(SPMATH),1) MATH_OBJS:=./lib/wolfssl/wolfcrypt/src/sp_int.o @@ -29,6 +31,13 @@ endif WOLFCRYPT_OBJS+=./lib/wolfssl/wolfcrypt/src/sha256.o ## ARM +ifeq ($(ARCH),AARCH64) + CROSS_COMPILE:=aarch64-none-elf- + CFLAGS+=-DARCH_AARCH64 -march=armv8-a + OBJS+=src/boot_aarch64.o src/boot_aarch64_start.o + CFLAGS+=-DNO_QNX +endif + ifeq ($(ARCH),ARM) CROSS_COMPILE:=arm-none-eabi- CFLAGS+=-mthumb -mlittle-endian -mthumb-interwork -DARCH_ARM @@ -149,3 +158,13 @@ ifeq ($(TARGET),stm32wb) -DSTM32WB55xx endif endif + + +## Update mechanism +ifeq ($(ARCH),AARCH64) + CFLAGS+=-DMMU + UPDATE_OBJS:=src/update_ram.o +endif +ifeq ($(DUALBANK_SWAP),1) + UPDATE_OBJS:=src/update_flash_hwswap.o +endif diff --git a/config/examples/hifive1.config b/config/examples/hifive1.config index f793db3cf..f924aafe8 100644 --- a/config/examples/hifive1.config +++ b/config/examples/hifive1.config @@ -1,6 +1,7 @@ ARCH?=RISCV TARGET?=hifive1 SIGN?=ECC256 +HASH?=SHA256 FREEDOM_E_SDK?=~/src/freedom-e-sdk DEBUG?=0 VTOR?=1 diff --git a/config/examples/kinetis-k82f.config b/config/examples/kinetis-k82f.config index 3f832222d..b212891bf 100644 --- a/config/examples/kinetis-k82f.config +++ b/config/examples/kinetis-k82f.config @@ -1,6 +1,7 @@ ARCH?=ARM TARGET?=kinetis SIGN?=ECC256 +HASH?=SHA256 MCUXPRESSO?=$(HOME)/src/FRDM-K82F MCUXPRESSO_CPU?=MK82FN256VLL15 MCUXPRESSO_DRIVERS?=$(MCUXPRESSO)/devices/MK82F25615 diff --git a/config/examples/raspi3.config b/config/examples/raspi3.config new file mode 100644 index 000000000..114374b72 --- /dev/null +++ b/config/examples/raspi3.config @@ -0,0 +1,29 @@ +ARCH?=AARCH64 +TARGET?=raspi3 +SIGN?=RSA4096 +HASH?=SHA3 +DEBUG?=1 +VTOR?=1 +CORTEX_M0?=0 +NO_ASM?=0 +EXT_FLASH?=0 +SPI_FLASH?=0 +ALLOW_DOWNGRADE?=0 +NVM_FLASH_WRITEONCE?=0 +WOLFBOOT_VERSION?=0 +V?=0 +SPMATH?=1 +RAM_CODE?=0 +DUALBANK_SWAP?=0 +IMAGE_HEADER_SIZE?=256 +PKA?=1 +WOLFTPM?=0 +WOLFBOOT_PARTITION_SIZE=0xF60000 +WOLFBOOT_SECTOR_SIZE=0x20000 +WOLFBOOT_PARTITION_BOOT_ADDRESS?=0xc0000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x10c0000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x1000000 +WOLFBOOT_LOAD_ADDRESS?=0x3000000 +WOLFBOOT_LOAD_DTS_ADDRESS?=0x4000000 +WOLFBOOT_DTS_BOOT_ADDRESS?=0xa0000 +WOLFBOOT_DTS_UPDATE_ADDRESS?=0x10a0000 diff --git a/config/examples/stm32f4.config b/config/examples/stm32f4.config index e50c738f9..20bfe5a7c 100644 --- a/config/examples/stm32f4.config +++ b/config/examples/stm32f4.config @@ -1,6 +1,7 @@ ARCH?=ARM TARGET?=stm32f4 SIGN?=ED25519 +HASH?=SHA256 DEBUG?=0 VTOR?=1 CORTEX_M0?=0 diff --git a/config/examples/stm32f7-dualbank.config b/config/examples/stm32f7-dualbank.config index 4017af792..6df277816 100644 --- a/config/examples/stm32f7-dualbank.config +++ b/config/examples/stm32f7-dualbank.config @@ -1,6 +1,7 @@ ARCH?=ARM TARGET?=stm32f7 SIGN?=ECC256 +HASH?=SHA256 DEBUG?=0 VTOR?=1 CORTEX_M0?=0 diff --git a/config/examples/stm32g0.config b/config/examples/stm32g0.config index 1ac893124..22d98bb70 100644 --- a/config/examples/stm32g0.config +++ b/config/examples/stm32g0.config @@ -1,6 +1,7 @@ ARCH?=ARM TARGET?=stm32g0 SIGN?=ED25519 +HASH?=SHA256 DEBUG?=0 VTOR?=1 CORTEX_M0?=1 diff --git a/config/examples/stm32h7.config b/config/examples/stm32h7.config index 41e5a8c5e..6164ca7d4 100644 --- a/config/examples/stm32h7.config +++ b/config/examples/stm32h7.config @@ -1,6 +1,7 @@ ARCH?=ARM TARGET?=stm32h7 SIGN?=ECC256 +HASH?=SHA256 DEBUG?=0 VTOR?=1 CORTEX_M0?=0 diff --git a/config/examples/stm32l0.config b/config/examples/stm32l0.config index 512f818b4..bcd1c878e 100644 --- a/config/examples/stm32l0.config +++ b/config/examples/stm32l0.config @@ -1,6 +1,7 @@ ARCH?=ARM TARGET?=stm32l0 SIGN?=ED25519 +HASH?=SHA256 DEBUG?=0 VTOR?=1 CORTEX_M0?=1 diff --git a/config/examples/stm32wb-small.config b/config/examples/stm32wb-small.config index e7de69c1c..929b841de 100644 --- a/config/examples/stm32wb-small.config +++ b/config/examples/stm32wb-small.config @@ -1,5 +1,6 @@ TARGET=stm32wb SIGN=ECC256 +HASH?=SHA256 WOLFBOOT_PARTITION_BOOT_ADDRESS=0xA000 WOLFBOOT_PARTITION_SIZE=0x4000 PKA=1 diff --git a/config/examples/stm32wb-tpm.config b/config/examples/stm32wb-tpm.config index 9587b7c30..0e2db8a14 100644 --- a/config/examples/stm32wb-tpm.config +++ b/config/examples/stm32wb-tpm.config @@ -1,5 +1,6 @@ TARGET=stm32wb SIGN=ECC256 +HASH?=SHA256 WOLFBOOT_SECTOR_SIZE?=0x20000 WOLFBOOT_PARTITION_SIZE?=0x60000 WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x20000 diff --git a/config/examples/stm32wb.config b/config/examples/stm32wb.config index 5f4634212..bca891d54 100644 --- a/config/examples/stm32wb.config +++ b/config/examples/stm32wb.config @@ -1,5 +1,6 @@ TARGET=stm32wb SIGN=ECC256 +HASH?=SHA256 WOLFBOOT_SECTOR_SIZE?=0x20000 WOLFBOOT_PARTITION_SIZE?=0x60000 WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x20000 diff --git a/config/examples/zynqmp.config b/config/examples/zynqmp.config new file mode 100644 index 000000000..25e64eca5 --- /dev/null +++ b/config/examples/zynqmp.config @@ -0,0 +1,39 @@ +ARCH?=AARCH64 +TARGET?=zynq +SIGN?=RSA4096 +HASH?=SHA3 +DEBUG?=0 +VTOR?=1 +CORTEX_M0?=0 +NO_ASM?=0 +ALLOW_DOWNGRADE?=0 +NVM_FLASH_WRITEONCE?=0 +WOLFBOOT_VERSION?=0 +V?=0 +SPMATH?=1 +RAM_CODE?=0 +DUALBANK_SWAP?=0 +IMAGE_HEADER_SIZE?=1024 +PKA?=1 +WOLFTPM?=0 +EXT_FLASH?=1 +SPI_FLASH?=0 +NO_XIP=1 + +# Flash Sector Size +WOLFBOOT_SECTOR_SIZE=0x20000 +# Application Partition Size +WOLFBOOT_PARTITION_SIZE=0x2A00000 +# Location in Flash for wolfBoot +WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x800000 +# Load Partition to RAM Address +WOLFBOOT_LOAD_ADDRESS?=0x10000000 +# Location in Flash for Secondary Partition +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x3A00000 +# Location to store wolfBoot state +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x63E0000 + +# DTS (Device Tree) +WOLFBOOT_LOAD_DTS_ADDRESS?=0x11800000 +WOLFBOOT_DTS_BOOT_ADDRESS?=0x7B0000 +WOLFBOOT_DTS_UPDATE_ADDRESS?=0x39B0000 diff --git a/docs/Signing.md b/docs/Signing.md new file mode 100644 index 000000000..1fe2b191e --- /dev/null +++ b/docs/Signing.md @@ -0,0 +1,86 @@ +# wolfBoot Signing + +Instructions for setting up Python, wolfCrypt-py module and wolfBoot for firmware signing. + +Note: There is a pure C signing tool available as well. See [C Signing Tool](#c-signing-tool) below. + +## Install Python3 + +1. Download latest Python 3.x and run installer: https://www.python.org/downloads +2. Check the box that says Add Python 3.x to PATH + +## Install wolfCrypt + +```sh +git clone https://github.com/wolfSSL/wolfssl.git +cd wolfssl +./configure --enable-keygen --enable-rsa --enable-ecc --enable-ed25519 --enable-des3 CFLAGS="-DWOLFSSL_PUBLIC_MP" +make +sudo make install +``` + +## Install wolfcrypt-py + +```sh +git clone https://github.com/wolfSSL/wolfcrypt-py.git +cd wolfcrypt-py +sudo USE_LOCAL_WOLFSSL=/usr/local pip3 install . +``` + +## Install wolfBoot + +```sh +git clone https://github.com/wolfSSL/wolfBoot.git +cd wolfBoot +git submodule update --init +# Setup configuration (or copy template from ./config/examples) +make config +# Build the wolfBoot binary and sign an example test application +make +``` + +## Signing Firmware + +1. Load the private key to use for signing into “./rsa4096.der” +2. `python3 ./tools/keytools/sign.py --rsa4096 --sha3 test-app/image.bin rsa4096.der 1` + +Note: The last argument is the “version” number. + +## Signing Firmware with External Private Key (HSM) + +I've tested this with separate signature and the correct public key, the two files are identical either if I do one step signing: + +```sh +# Create file with Public Key +openssl rsa -inform DER -outform DER -in rsa4096.der -out rsa4096_pub.der -pubout + +# Generate Hash to Sign +python3 ./tools/keytools/sign.py --rsa4096 --sha-only --sha3 test-app/image.bin rsa4096_pub.der 1 + +# Example for signing +openssl rsautl -sign -keyform der -inkey rsa4096.der -in test-app/image_v1_digest.bin > test-app/image_v1.sig + +# Generate final signed binary +python3 ./tools/keytools/sign.py --rsa4096 --sha3 --manual-sign test-app/image.bin rsa4096_pub.der 1 test-app/image_v1.sig +``` + +## C Signing Tool + +A standalone C version of the signing tool is available here: `./tools/keytools/sign.c`. Build using `make keytools` + +```sh +./tools/keytools/sign --rsa4096 --sha3 test-app/image.bin rsa4096.der 1 +``` + +### Windows Visual Studio + +Use the `wolfBootSignTool.vcxproj` Visual Studio project to build the `sign.exe` tool for use on Windows. + + +## Command Line Usage + +``` +./tools/keytools/sign [--ed25519 | --ecc256 | --rsa2048 | --rsa4096 ] [--sha256 | --sha3] [--wolfboot-update] image key.der fw_version + - or - ./tools/keytools/sign [--sha256 | --sha3] [--sha-only] [--wolfboot-update] image pub_key.der fw_version + - or - ./tools/keytools/sign [--ed25519 | --ecc256 | --rsa2048 | --rsa4096 ] [--sha256 | --sha3] [--manual-sign] image pub_key.der fw_version signature.sig +``` diff --git a/docs/Targets.md b/docs/Targets.md index 013172a47..32b6b7c38 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -412,6 +412,22 @@ Upon reboot, wolfboot will elect the best candidate (version 2 in this case) and If the accepted candidate image resides on BANK B (like in this case), wolfBoot will perform one bank swap before booting. +### Debugging + +Debugging with OpenOCD: + +Use the OpenOCD configuration from the previous section to run OpenOCD. + +From another console, connect using gdb, e.g.: + +Add wolfboot.elf to the make. + +``` +arm-none-eabi-gdb wolfboot.elf -ex "set remotetimeout 240" -ex "target extended-remote localhost:3333" +(gdb) add-symbol-file test-app/image.elf 0x08020000 +(gdb) add-symbol-file wolfboot.elf 0x08000000 +``` + ## LPC54606 @@ -440,9 +456,8 @@ r h ``` -### Debugging +### Debugging with JLink -Debugging with JLink: ``` JLinkGDBServer -device LPC606J512 -if SWD -speed 4000 -port 3333 ``` @@ -453,3 +468,87 @@ Then, from another console: arm-none-eabi-gdb wolfboot.elf -ex "target remote localhost:3333" (gdb) add-symbol-file test-app/image.elf 0x0000a100 ``` + + +## Cortex-A53 / Raspberry PI 3 (experimental) + +Tested using `https://github.com/raspberrypi/linux` + +### Compiling the kernel + +* Get raspberry-pi linux kernel: + +``` +git clone https://github.com/raspberrypi/linux linux-rpi -b rpi-4.19.y --depth=1 +``` + +* Build kernel image: + +``` +cd linux-rpi +make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcmrpi3_defconfig +make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- +``` + +* Copy Image and .dtb to the wolfboot directory + +``` +cp Image arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dtb $wolfboot_dir +cd $wolfboot_dir +``` + +### Testing with qemu-system-aarch64 + +* Build wolfboot using the example configuration (RSA4096, SHA3) + +``` +cp config/examples/raspi3.config .config +make wolfboot-align.bin +``` + +* Sign Image and DTB (Device Tree Blob) +``` +tools/keytools/sign.py --rsa4096 --sha3 Image rsa4096.der 1 +tools/keytools/sign.py --rsa4096 --sha3 bcm2710-rpi-3-b.dtb rsa4096.der 1 +``` + +* Compose the image + +``` +cat wolfboot-align.bin Image_v1_signed.bin >wolfboot_linux_raspi.bin +dd if=bcm2710-rpi-3-_v1_signed.bin of=wolfboot_linux_raspi.bin bs=1 seek=128K conv=notrunc +``` + +* Test boot using qemu + +``` +qemu-system-aarch64 -M raspi3 -m 512 -serial stdio -kernel wolfboot_linux_raspi.bin -append "terminal=ttyS0 rootwait" -dtb ./bcm2710-rpi-3-b.dtb -cpu cortex-a53 +``` + +## Xilinx Zynq UltraScale+ (Aarch64) + +Build configuration options (``.config`): + +``` +TARGET=zynq +ARCH=AARCH64 +SIGN=RSA4096 +HASH=SHA3 +``` + +### QNX + +```sh +source qnx700/qnxsdp-env.sh +cd wolfBoot +make clean +make CROSS_COMPILE=aarch64-unknown-nto-qnx7.0.0- +``` + +#### Debugging + +`qemu-system-aarch64 -M raspi3 -kernel /home/dan/src/wolfboot/factory.bin -serial stdio -gdb tcp::3333 -S` + +#### Signing + +`tools/keytools/sign.py --rsa4096 --sha3 /srv/linux-rpi4/vmlinux.bin rsa4096.der 1` diff --git a/docs/compile.md b/docs/compile.md index d3a8e2ca4..261a2d8db 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -150,6 +150,11 @@ To associate the update or the swap partition to an external memory, define `PAR `PART_SWAP_EXT`, respectively. By default, the makefile assumes that if an external memory is present, both `PART_UPDATE_EXT` and `PART_SWAP_EXT` are defined. +If the `NO_XIP=1` makefile option is present, `PART_BOOT_EXT` is assumed too, as no execute-in-place is +available on the system. This is typically the case of MMU system (e.g. Cortex-A) where the operating system +image(s) are position-independent ELF images stored in a non-executable non-volatile memory, and must be +copied in RAM to boot after verification. + When external memory is used, the HAL API must be extended to define methods to access the custom memory. Refer to the [HAL](HAL.md) page for the description of the `ext_flash_*` API. diff --git a/hal/raspi3.c b/hal/raspi3.c new file mode 100644 index 000000000..932e75a08 --- /dev/null +++ b/hal/raspi3.c @@ -0,0 +1,74 @@ +/* raspi3.c + * + * Copyright (C) 2020 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include +#include +#include +#include "image.h" +#ifndef ARCH_AARCH64 +# error "wolfBoot raspi3 HAL: wrong architecture selected. Please compile with ARCH=AARCH64." +#endif + + +#define CORTEXA53_0_CPU_CLK_FREQ_HZ 1099989014 +#define CORTEXA53_0_TIMESTAMP_CLK_FREQ 99998999 + + +/* QSPI functions */ +void qspi_init(uint32_t cpu_clock, uint32_t flash_freq) +{ +} + + +void zynq_init(uint32_t cpu_clock) +{ +} + + + +/* public HAL functions */ +void hal_init(void) +{ +} + +void hal_prepare_boot(void) +{ +} + + +int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len) +{ + return 0; +} + +void RAMFUNCTION hal_flash_unlock(void) +{ +} + +void RAMFUNCTION hal_flash_lock(void) +{ +} + + +int RAMFUNCTION hal_flash_erase(uint32_t address, int len) +{ + return 0; +} diff --git a/hal/raspi3.ld b/hal/raspi3.ld new file mode 100644 index 000000000..4bd8b5fd4 --- /dev/null +++ b/hal/raspi3.ld @@ -0,0 +1,55 @@ +MEMORY +{ + DDR_MEM(rwx): ORIGIN = 0x00080000, LENGTH = 0x80000000 +} +ENTRY(_vector_table); + +SECTIONS +{ + .text : + { + _start_text = .; + KEEP(*(.boot*)) + *(.text*) + *(.rodata*) + *(.note.*) + . = ALIGN(4); + _end_text = .; + } > DDR_MEM + .edidx : + { + . = ALIGN(4); + *(.ARM.exidx*) + } > DDR_MEM + + .edidx : + { + . = ALIGN(4); + *(.ARM.exidx*) + } > DDR_MEM + + .data : + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(4); + KEEP(*(.ramcode)) + . = ALIGN(4); + _end_data = .; + } > DDR_MEM + + .bss (NOLOAD) : + { + _start_bss = .; + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _end_bss = .; + __bss_end__ = .; + _end = .; + } > DDR_MEM + . = ALIGN(4); +} + +END_STACK = _start_text; diff --git a/hal/spi/spi_drv_zynq.c b/hal/spi/spi_drv_zynq.c new file mode 100644 index 000000000..78a6e3883 --- /dev/null +++ b/hal/spi/spi_drv_zynq.c @@ -0,0 +1,71 @@ +/* spi_drv_zynq.c + * + * Copyright (C) 2020 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + * Driver for the SPI back-end of the SPI_FLASH module. + * + * Example implementation for Zynq, using QSPI. + * + * Pinout: see spi_drv_zynq.h + */ + +#include +#include "spi_drv.h" +#include "spi_drv_zynq.h" + +#ifdef SPI_FLASH + +void spi_cs_off(int pin) +{ + (void)pin; +} + +void spi_cs_on(int pin) +{ + (void)pin; +} + +uint8_t spi_read(void) +{ + return 0; +} + +void spi_write(const char byte) +{ + +} + + +void spi_init(int polarity, int phase) +{ + static int initialized = 0; + if (!initialized) { + initialized++; + + (void)polarity; + (void)phase; + } +} + +void spi_release(void) +{ + +} + +#endif diff --git a/hal/spi/spi_drv_zynq.h b/hal/spi/spi_drv_zynq.h new file mode 100644 index 000000000..ec53bb5f9 --- /dev/null +++ b/hal/spi/spi_drv_zynq.h @@ -0,0 +1,24 @@ +/* spi_drv_zynq.h + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifndef SPI_DRV_ZYNQ_H_INCLUDED +#define SPI_DRV_ZYNQ_H_INCLUDED +#include + +#define SPI_CS_FLASH 0 + +#endif /* !SPI_DRV_ZYNQ_H_INCLUDED */ diff --git a/hal/zynq.c b/hal/zynq.c new file mode 100644 index 000000000..fc7f03267 --- /dev/null +++ b/hal/zynq.c @@ -0,0 +1,1090 @@ +/* zynq.c + * + * Copyright (C) 2020 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include +#include + +#if defined(__QNXNTO__) && !defined(NO_QNX) + #define USE_QNX +#endif + +#ifdef DEBUG_ZYNQ + #include + #ifndef USE_QNX + #include "xil_printf.h" + #endif +#endif + +#include +#include "image.h" +#ifndef ARCH_AARCH64 +# error "wolfBoot zynq HAL: wrong architecture selected. Please compile with ARCH=AARCH64." +#endif + +#ifdef USE_QNX + #include + #include "xzynq_gqspi.h" +#endif + +#define CORTEXA53_0_CPU_CLK_FREQ_HZ 1099989014 +#define CORTEXA53_0_TIMESTAMP_CLK_FREQ 99998999 + +/* Generic Quad-SPI */ +#define QSPI_BASE 0xFF0F0000UL +#define LQSPI_EN (*((volatile uint32_t*)(QSPI_BASE + 0x14))) /* SPI enable: 0: disable the SPI, 1: enable the SPI */ +#define GQSPI_CFG (*((volatile uint32_t*)(QSPI_BASE + 0x100))) /* configuration register. */ +#define GQSPI_ISR (*((volatile uint32_t*)(QSPI_BASE + 0x104))) /* interrupt status register. */ +#define GQSPI_IER (*((volatile uint32_t*)(QSPI_BASE + 0x108))) /* interrupt enable register. */ +#define GQSPI_IDR (*((volatile uint32_t*)(QSPI_BASE + 0x10C))) /* interrupt disable register. */ +#define GQSPI_IMR (*((volatile uint32_t*)(QSPI_BASE + 0x110))) /* interrupt unmask register. */ +#define GQSPI_EN (*((volatile uint32_t*)(QSPI_BASE + 0x114))) /* enable register. */ +#define GQSPI_TXD (*((volatile uint32_t*)(QSPI_BASE + 0x11C))) /* TX data register. Keyhole addresses for the transmit data FIFO. */ +#define GQSPI_RXD (*((volatile uint32_t*)(QSPI_BASE + 0x120))) /* RX data register. */ +#define GQSPI_TX_THRESH (*((volatile uint32_t*)(QSPI_BASE + 0x128))) /* TXFIFO Threshold Level register: (bits 5:0) Defines the level at which the TX_FIFO_NOT_FULL interrupt is generated */ +#define GQSPI_RX_THRESH (*((volatile uint32_t*)(QSPI_BASE + 0x12C))) /* RXFIFO threshold level register: (bits 5:0) Defines the level at which the RX_FIFO_NOT_EMPTY interrupt is generated */ +#define GQSPI_GPIO (*((volatile uint32_t*)(QSPI_BASE + 0x130))) +#define GQSPI_LPBK_DLY_ADJ (*((volatile uint32_t*)(QSPI_BASE + 0x138))) /* adjusting the internal loopback clock delay for read data capturing */ +#define GQSPI_GEN_FIFO (*((volatile uint32_t*)(QSPI_BASE + 0x140))) /* generic FIFO data register. Keyhole addresses for the generic FIFO. */ +#define GQSPI_SEL (*((volatile uint32_t*)(QSPI_BASE + 0x144))) /* select register. */ +#define GQSPI_FIFO_CTRL (*((volatile uint32_t*)(QSPI_BASE + 0x14C))) /* FIFO control register. */ +#define GQSPI_GF_THRESH (*((volatile uint32_t*)(QSPI_BASE + 0x150))) /* generic FIFO threshold level register: (bits 4:0) Defines the level at which the GEN_FIFO_NOT_FULL interrupt is generated */ +#define GQSPI_POLL_CFG (*((volatile uint32_t*)(QSPI_BASE + 0x154))) /* poll configuration register */ +#define GQSPI_P_TIMEOUT (*((volatile uint32_t*)(QSPI_BASE + 0x158))) /* poll timeout register. */ +#define GQSPI_XFER_STS (*((volatile uint32_t*)(QSPI_BASE + 0x15C))) /* transfer status register. */ +#define QSPI_DATA_DLY_ADJ (*((volatile uint32_t*)(QSPI_BASE + 0x1F8))) /* adjusting the internal receive data delay for read data capturing */ +#define GQSPI_MOD_ID (*((volatile uint32_t*)(QSPI_BASE + 0x1FC))) +#define QSPIDMA_DST_STS (*((volatile uint32_t*)(QSPI_BASE + 0x808))) +#define QSPIDMA_DST_CTRL (*((volatile uint32_t*)(QSPI_BASE + 0x80C))) +#define QSPIDMA_DST_I_STS (*((volatile uint32_t*)(QSPI_BASE + 0x814))) +#define QSPIDMA_DST_CTRL2 (*((volatile uint32_t*)(QSPI_BASE + 0x824))) + +/* 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 */ +/* 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 */ +#define GQSPI_CFG_BAUD_RATE_DIV_MASK (7UL << 3) +#define GQSPI_CFG_BAUD_RATE_DIV(d) ((d << 3) & GQSPI_CFG_BAUD_RATE_DIV_MASK) +#define GQSPI_CFG_WP_HOLD (1UL << 19) /* If set, Holdb and WPn pins are actively driven by the qspi controller in 1-bit and 2-bit modes. */ +#define GQSPI_CFG_EN_POLL_TIMEOUT (1UL << 20) /* Poll Timeout Enable: 0: disable, 1: enable */ +#define GQSPI_CFG_ENDIAN (1UL << 26) /* Endian format transmit data register: 0: little endian, 1: big endian */ +#define GQSPI_CFG_START_GEN_FIFO (1UL << 28) /* Trigger Generic FIFO Command Execution: 0:disable executing requests, 1: enable executing requests */ +#define GQSPI_CFG_GEN_FIFO_START_MODE (1UL << 29) /* Start mode of Generic FIFO: 0: Auto Start Mode, 1: Manual Start Mode */ +#define GQSPI_CFG_MODE_EN_MASK (3UL << 30) /* Flash memory interface mode control: 00: IO mode, 10: DMA mode */ +#define GQSPI_CFG_MODE_EN(m) ((m << 30) & GQSPI_CFG_MODE_EN_MASK) +#define GQSPI_CFG_MODE_EN_IO GQSPI_CFG_MODE_EN(0) +#define GQSPI_CFG_MODE_EN_DMA GQSPI_CFG_MODE_EN(2) + +/* GQSPI_ISR / GQSPI_IER / GQSPI_IDR / GQSPI_IMR: Interrupt registers */ +#define GQSPI_IXR_RX_FIFO_EMPTY (1UL << 11) +#define GQSPI_IXR_GEN_FIFO_FULL (1UL << 10) +#define GQSPI_IXR_GEN_FIFO_NOT_FULL (1UL << 9) +#define GQSPI_IXR_TX_FIFO_EMPTY (1UL << 8) +#define GQSPI_IXR_GEN_FIFO_EMPTY (1UL << 7) +#define GQSPI_IXR_RX_FIFO_FULL (1UL << 5) +#define GQSPI_IXR_RX_FIFO_NOT_EMPTY (1UL << 4) +#define GQSPI_IXR_TX_FIFO_FULL (1UL << 3) +#define GQSPI_IXR_TX_FIFO_NOT_FULL (1UL << 2) +#define GQSPI_IXR_POLL_TIME_EXPIRE (1UL << 1) + +#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) +#define GQSPI_ISR_WR_TO_CLR_MASK 0x00000002U + +/* GQSPI_GEN_FIFO: FIFO data register */ +/* bits 0-7: Length in bytes (except when GQSPI_GEN_FIFO_EXP_MASK is set length as 255 chunks) */ +#define GQSPI_GEN_FIFO_IMM_MASK (0xFFUL) /* Immediate Data Field */ +#define GQSPI_GEN_FIFO_IMM(imm) (imm & GQSPI_GEN_FIFO_IMM_MASK) +#define GQSPI_GEN_FIFO_DATA_XFER (1UL << 8) /* Indicates IMM is size, otherwise byte is sent directly in IMM reg */ +#define GQSPI_GEN_FIFO_EXP_MASK (1UL << 9) /* Length is Exponent (length / 255) */ +#define GQSPI_GEN_FIFO_MODE_MASK (3UL << 10) +#define GQSPI_GEN_FIFO_MODE(m) ((m << 10) & GQSPI_GEN_FIFO_MODE_MASK) +#define GQSPI_GEN_FIFO_MODE_SPI GQSPI_GEN_FIFO_MODE(1) +#define GQSPI_GEN_FIFO_MODE_DSPI GQSPI_GEN_FIFO_MODE(2) +#define GQSPI_GEN_FIFO_MODE_QSPI GQSPI_GEN_FIFO_MODE(3) +#define GQSPI_GEN_FIFO_CS_MASK (3UL << 12) +#define GQSPI_GEN_FIFO_CS(c) ((c << 12) & GQSPI_GEN_FIFO_CS_MASK) +#define GQSPI_GEN_FIFO_CS_LOWER GQSPI_GEN_FIFO_CS(1) +#define GQSPI_GEN_FIFO_CS_UPPER GQSPI_GEN_FIFO_CS(2) +#define GQSPI_GEN_FIFO_CS_BOTH GQSPI_GEN_FIFO_CS(3) +#define GQSPI_GEN_FIFO_BUS_MASK (3UL << 14) +#define GQSPI_GEN_FIFO_BUS(b) ((b << 14) & GQSPI_GEN_FIFO_BUS_MASK) +#define GQSPI_GEN_FIFO_BUS_LOW GQSPI_GEN_FIFO_BUS(1) +#define GQSPI_GEN_FIFO_BUS_UP GQSPI_GEN_FIFO_BUS(2) +#define GQSPI_GEN_FIFO_BUS_BOTH GQSPI_GEN_FIFO_BUS(3) +#define GQSPI_GEN_FIFO_TX (1UL << 16) +#define GQSPI_GEN_FIFO_RX (1UL << 17) +#define GQSPI_GEN_FIFO_STRIPE (1UL << 18) /* Stripe data across the lower and upper data buses. */ +#define GQSPI_GEN_FIFO_POLL (1UL << 19) + +/* GQSPI_FIFO_CTRL */ +#define GQSPI_FIFO_CTRL_RST_GEN_FIFO (1UL << 0) +#define GQSPI_FIFO_CTRL_RST_TX_FIFO (1UL << 1) +#define GQSPI_FIFO_CTRL_RST_RX_FIFO (1UL << 2) + +/* QSPIDMA_DST_CTRL */ +#define QSPIDMA_DST_CTRL_DEF 0x403FFA00UL +#define QSPIDMA_DST_CTRL2_DEF 0x081BFFF8UL + +/* QSPIDMA_DST_STS */ +#define QSPIDMA_DST_STS_WTC 0xE000U + +/* QSPIDMA_DST_I_STS */ +#define QSPIDMA_DST_I_STS_ALL_MASK 0xFEU + +/* IOP System-level Control */ +#define IOU_SLCR_BASSE 0xFF180000 +#define IOU_TAPDLY_BYPASS (*((volatile uint32_t*)(IOU_SLCR_BASSE + 390))) +#define IOU_TAPDLY_BYPASS_LQSPI_RX (1UL << 2) /* LQSPI Tap Delay Enable on Rx Clock signal. 0: enable. 1: disable (bypass tap delay). */ + + +/* QSPI Configuration */ +#define GQSPI_CLK_FREQ_HZ 124987511 +#define GQSPI_CLK_DIV 1 /* (CLK / (2 << val) = BUS) */ +#define GQSPI_CS_ASSERT_CLOCKS 5 /* CS Setup Time (tCSS) - num of clock cycles foes in IMM */ +#define GQSPI_QSPI_MODE GQSPI_GEN_FIFO_MODE_SPI +#define GQSPI_BUS_WIDTH 1 +#define GQPI_USE_DUAL_PARALLEL 1 +#define GQPI_USE_4BYTE_ADDR 1 +#define GQSPI_DUMMY_READ 10 /* Number of dummy clock cycles for reads */ +#define GQSPI_FIFO_WORD_SZ 4 +#define GQSPI_TIMEOUT_TRIES 100000 +#define QSPI_FLASH_READY_TRIES 1000 + +/* Flash Parameters: + * Micron Serial NOR Flash Memory 64KB Sector Erase MT25QU01GBBB + * Stacked device (two 512Mb die) + * Dual Parallel so total addressable size is double + */ +#define FLASH_DEVICE_SIZE 0x10000000 +#define FLASH_PAGE_SIZE 512 +#define FLASH_NUM_PAGES 0x80000 +#define FLASH_NUM_SECTORS (FLASH_DEVICE_SIZE/WOLFBOOT_SECTOR_SIZE) + + +/* Flash Commands */ +#define WRITE_ENABLE_CMD 0x06U +#define WRITE_DISABLE_CMD 0x04U +#define READ_ID_CMD 0x9FU +#define MULTI_IO_READ_ID_CMD 0xAFU +#define READ_FSR_CMD 0x70U +#define ENTER_QSPI_MODE_CMD 0x35U +#define EXIT_QSPI_MODE_CMD 0xF5U +#define ENTER_4B_ADDR_MODE_CMD 0xB7U +#define EXIT_4B_ADDR_MODE_CMD 0xE9U + +#define FAST_READ_CMD 0x0BU +#define QUAD_READ_4B_CMD 0x6CU + +#define PAGE_PROG_CMD 0x02U +#define QUAD_PAGE_PROG_4B_CMD 0x34U + +#define SEC_ERASE_CMD 0xD8U +#define SEC_4K_ERASE_CMD 0x20U + +#define RESET_ENABLE_CMD 0x66U +#define RESET_MEMORY_CMD 0x99U + +#define FLASH_READY_MASK 0x80 /* 0=Busy, 1=Ready */ + +/* Return Codes */ +#define GQSPI_CODE_SUCCESS 0 +#define GQSPI_CODE_FAILED -100 +#define GQSPI_CODE_TIMEOUT -101 + + +/* QSPI Slave Device Information */ +typedef struct QspiDev { + uint32_t mode; /* GQSPI_GEN_FIFO_MODE_SPI, GQSPI_GEN_FIFO_MODE_DSPI or GQSPI_GEN_FIFO_MODE_QSPI */ + uint32_t bus; /* GQSPI_GEN_FIFO_BUS_LOW, GQSPI_GEN_FIFO_BUS_UP or GQSPI_GEN_FIFO_BUS_BOTH */ + uint32_t cs; /* GQSPI_GEN_FIFO_CS_LOWER, GQSPI_GEN_FIFO_CS_UPPER */ + uint32_t stripe; /* OFF=0 or ON=GQSPI_GEN_FIFO_STRIPE */ +#ifdef USE_QNX + xzynq_qspi_t* qnx; +#endif +} QspiDev_t; + +static QspiDev_t mDev; + +#ifdef TEST_FLASH +static int test_flash(QspiDev_t* dev); +#endif + +#ifdef USE_QNX +static int qspi_transfer(QspiDev_t* pDev, + const uint8_t* cmdData, uint32_t cmdSz, + const uint8_t* txData, uint32_t txSz, + uint8_t* rxData, uint32_t rxSz, uint32_t dummySz) +{ + int ret; + qspi_buf cmd_buf; + qspi_buf tx_buf; + qspi_buf rx_buf; + uint32_t flags; + + flags = TRANSFER_FLAG_DEBUG; + if (pDev->mode & GQSPI_GEN_FIFO_MODE_QSPI) + flags |= TRANSFER_FLAG_MODE(TRANSFER_FLAG_MODE_QSPI); + else if (pDev->mode & GQSPI_GEN_FIFO_MODE_DSPI) + flags |= TRANSFER_FLAG_MODE(TRANSFER_FLAG_MODE_DSPI); + else + flags |= TRANSFER_FLAG_MODE(TRANSFER_FLAG_MODE_SPI); + if (pDev->stripe & GQSPI_GEN_FIFO_STRIPE) + flags |= TRANSFER_FLAG_STRIPE; + if (pDev->cs & GQSPI_GEN_FIFO_CS_LOWER) + flags |= TRANSFER_FLAG_LOW_DB | TRANSFER_FLAG_CS(TRANSFER_FLAG_CS_LOW); + else + flags |= TRANSFER_FLAG_UP_DB | TRANSFER_FLAG_CS(TRANSFER_FLAG_CS_UP); + + memset(&cmd_buf, 0, sizeof(cmd_buf)); + cmd_buf.offset = (uint8_t*)cmdData; + cmd_buf.len = cmdSz; + + memset(&tx_buf, 0, sizeof(tx_buf)); + tx_buf.offset = (uint8_t*)txData; + tx_buf.len = txSz; + + memset(&rx_buf, 0, sizeof(rx_buf)); + rx_buf.offset = rxData; + rx_buf.len = rxSz; + + /* Send the TX buffer */ + ret = xzynq_qspi_transfer(pDev->qnx, txData ? &tx_buf : NULL, + rxData ? &rx_buf : NULL, &cmd_buf, flags); + if (ret < 0) { + #ifdef DEBUG_ZYNQ + printf("QSPI Transfer failed! %d\n", ret); + #endif + return GQSPI_CODE_FAILED; + } + return GQSPI_CODE_SUCCESS; +} +#else +static inline int qspi_isr_wait(uint32_t wait_mask, uint32_t wait_val) +{ + uint32_t timeout = 0; + while ((GQSPI_ISR & wait_mask) == wait_val && + ++timeout < GQSPI_TIMEOUT_TRIES); + if (timeout == GQSPI_TIMEOUT_TRIES) { + return -1; + } + return 0; +} + +static int qspi_gen_fifo_write(uint32_t reg_genfifo) +{ + /* wait until the gen FIFO is not full to write */ + if (qspi_isr_wait(GQSPI_IXR_GEN_FIFO_NOT_FULL, 0)) { + return GQSPI_CODE_TIMEOUT; + } + +#if defined(DEBUG_ZYNQ) && DEBUG_ZYNQ >= 2 + printf("FifoEntry=%08x\n", reg_genfifo); +#endif + GQSPI_GEN_FIFO = reg_genfifo; + return GQSPI_CODE_SUCCESS; +} + +static int gspi_fifo_tx(const uint8_t* data, uint32_t sz) +{ + uint32_t tmp32, txSz; + uint8_t* txData = (uint8_t*)&tmp32; + + while (sz > 0) { + /* Wait for TX FIFO not full */ + if (qspi_isr_wait(GQSPI_IXR_TX_FIFO_FULL, GQSPI_IXR_TX_FIFO_FULL)) { + return GQSPI_CODE_TIMEOUT; + } + + /* Write data */ + txSz = sz; + if (txSz > GQSPI_FIFO_WORD_SZ) + txSz = GQSPI_FIFO_WORD_SZ; + tmp32 = 0; + memcpy(txData, data, txSz); + sz -= txSz; + data += txSz; + + #if defined(DEBUG_ZYNQ) && DEBUG_ZYNQ >= 3 + printf("TXD=%08x\n", tmp32); + #endif + GQSPI_TXD = tmp32; + } + return GQSPI_CODE_SUCCESS; +} + +static int gspi_fifo_rx(uint8_t* data, uint32_t sz, uint32_t discardSz) +{ + uint32_t tmp32, rxSz; + uint8_t* rxData = (uint8_t*)&tmp32; + + while (sz > 0) { + /* Wait for RX FIFO not empty */ + if (qspi_isr_wait(GQSPI_IXR_RX_FIFO_NOT_EMPTY, 0)) { + return GQSPI_CODE_TIMEOUT; + } + + /* Read data */ + tmp32 = GQSPI_RXD; + #if defined(DEBUG_ZYNQ) && DEBUG_ZYNQ >= 3 + printf("RXD=%08x\n", tmp32); + if (discardSz > 0) + printf("Discard %d\n", discardSz); + #endif + if (discardSz >= GQSPI_FIFO_WORD_SZ) { + discardSz -= GQSPI_FIFO_WORD_SZ; + continue; + } + + rxSz = sz; + if (rxSz > GQSPI_FIFO_WORD_SZ) + rxSz = GQSPI_FIFO_WORD_SZ; + if (rxSz > discardSz) { + rxSz -= discardSz; + sz -= discardSz; + } + memcpy(data, rxData + discardSz, rxSz); + discardSz = 0; + + sz -= rxSz; + data += rxSz; + } + return GQSPI_CODE_SUCCESS; +} + +static int qspi_cs(QspiDev_t* pDev, int csAssert) +{ + uint32_t reg_genfifo; + + /* Select slave bus, bank, mode and cs clocks */ + reg_genfifo = (pDev->bus & GQSPI_GEN_FIFO_BUS_MASK); + 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); + return qspi_gen_fifo_write(reg_genfifo); +} + +static int qspi_transfer(QspiDev_t* pDev, + const uint8_t* cmdData, uint32_t cmdSz, + const uint8_t* txData, uint32_t txSz, + uint8_t* rxData, uint32_t rxSz, uint32_t dummySz) +{ + int ret = GQSPI_CODE_SUCCESS; + uint32_t reg_genfifo, xferSz; + + GQSPI_EN = 1; /* Enable device */ + qspi_cs(pDev, 1); /* Select slave */ + + /* Setup bus slave selection */ + reg_genfifo = ((pDev->bus & GQSPI_GEN_FIFO_BUS_MASK) | + (pDev->cs & GQSPI_GEN_FIFO_CS_MASK) | + GQSPI_GEN_FIFO_MODE_SPI); + + /* Cmd Data */ + xferSz = cmdSz; + while (ret == GQSPI_CODE_SUCCESS && cmdData && xferSz > 0) { + /* Enable TX and send command inline */ + reg_genfifo |= GQSPI_GEN_FIFO_TX; + reg_genfifo &= ~(GQSPI_GEN_FIFO_RX | GQSPI_GEN_FIFO_IMM_MASK); + reg_genfifo |= GQSPI_GEN_FIFO_IMM(*cmdData); /* IMM is data */ + + /* Submit general FIFO operation */ + ret = qspi_gen_fifo_write(reg_genfifo); + if (ret != GQSPI_CODE_SUCCESS) + break; + + /* offset size and buffer */ + xferSz--; + cmdData++; + } + + /* Set desired data mode and stripe */ + reg_genfifo |= (pDev->mode & GQSPI_GEN_FIFO_MODE_MASK); + reg_genfifo |= (pDev->stripe & GQSPI_GEN_FIFO_STRIPE); + + /* TX Data */ + while (ret == GQSPI_CODE_SUCCESS && txData && txSz > 0) { + xferSz = txSz; + + /* Enable TX */ + reg_genfifo &= ~(GQSPI_GEN_FIFO_RX | GQSPI_GEN_FIFO_IMM_MASK | + GQSPI_GEN_FIFO_EXP_MASK); + reg_genfifo |= (GQSPI_GEN_FIFO_TX | GQSPI_GEN_FIFO_DATA_XFER); + + if (xferSz > GQSPI_GEN_FIFO_IMM_MASK) { + /* Use exponent mode */ + xferSz = 256; /* 2 ^ 8 = 256 */ + reg_genfifo |= GQSPI_GEN_FIFO_EXP_MASK; + reg_genfifo |= GQSPI_GEN_FIFO_IMM(8); /* IMM is exponent */ + } + else { + reg_genfifo |= GQSPI_GEN_FIFO_IMM(xferSz); /* IMM is length */ + } + + /* Submit general FIFO operation */ + ret = qspi_gen_fifo_write(reg_genfifo); + + /* Fill FIFO */ + ret = gspi_fifo_tx(txData, xferSz); + if (ret != GQSPI_CODE_SUCCESS) + break; + + /* offset size and buffer */ + txSz -= xferSz; + txData += xferSz; + } + + /* Dummy operations */ + if (ret == GQSPI_CODE_SUCCESS && dummySz) { + /* Send dummy clocks (Disable TX & RX) */ + reg_genfifo &= ~(GQSPI_GEN_FIFO_TX | GQSPI_GEN_FIFO_RX | + GQSPI_GEN_FIFO_IMM_MASK | GQSPI_GEN_FIFO_EXP_MASK); + /* IMM is number of dummy clock cycles */ + reg_genfifo |= GQSPI_GEN_FIFO_IMM(dummySz); + ret = qspi_gen_fifo_write(reg_genfifo); /* Submit FIFO Dummy Op */ + + if (rxSz > 0) { + /* Convert dummy bits to bytes */ + dummySz = (dummySz + 7) / 8; + /* Adjust rxSz for dummy bytes */ + rxSz += dummySz; + /* round up by FIFO Word Size */ + rxSz = (((rxSz + GQSPI_FIFO_WORD_SZ - 1) / GQSPI_FIFO_WORD_SZ) * + GQSPI_FIFO_WORD_SZ); + } + } + + /* RX Data */ + while (ret == GQSPI_CODE_SUCCESS && rxData && rxSz > 0) { + xferSz = rxSz; + + /* Enable RX */ + reg_genfifo &= ~(GQSPI_GEN_FIFO_TX | GQSPI_GEN_FIFO_IMM_MASK | + GQSPI_GEN_FIFO_EXP_MASK); + reg_genfifo |= (GQSPI_GEN_FIFO_RX | GQSPI_GEN_FIFO_DATA_XFER); + + if (xferSz > GQSPI_GEN_FIFO_IMM_MASK) { + /* Use exponent mode */ + xferSz = 256; /* 2 ^ 8 = 256 */ + reg_genfifo |= GQSPI_GEN_FIFO_EXP_MASK; + reg_genfifo |= GQSPI_GEN_FIFO_IMM(8); /* IMM is exponent */ + } + else { + reg_genfifo |= GQSPI_GEN_FIFO_IMM(xferSz); /* IMM is length */ + } + + /* Submit general FIFO operation */ + ret = qspi_gen_fifo_write(reg_genfifo); + if (ret != GQSPI_CODE_SUCCESS) + break; + + /* Read FIFO */ + ret = gspi_fifo_rx(rxData, xferSz, dummySz); + + /* offset size and buffer */ + rxSz -= xferSz; + rxData += (xferSz - dummySz); + dummySz = 0; /* only first RX */ + } + + qspi_cs(pDev, 0); /* Deselect Slave */ + GQSPI_EN = 0; /* Disable Device */ + + return ret; +} + +#if 0 +static void qspi_dump_regs(void) +{ + /* Dump Registers */ + printf("Config %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0x00))); + printf("ISR %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0x04))); + printf("IER %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0x08))); + printf("IDR %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0x0C))); + printf("LQSPI_En %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0x14))); + printf("Delay %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0x18))); + printf("Slave_Idle_count %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0x24))); + printf("TX_thres %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0x28))); + printf("RX_thres %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0x2C))); + printf("GPIO %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0x30))); + printf("LPBK_DLY_ADJ %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0x38))); + printf("LQSPI_CFG %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0xA0))); + printf("LQSPI_STS %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0xA4))); + printf("DUMMY_CYCLE_EN %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0xC8))); + printf("MOD_ID %08x\n", *((volatile uint32_t*)(QSPI_BASE + 0xFC))); + printf("GQSPI_CFG %08x\n", GQSPI_CFG); + printf("GQSPI_ISR %08x\n", GQSPI_ISR); + printf("GQSPI_IER %08x\n", GQSPI_IER); + printf("GQSPI_IDR %08x\n", GQSPI_IDR); + printf("GQSPI_IMR %08x\n", GQSPI_IMR); + printf("GQSPI_En %08x\n", GQSPI_EN); + printf("GQSPI_TX_THRESH %08x\n", GQSPI_TX_THRESH); + printf("GQSPI_RX_THRESH %08x\n", GQSPI_RX_THRESH); + printf("GQSPI_GPIO %08x\n", GQSPI_GPIO); + printf("GQSPI_LPBK_DLY_ADJ %08x\n", GQSPI_LPBK_DLY_ADJ); + printf("GQSPI_FIFO_CTRL %08x\n", GQSPI_FIFO_CTRL); + printf("GQSPI_GF_THRESH %08x\n", GQSPI_GF_THRESH); + printf("GQSPI_POLL_CFG %08x\n", GQSPI_POLL_CFG); + printf("GQSPI_P_TIMEOUT %08x\n", GQSPI_P_TIMEOUT); + printf("QSPI_DATA_DLY_ADJ %08x\n", QSPI_DATA_DLY_ADJ); + printf("GQSPI_MOD_ID %08x\n", GQSPI_MOD_ID); + printf("QSPIDMA_DST_STS %08x\n", QSPIDMA_DST_STS); + printf("QSPIDMA_DST_CTRL %08x\n", QSPIDMA_DST_CTRL); + printf("QSPIDMA_DST_I_STS %08x\n", QSPIDMA_DST_I_STS); + printf("QSPIDMA_DST_CTRL2 %08x\n", QSPIDMA_DST_CTRL2); +} +#endif +#endif /* USE_QNX */ + +static int qspi_flash_read_id(QspiDev_t* dev, uint8_t* id, uint32_t idSz) +{ + int ret; + uint8_t cmd[20]; + + /* ------ Flash Read ID ------ */ + cmd[0] = MULTI_IO_READ_ID_CMD; + ret = qspi_transfer(&mDev, cmd, 1, NULL, 0, cmd, sizeof(cmd), 0); +#ifdef DEBUG_ZYNQ + printf("Read FlashID %s: Ret %d, %02x %02x %02x\n", + (dev->cs & GQSPI_GEN_FIFO_CS_LOWER) ? "Lower" : "Upper", + ret, cmd[0], cmd[1], cmd[2]); +#endif + if (ret == GQSPI_CODE_SUCCESS && id) { + if (idSz > sizeof(cmd)) + idSz = sizeof(cmd); + memcpy(id, cmd, idSz); + } + return ret; +} + +static int qspi_write_enable(QspiDev_t* dev) +{ + int ret; + const uint8_t cmd[1] = {WRITE_ENABLE_CMD}; + ret = qspi_transfer(&mDev, cmd, sizeof(cmd), NULL, 0, NULL, 0, 0); +#ifdef DEBUG_ZYNQ + printf("Write Enable: Ret %d\n", ret); +#endif + return ret; +} +static int qspi_write_disable(QspiDev_t* dev) +{ + int ret; + const uint8_t cmd[1] = {WRITE_DISABLE_CMD}; + ret = qspi_transfer(&mDev, cmd, sizeof(cmd), NULL, 0, NULL, 0, 0); +#ifdef DEBUG_ZYNQ + printf("Write Disable: Ret %d\n", ret); +#endif + return ret; +} + +static int qspi_flash_status(QspiDev_t* dev, uint8_t* status) +{ + int ret; + uint8_t cmd[2]; + + /* ------ Read Flash Status ------ */ + cmd[0] = READ_FSR_CMD; + ret = qspi_transfer(&mDev, cmd, 1, NULL, 0, cmd, 2, 0); +#ifdef DEBUG_ZYNQ + printf("Flash Status: Ret %d Cmd %02x %02x\n", ret, cmd[0], cmd[1]); +#endif + if (ret == GQSPI_CODE_SUCCESS && status) { + if (dev->stripe) { + cmd[0] &= cmd[1]; + } + *status = cmd[0]; + } + return ret; +} + +static int qspi_wait_ready(QspiDev_t* dev) +{ + int ret; + uint32_t timeout; + uint8_t status = 0; + + timeout = 0; + while (++timeout < QSPI_FLASH_READY_TRIES) { + ret = qspi_flash_status(dev, &status); + if (ret == GQSPI_CODE_SUCCESS && (status & FLASH_READY_MASK)) { + return ret; + } + } + +#ifdef DEBUG_ZYNQ + printf("Flash Ready Timeout!\n"); +#endif + + return GQSPI_CODE_TIMEOUT; +} + +#if 0 +static int qspi_flash_reset(QspiDev_t* dev) +{ + uint8_t cmd[1]; + cmd[0] = RESET_ENABLE_CMD; + qspi_transfer(&mDev, cmd, 1, NULL, 0, NULL, 0, 0); + cmd[0] = RESET_MEMORY_CMD; + qspi_transfer(&mDev, cmd, 1, NULL, 0, NULL, 0, 0); + return GQSPI_CODE_SUCCESS; +} +#endif + +#if GQSPI_QSPI_MODE == GQSPI_GEN_FIFO_MODE_QSPI +static int qspi_enter_qspi_mode(QspiDev_t* dev) +{ + int ret; + const uint8_t cmd[1] = {ENTER_QSPI_MODE_CMD}; + ret = qspi_transfer(dev, cmd, sizeof(cmd), NULL, 0, NULL, 0, 0); +#ifdef DEBUG_ZYNQ + printf("Enable Quad SPI mode: Ret %d\n", ret); +#endif + return ret; +} +static int qspi_exit_qspi_mode(QspiDev_t* dev) +{ + int ret; + const uint8_t cmd[1] = {EXIT_QSPI_MODE_CMD}; + ret = qspi_transfer(dev, cmd, sizeof(cmd), NULL, 0, NULL, 0, 0); +#ifdef DEBUG_ZYNQ + printf("Disable Quad SPI mode: Ret %d\n", ret); +#endif + return ret; +} +#endif + +#if GQPI_USE_4BYTE_ADDR == 1 +static int qspi_enter_4byte_addr(QspiDev_t* dev) +{ + int ret; + const uint8_t cmd[1] = {ENTER_4B_ADDR_MODE_CMD}; + ret = qspi_transfer(dev, cmd, sizeof(cmd), NULL, 0, NULL, 0, 0); +#ifdef DEBUG_ZYNQ + printf("Enter 4-byte address mode: Ret %d\n", ret); +#endif + return ret; +} +static int qspi_exit_4byte_addr(QspiDev_t* dev) +{ + int ret; + const uint8_t cmd[1] = {EXIT_4B_ADDR_MODE_CMD}; + + ret = qspi_transfer(dev, cmd, sizeof(cmd), NULL, 0, NULL, 0, 0); +#ifdef DEBUG_ZYNQ + printf("Exit 4-byte address mode: Ret %d\n", ret); +#endif + return ret; +} +#endif + +/* QSPI functions */ +void qspi_init(uint32_t cpu_clock, uint32_t flash_freq) +{ + int ret; + uint32_t reg_cfg; + uint8_t id_low[4]; +#if GQPI_USE_DUAL_PARALLEL == 1 + uint8_t id_hi[4]; +#endif + uint32_t timeout; + + (void)cpu_clock; + (void)flash_freq; + + memset(&mDev, 0, sizeof(mDev)); + +#ifdef USE_QNX + mDev.qnx = xzynq_qspi_open(); + if (mDev.qnx == NULL) { + #ifdef DEBUG_ZYNQ + printf("QSPI failed to open\n"); + #endif + return; + } +#else + /* Disable Linear Mode in case FSBL enabled it */ + LQSPI_EN = 0; + + /* Select Generic Quad-SPI */ + GQSPI_SEL = 1; + + /* Clear and disable interrupts */ + reg_cfg = GQSPI_ISR; + GQSPI_ISR |= GQSPI_ISR_WR_TO_CLR_MASK; /* Clear poll timeout counter interrupt */ + QSPIDMA_DST_I_STS = QSPIDMA_DST_I_STS; /* clear all active interrupts */ + QSPIDMA_DST_STS |= QSPIDMA_DST_STS_WTC; /* mark outstanding DMA's done */ + GQSPI_IDR = GQSPI_IXR_ALL_MASK; /* disable interrupts */ + QSPIDMA_DST_I_STS = QSPIDMA_DST_I_STS_ALL_MASK; /* disable interrupts */ + /* Reset FIFOs */ + if (GQSPI_ISR & GQSPI_IXR_RX_FIFO_EMPTY) { + GQSPI_FIFO_CTRL |= (GQSPI_FIFO_CTRL_RST_TX_FIFO | GQSPI_FIFO_CTRL_RST_RX_FIFO); + } + if (reg_cfg & GQSPI_IXR_RX_FIFO_EMPTY) { + GQSPI_FIFO_CTRL |= GQSPI_FIFO_CTRL_RST_RX_FIFO; + } + + GQSPI_EN = 0; /* Disable device */ + + /* Initialize clock divisor, write protect hold and start mode */ + reg_cfg = GQSPI_CFG_MODE_EN_IO; /* Use I/O Transfer Mode */ + reg_cfg |= GQSPI_CFG_BAUD_RATE_DIV(GQSPI_CLK_DIV); /* Clock Divider */ + reg_cfg |= GQSPI_CFG_WP_HOLD; /* Use WP Hold */ + reg_cfg |= GQSPI_CFG_START_GEN_FIFO; /* Start GFIFO command execution */ + reg_cfg &= ~(GQSPI_CFG_CLK_POL | GQSPI_CFG_CLK_PH); /* Use POL=0,PH=0 */ + GQSPI_CFG = reg_cfg; + + /* use tap delay bypass < 40MHz SPI clock */ + GQSPI_LPBK_DLY_ADJ = 0; + QSPI_DATA_DLY_ADJ = 0; + + /* Initialize hardware parameters for Threshold and Interrupts */ + GQSPI_TX_THRESH = 1; + GQSPI_RX_THRESH = 1; + GQSPI_GF_THRESH = 16; + + /* Reset DMA */ + QSPIDMA_DST_CTRL = QSPIDMA_DST_CTRL_DEF; + QSPIDMA_DST_CTRL2 = QSPIDMA_DST_CTRL2_DEF; + + /* Interrupts unmask and enable */ + GQSPI_IMR = GQSPI_IXR_ALL_MASK; + GQSPI_IER = GQSPI_IXR_ALL_MASK; + + GQSPI_EN = 1; /* Enable Device */ +#endif /* USE_QNX */ + + /* Issue Flash Reset Command */ + //qspi_flash_reset(&mDev); + + /* ------ Flash Read ID (retry) ------ */ + timeout = 0; + while (++timeout < QSPI_FLASH_READY_TRIES) { + /* Slave Select - lower chip */ + mDev.mode = GQSPI_GEN_FIFO_MODE_SPI; + mDev.bus = GQSPI_GEN_FIFO_BUS_LOW; + mDev.cs = GQSPI_GEN_FIFO_CS_LOWER; + ret = qspi_flash_read_id(&mDev, id_low, sizeof(id_low)); + if (ret != GQSPI_CODE_SUCCESS) { + continue; + } + + #if GQPI_USE_DUAL_PARALLEL == 1 + /* Slave Select - upper chip */ + mDev.mode = GQSPI_GEN_FIFO_MODE_SPI; + mDev.bus = GQSPI_GEN_FIFO_BUS_UP; + mDev.cs = GQSPI_GEN_FIFO_CS_UPPER; + ret = qspi_flash_read_id(&mDev, id_hi, sizeof(id_hi)); + if (ret != GQSPI_CODE_SUCCESS) { + continue; + } + + /* ID's for upper and lower must match */ + if ((id_hi[0] == 0 || id_hi[0] == 0xFF) || + (id_hi[0] != id_low[0] && + id_hi[1] != id_low[1] && + id_hi[2] != id_low[2])) + { + #ifdef DEBUG_ZYNQ + printf("Flash ID error!\n"); + #endif + continue; + } + #endif + break; /* success */ + } + + /* 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.stripe = GQSPI_GEN_FIFO_STRIPE; +#endif + +#if GQSPI_QSPI_MODE == GQSPI_GEN_FIFO_MODE_QSPI + /* Enter Quad SPI mode */ + ret = qspi_enter_qspi_mode(&mDev); + if (ret != 0) + return; +#endif + +#if GQPI_USE_4BYTE_ADDR == 1 + /* Enter 4-byte address mode */ + ret = qspi_enter_4byte_addr(&mDev); + if (ret != GQSPI_CODE_SUCCESS) + return; +#endif + +#ifdef TEST_FLASH + test_flash(&mDev); +#endif +} + + +void zynq_init(uint32_t cpu_clock) +{ + qspi_init(cpu_clock, 0); +} + +void zynq_exit(void) +{ + int ret; + +#if GQPI_USE_4BYTE_ADDR == 1 + /* Exit 4-byte address mode */ + ret = qspi_exit_4byte_addr(&mDev); + if (ret != GQSPI_CODE_SUCCESS) + return; +#endif +#if GQSPI_QSPI_MODE == GQSPI_GEN_FIFO_MODE_QSPI + /* Exit Quad SPI mode */ + ret = qspi_exit_qspi_mode(&mDev); + if (ret != 0) + return; +#endif + +#ifdef USE_QNX + if (mDev.qnx) { + xzynq_qspi_close(mDev.qnx); + mDev.qnx = NULL; + } +#endif + + (void)ret; +} + + +/* public HAL functions */ +void hal_init(void) +{ + uint32_t cpu_freq = 0; + +#ifdef DEBUG_ZYNQ + printf("\nwolfBoot Secure Boot\n"); +#endif + + asm volatile("msr cntfrq_el0, %0" : : "r" (cpu_freq) : "memory"); + + zynq_init(cpu_freq); +} + +void hal_prepare_boot(void) +{ + zynq_exit(); +} + +/* Flash functions must be relocated to RAM for execution */ +int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len) +{ + return 0; +} + +void RAMFUNCTION hal_flash_unlock(void) +{ +} + +void RAMFUNCTION hal_flash_lock(void) +{ +} + + +int RAMFUNCTION hal_flash_erase(uint32_t address, int len) +{ + return 0; +} + +int RAMFUNCTION ext_flash_write(uintptr_t address, const uint8_t *data, int len) +{ + int ret = 0; + uint8_t cmd[5]; + uint32_t xferSz, page, pages, idx = 0; + uintptr_t addr; + + /* write by page */ + pages = ((len + (FLASH_PAGE_SIZE-1)) / FLASH_PAGE_SIZE); + for (page = 0; page < pages; page++) { + ret = qspi_write_enable(&mDev); + if (ret == GQSPI_CODE_SUCCESS) { + xferSz = len; + if (xferSz > FLASH_PAGE_SIZE) + xferSz = FLASH_PAGE_SIZE; + + addr = address + (page * FLASH_PAGE_SIZE); + if (mDev.stripe) { + /* For dual parallel the address divide by 2 */ + addr /= 2; + } + + /* ------ Write Flash (page at a time) ------ */ + cmd[idx++] = PAGE_PROG_CMD; + #if GQPI_USE_4BYTE_ADDR == 1 + cmd[idx++] = ((addr >> 24) & 0xFF); + #endif + cmd[idx++] = ((addr >> 16) & 0xFF); + cmd[idx++] = ((addr >> 8) & 0xFF); + cmd[idx++] = ((addr >> 0) & 0xFF); + ret = qspi_transfer(&mDev, cmd, idx, + (const uint8_t*)(data + (page * FLASH_PAGE_SIZE)), + xferSz, NULL, 0, 0); + #ifdef DEBUG_ZYNQ + printf("Flash Page %d Write: Ret %d\n", page, ret); + #endif + if (ret != GQSPI_CODE_SUCCESS) + break; + + ret = qspi_wait_ready(&mDev); /* Wait for not busy */ + if (ret != GQSPI_CODE_SUCCESS) { + break; + } + qspi_write_disable(&mDev); + } + } + + return ret; +} + +int RAMFUNCTION ext_flash_read(uintptr_t address, uint8_t *data, int len) +{ + int ret; + uint8_t cmd[5]; + uint32_t idx = 0; + + if (mDev.stripe) { + /* For dual parallel the address divide by 2 */ + address /= 2; + } + + /* ------ Read Flash ------ */ + cmd[idx++] = FAST_READ_CMD; +#if GQPI_USE_4BYTE_ADDR == 1 + cmd[idx++] = ((address >> 24) & 0xFF); +#endif + cmd[idx++] = ((address >> 16) & 0xFF); + cmd[idx++] = ((address >> 8) & 0xFF); + cmd[idx++] = ((address >> 0) & 0xFF); + ret = qspi_transfer(&mDev, cmd, idx, NULL, 0, data, len, GQSPI_DUMMY_READ); +#if defined(DEBUG_ZYNQ) && DEBUG_ZYNQ >= 2 + printf("Flash Read: Ret %d\r\n", ret); +#endif + + return ret; +} + +/* Issues a sector erase based on flash address */ +/* Assumes len is not > sector size */ +int RAMFUNCTION ext_flash_erase(uintptr_t address, int len) +{ + int ret; + uint8_t cmd[5]; + uint32_t idx = 0; + + if (mDev.stripe) { + /* For dual parallel the address divide by 2 */ + address /= 2; + } + + ret = qspi_write_enable(&mDev); + if (ret == GQSPI_CODE_SUCCESS) { + /* ------ Erase Flash ------ */ + cmd[idx++] = SEC_ERASE_CMD; + #if GQPI_USE_4BYTE_ADDR == 1 + cmd[idx++] = ((address >> 24) & 0xFF); + #endif + cmd[idx++] = ((address >> 16) & 0xFF); + cmd[idx++] = ((address >> 8) & 0xFF); + cmd[idx++] = ((address >> 0) & 0xFF); + ret = qspi_transfer(&mDev, cmd, idx, NULL, 0, NULL, 0, 0); + #ifdef DEBUG_ZYNQ + printf("Flash Erase: Ret %d\n", ret); + #endif + if (ret == GQSPI_CODE_SUCCESS) { + ret = qspi_wait_ready(&mDev); /* Wait for not busy */ + } + qspi_write_disable(&mDev); + } + + return ret; +} + +void RAMFUNCTION ext_flash_lock(void) +{ + +} + +void RAMFUNCTION ext_flash_unlock(void) +{ + +} + +#ifdef TEST_FLASH +#define TEST_ADDRESS 0x2800000 /* 40MB */ +static uint8_t testData[FLASH_PAGE_SIZE]; +static int test_flash(QspiDev_t* dev) +{ + int ret; + uint32_t i; + +#ifndef TEST_FLASH_READONLY + /* Erase sector */ + ret = ext_flash_erase(TEST_ADDRESS, WOLFBOOT_SECTOR_SIZE); +#ifdef DEBUG_ZYNQ + printf("Erase Sector: Ret %d\n", ret); +#endif + + /* Write Pages */ + for (i=0; i psu_ddr_0_MEM_0 + +.init (ALIGN(64)) : { + KEEP (*(.init)) +} > psu_ddr_0_MEM_0 + +.fini (ALIGN(64)) : { + KEEP (*(.fini)) +} > psu_ddr_0_MEM_0 + +.interp : { + KEEP (*(.interp)) +} > psu_ddr_0_MEM_0 + +.note-ABI-tag : { + KEEP (*(.note-ABI-tag)) +} > psu_ddr_0_MEM_0 + +.rodata : { + . = ALIGN(64); + __rodata_start = .; + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + __rodata_end = .; +} > psu_ddr_0_MEM_0 + +.rodata1 : { + . = ALIGN(64); + __rodata1_start = .; + *(.rodata1) + *(.rodata1.*) + __rodata1_end = .; +} > psu_ddr_0_MEM_0 + +.sdata2 : { + . = ALIGN(64); + __sdata2_start = .; + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + __sdata2_end = .; +} > psu_ddr_0_MEM_0 + +.sbss2 : { + . = ALIGN(64); + __sbss2_start = .; + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + __sbss2_end = .; +} > psu_ddr_0_MEM_0 + +.data : { + . = ALIGN(64); + __data_start = .; + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.jcr) + *(.got) + *(.got.plt) + __data_end = .; +} > psu_ddr_0_MEM_0 + +.data1 : { + . = ALIGN(64); + __data1_start = .; + *(.data1) + *(.data1.*) + __data1_end = .; +} > psu_ddr_0_MEM_0 + +.got : { + *(.got) +} > psu_ddr_0_MEM_0 + +.got1 : { + *(.got1) +} > psu_ddr_0_MEM_0 + +.got2 : { + *(.got2) +} > psu_ddr_0_MEM_0 + +.ctors : { + . = ALIGN(64); + __CTOR_LIST__ = .; + ___CTORS_LIST___ = .; + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __CTOR_END__ = .; + ___CTORS_END___ = .; +} > psu_ddr_0_MEM_0 + +.dtors : { + . = ALIGN(64); + __DTOR_LIST__ = .; + ___DTORS_LIST___ = .; + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + __DTOR_END__ = .; + ___DTORS_END___ = .; +} > psu_ddr_0_MEM_0 + +.fixup : { + __fixup_start = .; + *(.fixup) + __fixup_end = .; +} > psu_ddr_0_MEM_0 + +.eh_frame : { + *(.eh_frame) +} > psu_ddr_0_MEM_0 + +.eh_framehdr : { + __eh_framehdr_start = .; + *(.eh_framehdr) + __eh_framehdr_end = .; +} > psu_ddr_0_MEM_0 + +.gcc_except_table : { + *(.gcc_except_table) +} > psu_ddr_0_MEM_0 + +.mmu_tbl0 (ALIGN(4096)) : { + __mmu_tbl0_start = .; + *(.mmu_tbl0) + __mmu_tbl0_end = .; +} > psu_ddr_0_MEM_0 + +.mmu_tbl1 (ALIGN(4096)) : { + __mmu_tbl1_start = .; + *(.mmu_tbl1) + __mmu_tbl1_end = .; +} > psu_ddr_0_MEM_0 + +.mmu_tbl2 (ALIGN(4096)) : { + __mmu_tbl2_start = .; + *(.mmu_tbl2) + __mmu_tbl2_end = .; +} > psu_ddr_0_MEM_0 + +.ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + *(.gnu.linkonce.armexidix.*.*) + __exidx_end = .; +} > psu_ddr_0_MEM_0 + +.preinit_array : { + . = ALIGN(64); + __preinit_array_start = .; + KEEP (*(SORT(.preinit_array.*))) + KEEP (*(.preinit_array)) + __preinit_array_end = .; +} > psu_ddr_0_MEM_0 + +.init_array : { + . = ALIGN(64); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; +} > psu_ddr_0_MEM_0 + +.fini_array : { + . = ALIGN(64); + __fini_array_start = .; + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array)) + __fini_array_end = .; +} > psu_ddr_0_MEM_0 + +.ARM.attributes : { + __ARM.attributes_start = .; + *(.ARM.attributes) + __ARM.attributes_end = .; +} > psu_ddr_0_MEM_0 + +.sdata : { + . = ALIGN(64); + __sdata_start = .; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + __sdata_end = .; +} > psu_ddr_0_MEM_0 + +.sbss (NOLOAD) : { + . = ALIGN(64); + __sbss_start = .; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + . = ALIGN(64); + __sbss_end = .; +} > psu_ddr_0_MEM_0 + +.tdata : { + . = ALIGN(64); + __tdata_start = .; + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + __tdata_end = .; +} > psu_ddr_0_MEM_0 + +.tbss : { + . = ALIGN(64); + __tbss_start = .; + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + __tbss_end = .; +} > psu_ddr_0_MEM_0 + +.bss (NOLOAD) : { + . = ALIGN(64); + __bss_start__ = .; + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(64); + __bss_end__ = .; +} > psu_ddr_0_MEM_0 + +_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 ); + +_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); + +/* Generate Stack and Heap definitions */ + +.heap (NOLOAD) : { + . = ALIGN(64); + _heap = .; + HeapBase = .; + _heap_start = .; + . += _HEAP_SIZE; + _heap_end = .; + HeapLimit = .; +} > psu_ddr_0_MEM_0 + +.stack (NOLOAD) : { + . = ALIGN(64); + _el3_stack_end = .; + . += _STACK_SIZE; + __el3_stack = .; + _el2_stack_end = .; + . += _EL2_STACK_SIZE; + . = ALIGN(64); + __el2_stack = .; + _el1_stack_end = .; + . += _EL1_STACK_SIZE; + . = ALIGN(64); + __el1_stack = .; + _el0_stack_end = .; + . += _EL0_STACK_SIZE; + . = ALIGN(64); + __el0_stack = .; +} > psu_ddr_0_MEM_0 + +_end = .; +} diff --git a/include/hal.h b/include/hal.h index 82d379154..d80514a30 100644 --- a/include/hal.h +++ b/include/hal.h @@ -29,7 +29,11 @@ #include "target.h" /* Architecture specific calls */ +#ifdef MMU +extern void do_boot(const uint32_t *app_offset, const uint32_t* dts_offset); +#else extern void do_boot(const uint32_t *app_offset); +#endif extern void arch_reboot(void); @@ -44,30 +48,28 @@ void hal_prepare_boot(void); void hal_flash_dualbank_swap(void); #endif -#ifdef EXT_FLASH - #ifndef SPI_FLASH - /* user supplied external flash interfaces */ - int ext_flash_write(uint32_t address, const uint8_t *data, int len); - int ext_flash_read(uint32_t address, uint8_t *data, int len); - int ext_flash_erase(uint32_t address, int len); - void ext_flash_lock(void); - void ext_flash_unlock(void); - #else - #include "spi_flash.h" - #define ext_flash_lock() do{}while(0) - #define ext_flash_unlock() do{}while(0) - #define ext_flash_read spi_flash_read - #define ext_flash_write spi_flash_write +#ifndef SPI_FLASH + /* user supplied external flash interfaces */ + int ext_flash_write(uintptr_t address, const uint8_t *data, int len); + int ext_flash_read(uintptr_t address, uint8_t *data, int len); + int ext_flash_erase(uintptr_t address, int len); + void ext_flash_lock(void); + void ext_flash_unlock(void); +#else + #include "spi_flash.h" + #define ext_flash_lock() do{}while(0) + #define ext_flash_unlock() do{}while(0) + #define ext_flash_read spi_flash_read + #define ext_flash_write spi_flash_write - static int ext_flash_erase(uint32_t address, int len) - { - uint32_t end = address + len - 1; - uint32_t p; - for (p = address; p <= end; p += SPI_FLASH_SECTOR_SIZE) - spi_flash_sector_erase(p); - return 0; - } - #endif /* !SPI_FLASH */ -#endif /* EXT_FLASH */ + static int ext_flash_erase(uintptr_t address, int len) + { + uint32_t end = address + len - 1; + uint32_t p; + for (p = address; p <= end; p += SPI_FLASH_SECTOR_SIZE) + spi_flash_sector_erase(p); + return 0; + } +#endif /* !SPI_FLASH */ #endif /* H_HAL_FLASH_ */ diff --git a/include/image.h b/include/image.h index 31571bd0f..8a811127a 100644 --- a/include/image.h +++ b/include/image.h @@ -52,12 +52,13 @@ struct wolfBoot_image { uint8_t *hdr; uint8_t *trailer; - int hdr_ok; - int signature_ok; - int sha_ok; + uint8_t *sha_hash; uint8_t *fw_base; uint32_t fw_size; uint8_t part; + uint8_t hdr_ok : 1; + uint8_t signature_ok : 1; + uint8_t sha_ok : 1; }; @@ -69,10 +70,17 @@ int wolfBoot_set_sector_flag(uint8_t part, uint8_t sector, uint8_t newflag); int wolfBoot_get_partition_state(uint8_t part, uint8_t *st); int wolfBoot_get_sector_flag(uint8_t part, uint8_t sector, uint8_t *flag); +uint8_t* wolfBoot_peek_image(struct wolfBoot_image *img, uint32_t offset, uint32_t* sz); + /* Defined in libwolfboot */ uint16_t wolfBoot_find_header(uint8_t *haystack, uint16_t type, uint8_t **ptr); #ifdef EXT_FLASH +# ifdef PART_BOOT_EXT +# define BOOT_EXT 1 +# else +# define BOOT_EXT 0 +# endif # ifdef PART_UPDATE_EXT # define UPDATE_EXT 1 # else @@ -83,23 +91,27 @@ uint16_t wolfBoot_find_header(uint8_t *haystack, uint16_t type, uint8_t **ptr); # else # define SWAP_EXT 0 # endif -# define PART_IS_EXT(x) (((x)->part == PART_UPDATE)?UPDATE_EXT:(((x)->part == PART_SWAP)?SWAP_EXT:0)) +# define PARTN_IS_EXT(pn) \ + ((pn == PART_BOOT || pn == PART_DTS_BOOT)?BOOT_EXT: \ + ((pn == PART_UPDATE || pn == PART_DTS_UPDATE)?UPDATE_EXT: \ + ((pn == PART_SWAP)?SWAP_EXT:0))) +# define PART_IS_EXT(x) PARTN_IS_EXT(((x)->part)) #include "hal.h" static inline int wb_flash_erase(struct wolfBoot_image *img, uint32_t off, uint32_t size) { if (PART_IS_EXT(img)) - return ext_flash_erase((uint32_t)(img->hdr) + off, size); + return ext_flash_erase((uintptr_t)(img->hdr) + off, size); else - return hal_flash_erase((uint32_t)(img->hdr) + off, size); + return hal_flash_erase((uintptr_t)(img->hdr) + off, size); } static inline int wb_flash_write(struct wolfBoot_image *img, uint32_t off, const void *data, uint32_t size) { if (PART_IS_EXT(img)) - return ext_flash_write((uint32_t)(img->hdr) + off, data, size); + return ext_flash_write((uintptr_t)(img->hdr) + off, data, size); else - return hal_flash_write((uint32_t)(img->hdr) + off, data, size); + return hal_flash_write((uintptr_t)(img->hdr) + off, data, size); } static inline int wb_flash_write_verify_word(struct wolfBoot_image *img, uint32_t off, uint32_t word) @@ -108,17 +120,17 @@ static inline int wb_flash_write_verify_word(struct wolfBoot_image *img, uint32_ volatile uint32_t copy; if (PART_IS_EXT(img)) { - ext_flash_read((uint32_t)(img->hdr) + off, (void *)©, sizeof(uint32_t)); + ext_flash_read((uintptr_t)(img->hdr) + off, (void *)©, sizeof(uint32_t)); while (copy != word) { - ret = ext_flash_write((uint32_t)(img->hdr) + off, (void *)&word, sizeof(uint32_t)); + ret = ext_flash_write((uintptr_t)(img->hdr) + off, (void *)&word, sizeof(uint32_t)); if (ret < 0) return ret; - ext_flash_read((uint32_t)(img->hdr) + off, (void *)©, sizeof(uint32_t)); + ext_flash_read((uintptr_t)(img->hdr) + off, (void *)©, sizeof(uint32_t)); } } else { volatile uint32_t *pcopy = (volatile uint32_t*)(img->hdr + off); while(*pcopy != word) { - hal_flash_write((uint32_t)pcopy, (void *)&word, sizeof(uint32_t)); + hal_flash_write((uintptr_t)pcopy, (void *)&word, sizeof(uint32_t)); } } return 0; @@ -128,9 +140,19 @@ static inline int wb_flash_write_verify_word(struct wolfBoot_image *img, uint32_ #else # define PART_IS_EXT(x) (0) -# define wb_flash_erase(im, of, siz) hal_flash_erase(((uint32_t)(((im)->hdr)) + of), siz) -# define wb_flash_write(im, of, dat, siz) hal_flash_write(((uint32_t)((im)->hdr)) + of, dat, siz) +# define PARTN_IS_EXT(x) (0) +# define wb_flash_erase(im, of, siz) hal_flash_erase(((uintptr_t)(((im)->hdr)) + of), siz) +# define wb_flash_write(im, of, dat, siz) hal_flash_write(((uintptr_t)((im)->hdr)) + of, dat, siz) #endif /* EXT_FLASH */ +/* -- Image Formats -- */ +/* Legacy U-Boot Image */ +#define UBOOT_IMG_HDR_MAGIC 0x56190527UL +#define UBOOT_IMG_HDR_SZ 64 + +/* --- Flattened Device Tree Blob */ +#define UBOOT_FDT_MAGIC 0xEDFE0DD0UL + + #endif /* !IMAGE_H */ diff --git a/include/loader.h b/include/loader.h index e6e0ca50d..7e5fdb46b 100644 --- a/include/loader.h +++ b/include/loader.h @@ -56,4 +56,6 @@ #ifdef WOLFTPM2_NO_WOLFCRYPT int wolfBoot_tpm2_init(void); #endif + +void wolfBoot_start(void); #endif /* LOADER_H */ diff --git a/include/spi_drv.h b/include/spi_drv.h index 01edb1605..c198554b6 100644 --- a/include/spi_drv.h +++ b/include/spi_drv.h @@ -35,6 +35,10 @@ #include "hal/spi/spi_drv_stm32.h" #endif +#if defined(PLATFORM_zynq) +#include "hal/spi/spi_drv_zynq.h" +#endif + void spi_init(int polarity, int phase); void spi_write(const char byte); uint8_t spi_read(void); diff --git a/include/target.h.in b/include/target.h.in index eff2537c5..9286d533d 100644 --- a/include/target.h.in +++ b/include/target.h.in @@ -33,5 +33,10 @@ #define WOLFBOOT_PARTITION_UPDATE_ADDRESS ##WOLFBOOT_PARTITION_UPDATE_ADDRESS## #define WOLFBOOT_PARTITION_SWAP_ADDRESS ##WOLFBOOT_PARTITION_SWAP_ADDRESS## +/* Load address in RAM for staged OS (update_ram only) */ +#define WOLFBOOT_DTS_BOOT_ADDRESS ##WOLFBOOT_DTS_BOOT_ADDRESS## +#define WOLFBOOT_DTS_UPDATE_ADDRESS ##WOLFBOOT_DTS_UPDATE_ADDRESS## +#define WOLFBOOT_LOAD_ADDRESS ##WOLFBOOT_LOAD_ADDRESS## +#define WOLFBOOT_LOAD_DTS_ADDRESS ##WOLFBOOT_LOAD_DTS_ADDRESS## #endif /* !H_TARGETS_TARGET_ */ diff --git a/include/user_settings.h b/include/user_settings.h index af7137150..a2fc37261 100644 --- a/include/user_settings.h +++ b/include/user_settings.h @@ -26,12 +26,12 @@ #ifndef H_USER_SETTINGS_ #define H_USER_SETTINGS_ +#include + /* System */ #define WOLFSSL_GENERAL_ALIGNMENT 4 #define SINGLE_THREADED -//#define WOLFSSL_SMALL_STACK #define WOLFCRYPT_ONLY -//#define TFM_TIMING_RESISTANT #define SIZEOF_LONG_LONG 8 @@ -101,6 +101,7 @@ #ifdef WOLFBOOT_SIGN_RSA4096 # define HAVE_RSA # define RSA_LOW_MEM +# define WOLFSSL_RSA_PUBLIC_ONLY # define WOLFSSL_RSA_VERIFY_INLINE # define FP_MAX_BITS (4096 * 2) # define WC_RSA_BLINDING @@ -110,13 +111,16 @@ #ifdef WOLFBOOT_HASH_SHA3_384 # define WOLFSSL_SHA3 +# define NO_SHA256 #endif /* Disables - For minimum wolfCrypt build */ #define NO_AES #define NO_CMAC +#define NO_HMAC #define NO_CODING -#define NO_BIG_INT +#define WOLFSSL_NO_PEM +#define NO_ASN_TIME #define NO_RC4 #define NO_SHA #define NO_DH @@ -131,6 +135,7 @@ #define NO_DES3 #define NO_PWDBASED #define WC_NO_RNG +#define WC_NO_HASHDRBG #define NO_WRITEV #define NO_DEV_RANDOM #define NO_FILESYSTEM @@ -138,5 +143,16 @@ #define NO_OLD_RNGNAME #define NO_WOLFSSL_DIR #define WOLFSSL_NO_SOCK +#define WOLFSSL_IGNORE_FILE_WARN +#define NO_ERROR_STRINGS + +#define BENCH_EMBEDDED +#define NO_CRYPT_TEST +#define NO_CRYPT_BENCHMARK + +#ifdef __QNX__ +#define WOLFSSL_HAVE_MIN +#define WOLFSSL_HAVE_MAX +#endif #endif /* !H_USER_SETTINGS_ */ diff --git a/include/wolfboot/wolfboot.h b/include/wolfboot/wolfboot.h index b9f2c42c4..40d3322e9 100644 --- a/include/wolfboot/wolfboot.h +++ b/include/wolfboot/wolfboot.h @@ -73,6 +73,10 @@ #define PART_UPDATE 1 #define PART_SWAP 2 +#define PART_DTS (0x10) +#define PART_DTS_BOOT (PART_DTS | PART_BOOT) +#define PART_DTS_UPDATE (PART_DTS | PART_UPDATE) + #define IMG_STATE_NEW 0xFF #define IMG_STATE_UPDATING 0x70 #define IMG_STATE_TESTING 0x10 @@ -87,15 +91,18 @@ uint16_t wolfBoot_get_image_type(uint8_t part); #define wolfBoot_current_firmware_version() wolfBoot_get_image_version(PART_BOOT) #define wolfBoot_update_firmware_version() wolfBoot_get_image_version(PART_UPDATE) +int wolfBoot_fallback_is_possible(void); +int wolfBoot_dualboot_candidate(void); /* Hashing function configuration */ -#define WOLFBOOT_SHA_BLOCK_SIZE (16) #if defined(WOLFBOOT_HASH_SHA256) +# define WOLFBOOT_SHA_BLOCK_SIZE (16) # define WOLFBOOT_SHA_HDR HDR_SHA256 # define WOLFBOOT_SHA_DIGEST_SIZE (32) # define image_hash image_sha256 # define key_hash key_sha256 #elif defined(WOLFBOOT_HASH_SHA3_384) +# define WOLFBOOT_SHA_BLOCK_SIZE (128) # define WOLFBOOT_SHA_HDR HDR_SHA3_384 # define WOLFBOOT_SHA_DIGEST_SIZE (48) # define image_hash image_sha3_384 diff --git a/src/boot_aarch64.c b/src/boot_aarch64.c new file mode 100644 index 000000000..484fc2844 --- /dev/null +++ b/src/boot_aarch64.c @@ -0,0 +1,101 @@ +/* boot_aarch64.c + * + * Copyright (C) 2020 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include + +#include "image.h" +#include "loader.h" +#include "wolfboot/wolfboot.h" + +extern unsigned int __bss_start__; +extern unsigned int __bss_end__; +static volatile unsigned int cpu_id; +extern unsigned int *END_STACK; + +extern void main(void); +extern void gicv2_init_secure(void); + +void boot_entry_C(void) +{ + register unsigned int *dst; + /* Initialize the BSS section to 0 */ + dst = &__bss_start__; + while (dst < (unsigned int *)&__bss_end__) { + *dst = 0U; + dst++; + } + + /* Run wolfboot! */ + main(); +} + +/* This is the main loop for the bootloader. + * + * It performs the following actions: + * - Call the application entry point + * + */ + +#ifdef MMU +void RAMFUNCTION do_boot(const uint32_t *app_offset, const uint32_t* dts_offset) +#else +void RAMFUNCTION do_boot(const uint32_t *app_offset) +#endif +{ + /* Set application address via x4 */ + asm volatile("mov x4, %0" : : "r"(app_offset)); + +#ifdef MMU + /* Move the dts pointer to x5 (as first argument) */ + asm volatile("mov x5, %0" : : "r"(dts_offset)); +#else + asm volatile("mov x5, xzr"); +#endif + + /* Initialize GICv2 for Kernel */ + gicv2_init_secure(); + + /* Zero registers x1, x2, x3 */ + asm volatile("mov x3, xzr"); + asm volatile("mov x2, xzr"); + asm volatile("mov x1, xzr"); + + /* Move the dts pointer to x0 (as first argument) */ + asm volatile("mov x0, x5"); + + /* Unconditionally jump to app_entry at x4 */ + asm volatile("br x4"); +} + +#ifdef RAM_CODE + +#define AIRCR *(volatile uint32_t *)(0xE000ED0C) +#define AIRCR_VKEY (0x05FA << 16) +#define AIRCR_SYSRESETREQ (1 << 2) + +void RAMFUNCTION arch_reboot(void) +{ + AIRCR = AIRCR_SYSRESETREQ | AIRCR_VKEY; + while(1) + ; + +} +#endif diff --git a/src/boot_aarch64_start.S b/src/boot_aarch64_start.S new file mode 100644 index 000000000..16c3e8dd6 --- /dev/null +++ b/src/boot_aarch64_start.S @@ -0,0 +1,101 @@ +/** + * Aarch64 bootup + * Copyright (C) 2020 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#define GICD_BASE 0xF9010000 +#define GICD_CTLR 0x0000 +#define GICD_TYPER 0x0004 +#define GICD_SGIR 0x0F00 +#define GICD_IGROUPRn 0x0080 + +#define GICC_BASE 0xF9020000 +#define GICC_PMR 0x0004 + +#ifndef USE_BUILTIN_STARTUP +.section ".boot" +.global _vector_table +_vector_table: + mov x21, x0 // read ATAG/FDT address + +4: ldr x1, =_vector_table // get start of .text in x1 + // Read current EL + mrs x0, CurrentEL + and x0, x0, #0x0C + + // EL == 3? + cmp x0, #12 + bne 2f +3: mrs x2, scr_el3 + orr x2, x2, 0x0F // scr_el3 |= NS|IRQ|FIQ|EA + msr scr_el3, x2 + + msr cptr_el3, xzr // enable FP/SIMD + + // EL == 1? +2: cmp x0, #4 + beq 1f + + // EL == 2? + mov x2, #3 << 20 + msr cptr_el2, x2 /* Enable FP/SIMD */ + b 0f + +1: mov x0, #3 << 20 + msr cpacr_el1, x0 // Enable FP/SIMD for EL1 + msr sp_el1, x1 + + /* Suspend slave CPUs */ +0: mrs x3, mpidr_el1 // read MPIDR_EL1 + and x3, x3, #3 // CPUID = MPIDR_EL1 & 0x03 + cbz x3, 8f // if 0, branch forward +7: wfi // infinite sleep + b 7b + +8: mov sp, x1 // set stack pointer + bl boot_entry_C // boot_entry_C never returns + b 7b // go to sleep anyhow in case. +#endif /* USE_BUILTIN_STARTUP */ + + +/* Initialize GIC 400 (GICv2) */ +.global gicv2_init_secure +gicv2_init_secure: + ldr x0, =GICD_BASE + mov w9, #0x3 /* EnableGrp0 | EnableGrp1 */ + str w9, [x0, GICD_CTLR] /* Secure GICD_CTLR */ + ldr w9, [x0, GICD_TYPER] + and w10, w9, #0x1f /* ITLinesNumber */ + cbz w10, 1f /* No SPIs */ + add x11, x0, GICD_IGROUPRn + mov w9, #~0 /* Config SPIs as Grp1 */ + str w9, [x11], #0x4 +0: str w9, [x11], #0x4 + sub w10, w10, #0x1 + cbnz w10, 0b + + ldr x1, =GICC_BASE /* GICC_CTLR */ + mov w0, #3 /* EnableGrp0 | EnableGrp1 */ + str w0, [x1] + + mov w0, #1 << 7 /* Allow NS access to GICC_PMR */ + str w0, [x1, #4] /* GICC_PMR */ +1: + ret diff --git a/src/image.c b/src/image.c index 03a6fc785..033f6f25b 100644 --- a/src/image.c +++ b/src/image.c @@ -101,22 +101,13 @@ static int wolfBoot_verify_signature(uint8_t *hash, uint8_t *sig) #include #include -#ifdef WOLFBOOT_SIGN_RSA4096 -# define RSA_MAX_KEY_SIZE 512 -# define RSA_SIG_SIZE 512 -#else -# define RSA_MAX_KEY_SIZE 256 -# define RSA_SIG_SIZE 256 -#endif - static int wolfBoot_verify_signature(uint8_t *hash, uint8_t *sig) { - int ret, res = 0; + int ret; struct RsaKey rsa; uint8_t digest_out[IMAGE_SIGNATURE_SIZE]; word32 in_out = 0; - ret = wc_InitRsaKey(&rsa, NULL); if (ret < 0) { /* Failed to initialize key */ @@ -128,7 +119,7 @@ static int wolfBoot_verify_signature(uint8_t *hash, uint8_t *sig) /* Failed to import rsa key */ return -1; } - ret = wc_RsaSSL_Verify(sig, RSA_SIG_SIZE, digest_out, RSA_SIG_SIZE, &rsa); + ret = wc_RsaSSL_Verify(sig, IMAGE_SIGNATURE_SIZE, digest_out, IMAGE_SIGNATURE_SIZE, &rsa); if (ret == WOLFBOOT_SHA_DIGEST_SIZE) { if (memcmp(digest_out, hash, ret) == 0) return 0; @@ -150,11 +141,10 @@ static uint16_t get_header_ext(struct wolfBoot_image *img, uint16_t type, uint8_ static uint16_t get_header(struct wolfBoot_image *img, uint16_t type, uint8_t **ptr) { -#if defined(PART_UPDATE_EXT) - if(img->part == PART_UPDATE) + if (PART_IS_EXT(img)) return get_header_ext(img, type, ptr); -#endif - return wolfBoot_find_header(img->hdr + IMAGE_HEADER_OFFSET, type, ptr); + else + return wolfBoot_find_header(img->hdr + IMAGE_HEADER_OFFSET, type, ptr); } static uint8_t ext_hash_block[WOLFBOOT_SHA_BLOCK_SIZE]; @@ -163,17 +153,15 @@ static uint8_t *get_sha_block(struct wolfBoot_image *img, uint32_t offset) { if (offset > img->fw_size) return NULL; -#ifdef PART_UPDATE_EXT - if (img->part == PART_UPDATE) { - ext_flash_read((uint32_t)(img->fw_base) + offset, ext_hash_block, WOLFBOOT_SHA_BLOCK_SIZE); + if (PART_IS_EXT(img)) { + ext_flash_read((unsigned long)(img->fw_base) + offset, ext_hash_block, WOLFBOOT_SHA_BLOCK_SIZE); return ext_hash_block; - } -#endif - return (uint8_t *)(img->fw_base + offset); + } else + return (uint8_t *)(img->fw_base + offset); } static uint8_t digest[WOLFBOOT_SHA_DIGEST_SIZE]; -static uint8_t verification[IMAGE_SIGNATURE_SIZE]; + #ifdef EXT_FLASH static uint8_t hdr_cpy[IMAGE_HEADER_SIZE]; @@ -182,7 +170,7 @@ static int hdr_cpy_done = 0; static uint8_t *fetch_hdr_cpy(struct wolfBoot_image *img) { if (!hdr_cpy_done) { - ext_flash_read((uint32_t)img->hdr, hdr_cpy, IMAGE_HEADER_SIZE); + ext_flash_read((uintptr_t)img->hdr, hdr_cpy, IMAGE_HEADER_SIZE); hdr_cpy_done = 1; } return hdr_cpy; @@ -193,16 +181,17 @@ static uint16_t get_header_ext(struct wolfBoot_image *img, uint16_t type, uint8_ return wolfBoot_find_header(fetch_hdr_cpy(img) + IMAGE_HEADER_OFFSET, type, ptr); } +#else +# define fetch_hdr_cpy(i) ((uint8_t *)0) +static uint16_t get_header_ext(struct wolfBoot_image *img, uint16_t type, uint8_t **ptr) { return 0; } #endif static uint8_t *get_img_hdr(struct wolfBoot_image *img) { -#ifdef PART_UPDATE_EXT - if (img->part == PART_UPDATE) { + if (PART_IS_EXT(img)) return fetch_hdr_cpy(img); - } -#endif - return (uint8_t *)(img->hdr); + else + return (uint8_t *)(img->hdr); } #ifndef WOLFTPM2_NO_WOLFCRYPT @@ -278,7 +267,7 @@ static int image_sha3_384(struct wolfBoot_image *img, uint8_t *hash) stored_sha_len = get_header(img, HDR_SHA3_384, &stored_sha); if (stored_sha_len != WOLFBOOT_SHA_DIGEST_SIZE) return -1; - wc_InitSha3_384(&sha3_ctx, NULL, 0); + wc_InitSha3_384(&sha3_ctx, NULL, INVALID_DEVID); end_sha = stored_sha - (2 * sizeof(uint16_t)); /* Subtract 2 Type + 2 Len */ while (p < end_sha) { blksz = WOLFBOOT_SHA_BLOCK_SIZE; @@ -307,7 +296,7 @@ static void key_sha3_384(uint8_t *hash) int blksz; unsigned int i = 0; wc_Sha3 sha3_ctx; - wc_InitSha3_384(&sha3_ctx, NULL, 0); + wc_InitSha3_384(&sha3_ctx, NULL, INVALID_DEVID); while(i < KEY_LEN) { blksz = WOLFBOOT_SHA_BLOCK_SIZE; @@ -464,27 +453,56 @@ int wolfBoot_open_image(struct wolfBoot_image *img, uint8_t part) uint8_t *image; if (!img) return -1; + +#ifdef EXT_FLASH + hdr_cpy_done = 0; /* reset hdr "open" flag */ +#endif + memset(img, 0, sizeof(struct wolfBoot_image)); img->part = part; if (part == PART_SWAP) { - img->part = PART_SWAP; - img->hdr = (void *)WOLFBOOT_PARTITION_SWAP_ADDRESS; + img->hdr_ok = 1; + img->hdr = (void*)WOLFBOOT_PARTITION_SWAP_ADDRESS; img->fw_base = img->hdr; img->fw_size = WOLFBOOT_SECTOR_SIZE; return 0; } +#ifdef MMU + if (part == PART_DTS_BOOT || part == PART_DTS_UPDATE) { + img->hdr = (part == PART_DTS_BOOT) ? (void*)WOLFBOOT_DTS_BOOT_ADDRESS + : (void*)WOLFBOOT_DTS_UPDATE_ADDRESS; + if (PART_IS_EXT(img)) + image = fetch_hdr_cpy(img); + else + image = (uint8_t*)img->hdr; + if (*((uint32_t*)image) != UBOOT_FDT_MAGIC) + return -1; + img->hdr_ok = 1; + img->fw_base = img->hdr; + /* DTS data is big endian */ + size = (uint32_t*)(image + sizeof(uint32_t)); + img->fw_size = (((*size & 0x000000FF) << 24) | + ((*size & 0x0000FF00) << 8) | + ((*size & 0x00FF0000) >> 8) | + ((*size & 0xFF000000) >> 24)); + return 0; + } +#endif if (part == PART_BOOT) { - img->hdr = (void *)WOLFBOOT_PARTITION_BOOT_ADDRESS; - image = (uint8_t *)img->hdr; + img->hdr = (void*)WOLFBOOT_PARTITION_BOOT_ADDRESS; } else if (part == PART_UPDATE) { - img->hdr = (void *)WOLFBOOT_PARTITION_UPDATE_ADDRESS; -#ifdef PART_UPDATE_EXT - image = fetch_hdr_cpy(img); -#else - image = (uint8_t *)img->hdr; -#endif + img->hdr = (void*)WOLFBOOT_PARTITION_UPDATE_ADDRESS; } else return -1; + + /* fetch header address + * (or copy from external device to a local buffer via fetch_hdr_cpy) + */ + if (PART_IS_EXT(img)) + image = fetch_hdr_cpy(img); + else + image = (uint8_t *)img->hdr; + magic = (uint32_t *)(image); if (*magic != WOLFBOOT_MAGIC) return -1; @@ -511,6 +529,7 @@ int wolfBoot_verify_integrity(struct wolfBoot_image *img) if (memcmp(digest, stored_sha, stored_sha_len) != 0) return -1; img->sha_ok = 1; + img->sha_hash = stored_sha; return 0; } @@ -539,10 +558,24 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img) image_type = (uint16_t)(image_type_buf[0] + (image_type_buf[1] << 8)); if ((image_type & 0xFF00) != HDR_IMG_TYPE_AUTH) return -1; - if (image_hash(img, digest) != 0) - return -1; - if (wolfBoot_verify_signature(digest, stored_signature) != 0) + if (img->sha_hash == NULL) { + if (image_hash(img, digest) != 0) + return -1; + img->sha_hash = digest; + } + if (wolfBoot_verify_signature(img->sha_hash, stored_signature) != 0) return -1; img->signature_ok = 1; return 0; } + +/* Peek at image offset and return static pointer */ +/* sz: optional and returns length of peek */ +uint8_t* wolfBoot_peek_image(struct wolfBoot_image *img, uint32_t offset, + uint32_t* sz) +{ + uint8_t* p = get_sha_block(img, offset); + if (sz) + *sz = WOLFBOOT_SHA_BLOCK_SIZE; + return p; +} diff --git a/src/libwolfboot.c b/src/libwolfboot.c index f83799717..256d39017 100644 --- a/src/libwolfboot.c +++ b/src/libwolfboot.c @@ -58,14 +58,25 @@ int RAMFUNCTION hal_trailer_write(uint32_t addr, uint8_t val) { # define hal_trailer_write(addr, val) hal_flash_write(addr, (void *)&val, 1) #endif -#if defined PART_UPDATE_EXT +#if defined EXT_FLASH + static uint8_t* RAMFUNCTION get_trailer_at(uint8_t part, uint32_t at) { - if (part == PART_BOOT) - return (void *)(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at)); + if (part == PART_BOOT) { + if (PARTN_IS_EXT(PART_BOOT)) { + ext_flash_read(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&ext_cache, sizeof(uint32_t)); + return (uint8_t *)&ext_cache; + } else { + return (void *)(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at)); + } + } else if (part == PART_UPDATE) { - ext_flash_read(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&ext_cache, sizeof(uint32_t)); - return (uint8_t *)&ext_cache; + if (PARTN_IS_EXT(PART_UPDATE)) { + ext_flash_read(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&ext_cache, sizeof(uint32_t)); + return (uint8_t *)&ext_cache; + } else { + return (void *)(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at)); + } } else return NULL; } @@ -73,10 +84,18 @@ static uint8_t* RAMFUNCTION get_trailer_at(uint8_t part, uint32_t at) static void RAMFUNCTION set_trailer_at(uint8_t part, uint32_t at, uint8_t val) { if (part == PART_BOOT) { - hal_trailer_write(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at), val); + if (PARTN_IS_EXT(PART_BOOT)) { + ext_flash_write(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&val, 1); + } else { + hal_trailer_write(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at), val); + } } else if (part == PART_UPDATE) { - ext_flash_write(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&val, 1); + if (PARTN_IS_EXT(PART_UPDATE)) { + ext_flash_write(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&val, 1); + } else { + hal_trailer_write(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at), val); + } } } @@ -84,10 +103,18 @@ static void RAMFUNCTION set_partition_magic(uint8_t part) { uint32_t wolfboot_magic_trail = WOLFBOOT_MAGIC_TRAIL; if (part == PART_BOOT) { - hal_flash_write(PART_BOOT_ENDFLAGS - sizeof(uint32_t), (void *)&wolfboot_magic_trail, sizeof(uint32_t)); + if (PARTN_IS_EXT(PART_BOOT)) { + ext_flash_write(PART_BOOT_ENDFLAGS - sizeof(uint32_t), (void *)&wolfboot_magic_trail, sizeof(uint32_t)); + } else { + hal_flash_write(PART_BOOT_ENDFLAGS - sizeof(uint32_t), (void *)&wolfboot_magic_trail, sizeof(uint32_t)); + } } else if (part == PART_UPDATE) { - ext_flash_write(PART_UPDATE_ENDFLAGS - sizeof(uint32_t), (void *)&wolfboot_magic_trail, sizeof(uint32_t)); + if (PARTN_IS_EXT(PART_UPDATE)) { + ext_flash_write(PART_UPDATE_ENDFLAGS - sizeof(uint32_t), (void *)&wolfboot_magic_trail, sizeof(uint32_t)); + } else { + hal_flash_write(PART_UPDATE_ENDFLAGS - sizeof(uint32_t), (void *)&wolfboot_magic_trail, sizeof(uint32_t)); + } } } @@ -122,7 +149,7 @@ static void RAMFUNCTION set_partition_magic(uint8_t part) hal_flash_write(PART_UPDATE_ENDFLAGS - sizeof(uint32_t), (void *)&wolfboot_magic_trail, sizeof(uint32_t)); } } -#endif /* PART_UPDATE_EXT */ +#endif /* EXT_FLASH */ @@ -169,10 +196,10 @@ int RAMFUNCTION wolfBoot_set_sector_flag(uint8_t part, uint8_t sector, uint8_t n uint32_t *magic; uint8_t *flags; uint8_t fl_value; - uint32_t wolfboot_magic_trail = WOLFBOOT_MAGIC_TRAIL; + const uint32_t wolfboot_magic_trail = WOLFBOOT_MAGIC_TRAIL; uint8_t pos = sector >> 1; magic = get_partition_magic(part); - if (*magic != WOLFBOOT_MAGIC_TRAIL) + if (*magic != wolfboot_magic_trail) set_partition_magic(part); flags = get_sector_flags(part, pos); if (sector == (pos << 1)) @@ -214,41 +241,63 @@ int wolfBoot_get_sector_flag(uint8_t part, uint8_t sector, uint8_t *flag) void RAMFUNCTION wolfBoot_erase_partition(uint8_t part) { - if (part == PART_BOOT) - hal_flash_erase(WOLFBOOT_PARTITION_BOOT_ADDRESS, WOLFBOOT_PARTITION_SIZE); + if (part == PART_BOOT) { + if (PARTN_IS_EXT(PART_BOOT)) { + ext_flash_unlock(); + ext_flash_erase(WOLFBOOT_PARTITION_BOOT_ADDRESS, WOLFBOOT_PARTITION_SIZE); + ext_flash_lock(); + } else { + hal_flash_erase(WOLFBOOT_PARTITION_BOOT_ADDRESS, WOLFBOOT_PARTITION_SIZE); + } + } if (part == PART_UPDATE) { -#ifdef PART_UPDATE_EXT - ext_flash_unlock(); - ext_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_PARTITION_SIZE); - ext_flash_lock(); -#else - hal_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_PARTITION_SIZE); -#endif + if (PARTN_IS_EXT(PART_UPDATE)) { + ext_flash_unlock(); + ext_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_PARTITION_SIZE); + ext_flash_lock(); + } else { + hal_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_PARTITION_SIZE); + } + } + if (part == PART_SWAP) { + if (PARTN_IS_EXT(PART_SWAP)) { + ext_flash_unlock(); + ext_flash_erase(WOLFBOOT_PARTITION_SWAP_ADDRESS, WOLFBOOT_SECTOR_SIZE); + ext_flash_lock(); + } else { + hal_flash_erase(WOLFBOOT_PARTITION_SWAP_ADDRESS, WOLFBOOT_SECTOR_SIZE); + } } - if (part == PART_SWAP) - hal_flash_erase(WOLFBOOT_PARTITION_SWAP_ADDRESS, WOLFBOOT_SECTOR_SIZE); } void RAMFUNCTION wolfBoot_update_trigger(void) { uint8_t st = IMG_STATE_UPDATING; -#ifdef PART_UPDATE_EXT - ext_flash_unlock(); - wolfBoot_set_partition_state(PART_UPDATE, st); - ext_flash_lock(); -#else - hal_flash_unlock(); - wolfBoot_set_partition_state(PART_UPDATE, st); - hal_flash_lock(); -#endif + if (PARTN_IS_EXT(PART_UPDATE)) + { + ext_flash_unlock(); + wolfBoot_set_partition_state(PART_UPDATE, st); + ext_flash_lock(); + } else { + hal_flash_unlock(); + wolfBoot_set_partition_state(PART_UPDATE, st); + hal_flash_lock(); + } } void RAMFUNCTION wolfBoot_success(void) { uint8_t st = IMG_STATE_SUCCESS; - hal_flash_unlock(); - wolfBoot_set_partition_state(PART_BOOT, st); - hal_flash_lock(); + if (PARTN_IS_EXT(PART_BOOT)) + { + ext_flash_unlock(); + wolfBoot_set_partition_state(PART_BOOT, st); + ext_flash_lock(); + } else { + hal_flash_unlock(); + wolfBoot_set_partition_state(PART_BOOT, st); + hal_flash_lock(); + } } uint16_t wolfBoot_find_header(uint8_t *haystack, uint16_t type, uint8_t **ptr) @@ -276,33 +325,46 @@ static uint8_t hdr_cpy[IMAGE_HEADER_SIZE]; static uint32_t hdr_cpy_done = 0; #endif -uint32_t wolfBoot_get_image_version(uint8_t part) +uint32_t wolfBoot_get_blob_version(uint8_t *blob) { uint32_t *version_field = NULL; - uint32_t version = 0; - uint8_t *image = NULL; uint32_t *magic = NULL; - if(part == PART_UPDATE) { -#ifdef PART_UPDATE_EXT - ext_flash_read((uint32_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS, hdr_cpy, IMAGE_HEADER_SIZE); - hdr_cpy_done = 1; - image = hdr_cpy; -#else - image = (uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS; -#endif - } - if (part == PART_BOOT) - image = (uint8_t *)WOLFBOOT_PARTITION_BOOT_ADDRESS; + magic = (uint32_t *)blob; + if (*magic != WOLFBOOT_MAGIC) + return 0; + wolfBoot_find_header(blob + IMAGE_HEADER_OFFSET, HDR_VERSION, (void *)&version_field); + if (version_field) + return *version_field; + return 0; +} - if (image) { - magic = (uint32_t *)image; - if (*magic != WOLFBOOT_MAGIC) - return 0; - wolfBoot_find_header(image + IMAGE_HEADER_OFFSET, HDR_VERSION, (void *)&version_field); - if (version_field) - return *version_field; +uint32_t wolfBoot_get_image_version(uint8_t part) +{ + uint8_t *image = (uint8_t *)0x00000000; + if(part == PART_UPDATE) { + if (PARTN_IS_EXT(PART_UPDATE)) + { + #ifdef EXT_FLASH + ext_flash_read((uint32_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS, hdr_cpy, IMAGE_HEADER_SIZE); + hdr_cpy_done = 1; + image = hdr_cpy; + #endif + } else { + image = (uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS; + } + } else if (part == PART_BOOT) { + if (PARTN_IS_EXT(PART_BOOT)) { + #ifdef EXT_FLASH + ext_flash_read((uint32_t)WOLFBOOT_PARTITION_BOOT_ADDRESS, hdr_cpy, IMAGE_HEADER_SIZE); + hdr_cpy_done = 1; + image = hdr_cpy; + #endif + } else { + image = (uint8_t *)WOLFBOOT_PARTITION_BOOT_ADDRESS; + } } - return 0; + /* Don't check image against NULL to allow using address 0x00000000 */ + return wolfBoot_get_blob_version(image); } uint16_t wolfBoot_get_image_type(uint8_t part) @@ -311,17 +373,27 @@ uint16_t wolfBoot_get_image_type(uint8_t part) uint8_t *image = NULL; uint32_t *magic = NULL; if(part == PART_UPDATE) { -#ifdef PART_UPDATE_EXT - ext_flash_read((uint32_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS, hdr_cpy, IMAGE_HEADER_SIZE); - hdr_cpy_done = 1; - image = hdr_cpy; -#else - image = (uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS; -#endif + if (PARTN_IS_EXT(PART_UPDATE)) + { + #ifdef EXT_FLASH + ext_flash_read((uint32_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS, hdr_cpy, IMAGE_HEADER_SIZE); + hdr_cpy_done = 1; + image = hdr_cpy; + #endif + } else { + image = (uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS; + } + } else if (part == PART_BOOT) { + if (PARTN_IS_EXT(PART_BOOT)) { + #ifdef EXT_FLASH + ext_flash_read((uint32_t)WOLFBOOT_PARTITION_BOOT_ADDRESS, hdr_cpy, IMAGE_HEADER_SIZE); + hdr_cpy_done = 1; + image = hdr_cpy; + #endif + } else { + image = (uint8_t *)WOLFBOOT_PARTITION_BOOT_ADDRESS; + } } - if (part == PART_BOOT) - image = (uint8_t *)WOLFBOOT_PARTITION_BOOT_ADDRESS; - if (image) { magic = (uint32_t *)image; if (*magic != WOLFBOOT_MAGIC) @@ -332,3 +404,57 @@ uint16_t wolfBoot_get_image_type(uint8_t part) } return 0; } + +#if defined(ARCH_AARCH64) || defined(DUALBANK_SWAP) +int wolfBoot_fallback_is_possible(void) +{ + uint32_t boot_v, update_v; + boot_v = wolfBoot_current_firmware_version(); + update_v = wolfBoot_update_firmware_version(); + if ((boot_v == 0) || (update_v == 0)) + return 0; + return 1; +} + +int wolfBoot_dualboot_candidate(void) +{ + int candidate = PART_BOOT; + int fallback_possible = 0; + uint32_t boot_v, update_v; + uint8_t p_state; + /* Find the candidate */ + boot_v = wolfBoot_current_firmware_version(); + update_v = wolfBoot_update_firmware_version(); + /* -1 means no images available */ + if ((boot_v == 0) && (update_v == 0)) + return -1; + + if (boot_v == 0) /* No primary image */ + candidate = PART_UPDATE; + else if ((boot_v > 0) && (update_v > 0)) { + fallback_possible = 1; + if (update_v > boot_v) + candidate = PART_UPDATE; + } + /* Check current status for failure (still in TESTING), and fall-back + * if an alternative is available + */ + if (fallback_possible && + (wolfBoot_get_partition_state(candidate, &p_state) == 0) && + (p_state == IMG_STATE_TESTING)) + { + wolfBoot_erase_partition(candidate); + candidate ^= 1; /* switch to other partition if available */ + } + return candidate; +} +#else +int wolfBoot_dualboot_candidate(void) { return 0; } +int wolfBoot_fallback_is_possible(void) +{ + if (wolfBoot_update_firmware_version() > 0) + return 1; + return 0; +} +#endif + diff --git a/src/loader.c b/src/loader.c index 69cb38303..cec3ce435 100644 --- a/src/loader.c +++ b/src/loader.c @@ -165,196 +165,8 @@ static int wolfBoot_update(int fallback_allowed) hal_flash_lock(); return 0; } - -#else /* DUALBANK_SWAP */ - -static inline void boot_panic(void) -{ - while(1) - ; -} - -static void RAMFUNCTION wolfBoot_start(void) -{ - int ret; - struct wolfBoot_image fw_image, boot_image; - uint8_t p_state; - uint32_t boot_v, update_v; - int candidate = PART_BOOT; - int fallback_is_possible = 0; - - /* Find the candidate */ - boot_v = wolfBoot_current_firmware_version(); - update_v = wolfBoot_update_firmware_version(); - - /* panic if no images available */ - if ((boot_v == 0) && (update_v == 0)) - boot_panic(); - - else if (boot_v == 0) /* No primary image */ - { - candidate = PART_UPDATE; - } - else if ((boot_v > 0) && (update_v > 0)) { - fallback_is_possible = 1; - if (update_v > boot_v) - candidate = PART_UPDATE; - } - - /* Check current status for failure (still in TESTING), and fall-back - * if an alternative is available - */ - if (fallback_is_possible && - (wolfBoot_get_partition_state(candidate, &p_state) == 0) && - (p_state == IMG_STATE_TESTING)) - { - candidate ^= 1; /* switch to other partition if available */ - } - - for (;;) { - if ((wolfBoot_open_image(&fw_image, candidate) < 0) || - (wolfBoot_verify_integrity(&fw_image) < 0) || - (wolfBoot_verify_authenticity(&fw_image) < 0)) { - - /* panic if authentication fails and no backup */ - if (!fallback_is_possible) - boot_panic(); - else { - /* Invalidate failing image and switch to the - * other partition - */ - fallback_is_possible = 0; - wolfBoot_erase_partition(candidate); - candidate ^= 1; - } - } else - break; /* candidate successfully authenticated */ - } - - /* First time we boot this update, set to TESTING to await - * confirmation from the system - */ - if ((wolfBoot_get_partition_state(candidate, &p_state) == 0) && - (p_state == IMG_STATE_UPDATING)) - { - hal_flash_unlock(); - wolfBoot_set_partition_state(candidate, IMG_STATE_TESTING); - hal_flash_lock(); - } - - /* Booting from update is possible via HW-assisted swap */ - if (candidate == PART_UPDATE) - hal_flash_dualbank_swap(); - - hal_prepare_boot(); - do_boot((void *)WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_SIZE); -} -#endif - -#ifdef RAM_CODE - -static void RAMFUNCTION wolfBoot_erase_bootloader(void) -{ - uint32_t *start = (uint32_t *)&_start_text; - uint32_t len = WOLFBOOT_PARTITION_BOOT_ADDRESS - (uint32_t)start; - hal_flash_erase((uint32_t)start, len); - -} - -#include - -static void RAMFUNCTION wolfBoot_self_update(struct wolfBoot_image *src) -{ - uint32_t pos = 0; - uint32_t src_offset = IMAGE_HEADER_SIZE; - - hal_flash_unlock(); - wolfBoot_erase_bootloader(); -#ifdef EXT_FLASH - while (pos < src->fw_size) { - if (PART_IS_EXT(src)) { - uint8_t buffer[FLASHBUFFER_SIZE]; - if (src_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) { - ext_flash_read((uint32_t)(src->hdr) + src_offset + pos, (void *)buffer, FLASHBUFFER_SIZE); - hal_flash_write(pos + (uint32_t)&_start_text, buffer, FLASHBUFFER_SIZE); - } - pos += FLASHBUFFER_SIZE; - } - goto lock_and_reset; - } #endif - while (pos < src->fw_size) { - if (src_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) { - uint8_t *orig = (uint8_t*)(src->hdr + src_offset + pos); - hal_flash_write(pos + (uint32_t)&_start_text, orig, FLASHBUFFER_SIZE); - } - pos += FLASHBUFFER_SIZE; - } - -lock_and_reset: - hal_flash_lock(); - arch_reboot(); -} -static void wolfBoot_check_self_update(void) -{ - uint8_t st; - struct wolfBoot_image update; - uint8_t *update_type; - uint32_t update_version; - - /* Check for self update in the UPDATE partition */ - if ((wolfBoot_get_partition_state(PART_UPDATE, &st) == 0) && (st == IMG_STATE_UPDATING) && - (wolfBoot_open_image(&update, PART_UPDATE) == 0) && - wolfBoot_get_image_type(PART_UPDATE) == (HDR_IMG_TYPE_WOLFBOOT | HDR_IMG_TYPE_AUTH)) { - uint32_t update_version = wolfBoot_update_firmware_version(); - if (update_version <= wolfboot_version) { - hal_flash_unlock(); - wolfBoot_erase_partition(PART_UPDATE); - hal_flash_lock(); - return; - } - if (wolfBoot_verify_integrity(&update) < 0) - return; - if (wolfBoot_verify_authenticity(&update) < 0) - return; - wolfBoot_self_update(&update); - } -} -#endif /* RAM_CODE for self_update */ - -#ifndef DUALBANK_SWAP -static void wolfBoot_start(void) -{ - uint8_t st; - struct wolfBoot_image boot, update; - -#ifdef RAM_CODE - wolfBoot_check_self_update(); -#endif - - /* Check if the BOOT partition is still in TESTING, - * to trigger fallback. - */ - if ((wolfBoot_get_partition_state(PART_BOOT, &st) == 0) && (st == IMG_STATE_TESTING)) { - wolfBoot_update_trigger(); - wolfBoot_update(1); - /* Check for new updates in the UPDATE partition */ - } else if ((wolfBoot_get_partition_state(PART_UPDATE, &st) == 0) && (st == IMG_STATE_UPDATING)) { - wolfBoot_update(0); - } - if ((wolfBoot_open_image(&boot, PART_BOOT) < 0) || - (wolfBoot_verify_integrity(&boot) < 0) || - (wolfBoot_verify_authenticity(&boot) < 0)) { - if (wolfBoot_update(1) < 0) { - while(1) - /* panic */; - } - } - hal_prepare_boot(); - do_boot((void *)boot.fw_base); -} -#endif /* ifndef DUALBANK_SWAP */ int main(void) { diff --git a/src/string.c b/src/string.c index b09274c25..ca560854c 100644 --- a/src/string.c +++ b/src/string.c @@ -196,7 +196,7 @@ char *strcpy(char *dst, const char *src) { size_t i = 0; - while(1 < 2) { + while(1) { dst[i] = src[i]; if (src[i] == '\0') break; diff --git a/src/update_flash.c b/src/update_flash.c new file mode 100644 index 000000000..5d6fb5911 --- /dev/null +++ b/src/update_flash.c @@ -0,0 +1,268 @@ +/* update_flash.c + * + * Implementation for Flash based updater + * + * + * Copyright (C) 2020 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include "loader.h" +#include "image.h" +#include "hal.h" +#include "spi_flash.h" +#include "wolfboot/wolfboot.h" + +#define FLASHBUFFER_SIZE 256 + +#ifdef RAM_CODE +extern unsigned int _start_text; +static volatile const uint32_t __attribute__((used)) wolfboot_version = WOLFBOOT_VERSION; + +static void RAMFUNCTION wolfBoot_erase_bootloader(void) +{ + uint32_t *start = (uint32_t *)&_start_text; + uint32_t len = WOLFBOOT_PARTITION_BOOT_ADDRESS - (uint32_t)start; + hal_flash_erase((uint32_t)start, len); + +} + +#include + +static void RAMFUNCTION wolfBoot_self_update(struct wolfBoot_image *src) +{ + uint32_t pos = 0; + uint32_t src_offset = IMAGE_HEADER_SIZE; + + hal_flash_unlock(); + wolfBoot_erase_bootloader(); +#ifdef EXT_FLASH + while (pos < src->fw_size) { + if (PART_IS_EXT(src)) { + uint8_t buffer[FLASHBUFFER_SIZE]; + if (src_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) { + ext_flash_read((uint32_t)(src->hdr) + src_offset + pos, (void *)buffer, FLASHBUFFER_SIZE); + hal_flash_write(pos + (uint32_t)&_start_text, buffer, FLASHBUFFER_SIZE); + } + pos += FLASHBUFFER_SIZE; + } + goto lock_and_reset; + } +#endif + while (pos < src->fw_size) { + if (src_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) { + uint8_t *orig = (uint8_t*)(src->hdr + src_offset + pos); + hal_flash_write(pos + (uint32_t)&_start_text, orig, FLASHBUFFER_SIZE); + } + pos += FLASHBUFFER_SIZE; + } + +lock_and_reset: + hal_flash_lock(); + arch_reboot(); +} + +void wolfBoot_check_self_update(void) +{ + uint8_t st; + struct wolfBoot_image update; + uint8_t *update_type; + uint32_t update_version; + + /* Check for self update in the UPDATE partition */ + if ((wolfBoot_get_partition_state(PART_UPDATE, &st) == 0) && (st == IMG_STATE_UPDATING) && + (wolfBoot_open_image(&update, PART_UPDATE) == 0) && + wolfBoot_get_image_type(PART_UPDATE) == (HDR_IMG_TYPE_WOLFBOOT | HDR_IMG_TYPE_AUTH)) { + uint32_t update_version = wolfBoot_update_firmware_version(); + if (update_version <= wolfboot_version) { + hal_flash_unlock(); + wolfBoot_erase_partition(PART_UPDATE); + hal_flash_lock(); + return; + } + if (wolfBoot_verify_integrity(&update) < 0) + return; + if (wolfBoot_verify_authenticity(&update) < 0) + return; + wolfBoot_self_update(&update); + } +} +#endif /* RAM_CODE for self_update */ + +static int wolfBoot_copy_sector(struct wolfBoot_image *src, struct wolfBoot_image *dst, uint32_t sector) +{ + uint32_t pos = 0; + uint32_t src_sector_offset = (sector * WOLFBOOT_SECTOR_SIZE); + uint32_t dst_sector_offset = (sector * WOLFBOOT_SECTOR_SIZE); + if (src == dst) + return 0; + + if (src->part == PART_SWAP) + src_sector_offset = 0; + if (dst->part == PART_SWAP) + dst_sector_offset = 0; +#ifdef EXT_FLASH + if (PART_IS_EXT(src)) { + uint8_t buffer[FLASHBUFFER_SIZE]; + wb_flash_erase(dst, dst_sector_offset, WOLFBOOT_SECTOR_SIZE); + while (pos < WOLFBOOT_SECTOR_SIZE) { + if (src_sector_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) { + ext_flash_read((uint32_t)(src->hdr) + src_sector_offset + pos, (void *)buffer, FLASHBUFFER_SIZE); + wb_flash_write(dst, dst_sector_offset + pos, buffer, FLASHBUFFER_SIZE); + } + pos += FLASHBUFFER_SIZE; + } + return pos; + } +#endif + wb_flash_erase(dst, dst_sector_offset, WOLFBOOT_SECTOR_SIZE); + while (pos < WOLFBOOT_SECTOR_SIZE) { + if (src_sector_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) { + uint8_t *orig = (uint8_t*)(src->hdr + src_sector_offset + pos); + wb_flash_write(dst, dst_sector_offset + pos, orig, FLASHBUFFER_SIZE); + } + pos += FLASHBUFFER_SIZE; + } + return pos; +} + +static int wolfBoot_update(int fallback_allowed) +{ + uint32_t total_size = 0; + const uint32_t sector_size = WOLFBOOT_SECTOR_SIZE; + uint32_t sector = 0; + uint8_t flag, st; + struct wolfBoot_image boot, update, swap; + + /* No Safety check on open: we might be in the middle of a broken update */ + wolfBoot_open_image(&update, PART_UPDATE); + wolfBoot_open_image(&boot, PART_BOOT); + wolfBoot_open_image(&swap, PART_SWAP); + + /* Use biggest size for the swap */ + total_size = boot.fw_size + IMAGE_HEADER_SIZE; + if ((update.fw_size + IMAGE_HEADER_SIZE) > total_size) + total_size = update.fw_size + IMAGE_HEADER_SIZE; + + if (total_size <= IMAGE_HEADER_SIZE) + return -1; + + /* Check the first sector to detect interrupted update */ + if ((wolfBoot_get_sector_flag(PART_UPDATE, 0, &flag) < 0) || (flag == SECT_FLAG_NEW)) + { + uint16_t update_type; + /* In case this is a new update, do the required + * checks on the firmware update + * before starting the swap + */ + + update_type = wolfBoot_get_image_type(PART_UPDATE); + if (((update_type & 0x00FF) != HDR_IMG_TYPE_APP) || ((update_type & 0xFF00) != HDR_IMG_TYPE_AUTH)) + return -1; + if (!update.hdr_ok || (wolfBoot_verify_integrity(&update) < 0) + || (wolfBoot_verify_authenticity(&update) < 0)) { + return -1; + } +#ifndef ALLOW_DOWNGRADE + if ( !fallback_allowed && + (wolfBoot_update_firmware_version() <= wolfBoot_current_firmware_version()) ) + return -1; +#endif + } + + hal_flash_unlock(); +#ifdef EXT_FLASH + ext_flash_unlock(); +#endif + + /* Interruptible swap + * The status is saved in the sector flags of the update partition. + * If something goes wrong, the operation will be resumed upon reboot. + */ + while ((sector * sector_size) < total_size) { + if ((wolfBoot_get_sector_flag(PART_UPDATE, sector, &flag) != 0) || (flag == SECT_FLAG_NEW)) { + flag = SECT_FLAG_SWAPPING; + wolfBoot_copy_sector(&update, &swap, sector); + if (((sector + 1) * sector_size) < WOLFBOOT_PARTITION_SIZE) + wolfBoot_set_sector_flag(PART_UPDATE, sector, flag); + } + if (flag == SECT_FLAG_SWAPPING) { + uint32_t size = total_size - (sector * sector_size); + if (size > sector_size) + size = sector_size; + flag = SECT_FLAG_BACKUP; + wolfBoot_copy_sector(&boot, &update, sector); + if (((sector + 1) * sector_size) < WOLFBOOT_PARTITION_SIZE) + wolfBoot_set_sector_flag(PART_UPDATE, sector, flag); + } + if (flag == SECT_FLAG_BACKUP) { + uint32_t size = total_size - (sector * sector_size); + if (size > sector_size) + size = sector_size; + flag = SECT_FLAG_UPDATED; + wolfBoot_copy_sector(&swap, &boot, sector); + if (((sector + 1) * sector_size) < WOLFBOOT_PARTITION_SIZE) + wolfBoot_set_sector_flag(PART_UPDATE, sector, flag); + } + sector++; + } + while((sector * sector_size) < WOLFBOOT_PARTITION_SIZE) { + wb_flash_erase(&boot, sector * sector_size, sector_size); + wb_flash_erase(&update, sector * sector_size, sector_size); + sector++; + } + wb_flash_erase(&swap, 0, WOLFBOOT_SECTOR_SIZE); + st = IMG_STATE_TESTING; + wolfBoot_set_partition_state(PART_BOOT, st); +#ifdef EXT_FLASH + ext_flash_lock(); +#endif + hal_flash_lock(); + return 0; +} + +void RAMFUNCTION wolfBoot_start(void) +{ + uint8_t st; + struct wolfBoot_image boot, update; + +#ifdef RAM_CODE + wolfBoot_check_self_update(); +#endif + + /* Check if the BOOT partition is still in TESTING, + * to trigger fallback. + */ + if ((wolfBoot_get_partition_state(PART_BOOT, &st) == 0) && (st == IMG_STATE_TESTING)) { + wolfBoot_update_trigger(); + wolfBoot_update(1); + /* Check for new updates in the UPDATE partition */ + } else if ((wolfBoot_get_partition_state(PART_UPDATE, &st) == 0) && (st == IMG_STATE_UPDATING)) { + wolfBoot_update(0); + } + if ((wolfBoot_open_image(&boot, PART_BOOT) < 0) || + (wolfBoot_verify_integrity(&boot) < 0) || + (wolfBoot_verify_authenticity(&boot) < 0)) { + if (wolfBoot_update(1) < 0) { + while(1) + /* panic */; + } + } + hal_prepare_boot(); + do_boot((void *)boot.fw_base); +} diff --git a/src/update_flash_hwswap.c b/src/update_flash_hwswap.c new file mode 100644 index 000000000..f6881745c --- /dev/null +++ b/src/update_flash_hwswap.c @@ -0,0 +1,85 @@ +/* update_flash_hwswap.c + * + * Implementation for hardware assisted updater + * + * + * Copyright (C) 2020 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include "loader.h" +#include "image.h" +#include "hal.h" +#include "spi_flash.h" +#include "wolfboot/wolfboot.h" + +extern void hal_flash_dualbank_swap(void); + +static inline void boot_panic(void) +{ + while(1) + ; +} + +void RAMFUNCTION wolfBoot_start(void) +{ + int active; + struct wolfBoot_image fw_image; + uint8_t p_state; + active = wolfBoot_dualboot_candidate(); + + if (active < 1) /* panic if no images available */ + boot_panic(); + + for (;;) { + if ((wolfBoot_open_image(&fw_image, active) < 0) || + (wolfBoot_verify_integrity(&fw_image) < 0) || + (wolfBoot_verify_authenticity(&fw_image) < 0)) { + + /* panic if authentication fails and no backup */ + if (!wolfBoot_fallback_is_possible()) + boot_panic(); + else { + /* Invalidate failing image and switch to the + * other partition + */ + wolfBoot_erase_partition(active); + active ^= 1; + } + } else + break; /* candidate successfully authenticated */ + } + + /* First time we boot this update, set to TESTING to await + * confirmation from the system + */ + if ((wolfBoot_get_partition_state(active, &p_state) == 0) && + (p_state == IMG_STATE_UPDATING)) + { + hal_flash_unlock(); + wolfBoot_set_partition_state(active, IMG_STATE_TESTING); + hal_flash_lock(); + } + + /* Booting from update is possible via HW-assisted swap */ + if (active == PART_UPDATE) + hal_flash_dualbank_swap(); + + hal_prepare_boot(); + do_boot((void *)WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_SIZE); +} diff --git a/src/update_ram.c b/src/update_ram.c new file mode 100644 index 000000000..aee740c38 --- /dev/null +++ b/src/update_ram.c @@ -0,0 +1,140 @@ +/* update_ram.c + * + * Implementation for RAM based updater + * + * + * Copyright (C) 2020 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include "loader.h" +#include "image.h" +#include "hal.h" +#include "spi_flash.h" +#include "wolfboot/wolfboot.h" +#include + +extern void hal_flash_dualbank_swap(void); + +static inline void boot_panic(void) +{ + while(1) + ; +} + +void RAMFUNCTION wolfBoot_start(void) +{ + int active; + struct wolfBoot_image os_image; + uint32_t* load_address = (uint32_t*)WOLFBOOT_LOAD_ADDRESS; + uint8_t* image_ptr; + uint8_t p_state; +#ifdef MMU + uint32_t* dts_address = NULL; +#endif + + active = wolfBoot_dualboot_candidate(); + + if (active < 0) /* panic if no images available */ + boot_panic(); + + /* Check current status for failure (image still in TESTING), and fall-back + * if an alternative is available + */ + if (wolfBoot_fallback_is_possible() && + (wolfBoot_get_partition_state(active, &p_state) == 0) && + (p_state == IMG_STATE_TESTING)) + { + active ^= 1; /* switch to other partition if available */ + } + + for (;;) { + if ((wolfBoot_open_image(&os_image, active) < 0) || + (wolfBoot_verify_integrity(&os_image) < 0) || + (wolfBoot_verify_authenticity(&os_image) < 0)) { + + /* panic if authentication fails and no backup */ + if (!wolfBoot_fallback_is_possible()) + boot_panic(); + else { + /* Invalidate failing image and switch to the + * other partition + */ + active ^= 1; + continue; + } + } else { + break; + } + } + + /* First time we boot this update, set to TESTING to await + * confirmation from the system + */ + if ((wolfBoot_get_partition_state(active, &p_state) == 0) && + (p_state == IMG_STATE_UPDATING)) + { + hal_flash_unlock(); + wolfBoot_set_partition_state(active, IMG_STATE_TESTING); + hal_flash_lock(); + } + + /* Check for U-Boot Legacy format image header */ + image_ptr = wolfBoot_peek_image(&os_image, 0, NULL); + if (image_ptr) { + if (*((uint32_t*)image_ptr) == UBOOT_IMG_HDR_MAGIC) { + /* Note: Could parse header and get load_address at 0x10 */ + + /* Skip 64 bytes (size of Legacy format image header) */ + os_image.fw_base += UBOOT_IMG_HDR_SZ; + os_image.fw_size -= UBOOT_IMG_HDR_SZ; + } + } + +#ifdef EXT_FLASH + /* Load image to RAM */ + if (PART_IS_EXT(&os_image)) { + ext_flash_read((uintptr_t)os_image.fw_base, + (uint8_t*)load_address, + os_image.fw_size); + } +#endif + +#ifdef MMU + /* Device Tree Blob (DTB) Handling */ + if (wolfBoot_open_image(&os_image, PART_DTS_BOOT) >= 0) { + dts_address = (uint32_t*)WOLFBOOT_LOAD_DTS_ADDRESS; + + #ifdef EXT_FLASH + /* Load DTS to RAM */ + if (PART_IS_EXT(&os_image)) { + ext_flash_read((uintptr_t)os_image.fw_base, + (uint8_t*)dts_address, + os_image.fw_size); + } + #endif + } +#endif + + hal_prepare_boot(); +#ifdef MMU + do_boot((uint32_t*)load_address, (uint32_t*)dts_address); +#else + do_boot((uint32_t*)load_address); +#endif +} diff --git a/src/xmalloc_rsa.c b/src/xmalloc_rsa.c index 16d26534f..4a6942882 100644 --- a/src/xmalloc_rsa.c +++ b/src/xmalloc_rsa.c @@ -48,7 +48,6 @@ void* XMALLOC(size_t n, void* heap, int type) void XFREE(void *ptr) { - int i; if (ptr == sp_digit) sp_digit_in_use = 0; } diff --git a/test-app/AARCH64.ld b/test-app/AARCH64.ld new file mode 100644 index 000000000..18f423fdc --- /dev/null +++ b/test-app/AARCH64.ld @@ -0,0 +1,56 @@ +MEMORY +{ + DDR_MEM(rx) : ORIGIN = 0xa0000, LENGTH = 0x80000000 - 0xa0000 +} +ENTRY(main); + +SECTIONS +{ + .text : + { + _start_text = .; + KEEP(*(.boot*)) + *(.text*) + *(.rodata*) + *(.note.*) + . = ALIGN(4); + _end_text = .; + } > DDR_MEM + .edidx : + { + . = ALIGN(4); + *(.ARM.exidx*) + } > DDR_MEM + + .edidx : + { + . = ALIGN(4); + *(.ARM.exidx*) + } > DDR_MEM + + .data : + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(4); + KEEP(*(.ramcode)) + . = ALIGN(4); + _end_data = .; + } > DDR_MEM + + .bss (NOLOAD) : + { + _start_bss = .; + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _end_bss = .; + __bss_end__ = .; + _end = .; + } > DDR_MEM + . = ALIGN(4); +} + +END_STACK = _start_text; + diff --git a/test-app/app_raspi3.c b/test-app/app_raspi3.c new file mode 100644 index 000000000..427a177c8 --- /dev/null +++ b/test-app/app_raspi3.c @@ -0,0 +1,39 @@ +/* app_raspi3.c + * + * Test bare-metal boot application + * + * Copyright (C) 2020 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include +#include +#include + +#include "wolfboot/wolfboot.h" + +#ifdef PLATFORM_raspi3 + +volatile uint32_t time_elapsed = 0; +void __attribute__((section(".boot"))) main(void) { + + /* Wait for reboot */ + while(1) + ; +} +#endif /** PLATFORM_raspi3 **/ diff --git a/test-app/app_zynq.c b/test-app/app_zynq.c new file mode 100644 index 000000000..2d2df7d26 --- /dev/null +++ b/test-app/app_zynq.c @@ -0,0 +1,39 @@ +/* app_zynq.c + * + * Test bare-metal boot application + * + * Copyright (C) 2020 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include +#include +#include + +#include "wolfboot/wolfboot.h" + +#ifdef PLATFORM_zynq + +volatile uint32_t time_elapsed = 0; +void main(void) { + + /* Wait for reboot */ + while(1) + ; +} +#endif /** PLATFORM_zynq **/ diff --git a/tools/config.mk b/tools/config.mk index 872cec9cd..84db88615 100644 --- a/tools/config.mk +++ b/tools/config.mk @@ -16,6 +16,7 @@ ifeq ($(ARCH),) NO_ASM?=0 EXT_FLASH?=0 SPI_FLASH?=0 + NO_XIP?=0 ALLOW_DOWNGRADE?=0 NVM_FLASH_WRITEONCE?=0 WOLFBOOT_VERSION?=0 @@ -31,13 +32,18 @@ ifeq ($(ARCH),) WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x20000 WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x40000 WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x60000 + WOLFBOOT_DTS_BOOT_ADDRESS?=0x30000 + WOLFBOOT_DTS_UPDATE_ADDRESS=0x50000 + WOLFBOOT_LOAD_ADDRESS?=0x200000 + WOLFBOOT_LOAD_DTS_ADDRESS?=0x400000 endif CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO_DRIVERS \ MCUXPRESSO_CMSIS FREEDOM_E_SDK STM32CUBE DEBUG VTOR CORTEX_M0 NO_ASM EXT_FLASH \ - SPI_FLASH ALLOW_DOWNGRADE NVM_FLASH_WRITEONCE WOLFBOOT_VERSION V \ + SPI_FLASH NO_XIP ALLOW_DOWNGRADE NVM_FLASH_WRITEONCE WOLFBOOT_VERSION V \ SPMATH RAM_CODE DUALBANK_SWAP IMAGE_HEADER_SIZE PKA WOLFTPM \ WOLFBOOT_PARTITION_SIZE WOLFBOOT_SECTOR_SIZE \ WOLFBOOT_PARTITION_BOOT_ADDRESS WOLFBOOT_PARTITION_UPDATE_ADDRESS \ - WOLFBOOT_PARTITION_SWAP_ADDRESS + WOLFBOOT_PARTITION_SWAP_ADDRESS WOLFBOOT_LOAD_ADDRESS \ + WOLFBOOT_LOAD_DTS_ADDRESS diff --git a/tools/keytools/Makefile b/tools/keytools/Makefile new file mode 100644 index 000000000..14f1e2c09 --- /dev/null +++ b/tools/keytools/Makefile @@ -0,0 +1,52 @@ +# wolfBoot Signing Tool + +TARGET = sign +CC = gcc +WOLFDIR = ../../lib/wolfssl/ +CFLAGS = -Wall -I. -DWOLFSSL_USER_SETTINGS -I$(WOLFDIR) + +# option variables +DEBUG_FLAGS = -g -DDEBUG +OPTIMIZE = -Os + +# Options +#CFLAGS+=$(DEBUG_FLAGS) +CFLAGS+=$(OPTIMIZE) + +# Sources +SRC=sign.c \ + $(WOLFDIR)wolfcrypt/src/asn.c \ + $(WOLFDIR)wolfcrypt/src/ecc.c \ + $(WOLFDIR)wolfcrypt/src/coding.c \ + $(WOLFDIR)wolfcrypt/src/ed25519.c \ + $(WOLFDIR)wolfcrypt/src/fe_operations.c \ + $(WOLFDIR)wolfcrypt/src/ge_operations.c \ + $(WOLFDIR)wolfcrypt/src/hash.c \ + $(WOLFDIR)wolfcrypt/src/logging.c \ + $(WOLFDIR)wolfcrypt/src/memory.c \ + $(WOLFDIR)wolfcrypt/src/random.c \ + $(WOLFDIR)wolfcrypt/src/rsa.c \ + $(WOLFDIR)wolfcrypt/src/sp_int.c \ + $(WOLFDIR)wolfcrypt/src/sp_c32.c \ + $(WOLFDIR)wolfcrypt/src/sp_c64.c \ + $(WOLFDIR)wolfcrypt/src/sha3.c \ + $(WOLFDIR)wolfcrypt/src/sha256.c \ + $(WOLFDIR)wolfcrypt/src/sha512.c \ + $(WOLFDIR)wolfcrypt/src/tfm.c \ + $(WOLFDIR)wolfcrypt/src/wc_port.c \ + $(WOLFDIR)wolfcrypt/src/wolfmath.c + +.PHONY: clean all + +all: $(TARGET) + +debug: CFLAGS+=$(DEBUG_FLAGS) +debug: all + +# build template +$(TARGET): + @echo "Building C signing tool" + @$(CC) -o $(TARGET) $(SRC) $< $(CFLAGS) + +clean: + rm -f $(TARGET) diff --git a/tools/keytools/README.md b/tools/keytools/README.md new file mode 100644 index 000000000..30fee003c --- /dev/null +++ b/tools/keytools/README.md @@ -0,0 +1,3 @@ +# Signing Tool + +See documentation [here](../../docs/Signing.md). diff --git a/tools/keytools/keygen.py b/tools/keytools/keygen.py index 63199e14f..7825ff652 100755 --- a/tools/keytools/keygen.py +++ b/tools/keytools/keygen.py @@ -24,6 +24,17 @@ import sys,os from wolfcrypt import ciphers +def usage(): + print("Usage: %s [--ed25519 | --ecc256 | --rsa2048 | --rsa4096] [ --force ] pub_key_file.c\n" % sys.argv[0]) + parser.print_help() + sys.exit(1) + +def dupsign(): + print("") + print("Error: only one algorithm must be specified.") + print("") + usage() + Cfile_Banner="/* Public-key file for wolfBoot, automatically generated. Do not edit. */\n"+ \ "/*\n" + \ " * This file has been generated and contains the public key which is\n"+ \ @@ -38,21 +49,44 @@ sign="ed25519" -argc = len(sys.argv) -argv = sys.argv - -if (argc < 2) or (argc > 3): - print("Usage: %s [--ed25519 | --ecc256 | --rsa2048 | --rsa4096 ] pub_key_file.c\n" % sys.argv[0]) - sys.exit(1) +import argparse as ap + +parser = ap.ArgumentParser(prog='keygen.py', description='wolfBoot key generation tool') +parser.add_argument('--ed25519', dest='ed25519', action='store_true') +parser.add_argument('--ecc256', dest='ecc256', action='store_true') +parser.add_argument('--rsa2048', dest='rsa2048', action='store_true') +parser.add_argument('--rsa4096', dest='rsa4096', action='store_true') +parser.add_argument('--force', dest='force', action='store_true') +parser.add_argument('cfile') + +args=parser.parse_args() + +#print(args.ecc256) +#sys.exit(0) #test + +pubkey_cfile = args.cfile +sign=None +force=False +if (args.ed25519): + sign='ed25519' +if (args.ecc256): + if sign is not None: + dupsign() + sign='ecc256' +if (args.rsa2048): + if sign is not None: + dupsign() + sign='rsa2048' +if (args.rsa4096): + if sign is not None: + dupsign() + sign='rsa4096' + +if sign is None: + usage() + +force = args.force -if argc == 3: - if argv[1] != '--ed25519' and argv[1] != '--ecc256' and argv[1] != '--rsa2048' and argv[1] != '--rsa4096': - print("Usage: %s [--ed25519 | --ecc256 | --rsa2048 | --rsa4096] pub_key_file.c\n" % sys.argv[0]) - sys.exit(1) - sign=argv[1][2:] - pubkey_cfile = argv[2] -else: - pubkey_cfile = argv[1] if pubkey_cfile[-2:] != '.c': print("** Warning: generated public key cfile does not have a '.c' extension") @@ -62,11 +96,12 @@ print ("Selected cipher: " + sign) print ("Output Private key: " + key_file) print ("Output C file: " + pubkey_cfile) +print() if (sign == "ed25519"): ed = ciphers.Ed25519Private.make_key(32) priv,pub = ed.encode_key() - if os.path.exists(key_file): + if os.path.exists(key_file) and not force: choice = input("** Warning: key file already exist! Are you sure you want to "+ "generate a new key and overwrite the existing key? [Type 'Yes, I am sure!']: ") if (choice != "Yes, I am sure!"): @@ -97,7 +132,7 @@ if (sign == "ecc256"): ec = ciphers.EccPrivate.make_key(32) qx,qy,d = ec.encode_key_raw() - if os.path.exists(key_file): + if os.path.exists(key_file) and not force: choice = input("** Warning: key file already exist! Are you sure you want to "+ "generate a new key and overwrite the existing key? [Type 'Yes, I am sure!']: ") if (choice != "Yes, I am sure!"): @@ -133,7 +168,7 @@ if (sign == "rsa2048"): rsa = ciphers.RsaPrivate.make_key(2048) - if os.path.exists(key_file): + if os.path.exists(key_file) and not force: choice = input("** Warning: key file already exist! Are you sure you want to "+ "generate a new key and overwrite the existing key? [Type 'Yes, I am sure!']: ") if (choice != "Yes, I am sure!"): @@ -161,7 +196,7 @@ if (sign == "rsa4096"): rsa = ciphers.RsaPrivate.make_key(4096) - if os.path.exists(key_file): + if os.path.exists(key_file) and not force: choice = input("** Warning: key file already exist! Are you sure you want to "+ "generate a new key and overwrite the existing key? [Type 'Yes, I am sure!']: ") if (choice != "Yes, I am sure!"): diff --git a/tools/keytools/sign.c b/tools/keytools/sign.c new file mode 100755 index 000000000..38641616c --- /dev/null +++ b/tools/keytools/sign.c @@ -0,0 +1,650 @@ +/* sign.c + * + * C native signing tool + * + * + * Copyright (C) 2020 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* Option to enable sign tool debugging */ +/* Must also define DEBUG_WOLFSSL in user_settings.h */ +//#define DEBUG_SIGNTOOL + +#include +#ifndef NO_RSA + #include +#endif +#ifdef HAVE_ECC + #include +#endif +#ifdef HAVE_ED25519 + #include +#endif +#ifndef NO_SHA256 + #include +#endif +#ifdef WOLFSSL_SHA3 + #include +#endif +#include +#include +#ifdef DEBUG_SIGNTOOL + #include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 + #define PATH_MAX 256 +#endif + +#define WOLFBOOT_MAGIC 0x464C4F57 /* WOLF */ + +#define HDR_VERSION 0x01 +#define HDR_TIMESTAMP 0x02 +#define HDR_PUBKEY 0x10 +#define HDR_SIGNATURE 0x20 +#define HDR_IMG_TYPE 0x04 + +#define HDR_SHA256 0x03 +#define HDR_SHA3_384 0x13 + +#define HDR_SHA256_LEN 32 +#define HDR_SHA3_384_LEN 48 +#define HDR_VERSION_LEN 4 +#define HDR_TIMESTAMP_LEN 8 +#define HDR_IMG_TYPE_LEN 2 + +#define HDR_IMG_TYPE_AUTH_ED25519 0x0100 +#define HDR_IMG_TYPE_AUTH_ECC256 0x0200 +#define HDR_IMG_TYPE_AUTH_RSA2048 0x0300 +#define HDR_IMG_TYPE_AUTH_RSA4096 0x0400 +#define HDR_IMG_TYPE_WOLFBOOT 0x0000 +#define HDR_IMG_TYPE_APP 0x0001 + +#define HASH_SHA256 HDR_SHA256 +#define HASH_SHA3 HDR_SHA3_384 + +#define SIGN_AUTO 0 +#define SIGN_ED25519 HDR_IMG_TYPE_AUTH_ED25519 +#define SIGN_ECC256 HDR_IMG_TYPE_AUTH_ECC256 +#define SIGN_RSA2048 HDR_IMG_TYPE_AUTH_RSA2048 +#define SIGN_RSA4096 HDR_IMG_TYPE_AUTH_RSA4096 + +static void header_append_u32(uint8_t* header, uint32_t* idx, uint32_t tmp32) +{ + memcpy(&header[*idx], &tmp32, sizeof(tmp32)); + *idx += sizeof(tmp32); +} +static void header_append_u16(uint8_t* header, uint32_t* idx, uint16_t tmp16) +{ + memcpy(&header[*idx], &tmp16, sizeof(tmp16)); + *idx += sizeof(tmp16); +} +static void header_append_tag(uint8_t* header, uint32_t* idx, uint16_t tag, + uint16_t len, void* data) +{ + header_append_u16(header, idx, tag); + header_append_u16(header, idx, len); + memcpy(&header[*idx], data, len); + *idx += len; +} + +int main(int argc, char** argv) +{ + int ret = 0; + int i; + int self_update = 0; + int sha_only = 0; + int manual_sign = 0; + int hash_algo = HASH_SHA256; + int sign = SIGN_AUTO; + const char* image_file = NULL; + const char* key_file = NULL; + const char* fw_version = NULL; + const char* signature_file = NULL; + char output_image_file[PATH_MAX]; + char* tmpstr; + const char* sign_str = NULL; + const char* hash_str = NULL; + FILE *f, *f2; + uint8_t* key_buffer = NULL; + size_t key_buffer_sz = 0; + uint8_t* header = NULL; + uint32_t header_sz = 0; + uint32_t header_idx = 0; + uint8_t* signature = NULL; + uint32_t signature_sz = 0; + uint8_t* pubkey = NULL; + uint32_t pubkey_sz = 0; + size_t image_sz = 0; + uint8_t digest[48]; /* max digest */ + uint32_t digest_sz = 0; + uint8_t buf[1024]; + uint32_t idx, read_sz, pos; + uint16_t image_type; + uint32_t fw_version32; + struct stat attrib; + union { +#ifdef HAVE_ED25519 + ed25519_key ed; +#endif +#ifdef HAVE_ECC + ecc_key ecc; +#endif +#ifndef NO_RSA + RsaKey rsa; +#endif + } key; + WC_RNG rng; + +#ifdef DEBUG_SIGNTOOL + wolfSSL_Debugging_ON(); +#endif + + /* Check arguments and print usage */ + if (argc < 4 || argc > 8) { + printf("Usage: %s [--ed25519 | --ecc256 | --rsa2048 | --rsa4096 ] [--sha256 | --sha3] [--wolfboot-update] image key.der fw_version\n", argv[0]); + printf(" - or - "); + printf(" %s [--sha256 | --sha3] [--sha-only] [--wolfboot-update] image pub_key.der fw_version\n", argv[0]); + printf(" - or - "); + printf(" %s [--ed25519 | --ecc256 | --rsa2048 | --rsa4096 ] [--sha256 | --sha3] [--manual-sign] image pub_key.der fw_version signature.sig\n", argv[0]); + return 0; + } + + /* Parse Arguments */ + for (i=1; i 512) { + if (sign == SIGN_AUTO) { + sign = SIGN_RSA4096; + printf("rsa4096 key autodetected\n"); + } + } + else if (key_buffer_sz > 128) { + if (sign == SIGN_AUTO) { + sign = SIGN_RSA2048; + printf("rsa2048 key autodetected\n"); + } + if (sign != SIGN_RSA2048) { + printf("Error: key size too large for the selected cipher\n"); + goto exit; + } + } + else { + printf("Error: key size does not match any cipher\n"); + goto exit; + } + + /* get header and signature sizes */ + if (sign == SIGN_ED25519) { + header_sz = 256; + signature_sz = 64; + } + else if (sign == SIGN_ECC256) { + header_sz = 256; + signature_sz = 64; + } + else if (sign == SIGN_RSA2048) { + header_sz = 512; + signature_sz = 256; + } + else if (sign == SIGN_RSA4096) { + header_sz = 1024; + signature_sz = 512; + } + if (signature_sz == 0 || header_sz == 0) { + printf("Invalid hash or signature type!\n"); + goto exit; + } + + /* import (decode) private key for signing */ + if (!sha_only && !manual_sign) { + /* import (decode) private key for signing */ + if (sign == SIGN_ED25519) { + #ifdef HAVE_ED25519 + ret = wc_ed25519_init(&key.ed); + if (ret == 0) { + ret = wc_ed25519_import_private_only(key_buffer, key_buffer_sz, &key.ed); + if (ret == 0) { + ret = wc_ed25519_export_public(&key.ed, key_buffer, &pubkey_sz); + if (ret == 0) { + pubkey = key_buffer; + pubkey_sz = ED25519_PUB_KEY_SIZE; + } + } + } + #endif + } + else if (sign == SIGN_ECC256) { + #ifdef HAVE_ECC + ret = wc_ecc_init(&key.ecc); + if (ret == 0) { + ret = wc_ecc_import_unsigned(&key.ecc, &key_buffer[0], &key_buffer[32], + &key_buffer[64], ECC_SECP256R1); + if (ret == 0) { + pubkey = key_buffer; /* first 64 bytes is public porition */ + pubkey_sz = 64; + } + } + #endif + } + else if (sign == SIGN_RSA2048 || sign == SIGN_RSA4096) { + #ifndef NO_RSA + idx = 0; + ret = wc_InitRsaKey(&key.rsa, NULL); + if (ret == 0) { + ret = wc_RsaPrivateKeyDecode(key_buffer, &idx, &key.rsa, key_buffer_sz); + if (ret == 0) { + ret = wc_RsaKeyToPublicDer(&key.rsa, key_buffer, key_buffer_sz); + if (ret > 0) { + pubkey = key_buffer; + pubkey_sz = ret; + ret = 0; + } + } + } + #endif + } + if (ret != 0) { + printf("Error %d loading key\n", ret); + goto exit; + } + } + else { + /* using external key to sign, so only public portion is used */ + pubkey = key_buffer; + pubkey_sz = key_buffer_sz; + } +#ifdef DEBUG_SIGNTOOL + printf("Pubkey %d\n", pubkey_sz); + WOLFSSL_BUFFER(pubkey, pubkey_sz); +#endif + + /* Get size of image */ + f = fopen(image_file, "rb"); + if (f == NULL) { + printf("Open image file %s failed\n", image_file); + goto exit; + } + fseek(f, 0, SEEK_END); + image_sz = ftell(f); + fseek(f, 0, SEEK_SET); + fclose(f); + + header_idx = 0; + header = malloc(header_sz); + if (header == NULL) { + printf("Header malloc error!\n"); + goto exit; + } + memset(header, 0xFF, header_sz); + + /* Append Magic header (spells 'WOLF') */ + header_append_u32(header, &header_idx, WOLFBOOT_MAGIC); + /* Append Image size */ + header_append_u32(header, &header_idx, image_sz); + + /* No pad bytes, version is aligned */ + + /* Append Version field */ + fw_version32 = strtol(fw_version, NULL, 10); + header_append_tag(header, &header_idx, HDR_VERSION, HDR_VERSION_LEN, + &fw_version32); + + /* Append Four pad bytes, so timestamp is aligned */ + header_append_u32(header, &header_idx, 0xFFFFFFFF); + + /* Append Timestamp field */ + stat(image_file, &attrib); + header_append_tag(header, &header_idx, HDR_TIMESTAMP, HDR_TIMESTAMP_LEN, + &attrib.st_ctime); + + /* Append Image type field */ + image_type = (uint16_t)sign; + if (!self_update) + image_type |= HDR_IMG_TYPE_APP; + header_append_tag(header, &header_idx, HDR_IMG_TYPE, HDR_IMG_TYPE_LEN, + &image_type); + + /* Calculate hashes */ + if (hash_algo == HASH_SHA256) + { + #ifndef NO_SHA256 + wc_Sha256 sha; + + printf("Calculating SHA256 digest...\n"); + ret = wc_InitSha256_ex(&sha, NULL, INVALID_DEVID); + if (ret == 0) { + /* Hash Header */ + ret = wc_Sha256Update(&sha, header, header_idx); + + /* Hash image file */ + f = fopen(image_file, "rb"); + pos = 0; + while (ret == 0 && pos < image_sz) { + read_sz = image_sz - pos; + if (read_sz > 32) + read_sz = 32; + fread(buf, read_sz, 1, f); + ret = wc_Sha256Update(&sha, buf, read_sz); + pos += read_sz; + } + fclose(f); + if (ret == 0) + wc_Sha256Final(&sha, digest); + wc_Sha256Free(&sha); + } + + /* pubkey hash calculation */ + if (ret == 0) { + ret = wc_InitSha256_ex(&sha, NULL, INVALID_DEVID); + if (ret == 0) { + ret = wc_Sha256Update(&sha, pubkey, pubkey_sz); + if (ret == 0) + wc_Sha256Final(&sha, buf); + wc_Sha256Free(&sha); + } + } + if (ret == 0) + digest_sz = HDR_SHA256_LEN; + #endif + } + else if (hash_algo == HASH_SHA3) + { + #ifdef WOLFSSL_SHA3 + wc_Sha3 sha; + + printf("Calculating SHA3 digest...\n"); + + ret = wc_InitSha3_384(&sha, NULL, INVALID_DEVID); + if (ret == 0) { + /* Hash Header */ + ret = wc_Sha3_384_Update(&sha, header, header_idx); + + /* Hash image file */ + f = fopen(image_file, "rb"); + pos = 0; + while (ret == 0 && pos < image_sz) { + read_sz = image_sz - pos; + if (read_sz > 128) + read_sz = 128; + fread(buf, read_sz, 1, f); + ret = wc_Sha3_384_Update(&sha, buf, read_sz); + pos += read_sz; + } + fclose(f); + if (ret == 0) + ret = wc_Sha3_384_Final(&sha, digest); + wc_Sha3_384_Free(&sha); + } + + /* pubkey hash calculation */ + if (ret == 0) { + ret = wc_InitSha3_384(&sha, NULL, INVALID_DEVID); + if (ret == 0) { + ret = wc_Sha3_384_Update(&sha, pubkey, pubkey_sz); + if (ret == 0) + ret = wc_Sha3_384_Final(&sha, buf); + wc_Sha3_384_Free(&sha); + } + } + if (ret == 0) + digest_sz = HDR_SHA3_384_LEN; + #endif + } + if (digest_sz == 0) { + printf("Hash algorithm error %d\n", ret); + goto exit; + } +#ifdef DEBUG_SIGNTOOL + printf("Image hash %d\n", digest_sz); + WOLFSSL_BUFFER(digest, digest_sz); + printf("Pubkey hash %d\n", digest_sz); + WOLFSSL_BUFFER(buf, digest_sz); +#endif + + /* Add image hash to header */ + header_append_tag(header, &header_idx, hash_algo, digest_sz, digest); + + /* Add Pubkey Hash to header */ + header_append_tag(header, &header_idx, HDR_PUBKEY, digest_sz, buf); + + /* If hash only, then save digest and exit */ + if (sha_only) { + f = fopen(output_image_file, "wb"); + if (f == NULL) { + printf("Open output file %s failed\n", output_image_file); + goto exit; + } + fwrite(digest, digest_sz, 1, f); + fclose(f); + printf("Digest image %s successfully created.\n", output_image_file); + ret = 0; + goto exit; + } + + /* Sign the digest */ + ret = NOT_COMPILED_IN; /* default erorr */ + signature = malloc(signature_sz); + if (signature == NULL) { + printf("Signature malloc error!\n"); + goto exit; + } + memset(signature, 0, signature_sz); + if (!manual_sign) { + printf("Signing the firmware...\n"); + + wc_InitRng(&rng); + if (sign == SIGN_ED25519) { + #ifdef HAVE_ED25519 + ret = wc_ed25519_sign_msg(digest, digest_sz, signature, &signature_sz, &key.ed); + #endif + } + else if (sign == SIGN_ECC256) { + #ifdef HAVE_ECC + mp_int r, s; + mp_init(&r); mp_init(&s); + ret = wc_ecc_sign_hash_ex(digest, digest_sz, &rng, &key.ecc, &r, &s); + mp_to_unsigned_bin(&r, &signature[0]); + mp_to_unsigned_bin(&s, &signature[32]); + mp_clear(&r); mp_clear(&s); + wc_ecc_free(&key.ecc); + #endif + } + else if (sign == SIGN_RSA2048 || sign == SIGN_RSA4096) { + #ifndef NO_RSA + ret = wc_RsaSSL_Sign(digest, digest_sz, signature, signature_sz, &key.rsa, &rng); + wc_FreeRsaKey(&key.rsa); + if (ret > 0) { + signature_sz = ret; + ret = 0; + } + #endif + } + wc_FreeRng(&rng); + + if (ret != 0) { + printf("Signing error %d\n", ret); + goto exit; + } + } + else { + printf("Opening signature file %s\n", signature_file); + + f = fopen(signature_file, "rb"); + if (f == NULL) { + printf("Open signature file %s failed\n", signature_file); + goto exit; + } + fread(signature, signature_sz, 1, f); + fclose(f); + } +#ifdef DEBUG_SIGNTOOL + printf("Signature %d\n", signature_sz); + WOLFSSL_BUFFER(signature, signature_sz); +#endif + + /* Add signature to header */ + header_append_tag(header, &header_idx, HDR_SIGNATURE, signature_sz, signature); + + /* Add padded header at end */ + while (header_idx < header_sz) { + header[header_idx++] = 0xFF; + } + + /* Create output image */ + f = fopen(output_image_file, "wb"); + if (f == NULL) { + printf("Open output image file %s failed\n", output_image_file); + goto exit; + } + fwrite(header, header_idx, 1, f); + + /* Copy image to output */ + f2 = fopen(image_file, "rb"); + pos = 0; + while (pos < image_sz) { + read_sz = image_sz; + if (read_sz > sizeof(buf)) + read_sz = sizeof(buf); + fread(buf, read_sz, 1, f2); + fwrite(buf, read_sz, 1, f); + pos += read_sz; + } + fclose(f2); + fclose(f); + + printf("Output image successfully created.\n"); + ret = 0; + +exit: + if (header) + free(header); + if (key_buffer) + free(key_buffer); + if (signature) + free(signature); + + return ret; +} diff --git a/tools/keytools/sign.py b/tools/keytools/sign.py index 95e41aba9..82c4fecf6 100755 --- a/tools/keytools/sign.py +++ b/tools/keytools/sign.py @@ -56,13 +56,20 @@ sign="auto" self_update=False +sha_only=False +manual_sign=False + argc = len(sys.argv) argv = sys.argv hash_algo='sha256' -if (argc < 4) or (argc > 7): +if (argc < 4) or (argc > 8): print("Usage: %s [--ed25519 | --ecc256 | --rsa2048 | --rsa4096 ] [--sha256 | --sha3] [--wolfboot-update] image key.der fw_version\n" % sys.argv[0]) + print(" - or - ") + print(" %s [--sha256 | --sha3] [--sha-only] [--wolfboot-update] image pub_key.der fw_version\n" % sys.argv[0]) + print(" - or - ") + print(" %s [--ed25519 | --ecc256 | --rsa2048 | --rsa4096 ] [--sha256 | --sha3] [--manual-sign] image pub_key.der fw_version signature.sig\n" % sys.argv[0]) sys.exit(1) for i in range(1, len(argv)): if (argv[i] == '--ed25519'): @@ -79,6 +86,11 @@ hash_algo='sha3' elif (argv[i] == '--wolfboot-update'): self_update = True + elif (argv[i] == '--sha-only'): + sha_only = True + elif (argv[i] == '--manual-sign'): + manual_sign = True + else: i-=1 break @@ -87,46 +99,60 @@ key_file = argv[i+2] fw_version = int(argv[i+3]) -if '.' in image_file: - tokens = image_file.split('.') - output_image_file = image_file.rstrip('.' + tokens[-1]) - output_image_file += "_v" + str(fw_version) + "_signed.bin" +if manual_sign: + signature_file = argv[i+4] + +if not sha_only: + if '.' in image_file: + tokens = image_file.split('.') + output_image_file = image_file.rstrip('.' + tokens[-1]) + output_image_file += "_v" + str(fw_version) + "_signed.bin" + else: + output_image_file = image_file + "_v" + str(fw_version) + "_signed.bin" else: - output_image_file = image_file + "_v" + str(fw_version) + "_signed.bin" + if '.' in image_file: + tokens = image_file.split('.') + output_image_file = image_file.rstrip('.' + tokens[-1]) + output_image_file += "_v" + str(fw_version) + "_digest.bin" + else: + output_image_file = image_file + "_v" + str(fw_version) + "_digest.bin" if (self_update): print("Update type: wolfBoot") else: print("Update type: Firmware") -print ("Selected cipher: " + sign) -print ("Private key: " + key_file) print ("Input image: " + image_file) -print ("Output image: " + output_image_file) +print ("Selected cipher: " + sign) +print ("Public key: " + key_file) + +if not sha_only: + print ("Output image: " + output_image_file) +else: + print ("Output digest: " + output_image_file) -''' import (decode) private key for signing ''' kf = open(key_file, "rb") -wolfboot_private_key = kf.read(4096) -wolfboot_private_key_len = len(wolfboot_private_key) -if wolfboot_private_key_len == 64: +wolfboot_key_buffer = kf.read(4096) +wolfboot_key_buffer_len = len(wolfboot_key_buffer) +if wolfboot_key_buffer_len == 64: if (sign == 'ecc256'): print("Error: key size does not match the cipher selected") sys.exit(1) if sign == 'auto': sign = 'ed25519' print("'ed25519' key autodetected.") -elif wolfboot_private_key_len == 96: +elif wolfboot_key_buffer_len == 96: if (sign == 'ed25519'): print("Error: key size does not match the cipher selected") sys.exit(1) if sign == 'auto': sign = 'ecc256' print("'ecc256' key autodetected.") -elif (wolfboot_private_key_len > 512): +elif (wolfboot_key_buffer_len > 512): if (sign == 'auto'): print("'rsa4096' key autodetected.") -elif (wolfboot_private_key_len > 128): +elif (wolfboot_key_buffer_len > 128): if (sign == 'auto'): print("'rsa2048' key autodetected.") elif (sign != 'rsa2048'): @@ -136,26 +162,38 @@ sys.exit(2) -if sign == 'ed25519': - ed = ciphers.Ed25519Private(key = wolfboot_private_key) - privkey, pubkey = ed.encode_key() +if not sha_only and not manual_sign: + ''' import (decode) private key for signing ''' + if sign == 'ed25519': + ed = ciphers.Ed25519Private(key = wolfboot_key_buffer) + privkey, pubkey = ed.encode_key() -if sign == 'ecc256': - ecc = ciphers.EccPrivate() - ecc.decode_key_raw(wolfboot_private_key[0:31], wolfboot_private_key[32:63], wolfboot_private_key[64:]) - pubkey = wolfboot_private_key[0:64] + if sign == 'ecc256': + ecc = ciphers.EccPrivate() + ecc.decode_key_raw(wolfboot_key_buffer[0:31], wolfboot_key_buffer[32:63], wolfboot_key_buffer[64:]) + pubkey = wolfboot_key_buffer[0:64] -if sign == 'rsa2048': - WOLFBOOT_HEADER_SIZE = 512 - HDR_SIGNATURE_LEN = 256 - rsa = ciphers.RsaPrivate(wolfboot_private_key) - privkey,pubkey = rsa.encode_key() + if sign == 'rsa2048': + WOLFBOOT_HEADER_SIZE = 512 + HDR_SIGNATURE_LEN = 256 + rsa = ciphers.RsaPrivate(wolfboot_key_buffer) + privkey,pubkey = rsa.encode_key() + + if sign == 'rsa4096': + WOLFBOOT_HEADER_SIZE = 1024 + HDR_SIGNATURE_LEN = 512 + rsa = ciphers.RsaPrivate(wolfboot_key_buffer) + privkey,pubkey = rsa.encode_key() + +else: + if sign == 'rsa2048': + WOLFBOOT_HEADER_SIZE = 512 + HDR_SIGNATURE_LEN = 256 + if sign == 'rsa4096': + WOLFBOOT_HEADER_SIZE = 1024 + HDR_SIGNATURE_LEN = 512 -if sign == 'rsa4096': - WOLFBOOT_HEADER_SIZE = 1024 - HDR_SIGNATURE_LEN = 512 - rsa = ciphers.RsaPrivate(wolfboot_private_key) - privkey,pubkey = rsa.encode_key() + pubkey = wolfboot_key_buffer img_size = os.path.getsize(image_file) @@ -194,6 +232,11 @@ header += struct.pack(' + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {0E5B9C81-CA2B-47CA-BA83-074078CF3393} + Win32Proj + wolfBootSignTool + 10.0.17763.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + sign + + + true + sign + + + false + sign + + + false + sign + + + + + + Level3 + Disabled + WIN32;WOLFSSL_USER_SETTINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\..\lib\wolfssl;.;%(AdditionalIncludeDirectories) + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions);WOLFSSL_USER_SETTINGS + .;../../lib/wolfssl;%(AdditionalIncludeDirectories) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;WOLFSSL_USER_SETTINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\..\lib\wolfssl;.;%(AdditionalIncludeDirectories) + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions);WOLFSSL_USER_SETTINGS + .;../../lib/wolfssl;%(AdditionalIncludeDirectories) + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file