diff --git a/config/examples/nxp-ls1028a.config b/config/examples/nxp-ls1028a.config index 366b7dcee1..39f879e1b4 100644 --- a/config/examples/nxp-ls1028a.config +++ b/config/examples/nxp-ls1028a.config @@ -53,3 +53,34 @@ WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x20080000 WOLFBOOT_LOAD_DTS_ADDRESS?=0x80000000 WOLFBOOT_DTS_BOOT_ADDRESS?=0x20F00000 WOLFBOOT_DTS_UPDATE_ADDRESS?=0x20F00000 + +# ----------------------------------------------------------------------------- +# wolfIP network test in the test-app (optional) +# ----------------------------------------------------------------------------- +# Compiles the wolfIP TCP/IP stack + the NXP ENETC ethernet port into the +# test-app and runs a board-side network test (the test-app Makefile selects +# the nxp_enetc port automatically for TARGET=nxp_ls1028a). ENETC is a PCIe +# integrated-endpoint MAC discovered over ECAM; the driver needs no byte-swap +# (AArch64 LE) and no cache maintenance (wolfBoot runs this target with the +# MMU/D-cache off, so DMA memory is non-cacheable). +# +# wolfIP does not fit the default 256KB OCRAM load region, so load the app +# into DDR and enlarge the boot partition. Override the flash layout below +# (the defaults above target a minimal OCRAM-resident app): +#ENABLE_WOLFIP=1 +#WOLFBOOT_LIB_WOLFIP=../lib/wolfip +#WOLFBOOT_PARTITION_SIZE=0x100000 +#WOLFBOOT_PARTITION_BOOT_ADDRESS=0x20100000 +#WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x20300000 +#WOLFBOOT_PARTITION_SWAP_ADDRESS=0x20500000 +# Load (and run) the app from DDR rather than OCRAM: +#WOLFBOOT_LOAD_ADDRESS=0x80100000 +# Set the PHY interface for the board if it differs from port0 SGMII (the +# nxp_enetc_board.h default); RGMII boards set NXP_ENETC_IF_SGMII=0. +#CFLAGS_EXTRA+=-DNXP_ENETC_IF_SGMII=0 +# Test mode (default with neither flag = acquire a DHCP lease and stop): +# WOLFBOOT_TEST_TFTP=1 RRQ a file from a host tftpd, report size+checksum +# (set CFLAGS_EXTRA TFTP_EXPECT_SIZE/TFTP_EXPECT_SUM to verify) +# WOLFIP_SPEED_TEST=1 TCP throughput server on port 9 (drive with nc/dd/pv) +#WOLFBOOT_TEST_TFTP=1 +#WOLFIP_SPEED_TEST=1 diff --git a/config/examples/nxp-t1024.config b/config/examples/nxp-t1024.config index 8cbd033897..a793444b70 100644 --- a/config/examples/nxp-t1024.config +++ b/config/examples/nxp-t1024.config @@ -65,3 +65,28 @@ WOLFBOOT_LOAD_DTS_ADDRESS?=0x7F100000 # Load to RAM before hash and verify CFLAGS_EXTRA+=-DWOLFBOOT_USE_RAMBOOT + +# ----------------------------------------------------------------------------- +# wolfIP network test in the test-app (optional) +# ----------------------------------------------------------------------------- +# Compiles the wolfIP TCP/IP stack + the NXP QorIQ FMan ethernet port +# (mEMAC/MDIO, FM1@DTSEC1) into the test-app and runs a board-side network +# test. The T1024 (e5500) reuses the same nxp_fman driver as the T2080/T1040; +# the default CCSRBAR is the reset value 0xFE000000 (no BOARD_CW_VPX3152 +# relocate). Build the app FLAT and 32-bit (ELF=0) at a low load address -- +# the elf32 load path is not used here. The wolfIP objects are built -fno-plt +# -D_FORTIFY_SOURCE=0 (the test-app does no PLT/GOT runtime fixup). +# Point WOLFBOOT_LIB_WOLFIP at a wolfIP checkout (or add it as lib/wolfip). +#ENABLE_WOLFIP=1 +#WOLFBOOT_LIB_WOLFIP=../lib/wolfip +#ELF=0 +#WOLFBOOT_LOAD_ADDRESS=0x100000 +# Set the PHY interface for the T1024 board if it differs from FM1@DTSEC1 +# SGMII (the nxp_fman_board.h default); RGMII boards set NXP_FMAN_IF_SGMII=0. +#CFLAGS_EXTRA+=-DNXP_FMAN_IF_SGMII=0 +# Test mode (default with neither flag = acquire a DHCP lease and stop): +# WOLFBOOT_TEST_TFTP=1 RRQ a file from a host tftpd, report size+checksum +# (set CFLAGS_EXTRA TFTP_EXPECT_SIZE/TFTP_EXPECT_SUM to verify) +# WOLFIP_SPEED_TEST=1 TCP throughput server on port 9 (drive with nc/dd/pv) +#WOLFBOOT_TEST_TFTP=1 +#WOLFIP_SPEED_TEST=1 diff --git a/config/examples/nxp-t1040.config b/config/examples/nxp-t1040.config index 317eb470ef..25c1a62739 100644 --- a/config/examples/nxp-t1040.config +++ b/config/examples/nxp-t1040.config @@ -65,3 +65,37 @@ WOLFBOOT_LOAD_DTS_ADDRESS?=0x7F100000 # Load to RAM before hash and verify CFLAGS_EXTRA+=-DWOLFBOOT_USE_RAMBOOT + +# ----------------------------------------------------------------------------- +# wolfIP network test in the test-app (optional) +# ----------------------------------------------------------------------------- +# Compiles the wolfIP TCP/IP stack + the NXP QorIQ FMan ethernet port +# (mEMAC/MDIO, FM1@DTSEC1) into the test-app and runs a board-side network +# test. The T1040 (e5500) reuses the same nxp_fman driver as the T2080; the +# default CCSRBAR is the reset value 0xFE000000 (no BOARD_CW_VPX3152 relocate). +# Build the app FLAT and 32-bit (ELF=0) at a low load address -- the elf32 +# load path is not used here. The wolfIP objects are built -fno-plt +# -D_FORTIFY_SOURCE=0 (the test-app does no PLT/GOT runtime fixup). +# Point WOLFBOOT_LIB_WOLFIP at a wolfIP checkout (or add it as lib/wolfip). +#ENABLE_WOLFIP=1 +#WOLFBOOT_LIB_WOLFIP=../lib/wolfip +#ELF=0 +#WOLFBOOT_LOAD_ADDRESS=0x100000 +# PHY wiring. The nxp_fman default is FM1@DTSEC1 SGMII, PHY probed at addr 0x2. +# On the T1040D4RDB the cabled front port "ETH0" is FM1@DTSEC4 (ethernet@e6000), +# RGMII, with a Realtek RTL8211 PHY (id 0x001CC915) at MDIO addr 4 -- verified +# on hardware (DHCP lease, WOLFIP_TEST: PASS). DTSEC1/2 are fixed-link to the +# on-board L2 switch (no PHY). Uncomment for the RDB ETH0 port: +#CFLAGS_EXTRA+=-DNXP_FMAN_MEMAC_IDX=4 +#CFLAGS_EXTRA+=-DNXP_FMAN_IF_SGMII=0 +#CFLAGS_EXTRA+=-DNXP_FMAN_PHY_ADDR=4 +# To identify the cabled port on a different board, enable the MDIO bus scan: +# it prints ID1/ID2/BSR for every address after init; the one with link=UP is +# the wired port (BSR bit 2). Diagnostic only. +#CFLAGS_EXTRA+=-DWOLFIP_PHY_SCAN +# Test mode (default with neither flag = acquire a DHCP lease and stop): +# WOLFBOOT_TEST_TFTP=1 RRQ a file from a host tftpd, report size+checksum +# (set CFLAGS_EXTRA TFTP_EXPECT_SIZE/TFTP_EXPECT_SUM to verify) +# WOLFIP_SPEED_TEST=1 TCP throughput server on port 9 (drive with nc/dd/pv) +#WOLFBOOT_TEST_TFTP=1 +#WOLFIP_SPEED_TEST=1 diff --git a/config/examples/nxp-t2080.config b/config/examples/nxp-t2080.config index 39e11134fc..6f73724f91 100644 --- a/config/examples/nxp-t2080.config +++ b/config/examples/nxp-t2080.config @@ -124,3 +124,37 @@ WOLFBOOT_LOAD_DTS_ADDRESS?=0x200000 # wolfCrypt Test and Benchmark (requires larger partition size) #WOLFCRYPT_TEST?=1 #WOLFCRYPT_BENCHMARK?=1 + +# ----------------------------------------------------------------------------- +# wolfIP network test in the test-app (optional) +# ----------------------------------------------------------------------------- +# Compiles the wolfIP TCP/IP stack + the NXP QorIQ FMan ethernet port +# (mEMAC/MDIO/SGMII, FM1@DTSEC1) into the test-app and runs a board-side +# network test. Build the app FLAT and 32-bit (ELF=0, OS_64BIT=0) at a low +# load address (WOLFBOOT_LOAD_ADDRESS=0x100000) -- the elf32 load path and +# the 64-bit RTOS handoff are not used here. The wolfIP objects are built +# -fno-plt -D_FORTIFY_SOURCE=0 (the test-app does no PLT/GOT runtime fixup). +# Point WOLFBOOT_LIB_WOLFIP at a wolfIP checkout (or add it as lib/wolfip). +#ENABLE_WOLFIP=1 +#WOLFBOOT_LIB_WOLFIP=../lib/wolfip +# Test mode (default with neither flag = acquire a DHCP lease and stop): +# WOLFBOOT_TEST_TFTP=1 RRQ a file from a host tftpd, report size+checksum +# (set CFLAGS_EXTRA TFTP_EXPECT_SIZE/TFTP_EXPECT_SUM to verify) +# WOLFIP_SPEED_TEST=1 TCP throughput server on port 9 (drive with nc/dd/pv) +#WOLFBOOT_TEST_TFTP=1 +#WOLFIP_SPEED_TEST=1 +# +# Per-board wolfIP ethernet wiring (defaults above are CW VPX3-152 / RDB = +# FM1@DTSEC1, SGMII, PHY probed at addr 0x2). Override per the board device +# tree if the wired port differs: +# +# NAII 68PPC2 (hardware-verified): PRIME port is FM1@DTSEC3 = RGMII with the +# Marvell PHY at MDIO addr 0 (68ppc2.dts ethernet@e4000: phy-connection-type +# "rgmii-id", phy-handle -> ethernet-phy@0 reg <0>). The MDIO scan would +# otherwise grab DTSEC4's PHY at addr 1, so set the address explicitly: +#CFLAGS_EXTRA+=-DNXP_FMAN_MEMAC_IDX=3 +#CFLAGS_EXTRA+=-DNXP_FMAN_IF_SGMII=0 +#CFLAGS_EXTRA+=-DNXP_FMAN_PHY_ADDR=0 +# +# NAII NOR is dual-bank with only the top 128KB boot sector common to both +# banks; flash the ucode/app with the boot-bank select in its runtime state. diff --git a/docs/Targets.md b/docs/Targets.md index d2634cb372..161f4c4f71 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -5918,6 +5918,19 @@ variants are supported: Example configuration: [/config/examples/nxp-t2080.config](/config/examples/nxp-t2080.config). See [Board Selection](#board-selection) below for per-board setup. +> **FMan microcode (DPAA/wolfIP):** when DPAA/FMan is enabled, wolfBoot +> uploads the FMan microcode from NOR at `FMAN_FW_ADDR` (`hal/nxp_t2080.c`). +> This default is board-gated: CW VPX3-152 (256 MB NOR) uses `0xFFE60000`; +> the T2080 RDB and NAII 68PPC2 (128 MB NOR at `0xE8000000`) use `0xEFF00000` +> (just below the wolfBoot region, like the T1040 RDB). The address is +> bounds-checked against the NOR window, so a wrong value fails gracefully +> instead of machine-checking. Flash the matching `fsl_fman_ucode_*` blob at +> that address. wolfIP-on-FMan is hardware-verified on the CW VPX3-152 +> (FM1@DTSEC1, SGMII) and the NAII 68PPC2 (FM1@DTSEC3, RGMII, PHY @ addr 0 -- +> see the wolfIP block in the example config). NAII NOR is dual-bank with only +> the top 128 KB boot sector common to both banks, so flash the ucode/app with +> the boot-bank select in its runtime state. + ### Design NXP T2080 PPC The QorIQ requires a Reset Configuration Word (RCW) to define the boot parameters, which resides at the start of the flash (`0xE8000000` for 128 MB boards, `0xF0000000` for the 256 MB CW VPX3-152). diff --git a/hal/nxp_t10xx.c b/hal/nxp_t10xx.c index 973dcffe46..c263c5177a 100644 --- a/hal/nxp_t10xx.c +++ b/hal/nxp_t10xx.c @@ -3293,9 +3293,9 @@ int hal_flash_write(uint32_t address, const uint8_t *data, int len) for (i=0; iheader; unsigned int i; + /* Guard: FMAN_FW_ADDR must lie inside the NOR flash window, else the + * magic read below faults (machine check) -- e.g. a wrong board's + * address on a smaller NOR. Fail gracefully instead. Compare via the + * offset from the base (not base+size) so the upper bound does not + * overflow uintptr_t on a 256 MB NOR mapped at the top of the 32-bit + * address space (CW VPX3-152: 0xF0000000 + 256 MB wraps to 0). The + * first clause guarantees addr >= base, so the subtraction is safe. */ + if ((uintptr_t)FMAN_FW_ADDR < (uintptr_t)FLASH_BASE_ADDR || + ((uintptr_t)FMAN_FW_ADDR - (uintptr_t)FLASH_BASE_ADDR) >= + (uintptr_t)FLASH_BANK_SIZE) { + wolfBoot_printf("FMAN: fw addr 0x%x outside NOR, skipping\n", + (unsigned)FMAN_FW_ADDR); + return -1; + } + /* Check firmware magic */ if (hdr->magic[0] != 'Q' || hdr->magic[1] != 'E' || hdr->magic[2] != 'F') { wolfBoot_printf("FMAN: no firmware at 0x%x\n", FMAN_FW_ADDR); diff --git a/src/update_ram.c b/src/update_ram.c index 9407e0a93a..5b1089bf24 100644 --- a/src/update_ram.c +++ b/src/update_ram.c @@ -49,7 +49,8 @@ extern uint32_t kernel_load_addr; extern uint32_t dts_load_addr; #if defined(__WOLFBOOT) && defined(WOLFBOOT_LOAD_ADDRESS) -extern uint8_t _end[]; /* linker symbol: end of wolfBoot BSS */ +extern uint8_t _end[]; /* linker symbol: end of wolfBoot BSS */ +extern uint8_t _start_text[]; /* linker symbol: start of wolfBoot text */ #endif #if ((defined(EXT_FLASH) && defined(NO_XIP)) || \ @@ -67,6 +68,9 @@ int wolfBoot_ramboot(struct wolfBoot_image *img, uint8_t *src, uint8_t *dst) { int ret; uint32_t img_size; +#if defined(__WOLFBOOT) && defined(WOLFBOOT_LOAD_ADDRESS) + uint8_t *img_end; +#endif BENCHMARK_DECLARE(); /* read header into RAM */ @@ -114,11 +118,17 @@ int wolfBoot_ramboot(struct wolfBoot_image *img, uint8_t *src, uint8_t *dst) #endif #if defined(__WOLFBOOT) && defined(WOLFBOOT_LOAD_ADDRESS) - /* Runtime overlap check: ensure image destination does not overwrite - * wolfBoot's own code/data/bss in RAM. */ - if ((uintptr_t)dst < (uintptr_t)_end) { - wolfBoot_printf("Error: image dest %p overlaps wolfBoot end %p\n", - dst, _end); + /* Runtime overlap check: ensure the image load region does not intersect + * wolfBoot's own code/data/bss in RAM. Full interval-overlap test (not + * just dst < _end) so it is correct whether wolfBoot is relocated to the + * bottom of RAM (image loads above it) or to the top -- the T1040/T1024 + * two-stage boot relocates wolfBoot near the 2GB DDR top and the image + * loads low. wolfBoot occupies [_start_text, _end]. */ + img_end = dst + IMAGE_HEADER_SIZE + img_size; + if ((uintptr_t)dst < (uintptr_t)_end && + (uintptr_t)img_end > (uintptr_t)_start_text) { + wolfBoot_printf("Error: image %p..%p overlaps wolfBoot %p..%p\n", + dst, img_end, _start_text, _end); return -1; } #endif diff --git a/test-app/Makefile b/test-app/Makefile index a52ef53fa8..1b9e1681fd 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -5,12 +5,15 @@ WOLFBOOT_LIB_WOLFSSL?=../lib/wolfssl WOLFBOOT_LIB_WOLFTPM?=../lib/wolfTPM +WOLFBOOT_LIB_WOLFIP?=../lib/wolfip WOLFSSL_LOCAL_OBJDIR?=wolfssl_obj WOLFTPM_LOCAL_OBJDIR?=wolftpm_obj +WOLFIP_LOCAL_OBJDIR?=wolfip_obj vpath %.c $(WOLFBOOT_LIB_WOLFSSL) vpath %.S $(WOLFBOOT_LIB_WOLFSSL) vpath %.c $(WOLFBOOT_LIB_WOLFTPM) vpath %.S $(WOLFBOOT_LIB_WOLFTPM) +vpath %.c $(WOLFBOOT_LIB_WOLFIP) WOLFBOOT_ROOT?=.. TARGET?=none @@ -593,8 +596,6 @@ ifeq ($(TARGET),nxp_t2080) ifneq ($(SIGN),NONE) APP_OBJS+=../src/keystore.o endif - CFLAGS+=-ffunction-sections -fdata-sections - # PowerPC e6500 PPC64=1 endif @@ -1094,6 +1095,60 @@ endif WOLFSSL_CFLAGS:=$(CFLAGS) WOLFTPM_CFLAGS:=$(CFLAGS) +# Optional wolfIP network stack in the test-app. +# ENABLE_WOLFIP=1 compile the wolfIP ethernet port (nxp_fman) and a +# link/PHY smoke test into the app. +# WOLFBOOT_TEST_TFTP=1 additionally pull in wolfIP core + TFTP client for +# the full network TFTP-fetch test. +# For local iteration point WOLFBOOT_LIB_WOLFIP at a wolfIP checkout, e.g. +# make WOLFBOOT_LIB_WOLFIP=/path/to/wolfip ENABLE_WOLFIP=1 ... +ifeq ($(ENABLE_WOLFIP),1) + # ENABLE_WOLFIP needs a wolfIP checkout at WOLFBOOT_LIB_WOLFIP. Fail early + # with a clear message rather than a confusing compile error later. + ifeq ($(wildcard $(WOLFBOOT_LIB_WOLFIP)/src/wolfip.c),) + $(error ENABLE_WOLFIP=1 but no wolfIP sources found at WOLFBOOT_LIB_WOLFIP=$(WOLFBOOT_LIB_WOLFIP). Set WOLFBOOT_LIB_WOLFIP to a wolfIP checkout, e.g. make WOLFBOOT_LIB_WOLFIP=/path/to/wolfip ENABLE_WOLFIP=1 ...) + endif + # Select the wolfIP ethernet port by target: LS1028A (AArch64) uses the + # ENETC port; the QorIQ PowerPC parts use the FMan port. + ifeq ($(TARGET),nxp_ls1028a) + WOLFIP_PORT:=nxp_enetc + WOLFIP_PORT_OBJ:=nxp_enetc.o + CFLAGS+=-DWOLFIP_PORT_ENETC + else + WOLFIP_PORT:=nxp_fman + WOLFIP_PORT_OBJ:=nxp_fman.o + # The PowerPC test-app is a standalone binary whose _app_entry does no + # BSS-PLT fixup; -mbss-plt (arch.mk) would route cross-module libc calls + # (e.g. variable-size memcpy in the wolfIP driver) through an + # uninitialized PLT stub that branches to 0, and the cross-gcc's default + # _FORTIFY_SOURCE rewrites memcpy/memmove into __memcpy_chk/__memmove_chk + # (glibc symbols absent here -> R_PPC_JMP_SLOT imports with zero GOT + # slots). -fno-plt + fortify-off keep those calls direct and unfortified. + # Scoped to the wolfIP build so default (non-wolfIP) builds are unchanged. + CFLAGS+=-ffunction-sections -fdata-sections + CFLAGS+=-fno-plt -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 + endif + WOLFIP_PORTDIR:=$(WOLFBOOT_LIB_WOLFIP)/src/port/$(WOLFIP_PORT) + CFLAGS+=-DENABLE_WOLFIP + # wolfIP core (wolfip.c) provides the stack incl. DHCP/ICMP/TCP/UDP. + WOLFIP_OBJS:=$(WOLFIP_PORTDIR)/$(WOLFIP_PORT_OBJ) \ + $(WOLFBOOT_LIB_WOLFIP)/src/wolfip.o + ifeq ($(WOLFBOOT_TEST_TFTP),1) + CFLAGS+=-DWOLFBOOT_TEST_TFTP + WOLFIP_OBJS+=$(WOLFBOOT_LIB_WOLFIP)/src/tftp/wolftftp.o + endif + ifeq ($(WOLFIP_SPEED_TEST),1) + CFLAGS+=-DWOLFIP_SPEED_TEST + endif + APP_OBJS+=$(WOLFIP_OBJS) wolfip_tftp_test.o + # wolfIP TUs need the port headers first (so config.h resolves to the + # port copy) and tolerate wolfIP's own style; drop -Werror/-Wstack-usage. + WOLFIP_CFLAGS:=-I"$(WOLFIP_PORTDIR)" -I"$(WOLFBOOT_LIB_WOLFIP)" \ + $(filter-out -Werror -Wstack-usage=$(STACK_USAGE_LIMIT),$(CFLAGS)) \ + -DWOLFIP_ENABLE_TFTP=$(if $(filter 1,$(WOLFBOOT_TEST_TFTP)),1,0) \ + -Wno-unused -Wno-sign-compare -Wno-missing-field-initializers +endif + ifeq ($(WOLFHSM_CLIENT),1) CFLAGS += -DSTRING_USER -I"$(WOLFBOOT_LIB_WOLFSSL)" APP_OBJS += $(WOLFHSM_OBJS) @@ -1128,6 +1183,9 @@ image.srec: image.elf APP_OBJS := $(patsubst $(WOLFBOOT_LIB_WOLFSSL)/%, \ $(WOLFSSL_LOCAL_OBJDIR)/%, $(APP_OBJS)) +APP_OBJS := $(patsubst $(WOLFBOOT_LIB_WOLFIP)/%, \ + $(WOLFIP_LOCAL_OBJDIR)/%, $(APP_OBJS)) + ifeq ($(ELF_FLASH_SCATTER),1) # When ELF_FLASH_SCATTER=1, preprocess the ELF file with the squashelf tool SQUASHELF_TOOL = ../tools/squashelf/squashelf @@ -1194,9 +1252,19 @@ $(WOLFTPM_LOCAL_OBJDIR)/%.o: %.S $(Q)mkdir -p $(dir $@) $(Q)$(CC) $(WOLFTPM_CFLAGS) -c $(OUTPUT_FLAG) $@ $< +$(WOLFIP_LOCAL_OBJDIR)/%.o: %.c + @echo "\t[CC-$(ARCH)] $@" + $(Q)mkdir -p $(dir $@) + $(Q)$(CC) $(WOLFIP_CFLAGS) -c $(OUTPUT_FLAG) $@ $< + +# Local test-app wolfIP glue, built with the wolfIP include/flag set. +wolfip_tftp_test.o: wolfip_tftp_test.c + @echo "\t[CC-$(ARCH)] $@" + $(Q)$(CC) $(WOLFIP_CFLAGS) -c $(OUTPUT_FLAG) $@ $< + clean: $(Q)rm -f *.bin *.elf tags *.o $(LSCRIPT) $(APP_OBJS) wcs/*.o - $(Q)rm -rf $(WOLFSSL_LOCAL_OBJDIR) $(WOLFTPM_LOCAL_OBJDIR) + $(Q)rm -rf $(WOLFSSL_LOCAL_OBJDIR) $(WOLFTPM_LOCAL_OBJDIR) $(WOLFIP_LOCAL_OBJDIR) $(LSCRIPT): $(LSCRIPT_TEMPLATE) FORCE $(Q)printf "%d" $(WOLFBOOT_PARTITION_BOOT_ADDRESS) > .wolfboot-offset diff --git a/test-app/app_nxp_ls1028a.c b/test-app/app_nxp_ls1028a.c index fb0f6af527..d708884a60 100644 --- a/test-app/app_nxp_ls1028a.c +++ b/test-app/app_nxp_ls1028a.c @@ -21,96 +21,38 @@ #include #include "wolfboot/wolfboot.h" +#include "printf.h" -/* P1021 */ -#define CCSRBAR (0x1000000) -#define SYS_CLK (400000000) +#ifdef ENABLE_WOLFIP +#include "wolfip_tftp_test.h" +#endif -/* P1021 PC16552D Dual UART */ -#define BAUD_RATE 115200 -#define UART_SEL 0 /* select UART 0 or 1 */ - -#define UART_BASE(n) (0x21C0500 + (n * 100)) - -#define UART_RBR(n) *((volatile uint8_t*)(UART_BASE(n) + 0)) /* receiver buffer register */ -#define UART_THR(n) *((volatile uint8_t*)(UART_BASE(n) + 0)) /* transmitter holding register */ -#define UART_IER(n) *((volatile uint8_t*)(UART_BASE(n) + 1)) /* interrupt enable register */ -#define UART_FCR(n) *((volatile uint8_t*)(UART_BASE(n) + 2)) /* FIFO control register */ -#define UART_IIR(n) *((volatile uint8_t*)(UART_BASE(n) + 2)) /* interrupt ID register */ -#define UART_LCR(n) *((volatile uint8_t*)(UART_BASE(n) + 3)) /* line control register */ -#define UART_LSR(n) *((volatile uint8_t*)(UART_BASE(n) + 5)) /* line status register */ -#define UART_SCR(n) *((volatile uint8_t*)(UART_BASE(n) + 7)) /* scratch register */ - -/* enabled when UART_LCR_DLAB set */ -#define UART_DLB(n) *((volatile uint8_t*)(UART_BASE(n) + 0)) /* divisor least significant byte register */ -#define UART_DMB(n) *((volatile uint8_t*)(UART_BASE(n) + 1)) /* divisor most significant byte register */ - -#define UART_FCR_TFR (0x04) /* Transmitter FIFO reset */ -#define UART_FCR_RFR (0x02) /* Receiver FIFO reset */ -#define UART_FCR_FEN (0x01) /* FIFO enable */ -#define UART_LCR_DLAB (0x80) /* Divisor latch access bit */ -#define UART_LCR_WLS (0x03) /* Word length select: 8-bits */ -#define UART_LSR_TEMT (0x40) /* Transmitter empty */ -#define UART_LSR_THRE (0x20) /* Transmitter holding register empty */ - -static void uart_init(void) -{ - /* calc divisor for UART - * example config values: - * clock_div, baud, base_clk 163 115200 300000000 - * +0.5 to round up - */ - uint32_t div = (((SYS_CLK / 2.0) / (16 * BAUD_RATE)) + 0.5); - - while (!(UART_LSR(UART_SEL) & UART_LSR_TEMT)) - ; - - /* set ier, fcr, mcr */ - UART_IER(UART_SEL) = 0; - UART_FCR(UART_SEL) = (UART_FCR_TFR | UART_FCR_RFR | UART_FCR_FEN); - - /* enable baud rate access (DLAB=1) - divisor latch access bit*/ - UART_LCR(UART_SEL) = (UART_LCR_DLAB | UART_LCR_WLS); - /* set divisor */ - UART_DLB(UART_SEL) = (div & 0xff); - UART_DMB(UART_SEL) = ((div >> 8) & 0xff); - /* disable rate access (DLAB=0) */ - UART_LCR(UART_SEL) = (UART_LCR_WLS); -} - -static void uart_write(const char* buf, uint32_t sz) -{ - uint32_t pos = 0; - while (sz-- > 0) { - while (!(UART_LSR(UART_SEL) & UART_LSR_THRE)) - ; - UART_THR(UART_SEL) = buf[pos++]; - } -} - -static const char* hex_lut = "0123456789abcdef"; +/* UART is brought up by wolfBoot (hal/nxp_ls1028a.c hal_init). All output + * here goes through wolfBoot_printf(): with DEBUG_UART it routes to the HAL + * uart_write(), and with DEBUG_UART=0 it compiles to a no-op (so the app + * does not depend on uart_write being defined). */ __attribute__((section(".boot"))) void main(void) { int i = 0; int j = 0; - int k = 0; - char snum[8]; - uint32_t bootver; - uint32_t updv; - uart_write("Test App\n", 9); + wolfBoot_printf("Test App\r\n"); - /* Wait for reboot */ - while(1) { - for (j=0; j<1000000; j++); - i++; +#ifdef ENABLE_WOLFIP + wolfBoot_printf("\r\nStarting wolfIP network test...\r\n"); + if (wolfip_tftp_test_run() == 0) + wolfBoot_printf("WOLFIP_TEST: PASS\r\n"); + else + wolfBoot_printf("WOLFIP_TEST: FAIL\r\n"); +#endif - uart_write("\r\n0x", 4); - for (k=0; k<8; k++) { - snum[7 - k] = hex_lut[(i >> 4*k) & 0xf]; - } - uart_write(snum, 8); + /* Wait for reboot, printing a liveness counter. */ + while (1) { + for (j = 0; j < 1000000; j++) + ; + i++; + wolfBoot_printf("\r\n0x%x", (unsigned)i); } } diff --git a/test-app/app_nxp_t1024.c b/test-app/app_nxp_t1024.c index 8e511b5af8..842972cf00 100644 --- a/test-app/app_nxp_t1024.c +++ b/test-app/app_nxp_t1024.c @@ -73,6 +73,10 @@ __asm__ ( #include "../hal/nxp_ppc.h" +#ifdef ENABLE_WOLFIP +#include "wolfip_tftp_test.h" +#endif + static uint8_t boot_part_state = IMG_STATE_NEW; static uint8_t update_part_state = IMG_STATE_NEW; @@ -174,6 +178,14 @@ void main(void) wolfBoot_success(); wolfBoot_printf("\r\nBoot partition marked successful\r\n"); +#ifdef ENABLE_WOLFIP + wolfBoot_printf("\r\nStarting wolfIP network test...\r\n"); + if (wolfip_tftp_test_run() == 0) + wolfBoot_printf("WOLFIP_TEST: PASS\r\n"); + else + wolfBoot_printf("WOLFIP_TEST: FAIL\r\n"); +#endif + wolfBoot_printf("Test App: idle loop\r\n"); while(1) { /* Idle */ diff --git a/test-app/app_nxp_t1040.c b/test-app/app_nxp_t1040.c index c58e586416..e31eac9232 100644 --- a/test-app/app_nxp_t1040.c +++ b/test-app/app_nxp_t1040.c @@ -73,6 +73,10 @@ __asm__ ( #include "../hal/nxp_ppc.h" +#ifdef ENABLE_WOLFIP +#include "wolfip_tftp_test.h" +#endif + static uint8_t boot_part_state = IMG_STATE_NEW; static uint8_t update_part_state = IMG_STATE_NEW; @@ -174,6 +178,14 @@ void main(void) wolfBoot_success(); wolfBoot_printf("\r\nBoot partition marked successful\r\n"); +#ifdef ENABLE_WOLFIP + wolfBoot_printf("\r\nStarting wolfIP network test...\r\n"); + if (wolfip_tftp_test_run() == 0) + wolfBoot_printf("WOLFIP_TEST: PASS\r\n"); + else + wolfBoot_printf("WOLFIP_TEST: FAIL\r\n"); +#endif + wolfBoot_printf("Test App: idle loop\r\n"); while(1) { /* Idle */ diff --git a/test-app/app_nxp_t2080.c b/test-app/app_nxp_t2080.c index 7167cc70b4..702d7a09e5 100644 --- a/test-app/app_nxp_t2080.c +++ b/test-app/app_nxp_t2080.c @@ -51,6 +51,10 @@ void __attribute__((naked, section(".text._app_entry"))) _app_entry(void) #include "../hal/nxp_ppc.h" +#ifdef ENABLE_WOLFIP +#include "wolfip_tftp_test.h" +#endif + /* wolfCrypt test/benchmark support */ #ifdef WOLFCRYPT_TEST #include @@ -177,6 +181,14 @@ void main(void) wolfCrypt_Cleanup(); #endif +#ifdef ENABLE_WOLFIP + wolfBoot_printf("\r\nStarting wolfIP network test...\r\n"); + if (wolfip_tftp_test_run() == 0) + wolfBoot_printf("WOLFIP_TEST: PASS\r\n"); + else + wolfBoot_printf("WOLFIP_TEST: FAIL\r\n"); +#endif + wolfBoot_printf("Test App: idle loop\r\n"); while(1) { /* Idle */ diff --git a/test-app/wolfip_tftp_test.c b/test-app/wolfip_tftp_test.c new file mode 100644 index 0000000000..e77e1ca9ca --- /dev/null +++ b/test-app/wolfip_tftp_test.c @@ -0,0 +1,501 @@ +/* wolfip_tftp_test.c + * + * Optional wolfIP network test for the wolfBoot test-app. Targets the NXP + * QorIQ FMan ports (T2080 / T1024 / T1040, big-endian PowerPC) and the NXP + * Layerscape ENETC port (LS1028A, AArch64) -- the ethernet port and the ms + * timebase are selected at compile time. Modes (compile-time): + * default DHCP lease (C6) + * WOLFBOOT_TEST_TFTP + TFTP RRQ fetch into RAM, report size+checksum + * (optionally verify them via TFTP_EXPECT_SIZE/SUM) + * WOLFIP_SPEED_TEST + TCP throughput server on port 9 (benchmark) + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include +#include + +#include "printf.h" +#include "wolfip.h" +#ifdef WOLFBOOT_TEST_TFTP +#include "src/tftp/wolftftp.h" +#endif + +/* Ethernet port selection. WOLFIP_PORT_ENETC -> the LS1028A ENETC port; + * otherwise the QorIQ FMan port. The driver entry points are wrapped so the + * bring-up code below is port-agnostic. */ +#if defined(WOLFIP_PORT_ENETC) +#include "nxp_enetc.h" +#define WOLFIP_NETDEV_INIT nxp_enetc_init +#define WOLFIP_NETDEV_PHY_ADDR nxp_enetc_phy_addr +#define WOLFIP_NETDEV_PHY_READ nxp_enetc_phy_read +#define WOLFIP_NETDEV_LINK_UP nxp_enetc_link_up +#define WOLFIP_NETDEV_NAME "ENETC" +#else +#include "nxp_fman.h" +#define WOLFIP_NETDEV_INIT nxp_fman_init +#define WOLFIP_NETDEV_PHY_ADDR nxp_fman_phy_addr +#define WOLFIP_NETDEV_PHY_READ nxp_fman_phy_read +#define WOLFIP_NETDEV_PHY_READ_AT nxp_fman_phy_read_at +#define WOLFIP_NETDEV_LINK_UP nxp_fman_link_up +#define WOLFIP_NETDEV_NAME "FMan mEMAC" +#endif + +/* Host running in.tftpd / the throughput peer (same subnet as the DHCP + * lease). Defaults to the lab rig; override from the build config, e.g. + * CFLAGS_EXTRA+=-DHOST_IP_STR='"192.168.1.5"' -DTFTP_FILENAME='"img.bin"'. */ +#ifndef HOST_IP_STR +#define HOST_IP_STR "10.0.4.24" +#endif +#ifndef TFTP_FILENAME +#define TFTP_FILENAME "wolfip_test.bin" +#endif +/* Optional integrity check. When non-zero, the fetched byte count and/or + * additive 32-bit checksum must match these values or the test FAILS; + * 0 (default) reports the measured size/checksum without comparing. Set from + * the build config, e.g. CFLAGS_EXTRA+=-DTFTP_EXPECT_SIZE=8192 + * -DTFTP_EXPECT_SUM=0xFF000. */ +#ifndef TFTP_EXPECT_SIZE +#define TFTP_EXPECT_SIZE 0U +#endif +#ifndef TFTP_EXPECT_SUM +#define TFTP_EXPECT_SUM 0U +#endif + +/* Millisecond clock from a free-running counter, self-contained (no + * bootloader symbol). wolfIP timers are coarse so exactness is moot. */ +#if defined(__aarch64__) +/* ARMv8 generic timer: CNTPCT_EL0 counts at CNTFRQ_EL0 Hz. */ +static uint64_t read_tb(void) +{ + uint64_t v; + __asm__ __volatile__("isb; mrs %0, cntpct_el0" : "=r"(v)); + return v; +} +static uint64_t tb_hz(void) +{ + uint64_t f; + __asm__ __volatile__("mrs %0, cntfrq_el0" : "=r"(f)); + return f ? f : 25000000ULL; /* LS1028A SYSCLK-derived default */ +} +static uint64_t now_ms(void) +{ + return read_tb() / (tb_hz() / 1000ULL); +} +#else +/* PowerPC e5500/e6500 Time Base via SPRs (TBL=268, TBU=269). The timebase + * is the platform clock / 16; the default is the VPX3-152 value (600 MHz -> + * 37.5 MHz). Boards with a different platform clock MUST override this (it + * scales not just the harness timeouts but the wolfIP TCP/DHCP timers fed by + * now_ms), e.g. CFLAGS_EXTRA+=-DTIMEBASE_HZ=50000000ULL. */ +#ifndef TIMEBASE_HZ +#define TIMEBASE_HZ 37500000ULL +#endif + +static uint64_t read_tb(void) +{ + uint32_t hi, lo, hi2; + do { + __asm__ __volatile__("mfspr %0, 269" : "=r"(hi)); + __asm__ __volatile__("mfspr %0, 268" : "=r"(lo)); + __asm__ __volatile__("mfspr %0, 269" : "=r"(hi2)); + } while (hi != hi2); + return ((uint64_t)hi << 32) | lo; +} + +static uint64_t now_ms(void) +{ + return (uint64_t)(read_tb() / (TIMEBASE_HZ / 1000ULL)); +} +#endif + +/* wolfIP needs an RNG (TCP ISN, DHCP xid, ephemeral ports). LFSR seeded + * from the free-running timebase. NOT cryptographic. */ +uint32_t wolfIP_getrandom(void) +{ + static uint32_t lfsr; + if (lfsr == 0) + lfsr = (uint32_t)read_tb() | 1U; + lfsr ^= (uint32_t)read_tb(); + lfsr ^= lfsr << 13; + lfsr ^= lfsr >> 17; + lfsr ^= lfsr << 5; + return lfsr; +} + +#define DHCP_TIMEOUT_MS 30000ULL + +/* Bring up the driver + wolfIP + DHCP. Returns the stack on a bound lease, + * NULL on failure. Prints PHY/link and the lease. */ +static struct wolfIP *wolfip_bringup(void) +{ + struct wolfIP *s = NULL; + struct wolfIP_ll_dev *ll; + uint64_t start, now; + ip4 ip = 0, nm = 0, gw = 0; + int rc, addr; + uint16_t id1, bsr; + + wolfIP_init_static(&s); + ll = wolfIP_getdev(s); + + wolfBoot_printf("wolfIP: bringing up %s\r\n", WOLFIP_NETDEV_NAME); + rc = WOLFIP_NETDEV_INIT(ll, NULL); + if (rc < 0) { + wolfBoot_printf("wolfIP: netdev init failed rc=%d\r\n", rc); + return NULL; + } + addr = WOLFIP_NETDEV_PHY_ADDR(); + id1 = WOLFIP_NETDEV_PHY_READ(0x02); + bsr = WOLFIP_NETDEV_PHY_READ(0x01); + wolfBoot_printf("wolfIP: PHY addr=%d ID1=0x%x BSR=0x%x link=%s\r\n", + addr, id1, bsr, WOLFIP_NETDEV_LINK_UP() ? "UP" : "down"); + +#if defined(WOLFIP_PHY_SCAN) && defined(WOLFIP_NETDEV_PHY_READ_AT) + /* MDIO bus scan: print ID1/ID2/BSR for every clause-22 address so the + * cabled port can be identified (BSR bit 2 = link up). Diagnostic only -- + * enable with CFLAGS_EXTRA+=-DWOLFIP_PHY_SCAN. */ + { + int a; + uint16_t i1, i2, bs; + wolfBoot_printf("wolfIP: MDIO scan (addr: ID1 ID2 BSR link)\r\n"); + for (a = 0; a < 32; a++) { + i1 = WOLFIP_NETDEV_PHY_READ_AT((uint8_t)a, 0x02); + if (i1 == 0xFFFFU || i1 == 0x0000U) + continue; /* no PHY at this address */ + i2 = WOLFIP_NETDEV_PHY_READ_AT((uint8_t)a, 0x03); + bs = WOLFIP_NETDEV_PHY_READ_AT((uint8_t)a, 0x01); + wolfBoot_printf(" %d: 0x%x 0x%x 0x%x %s\r\n", + a, i1, i2, bs, (bs & 0x0004U) ? "UP" : "down"); + } + } +#endif + + (void)wolfIP_poll(s, now_ms()); + wolfBoot_printf("wolfIP: starting DHCP...\r\n"); + (void)dhcp_client_init(s); + + start = now_ms(); + for (;;) { + now = now_ms(); + (void)wolfIP_poll(s, now); + if (dhcp_bound(s)) { + wolfIP_ipconfig_get(s, &ip, &nm, &gw); + wolfBoot_printf("wolfIP: DHCP bound ip=%u.%u.%u.%u gw=%u.%u.%u.%u\r\n", + (unsigned)((ip >> 24) & 0xFF), (unsigned)((ip >> 16) & 0xFF), + (unsigned)((ip >> 8) & 0xFF), (unsigned)(ip & 0xFF), + (unsigned)((gw >> 24) & 0xFF), (unsigned)((gw >> 16) & 0xFF), + (unsigned)((gw >> 8) & 0xFF), (unsigned)(gw & 0xFF)); + return s; + } + if ((now - start) > DHCP_TIMEOUT_MS) { + wolfBoot_printf("wolfIP: DHCP timed out\r\n"); + return NULL; + } + } +} + +#ifdef WOLFBOOT_TEST_TFTP +/* ---- C7/C8: TFTP RRQ fetch into a RAM buffer + integrity check ------- */ +#define TFTP_RAM_MAX (128U * 1024U) +#define TFTP_LOCAL_PORT 6900U + +struct tftp_ram_ctx { + uint8_t buf[TFTP_RAM_MAX]; + uint32_t len; /* highest offset+len written */ + uint32_t sum; /* additive 32-bit checksum of all bytes */ + int overflow; +}; +static struct tftp_ram_ctx g_tftp; + +struct tftp_glue { struct wolfIP *s; int sock; }; + +static int tftp_io_open(void *arg, const char *name, int is_write, + uint32_t *size_hint, void **handle) +{ + (void)name; (void)is_write; (void)size_hint; + g_tftp.len = 0; + g_tftp.sum = 0; + g_tftp.overflow = 0; + *handle = &g_tftp; + return 0; +} + +static int tftp_io_write(void *arg, void *handle, uint32_t offset, + const uint8_t *buf, uint16_t len) +{ + struct tftp_ram_ctx *c = (struct tftp_ram_ctx *)handle; + uint16_t i; + (void)arg; + /* Overflow-safe bounds check: never compute offset+len (could wrap a + * 32-bit offset). Compare against the remaining space instead. */ + if (offset > TFTP_RAM_MAX || len > TFTP_RAM_MAX - offset) { + c->overflow = 1; + return -1; + } + for (i = 0; i < len; i++) { + c->buf[offset + i] = buf[i]; + c->sum += buf[i]; + } + if (offset + len > c->len) + c->len = offset + len; + return 0; +} + +static int tftp_send(void *arg, uint16_t local_port, + const struct wolftftp_endpoint *remote, const uint8_t *buf, uint16_t len) +{ + struct tftp_glue *g = (struct tftp_glue *)arg; + struct wolfIP_sockaddr_in dst; + int ret, i; + (void)local_port; + for (i = 0; i < (int)sizeof(dst); i++) + ((uint8_t *)&dst)[i] = 0; + dst.sin_family = AF_INET; + dst.sin_port = ee16(remote->port); + dst.sin_addr.s_addr = ee32(remote->ip); + ret = wolfIP_sock_sendto(g->s, g->sock, buf, len, 0, + (struct wolfIP_sockaddr *)&dst, sizeof(dst)); + return (ret == (int)len) ? 0 : (ret < 0 ? ret : -1); +} + +static int run_tftp_fetch(struct wolfIP *s) +{ + struct tftp_glue glue; + struct wolftftp_transport_ops transport; + struct wolftftp_io_ops io; + struct wolftftp_transfer_cfg cfg; + struct wolftftp_client client; + struct wolftftp_endpoint srv; + struct wolfIP_sockaddr_in bind_addr; + uint8_t pkt[1500]; + int sock, i, ret = -1; + uint64_t deadline; + + sock = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_DGRAM, 0); + if (sock < 0) { + wolfBoot_printf("TFTP: udp socket failed\r\n"); + return -1; + } + for (i = 0; i < (int)sizeof(bind_addr); i++) + ((uint8_t *)&bind_addr)[i] = 0; + bind_addr.sin_family = AF_INET; + bind_addr.sin_port = ee16(TFTP_LOCAL_PORT); + (void)wolfIP_sock_bind(s, sock, (struct wolfIP_sockaddr *)&bind_addr, + sizeof(bind_addr)); + + glue.s = s; glue.sock = sock; + for (i = 0; i < (int)sizeof(transport); i++) ((uint8_t *)&transport)[i] = 0; + transport.send = tftp_send; + transport.arg = &glue; + for (i = 0; i < (int)sizeof(io); i++) ((uint8_t *)&io)[i] = 0; + io.open = tftp_io_open; + io.write = tftp_io_write; + io.arg = &g_tftp; + for (i = 0; i < (int)sizeof(cfg); i++) ((uint8_t *)&cfg)[i] = 0; + cfg.local_port = TFTP_LOCAL_PORT; + cfg.blksize = WOLFTFTP_DEFAULT_BLKSIZE; + cfg.timeout_s = WOLFTFTP_DEFAULT_TIMEOUT_S; + cfg.windowsize = 1; + cfg.max_retries = 5; + + wolftftp_client_init(&client, &transport, &io, &cfg); + for (i = 0; i < (int)sizeof(srv); i++) ((uint8_t *)&srv)[i] = 0; + srv.ip = atoip4(HOST_IP_STR); + srv.port = 69; + + wolfBoot_printf("TFTP: RRQ %s from %s\r\n", TFTP_FILENAME, HOST_IP_STR); + if (wolftftp_client_start_rrq(&client, &srv, TFTP_FILENAME) != 0) { + wolfBoot_printf("TFTP: start_rrq failed\r\n"); + goto out; + } + + deadline = now_ms() + 20000ULL; + while (client.state != WOLFTFTP_CLIENT_COMPLETE && + client.state != WOLFTFTP_CLIENT_ERROR && + now_ms() < deadline) { + struct wolfIP_sockaddr_in rem; + uint32_t rlen; + int n; + (void)wolfIP_poll(s, now_ms()); + for (;;) { + rlen = sizeof(rem); + n = wolfIP_sock_recvfrom(s, sock, pkt, sizeof(pkt), 0, + (struct wolfIP_sockaddr *)&rem, &rlen); + if (n <= 0) + break; + { + struct wolftftp_endpoint rep; + rep.ip = ee32(rem.sin_addr.s_addr); + rep.port = ee16(rem.sin_port); + (void)wolftftp_client_receive(&client, TFTP_LOCAL_PORT, + &rep, pkt, (uint16_t)n); + } + } + (void)wolftftp_client_poll(&client, (uint32_t)now_ms()); + } + + if (client.state != WOLFTFTP_CLIENT_COMPLETE) { + wolfBoot_printf("TFTP: FAILED (state=%d status=%d)\r\n", + client.state, client.last_status); + goto out; + } + if (g_tftp.overflow) { + wolfBoot_printf("TFTP: file exceeds %u byte RAM buffer\r\n", TFTP_RAM_MAX); + goto out; + } + wolfBoot_printf("TFTP: got %u bytes, checksum 0x%x\r\n", + (unsigned)g_tftp.len, (unsigned)g_tftp.sum); +#if (TFTP_EXPECT_SIZE != 0U) + if (g_tftp.len != (uint32_t)TFTP_EXPECT_SIZE) { + wolfBoot_printf("TFTP: size mismatch (expected %u)\r\n", + (unsigned)TFTP_EXPECT_SIZE); + goto out; + } +#endif +#if (TFTP_EXPECT_SUM != 0U) + if (g_tftp.sum != (uint32_t)TFTP_EXPECT_SUM) { + wolfBoot_printf("TFTP: checksum mismatch (expected 0x%x)\r\n", + (unsigned)TFTP_EXPECT_SUM); + goto out; + } +#endif + ret = 0; + +out: + (void)wolfIP_sock_close(s, sock); + return ret; +} +#endif /* WOLFBOOT_TEST_TFTP */ + +#ifdef WOLFIP_SPEED_TEST +/* ---- Benchmark: one-connection TCP throughput server on port 9 ------- * + * Mirrors the AMD port_amd_fpga SPEED_TEST. RX sinks everything the peer + * sends; TX pushes a chargen buffer whenever writable. Prints B/s on close. + * RX (board sinks): dd if=/dev/zero bs=1460 count=N | nc 9 + * TX (board sources): nc 9 /dev/null */ +#define SPEED_PORT 9 +static int speed_listen_fd = -1; +static int speed_client_fd = -1; +static uint64_t speed_rx_bytes, speed_tx_bytes, speed_start_ms; +static uint8_t speed_buf[1460]; + +static void speed_print(void) +{ + uint64_t ms = now_ms() - speed_start_ms; + if (ms == 0) ms = 1; + wolfBoot_printf("SPEED done %ums RX %u B (~%u B/s) TX %u B (~%u B/s)\r\n", + (unsigned)ms, (unsigned)speed_rx_bytes, + (unsigned)((speed_rx_bytes * 1000ULL) / ms), + (unsigned)speed_tx_bytes, + (unsigned)((speed_tx_bytes * 1000ULL) / ms)); +} + +static void speed_cb(int fd, uint16_t event, void *arg) +{ + struct wolfIP *s = (struct wolfIP *)arg; + int n, k; + + if (fd == speed_listen_fd) { + if (event & CB_EVENT_READABLE) { + int c = wolfIP_sock_accept(s, speed_listen_fd, NULL, NULL); + if (c >= 0) { + if (speed_client_fd >= 0) { + (void)wolfIP_sock_close(s, c); + } else { + speed_client_fd = c; + speed_rx_bytes = 0; speed_tx_bytes = 0; + speed_start_ms = now_ms(); + wolfIP_register_callback(s, c, speed_cb, s); + wolfBoot_printf("SPEED client connected\r\n"); + } + } + } + return; + } + if (fd != speed_client_fd) + return; + + if (event & CB_EVENT_READABLE) { + k = 0; + do { + n = wolfIP_sock_recvfrom(s, fd, speed_buf, sizeof(speed_buf), 0, + NULL, NULL); + if (n > 0) + speed_rx_bytes += (uint64_t)n; + } while (n > 0 && ++k < 32); + } + if (event & CB_EVENT_WRITABLE) { + k = 0; + do { + n = wolfIP_sock_send(s, fd, speed_buf, sizeof(speed_buf), 0); + if (n > 0) + speed_tx_bytes += (uint64_t)n; + } while (n > 0 && ++k < 32); + } + if (event & CB_EVENT_CLOSED) { + speed_print(); + (void)wolfIP_sock_close(s, fd); + speed_client_fd = -1; + } +} + +static int run_speed_server(struct wolfIP *s) +{ + struct wolfIP_sockaddr_in addr; + int i; + + speed_listen_fd = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0); + if (speed_listen_fd < 0) { + wolfBoot_printf("SPEED: socket failed\r\n"); + return -1; + } + wolfIP_register_callback(s, speed_listen_fd, speed_cb, s); + for (i = 0; i < (int)sizeof(addr); i++) ((uint8_t *)&addr)[i] = 0; + addr.sin_family = AF_INET; + addr.sin_port = ee16(SPEED_PORT); + (void)wolfIP_sock_bind(s, speed_listen_fd, + (struct wolfIP_sockaddr *)&addr, sizeof(addr)); + (void)wolfIP_sock_listen(s, speed_listen_fd, 1); + + wolfBoot_printf("SPEED: TCP throughput server on port %d. Drive from host:\r\n", + SPEED_PORT); + wolfBoot_printf(" RX: dd if=/dev/zero bs=1460 count=20000 | nc %d\r\n", + SPEED_PORT); + wolfBoot_printf(" TX: nc %d /dev/null\r\n", + SPEED_PORT); + for (;;) + (void)wolfIP_poll(s, now_ms()); + /* not reached */ +} +#endif /* WOLFIP_SPEED_TEST */ + +int wolfip_tftp_test_run(void) +{ + struct wolfIP *s = wolfip_bringup(); + if (s == NULL) + return -1; +#if defined(WOLFBOOT_TEST_TFTP) + return run_tftp_fetch(s); +#elif defined(WOLFIP_SPEED_TEST) + return run_speed_server(s); /* loops forever */ +#else + return 0; /* C6: DHCP only */ +#endif +} diff --git a/test-app/wolfip_tftp_test.h b/test-app/wolfip_tftp_test.h new file mode 100644 index 0000000000..e1e96202d3 --- /dev/null +++ b/test-app/wolfip_tftp_test.h @@ -0,0 +1,31 @@ +/* wolfip_tftp_test.h + * + * Optional wolfIP network test entry for the wolfBoot test-app. + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#ifndef WOLFIP_TFTP_TEST_H +#define WOLFIP_TFTP_TEST_H + +/* Run the wolfIP network test. Returns 0 on success, negative on failure. + * Without WOLFBOOT_TEST_TFTP this is a link/PHY bring-up smoke test; + * with WOLFBOOT_TEST_TFTP it performs a full TFTP fetch and verify. */ +int wolfip_tftp_test_run(void); + +#endif /* WOLFIP_TFTP_TEST_H */ diff --git a/tools/scripts/nxp_t1040/t1040_flash.cmm b/tools/scripts/nxp_t1040/t1040_flash.cmm index cac80d7e3f..b12c33f205 100644 --- a/tools/scripts/nxp_t1040/t1040_flash.cmm +++ b/tools/scripts/nxp_t1040/t1040_flash.cmm @@ -28,12 +28,12 @@ ; Base directory for wolfBoot build output. "." means the TRACE32 current ; working directory - set this to your wolfBoot checkout path if running ; TRACE32 from elsewhere (e.g. "C:/src/wolfBoot" or "/home/user/wolfBoot"). -&basedir="." +&basedir="/home/davidgarske/GitHub/wolfboot-alt" ; Persistent backup directory (survives make clean). Leave as "." to keep ; artifacts alongside the build tree, or point elsewhere to preserve ; signed/backup images across source cleans. -&backupdir="." +&backupdir="/home/davidgarske/GitHub/wolfboot-alt" ; FLASH Number of banks ; The JS28F00AM29EWHA is a single 128MB NOR chip. CPLD virtual banking @@ -59,36 +59,24 @@ SYStem.DETECT CPU CORE.ASSIGN 1. SYStem.Option.FREEZE OFF -; Use RCW override to prevent flash RCW from running before we are ready. -; This keeps the system halted for configuration. -PRINT "Initializing with temporary RCW override..." -SYStem.Mode.Prepare - -SYStem.Option.HRCWOVerRide ON - -; Load RCW (T1040D4RDB values extracted from factory flash) -Data.Set DBG:0x01000000 0x0c18000e -Data.Set DBG:0x01000001 0x0e000000 -Data.Set DBG:0x01000002 0x00000000 -Data.Set DBG:0x01000003 0x00000000 -Data.Set DBG:0x01000004 0x66000002 -Data.Set DBG:0x01000005 0x40000002 -Data.Set DBG:0x01000006 0xec027000 -Data.Set DBG:0x01000007 0x01000000 -Data.Set DBG:0x01000008 0x00000000 -Data.Set DBG:0x01000009 0x00000000 -Data.Set DBG:0x0100000A 0x00000000 -Data.Set DBG:0x0100000B 0x00030810 -Data.Set DBG:0x0100000C 0x00000000 -Data.Set DBG:0x0100000D 0x0342580f -Data.Set DBG:0x0100000E 0x00000000 -Data.Set DBG:0x0100000F 0x00000000 - +; RCW handling. On a BARE board with no valid RCW, a hard RCW override holds +; the core in a clean pre-boot state. But a board that already has a valid RCW +; in NOR (this T1040D4RDB boots) rejects the hard override -- it fails with +; "RCW override finished without success ... debug port fail". For that case +; use a plain SYStem.Up: the NOR RCW runs (clocks/DDR come up) and TRACE32 +; halts the core at the reset vector. The flash algorithm runs from CPC-SRAM, +; so erasing/reprogramming NOR with the core halted is safe. +; (For a BARE board with no valid RCW, restore a hard RCW override here: +; SYStem.Mode.Prepare ; SYStem.Option.HRCWOVerRide ON +; write the 16 RCW words to DBG:0x01000000..0x0100000F ; SYStem.Up +; SYStem.Option.HRCWOVerRide OFF +; The T1040D4RDB RCW words are preserved in this file's git history. The hard +; override FAILS on a board that already has a valid NOR RCW -- "RCW override +; finished without success ... debug port fail" -- so this board uses a plain +; SYStem.Up instead.) +PRINT "Attaching to running target (using the valid NOR RCW)..." SYStem.Up - -SYStem.Option.HRCWOVerRide OFF - -PRINT "System initialized (halted state with temporary RCW)" +PRINT "System halted for flashing (NOR RCW applied)" ; Set CCSRBAR to 0x40000000 Data.Set ANC:IOBASE()+0x00004 %Long 0x40000000