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..ed26d37cd6 100644 --- a/config/examples/nxp-t1040.config +++ b/config/examples/nxp-t1040.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 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, 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..b66071bc58 100644 --- a/config/examples/nxp-t2080.config +++ b/config/examples/nxp-t2080.config @@ -124,3 +124,22 @@ 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 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..e1b1d868ab --- /dev/null +++ b/test-app/wolfip_tftp_test.c @@ -0,0 +1,480 @@ +/* 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_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"); + + (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 */