Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/test-configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,38 @@ jobs:
config-file: ./config/examples/imx8mm-pico.config
make-args: IMX8MM_BL33=1 DISK_EMMC=0 IMX8MM_MMU=0 wolfboot.bin test-app/image_v1_signed.bin

s32g2_test:
uses: ./.github/workflows/test-build-aarch64.yml
with:
arch: aarch64
# Boot ROM image in SRAM, signed FIT from the SD card.
config-file: ./config/examples/s32g2-goldbox.config
make-args: wolfboot.bin

s32g2_emmc_test:
uses: ./.github/workflows/test-build-aarch64.yml
with:
arch: aarch64
# FIT from the eMMC behind the board's SW3, no console.
config-file: ./config/examples/s32g2-goldbox.config
make-args: DISK_EMMC=1 DISK_SDCARD=0 DEBUG_UART=0 wolfboot.bin

s32g2_qspi_test:
uses: ./.github/workflows/test-build-aarch64.yml
with:
arch: aarch64
# Boot from the QuadSPI NOR with the A/B partitions in the NOR.
config-file: ./config/examples/s32g2-goldbox-qspi.config
make-args: wolfboot.bin

s32g2_qspi_program_test:
uses: ./.github/workflows/test-build-aarch64.yml
with:
arch: aarch64
# NOR programmer build: image file from the SD card to the NOR.
config-file: ./config/examples/s32g2-goldbox.config
make-args: S32G2_QSPI=1 S32G2_QSPI_PROGRAM_FILE=/s32g2_qspi_boot.bin wolfboot.bin

disk_boot_confirm_test:
uses: ./.github/workflows/test-build-aarch64.yml
with:
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -694,3 +694,9 @@ tools/unit-tests/stm32wb_write_extract.h
tools/unit-tests/t10xx_flash_status_extract.h
tools/unit-tests/ti_hercules_erase_extract.h
tools/unit-tests/versal_host_write.c
# S32G2 GoldBox FIT build outputs (tools/scripts/s32g2/s32g2-mkfit.sh)
Image.gz
s32g2-fitImage*
boot.scr
s32g2.dtb
s32g2_ddr.bin
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,11 @@ ifeq ($(TARGET),imx8mm)
MAIN_TARGET:=wolfboot.bin test-app/image_v1_signed.bin
endif

# S32G2 runs from SRAM and boots a signed FIT; there is no factory.bin.
ifeq ($(TARGET),s32g2)
MAIN_TARGET:=wolfboot.bin
endif

# i.MX95 M7 runs from ITCM (loaded by the Linux remoteproc driver); the payload
# lives in DDR at 0x80100000, so there is no contiguous flash image to assemble.
ifeq ($(TARGET),imx95_m7)
Expand Down
48 changes: 48 additions & 0 deletions arch.mk
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,54 @@ ifeq ($(ARCH),AARCH64)
endif
endif

ifeq ($(TARGET),s32g2)
# NXP S32G274A GoldBox: wolfBoot is the Boot ROM's application image,
# copied into SRAM and entered at EL3. It runs its own identity MMU there
# and tears it down at the handoff with the stack-free flush routine.
ARCH_FLAGS=-mcpu=cortex-a53+crypto -march=armv8-a+crypto -mstrict-align
CFLAGS+=$(ARCH_FLAGS) -DCORTEX_A53
CFLAGS+=-DWOLFBOOT_AARCH64_MMU_TEARDOWN
# The RVBAR write in the full startup path is a ZynqMP register.
CFLAGS+=-DSKIP_RVBAR=1
WOLFBOOT_ORIGIN=0x340A0000
OBJS+=hal/s32g2_ddr.o
# wolfBoot adds /memory and the spin-table addresses to the FIT's DTB,
# which needs more room than the default headroom.
CFLAGS+=-DWOLFBOOT_FDT_FIXUP_HEADROOM=4096
# LPDDR4 register tables and PHY training firmware, generated by
# tools/scripts/s32g2/s32g2-ddr-blob.py. Without the file the image
# still builds, and reports the missing blob instead of training.
S32G2_DDR_BLOB ?= s32g2_ddr.bin
ifneq ($(wildcard $(S32G2_DDR_BLOB)),)
CFLAGS+=-DS32G2_DDR_BLOB='"$(abspath $(S32G2_DDR_BLOB))"'
endif
# uSDHC0 board facts. Here rather than in the config because a command-line
# CFLAGS_EXTRA= would replace the config's, whereas CFLAGS is additive.
ifneq ($(filter 1,$(DISK_SDCARD) $(DISK_EMMC)),)
# uSDHC -> SDHCI shim, shared with the i.MX 8 targets
OBJS+=hal/imx_usdhc_sdhci.o
# Card detect is a GPIO, so PRES_STATE bit 16 never sets.
CFLAGS+=-DSDHCI_FORCE_CARD_DETECT
# Read the payload in 64 KB chunks rather than the 512-byte default.
DISK_BLOCK_SIZE ?= 65536
CFLAGS+=-DDISK_BLOCK_SIZE=$(DISK_BLOCK_SIZE)
# The slot is 3.3 V only (no-1-8-v).
S32G2_USDHC_MAX_CLK_KHZ ?= 25000
CFLAGS+=-DS32G2_USDHC_MAX_CLK_KHZ=$(S32G2_USDHC_MAX_CLK_KHZ)
endif
# QuadSPI NOR driver (the ext_flash API with EXT_FLASH=1)
ifeq ($(S32G2_QSPI),1)
CFLAGS+=-DS32G2_QSPI
# NOR programmer build: writes the named file from the SD/eMMC FAT
# partition to the NOR at S32G2_QSPI_PROGRAM_OFFSET, then halts.
ifneq ($(S32G2_QSPI_PROGRAM_FILE),)
S32G2_QSPI_PROGRAM_OFFSET ?= 0
CFLAGS+=-DS32G2_QSPI_PROGRAM_FILE='"$(S32G2_QSPI_PROGRAM_FILE)"'
CFLAGS+=-DS32G2_QSPI_PROGRAM_OFFSET=$(S32G2_QSPI_PROGRAM_OFFSET)
endif
endif
endif

ifeq ($(TARGET),imx8mm)
# uSDHC -> SDHCI shim, shared with imx8qm
ifneq ($(filter 1,$(DISK_SDCARD) $(DISK_EMMC)),)
Expand Down
40 changes: 40 additions & 0 deletions config/examples/s32g2-goldbox-qspi.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# NXP S32G2 GoldBox (S32G-VNP-GLDBOX, S32G274A-RDB2) - wolfBoot as the Boot
# ROM's application image booting from the 64 MB QuadSPI NOR, with the A/B
# image partitions in the same NOR and the signed FIT loaded into DDR. No SD
# card is needed (DISK_SDCARD=0).
#
# NOR layout: wolfBoot at 0 (IVT, ROM QSPI parameters, code), BOOT partition
# at 1 MB, UPDATE at 17 MB, SWAP sector at 33 MB; 4 KB erase sectors.
# tools/scripts/s32g2/s32g2_mkimage.py wolfboot.bin s32g2_qspi_boot.bin --qspi
# The NOR is written by a programmer build of the SD config
# (S32G2_QSPI=1 S32G2_QSPI_PROGRAM_FILE=/<file>); the board must be strapped
# for QuadSPI boot.
# See docs/Targets.md.
#
# Never pass CFLAGS_EXTRA= on the command line - it replaces, not appends.
ARCH=AARCH64
TARGET=s32g2
S32G2_QSPI=1
SIGN?=ECC384
HASH?=SHA384
DEBUG?=1
DEBUG_UART?=1
SPMATH?=1
NO_XIP?=1
EXT_FLASH?=1
SKIP_GIC_INIT?=1
GZIP?=1
DISK_SDCARD?=0
WOLFBOOT_SECTOR_SIZE?=0x1000
WOLFBOOT_PARTITION_SIZE?=0x1000000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x100000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x1100000
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x2100000
# Separate DTB partitions are not used (the FIT carries the DTB) but the
# RAM-boot flow needs them defined; they sit after the swap sector.
WOLFBOOT_DTS_BOOT_ADDRESS?=0x2110000
WOLFBOOT_DTS_UPDATE_ADDRESS?=0x2120000

WOLFBOOT_RAMBOOT_MAX_SIZE=0x4000000
WOLFBOOT_LOAD_ADDRESS?=0xA0000000
WOLFBOOT_LOAD_DTS_ADDRESS?=0xA5000000
41 changes: 41 additions & 0 deletions config/examples/s32g2-goldbox.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# NXP S32G2 GoldBox (S32G-VNP-GLDBOX, S32G274A-RDB2) - wolfBoot as the Boot
# ROM's application image: copied into SRAM at 0x340A0000 and entered at EL3
# with only FIRC running, in place of U-Boot. The signed FIT (kernel + DTB,
# hal/s32g2.its) is read from a FAT32 partition of the SD card, or of the
# eMMC with DISK_EMMC=1 DISK_SDCARD=0.
#
# The LPDDR4 tables and PHY firmware come from the NXP BSP U-Boot sources:
# tools/scripts/s32g2/s32g2-ddr-blob.py <nxp-u-boot> s32g2_ddr.bin
# Wrap wolfboot.bin for the Boot ROM and write it at SD byte offset 0x1000:
# tools/scripts/s32g2/s32g2_mkimage.py wolfboot.bin s32g2_boot.bin
# dd if=s32g2_boot.bin of=/dev/sdX bs=512 seek=8
# See docs/Targets.md.
#
# Never pass CFLAGS_EXTRA= on the command line - it replaces, not appends.
ARCH=AARCH64
TARGET=s32g2
SIGN?=ECC384
HASH?=SHA384
DEBUG?=1
DEBUG_UART?=1
SPMATH?=1
NO_XIP?=1
SKIP_GIC_INIT?=1
WOLFBOOT_SECTOR_SIZE?=0x1000
WOLFBOOT_NO_PARTITIONS=1
GZIP?=1
WOLFBOOT_PARTITION_SIZE?=0x100000
DISK_SDCARD?=1
DISK_FS?=fat32

# A/B slots: two files on the third partition (FAT32). The higher version
# boots. An older version is not used when the newer one fails to verify
# (anti-rollback), unless built with ALLOW_DOWNGRADE=1.
CFLAGS_EXTRA+=-DBOOT_PART_A=2
CFLAGS_EXTRA+=-DBOOT_PART_B=2
CFLAGS_EXTRA+=-DBOOT_FILE_A='"/fitImage_a.bin"'
CFLAGS_EXTRA+=-DBOOT_FILE_B='"/fitImage_b.bin"'

WOLFBOOT_RAMBOOT_MAX_SIZE=0x4000000
WOLFBOOT_LOAD_ADDRESS?=0xA0000000
WOLFBOOT_LOAD_DTS_ADDRESS?=0xA5000000
122 changes: 122 additions & 0 deletions docs/Targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ This README describes configuration of supported targets.
* [Nordic nRF54LM20](#nordic-nrf54lm20)
* [NXP i.MX 8M Mini](#nxp-imx-8m-mini)
* [NXP i.MX 8QuadMax](#nxp-imx-8quadmax)
* [NXP S32G2 (S32G274A GoldBox)](#nxp-s32g2-s32g274a-goldbox)
* [NXP i.MX95 Cortex-M7](#nxp-imx95-cortex-m7)
* [NXP i.MX95 Cortex-A55 (BL33)](#nxp-imx95-cortex-a55-bl33)
* [NXP iMX-RT](#nxp-imx-rt)
Expand Down Expand Up @@ -10438,6 +10439,127 @@ Register bases used by the HAL, from the upstream device tree (`imx8-ss-{lsio,co

`-DDEBUG_SDHCI -DDEBUG_DISK -DDEBUG_GPT` add command-level tracing to the storage paths, and `-DDEBUG_FS` traces the filesystem layer when `DISK_FS` is enabled.

## NXP S32G2 (S32G274A GoldBox)

wolfBoot runs on the NXP S32G274A (4x Cortex-A53 + 3x Cortex-M7 lock-step pairs) as the Boot ROM's application image, in place of U-Boot: the ROM copies it into the 8 MB system SRAM at 0x340A0000 and enters it at EL3 with only the 48 MHz FIRC running. wolfBoot brings the SoC up, verifies a signed FIT (kernel plus device tree) and enters Linux at EL2. Developed against the S32G-VNP-GLDBOX, which is an S32G274A-RDB2 in an enclosure.

```
Boot ROM -> wolfBoot in SRAM (EL3) -> signed FIT from SD, eMMC or QuadSPI NOR -> Linux (EL2)
```

### Example configurations

| Config | Boot ROM loads wolfBoot from | Signed FIT from |
|---|---|---|
| [/config/examples/s32g2-goldbox.config](/config/examples/s32g2-goldbox.config) | SD card (or eMMC) | FAT32 partition of the SD card; of the eMMC with `DISK_EMMC=1 DISK_SDCARD=0` |
| [/config/examples/s32g2-goldbox-qspi.config](/config/examples/s32g2-goldbox-qspi.config) | QuadSPI NOR | BOOT / UPDATE partitions in the same NOR |

Both use `SIGN=ECC384 HASH=SHA384`. The disk config has two file slots on the third partition, `/fitImage_a.bin` and `/fitImage_b.bin`: the higher version boots. With wolfBoot's anti-rollback default an older version is not booted when the newer one fails to verify; that needs `ALLOW_DOWNGRADE=1`. The NOR config has BOOT at 1 MB, UPDATE at 17 MB and a 4 KB SWAP sector at 33 MB, with the FIT read into DDR through the `ext_flash` API.

### LPDDR4 data blob

wolfBoot trains the LPDDR4 itself ([/hal/s32g2_ddr.c](/hal/s32g2_ddr.c)) but does not carry the board's controller and PHY register tables or the Synopsys PHY training firmware. NXP publishes both in the BSP U-Boot tree, and [/tools/scripts/s32g2/s32g2-ddr-blob.py](/tools/scripts/s32g2/s32g2-ddr-blob.py) packs them into the binary the build links in:

```
git clone -b release/bsp29.0-2020.04 https://github.com/nxp-auto-linux/u-boot.git
tools/scripts/s32g2/s32g2-ddr-blob.py u-boot s32g2_ddr.bin
```

`S32G2_DDR_BLOB` names the file (default `s32g2_ddr.bin` in the wolfBoot root). Without it the image still builds, and reports the missing blob on the console instead of training. The blob is checked by magic, version and CRC before use. Inline ECC is not supported.

### Building

```
cp config/examples/s32g2-goldbox.config .config
make
tools/scripts/s32g2/s32g2_mkimage.py wolfboot.bin s32g2_boot.bin
dd if=/dev/sdX bs=512 count=8192 of=sd_raw_backup.bin # keep the stock boot area
dd if=s32g2_boot.bin of=/dev/sdX bs=512 seek=8 conv=fsync # IVT at byte 0x1000
tools/scripts/s32g2/s32g2-mkfit.sh Image 1 wolfboot_signing_private_key.der fsl-s32g274a-rdb2.dtb
mcopy -i /dev/sdX3 s32g2-fitImage_v1_signed.bin ::/fitImage_a.bin
```

[/tools/scripts/s32g2/s32g2_mkimage.py](/tools/scripts/s32g2/s32g2_mkimage.py) writes the IVT (tag 0xD1), a no-op DCD and the application boot code header (tag 0xD5) in the stock BSP's layout. The card must stay MBR: the IVT sits where GPT entries would be. Restoring the backup puts the stock chain back. The stock card's first partition is FAT16, which wolfBoot does not read, so the FIT goes on an added FAT32 partition (`mkfs.vfat -F 32 -s 8`).

`s32g2-mkfit.sh` builds the FIT from [/hal/s32g2.its](/hal/s32g2.its): the gzip-compressed kernel, loaded at 0x84080000 (2 MB-aligned base plus the image's text offset), and the board DTB, both under the wolfBoot signature.

### What wolfBoot does before the FIT

In this order, in [/hal/s32g2.c](/hal/s32g2.c) and the S32G2 block of [/src/boot_aarch64_start.S](/src/boot_aarch64_start.S):

- ECC-initialises `.bss`, the stack and the spin-table page through SRAM controller 0. The ROM only initialises the bytes it copies, and the controller works in 512-byte granules, so `.data` ends on a granule boundary.
- Routes the UART0 pads and programs LINFlexD_0.
- Services the VR5510 PMIC over I2C4: fail-safe watchdog and FCCU monitoring off. Unserviced, the PMIC power-cycles the board about a second after power-up, and on any clock change.
- Clock tree: FXOSC, ARM PLL (A53 at 1 GHz), XBAR 800 MHz, PERIPH PLL (LINFlexD 125 MHz, uSDHC 400 MHz, QuadSPI), DDR PLL 800 MHz.
- Ncore coherent interconnect, then an identity MMU at EL3 with the caches on: SRAM Normal, peripherals and the QuadSPI window Device. Cluster 1's interconnect port only joins when its cores are released, since a port admitted with its cores in reset stalls the barrier after a TLB invalidate.
- LPDDR4 training (1D and 2D), a read-back check through a Device mapping, then DRAM mapped Normal.
- MSCM interrupt routing, GICv3 distributor and redistributors, and the three secondary cores released through MC_ME and parked at EL2 on a spin table at 0x34000000.
- uSDHC and QuadSPI pads, whichever medium holds the FIT, as the OS expects them routed.

`hal_dts_fixup` adds the `/memory` node for both DRAM banks, each core's `enable-method = "spin-table"` and `cpu-release-addr`, the bootargs, and clears `linux,initrd-start/end` (the stock DTB's range overlaps the kernel). The handoff flushes the caches, turns the MMU off and enters the kernel at EL2 with `SCR_EL3` leaving IRQ and FIQ to EL2. EL3 exception vectors report ESR, ELR and FAR on the console.

### QuadSPI NOR

`S32G2_QSPI=1` builds the driver for the QuadSPI controller at 0x40134000 and the GoldBox's 64 MB Macronix MX25UW51245G. The flash runs in plain SPI mode with 4-byte addresses: single commands are IP commands described by a LUT sequence (page program 0x12, 4 KB sector erase 0x21), bulk reads go through the memory-mapped AHB window (fast read 0x0C), the DLL slave is bypassed and data is sampled from the internal DQS loopback. The serial clock comes from PERIPH DFS1 through MC_CGM0 mux 12 (`S32G2_QSPI_2X_DIV`, 8 = 50 MHz). If the Boot ROM left the flash in octal DTR mode, the init resets it to SPI mode with the two-byte OPI reset commands.

```
cp config/examples/s32g2-goldbox-qspi.config .config
make
tools/scripts/s32g2/s32g2_mkimage.py wolfboot.bin s32g2_qspi_boot.bin --qspi
```

`--qspi` lays the image out for QuadSPI boot: the IVT at flash offset 0, the 0x200-byte QuadSPI parameter block the ROM programs the controller with at 0x200 (`sdr`, the default, reads in plain SPI mode with no mode switch; `--qspi-params octal` is the stock BSP block that moves the flash to octal DTR), the DCD and the application. Strap the RDB2 for QuadSPI boot with SW4 all OFF, SW9 OFF, SW10 1 ON / 2 OFF.

The NOR is written by a programmer build of the SD config: it reads the named file from the FAT32 partition into DDR, erases, programs and reads it back, then halts. Boot it from the SD card once per image:

```
cp config/examples/s32g2-goldbox.config .config
make S32G2_QSPI=1 S32G2_QSPI_PROGRAM_FILE=/s32g2_qspi_boot.bin # wolfBoot at 0
make S32G2_QSPI=1 S32G2_QSPI_PROGRAM_FILE=/fitImage_a.bin S32G2_QSPI_PROGRAM_OFFSET=0x100000 # FIT in BOOT
```

### eMMC

The GoldBox routes uSDHC0 either to the microSD slot or to the on-board 32 GB eMMC with the RDB2's SW3 (ON = microSD, OFF = eMMC). `make DISK_EMMC=1 DISK_SDCARD=0` drives the eMMC through the same uSDHC shim. The factory eMMC carries the BSP image (FAT16 boot partition, ext3 rootfs), so a FAT32 partition is appended from the board's Linux (`sfdisk --append`, `mkfs.vfat -F 32 -s 8`) for the FIT files. With wolfBoot in the NOR and SW3 OFF the box boots with no card inserted.

### Hardware setup (GoldBox)

- Console: UART0 micro-USB (FTDI FT232R), LINFlexD_0, 115200 8N1. The second micro-USB is UART1 and prints nothing.
- Boot source switches on the RDB2: SD boot is SW4 position 7 ON only; QuadSPI boot is SW4 all OFF; SW9 OFF and SW10 1 ON / 2 OFF for both.
- Expected console, booting from the SD card:

```
wolfBoot S32G2 (EL3, running from SRAM)
s32g2: VR5510 watchdog disabled
s32g2: A53 1000 MHz, XBAR_2X 800 MHz, LIN 125 MHz, ...
s32g2: MMU on at EL3, caches enabled
DDR: 1D training
DDR: 2D training
s32g2: DDR up, 4096 MB, erratum polling 0
s32g2: core 1 parked
p2: fat32, /fitImage_a.bin
Firmware Valid.
FDT: memory and spin-table set
```

### Peripheral map

| Block | Base | Notes |
|---|---|---|
| LINFlexD_0 | 0x401C8000 | FIFO mode; TX pin PC09 (MSCR41), RX PC10 (MSCR42, IMCR512) |
| uSDHC0 | 0x402F0000 | i.MX uSDHC v3, shared shim [/hal/imx_usdhc_sdhci.c](/hal/imx_usdhc_sdhci.c), per clock 400 MHz |
| QuadSPI | 0x40134000 | AHB window at 0x0 |
| I2C4 | 0x402DC000 | VR5510 fail-safe unit at 0x21 |
| SRAM | 0x34000000 | 8 MB; controllers at 0x4019C000 / 0x401A0000 |
| DRAM | 0x80000000 + 0x880000000 | 2 GB + 2 GB |
| Ncore / GICv3 | 0x50400000 / 0x50800000 | |

### Known limitations

- The NOR UPDATE partition has not been written from Linux: the BSP29 5.4 kernel's QuadSPI driver blocks on its first flash read under this boot chain, so the NOR update and rollback flow is untested and the NOR is programmed through the programmer build.
- QuadSPI boot with the octal DTR parameter block is untested.
- Inline DRAM ECC, HSE secure boot and chain-loading BL31 (for kernels that need PSCI or SCMI) are not implemented.

## NXP i.MX95 Cortex-M7

The i.MX95 pairs an A55 cluster running Linux with a real-time Cortex-M7 and a Cortex-M33 System Manager. The M7 has no dedicated flash: it is loaded into TCM by the Linux `remoteproc` driver on the A55 side, so wolfBoot is the ELF that `remoteproc` loads, and the images it verifies live in the DDR region the device tree reserves for the M7.
Expand Down
2 changes: 2 additions & 0 deletions hal/imx_usdhc_sdhci.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
#include "hal/imx8qm.h"
#elif defined(TARGET_imx8mm)
#include "hal/imx8mm.h"
#elif defined(TARGET_s32g2)
#include "hal/s32g2.h"
#else
#error "hal/imx_usdhc_sdhci.c: unsupported target"
#endif
Expand Down
Loading
Loading