Skip to content

Commit a0a9288

Browse files
committed
Add Xilinx Zynq-7000 (ZC702) wolfBoot port
1 parent 8c7b864 commit a0a9288

19 files changed

Lines changed: 2791 additions & 98 deletions

.github/workflows/test-configs.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,18 @@ jobs:
648648
arch: aarch64
649649
config-file: ./config/examples/zynqmp_sdcard.config
650650

651+
zynq7000_test:
652+
uses: ./.github/workflows/test-build.yml
653+
with:
654+
arch: arm
655+
config-file: ./config/examples/zynq7000.config
656+
657+
zynq7000_sdcard_test:
658+
uses: ./.github/workflows/test-build.yml
659+
with:
660+
arch: arm
661+
config-file: ./config/examples/zynq7000_sdcard.config
662+
651663
versal_vmk180_test:
652664
uses: ./.github/workflows/test-build-aarch64.yml
653665
with:

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,10 @@ ifeq ($(TARGET),sama5d3)
285285
MAIN_TARGET:=wolfboot.bin test-app/image_v1_signed.bin
286286
endif
287287

288+
ifeq ($(TARGET),zynq7000)
289+
MAIN_TARGET:=wolfboot.bin test-app/image_v1_signed.bin
290+
endif
291+
288292
ifeq ($(TARGET),rp2350)
289293
MAIN_TARGET:=include/target.h keytools wolfboot_signing_private_key.der pico-sdk-info
290294
endif

arch.mk

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,30 @@ ifeq ($(ARCH),ARM)
303303
CFLAGS+=-DWOLFBOOT_USE_STDLIBC
304304
endif
305305

306+
ifeq ($(TARGET),zynq7000)
307+
# AMD/Xilinx Zynq-7000 (Cortex-A9, ARMv7-A) - ZC702 Evaluation Kit.
308+
# Loaded by Xilinx FSBL into DDR; see hal/zynq7000.{c,h,ld}.
309+
CORTEX_A9=1
310+
UPDATE_OBJS:=src/update_ram.o
311+
CFLAGS+=-DWOLFBOOT_DUALBOOT -fno-builtin -ffreestanding
312+
# Do NOT define WOLFBOOT_USE_STDLIBC: newlib's memcpy uses unaligned
313+
# LDRs which fault on ARMv7-A whenever the active mapping treats memory
314+
# as Strongly-Ordered (typically MMU off, but also some boot-stage
315+
# configurations). wolfBoot's startup keeps FSBL's MMU + flat 1:1
316+
# mapping enabled to avoid that, but we still link against the
317+
# aligned-safe memcpy in src/string.c so unaligned loads can never
318+
# surprise us regardless of MMU state.
319+
# Enable the legacy 64-byte uImage header strip unconditionally to
320+
# match sibling Xilinx targets (zynqmp, versal). update_ram.c
321+
# validates magic + ih_hcrc (header CRC32) + ih_size before
322+
# stripping, so a non-uImage payload whose first 4 bytes happen to
323+
# match UBOOT_IMG_HDR_MAGIC cannot be silently treated as a uImage
324+
# -- the additional CRC32 + size checks drop the joint false-
325+
# positive probability from ~2^-32 to ~2^-64, matching what U-Boot's
326+
# own mkimage/bootm does.
327+
CFLAGS+=-DWOLFBOOT_UBOOT_LEGACY
328+
endif
329+
306330
ifeq ($(TARGET),va416x0)
307331
CFLAGS+=-I$(WOLFBOOT_ROOT)/hal/vorago/ \
308332
-I$(VORAGO_SDK_DIR)/common/drivers/hdr/ \
@@ -344,6 +368,52 @@ ifeq ($(CORTEX_A5),1)
344368
-DWOLFSSL_ARM_ARCH=7 -DWOLFSSL_ARMASM_INLINE -DWOLFSSL_ARMASM_NO_NEON
345369
endif
346370
endif
371+
else
372+
ifeq ($(CORTEX_A9),1)
373+
# Cortex-A9 (ARMv7-A, 32-bit) - Zynq-7000.
374+
# Build in ARM state (-marm); reset vector lands in ARM mode after FSBL.
375+
# Note: do not filter out -mthumb from CFLAGS/LDFLAGS - that converts the
376+
# variables to simple-expansion flavor and breaks lazy $(LSCRIPT) expansion
377+
# in test-app/Makefile. -marm appended later wins over -mthumb anyway.
378+
FPU=-mfpu=vfp3-d16
379+
CFLAGS+=-mcpu=cortex-a9 -mtune=cortex-a9 -marm -mno-unaligned-access
380+
LDFLAGS+=-mcpu=cortex-a9 -mtune=cortex-a9 -marm -static \
381+
-Wl,-z,noexecstack
382+
# Cortex-A9 uses the same generic ARMv7-A startup as Cortex-A5
383+
# (src/boot_arm32_start.S handles VBAR, per-mode stacks, cache
384+
# invalidate, async-abort enable for any ARMv7-A target).
385+
OBJS+=src/boot_arm32.o src/boot_arm32_start.o
386+
# Linux/U-Boot payload: enable MMU + FDT codepaths in update_ram.c so DTBs
387+
# can be loaded from a separate signed PART_DTS_BOOT partition. The MMU
388+
# itself stays inherited from FSBL's flat 1:1 mapping; wolfBoot does not
389+
# manage page tables on Cortex-A9.
390+
ifeq ($(MMU),1)
391+
CFLAGS+=-DMMU -DWOLFBOOT_FDT
392+
OBJS+=src/fdt.o
393+
endif
394+
# CRC32 helpers in src/gpt.c are reused by update_ram.c's uImage header
395+
# validator (WOLFBOOT_UBOOT_LEGACY), so link gpt.o for every Cortex-A9
396+
# build, not just the disk-boot variant below.
397+
OBJS+=src/gpt.o
398+
# SD card / eMMC boot: swap the update_ram loader for update_disk + GPT.
399+
# The SDHCI HAL hooks live in hal/zynq7000.c and translate the generic
400+
# Cadence-layout driver to the Arasan SDHCI v2.0 controller.
401+
ifneq ($(filter 1,$(DISK_SDCARD) $(DISK_EMMC)),)
402+
CFLAGS+=-DWOLFBOOT_UPDATE_DISK -DMAX_DISKS=1
403+
UPDATE_OBJS:=src/update_disk.o
404+
OBJS += src/disk.o
405+
endif
406+
ifeq ($(NO_ASM),1)
407+
MATH_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sp_c32.o
408+
else
409+
MATH_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sp_arm32.o
410+
ifneq ($(NO_ARM_ASM),1)
411+
OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/arm/armv8-32-sha256-asm.o
412+
OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/arm/armv8-32-sha256-asm_c.o
413+
CFLAGS+=-DWOLFSSL_SP_ARM32_ASM -DWOLFSSL_ARMASM -DWOLFSSL_ARMASM_NO_HW_CRYPTO \
414+
-DWOLFSSL_ARM_ARCH=7 -DWOLFSSL_ARMASM_INLINE -DWOLFSSL_ARMASM_NO_NEON
415+
endif
416+
endif
347417
else
348418
# All others use boot_arm.o
349419
OBJS+=src/boot_arm.o
@@ -456,6 +526,7 @@ else
456526
endif
457527
endif
458528
endif
529+
endif
459530

460531

461532
## Renesas RX
@@ -1734,6 +1805,11 @@ endif
17341805
ifeq ($(ARCH),AARCH64)
17351806
CFLAGS+=-DMMU -DWOLFBOOT_FDT -DWOLFBOOT_DUALBOOT
17361807
OBJS+=src/fdt.o
1808+
# src/gpt.c provides the CRC32 helpers reused by update_ram.c's uImage
1809+
# header validator under WOLFBOOT_UBOOT_LEGACY (zynq, versal). Also
1810+
# needed for the disk variant. Targets without WOLFBOOT_UBOOT_LEGACY or
1811+
# disk support (e.g. nxp_ls1028a) GC the unused code via --gc-sections.
1812+
OBJS+=src/gpt.o
17371813
ifneq ($(filter 1,$(DISK_SDCARD) $(DISK_EMMC)),)
17381814
# Disk-based boot (SD card or eMMC)
17391815
CFLAGS+=-DWOLFBOOT_UPDATE_DISK
@@ -1742,7 +1818,6 @@ ifeq ($(ARCH),AARCH64)
17421818
endif
17431819
CFLAGS+=-DMAX_DISKS=$(MAX_DISKS)
17441820
UPDATE_OBJS:=src/update_disk.o
1745-
OBJS+=src/gpt.o
17461821
OBJS+=src/disk.o
17471822
else
17481823
# RAM-based boot from external flash (default)

config/examples/zynq7000.config

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
ARCH?=ARM
2+
TARGET?=zynq7000
3+
SIGN?=ECC256
4+
HASH?=SHA256
5+
6+
# Cortex-A9 (Zynq-7000) - selected automatically via TARGET=zynq7000 in arch.mk.
7+
# wolfBoot replaces U-Boot in the Z7 boot flow (BootROM -> FSBL -> wolfBoot ->
8+
# kernel/app, no U-Boot stage). This single config supports both bare-metal
9+
# and Linux payloads from QSPI.
10+
DEBUG?=0
11+
DEBUG_UART?=1
12+
V?=0
13+
SPMATH?=1
14+
15+
# One config for both bare-metal and Linux payloads. do_boot in
16+
# src/boot_arm32.c always emits the ARM Linux boot ABI (r0=0, r1=~0,
17+
# r2=DTB_phys, r3=0) when MMU=1; bare-metal apps simply ignore r0..r3,
18+
# so a single register-handoff covers both payload types.
19+
# MMU=1 -> enables update_ram.c DTB-load codepath and pulls in
20+
# src/fdt.o. wolfBoot itself does NOT manage page tables; it
21+
# inherits FSBL's flat 1:1 DDR mapping.
22+
# ELF=1 -> wolfBoot understands ELF inputs (e.g. vmlinux) and loads
23+
# only their LOAD segments. Flat binaries (zImage, bare-metal
24+
# .bin) fall through to raw-binary boot.
25+
# Cost vs. a strictly bare-metal-only build: ~5 KB extra wolfBoot binary
26+
# from the FDT/MMU/ELF support, in exchange for one config that covers
27+
# both payload types.
28+
MMU=1
29+
ELF=1
30+
31+
# wolfBoot itself is staged by FSBL to DDR at 0x04000000 (hal/zynq7000.ld);
32+
# the verified payload (kernel or bare-metal app) is staged at
33+
# WOLFBOOT_LOAD_ADDRESS, well clear of wolfBoot. 1 GB DDR3 on ZC702
34+
# starts at 0x00000000.
35+
WOLFBOOT_LOAD_ADDRESS=0x10000000
36+
37+
# DTB load address (Linux only). Kernel reads it from r2. 16 MB clear of
38+
# WOLFBOOT_LOAD_ADDRESS. Ignored for bare-metal payloads.
39+
WOLFBOOT_LOAD_DTS_ADDRESS=0x11000000
40+
41+
# QSPI flash (16 MB N25Q128A on ZC702) via XQspiPs (hal/zynq7000.c).
42+
# Override EXT_FLASH=0 on the make command line for JTAG-only dev builds.
43+
EXT_FLASH?=1
44+
NO_XIP=1
45+
46+
# QSPI partition layout (16 MB total) - sized for a full Linux kernel + DTB
47+
# pair so the same layout also works for bare-metal payloads.
48+
# 0x000000 - 0x07FFFF BOOT.BIN (FSBL + wolfboot, 512 KB)
49+
# 0x080000 - 0x0FFFFF DTS_BOOT (signed DTB, 512 KB - Linux only)
50+
# 0x100000 - 0x6FFFFF BOOT_A (~6 MB primary)
51+
# 0x700000 - 0x77FFFF DTS_UPD (signed update DTB, 512 KB - Linux only)
52+
# 0x780000 - 0xDFFFFF UPDATE_B (~6.5 MB update)
53+
# 0xE00000 - 0xE0FFFF SWAP (64 KB scratch)
54+
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x00100000
55+
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x00780000
56+
WOLFBOOT_PARTITION_SWAP_ADDRESS=0x00E00000
57+
WOLFBOOT_PARTITION_SIZE=0x00600000
58+
WOLFBOOT_SECTOR_SIZE=0x10000
59+
60+
WOLFBOOT_DTS_BOOT_ADDRESS=0x00080000
61+
WOLFBOOT_DTS_UPDATE_ADDRESS=0x00700000
62+
63+
IMAGE_HEADER_SIZE=1024
64+
65+
CROSS_COMPILE?=arm-none-eabi-
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
ARCH?=ARM
2+
TARGET?=zynq7000
3+
SIGN?=ECC256
4+
HASH?=SHA256
5+
6+
# Cortex-A9 Zynq-7000 SD-card boot variant. Uses the generic SDHCI driver
7+
# (src/sdhci.c) with HAL hooks in hal/zynq7000.c that translate between the
8+
# driver's Cadence SD4HC register layout and the Arasan SDHCI v2.0 standard
9+
# layout used by the Zynq-7000 controller (same IP family as ZynqMP's v3.0,
10+
# just an older revision; the translation is reused from hal/zynq.c).
11+
#
12+
# wolfBoot replaces U-Boot in the Z7 boot flow (BootROM -> FSBL -> wolfBoot
13+
# -> kernel/app, no U-Boot stage). This single config supports both
14+
# bare-metal and Linux payloads from SD card -- see the MMU/ELF block below.
15+
DEBUG?=0
16+
DEBUG_UART?=1
17+
V?=0
18+
SPMATH?=1
19+
20+
# SD card boot - swaps update_ram.o for update_disk.o + GPT/disk support.
21+
DISK_SDCARD=1
22+
NO_XIP=1
23+
24+
# One config for both bare-metal and Linux payloads. do_boot in
25+
# src/boot_arm32.c always emits the ARM Linux boot ABI (r0=0, r1=~0,
26+
# r2=DTB_phys, r3=0) when MMU=1; bare-metal apps simply ignore r0..r3,
27+
# so a single register-handoff covers both payload types.
28+
# MMU=1 -> pulls in src/fdt.o for FDT-aware paths in update_disk.c.
29+
# wolfBoot does NOT manage page tables; it inherits FSBL's
30+
# flat 1:1 DDR mapping.
31+
# ELF=1 -> wolfBoot understands ELF inputs (e.g. vmlinux) and loads
32+
# only their LOAD segments. Flat binaries (zImage, bare-metal
33+
# .bin) fall through to raw-binary boot.
34+
# For Linux from SD use tools/scripts/zynq7000/prepare_linux.sh APPENDED=1
35+
# (DTB concatenated to zImage and signed as one image). update_disk.c does
36+
# not read a separate PART_DTS_BOOT partition; the appended-DTB path is
37+
# what carries the device tree to the kernel via CONFIG_ARM_APPENDED_DTB.
38+
MMU=1
39+
ELF=1
40+
41+
# Stage payload at low DDR (clear of wolfBoot at 0x04000000-0x040FFFFF).
42+
WOLFBOOT_LOAD_ADDRESS=0x10000000
43+
44+
# DTB load address (Linux only, used by update_disk.c when a FIT image
45+
# carries a DTB). Ignored for bare-metal and for the appended-DTB Linux
46+
# flow. 16 MB clear of WOLFBOOT_LOAD_ADDRESS.
47+
WOLFBOOT_LOAD_DTS_ADDRESS=0x11000000
48+
49+
# MBR partition layout on the SD card. Pure MBR (no GPT) - the Zynq-7000
50+
# BootROM (UG821 ch.6.3) only accepts MBR with the first partition as
51+
# FAT32 and the Active flag set. wolfBoot's src/disk.c falls back to MBR
52+
# parsing when no protective-GPT entry is present.
53+
# MBR p1 (wolfBoot idx 0): FAT32-LBA Active - holds BOOT.BIN for BootROM.
54+
# MBR p2 (wolfBoot idx 1): Linux raw (0x83) - signed boot image.
55+
# MBR p3 (wolfBoot idx 2): Linux raw (0x83) - signed update image.
56+
# tools/scripts/zynq7000/prepare_sdcard.sh lays this out; BOOT_PART_A/B tell
57+
# update_disk.c which MBR entries (0-indexed) to use for boot/update.
58+
CFLAGS_EXTRA+=-DBOOT_PART_A=1 -DBOOT_PART_B=2
59+
60+
# Arasan SDHCI v2.0 on Zynq-7000 is 3.3V-only, no UHS-I. The generic
61+
# driver tries to push the card to UHS-I SDR25 / 50 MHz / High Speed mode
62+
# which is invalid for our v2.0 + 3.3V combo and causes DTOE on the first
63+
# data transfer (MBR read). Cap the post-init clock at SD default-speed
64+
# 25 MHz; the HSE bit is also masked in hal/zynq7000.c sdhci_reg_write so
65+
# the controller stays in single-edge timing the card matches.
66+
# Cap the post-init SDHCI clock at 6 MHz. The Arasan SDHCI v2.0 on
67+
# Zynq-7000 has a clock-dependent state-cleanup issue: at 12 MHz multi-
68+
# block reads (CMD18) work, but a single-block read (CMD17) issued
69+
# immediately after a CMD18+CMD12 sequence times out (DTOE) on the first
70+
# data block. At 24 MHz even the very first CMD17 fails. 6 MHz / 4-bit
71+
# bus is plenty fast for boot-time loading (~3 MB/s) and is well below
72+
# the v2.0 quirk threshold; raise this if a future fix in src/sdhci.c
73+
# adds an explicit DAT-line reset between transfers.
74+
CFLAGS_EXTRA+=-DSDHCI_CLK_50MHZ=6000 -DSDHCI_CLK_25MHZ=6000
75+
76+
# update_disk.c reads images in DISK_BLOCK_SIZE chunks. Default 512 B = one
77+
# disk_read = one CMD17 per 512 B, which makes a multi-MB Linux load issue
78+
# thousands of CMDs and stall the card with per-CMD overhead. Bump to
79+
# 512 KB so each disk_read pulls 1024 blocks via one CMD18 SDMA (matches
80+
# ZynqMP). Verified on ZC702 with a 4.76 MB appended-DTB zImage: 9 CMD18s
81+
# complete in well under a second. The default 4 KB SDMA buffer boundary
82+
# is left in place -- overriding it to 512 KB stalled SDMA on Arasan v2.0.
83+
CFLAGS_EXTRA+=-DDISK_BLOCK_SIZE=0x80000
84+
85+
# Uncomment for verbose SDHCI driver logging when bringing up new boards
86+
# or debugging timing issues.
87+
#CFLAGS_EXTRA+=-DDEBUG_SDHCI
88+
89+
# Image-header partition addresses are unused for disk boot (kept for the
90+
# Makefile sanity checks). update_disk.c finds images by GPT entry, not by
91+
# memory address.
92+
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x00100000
93+
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x00700000
94+
WOLFBOOT_PARTITION_SWAP_ADDRESS=0x00D00000
95+
WOLFBOOT_PARTITION_SIZE=0x00600000
96+
# Sector size of WOLFBOOT_PARTITION (not the SD physical sector, which is
97+
# always 512 B). Used as the smallest erase/copy unit for the BOOT/UPDATE
98+
# partitions; must be > IMAGE_HEADER_SIZE.
99+
WOLFBOOT_SECTOR_SIZE=0x1000
100+
101+
IMAGE_HEADER_SIZE=1024
102+
103+
# Required by image.c when MMU=1 is set, even though update_disk.c never
104+
# opens PART_DTS_BOOT/PART_DTS_UPDATE on this target (the disk boot path
105+
# selects images by partition index -- BOOT_PART_A / BOOT_PART_B above --
106+
# not by memory-mapped address, and the DTB travels with the kernel via
107+
# appended-DTB or FIT). src/disk.c parses either GPT or MBR (it falls
108+
# back to MBR when there is no protective-GPT entry), so the layout
109+
# choice is orthogonal to this knob. Set to dummy addresses to satisfy
110+
# the build.
111+
WOLFBOOT_DTS_BOOT_ADDRESS=0x0
112+
WOLFBOOT_DTS_UPDATE_ADDRESS=0x0
113+
114+
CROSS_COMPILE=arm-none-eabi-

0 commit comments

Comments
 (0)