From 57fb42b7650358e4d3da4bd1c01fc50c12fbe1b2 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 15 Jun 2026 16:21:30 -0700 Subject: [PATCH 1/6] Add NXP QorIQ T2080 wolfIP network test to the test-app --- config/examples/nxp-t2080.config | 18 ++ test-app/Makefile | 57 ++++- test-app/app_nxp_t2080.c | 12 + test-app/wolfip_tftp_test.c | 399 +++++++++++++++++++++++++++++++ test-app/wolfip_tftp_test.h | 31 +++ 5 files changed, 516 insertions(+), 1 deletion(-) create mode 100644 test-app/wolfip_tftp_test.c create mode 100644 test-app/wolfip_tftp_test.h diff --git a/config/examples/nxp-t2080.config b/config/examples/nxp-t2080.config index 39e11134fc..27d930b7f7 100644 --- a/config/examples/nxp-t2080.config +++ b/config/examples/nxp-t2080.config @@ -124,3 +124,21 @@ 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, verify size+checksum +# 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/test-app/Makefile b/test-app/Makefile index a52ef53fa8..74ae6c50c7 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 @@ -594,6 +597,16 @@ ifeq ($(TARGET),nxp_t2080) APP_OBJS+=../src/keystore.o endif CFLAGS+=-ffunction-sections -fdata-sections + # The 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. -fno-plt makes those calls direct. + CFLAGS+=-fno-plt + # The cross-gcc defaults _FORTIFY_SOURCE on, which rewrites memcpy/memmove + # into __memcpy_chk/__memmove_chk -- glibc symbols absent from this + # freestanding binary, so the linker emits R_PPC_JMP_SLOT imports with + # zero GOT slots that branch to 0. Disable fortify for the bare-metal app. + CFLAGS+=-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 # PowerPC e6500 PPC64=1 @@ -1094,6 +1107,35 @@ 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) + WOLFIP_PORTDIR:=$(WOLFBOOT_LIB_WOLFIP)/src/port/nxp_fman + CFLAGS+=-DENABLE_WOLFIP + # wolfIP core (wolfip.c) provides the stack incl. DHCP/ICMP/TCP/UDP. + WOLFIP_OBJS:=$(WOLFIP_PORTDIR)/nxp_fman.o \ + $(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 +1170,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 +1239,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_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..74d2664345 --- /dev/null +++ b/test-app/wolfip_tftp_test.c @@ -0,0 +1,399 @@ +/* wolfip_tftp_test.c + * + * Optional wolfIP network test for the wolfBoot test-app on NXP QorIQ + * (T2080 / T1024 / T1040) boards. Modes (compile-time): + * default DHCP lease (C6) + * WOLFBOOT_TEST_TFTP + TFTP RRQ fetch into RAM and verify (C7/C8) + * 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 "nxp_fman.h" +#include "wolfip.h" +#ifdef WOLFBOOT_TEST_TFTP +#include "src/tftp/wolftftp.h" +#endif + +/* Host running in.tftpd / the throughput peer (same subnet as the DHCP + * lease). 10.0.4.24 on the lab rig. */ +#define HOST_IP_STR "10.0.4.24" +#define TFTP_FILENAME "wolfip_test.bin" + +/* e6500 timebase = platform clock / 16 (VPX3-152: 600 MHz -> 37.5 MHz). + * Read the 64-bit Time Base via the SPRs (TBL=268, TBU=269); self-contained + * (no bootloader symbol). wolfIP timers are coarse so exactness is moot. */ +#define TIMEBASE_HZ 37500000ULL + +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)); +} + +/* 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 FMan mEMAC%d\r\n", NXP_FMAN_MEMAC_IDX); + rc = nxp_fman_init(ll, NULL); + if (rc < 0) { + wolfBoot_printf("wolfIP: nxp_fman_init failed rc=%d\r\n", rc); + return NULL; + } + addr = nxp_fman_phy_addr(); + id1 = nxp_fman_phy_read(0x02); + bsr = nxp_fman_phy_read(0x01); + wolfBoot_printf("wolfIP: PHY addr=%d ID1=0x%x BSR=0x%x link=%s\r\n", + addr, id1, bsr, nxp_fman_link_up() ? "UP" : "down"); + + (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; + if ((uint32_t)offset + len > TFTP_RAM_MAX) { + 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; + 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"); + return -1; + } + + 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); + return -1; + } + if (g_tftp.overflow) { + wolfBoot_printf("TFTP: file exceeds %u byte RAM buffer\r\n", TFTP_RAM_MAX); + return -1; + } + wolfBoot_printf("TFTP: got %u bytes, checksum 0x%x\r\n", + (unsigned)g_tftp.len, (unsigned)g_tftp.sum); + return 0; +} +#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 struct wolfIP *g_speed_stack; +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; + + g_speed_stack = s; + 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 */ From 0c64ce5327e1dd4ce687dfbde7e050878aa9e022 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 15 Jun 2026 16:29:45 -0700 Subject: [PATCH 2/6] Add NXP QorIQ T1040 wolfIP network test to the test-app --- config/examples/nxp-t1040.config | 24 ++++++++++++++++++++++++ test-app/Makefile | 8 ++++++++ test-app/app_nxp_t1040.c | 12 ++++++++++++ 3 files changed, 44 insertions(+) diff --git a/config/examples/nxp-t1040.config b/config/examples/nxp-t1040.config index 317eb470ef..497bdad037 100644 --- a/config/examples/nxp-t1040.config +++ b/config/examples/nxp-t1040.config @@ -65,3 +65,27 @@ 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 +# Set the PHY interface for the T1040 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, verify size+checksum +# 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/test-app/Makefile b/test-app/Makefile index 74ae6c50c7..c648e2f67e 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -616,6 +616,10 @@ ifeq ($(TARGET),nxp_t1024) ifneq ($(SIGN),NONE) APP_OBJS+=../src/keystore.o endif + CFLAGS+=-ffunction-sections -fdata-sections + # Bare-metal app does no PLT/GOT fixup; keep cross-module libc calls direct + # and avoid fortified __memcpy_chk glibc imports (see nxp_t2080 block). + CFLAGS+=-fno-plt -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 # PowerPC e5500 PPC64=1 endif @@ -623,6 +627,10 @@ ifeq ($(TARGET),nxp_t1040) ifneq ($(SIGN),NONE) APP_OBJS+=../src/keystore.o endif + CFLAGS+=-ffunction-sections -fdata-sections + # Bare-metal app does no PLT/GOT fixup; keep cross-module libc calls direct + # and avoid fortified __memcpy_chk glibc imports (see nxp_t2080 block). + CFLAGS+=-fno-plt -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 # PowerPC e5500 PPC64=1 endif 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 */ From 4cdecfa79c59a0405fa18984bd3166cced73e3d4 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 16 Jun 2026 11:02:08 -0700 Subject: [PATCH 3/6] Add NXP QorIQ T1024 wolfIP network test to the test-app --- config/examples/nxp-t1024.config | 24 ++++++++++++++++++++++++ test-app/app_nxp_t1024.c | 12 ++++++++++++ 2 files changed, 36 insertions(+) diff --git a/config/examples/nxp-t1024.config b/config/examples/nxp-t1024.config index 8cbd033897..ed656dcc4a 100644 --- a/config/examples/nxp-t1024.config +++ b/config/examples/nxp-t1024.config @@ -65,3 +65,27 @@ 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, verify size+checksum +# 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/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 */ From 1bdbe52717b98a5aab90ebe33df0897081755e13 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 16 Jun 2026 14:12:14 -0700 Subject: [PATCH 4/6] Add NXP LS1028A ENETC wolfIP network test to the test-app --- config/examples/nxp-ls1028a.config | 30 ++++++++++++ test-app/Makefile | 14 +++++- test-app/app_nxp_ls1028a.c | 79 ++++++------------------------ test-app/wolfip_tftp_test.c | 67 ++++++++++++++++++++----- 4 files changed, 111 insertions(+), 79 deletions(-) diff --git a/config/examples/nxp-ls1028a.config b/config/examples/nxp-ls1028a.config index 366b7dcee1..ae61d1cc9a 100644 --- a/config/examples/nxp-ls1028a.config +++ b/config/examples/nxp-ls1028a.config @@ -53,3 +53,33 @@ 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, verify size+checksum +# 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/test-app/Makefile b/test-app/Makefile index c648e2f67e..05b9b265de 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -1123,10 +1123,20 @@ WOLFTPM_CFLAGS:=$(CFLAGS) # 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) - WOLFIP_PORTDIR:=$(WOLFBOOT_LIB_WOLFIP)/src/port/nxp_fman + # 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 + 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)/nxp_fman.o \ + WOLFIP_OBJS:=$(WOLFIP_PORTDIR)/$(WOLFIP_PORT_OBJ) \ $(WOLFBOOT_LIB_WOLFIP)/src/wolfip.o ifeq ($(WOLFBOOT_TEST_TFTP),1) CFLAGS+=-DWOLFBOOT_TEST_TFTP diff --git a/test-app/app_nxp_ls1028a.c b/test-app/app_nxp_ls1028a.c index fb0f6af527..8bb2d04a86 100644 --- a/test-app/app_nxp_ls1028a.c +++ b/test-app/app_nxp_ls1028a.c @@ -21,72 +21,15 @@ #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++]; - } -} +/* UART is brought up by wolfBoot (hal/nxp_ls1028a.c hal_init); uart_init() + * and uart_write() are provided by the linked HAL and declared in printf.h, + * so wolfBoot_printf() works here too. */ static const char* hex_lut = "0123456789abcdef"; @@ -102,6 +45,14 @@ void main(void) uart_write("Test App\n", 9); +#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 + /* Wait for reboot */ while(1) { for (j=0; j<1000000; j++); diff --git a/test-app/wolfip_tftp_test.c b/test-app/wolfip_tftp_test.c index 74d2664345..a3aaa401b7 100644 --- a/test-app/wolfip_tftp_test.c +++ b/test-app/wolfip_tftp_test.c @@ -1,7 +1,9 @@ /* wolfip_tftp_test.c * - * Optional wolfIP network test for the wolfBoot test-app on NXP QorIQ - * (T2080 / T1024 / T1040) boards. Modes (compile-time): + * 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 and verify (C7/C8) * WOLFIP_SPEED_TEST + TCP throughput server on port 9 (benchmark) @@ -29,20 +31,58 @@ #include #include "printf.h" -#include "nxp_fman.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_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). 10.0.4.24 on the lab rig. */ #define HOST_IP_STR "10.0.4.24" #define TFTP_FILENAME "wolfip_test.bin" -/* e6500 timebase = platform clock / 16 (VPX3-152: 600 MHz -> 37.5 MHz). - * Read the 64-bit Time Base via the SPRs (TBL=268, TBU=269); self-contained - * (no bootloader symbol). wolfIP timers are coarse so exactness is moot. */ +/* 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 (VPX3-152: 600 MHz -> 37.5 MHz). */ #define TIMEBASE_HZ 37500000ULL static uint64_t read_tb(void) @@ -60,6 +100,7 @@ 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. */ @@ -91,17 +132,17 @@ static struct wolfIP *wolfip_bringup(void) wolfIP_init_static(&s); ll = wolfIP_getdev(s); - wolfBoot_printf("wolfIP: bringing up FMan mEMAC%d\r\n", NXP_FMAN_MEMAC_IDX); - rc = nxp_fman_init(ll, NULL); + wolfBoot_printf("wolfIP: bringing up %s\r\n", WOLFIP_NETDEV_NAME); + rc = WOLFIP_NETDEV_INIT(ll, NULL); if (rc < 0) { - wolfBoot_printf("wolfIP: nxp_fman_init failed rc=%d\r\n", rc); + wolfBoot_printf("wolfIP: netdev init failed rc=%d\r\n", rc); return NULL; } - addr = nxp_fman_phy_addr(); - id1 = nxp_fman_phy_read(0x02); - bsr = nxp_fman_phy_read(0x01); + 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, nxp_fman_link_up() ? "UP" : "down"); + addr, id1, bsr, WOLFIP_NETDEV_LINK_UP() ? "UP" : "down"); (void)wolfIP_poll(s, now_ms()); wolfBoot_printf("wolfIP: starting DHCP...\r\n"); From 2ec2f626936f79ee5e427b4e55a08026dae5b6da Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 16 Jun 2026 15:19:28 -0700 Subject: [PATCH 5/6] Peer review fixes (thank you copilot) --- test-app/Makefile | 5 +++++ test-app/wolfip_tftp_test.c | 18 ++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/test-app/Makefile b/test-app/Makefile index 05b9b265de..d4b25564b0 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -1123,6 +1123,11 @@ WOLFTPM_CFLAGS:=$(CFLAGS) # 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) diff --git a/test-app/wolfip_tftp_test.c b/test-app/wolfip_tftp_test.c index a3aaa401b7..fd23f5d4ea 100644 --- a/test-app/wolfip_tftp_test.c +++ b/test-app/wolfip_tftp_test.c @@ -200,7 +200,9 @@ static int tftp_io_write(void *arg, void *handle, uint32_t offset, struct tftp_ram_ctx *c = (struct tftp_ram_ctx *)handle; uint16_t i; (void)arg; - if ((uint32_t)offset + len > TFTP_RAM_MAX) { + /* 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; } @@ -240,7 +242,7 @@ static int run_tftp_fetch(struct wolfIP *s) struct wolftftp_endpoint srv; struct wolfIP_sockaddr_in bind_addr; uint8_t pkt[1500]; - int sock, i; + int sock, i, ret = -1; uint64_t deadline; sock = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_DGRAM, 0); @@ -278,7 +280,7 @@ static int run_tftp_fetch(struct wolfIP *s) 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"); - return -1; + goto out; } deadline = now_ms() + 20000ULL; @@ -309,15 +311,19 @@ static int run_tftp_fetch(struct wolfIP *s) if (client.state != WOLFTFTP_CLIENT_COMPLETE) { wolfBoot_printf("TFTP: FAILED (state=%d status=%d)\r\n", client.state, client.last_status); - return -1; + goto out; } if (g_tftp.overflow) { wolfBoot_printf("TFTP: file exceeds %u byte RAM buffer\r\n", TFTP_RAM_MAX); - return -1; + goto out; } wolfBoot_printf("TFTP: got %u bytes, checksum 0x%x\r\n", (unsigned)g_tftp.len, (unsigned)g_tftp.sum); - return 0; + ret = 0; + +out: + (void)wolfIP_sock_close(s, sock); + return ret; } #endif /* WOLFBOOT_TEST_TFTP */ From 789c91f92601a29bb6f78243827dbe54119120ba Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 16 Jun 2026 15:26:07 -0700 Subject: [PATCH 6/6] Peer review fixes (thank you skoll) --- config/examples/nxp-ls1028a.config | 3 +- config/examples/nxp-t1024.config | 3 +- config/examples/nxp-t1040.config | 3 +- config/examples/nxp-t2080.config | 3 +- test-app/Makefile | 30 +++++++------------- test-app/app_nxp_ls1028a.c | 29 +++++++------------- test-app/wolfip_tftp_test.c | 44 ++++++++++++++++++++++++++---- 7 files changed, 67 insertions(+), 48 deletions(-) diff --git a/config/examples/nxp-ls1028a.config b/config/examples/nxp-ls1028a.config index ae61d1cc9a..39f879e1b4 100644 --- a/config/examples/nxp-ls1028a.config +++ b/config/examples/nxp-ls1028a.config @@ -79,7 +79,8 @@ WOLFBOOT_DTS_UPDATE_ADDRESS?=0x20F00000 # 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, verify size+checksum +# 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 ed656dcc4a..a793444b70 100644 --- a/config/examples/nxp-t1024.config +++ b/config/examples/nxp-t1024.config @@ -85,7 +85,8 @@ CFLAGS_EXTRA+=-DWOLFBOOT_USE_RAMBOOT # 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, verify size+checksum +# 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 497bdad037..ed26d37cd6 100644 --- a/config/examples/nxp-t1040.config +++ b/config/examples/nxp-t1040.config @@ -85,7 +85,8 @@ CFLAGS_EXTRA+=-DWOLFBOOT_USE_RAMBOOT # 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, verify size+checksum +# 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 27d930b7f7..b66071bc58 100644 --- a/config/examples/nxp-t2080.config +++ b/config/examples/nxp-t2080.config @@ -138,7 +138,8 @@ WOLFBOOT_LOAD_DTS_ADDRESS?=0x200000 #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, verify size+checksum +# 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/test-app/Makefile b/test-app/Makefile index d4b25564b0..1b9e1681fd 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -596,18 +596,6 @@ ifeq ($(TARGET),nxp_t2080) ifneq ($(SIGN),NONE) APP_OBJS+=../src/keystore.o endif - CFLAGS+=-ffunction-sections -fdata-sections - # The 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. -fno-plt makes those calls direct. - CFLAGS+=-fno-plt - # The cross-gcc defaults _FORTIFY_SOURCE on, which rewrites memcpy/memmove - # into __memcpy_chk/__memmove_chk -- glibc symbols absent from this - # freestanding binary, so the linker emits R_PPC_JMP_SLOT imports with - # zero GOT slots that branch to 0. Disable fortify for the bare-metal app. - CFLAGS+=-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 - # PowerPC e6500 PPC64=1 endif @@ -616,10 +604,6 @@ ifeq ($(TARGET),nxp_t1024) ifneq ($(SIGN),NONE) APP_OBJS+=../src/keystore.o endif - CFLAGS+=-ffunction-sections -fdata-sections - # Bare-metal app does no PLT/GOT fixup; keep cross-module libc calls direct - # and avoid fortified __memcpy_chk glibc imports (see nxp_t2080 block). - CFLAGS+=-fno-plt -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 # PowerPC e5500 PPC64=1 endif @@ -627,10 +611,6 @@ ifeq ($(TARGET),nxp_t1040) ifneq ($(SIGN),NONE) APP_OBJS+=../src/keystore.o endif - CFLAGS+=-ffunction-sections -fdata-sections - # Bare-metal app does no PLT/GOT fixup; keep cross-module libc calls direct - # and avoid fortified __memcpy_chk glibc imports (see nxp_t2080 block). - CFLAGS+=-fno-plt -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 # PowerPC e5500 PPC64=1 endif @@ -1137,6 +1117,16 @@ ifeq ($(ENABLE_WOLFIP),1) 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 diff --git a/test-app/app_nxp_ls1028a.c b/test-app/app_nxp_ls1028a.c index 8bb2d04a86..d708884a60 100644 --- a/test-app/app_nxp_ls1028a.c +++ b/test-app/app_nxp_ls1028a.c @@ -27,23 +27,18 @@ #include "wolfip_tftp_test.h" #endif -/* UART is brought up by wolfBoot (hal/nxp_ls1028a.c hal_init); uart_init() - * and uart_write() are provided by the linked HAL and declared in printf.h, - * so wolfBoot_printf() works here too. */ - -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"); #ifdef ENABLE_WOLFIP wolfBoot_printf("\r\nStarting wolfIP network test...\r\n"); @@ -53,15 +48,11 @@ void main(void) wolfBoot_printf("WOLFIP_TEST: FAIL\r\n"); #endif - /* Wait for reboot */ - while(1) { - for (j=0; j<1000000; j++); + /* Wait for reboot, printing a liveness counter. */ + while (1) { + for (j = 0; j < 1000000; j++) + ; i++; - - uart_write("\r\n0x", 4); - for (k=0; k<8; k++) { - snum[7 - k] = hex_lut[(i >> 4*k) & 0xf]; - } - uart_write(snum, 8); + wolfBoot_printf("\r\n0x%x", (unsigned)i); } } diff --git a/test-app/wolfip_tftp_test.c b/test-app/wolfip_tftp_test.c index fd23f5d4ea..e1b1d868ab 100644 --- a/test-app/wolfip_tftp_test.c +++ b/test-app/wolfip_tftp_test.c @@ -5,7 +5,8 @@ * 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 and verify (C7/C8) + * 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. @@ -56,9 +57,25 @@ #endif /* Host running in.tftpd / the throughput peer (same subnet as the DHCP - * lease). 10.0.4.24 on the lab rig. */ + * 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. */ @@ -82,8 +99,13 @@ static uint64_t now_ms(void) } #else /* PowerPC e5500/e6500 Time Base via SPRs (TBL=268, TBU=269). The timebase - * is the platform clock / 16 (VPX3-152: 600 MHz -> 37.5 MHz). */ + * 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) { @@ -319,6 +341,20 @@ static int run_tftp_fetch(struct wolfIP *s) } 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: @@ -334,7 +370,6 @@ static int run_tftp_fetch(struct wolfIP *s) * 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 struct wolfIP *g_speed_stack; static int speed_listen_fd = -1; static int speed_client_fd = -1; static uint64_t speed_rx_bytes, speed_tx_bytes, speed_start_ms; @@ -405,7 +440,6 @@ static int run_speed_server(struct wolfIP *s) struct wolfIP_sockaddr_in addr; int i; - g_speed_stack = s; 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");