Skip to content

Commit b11f5ae

Browse files
committed
Peer review fixes
1 parent 27b52d5 commit b11f5ae

11 files changed

Lines changed: 215 additions & 132 deletions

File tree

.github/workflows/test-configs.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -654,12 +654,6 @@ jobs:
654654
arch: arm
655655
config-file: ./config/examples/zynq7000.config
656656

657-
zynq7000_linux_test:
658-
uses: ./.github/workflows/test-build.yml
659-
with:
660-
arch: arm
661-
config-file: ./config/examples/zynq7000_linux.config
662-
663657
zc702_sdcard_test:
664658
uses: ./.github/workflows/test-build.yml
665659
with:

arch.mk

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -310,10 +310,19 @@ ifeq ($(ARCH),ARM)
310310
UPDATE_OBJS:=src/update_ram.o
311311
CFLAGS+=-DWOLFBOOT_DUALBOOT -fno-builtin -ffreestanding
312312
# Do NOT define WOLFBOOT_USE_STDLIBC: newlib's memcpy uses unaligned
313-
# LDRs which fault on Cortex-A9 when MMU is off (FSBL leaves MMU off
314-
# on Zynq-7000). Use wolfBoot's own aligned-safe memcpy from src/string.c.
315-
# U-Boot legacy header detection for Linux/U-Boot payloads (Milestone 5)
316-
CFLAGS+=-DWOLFBOOT_UBOOT_LEGACY
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+
# U-Boot legacy 64-byte header strip is only meaningful for the
320+
# Linux/U-Boot payload variant (zynq7000_linux.config). Bare-metal
321+
# payloads (zynq7000.config, zc702_sdcard.config) shouldn't risk a
322+
# ~1-in-2^32 false-positive collision with UBOOT_IMG_HDR_MAGIC.
323+
ifeq ($(LINUX_PAYLOAD),1)
324+
CFLAGS+=-DWOLFBOOT_UBOOT_LEGACY
325+
endif
317326
endif
318327

319328
ifeq ($(TARGET),va416x0)

config/examples/zc702_sdcard.config

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@ NO_XIP=1
2020
# Stage payload at low DDR (clear of wolfBoot at 0x04000000-0x040FFFFF).
2121
WOLFBOOT_LOAD_ADDRESS=0x10000000
2222

23-
# GPT/MBR partition layout on the SD card.
24-
# GPT partition 0 (idx 0): FAT32 - holds BOOT.BIN for the BootROM.
25-
# GPT partition 1 (idx 1): raw - signed boot image (BOOT_PART_A).
26-
# GPT partition 2 (idx 2): raw - signed update image (BOOT_PART_B).
23+
# MBR partition layout on the SD card. Pure MBR (no GPT) - the Zynq-7000
24+
# BootROM (UG821 ch.6.3) only accepts MBR with the first partition as
25+
# FAT32 and the Active flag set. wolfBoot's src/disk.c falls back to MBR
26+
# parsing when no protective-GPT entry is present.
27+
# MBR p1 (wolfBoot idx 0): FAT32-LBA Active - holds BOOT.BIN for BootROM.
28+
# MBR p2 (wolfBoot idx 1): Linux raw (0x83) - signed boot image.
29+
# MBR p3 (wolfBoot idx 2): Linux raw (0x83) - signed update image.
2730
# tools/scripts/zc702/prepare_sdcard.sh lays this out; BOOT_PART_A/B tell
28-
# update_disk.c which GPT entries to use for boot/update.
31+
# update_disk.c which MBR entries (0-indexed) to use for boot/update.
2932
CFLAGS_EXTRA+=-DBOOT_PART_A=1 -DBOOT_PART_B=2
3033

3134
# Arasan SDHCI v2.0 on Zynq-7000 is 3.3V-only, no UHS-I. The generic

config/examples/zynq7000.config

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,63 @@ TARGET?=zynq7000
33
SIGN?=ECC256
44
HASH?=SHA256
55

6-
# Cortex-A9 (Zynq-7000) - selected automatically via TARGET=zynq7000 in arch.mk
6+
# Cortex-A9 (Zynq-7000) - selected automatically via TARGET=zynq7000 in arch.mk.
7+
# This single config supports bare-metal, U-Boot, and Linux payloads from QSPI.
78
DEBUG?=0
89
DEBUG_UART?=1
910
V?=0
1011
SPMATH?=1
1112

12-
# wolfBoot itself is loaded by Xilinx FSBL to DDR at 0x04000000 (hal/zynq7000.ld).
13-
# WOLFBOOT_LOAD_ADDRESS is the *app* staging address: where wolfBoot copies
14-
# the verified signed image before do_boot. Must NOT overlap wolfBoot itself
15-
# AND src/update_ram.c expects dst > wolfBoot's _end - so place it above the
16-
# wolfBoot region (0x04000000-0x040FFFFF) at 16 MB.
13+
# Linux/U-Boot payload support (no-op for plain bare-metal payloads):
14+
# LINUX_PAYLOAD=1 -> do_boot uses ARM Linux boot ABI (r0=0, r1=~0,
15+
# r2=DTB_phys, r3=0). Bare-metal apps don't read these
16+
# registers, so the same ABI is fine for them.
17+
# MMU=1 -> enables update_ram.c DTB-load codepath and pulls in
18+
# src/fdt.o. wolfBoot itself does NOT manage page
19+
# tables; it inherits FSBL's flat 1:1 DDR mapping.
20+
# ELF=1 -> wolfBoot understands ELF inputs (vmlinux / u-boot.elf)
21+
# and loads only their LOAD segments. Flat binaries
22+
# (zImage, bare-metal .bin) fall through to raw-binary
23+
# boot.
24+
# Cost vs. a strictly bare-metal-only build: ~5 KB extra wolfBoot binary
25+
# from the FDT/MMU/ELF support, in exchange for one config that covers all
26+
# three payload types.
27+
LINUX_PAYLOAD=1
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/U-Boot/bare-metal app) is staged at
33+
# WOLFBOOT_LOAD_ADDRESS, well clear of wolfBoot. 1 GB DDR3 on ZC702
34+
# starts at 0x00000000.
1735
WOLFBOOT_LOAD_ADDRESS=0x10000000
1836

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+
1941
# QSPI flash (16 MB N25Q128A on ZC702) via XQspiPs (hal/zynq7000.c).
2042
# Override EXT_FLASH=0 on the make command line for JTAG-only dev builds.
2143
EXT_FLASH?=1
2244
NO_XIP=1
2345

24-
# QSPI partition layout (16 MB total):
25-
# 0x000000 - 0x0FFFFF BOOT.BIN (FSBL + wolfboot)
26-
# 0x100000 - 0x6FFFFF BOOT_A (~6 MB primary)
27-
# 0x700000 - 0xCFFFFF UPDATE_B (~6 MB update)
28-
# 0xD00000 - 0xD0FFFF SWAP scratch (64 KB sector)
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)
2954
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x00100000
30-
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x00700000
31-
WOLFBOOT_PARTITION_SWAP_ADDRESS=0x00D00000
55+
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x00780000
56+
WOLFBOOT_PARTITION_SWAP_ADDRESS=0x00E00000
3257
WOLFBOOT_PARTITION_SIZE=0x00600000
3358
WOLFBOOT_SECTOR_SIZE=0x10000
3459

35-
# DTS placeholders (used in Milestone 5 for Linux payload)
36-
WOLFBOOT_LOAD_DTS_ADDRESS=0x00100000
3760
WOLFBOOT_DTS_BOOT_ADDRESS=0x00080000
38-
WOLFBOOT_DTS_UPDATE_ADDRESS=0x00680000
61+
WOLFBOOT_DTS_UPDATE_ADDRESS=0x00700000
3962

4063
IMAGE_HEADER_SIZE=1024
4164

42-
CROSS_COMPILE=arm-none-eabi-
65+
CROSS_COMPILE?=arm-none-eabi-

config/examples/zynq7000_linux.config

Lines changed: 0 additions & 53 deletions
This file was deleted.

docs/Targets.md

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3404,9 +3404,9 @@ BootROM -> FSBL -> wolfBoot -> signed app (or U-Boot/Linux)
34043404
The FSBL handles all PS init (DDR, MIO, clocks, QSPI ref clock); wolfBoot only initializes UART, the QSPI controller, runs the verify/swap logic, and chain-loads the next stage.
34053405

34063406
This target supports:
3407-
- **QSPI boot** (primary): `config/examples/zynq7000.config`
3408-
- **SD card boot** (Milestone 6, planned): `config/examples/zc702_sdcard.config`
3409-
- **JTAG-loaded dev** via Platform Cable II + xsdb (no flash required)
3407+
- **QSPI boot** (primary): `config/examples/zynq7000.config` -- one config for bare-metal, U-Boot, and Linux payloads (LINUX_PAYLOAD=1 + MMU=1 + ELF=1; bare-metal apps don't pay any runtime cost beyond ~5 KB of unused FDT/MMU code).
3408+
- **SD card boot**: `config/examples/zc702_sdcard.config` -- bare-metal payload from MBR-partitioned SD via the generic SDHCI driver and the Arasan v2.0 translation in `hal/zynq7000.c`.
3409+
- **JTAG-loaded dev** via Platform Cable II + xsdb (no flash required).
34103410

34113411
### Prerequisites
34123412

@@ -3438,8 +3438,10 @@ Key options in `config/examples/zynq7000.config`:
34383438
- `ARCH=ARM` - 32-bit ARM
34393439
- `TARGET=zynq7000` - selects `hal/zynq7000.{c,h,ld}` and the `CORTEX_A9` arch.mk block
34403440
- `SIGN=ECC256` / `HASH=SHA256` - smaller and faster than RSA on Cortex-A9
3441+
- `LINUX_PAYLOAD=1 MMU=1 ELF=1` - lets the same image boot Linux/U-Boot or bare-metal. `do_boot` switches to the ARM Linux boot ABI (`r0=0`, `r1=~0`, `r2=DTB_phys`, `r3=0`) which bare-metal apps simply ignore. `MMU=1` enables `update_ram.c`'s DTB-load codepath and pulls in `src/fdt.o`; wolfBoot does not manage page tables (it inherits FSBL's flat 1:1 DDR mapping). `ELF=1` lets wolfBoot understand `vmlinux` / `u-boot.elf` inputs and load only their LOAD segments. Cost over a strictly bare-metal-only build: ~5 KB extra wolfBoot binary (31 KB -> 36 KB).
34413442
- `EXT_FLASH=1` - QSPI as external flash via `XQspiPs`
34423443
- `WOLFBOOT_LOAD_ADDRESS=0x10000000` - DDR offset 256 MB, where the verified app is staged before `do_boot`. Must be **above** wolfBoot's own region (`0x04000000`-`0x040FFFFF`) because `src/update_ram.c` enforces `dst > _end`.
3444+
- `WOLFBOOT_LOAD_DTS_ADDRESS=0x11000000` - DDR offset 272 MB, where a DTB read out of `PART_DTS_BOOT` would be relocated. Ignored for bare-metal payloads and for the appended-DTB Linux flow (where the DTB lives at the end of the signed kernel image).
34433445
- `WOLFBOOT_PARTITION_BOOT_ADDRESS=0x00100000` - 16 MB QSPI layout below
34443446
- `CROSS_COMPILE=arm-none-eabi-`
34453447

@@ -3483,11 +3485,31 @@ bootgen -arch zynq -image tools/scripts/zc702/zc702_qspi.bif -w -o BOOT.BIN
34833485

34843486
### Programming QSPI
34853487

3486-
Set ZC702 boot mode straps to **JTAG** (SW16 all OFF) for programming, then either:
3487-
- Vitis: `program_flash -f BOOT.BIN -flash_type qspi-x4-single -fsbl ${PREBUILT_DIR}/zynq_fsbl.elf -target_id <id>` (use `program_flash -jtagtargets` to get the `arm_dap` target ID for your Platform Cable; only needed when more than one cable is connected)
3488-
- Vivado Hardware Manager: Tools -> Add Configuration Memory Device -> select N25Q128 -> program with BOOT.BIN at offset 0.
3488+
The 16 MB QSPI flash holds two artifacts: `BOOT.BIN` at offset `0x0` (FSBL + wolfBoot, < 1 MB) and the signed payload at `WOLFBOOT_PARTITION_BOOT_ADDRESS` (default `0x100000` for the BOOT_A partition). Both go through `program_flash` over JTAG.
34893489

3490-
After programming, set boot mode to **QSPI** by turning **SW16-4 ON** (the four-position dip mapping is `SW16-4 = MIO[5]` MSB of the boot device strap, with SW16-1..3 = MIO[2..4]; per UG850 ch.1.2.4). Power-cycle the board (cold) so the BootROM re-samples the strap. Console comes up on UART1 (J17 USB-UART), 115200 8N1.
3490+
Set ZC702 boot mode straps to **JTAG** (SW16 all OFF) for programming. Then run two commands:
3491+
3492+
```sh
3493+
# 1. List JTAG targets and note the arm_dap target ID for the Xilinx Platform
3494+
# Cable USB II (skip this step if you only have one JTAG cable connected).
3495+
program_flash -jtagtargets -url TCP:127.0.0.1:3121
3496+
3497+
# 2. Program BOOT.BIN at offset 0
3498+
program_flash -f BOOT.BIN -offset 0 -flash_type qspi-x4-single \
3499+
-fsbl ${PREBUILT_DIR}/zynq_fsbl.elf \
3500+
-target_id <arm_dap_id> -url TCP:127.0.0.1:3121
3501+
3502+
# 3. Program the signed payload at the BOOT_A partition offset
3503+
program_flash -f test-app/image_v1_signed.bin -offset 0x100000 \
3504+
-flash_type qspi-x4-single -fsbl ${PREBUILT_DIR}/zynq_fsbl.elf \
3505+
-target_id <arm_dap_id> -url TCP:127.0.0.1:3121
3506+
```
3507+
3508+
`program_flash` ships with Vitis. The Vivado Hardware Manager UI works equivalently (Tools -> Add Configuration Memory Device -> select N25Q128 -> program two files at offsets 0 and 0x100000).
3509+
3510+
After programming, set boot mode to **QSPI** by turning **SW16-4 ON** (the four-position dip mapping is `SW16-4 = MIO[5]` MSB of the boot device strap, with SW16-1..3 = MIO[2..4]; per UG850 ch.1.2.4). Power-cycle the board (cold) so the BootROM re-samples the strap. Console comes up on UART1 (J17 USB-UART), 115200 8N1, and you should see the wolfBoot banner followed by `=== ZC702 test-app: BOOT OK ===` (or, with `LINUX_PAYLOAD=1` and a signed kernel, the Linux boot log).
3511+
3512+
`program_flash` may print a segmentation fault on exit ("Flash Operation Successful" precedes it) -- that's a Vitis tool quirk on cleanup, not a programming failure; the flash content is correct.
34913513

34923514
### JTAG-loaded development (no flash)
34933515

hal/zynq7000.c

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,14 @@ static void qspi_linear_mode_setup(void)
251251
Z7_QSPI_ISR = Z7_QSPI_ISR_MASK;
252252

253253
/* CR: IFMODE=1, FIFO=32-bit, MSTREN=1, SSFORCE=1, HOLD_B=1, /4 baud,
254-
* MANSTRTEN=0 (auto-start), CPHA/CPOL=0, PCS bit 10 cleared (CS0
255-
* asserted - in linear mode the controller still wants this). */
254+
* MANSTRTEN=0 (auto-start), CPHA/CPOL=0, PCS=CS0 asserted explicitly
255+
* (the linear-mode controller still drives PCS even with SSFORCE; we
256+
* set the field deterministically rather than relying on the reset
257+
* default). */
256258
Z7_QSPI_CR = Z7_QSPI_CR_IFMODE
257259
| Z7_QSPI_CR_HOLD_B
258260
| Z7_QSPI_CR_SSFORCE
261+
| Z7_QSPI_CR_PCS_CS0
259262
| Z7_QSPI_CR_FIFO_WIDTH
260263
| Z7_QSPI_CR_BAUD_DIV_4
261264
| Z7_QSPI_CR_MSTREN;
@@ -461,18 +464,12 @@ static void qspi_print_hex32(uint32_t v)
461464

462465
static void qspi_selftest(void)
463466
{
464-
static const uint8_t pattern[SPI_NOR_PAGE_SIZE] = {
465-
/* zero-initialized, filled in below */
466-
0
467-
};
467+
uint8_t patbuf[SPI_NOR_PAGE_SIZE];
468468
uint8_t rdback[SPI_NOR_PAGE_SIZE];
469469
uint8_t id[3] = { 0, 0, 0 };
470470
unsigned int i;
471471
int rc;
472-
/* Local mutable pattern buffer */
473-
uint8_t patbuf[SPI_NOR_PAGE_SIZE];
474472

475-
(void)pattern;
476473
for (i = 0; i < SPI_NOR_PAGE_SIZE; i++)
477474
patbuf[i] = (uint8_t)(i & 0xFFU);
478475

@@ -600,7 +597,29 @@ void hal_init(void)
600597
const char banner[] = "wolfBoot Zynq-7000 (ZC702) hal_init\n";
601598
uart_write(banner, sizeof(banner) - 1);
602599
}
600+
/* One-line boot config summary so the UART log identifies which
601+
* config / storage / payload / clock plan the running wolfBoot was
602+
* built for. Useful when juggling QSPI vs SD images. */
603+
#if defined(DISK_SDCARD) || defined(DISK_EMMC)
604+
wolfBoot_printf(" storage : SDCard (Arasan SDHCI v2.0, %d MHz post-init)\n",
605+
SDHCI_CLK_50MHZ / 1000);
606+
#elif defined(EXT_FLASH)
607+
wolfBoot_printf(" storage : QSPI (XQspiPs N25Q128, IO_PLL/40 ~12.5 MHz)\n");
608+
#else
609+
wolfBoot_printf(" storage : NONE (JTAG-loaded)\n");
610+
#endif
611+
#if defined(WOLFBOOT_LINUX_PAYLOAD)
612+
wolfBoot_printf(" payload : ARM Linux ABI (r0=0, r1=~0, r2=DTB)\n");
613+
#else
614+
wolfBoot_printf(" payload : bare-metal (r0=DTB, r1=r2=r3=0)\n");
603615
#endif
616+
wolfBoot_printf(" partns : load=0x%x boot=0x%x update=0x%x\n",
617+
(unsigned int)WOLFBOOT_LOAD_ADDRESS,
618+
(unsigned int)WOLFBOOT_PARTITION_BOOT_ADDRESS,
619+
(unsigned int)WOLFBOOT_PARTITION_UPDATE_ADDRESS);
620+
wolfBoot_printf(" cputmr : Cortex-A9 GTimer @ %u Hz\n",
621+
(unsigned int)Z7_GTIMER_FREQ_HZ);
622+
#endif /* DEBUG_UART */
604623
#ifdef EXT_FLASH
605624
qspi_init();
606625
#if defined(TEST_EXT_FLASH) || defined(TEST_QSPI)
@@ -814,10 +833,12 @@ void *hal_get_dts_update_address(void)
814833
#endif /* MMU */
815834

816835
/* Microsecond timer using the Cortex-A9 Global Timer at PERIPHBASE+0x200.
817-
* 64-bit free-running counter, increments at PERIPHCLK (~166.67 MHz on
818-
* ZC702 with the default FSBL clock plan: CPU_6x4x = 666.67 MHz). The
819-
* Global Timer is started by the FSBL; if it isn't running yet we kick
820-
* it here. */
836+
* 64-bit free-running counter, increments at PERIPHCLK = CPU_3x2x =
837+
* 333.33 MHz on ZC702 with the default FSBL clock plan (ARM_PLL =
838+
* 1.333 GHz, CPU_6x4x = 666.67 MHz). The actual divide constant lives
839+
* in Z7_GTIMER_FREQ_HZ in hal/zynq7000.h - override there if you reclock
840+
* the CPU. The Global Timer is started by the FSBL; if it isn't running
841+
* yet we kick it here. */
821842
uint64_t hal_get_timer_us(void)
822843
{
823844
uint32_t hi1, lo, hi2;
@@ -1075,11 +1096,18 @@ void sdhci_platform_dma_prepare(void *buf, uint32_t sz, int is_write)
10751096
void sdhci_platform_dma_complete(void *buf, uint32_t sz, int is_write)
10761097
{
10771098
if (!is_write) {
1099+
/* Post-DMA-read: invalidate-only (DCIMVAC, c7,c6,1). The DMA
1100+
* controller has just written fresh data into DRAM; we must
1101+
* discard any stale CPU lines (including ones the prefetcher
1102+
* may have pulled in between dma_prepare and dma_complete) so
1103+
* subsequent CPU reads see the new data. clean+invalidate
1104+
* (DCCIMVAC) would write back the stale lines first, partially
1105+
* overwriting the controller's data. */
10781106
uintptr_t start = (uintptr_t)buf & ~31U;
10791107
uintptr_t end = ((uintptr_t)buf + sz + 31U) & ~31U;
10801108
uintptr_t addr;
10811109
for (addr = start; addr < end; addr += 32U) {
1082-
__asm__ volatile("mcr p15, 0, %0, c7, c14, 1" : : "r"(addr) : "memory");
1110+
__asm__ volatile("mcr p15, 0, %0, c7, c6, 1" : : "r"(addr) : "memory");
10831111
}
10841112
__asm__ volatile("dsb sy" : : : "memory");
10851113
}

0 commit comments

Comments
 (0)