diff --git a/.github/workflows/wolfhal-stm32h563zi-nucleo.yml b/.github/workflows/wolfhal-stm32h563zi-nucleo.yml new file mode 100644 index 00000000..fb2efbc6 --- /dev/null +++ b/.github/workflows/wolfhal-stm32h563zi-nucleo.yml @@ -0,0 +1,69 @@ +name: wolfHAL STM32H563ZI Nucleo Build + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +env: + # wolfHAL pinned to a wolfSSL/wolfHAL main commit for reproducible CI. + # Bump WOLFHAL_REF to build against a newer HAL. + WOLFHAL_REF: 5302069e8d7baacefeeada94c4c8e5ef7426c1db + +jobs: + wolfhal_stm32h563zi_nucleo_build: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v4 + + - name: Install ARM toolchain + run: | + set -euo pipefail + sudo apt-get update + sudo apt-get install -y gcc-arm-none-eabi + + - name: Fetch wolfHAL (pinned to ${{ env.WOLFHAL_REF }}) + run: | + set -euo pipefail + git init -q ../wolfHAL + git -C ../wolfHAL remote add origin https://github.com/wolfSSL/wolfHAL.git + git -C ../wolfHAL fetch --depth 1 origin "$WOLFHAL_REF" + git -C ../wolfHAL checkout -q FETCH_HEAD + + - name: Build STM32H563 port with the wolfHAL driver backend + run: | + set -euo pipefail + make -C src/port/stm32h563 ENABLE_WOLFHAL=1 BOARD=stm32h563zi_nucleo \ + CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy + + - name: Verify binary + run: | + set -euo pipefail + test -f src/port/stm32h563/app.bin + arm-none-eabi-size src/port/stm32h563/app.elf + + wolfhal_stm32h563zi_nucleo_m33mu: + runs-on: ubuntu-latest + timeout-minutes: 20 + container: + image: ghcr.io/wolfssl/wolfboot-ci-m33mu:latest + options: --privileged + + steps: + - uses: actions/checkout@v4 + + - name: DHCP + TCP echo under m33mu with the wolfHAL driver backend + run: /bin/bash tools/scripts/run-m33mu-ci-in-container.sh stm32h563-m33mu-wolfhal stm32h563_m33mu_echo_wolfhal + + - uses: actions/upload-artifact@v4 + if: always() + with: + name: wolfhal-m33mu-logs + path: | + /tmp/m33mu.log + /tmp/echo.pcap + /tmp/echo.log + if-no-files-found: ignore diff --git a/.gitignore b/.gitignore index 4583854b..f2575f81 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ tags cppcheck_results.xml src/port/stm32h563/app.elf src/port/va416xx/app.elf +src/port/wolfHAL/build/ diff --git a/Makefile b/Makefile index f0741492..d0fef6d9 100644 --- a/Makefile +++ b/Makefile @@ -153,6 +153,8 @@ CPPCHECK_FLAGS=--enable=warning,performance,portability,missingInclude \ --suppress=unknownMacro:src/port/stm32h563/dot1x_client.c \ --suppress=unknownMacro:src/port/stm32c5a3/startup.c \ --suppress=preprocessorErrorDirective:src/supplicant/supplicant_features.h \ + --suppress=comparePointers:src/port/stm32h563/boards/stm32h563zi_nucleo/startup.c \ + --suppress=comparePointers:src/port/stm32h563/boards/stm32h563zi_nucleo/syscalls.c \ --disable=style \ --std=c99 --language=c \ --platform=unix64 \ diff --git a/src/port/stm32h563/Makefile b/src/port/stm32h563/Makefile index 753314a3..69c96e32 100644 --- a/src/port/stm32h563/Makefile +++ b/src/port/stm32h563/Makefile @@ -7,6 +7,14 @@ ROOT := ../../.. # Default is TZEN=0 (TrustZone disabled) TZEN ?= 0 +# wolfHAL driver backend: set ENABLE_WOLFHAL=1 to build the port on top of +# the wolfHAL HAL (Ethernet MAC/PHY, RNG, UART, GPIO, clocks) instead of the +# in-tree bare-metal drivers. Selects the self-contained board directory +# boards/$(BOARD). First cut supports TZEN=0 and FREERTOS=0 only. +ENABLE_WOLFHAL ?= 0 +BOARD ?= stm32h563zi_nucleo +WOLFHAL_ROOT ?= $(ROOT)/../wolfHAL + # TLS support: set ENABLE_TLS=1 to include wolfSSL TLS server # Requires wolfSSL cloned alongside wolfip (or set WOLFSSL_ROOT) ENABLE_TLS ?= 0 @@ -126,6 +134,44 @@ CFLAGS_WOLFSSL += $(EXTRA_CFLAGS_WOLFSSL) # $(WOLFSSL_ROOT)/%.o relaxed-warning rule. include $(ROOT)/src/port/stm32/wolfssl.mk +ifeq ($(ENABLE_WOLFHAL),1) +# ----------------------------------------------------------------------------- +# wolfHAL driver backend +# ----------------------------------------------------------------------------- +# board_init() programs the PLL directly and the wolfHAL SysTick driver owns +# the SysTick handler, so the wolfBoot-launched (TZEN=1) clock flow and the +# FreeRTOS SysTick are not supported in this first cut. +ifeq ($(TZEN),1) + $(error ENABLE_WOLFHAL=1 does not support TZEN=1 yet (board_init owns the PLL, which conflicts with the wolfBoot-launched NS clock flow)) +endif +ifeq ($(FREERTOS),1) + $(error ENABLE_WOLFHAL=1 does not support FREERTOS=1 yet (wolfHAL SysTick conflicts with the FreeRTOS SysTick handler)) +endif + +ifeq ($(wildcard $(WOLFHAL_ROOT)/wolfHAL/wolfHAL.h),) + $(error wolfHAL not found at $(WOLFHAL_ROOT). Clone it alongside wolfip: git clone https://github.com/wolfSSL/wolfHAL.git (or set WOLFHAL_ROOT)) +endif + +BOARD_DIR := boards/$(BOARD) + +CFLAGS += -DENABLE_WOLFHAL -DTZEN_ENABLED=0 +CFLAGS += -I$(WOLFHAL_ROOT) -I$(BOARD_DIR) -I$(ROOT)/src/port/wolfHAL + +LDSCRIPT := $(BOARD_DIR)/linker.ld + +# The board dir carries its own wolfHAL-specific startup/ivt/syscalls; the +# bare-metal stm32_eth.c driver is replaced by board.c (BSP bringup) plus the +# generic wolfhal_eth.c bridge. +SRCS := $(BOARD_DIR)/startup.c $(BOARD_DIR)/ivt.c syscalls.c +SRCS += main.c $(BOARD_DIR)/board.c $(ROOT)/src/port/wolfHAL/wolfhal_eth.c +SRCS += $(ROOT)/src/wolfip.c + +# wolfHAL driver selection (WHAL_CFG_* defines) + wolfHAL driver TUs. +include $(BOARD_DIR)/board.mk +else +# ----------------------------------------------------------------------------- +# In-tree bare-metal drivers (default) +# ----------------------------------------------------------------------------- # Select linker script based on TZEN setting ifeq ($(TZEN),1) LDSCRIPT := target_tzen.ld @@ -135,11 +181,12 @@ else CFLAGS += -DTZEN_ENABLED=0 endif -LDFLAGS := -nostdlib -T $(LDSCRIPT) -Wl,-gc-sections - # Base source files SRCS := startup.c ivt.c syscalls.c SRCS += main.c $(ROOT)/src/port/stm32/stm32_eth.c $(ROOT)/src/wolfip.c +endif + +LDFLAGS := -nostdlib -T $(LDSCRIPT) -Wl,-gc-sections ifeq ($(FREERTOS),1) ifeq ($(wildcard $(FREERTOS_PATH)/include/FreeRTOS.h),) @@ -256,6 +303,7 @@ WOLFSSH_SRCS := \ $(WOLFSSH_ROOT)/src/io.c \ $(WOLFSSH_ROOT)/src/keygen.c \ $(WOLFSSH_ROOT)/src/log.c \ + $(WOLFSSH_ROOT)/src/ossh.c \ $(WOLFSSH_ROOT)/src/port.c SRCS += $(WOLFSSH_SRCS) @@ -483,7 +531,7 @@ endif OBJS := $(patsubst %.c,%.o,$(SRCS)) all: app.bin - @echo "Built with TZEN=$(TZEN) ENABLE_TLS=$(ENABLE_TLS) ENABLE_TLS_CLIENT=$(ENABLE_TLS_CLIENT) ENABLE_HTTPS=$(ENABLE_HTTPS) ENABLE_SSH=$(ENABLE_SSH) ENABLE_MQTT=$(ENABLE_MQTT) ENABLE_MQTT_BROKER=$(ENABLE_MQTT_BROKER) FREERTOS=$(FREERTOS)" + @echo "Built with TZEN=$(TZEN) ENABLE_WOLFHAL=$(ENABLE_WOLFHAL) ENABLE_TLS=$(ENABLE_TLS) ENABLE_TLS_CLIENT=$(ENABLE_TLS_CLIENT) ENABLE_HTTPS=$(ENABLE_HTTPS) ENABLE_SSH=$(ENABLE_SSH) ENABLE_MQTT=$(ENABLE_MQTT) ENABLE_MQTT_BROKER=$(ENABLE_MQTT_BROKER) FREERTOS=$(FREERTOS)" ifeq ($(ENABLE_TLS),1) @echo " wolfSSL: $(WOLFSSL_ROOT)" endif @@ -544,6 +592,11 @@ factory: factory.bin # shared $(WOLFSSL_ROOT)/%.o rule in wolfssl.mk via WOLFSSL_EXTRA_DEFS. WOLFSSL_EXTRA_DEFS = $(if $(filter 1,$(ENABLE_SSH)),-DENABLE_SSH -DWOLFSSL_WOLFSSH) $(if $(filter 1,$(ENABLE_MQTT_BROKER)),-DENABLE_MQTT_BROKER) $(if $(filter 1,$(ENABLE_DOT1X)),-DHAVE_PBKDF2 -DHAVE_AES_KEYWRAP) +# wolfHAL driver objects: first-party HAL, but built with -Werror relaxed +# since the port's -Wextra is stricter than wolfHAL's own build. +$(WOLFHAL_ROOT)/%.o: $(WOLFHAL_ROOT)/%.c + $(CC) $(filter-out -Werror,$(CFLAGS)) -c $< -o $@ + clean: rm -f *.o app.elf app.bin rm -f app_v1_signed.bin factory.bin wolfboot_padded.bin @@ -552,6 +605,10 @@ clean: rm -f $(ROOT)/src/port/stm32/*.o rm -f $(ROOT)/src/port/freeRTOS/*.o rm -f $(ROOT)/src/supplicant/*.o +ifeq ($(ENABLE_WOLFHAL),1) + rm -f boards/$(BOARD)/*.o + rm -f $(WOLFHAL_ROOT)/src/*.o $(WOLFHAL_ROOT)/src/*/*.o +endif ifeq ($(FREERTOS),1) rm -f $(FREERTOS_PATH)/*.o rm -f $(FREERTOS_PATH)/portable/MemMang/*.o @@ -582,7 +639,7 @@ verify: app.bin @strings app.bin | grep -q "MQTT Broker: Initializing" && echo " ✓ MQTT broker enabled" || echo " ✗ MQTT broker disabled" @echo "" @echo "Binary size: $$(ls -lh app.bin | awk '{print $$5}')" - @echo "Build flags: TZEN=$(TZEN) ENABLE_TLS=$(ENABLE_TLS) ENABLE_HTTPS=$(ENABLE_HTTPS) ENABLE_SSH=$(ENABLE_SSH) ENABLE_MQTT=$(ENABLE_MQTT) ENABLE_MQTT_BROKER=$(ENABLE_MQTT_BROKER) FREERTOS=$(FREERTOS)" + @echo "Build flags: TZEN=$(TZEN) ENABLE_WOLFHAL=$(ENABLE_WOLFHAL) ENABLE_TLS=$(ENABLE_TLS) ENABLE_HTTPS=$(ENABLE_HTTPS) ENABLE_SSH=$(ENABLE_SSH) ENABLE_MQTT=$(ENABLE_MQTT) ENABLE_MQTT_BROKER=$(ENABLE_MQTT_BROKER) FREERTOS=$(FREERTOS)" # Show memory usage size: app.elf @@ -611,6 +668,8 @@ help: @echo "" @echo "Options:" @echo " TZEN=1 Enable TrustZone support" + @echo " ENABLE_WOLFHAL=1 Use the wolfHAL driver backend (requires wolfHAL; TZEN=0, FREERTOS=0)" + @echo " BOARD= Board under boards/ (default: stm32h563zi_nucleo)" @echo " ENABLE_TLS=1 Enable TLS server (requires wolfSSL)" @echo " ENABLE_TLS_CLIENT=1 Enable TLS client test (Google)" @echo " ENABLE_HTTPS=1 Enable HTTPS web server (requires TLS)" @@ -623,11 +682,13 @@ help: @echo " WOLFSSL_ROOT= Path to wolfSSL (default: ../wolfssl)" @echo " WOLFSSH_ROOT= Path to wolfSSH (default: ../wolfssh)" @echo " WOLFMQTT_ROOT= Path to wolfMQTT (default: ../wolfmqtt)" + @echo " WOLFHAL_ROOT= Path to wolfHAL (default: ../wolfHAL)" @echo " CC= C compiler (default: arm-none-eabi-gcc)" @echo " OBJCOPY= Objcopy tool (default: arm-none-eabi-objcopy)" @echo "" @echo "Examples:" @echo " make # Basic TCP echo (port 7)" + @echo " make ENABLE_WOLFHAL=1 # Basic TCP echo via the wolfHAL driver backend" @echo " make ENABLE_TLS=1 # TLS echo server (port 8443)" @echo " make ENABLE_TLS=1 ENABLE_HTTPS=1 # TLS + HTTPS web (port 443)" @echo " make ENABLE_TLS=1 ENABLE_SSH=1 # TLS + SSH shell (port 22)" diff --git a/src/port/stm32h563/boards/stm32h563zi_nucleo/board.c b/src/port/stm32h563/boards/stm32h563zi_nucleo/board.c new file mode 100644 index 00000000..4b6a8876 --- /dev/null +++ b/src/port/stm32h563/boards/stm32h563zi_nucleo/board.c @@ -0,0 +1,232 @@ +/* board.c + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Minimal board configuration for STM32H563ZI Nucleo-144 + * Only sets up what's needed for wolfIP: clocks, GPIO, Ethernet, PHY, RNG. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP 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. + * + * wolfIP 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 "board.h" +#include +#include + +/* SysTick timing */ +volatile uint64_t g_tick = 0; + +void SysTick_Handler(void) +{ + g_tick++; +} + +uint64_t board_get_tick(void) +{ + return g_tick; +} + +whal_Timeout g_whalTimeout = { + .timeoutTicks = 1000, + .GetTick = board_get_tick, +}; + +/* Peripheral clocks enabled before bringing up the peripherals (ETH clocks + * are enabled separately, after RMII mode is selected in SBS). */ +static const whal_Stm32h5_Rcc_PeriphClk g_periphClks[] = { + {WHAL_STM32H563_GPIOA_CLOCK}, + {WHAL_STM32H563_GPIOB_CLOCK}, + {WHAL_STM32H563_GPIOC_CLOCK}, + {WHAL_STM32H563_GPIOD_CLOCK}, + {WHAL_STM32H563_GPIOG_CLOCK}, + {WHAL_STM32H563_USART3_CLOCK}, + {WHAL_STM32H563_RNG_CLOCK}, + {WHAL_STM32H563_SBS_CLOCK}, +}; +#define PERIPH_CLK_COUNT (sizeof(g_periphClks) / sizeof(g_periphClks[0])) + +static const whal_Stm32h5_Rcc_PeriphClk g_ethClocks[] = { + {WHAL_STM32H563_ETH_CLOCK}, + {WHAL_STM32H563_ETHTX_CLOCK}, + {WHAL_STM32H563_ETHRX_CLOCK}, +}; +#define ETH_CLOCK_COUNT (sizeof(g_ethClocks) / sizeof(g_ethClocks[0])) + +/* Ethernet descriptor rings + buffer pool. Referenced by the ETH singleton's + * cfg (WHAL_CFG_STM32H5_ETH_DEV in board.h), so these must be global. */ +whal_Stm32h5_Eth_TxDesc ethTxDescs[BOARD_ETH_TX_DESC_COUNT] + __attribute__((aligned(16))); +whal_Stm32h5_Eth_RxDesc ethRxDescs[BOARD_ETH_RX_DESC_COUNT] + __attribute__((aligned(16))); +uint8_t ethTxBufs[BOARD_ETH_TX_DESC_COUNT * BOARD_ETH_TX_BUF_SIZE] + __attribute__((aligned(4))); +uint8_t ethRxBufs[BOARD_ETH_RX_DESC_COUNT * BOARD_ETH_RX_BUF_SIZE] + __attribute__((aligned(4))); + +/* + * FLASH_ACR (0x40022000): LATENCY[3:0] = 5 wait states for 168 MHz, + * WRHIGHFREQ[5:4] = 2. Must be set before raising the clock. + */ +#define FLASH_ACR_ADDR 0x40022000 +#define FLASH_ACR_LATENCY_168MHZ ((2 << 4) | 5) + +/* RMII mode select lives in SBS_PMCR (0x44000500), bits [23:21] = 0b100. */ +#define SBS_PMCR (*(volatile uint32_t *)0x44000500) +#define SBS_PMCR_ETH_SEL_Msk (7UL << 21) +#define SBS_PMCR_ETH_SEL_RMII (4UL << 21) + +whal_Error board_init(void) +{ + whal_Error err; + size_t i; + + /* Set flash latency before increasing clock speed */ + *(volatile uint32_t *)FLASH_ACR_ADDR = FLASH_ACR_LATENCY_168MHZ; + + /* HSI 64 MHz -> PLL1 (HSI/8 * 63 / 3 = 168 MHz) -> SYSCLK = PLL1 */ + + /* RCC_CR.HSIDIV resets to /4 (16 MHz) on H5, not /1. Force it back to + * /1 so the PLL sees 64 MHz; otherwise the divider chain below silently + * lands on 42 MHz instead of 168 MHz. */ + err = whal_Stm32h5_Rcc_SetHsiDiv(0); + if (err) + return err; + + err = whal_Stm32h5_Rcc_EnableOsc( + &(whal_Stm32h5_Rcc_OscCfg){WHAL_STM32H5_RCC_HSI_CFG}); + if (err) + return err; + + err = whal_Stm32h5_Rcc_EnablePll1(&(whal_Stm32h5_Rcc_PllCfg){ + .clkSrc = WHAL_STM32H5_RCC_PLLCLK_SRC_HSI, + .m = 8, .n = 62, .p = 2, .q = 2, .r = 2, + }); + if (err) + return err; + + err = whal_Stm32h5_Rcc_SetSysClock(WHAL_STM32H5_RCC_SYSCLK_SRC_PLL1); + if (err) + return err; + + /* Enable peripheral clocks (ETH excluded — needs SBS RMII config first) */ + for (i = 0; i < PERIPH_CLK_COUNT; i++) { + err = whal_Stm32h5_Rcc_EnablePeriphClk(&g_periphClks[i]); + if (err) + return err; + } + + /* Select RMII mode before enabling the ETH clocks */ + SBS_PMCR = (SBS_PMCR & ~SBS_PMCR_ETH_SEL_Msk) | SBS_PMCR_ETH_SEL_RMII; + + for (i = 0; i < ETH_CLOCK_COUNT; i++) { + err = whal_Stm32h5_Rcc_EnablePeriphClk(&g_ethClocks[i]); + if (err) + return err; + } + + /* Enable HSI48 for the RNG kernel clock */ + err = whal_Stm32h5_Rcc_EnableOsc( + &(whal_Stm32h5_Rcc_OscCfg){WHAL_STM32H5_RCC_HSI48_CFG}); + if (err) + return err; + + err = whal_Gpio_Init(WHAL_INTERNAL_DEV); + if (err) + return err; + + err = whal_Uart_Init(WHAL_INTERNAL_DEV); + if (err) + return err; + + err = whal_Rng_Init(WHAL_INTERNAL_DEV); + if (err) + return err; + + err = whal_Timer_Init(WHAL_INTERNAL_DEV); + if (err) + return err; + + err = whal_Timer_Start(WHAL_INTERNAL_DEV); + if (err) + return err; + + err = whal_Eth_Init(WHAL_INTERNAL_DEV); + if (err) + return err; + + err = whal_EthPhy_Init(WHAL_INTERNAL_DEV); + if (err) + return err; + + return WHAL_SUCCESS; +} + +whal_Error board_deinit(void) +{ + whal_Error err; + size_t i; + + err = whal_Timer_Stop(WHAL_INTERNAL_DEV); + if (err) + return err; + + err = whal_Timer_Deinit(WHAL_INTERNAL_DEV); + if (err) + return err; + + err = whal_EthPhy_Deinit(WHAL_INTERNAL_DEV); + if (err) + return err; + + err = whal_Eth_Deinit(WHAL_INTERNAL_DEV); + if (err) + return err; + + err = whal_Rng_Deinit(WHAL_INTERNAL_DEV); + if (err) + return err; + + err = whal_Uart_Deinit(WHAL_INTERNAL_DEV); + if (err) + return err; + + err = whal_Gpio_Deinit(WHAL_INTERNAL_DEV); + if (err) + return err; + + for (i = 0; i < ETH_CLOCK_COUNT; i++) { + err = whal_Stm32h5_Rcc_DisablePeriphClk(&g_ethClocks[i]); + if (err) + return err; + } + + for (i = 0; i < PERIPH_CLK_COUNT; i++) { + err = whal_Stm32h5_Rcc_DisablePeriphClk(&g_periphClks[i]); + if (err) + return err; + } + + err = whal_Stm32h5_Rcc_SetSysClock(WHAL_STM32H5_RCC_SYSCLK_SRC_HSI); + if (err) + return err; + err = whal_Stm32h5_Rcc_DisablePll1(); + if (err) + return err; + + return WHAL_SUCCESS; +} diff --git a/src/port/stm32h563/boards/stm32h563zi_nucleo/board.h b/src/port/stm32h563/boards/stm32h563zi_nucleo/board.h new file mode 100644 index 00000000..4bcf6e3f --- /dev/null +++ b/src/port/stm32h563/boards/stm32h563zi_nucleo/board.h @@ -0,0 +1,199 @@ +/* board.h + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Minimal board configuration for STM32H563ZI Nucleo-144 + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP 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. + * + * wolfIP 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 BOARD_H +#define BOARD_H + +#include +#include +#include +#include +#include + +extern whal_Timeout g_whalTimeout; +extern volatile uint64_t g_tick; + +/* The generic wolfIP port (main.c, wolfhal_eth.c, syscalls.c) references the + * board's Ethernet, PHY, RNG, and UART devices through these names. Under the + * current wolfHAL API these are single-instance drivers whose device structs + * live in the driver translation units (built from the WHAL_CFG_*_DEV + * initializers below), so we alias the documented g_whal* names onto those + * driver-owned device structs. */ +#define g_whalEth (*(whal_Eth *)&whal_Stm32h5_Eth_Dev) +#define g_whalEthPhy (*(whal_EthPhy *)&whal_Lan8742a_Dev) +#define g_whalRng (*(whal_Rng *)&whal_Stm32h5_Rng_Dev) +#define g_whalUart (*(whal_Uart *)&whal_Stm32h5_Uart_Dev) + +/* Ethernet PHY: LAN8742A on MDIO address 0 */ +#define BOARD_ETH_PHY_ADDR 0 + +enum { + UART_TX_PIN, + UART_RX_PIN, + ETH_RMII_REF_CLK_PIN, + ETH_RMII_MDIO_PIN, + ETH_RMII_MDC_PIN, + ETH_RMII_CRS_DV_PIN, + ETH_RMII_RXD0_PIN, + ETH_RMII_RXD1_PIN, + ETH_RMII_TX_EN_PIN, + ETH_RMII_TXD0_PIN, + ETH_RMII_TXD1_PIN, + PIN_COUNT, +}; + +/* GPIO dev initializer — device struct defined in the gpio driver code. + * Only the USART3 (ST-Link VCP) and Ethernet RMII pins are configured. */ +#define WHAL_CFG_STM32H5_GPIO_DEV { \ + .base = WHAL_STM32H563_GPIO_BASE, \ + .cfg = (void *)&(const whal_Stm32h5_Gpio_Cfg){ \ + .pinCfg = (const whal_Stm32h5_Gpio_PinCfg[PIN_COUNT]){ \ + /* USART3 TX on PD8, AF7 (ST-Link VCP) */ \ + [UART_TX_PIN] = WHAL_STM32H5_GPIO_PIN( \ + WHAL_STM32H5_GPIO_PORT_D, 8, WHAL_STM32H5_GPIO_MODE_ALTFN, \ + WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32H5_GPIO_SPEED_FAST, \ + WHAL_STM32H5_GPIO_PULL_UP, 7), \ + /* USART3 RX on PD9, AF7 (ST-Link VCP) */ \ + [UART_RX_PIN] = WHAL_STM32H5_GPIO_PIN( \ + WHAL_STM32H5_GPIO_PORT_D, 9, WHAL_STM32H5_GPIO_MODE_ALTFN, \ + WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32H5_GPIO_SPEED_FAST, \ + WHAL_STM32H5_GPIO_PULL_UP, 7), \ + [ETH_RMII_REF_CLK_PIN] = WHAL_STM32H5_GPIO_PIN( \ + WHAL_STM32H5_GPIO_PORT_A, 1, WHAL_STM32H5_GPIO_MODE_ALTFN, \ + WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32H5_GPIO_SPEED_HIGH, \ + WHAL_STM32H5_GPIO_PULL_NONE, 11), \ + [ETH_RMII_MDIO_PIN] = WHAL_STM32H5_GPIO_PIN( \ + WHAL_STM32H5_GPIO_PORT_A, 2, WHAL_STM32H5_GPIO_MODE_ALTFN, \ + WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32H5_GPIO_SPEED_HIGH, \ + WHAL_STM32H5_GPIO_PULL_NONE, 11), \ + [ETH_RMII_MDC_PIN] = WHAL_STM32H5_GPIO_PIN( \ + WHAL_STM32H5_GPIO_PORT_C, 1, WHAL_STM32H5_GPIO_MODE_ALTFN, \ + WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32H5_GPIO_SPEED_HIGH, \ + WHAL_STM32H5_GPIO_PULL_NONE, 11), \ + [ETH_RMII_CRS_DV_PIN] = WHAL_STM32H5_GPIO_PIN( \ + WHAL_STM32H5_GPIO_PORT_A, 7, WHAL_STM32H5_GPIO_MODE_ALTFN, \ + WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32H5_GPIO_SPEED_HIGH, \ + WHAL_STM32H5_GPIO_PULL_NONE, 11), \ + [ETH_RMII_RXD0_PIN] = WHAL_STM32H5_GPIO_PIN( \ + WHAL_STM32H5_GPIO_PORT_C, 4, WHAL_STM32H5_GPIO_MODE_ALTFN, \ + WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32H5_GPIO_SPEED_HIGH, \ + WHAL_STM32H5_GPIO_PULL_NONE, 11), \ + [ETH_RMII_RXD1_PIN] = WHAL_STM32H5_GPIO_PIN( \ + WHAL_STM32H5_GPIO_PORT_C, 5, WHAL_STM32H5_GPIO_MODE_ALTFN, \ + WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32H5_GPIO_SPEED_HIGH, \ + WHAL_STM32H5_GPIO_PULL_NONE, 11), \ + [ETH_RMII_TX_EN_PIN] = WHAL_STM32H5_GPIO_PIN( \ + WHAL_STM32H5_GPIO_PORT_G, 11, WHAL_STM32H5_GPIO_MODE_ALTFN, \ + WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32H5_GPIO_SPEED_HIGH, \ + WHAL_STM32H5_GPIO_PULL_NONE, 11), \ + [ETH_RMII_TXD0_PIN] = WHAL_STM32H5_GPIO_PIN( \ + WHAL_STM32H5_GPIO_PORT_G, 13, WHAL_STM32H5_GPIO_MODE_ALTFN, \ + WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32H5_GPIO_SPEED_HIGH, \ + WHAL_STM32H5_GPIO_PULL_NONE, 11), \ + [ETH_RMII_TXD1_PIN] = WHAL_STM32H5_GPIO_PIN( \ + WHAL_STM32H5_GPIO_PORT_B, 15, WHAL_STM32H5_GPIO_MODE_ALTFN, \ + WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32H5_GPIO_SPEED_HIGH, \ + WHAL_STM32H5_GPIO_PULL_NONE, 11), \ + }, \ + .pinCount = PIN_COUNT, \ + }, \ +} + +/* RNG dev initializer — device struct defined in the rng driver code. */ +#define WHAL_CFG_STM32H5_RNG_DEV { \ + .base = WHAL_STM32H563_RNG_BASE, \ + .cfg = (void *)&(const whal_Stm32h5_Rng_Cfg){ \ + .timeout = &g_whalTimeout, \ + }, \ +} + +/* UART dev initializer — device struct defined in the UART driver code. Named + * WHAL_CFG_STM32WB_UART_DEV (not _STM32H5_) because the STM32H5 USART reuses + * the shared STM32WB UART driver, which instantiates the device from that + * exact name. USART3 on the ST-Link VCP; BRR for PCLK 168 MHz @ 115200. */ +#define WHAL_CFG_STM32WB_UART_DEV { \ + .base = WHAL_STM32H563_USART3_BASE, \ + .cfg = (void *)&(const whal_Stm32h5_Uart_Cfg){ \ + .brr = WHAL_STM32H5_UART_BRR(168000000, 115200), \ + .timeout = &g_whalTimeout, \ + }, \ +} + +/* ETH descriptor rings + buffer pool — defined in board.c, captured by the + * ETH device's cfg below (expanded in the eth driver code). */ +#define BOARD_ETH_TX_DESC_COUNT 3 +#define BOARD_ETH_RX_DESC_COUNT 4 +#define BOARD_ETH_TX_BUF_SIZE 1536 +#define BOARD_ETH_RX_BUF_SIZE 1536 + +extern whal_Stm32h5_Eth_TxDesc ethTxDescs[BOARD_ETH_TX_DESC_COUNT]; +extern whal_Stm32h5_Eth_RxDesc ethRxDescs[BOARD_ETH_RX_DESC_COUNT]; +extern uint8_t ethTxBufs[BOARD_ETH_TX_DESC_COUNT * BOARD_ETH_TX_BUF_SIZE]; +extern uint8_t ethRxBufs[BOARD_ETH_RX_DESC_COUNT * BOARD_ETH_RX_BUF_SIZE]; + +#ifndef BOARD_MAC_ADDR +#define BOARD_MAC_ADDR {0x00, 0x80, 0xE1, 0x00, 0x00, 0x01} +#endif + +/* ETH dev initializer — device struct defined in the eth driver code. */ +#define WHAL_CFG_STM32H5_ETH_DEV { \ + .base = WHAL_STM32H563_ETH_BASE, \ + .macAddr = BOARD_MAC_ADDR, \ + .cfg = (void *)&(const whal_Stm32h5_Eth_Cfg){ \ + .txDescs = ethTxDescs, \ + .txBufs = ethTxBufs, \ + .txDescCount = BOARD_ETH_TX_DESC_COUNT, \ + .txBufSize = BOARD_ETH_TX_BUF_SIZE, \ + .rxDescs = ethRxDescs, \ + .rxBufs = ethRxBufs, \ + .rxDescCount = BOARD_ETH_RX_DESC_COUNT, \ + .rxBufSize = BOARD_ETH_RX_BUF_SIZE, \ + .mdioCr = 4, /* HCLK 168 MHz -> MDC = 168/102 ~= 1.6 MHz */ \ + .timeout = &g_whalTimeout, \ + }, \ +} + +/* LAN8742A PHY dev initializer — device struct defined in the phy driver code. */ +#define WHAL_CFG_LAN8742A_DEV { \ + .eth = NULL, \ + .addr = BOARD_ETH_PHY_ADDR, \ + .cfg = (void *)&(const whal_Lan8742a_Cfg){ \ + .timeout = &g_whalTimeout, \ + }, \ +} + +/* SysTick dev initializer — device struct defined in the systick driver code. */ +#define WHAL_CFG_SYSTICK_DEV { \ + .base = WHAL_CORTEX_M33_SYSTICK_BASE, \ + .cfg = (void *)&(const whal_SysTick_Cfg){ \ + .cyclesPerTick = (168000000-1) / 1000, \ + .clkSrc = WHAL_SYSTICK_CLKSRC_SYSCLK, \ + .tickInt = WHAL_SYSTICK_TICKINT_ENABLED, \ + }, \ +} + +whal_Error board_init(void); +whal_Error board_deinit(void); +uint64_t board_get_tick(void); + +#endif /* BOARD_H */ diff --git a/src/port/stm32h563/boards/stm32h563zi_nucleo/board.mk b/src/port/stm32h563/boards/stm32h563zi_nucleo/board.mk new file mode 100644 index 00000000..4a54965c --- /dev/null +++ b/src/port/stm32h563/boards/stm32h563zi_nucleo/board.mk @@ -0,0 +1,32 @@ +# wolfHAL-specific build settings for the STM32H563ZI Nucleo board. +# +# Included by the port Makefile only when ENABLE_WOLFHAL=1. The port +# Makefile owns the toolchain, base CFLAGS, include paths, and linker +# script; this fragment contributes only the wolfHAL driver selection +# and the wolfHAL driver translation units. WOLFHAL_ROOT is set by the +# port Makefile. + +# Direct-API-mapping driver selection: one concrete driver TU per domain, +# no generic dispatch layer (which would redefine the top-level symbols). +CFLAGS += -DPLATFORM_STM32H5 +CFLAGS += -DWHAL_CFG_STM32H5_GPIO_DIRECT_API_MAPPING +CFLAGS += -DWHAL_CFG_STM32H5_RCC_PLL_DRIVER +CFLAGS += -DWHAL_CFG_STM32H5_RCC_DIRECT_API_MAPPING +CFLAGS += -DWHAL_CFG_STM32H5_UART_DIRECT_API_MAPPING +CFLAGS += -DWHAL_CFG_STM32H5_UART_SINGLE_INSTANCE +CFLAGS += -DWHAL_CFG_STM32H5_RNG_DIRECT_API_MAPPING +CFLAGS += -DWHAL_CFG_STM32H5_ETH_DIRECT_API_MAPPING +CFLAGS += -DWHAL_CFG_LAN8742A_ETH_PHY_DIRECT_API_MAPPING +CFLAGS += -DWHAL_CFG_STM32H5_FLASH_DIRECT_API_MAPPING +CFLAGS += -DWHAL_CFG_SYSTICK_TIMER_DIRECT_API_MAPPING +CFLAGS += -DWHAL_CFG_64BIT_TICK + +# wolfHAL driver translation units. Built with relaxed warnings via the +# port Makefile's $(WOLFHAL_ROOT)/%.o rule. +SRCS += $(WOLFHAL_ROOT)/src/reg.c +SRCS += $(WOLFHAL_ROOT)/src/eth/stm32h5_eth.c +SRCS += $(WOLFHAL_ROOT)/src/eth_phy/lan8742a_eth_phy.c +SRCS += $(WOLFHAL_ROOT)/src/gpio/stm32h5_gpio.c +SRCS += $(WOLFHAL_ROOT)/src/uart/stm32h5_uart.c +SRCS += $(WOLFHAL_ROOT)/src/rng/stm32h5_rng.c +SRCS += $(WOLFHAL_ROOT)/src/timer/systick.c diff --git a/src/port/stm32h563/boards/stm32h563zi_nucleo/ivt.c b/src/port/stm32h563/boards/stm32h563zi_nucleo/ivt.c new file mode 100644 index 00000000..050ee86d --- /dev/null +++ b/src/port/stm32h563/boards/stm32h563zi_nucleo/ivt.c @@ -0,0 +1,59 @@ +/* ivt.c + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Interrupt vector table for Cortex-M33 (STM32H563) + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP 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. + * + * wolfIP 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 + +extern void Reset_Handler(void); +extern unsigned long _estack; + +static void default_handler(void) +{ + while (1) { } +} + +void NMI_Handler(void) __attribute__((weak, alias("default_handler"))); +void HardFault_Handler(void) __attribute__((weak, alias("default_handler"))); +void MemManage_Handler(void) __attribute__((weak, alias("default_handler"))); +void BusFault_Handler(void) __attribute__((weak, alias("default_handler"))); +void UsageFault_Handler(void) __attribute__((weak, alias("default_handler"))); +void SVC_Handler(void) __attribute__((weak, alias("default_handler"))); +void DebugMon_Handler(void) __attribute__((weak, alias("default_handler"))); +void PendSV_Handler(void) __attribute__((weak, alias("default_handler"))); +void SysTick_Handler(void) __attribute__((weak, alias("default_handler"))); + +__attribute__((section(".isr_vector"))) +const uint32_t vector_table[16 + 96] = { + [0] = (uint32_t)&_estack, + [1] = (uint32_t)&Reset_Handler, + [2] = (uint32_t)&NMI_Handler, + [3] = (uint32_t)&HardFault_Handler, + [4] = (uint32_t)&MemManage_Handler, + [5] = (uint32_t)&BusFault_Handler, + [6] = (uint32_t)&UsageFault_Handler, + [7] = 0, [8] = 0, [9] = 0, [10] = 0, + [11] = (uint32_t)&SVC_Handler, + [12] = (uint32_t)&DebugMon_Handler, + [13] = 0, + [14] = (uint32_t)&PendSV_Handler, + [15] = (uint32_t)&SysTick_Handler, + [16 ... 111] = (uint32_t)&default_handler, +}; diff --git a/src/port/stm32h563/boards/stm32h563zi_nucleo/linker.ld b/src/port/stm32h563/boards/stm32h563zi_nucleo/linker.ld new file mode 100644 index 00000000..e7115549 --- /dev/null +++ b/src/port/stm32h563/boards/stm32h563zi_nucleo/linker.ld @@ -0,0 +1,92 @@ +/* STM32H563ZI Linker Script + * + * Memory Map: + * FLASH: 2MB @ 0x08000000 + * SRAM: 640KB @ 0x20000000 (contiguous SRAM1+SRAM2+SRAM3) + */ + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 640K +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +_Min_Heap_Size = 0x10000; /* 64KB heap */ +_Min_Stack_Size = 0x8000; /* 32KB stack */ +_heap_limit = _estack - _Min_Stack_Size; + +SECTIONS +{ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) + . = ALIGN(4); + } > FLASH + + .text : + { + . = ALIGN(4); + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + . = ALIGN(4); + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + . = ALIGN(4); + _sdata = .; + *(.data*) + . = ALIGN(4); + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } > RAM + + ._user_heap_stack (NOLOAD) : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } > RAM +} diff --git a/src/port/stm32h563/boards/stm32h563zi_nucleo/startup.c b/src/port/stm32h563/boards/stm32h563zi_nucleo/startup.c new file mode 100644 index 00000000..45c4f0f3 --- /dev/null +++ b/src/port/stm32h563/boards/stm32h563zi_nucleo/startup.c @@ -0,0 +1,47 @@ +/* startup.c + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Cortex-M startup: copies .data, zeros .bss, calls main(). + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP 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. + * + * wolfIP 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 + +extern uint32_t _sidata; +extern uint32_t _sdata; +extern uint32_t _edata; +extern uint32_t _sbss; +extern uint32_t _ebss; +extern void __libc_init_array(void); + +int main(void); + +void Reset_Handler(void) +{ + uint32_t *src; + uint32_t *dst; + + src = &_sidata; + for (dst = &_sdata; dst < &_edata; ) + *dst++ = *src++; + for (dst = &_sbss; dst < &_ebss; ) + *dst++ = 0u; + __libc_init_array(); + (void)main(); + while (1) { } +} diff --git a/src/port/stm32h563/dot1x_client.c b/src/port/stm32h563/dot1x_client.c index 29ce4f2d..9b082b8b 100644 --- a/src/port/stm32h563/dot1x_client.c +++ b/src/port/stm32h563/dot1x_client.c @@ -42,6 +42,10 @@ #include "dot1x_client.h" #include "dot1x_certs.h" +#ifdef ENABLE_WOLFHAL +#include "board.h" +#endif + #define DOT1X_EAPOL_ETHERTYPE 0x888EU #define DOT1X_ETH_HDR_LEN 14U #define DOT1X_FRAME_MAX 1600 @@ -49,6 +53,8 @@ * completes in a handful of round-trips; this is a generous backstop. */ #define DOT1X_MAX_ITERS 4000000UL +#ifndef ENABLE_WOLFHAL + /* ---- Real millisecond clock (SysTick) ---------------------------------- * The supplicant timeout (WOLFIP_SUPPLICANT_HS_TIMEOUT_MS) and M2-retransmit * timing are in milliseconds. The bare-metal H563 build otherwise has no ms @@ -81,6 +87,8 @@ static void dot1x_systick_arm_1khz(void) SYST_CSR = (1U << 2) | (1U << 1) | (1U << 0); } +#endif /* !ENABLE_WOLFHAL */ + /* IEEE 802.1X PAE group address - the standard multicast dst for supplicant * EAPOL. Works on a point-to-point link, but 802.1D switches do NOT forward * this reserved link-local address, so on a switched segment the @@ -239,9 +247,12 @@ int dot1x_eaptls_run(struct wolfIP *stack, void (*log)(const char *msg)) /* Arm the real ms clock and feed wall-clock milliseconds to the supplicant * and the poll loop, so the handshake timeout is time-based not iteration- * based. DOT1X_MAX_ITERS remains the absolute backstop. */ +#ifdef ENABLE_WOLFHAL + now = board_get_tick(); +#else /* ENABLE_WOLFHAL */ dot1x_systick_arm_1khz(); now = g_dot1x_ms; - +#endif dot1x_log(&ctx, "dot1x: EAP-TLS start (EAPOL-Start) as " DOT1X_EAP_IDENTITY "\n"); wolfip_supplicant_kick(&supp, now); @@ -250,7 +261,11 @@ int dot1x_eaptls_run(struct wolfIP *stack, void (*log)(const char *msg)) wolfip_supplicant_state_t st; int n; +#ifdef ENABLE_WOLFHAL + now = board_get_tick(); +#else /* ENABLE_WOLFHAL */ now = g_dot1x_ms; +#endif (void)wolfIP_poll(stack, now); n = wolfIP_sock_recvfrom(stack, ctx.sock, dot1x_rxframe, diff --git a/src/port/stm32h563/main.c b/src/port/stm32h563/main.c index 421be6c4..7ac60e4c 100644 --- a/src/port/stm32h563/main.c +++ b/src/port/stm32h563/main.c @@ -24,7 +24,14 @@ #include #include "config.h" #include "wolfip.h" +#ifdef ENABLE_WOLFHAL +#include "board.h" +#include "wolfhal_eth.h" +#include +#include +#else #include "stm32_eth.h" +#endif #ifdef WOLFIP_USE_FREERTOS #include "FreeRTOS.h" @@ -300,12 +307,16 @@ static int https_status_handler(struct httpd *httpd, struct http_client *hc, #define RNG_SR_SEIS (1u << 6) static struct wolfIP *IPStack; +#ifdef ENABLE_WOLFHAL +static struct wolfhal_eth_ctx eth_ctx; +#endif #ifndef WOLFIP_USE_FREERTOS static int listen_fd = -1; static int client_fd = -1; static uint8_t rx_buf[RX_BUF_SIZE]; #endif +#ifndef ENABLE_WOLFHAL static void rng_init(void) { uint32_t rng_cr; @@ -364,9 +375,15 @@ static int rng_get_word(uint32_t *out) *out = RNG_DR; return 0; } +#endif /* !ENABLE_WOLFHAL */ int custom_rand_gen_block(unsigned char *output, unsigned int sz) { +#ifdef ENABLE_WOLFHAL + if (whal_Rng_Generate(&g_whalRng, output, (size_t)sz) != WHAL_SUCCESS) + return -1; + return 0; +#else uint32_t word; while (sz >= 4u) { @@ -392,14 +409,22 @@ int custom_rand_gen_block(unsigned char *output, unsigned int sz) } return 0; +#endif /* ENABLE_WOLFHAL */ } uint32_t wolfIP_getrandom(void) { +#ifdef ENABLE_WOLFHAL + uint32_t word = 0u; + + (void)whal_Rng_Generate(&g_whalRng, &word, sizeof(word)); + return word; +#else uint32_t word = 0u; (void)rng_get_word(&word); return word; +#endif } /* Simple delay */ @@ -446,6 +471,7 @@ static void led_toggle(void) #define USART3_CR3 (*(volatile uint32_t *)(USART3_BASE + 0x08u)) #define USART3_PRESC (*(volatile uint32_t *)(USART3_BASE + 0x2Cu)) +#ifndef ENABLE_WOLFHAL /* Initialize USART3 for debug output (115200 baud @ 64MHz HSI) */ static void uart_init(void) { @@ -486,19 +512,41 @@ static void uart_init(void) USART3_CR1 |= (1u << 0); /* UE */ delay(100); } +#endif /* !ENABLE_WOLFHAL */ static void uart_putc(char c) { +#ifdef ENABLE_WOLFHAL + (void)whal_Uart_Send(&g_whalUart, &c, 1); +#else while ((USART3_ISR & (1u << 7)) == 0) { } /* Wait for TXE */ USART3_TDR = (uint32_t)c; +#endif } void uart_puts(const char *s) { +#ifdef ENABLE_WOLFHAL + /* Send whole runs between newlines in a single wolfHAL call, translating + * LF -> CRLF at run boundaries (matching the per-char path below). */ + while (*s) { + size_t len = 0; + while (s[len] && s[len] != '\n') + len++; + if (len) + (void)whal_Uart_Send(&g_whalUart, s, len); + if (s[len] == '\n') { + (void)whal_Uart_Send(&g_whalUart, "\r\n", 2); + len++; + } + s += len; + } +#else while (*s) { if (*s == '\n') uart_putc('\r'); uart_putc(*s++); } +#endif } void wolfssl_tls13_dbg_hex(const char *tag, const unsigned char *buf, @@ -627,6 +675,7 @@ static void uart_putip4(ip4 ip) uart_putdec(ip & 0xFF); } +#ifndef ENABLE_WOLFHAL /* Configure GPIO pin for Ethernet alternate function (AF11) */ static void gpio_eth_pin(uint32_t base, uint32_t pin) { @@ -702,6 +751,7 @@ static void eth_gpio_init(void) gpio_eth_pin(GPIOG_BASE, 11); /* TX_EN */ gpio_eth_pin(GPIOG_BASE, 13); /* TXD0 */ } +#endif /* !ENABLE_WOLFHAL */ #ifdef ENABLE_TLS_CLIENT /* Callback for TLS client responses */ @@ -808,6 +858,17 @@ int main(void) uint64_t tick = 0; int ret; +#ifdef ENABLE_WOLFHAL + /* wolfHAL BSP owns all clock + peripheral bringup: clocks, GPIO, UART, + * RNG, system timer, Ethernet MAC + PHY. */ + if (board_init() != WHAL_SUCCESS) { + while (1) { } + } + + /* PF4 debug LED stays a driver-independent register poke. */ + led_init(); + led_on(); /* LED ON = Reset_Handler ran, main() started */ +#else #if TZEN_ENABLED revert_sysclk_to_hsi(); #endif @@ -819,6 +880,7 @@ int main(void) /* Initialize UART for debug output */ uart_init(); rng_init(); +#endif /* Blink to show UART init done */ led_off(); @@ -849,6 +911,29 @@ int main(void) uart_puts("Initializing wolfIP stack...\n"); wolfIP_init_static(&IPStack); +#ifdef ENABLE_WOLFHAL + /* MAC + PHY are already brought up by board_init(). Wait for link, + * start the MAC at the negotiated speed/duplex, and bind the wolfIP + * device to the wolfHAL Ethernet bridge. */ + uart_puts("Initializing Ethernet (wolfHAL, waiting for link)...\n"); + ll = wolfIP_getdev(IPStack); + eth_ctx.eth = &g_whalEth; + eth_ctx.phy = &g_whalEthPhy; + ret = wolfhal_eth_init(ll, ð_ctx); + if (ret < 0) { + uart_puts(" ERROR: wolfhal_eth_init failed ("); + uart_puthex((uint32_t)ret); + uart_puts(")\n"); + } else { + int mi; + uart_puts(" MAC: "); + for (mi = 0; mi < 6; mi++) { + if (mi > 0) uart_puts(":"); + uart_puthex8(ll->mac[mi]); + } + uart_puts("\n"); + } +#else /* Initialize GPIO pins for RMII - MUST happen before Ethernet clocks! */ uart_puts("Configuring GPIO for RMII...\n"); eth_gpio_init(); @@ -900,6 +985,7 @@ int main(void) } uart_puts("\n"); } +#endif /* ENABLE_WOLFHAL */ #ifdef ENABLE_DOT1X /* Wired IEEE 802.1X EAP-TLS: authenticate at layer 2 (EAPOL/0x888E) @@ -968,8 +1054,12 @@ int main(void) } else { uart_puts(" DHCP discover sent, waiting for lease...\n"); /* Wait for DHCP to complete - poll frequently */ +#ifdef ENABLE_WOLFHAL + dhcp_start_tick = board_get_tick(); +#else dhcp_start_tick = tick; -#ifdef DEBUG_H5_ETH +#endif +#if defined(DEBUG_H5_ETH) && !defined(ENABLE_WOLFHAL) { uint32_t dbg_polls = 0, dbg_pkts = 0; volatile uint32_t *probe_ns = (volatile uint32_t *)0x2009aa40u; @@ -1002,13 +1092,19 @@ int main(void) } #endif while (!dhcp_bound(IPStack) && dhcp_client_is_running(IPStack)) { +#ifdef ENABLE_WOLFHAL + /* Real millisecond tick from the SysTick BSP. */ + tick = board_get_tick(); + (void)wolfIP_poll(IPStack, tick); +#else /* Poll the stack - this processes received packets and sends pending data */ (void)wolfIP_poll(IPStack, tick); /* Increment tick counter (approximate 1ms per iteration at 64MHz HSI) * volatile loop ~8 cycles/iter: 8000 * 8 / 64MHz = 1ms */ tick++; delay(8000); -#ifdef DEBUG_H5_ETH +#endif +#if defined(DEBUG_H5_ETH) && !defined(ENABLE_WOLFHAL) if ((tick - dhcp_start_tick) % 500 == 0) { uint32_t dbg_polls = 0, dbg_pkts = 0; stm32_eth_get_stats(&dbg_polls, &dbg_pkts); @@ -1233,7 +1329,12 @@ int main(void) #endif for (;;) { +#ifdef ENABLE_WOLFHAL + tick = board_get_tick(); + (void)wolfIP_poll(IPStack, tick); +#else (void)wolfIP_poll(IPStack, tick++); +#endif #ifdef ENABLE_HTTPS /* Update HTTPS server status info for handler */ diff --git a/src/port/stm32h563/syscalls.c b/src/port/stm32h563/syscalls.c index c597b604..2a020ae7 100644 --- a/src/port/stm32h563/syscalls.c +++ b/src/port/stm32h563/syscalls.c @@ -24,6 +24,10 @@ #include #include #include +#ifdef ENABLE_WOLFHAL +#include +#include "board.h" /* g_whalUart for _write -> UART */ +#endif extern uint32_t _ebss; extern uint32_t _heap_limit; @@ -33,7 +37,12 @@ static char *heap_end; int _write(int file, const char *ptr, int len) { (void)file; +#ifdef ENABLE_WOLFHAL + if (len > 0) + whal_Uart_Send(&g_whalUart, ptr, (size_t)len); +#else (void)ptr; +#endif return len; } diff --git a/src/port/wolfHAL/README.md b/src/port/wolfHAL/README.md new file mode 100644 index 00000000..f86b1cda --- /dev/null +++ b/src/port/wolfHAL/README.md @@ -0,0 +1,72 @@ +# wolfHAL Ethernet bridge for wolfIP + +Generic, board-agnostic glue between wolfIP's link-layer device interface +and the wolfHAL Ethernet API (`whal_Eth` / `whal_EthPhy`). This directory +holds only the bridge: + +``` +src/port/wolfHAL/ +├── wolfhal_eth.h # Port API and wolfhal_eth_ctx struct +└── wolfhal_eth.c # Bridges wolfIP_ll_dev poll/send to whal_Eth_Recv/whal_Eth_Send +``` + +There is no platform code here — the bridge works with any board that +provides a configured `whal_Eth` and `whal_EthPhy`. Board bringup +(clocks, GPIO, MAC/PHY/RNG/UART init) and the bare-metal scaffolding +live in the chip port under `src/port//boards//`. + +## Reference integration + +`src/port/stm32h563/` integrates this bridge as an opt-in driver backend +for the NUCLEO-H563ZI board: + +``` +make -C src/port/stm32h563 ENABLE_WOLFHAL=1 +``` + +The build requires `TZEN=0` (the default) and `FREERTOS=0` (the default); +the Makefile errors out otherwise. `board_init()` programs the PLL +directly, which conflicts with the wolfBoot-launched non-secure clock +flow used by `TZEN=1`, and the wolfHAL SysTick driver owns the SysTick +handler that FreeRTOS also needs. + +`ENABLE_WOLFHAL=1` selects `boards/stm32h563zi_nucleo/` (its own +`startup.c`/`ivt.c`/`syscalls.c`/`linker.ld` plus `board.c`/`board.h`/`board.mk`), +pulls the wolfHAL STM32H5 driver TUs from a sibling wolfHAL checkout +(`WOLFHAL_ROOT ?= ../wolfHAL`), and compiles the port's `main.c` against +wolfHAL drivers instead of the hand-rolled bare-metal ones. + +## Port API + +```c +#include "wolfhal_eth.h" + +struct wolfhal_eth_ctx ctx = { + .eth = &g_whalEth, /* configured by board_init() */ + .phy = &g_whalEthPhy, +}; + +int ret = wolfhal_eth_init(wolfIP_getdev(ipstack), &ctx); +``` + +`wolfhal_eth_init` will: +1. Poll `whal_EthPhy_GetLinkState` until link comes up (5s timeout, + configurable via `WOLFHAL_ETH_LINK_TIMEOUT_MS`). +2. Start the MAC with the negotiated speed/duplex. +3. Copy `eth->macAddr` to the wolfIP device. +4. Register poll/send callbacks that bridge to `whal_Eth_Recv`/`whal_Eth_Send`. + +## What a board must provide + +The bridge needs the hardware already brought up. A board's `board.c` +(see `src/port/stm32h563/boards/stm32h563zi_nucleo/board.c`) must, before +`wolfhal_eth_init` is called: + +- Initialize clocks and GPIO, then call `whal_Eth_Init` / `whal_EthPhy_Init` + (typically from `board_init()`). +- Set the `whal_Eth` device's `macAddr` field — wolfIP reads the interface + MAC from there. +- Expose the devices the port references by name: `g_whalEth`, `g_whalEthPhy`, + and (for the port's `printf`/RNG hooks) `g_whalUart`, `g_whalRng`. +- Provide `uint32_t board_get_tick(void)` — a millisecond counter used both + for the `wolfhal_eth_init` link timeout and for `wolfIP_poll` timing. diff --git a/src/port/wolfHAL/wolfhal_eth.c b/src/port/wolfHAL/wolfhal_eth.c new file mode 100644 index 00000000..29d8d26f --- /dev/null +++ b/src/port/wolfHAL/wolfhal_eth.c @@ -0,0 +1,96 @@ +/* wolfhal_eth.c + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Generic wolfHAL Ethernet port for wolfIP + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP 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. + * + * wolfIP 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 "wolfhal_eth.h" +#include "board.h" +#include + +#ifndef WOLFHAL_ETH_LINK_TIMEOUT_MS +#define WOLFHAL_ETH_LINK_TIMEOUT_MS 5000 +#endif + +static int wolfhal_eth_poll(struct wolfIP_ll_dev *dev, void *buf, uint32_t len) +{ + struct wolfhal_eth_ctx *ctx = (struct wolfhal_eth_ctx *)dev->priv; + size_t recv_len = (size_t)len; + whal_Error err; + + err = whal_Eth_Recv(ctx->eth, buf, &recv_len); + if (err == WHAL_ENOTREADY) + return 0; + if (err != WHAL_SUCCESS) + return -1; + + return (int)recv_len; +} + +static int wolfhal_eth_send(struct wolfIP_ll_dev *dev, void *buf, uint32_t len) +{ + struct wolfhal_eth_ctx *ctx = (struct wolfhal_eth_ctx *)dev->priv; + whal_Error err; + + err = whal_Eth_Send(ctx->eth, buf, (size_t)len); + if (err != WHAL_SUCCESS) + return -1; + + return (int)len; +} + +int wolfhal_eth_init(struct wolfIP_ll_dev *ll, struct wolfhal_eth_ctx *ctx) +{ + uint8_t link_up, speed, duplex; + whal_Error err; + uint64_t start; + + if (ll == NULL || ctx == NULL || ctx->eth == NULL || ctx->phy == NULL) + return -1; + + /* Wait for PHY link to come up */ + link_up = 0; + start = board_get_tick(); + do { + err = whal_EthPhy_GetLinkState(ctx->phy, &link_up, &speed, &duplex); + if (err != WHAL_SUCCESS) + return -2; + if (link_up) + break; + } while ((board_get_tick() - start) < WOLFHAL_ETH_LINK_TIMEOUT_MS); + + if (!link_up) + return -4; + + /* Start the MAC with negotiated link parameters */ + err = whal_Eth_Start(ctx->eth, speed, duplex); + if (err != WHAL_SUCCESS) + return -3; + + /* Configure wolfIP device */ + memcpy(ll->mac, ctx->eth->macAddr, 6); + strncpy(ll->ifname, "eth0", sizeof(ll->ifname) - 1); + ll->ifname[sizeof(ll->ifname) - 1] = '\0'; + ll->poll = wolfhal_eth_poll; + ll->send = wolfhal_eth_send; + ll->priv = ctx; + + return 0; +} diff --git a/src/port/wolfHAL/wolfhal_eth.h b/src/port/wolfHAL/wolfhal_eth.h new file mode 100644 index 00000000..9c9be923 --- /dev/null +++ b/src/port/wolfHAL/wolfhal_eth.h @@ -0,0 +1,107 @@ +/* wolfhal_eth.h + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Generic wolfHAL Ethernet port for wolfIP + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP 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. + * + * wolfIP 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 + */ + +/** + * @file wolfhal_eth.h + * @brief Generic wolfHAL Ethernet port for wolfIP + * + * This port bridges wolfIP's link-layer device interface to wolfHAL's + * Ethernet MAC and PHY APIs. It works with any board that provides a + * configured whal_Eth and whal_EthPhy — no platform-specific code needed. + * + * ## Quick Start + * + * @code + * #include "wolfip.h" + * #include "wolfhal_eth.h" + * #include "board.h" + * + * int main(void) + * { + * struct wolfIP *ipstack; + * + * board_init(); + * + * struct wolfhal_eth_ctx eth_ctx = { + * .eth = &g_whalEth, + * .phy = &g_whalEthPhy, + * }; + * + * wolfIP_init_static(&ipstack); + * wolfhal_eth_init(wolfIP_getdev(ipstack), ð_ctx); + * wolfIP_ipconfig_set(ipstack, + * atoip4("192.168.1.100"), + * atoip4("255.255.255.0"), + * atoip4("192.168.1.1")); + * + * while (1) { + * wolfIP_poll(ipstack, board_get_tick()); + * } + * } + * @endcode + */ + +#ifndef WOLFIP_WOLFHAL_ETH_H +#define WOLFIP_WOLFHAL_ETH_H + +#include +#include "wolfip.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct wolfhal_eth_ctx { + whal_Eth *eth; + whal_EthPhy *phy; +}; + +/** + * @brief Initialize the wolfHAL Ethernet port for wolfIP + * + * Queries the PHY for link state, starts the MAC with the negotiated + * speed and duplex, and registers poll/send callbacks on the wolfIP + * device. + * + * Prerequisites: + * - board_init() (or equivalent) has already called whal_Eth_Init() + * and whal_EthPhy_Init() to set up the hardware. + * + * @param ll Pointer to wolfIP low-level device (from wolfIP_getdev()) + * @param ctx Caller-owned context with eth and phy already set + * + * @return 0 on success + * @return -1 if any argument is NULL + * @return -2 if PHY link state query fails + * @return -3 if MAC start fails + * @return -4 if PHY link did not come up within timeout + */ +int wolfhal_eth_init(struct wolfIP_ll_dev *ll, struct wolfhal_eth_ctx *ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFIP_WOLFHAL_ETH_H */ diff --git a/tools/scripts/run-m33mu-ci-in-container.sh b/tools/scripts/run-m33mu-ci-in-container.sh index 465115c2..b5121896 100755 --- a/tools/scripts/run-m33mu-ci-in-container.sh +++ b/tools/scripts/run-m33mu-ci-in-container.sh @@ -1,6 +1,10 @@ #!/usr/bin/env bash set -euo pipefail +# wolfHAL commit the wolfHAL jobs build against. CI passes this in from the +# workflow; the default keeps local runs on the same pinned HAL. +WOLFHAL_REF="${WOLFHAL_REF:-5302069e8d7baacefeeada94c4c8e5ef7426c1db}" + usage() { cat <<'EOF' Usage: tools/scripts/run-m33mu-ci-in-container.sh [job] @@ -39,6 +43,18 @@ ensure_repo() { fi } +ensure_repo_ref() { + local name="$1" + local url="$2" + local ref="$3" + if [ ! -d "../${name}/.git" ]; then + git init -q "../${name}" + git -C "../${name}" remote add origin "${url}" + git -C "../${name}" fetch --depth 1 origin "${ref}" + git -C "../${name}" checkout -q FETCH_HEAD + fi +} + build_echo() { make -C src/port/stm32h563 clean \ CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy @@ -46,6 +62,16 @@ build_echo() { CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy } +build_echo_wolfhal() { + ensure_repo_ref wolfHAL https://github.com/wolfSSL/wolfHAL.git "${WOLFHAL_REF}" + make -C src/port/stm32h563 clean TZEN=0 ENABLE_WOLFHAL=1 BOARD=stm32h563zi_nucleo \ + CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy + make -C src/port/stm32h563 TZEN=0 ENABLE_WOLFHAL=1 BOARD=stm32h563zi_nucleo \ + CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy + strings src/port/stm32h563/app.bin > /tmp/wolfip-app.strings + grep -Fq "Initializing Ethernet (wolfHAL" /tmp/wolfip-app.strings +} + build_full() { ensure_repo wolfssl https://github.com/wolfSSL/wolfssl.git ensure_repo wolfssh https://github.com/wolfSSL/wolfssh.git @@ -437,6 +463,39 @@ job_echo_freertos() { trap - EXIT } +job_echo_wolfhal() { + echo "==> Building stm32h563_m33mu_echo_wolfhal" + build_echo_wolfhal + echo "==> Running stm32h563_m33mu_echo_wolfhal" + trap cleanup_runtime EXIT + setup_tap_and_dnsmasq + tcpdump -i tap0 -nn -s0 -U -w /tmp/echo.pcap > /tmp/tcpdump.log 2>&1 & + printf '%s\n' "$!" > /tmp/tcpdump.pid + start_m33mu 180 --quit-on-faults + local ip + ip="$(wait_for_lease 90)" + echo "Leased IP: ${ip}" + local ok=0 + for _ in $(seq 1 60); do + check_alive + if timeout 10s bash -lc "printf 'wolfip-wolfhal-echo' | nc -w 5 '${ip}' 7" \ + | tee /tmp/echo.log | grep -q "^wolfip-wolfhal-echo$"; then + ok=1 + break + fi + sleep 0.5 + done + [ "${ok}" -eq 1 ] || { + echo "wolfHAL echo test failed." >&2 + tail -n 200 /tmp/m33mu.log || true + tail -n 200 /tmp/echo.log || true + exit 1 + } + echo "wolfHAL echo test succeeded." + cleanup_runtime + trap - EXIT +} + job_ssh_tzen() { echo "==> Building stm32h563_m33mu_ssh_tzen" build_ssh_tzen @@ -472,6 +531,7 @@ run_job() { case "$1" in stm32h563_m33mu_echo) job_echo ;; stm32h563_m33mu_echo_freertos) job_echo_freertos ;; + stm32h563_m33mu_echo_wolfhal) job_echo_wolfhal ;; stm32h563_m33mu_full) job_full ;; stm32h563_m33mu_https_tls13) job_https_tls13 ;; stm32h563_m33mu_https_freertos) job_https_freertos ;; @@ -493,6 +553,9 @@ run_workflow() { stm32h563-m33mu-freertos) run_job stm32h563_m33mu_echo_freertos ;; + stm32h563-m33mu-wolfhal) + run_job stm32h563_m33mu_echo_wolfhal + ;; stm32h563-m33mu-ssh-tzen) run_job stm32h563_m33mu_ssh_tzen ;; diff --git a/tools/scripts/run-m33mu-workflow.sh b/tools/scripts/run-m33mu-workflow.sh index 4866f002..9ba2219f 100755 --- a/tools/scripts/run-m33mu-workflow.sh +++ b/tools/scripts/run-m33mu-workflow.sh @@ -18,10 +18,14 @@ Accepted workflows: stm32h563-m33mu-ssh-tzen stm32h563-m33mu-ssh-tzen.yml .github/workflows/stm32h563-m33mu-ssh-tzen.yml + stm32h563-m33mu-wolfhal + wolfhal-stm32h563zi-nucleo.yml + .github/workflows/wolfhal-stm32h563zi-nucleo.yml Optional job names: stm32h563_m33mu_echo stm32h563_m33mu_echo_freertos + stm32h563_m33mu_echo_wolfhal stm32h563_m33mu_full stm32h563_m33mu_https_tls13 stm32h563_m33mu_https_freertos @@ -43,6 +47,9 @@ normalize_workflow() { stm32h563-m33mu-ssh-tzen|stm32h563-m33mu-ssh-tzen.yml|.github/workflows/stm32h563-m33mu-ssh-tzen.yml) printf '%s\n' stm32h563-m33mu-ssh-tzen ;; + stm32h563-m33mu-wolfhal|wolfhal-stm32h563zi-nucleo.yml|.github/workflows/wolfhal-stm32h563zi-nucleo.yml) + printf '%s\n' stm32h563-m33mu-wolfhal + ;; *) return 1 ;;