Skip to content

Commit 4f7a802

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

18 files changed

Lines changed: 2687 additions & 87 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: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,28 @@ 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+
# The legacy 64-byte uImage header strip is only meaningful when the
320+
# payload is a Linux kernel (LINUX_PAYLOAD=1). Bare-metal payloads
321+
# shouldn't risk a ~1-in-2^32 false-positive collision against
322+
# UBOOT_IMG_HDR_MAGIC, so the flag is gated on LINUX_PAYLOAD.
323+
ifeq ($(LINUX_PAYLOAD),1)
324+
CFLAGS+=-DWOLFBOOT_UBOOT_LEGACY
325+
endif
326+
endif
327+
306328
ifeq ($(TARGET),va416x0)
307329
CFLAGS+=-I$(WOLFBOOT_ROOT)/hal/vorago/ \
308330
-I$(VORAGO_SDK_DIR)/common/drivers/hdr/ \
@@ -344,6 +366,49 @@ ifeq ($(CORTEX_A5),1)
344366
-DWOLFSSL_ARM_ARCH=7 -DWOLFSSL_ARMASM_INLINE -DWOLFSSL_ARMASM_NO_NEON
345367
endif
346368
endif
369+
else
370+
ifeq ($(CORTEX_A9),1)
371+
# Cortex-A9 (ARMv7-A, 32-bit) - Zynq-7000.
372+
# Build in ARM state (-marm); reset vector lands in ARM mode after FSBL.
373+
# Note: do not filter out -mthumb from CFLAGS/LDFLAGS - that converts the
374+
# variables to simple-expansion flavor and breaks lazy $(LSCRIPT) expansion
375+
# in test-app/Makefile. -marm appended later wins over -mthumb anyway.
376+
FPU=-mfpu=vfp3-d16
377+
CFLAGS+=-mcpu=cortex-a9 -mtune=cortex-a9 -marm -mno-unaligned-access
378+
LDFLAGS+=-mcpu=cortex-a9 -mtune=cortex-a9 -marm -static \
379+
-Wl,-z,noexecstack
380+
# Cortex-A9 uses the same generic ARMv7-A startup as Cortex-A5
381+
# (src/boot_arm32_start.S handles VBAR, per-mode stacks, cache
382+
# invalidate, async-abort enable for any ARMv7-A target).
383+
OBJS+=src/boot_arm32.o src/boot_arm32_start.o
384+
# Linux/U-Boot payload: enable MMU + FDT codepaths in update_ram.c so DTBs
385+
# can be loaded from a separate signed PART_DTS_BOOT partition. The MMU
386+
# itself stays inherited from FSBL's flat 1:1 mapping; wolfBoot does not
387+
# manage page tables on Cortex-A9.
388+
ifeq ($(MMU),1)
389+
CFLAGS+=-DMMU -DWOLFBOOT_FDT
390+
OBJS+=src/fdt.o
391+
endif
392+
# SD card / eMMC boot: swap the update_ram loader for update_disk + GPT.
393+
# The SDHCI HAL hooks live in hal/zynq7000.c and translate the generic
394+
# Cadence-layout driver to the Arasan SDHCI v2.0 controller.
395+
ifneq ($(filter 1,$(DISK_SDCARD) $(DISK_EMMC)),)
396+
CFLAGS+=-DWOLFBOOT_UPDATE_DISK -DMAX_DISKS=1
397+
UPDATE_OBJS:=src/update_disk.o
398+
OBJS += src/gpt.o
399+
OBJS += src/disk.o
400+
endif
401+
ifeq ($(NO_ASM),1)
402+
MATH_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sp_c32.o
403+
else
404+
MATH_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sp_arm32.o
405+
ifneq ($(NO_ARM_ASM),1)
406+
OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/arm/armv8-32-sha256-asm.o
407+
OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/arm/armv8-32-sha256-asm_c.o
408+
CFLAGS+=-DWOLFSSL_SP_ARM32_ASM -DWOLFSSL_ARMASM -DWOLFSSL_ARMASM_NO_HW_CRYPTO \
409+
-DWOLFSSL_ARM_ARCH=7 -DWOLFSSL_ARMASM_INLINE -DWOLFSSL_ARMASM_NO_NEON
410+
endif
411+
endif
347412
else
348413
# All others use boot_arm.o
349414
OBJS+=src/boot_arm.o
@@ -456,6 +521,7 @@ else
456521
endif
457522
endif
458523
endif
524+
endif
459525

460526

461527
## Renesas RX

config/examples/zynq7000.config

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

0 commit comments

Comments
 (0)