diff --git a/.github/workflows/wolfhal-stm32h563zi-nucleo.yml b/.github/workflows/wolfhal-stm32h563zi-nucleo.yml new file mode 100644 index 00000000..5abf421e --- /dev/null +++ b/.github/workflows/wolfhal-stm32h563zi-nucleo.yml @@ -0,0 +1,38 @@ +name: wolfHAL STM32H563ZI Nucleo Build + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +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: Clone wolfHAL + run: | + set -euo pipefail + git clone --depth 1 https://github.com/wolfSSL/wolfHAL.git ../wolfHAL + + - 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 diff --git a/Makefile b/Makefile index ba1760bb..7a2fcf0d 100644 --- a/Makefile +++ b/Makefile @@ -150,6 +150,8 @@ CPPCHECK_FLAGS=--enable=warning,performance,portability,missingInclude \ --suppress=comparePointers:src/port/rp2350_cyw43439/syscalls.c \ --suppress=unknownMacro:src/port/stm32h563/dot1x_client.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 41003368..4d26bfb9 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 @@ -122,6 +130,44 @@ CFLAGS_WOLFSSL := $(filter-out -Werror,$(CFLAGS_WOLFSSL)) CFLAGS_WOLFSSL += -Wno-unused-variable -Wno-unused-function CFLAGS_WOLFSSL += $(EXTRA_CFLAGS_WOLFSSL) +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 $(BOARD_DIR)/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 @@ -131,11 +177,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),) @@ -515,7 +562,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 @@ -576,6 +623,11 @@ factory: factory.bin $(WOLFSSL_ROOT)/%.o: $(WOLFSSL_ROOT)/%.c $(CC) $(CFLAGS_WOLFSSL) -DWOLFSSL_USER_SETTINGS $(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) -I$(WOLFSSL_ROOT) -c $< -o $@ +# 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 @@ -584,6 +636,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 @@ -614,7 +670,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 @@ -643,6 +699,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)" @@ -655,11 +713,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..cf9712ee --- /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 uint32_t g_tick = 0; + +void SysTick_Handler(void) +{ + g_tick++; +} + +uint32_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..6e8c4f96 --- /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 uint32_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 / 1000, \ + .clkSrc = WHAL_SYSTICK_CLKSRC_SYSCLK, \ + .tickInt = WHAL_SYSTICK_TICKINT_ENABLED, \ + }, \ +} + +whal_Error board_init(void); +whal_Error board_deinit(void); +uint32_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..a0c65d2b --- /dev/null +++ b/src/port/stm32h563/boards/stm32h563zi_nucleo/board.mk @@ -0,0 +1,31 @@ +# 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 + +# 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/boards/stm32h563zi_nucleo/syscalls.c b/src/port/stm32h563/boards/stm32h563zi_nucleo/syscalls.c new file mode 100644 index 00000000..302e5503 --- /dev/null +++ b/src/port/stm32h563/boards/stm32h563zi_nucleo/syscalls.c @@ -0,0 +1,121 @@ +/* syscalls.c + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Minimal libc stubs and wolfIP platform hooks for bare-metal. + * + * 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 +#include +#include +#include "board.h" /* g_whalUart singleton alias (single-instance UART) */ +extern uint32_t _ebss; +extern uint32_t _heap_limit; + +static char *heap_end; + +int _write(int file, const char *ptr, int len) +{ + (void)file; + if (len > 0) + whal_Uart_Send(&g_whalUart, ptr, (size_t)len); + return len; +} + +int _close(int file) +{ + (void)file; + return -1; +} + +int _fstat(int file, struct stat *st) +{ + (void)file; + if (st == NULL) { + errno = EINVAL; + return -1; + } + st->st_mode = S_IFCHR; + return 0; +} + +int _isatty(int file) +{ + (void)file; + return 1; +} + +int _lseek(int file, int ptr, int dir) +{ + (void)file; + (void)ptr; + (void)dir; + return 0; +} + +int _read(int file, char *ptr, int len) +{ + (void)file; + (void)ptr; + (void)len; + return 0; +} + +void *_sbrk(ptrdiff_t incr) +{ + char *prev; + if (heap_end == 0) + heap_end = (char *)&_ebss; + prev = heap_end; + if ((heap_end + incr) >= (char *)&_heap_limit) { + errno = ENOMEM; + return (void *)-1; + } + heap_end += incr; + return prev; +} + +void _exit(int status) +{ + (void)status; + while (1) { } +} + +int _kill(int pid, int sig) +{ + (void)pid; + (void)sig; + errno = EINVAL; + return -1; +} + +int _getpid(void) +{ + return 1; +} + +void _init(void) +{ +} + +void _fini(void) +{ +} + diff --git a/src/port/stm32h563/main.c b/src/port/stm32h563/main.c index 421be6c4..535f8d20 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" @@ -306,6 +313,7 @@ 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 +372,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 +406,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 +468,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 +509,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 +672,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 +748,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 +855,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 +877,7 @@ int main(void) /* Initialize UART for debug output */ uart_init(); rng_init(); +#endif /* Blink to show UART init done */ led_off(); @@ -849,6 +908,32 @@ 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); + { + static struct wolfhal_eth_ctx eth_ctx; + 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,7 +1054,11 @@ 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; +#endif #ifdef DEBUG_H5_ETH { uint32_t dbg_polls = 0, dbg_pkts = 0; @@ -1002,12 +1092,18 @@ 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); +#endif #ifdef DEBUG_H5_ETH if ((tick - dhcp_start_tick) % 500 == 0) { uint32_t dbg_polls = 0, dbg_pkts = 0; @@ -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/wolfHAL/README.md b/src/port/wolfHAL/README.md new file mode 100644 index 00000000..ec5aac29 --- /dev/null +++ b/src/port/wolfHAL/README.md @@ -0,0 +1,66 @@ +# 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 +``` + +`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..463b8522 --- /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; + uint32_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 */