Skip to content

Commit b94954e

Browse files
dgarskedanielinux
authored andcommitted
Add Xilinx Zynq-7000 (ZC702) wolfBoot port
1 parent 7b0bee5 commit b94954e

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
@@ -667,6 +667,18 @@ jobs:
667667
arch: aarch64
668668
config-file: ./config/examples/zynqmp_sdcard.config
669669

670+
zynq7000_test:
671+
uses: ./.github/workflows/test-build.yml
672+
with:
673+
arch: arm
674+
config-file: ./config/examples/zynq7000.config
675+
676+
zynq7000_sdcard_test:
677+
uses: ./.github/workflows/test-build.yml
678+
with:
679+
arch: arm
680+
config-file: ./config/examples/zynq7000_sdcard.config
681+
670682
versal_vmk180_test:
671683
uses: ./.github/workflows/test-build-aarch64.yml
672684
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
@@ -312,6 +312,30 @@ ifeq ($(ARCH),ARM)
312312
CFLAGS+=-DWOLFBOOT_USE_STDLIBC
313313
endif
314314

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

469540

470541
## Renesas RX
@@ -1760,6 +1831,11 @@ endif
17601831
ifeq ($(ARCH),AARCH64)
17611832
CFLAGS+=-DMMU -DWOLFBOOT_FDT -DWOLFBOOT_DUALBOOT
17621833
OBJS+=src/fdt.o
1834+
# src/gpt.c provides the CRC32 helpers reused by update_ram.c's uImage
1835+
# header validator under WOLFBOOT_UBOOT_LEGACY (zynq, versal). Also
1836+
# needed for the disk variant. Targets without WOLFBOOT_UBOOT_LEGACY or
1837+
# disk support (e.g. nxp_ls1028a) GC the unused code via --gc-sections.
1838+
OBJS+=src/gpt.o
17631839
ifneq ($(filter 1,$(DISK_SDCARD) $(DISK_EMMC)),)
17641840
# Disk-based boot (SD card or eMMC)
17651841
CFLAGS+=-DWOLFBOOT_UPDATE_DISK
@@ -1768,7 +1844,6 @@ ifeq ($(ARCH),AARCH64)
17681844
endif
17691845
CFLAGS+=-DMAX_DISKS=$(MAX_DISKS)
17701846
UPDATE_OBJS:=src/update_disk.o
1771-
OBJS+=src/gpt.o
17721847
OBJS+=src/disk.o
17731848
else
17741849
# 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)