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