From 8852f8ea65c0b9f09843a9b3bd7fc475ac277365 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Thu, 8 Jan 2026 18:48:56 +0100 Subject: [PATCH 1/4] STM32H563 port + test application --- src/port/stm32h563/Makefile | 28 ++ src/port/stm32h563/config.h | 56 ++++ src/port/stm32h563/ivt.c | 57 ++++ src/port/stm32h563/main.c | 106 ++++++++ src/port/stm32h563/startup.c | 47 ++++ src/port/stm32h563/stm32h5_eth.c | 443 +++++++++++++++++++++++++++++++ src/port/stm32h563/stm32h5_eth.h | 29 ++ src/port/stm32h563/syscalls.c | 141 ++++++++++ src/port/stm32h563/target.ld | 63 +++++ 9 files changed, 970 insertions(+) create mode 100644 src/port/stm32h563/Makefile create mode 100644 src/port/stm32h563/config.h create mode 100644 src/port/stm32h563/ivt.c create mode 100644 src/port/stm32h563/main.c create mode 100644 src/port/stm32h563/startup.c create mode 100644 src/port/stm32h563/stm32h5_eth.c create mode 100644 src/port/stm32h563/stm32h5_eth.h create mode 100644 src/port/stm32h563/syscalls.c create mode 100644 src/port/stm32h563/target.ld diff --git a/src/port/stm32h563/Makefile b/src/port/stm32h563/Makefile new file mode 100644 index 0000000..026557d --- /dev/null +++ b/src/port/stm32h563/Makefile @@ -0,0 +1,28 @@ +CC=arm-none-eabi-gcc +OBJCOPY ?= arm-none-eabi-objcopy + +ROOT := ../../.. + +CFLAGS := -mcpu=cortex-m33 -mthumb -mcmse -Os -ffreestanding -fdata-sections -ffunction-sections +CFLAGS += -g -ggdb -Wall -Wextra -Werror -Wdeclaration-after-statement +CFLAGS += -I. -I$(ROOT) -I$(ROOT)/src +LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections + +SRCS := startup.c ivt.c syscalls.c main.c stm32h5_eth.c $(ROOT)/src/wolfip.c +OBJS := $(patsubst %.c,%.o,$(SRCS)) + +all: app.bin + +app.elf: $(OBJS) target.ld + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group -o $@ + +app.bin: app.elf + $(OBJCOPY) -O binary $< $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJS) app.elf app.bin + +.PHONY: all clean diff --git a/src/port/stm32h563/config.h b/src/port/stm32h563/config.h new file mode 100644 index 0000000..eebf072 --- /dev/null +++ b/src/port/stm32h563/config.h @@ -0,0 +1,56 @@ +/* config.h + * + * Copyright (C) 2026 wolfSSL Inc. + * + * 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 WOLF_CONFIG_H +#define WOLF_CONFIG_H + +#ifndef CONFIG_IPFILTER +#define CONFIG_IPFILTER 0 +#endif + +#define ETHERNET +#define LINK_MTU 1536 + +#define MAX_TCPSOCKETS 4 +#define MAX_UDPSOCKETS 2 +#define MAX_ICMPSOCKETS 2 +#define RXBUF_SIZE (LINK_MTU * 16) +#define TXBUF_SIZE (LINK_MTU * 16) + +#define MAX_NEIGHBORS 16 + +#ifndef WOLFIP_MAX_INTERFACES +#define WOLFIP_MAX_INTERFACES 1 +#endif + +#ifndef WOLFIP_ENABLE_FORWARDING +#define WOLFIP_ENABLE_FORWARDING 0 +#endif + +#ifndef WOLFIP_ENABLE_LOOPBACK +#define WOLFIP_ENABLE_LOOPBACK 0 +#endif + +#define WOLFIP_IP "192.168.12.11" +#define WOLFIP_NETMASK "255.255.255.0" +#define WOLFIP_GW "192.168.12.1" +#define WOLFIP_STATIC_DNS_IP "9.9.9.9" + +#endif diff --git a/src/port/stm32h563/ivt.c b/src/port/stm32h563/ivt.c new file mode 100644 index 0000000..2ae1689 --- /dev/null +++ b/src/port/stm32h563/ivt.c @@ -0,0 +1,57 @@ +/* ivt.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * 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/main.c b/src/port/stm32h563/main.c new file mode 100644 index 0000000..f121dd0 --- /dev/null +++ b/src/port/stm32h563/main.c @@ -0,0 +1,106 @@ +/* main.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * 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 "config.h" +#include "wolfip.h" +#include "stm32h5_eth.h" + +#define ECHO_PORT 7 +#define RX_BUF_SIZE 1024 + +#define RCC_BASE 0x44020C00u +#define RCC_AHB1ENR (*(volatile uint32_t *)(RCC_BASE + 0x88u)) + +static struct wolfIP *IPStack; +static int listen_fd = -1; +static int client_fd = -1; +static uint8_t rx_buf[RX_BUF_SIZE]; + +uint32_t wolfIP_getrandom(void) +{ + static uint32_t lfsr = 0x1A2B3C4DU; + lfsr ^= lfsr << 13; + lfsr ^= lfsr >> 17; + lfsr ^= lfsr << 5; + return lfsr; +} + +static void echo_cb(int fd, uint16_t event, void *arg) +{ + struct wolfIP *s = (struct wolfIP *)arg; + int ret; + + if ((fd == listen_fd) && (event & CB_EVENT_READABLE) && (client_fd == -1)) { + client_fd = wolfIP_sock_accept(s, listen_fd, NULL, NULL); + if (client_fd > 0) { + wolfIP_register_callback(s, client_fd, echo_cb, s); + } + return; + } + + if ((fd == client_fd) && (event & CB_EVENT_READABLE)) { + ret = wolfIP_sock_recvfrom(s, client_fd, rx_buf, sizeof(rx_buf), 0, NULL, NULL); + if (ret > 0) { + (void)wolfIP_sock_sendto(s, client_fd, rx_buf, (uint32_t)ret, 0, NULL, 0); + } else if (ret == 0) { + wolfIP_sock_close(s, client_fd); + client_fd = -1; + } + } + + if ((fd == client_fd) && (event & CB_EVENT_CLOSED)) { + wolfIP_sock_close(s, client_fd); + client_fd = -1; + } +} + +int main(void) +{ + struct wolfIP_ll_dev *ll; + struct wolfIP_sockaddr_in addr; + uint64_t tick = 0; + + wolfIP_init_static(&IPStack); + RCC_AHB1ENR |= (1u << 19) | (1u << 20) | (1u << 21); + ll = wolfIP_getdev(IPStack); + (void)stm32h5_eth_init(ll, NULL); + + wolfIP_ipconfig_set(IPStack, + atoip4(WOLFIP_IP), + atoip4(WOLFIP_NETMASK), + atoip4(WOLFIP_GW)); + + listen_fd = wolfIP_sock_socket(IPStack, AF_INET, IPSTACK_SOCK_STREAM, 0); + wolfIP_register_callback(IPStack, listen_fd, echo_cb, IPStack); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = ee16(ECHO_PORT); + addr.sin_addr.s_addr = 0; + (void)wolfIP_sock_bind(IPStack, listen_fd, (struct wolfIP_sockaddr *)&addr, sizeof(addr)); + (void)wolfIP_sock_listen(IPStack, listen_fd, 1); + + for (;;) { + (void)wolfIP_poll(IPStack, tick++); + } + return 0; +} diff --git a/src/port/stm32h563/startup.c b/src/port/stm32h563/startup.c new file mode 100644 index 0000000..53cecea --- /dev/null +++ b/src/port/stm32h563/startup.c @@ -0,0 +1,47 @@ +/* startup.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * 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/stm32h5_eth.c b/src/port/stm32h563/stm32h5_eth.c new file mode 100644 index 0000000..4530338 --- /dev/null +++ b/src/port/stm32h563/stm32h5_eth.c @@ -0,0 +1,443 @@ +/* stm32h5_eth.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * 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 "config.h" +#include "stm32h5_eth.h" + +#define ETH_BASE 0x40028000UL +#define ETH_REG(offset) (*(volatile uint32_t *)(ETH_BASE + (offset))) +#define ETH_TPDR ETH_REG(0x1180U) + +/* MAC registers */ +#define ETH_MACCR ETH_REG(0x0000U) +#define ETH_MACPFR ETH_REG(0x0004U) +#define ETH_MACA0HR ETH_REG(0x0300U) +#define ETH_MACA0LR ETH_REG(0x0304U) + +/* MTL registers */ +#define ETH_MTLTXQOMR ETH_REG(0x0D00U) +#define ETH_MTLRXQOMR ETH_REG(0x0D30U) + +/* DMA registers */ +#define ETH_DMAMR ETH_REG(0x1000U) +#define ETH_DMASBMR ETH_REG(0x1004U) +#define ETH_DMACTXCR ETH_REG(0x1104U) +#define ETH_DMACRXCR ETH_REG(0x1108U) +#define ETH_DMACTXDLAR ETH_REG(0x1114U) +#define ETH_DMACRXDLAR ETH_REG(0x111CU) +#define ETH_DMACTXDTPR ETH_REG(0x1120U) +#define ETH_DMACRXDTPR ETH_REG(0x1128U) +#define ETH_DMACTXRLR ETH_REG(0x112CU) +#define ETH_DMACRXRLR ETH_REG(0x1130U) +#define ETH_DMACSR ETH_REG(0x1160U) +#define ETH_MACMDIOAR ETH_REG(0x0200U) +#define ETH_MACMDIODR ETH_REG(0x0204U) + +/* MAC control bits */ +#define ETH_MACCR_RE (1U << 0) +#define ETH_MACCR_TE (1U << 1) +#define ETH_MACCR_DM (1U << 13) +#define ETH_MACCR_FES (1U << 14) + +/* DMA bits */ +#define ETH_DMAMR_SWR (1U << 0) +#define ETH_DMASBMR_FB (1U << 0) +#define ETH_DMASBMR_AAL (1U << 12) + +#define ETH_DMACTXCR_ST (1U << 0) +#define ETH_DMACTXCR_OSF (1U << 4) +#define ETH_DMACRXCR_SR (1U << 0) +#define ETH_DMACRXCR_RBSZ_SHIFT 1 +#define ETH_DMACSR_TBU (1U << 2) +#define ETH_DMACTXCR_TPBL_SHIFT 16 +#define ETH_DMACTXCR_TPBL(val) (((uint32_t)(val) & 0x3FU) << ETH_DMACTXCR_TPBL_SHIFT) +#define ETH_DMACRXCR_RPBL_SHIFT 16 +#define ETH_DMACRXCR_RPBL(val) (((uint32_t)(val) & 0x3FU) << ETH_DMACRXCR_RPBL_SHIFT) + +/* MTL bits */ +#define ETH_MTLTXQOMR_FTQ (1U << 0) +#define ETH_MTLTXQOMR_TSF (1U << 1) +#define ETH_MTLTXQOMR_TXQEN_SHIFT 2 +#define ETH_MTLTXQOMR_TXQEN_ENABLE (2U << ETH_MTLTXQOMR_TXQEN_SHIFT) +#define ETH_MTLTXQOMR_MASK 0x00000072U +#define ETH_MTLRXQOMR_RSF (1U << 5) +#define ETH_MTLRXQOMR_MASK 0x0000007BU + +#define ETH_MACMDIOAR_MB (1U << 0) +#define ETH_MACMDIOAR_GOC_SHIFT 2 +#define ETH_MACMDIOAR_GOC_WRITE 0x1U +#define ETH_MACMDIOAR_GOC_READ 0x3U +#define ETH_MACMDIOAR_CR_SHIFT 8 +#define ETH_MACMDIOAR_RDA_SHIFT 16 +#define ETH_MACMDIOAR_PA_SHIFT 21 + +#define PHY_REG_BCR 0x00U +#define PHY_REG_BSR 0x01U +#define PHY_REG_ID1 0x02U +#define PHY_REG_ANAR 0x04U +#define PHY_REG_SCSR 0x1FU + +#define PHY_BCR_RESET (1U << 15) +#define PHY_BCR_SPEED_100 (1U << 13) +#define PHY_BCR_AUTONEG_ENABLE (1U << 12) +#define PHY_BCR_POWER_DOWN (1U << 11) +#define PHY_BCR_ISOLATE (1U << 10) +#define PHY_BCR_RESTART_AUTONEG (1U << 9) +#define PHY_BCR_FULL_DUPLEX (1U << 8) + +#define PHY_BSR_LINK_STATUS (1U << 2) +#define PHY_BSR_AUTONEG_COMPLETE (1U << 5) +#define PHY_BSR_10_HALF (1U << 11) +#define PHY_BSR_10_FULL (1U << 12) +#define PHY_BSR_100_HALF (1U << 13) +#define PHY_BSR_100_FULL (1U << 14) + +#define PHY_ANAR_DEFAULT 0x01E1U + +struct eth_desc { + volatile uint32_t des0; + volatile uint32_t des1; + volatile uint32_t des2; + volatile uint32_t des3; +}; + +#define ETH_TDES3_OWN (1U << 31) +#define ETH_TDES3_FD (1U << 29) +#define ETH_TDES3_LD (1U << 28) +#define ETH_TDES2_B1L_MASK (0x3FFFU) +#define ETH_TDES3_FL_MASK (0x7FFFU) + +#define ETH_RDES3_OWN (1U << 31) +#define ETH_RDES3_BUF1V (1U << 24) +#define ETH_RDES3_FS (1U << 29) +#define ETH_RDES3_LS (1U << 28) +#define ETH_RDES3_PL_MASK (0x3FFFU) + +#define RX_DESC_COUNT 4U +#define TX_DESC_COUNT 3U +#define RX_BUF_SIZE LINK_MTU +#define TX_BUF_SIZE LINK_MTU +#define FRAME_MIN_LEN 60U +#define DMA_TPBL 32U +#define DMA_RPBL 32U + +static struct eth_desc rx_ring[RX_DESC_COUNT] __attribute__((aligned(32))); +static struct eth_desc tx_ring[TX_DESC_COUNT] __attribute__((aligned(32))); +static uint8_t rx_buffers[RX_DESC_COUNT][RX_BUF_SIZE] __attribute__((aligned(32))); +static uint8_t tx_buffers[TX_DESC_COUNT][TX_BUF_SIZE] __attribute__((aligned(32))); +static uint8_t rx_staging_buffer[RX_BUF_SIZE] __attribute__((aligned(32))); + +static uint32_t rx_idx; +static uint32_t tx_idx; +static int32_t phy_addr = -1; + +static void eth_hw_reset(void) +{ + ETH_DMAMR |= ETH_DMAMR_SWR; + while (ETH_DMAMR & ETH_DMAMR_SWR) { + } +} + +static void eth_trigger_tx(void) +{ + ETH_TPDR = 0U; + __asm volatile ("dsb sy" ::: "memory"); +} + +static uint16_t eth_mdio_read(uint32_t phy, uint32_t reg); +static void eth_mdio_write(uint32_t phy, uint32_t reg, uint16_t value); + +static void eth_config_mac(const uint8_t mac[6]) +{ + uint32_t maccr = ETH_MACCR; + maccr &= ~(ETH_MACCR_DM | ETH_MACCR_FES); + maccr |= ETH_MACCR_DM | ETH_MACCR_FES; + ETH_MACCR = maccr; + ETH_MACPFR = 0U; + ETH_MACA0HR = ((uint32_t)mac[5] << 8) | (uint32_t)mac[4]; + ETH_MACA0LR = ((uint32_t)mac[3] << 24) | + ((uint32_t)mac[2] << 16) | + ((uint32_t)mac[1] << 8) | + (uint32_t)mac[0]; +} + +static void eth_config_speed_duplex(void) +{ + uint32_t maccr; + uint16_t bsr; + + if (phy_addr < 0) return; + + maccr = ETH_MACCR; + maccr &= ~(ETH_MACCR_FES | ETH_MACCR_DM); + bsr = eth_mdio_read((uint32_t)phy_addr, PHY_REG_BSR); + bsr |= eth_mdio_read((uint32_t)phy_addr, PHY_REG_BSR); + + if ((bsr & PHY_BSR_100_FULL) != 0U) { + maccr |= ETH_MACCR_FES | ETH_MACCR_DM; + } else if ((bsr & PHY_BSR_100_HALF) != 0U) { + maccr |= ETH_MACCR_FES; + } else if ((bsr & PHY_BSR_10_FULL) != 0U) { + maccr |= ETH_MACCR_DM; + } + ETH_MACCR = maccr; +} + +static void eth_config_mtl(void) +{ + uint32_t txqomr = ETH_MTLTXQOMR; + uint32_t rxqomr = ETH_MTLRXQOMR; + + txqomr &= ~ETH_MTLTXQOMR_MASK; + txqomr |= (ETH_MTLTXQOMR_TSF | ETH_MTLTXQOMR_TXQEN_ENABLE); + ETH_MTLTXQOMR = txqomr; + + rxqomr &= ~ETH_MTLRXQOMR_MASK; + rxqomr |= ETH_MTLRXQOMR_RSF; + ETH_MTLRXQOMR = rxqomr; +} + +static void eth_init_desc(void) +{ + uint32_t i; + for (i = 0; i < TX_DESC_COUNT; i++) { + tx_ring[i].des0 = (uint32_t)tx_buffers[i]; + tx_ring[i].des1 = 0; + tx_ring[i].des2 = 0; + tx_ring[i].des3 = 0; + } + for (i = 0; i < RX_DESC_COUNT; i++) { + rx_ring[i].des0 = (uint32_t)rx_buffers[i]; + rx_ring[i].des1 = 0; + rx_ring[i].des2 = 0; + rx_ring[i].des3 = (RX_BUF_SIZE & ETH_RDES3_PL_MASK) | + ETH_RDES3_OWN | + ETH_RDES3_BUF1V; + } + rx_idx = 0; + tx_idx = 0; + ETH_DMACTXDLAR = (uint32_t)&tx_ring[0]; + ETH_DMACRXDLAR = (uint32_t)&rx_ring[0]; + ETH_DMACTXRLR = TX_DESC_COUNT - 1U; + ETH_DMACRXRLR = RX_DESC_COUNT - 1U; + ETH_DMACTXDTPR = (uint32_t)&tx_ring[0]; + ETH_DMACRXDTPR = (uint32_t)&rx_ring[RX_DESC_COUNT - 1U]; +} + +static void eth_config_dma(void) +{ + ETH_DMASBMR = ETH_DMASBMR_FB | ETH_DMASBMR_AAL; + ETH_DMACRXCR = ((RX_BUF_SIZE & ETH_RDES3_PL_MASK) << ETH_DMACRXCR_RBSZ_SHIFT) | + ETH_DMACRXCR_RPBL(DMA_RPBL); + ETH_DMACTXCR = ETH_DMACTXCR_OSF | ETH_DMACTXCR_TPBL(DMA_TPBL); +} + +static void eth_start(void) +{ + ETH_MACCR |= ETH_MACCR_TE | ETH_MACCR_RE; + ETH_MTLTXQOMR |= ETH_MTLTXQOMR_FTQ; + ETH_DMACTXCR |= ETH_DMACTXCR_ST; + ETH_DMACRXCR |= ETH_DMACRXCR_SR; +} + +static void eth_stop(void) +{ + ETH_DMACTXCR &= ~ETH_DMACTXCR_ST; + ETH_DMACRXCR &= ~ETH_DMACRXCR_SR; + ETH_MACCR &= ~ETH_MACCR_RE; + ETH_MTLTXQOMR |= ETH_MTLTXQOMR_FTQ; + ETH_MACCR &= ~ETH_MACCR_TE; +} + +static void eth_mdio_wait_ready(void) +{ + uint32_t timeout = 100000U; + while ((ETH_MACMDIOAR & ETH_MACMDIOAR_MB) != 0U && timeout != 0U) { + timeout--; + } +} + +static uint16_t eth_mdio_read(uint32_t phy, uint32_t reg) +{ + uint32_t cfg; + eth_mdio_wait_ready(); + cfg = (4U << ETH_MACMDIOAR_CR_SHIFT) | + (reg << ETH_MACMDIOAR_RDA_SHIFT) | + (phy << ETH_MACMDIOAR_PA_SHIFT) | + (ETH_MACMDIOAR_GOC_READ << ETH_MACMDIOAR_GOC_SHIFT); + ETH_MACMDIOAR = cfg | ETH_MACMDIOAR_MB; + eth_mdio_wait_ready(); + return (uint16_t)(ETH_MACMDIODR & 0xFFFFU); +} + +static void eth_mdio_write(uint32_t phy, uint32_t reg, uint16_t value) +{ + uint32_t cfg; + eth_mdio_wait_ready(); + ETH_MACMDIODR = (uint32_t)value; + cfg = (4U << ETH_MACMDIOAR_CR_SHIFT) | + (reg << ETH_MACMDIOAR_RDA_SHIFT) | + (phy << ETH_MACMDIOAR_PA_SHIFT) | + (ETH_MACMDIOAR_GOC_WRITE << ETH_MACMDIOAR_GOC_SHIFT); + ETH_MACMDIOAR = cfg | ETH_MACMDIOAR_MB; + eth_mdio_wait_ready(); +} + +static int32_t eth_detect_phy(void) +{ + uint32_t addr; + for (addr = 0U; addr < 32U; addr++) { + uint16_t id1 = eth_mdio_read(addr, PHY_REG_ID1); + if (id1 != 0xFFFFU && id1 != 0x0000U) { + return (int32_t)addr; + } + } + return -1; +} + +static void eth_phy_init(void) +{ + uint32_t timeout; + uint16_t ctrl; + uint16_t bsr; + + if (phy_addr < 0) { + phy_addr = eth_detect_phy(); + if (phy_addr < 0) phy_addr = 0; + } + + eth_mdio_write((uint32_t)phy_addr, PHY_REG_BCR, PHY_BCR_RESET); + timeout = 100000U; + do { + ctrl = eth_mdio_read((uint32_t)phy_addr, PHY_REG_BCR); + } while ((ctrl & PHY_BCR_RESET) != 0U && --timeout != 0U); + + ctrl &= ~(PHY_BCR_POWER_DOWN | PHY_BCR_ISOLATE | PHY_BCR_SPEED_100 | PHY_BCR_FULL_DUPLEX); + eth_mdio_write((uint32_t)phy_addr, PHY_REG_ANAR, PHY_ANAR_DEFAULT); + ctrl |= PHY_BCR_AUTONEG_ENABLE | PHY_BCR_RESTART_AUTONEG; + eth_mdio_write((uint32_t)phy_addr, PHY_REG_BCR, ctrl); + + timeout = 100000U; + do { + bsr = eth_mdio_read((uint32_t)phy_addr, PHY_REG_BSR); + bsr |= eth_mdio_read((uint32_t)phy_addr, PHY_REG_BSR); + } while ((bsr & PHY_BSR_AUTONEG_COMPLETE) == 0U && --timeout != 0U); + + timeout = 100000U; + do { + bsr = eth_mdio_read((uint32_t)phy_addr, PHY_REG_BSR); + bsr |= eth_mdio_read((uint32_t)phy_addr, PHY_REG_BSR); + } while ((bsr & PHY_BSR_LINK_STATUS) == 0U && --timeout != 0U); +} + +static int eth_poll(struct wolfIP_ll_dev *dev, void *frame, uint32_t len) +{ + struct eth_desc *desc; + uint32_t status; + uint32_t frame_len = 0; + + (void)dev; + desc = &rx_ring[rx_idx]; + if (desc->des3 & ETH_RDES3_OWN) return 0; + status = desc->des3; + if ((status & (ETH_RDES3_FS | ETH_RDES3_LS)) == + (ETH_RDES3_FS | ETH_RDES3_LS)) { + frame_len = status & ETH_RDES3_PL_MASK; + if (frame_len > len) frame_len = len; + memcpy(rx_staging_buffer, rx_buffers[rx_idx], frame_len); + memcpy(frame, rx_staging_buffer, frame_len); + } + desc->des1 = 0; + desc->des3 = (RX_BUF_SIZE & ETH_RDES3_PL_MASK) | + ETH_RDES3_OWN | + ETH_RDES3_BUF1V; + __asm volatile ("dsb sy" ::: "memory"); + ETH_DMACRXDTPR = (uint32_t)desc; + rx_idx = (rx_idx + 1U) % RX_DESC_COUNT; + return (int)frame_len; +} + +static int eth_send(struct wolfIP_ll_dev *dev, void *frame, uint32_t len) +{ + struct eth_desc *desc; + uint32_t dma_len; + uint32_t next_idx; + + (void)dev; + if (len == 0 || len > TX_BUF_SIZE) return -1; + desc = &tx_ring[tx_idx]; + if (desc->des3 & ETH_TDES3_OWN) return -2; + memcpy(tx_buffers[tx_idx], frame, len); + dma_len = (len < FRAME_MIN_LEN) ? FRAME_MIN_LEN : len; + if (dma_len > len) memset(tx_buffers[tx_idx] + len, 0, dma_len - len); + desc->des0 = (uint32_t)tx_buffers[tx_idx]; + desc->des1 = 0; + desc->des2 = (dma_len & ETH_TDES2_B1L_MASK); + __asm volatile ("dsb sy" ::: "memory"); + desc->des3 = (dma_len & ETH_TDES3_FL_MASK) | + ETH_TDES3_FD | + ETH_TDES3_LD | + ETH_TDES3_OWN; + __asm volatile ("dsb sy" ::: "memory"); + ETH_DMACSR = ETH_DMACSR_TBU; + if (tx_idx == 0U) eth_trigger_tx(); + next_idx = (tx_idx + 1U) % TX_DESC_COUNT; + ETH_DMACTXDTPR = (uint32_t)&tx_ring[next_idx]; + tx_idx = next_idx; + return (int)len; +} + +static void stm32h5_eth_generate_mac(uint8_t mac[6]) +{ + mac[0] = 0x02; + mac[1] = 0x11; + mac[2] = 0xAA; + mac[3] = 0xBB; + mac[4] = 0x22; + mac[5] = 0x33; +} + +int stm32h5_eth_init(struct wolfIP_ll_dev *ll, const uint8_t *mac) +{ + uint8_t local_mac[6]; + if (ll == NULL) return -1; + if (mac == NULL) { + stm32h5_eth_generate_mac(local_mac); + mac = local_mac; + } + memcpy(ll->mac, mac, 6); + strncpy(ll->ifname, "eth0", sizeof(ll->ifname) - 1); + ll->ifname[sizeof(ll->ifname) - 1] = '\0'; + ll->poll = eth_poll; + ll->send = eth_send; + + eth_stop(); + eth_hw_reset(); + eth_config_mac(mac); + eth_config_mtl(); + eth_init_desc(); + eth_config_dma(); + eth_phy_init(); + eth_config_speed_duplex(); + eth_start(); + return 0; +} diff --git a/src/port/stm32h563/stm32h5_eth.h b/src/port/stm32h563/stm32h5_eth.h new file mode 100644 index 0000000..0b31e11 --- /dev/null +++ b/src/port/stm32h563/stm32h5_eth.h @@ -0,0 +1,29 @@ +/* stm32h5_eth.h + * + * Copyright (C) 2026 wolfSSL Inc. + * + * 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 WOLFIP_STM32H5_ETH_H +#define WOLFIP_STM32H5_ETH_H + +#include +#include "wolfip.h" + +int stm32h5_eth_init(struct wolfIP_ll_dev *ll, const uint8_t *mac); + +#endif diff --git a/src/port/stm32h563/syscalls.c b/src/port/stm32h563/syscalls.c new file mode 100644 index 0000000..034d707 --- /dev/null +++ b/src/port/stm32h563/syscalls.c @@ -0,0 +1,141 @@ +/* syscalls.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * 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 + +extern uint32_t _ebss; +extern uint32_t _estack; + +static char *heap_end; + +int _write(int file, const char *ptr, int len) +{ + (void)file; + (void)ptr; + return len; +} + +int _close(int file) +{ + (void)file; + return -1; +} + +int _fstat(int file, struct stat *st) +{ + (void)file; + if (st == 0) { + 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 *)&_estack) { + errno = ENOMEM; + return (void *)-1; + } + heap_end += incr; + return prev; +} + +int _gettimeofday(struct timeval *tv, void *tzvp) +{ + (void)tzvp; + if (tv == 0) { + errno = EINVAL; + return -1; + } + tv->tv_sec = 0; + tv->tv_usec = 0; + return 0; +} + +time_t time(time_t *t) +{ + if (t != 0) { + *t = 0; + } + return 0; +} + +void _exit(int status) +{ + (void)status; + while (1) { + __asm volatile("wfi"); + } +} + +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/target.ld b/src/port/stm32h563/target.ld new file mode 100644 index 0000000..32a273c --- /dev/null +++ b/src/port/stm32h563/target.ld @@ -0,0 +1,63 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x0C000000, LENGTH = 0x00200000 + RAM (rwx) : ORIGIN = 0x30000000, LENGTH = 0x000A0000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > 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 : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} From 2f5df913ab07d7731b60e23b7040ea72b60af78c Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 15 Jan 2026 11:37:04 -0800 Subject: [PATCH 2/4] Fixes to get working NUCLEO-STM32H563ZI --- .gitignore | 1 + src/port/stm32h563/main.c | 383 ++++++++++++++++++++++++++++++- src/port/stm32h563/stm32h5_eth.c | 179 +++++++++++++-- src/port/stm32h563/stm32h5_eth.h | 14 ++ src/port/stm32h563/target.ld | 5 +- src/wolfip.c | 10 +- 6 files changed, 570 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index 01d773e..3e93391 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ build/* test/unit/unit tags cppcheck_results.xml +src/port/stm32h563/app.elf diff --git a/src/port/stm32h563/main.c b/src/port/stm32h563/main.c index f121dd0..188a3f0 100644 --- a/src/port/stm32h563/main.c +++ b/src/port/stm32h563/main.c @@ -28,7 +28,51 @@ #define RX_BUF_SIZE 1024 #define RCC_BASE 0x44020C00u -#define RCC_AHB1ENR (*(volatile uint32_t *)(RCC_BASE + 0x88u)) +#define RCC_AHB1ENR (*(volatile uint32_t *)(RCC_BASE + 0x88u)) +#define RCC_AHB2ENR (*(volatile uint32_t *)(RCC_BASE + 0x8Cu)) +#define RCC_APB3ENR (*(volatile uint32_t *)(RCC_BASE + 0xA8u)) +#define RCC_AHB1RSTR (*(volatile uint32_t *)(RCC_BASE + 0x60u)) +#define RCC_AHB1RSTR_ETHRST (1u << 19) + +/* GTZC (Global TrustZone Controller) - unlock SRAM for DMA access */ +#define GTZC1_BASE 0x40032400u /* Non-secure alias */ +#define GTZC1_MPCBB1_CR (*(volatile uint32_t *)(GTZC1_BASE + 0x800u)) +#define GTZC1_MPCBB2_CR (*(volatile uint32_t *)(GTZC1_BASE + 0xC00u)) +#define GTZC1_MPCBB3_CR (*(volatile uint32_t *)(GTZC1_BASE + 0x1000u)) + +/* GPIO base addresses */ +#define GPIOA_BASE 0x42020000u +#define GPIOB_BASE 0x42020400u +#define GPIOC_BASE 0x42020800u +#define GPIOG_BASE 0x42021800u + +/* GPIO register offsets */ +#define GPIO_MODER(base) (*(volatile uint32_t *)((base) + 0x00u)) +#define GPIO_OSPEEDR(base) (*(volatile uint32_t *)((base) + 0x08u)) +#define GPIO_PUPDR(base) (*(volatile uint32_t *)((base) + 0x0Cu)) +#define GPIO_AFRL(base) (*(volatile uint32_t *)((base) + 0x20u)) +#define GPIO_AFRH(base) (*(volatile uint32_t *)((base) + 0x24u)) + +/* SBS (System Bus Security) for RMII selection */ +/* SBS register definitions - PMCR is at offset 0x100 in SBS structure */ +#define SBS_BASE 0x44000400u +#define SBS_PMCR (*(volatile uint32_t *)(SBS_BASE + 0x100u)) +#define SBS_PMCR_ETH_SEL_RMII (4u << 21) + +/* USART3 for debug output (ST-Link VCP on NUCLEO-H563ZI) */ +#define GPIOD_BASE 0x42020C00u +#define GPIOF_BASE 0x42021400u +#define RCC_APB1ENR (*(volatile uint32_t *)(RCC_BASE + 0x9Cu)) +#define USART3_BASE 0x40004800u +#define USART3_CR1 (*(volatile uint32_t *)(USART3_BASE + 0x00u)) +#define USART3_BRR (*(volatile uint32_t *)(USART3_BASE + 0x0Cu)) +#define USART3_ISR (*(volatile uint32_t *)(USART3_BASE + 0x1Cu)) +#define USART3_TDR (*(volatile uint32_t *)(USART3_BASE + 0x28u)) + +/* LED2 on PF4 */ +#define GPIO_ODR(base) (*(volatile uint32_t *)((base) + 0x14u)) +#define GPIO_BSRR(base) (*(volatile uint32_t *)((base) + 0x18u)) +#define LED2_PIN 4u static struct wolfIP *IPStack; static int listen_fd = -1; @@ -44,6 +88,200 @@ uint32_t wolfIP_getrandom(void) return lfsr; } +/* Simple delay */ +static void delay(uint32_t count) +{ + for (volatile uint32_t i = 0; i < count; i++) { } +} + +/* Initialize LED2 on PF4 */ +static void led_init(void) +{ + uint32_t moder; + + /* Enable GPIOF clock */ + RCC_AHB2ENR |= (1u << 5); + delay(100); + + /* Set PF4 as output */ + moder = GPIO_MODER(GPIOF_BASE); + moder &= ~(3u << (LED2_PIN * 2u)); + moder |= (1u << (LED2_PIN * 2u)); /* Output mode */ + GPIO_MODER(GPIOF_BASE) = moder; +} + +static void led_on(void) +{ + GPIO_BSRR(GPIOF_BASE) = (1u << LED2_PIN); +} + +static void led_off(void) +{ + GPIO_BSRR(GPIOF_BASE) = (1u << (LED2_PIN + 16u)); +} + +static void led_toggle(void) +{ + GPIO_ODR(GPIOF_BASE) ^= (1u << LED2_PIN); +} + +/* USART3 additional registers */ +#define USART3_CR2 (*(volatile uint32_t *)(USART3_BASE + 0x04u)) +#define USART3_CR3 (*(volatile uint32_t *)(USART3_BASE + 0x08u)) +#define USART3_PRESC (*(volatile uint32_t *)(USART3_BASE + 0x2Cu)) + +/* Initialize USART3 for debug output (115200 baud @ 64MHz HSI) */ +static void uart_init(void) +{ + uint32_t moder, afr; + + /* Enable GPIOD clock */ + RCC_AHB2ENR |= (1u << 3); + /* Enable USART3 clock (APB1LENR bit 18) */ + RCC_APB1ENR |= (1u << 18); + + delay(100); + + /* Configure PD8 (TX) as AF7, push-pull, high speed */ + moder = GPIO_MODER(GPIOD_BASE); + moder &= ~(3u << 16); /* Clear PD8 mode */ + moder |= (2u << 16); /* Alternate function */ + GPIO_MODER(GPIOD_BASE) = moder; + + GPIO_OSPEEDR(GPIOD_BASE) |= (3u << 16); /* High speed for PD8 */ + + afr = GPIO_AFRH(GPIOD_BASE); + afr &= ~(0xFu << 0); /* PD8 is AFRH bit 0-3 */ + afr |= (7u << 0); /* AF7 = USART3 */ + GPIO_AFRH(GPIOD_BASE) = afr; + + /* Disable USART before configuration */ + USART3_CR1 = 0; + + /* Configure USART3: 115200 baud, assuming PCLK1 = 32MHz */ + USART3_CR2 = 0; /* 1 stop bit */ + USART3_CR3 = 0; /* No flow control, disable FIFO */ + USART3_PRESC = 0; /* No prescaler */ + USART3_BRR = 32000000u / 115200u; /* 278 */ + + /* Enable transmitter, then enable USART */ + USART3_CR1 = (1u << 3); /* TE */ + delay(10); + USART3_CR1 |= (1u << 0); /* UE */ + delay(100); +} + +static void uart_putc(char c) +{ + while ((USART3_ISR & (1u << 7)) == 0) { } /* Wait for TXE */ + USART3_TDR = (uint32_t)c; +} + +static void uart_puts(const char *s) +{ + while (*s) { + if (*s == '\n') uart_putc('\r'); + uart_putc(*s++); + } +} + +static void uart_puthex(uint32_t val) +{ + const char hex[] = "0123456789ABCDEF"; + uart_puts("0x"); + for (int i = 28; i >= 0; i -= 4) { + uart_putc(hex[(val >> i) & 0xF]); + } +} + +/* Configure GPIO pin for Ethernet alternate function (AF11) */ +static void gpio_eth_pin(uint32_t base, uint32_t pin) +{ + uint32_t moder, ospeedr, afr; + uint32_t pos2 = pin * 2u; + + /* Set mode to alternate function (0b10) */ + moder = GPIO_MODER(base); + moder &= ~(3u << pos2); + moder |= (2u << pos2); + GPIO_MODER(base) = moder; + + /* Set high speed */ + ospeedr = GPIO_OSPEEDR(base); + ospeedr |= (3u << pos2); + GPIO_OSPEEDR(base) = ospeedr; + + /* Set AF11 for Ethernet */ + if (pin < 8u) { + afr = GPIO_AFRL(base); + afr &= ~(0xFu << (pin * 4u)); + afr |= (11u << (pin * 4u)); + GPIO_AFRL(base) = afr; + } else { + afr = GPIO_AFRH(base); + afr &= ~(0xFu << ((pin - 8u) * 4u)); + afr |= (11u << ((pin - 8u) * 4u)); + GPIO_AFRH(base) = afr; + } +} + +/* Initialize GPIO pins for RMII Ethernet (NUCLEO-H563ZI pinout) */ +static void eth_gpio_init(void) +{ + /* SBS->PMCR is at SBS_BASE + 0x100 = 0x44000400 + 0x100 = 0x44000500 */ + volatile uint32_t *sbs_pmcr = (volatile uint32_t *)(0x44000500u); + uint32_t val; + + /* Enable GPIO clocks: A, B, C, G */ + RCC_AHB2ENR |= (1u << 0) | (1u << 1) | (1u << 2) | (1u << 6); + + /* Enable SBS clock for RMII selection - bit 1 in APB3ENR (RCC_APB3ENR_SBSEN) */ + RCC_APB3ENR |= (1u << 1); + + /* Longer delay for clock to stabilize */ + for (volatile int i = 0; i < 10000; i++) { } + + /* Debug: read registers to verify structure layout */ + uart_puts(" SBS@0x500 (PMCR) = "); + uart_puthex(*(volatile uint32_t *)(0x44000500u)); + uart_puts("\n"); + uart_puts(" SBS@0x504 (FPUIMR) = "); + uart_puthex(*(volatile uint32_t *)(0x44000504u)); + uart_puts("\n"); + + /* Set RMII mode: read-modify-write to preserve other bits */ + val = *sbs_pmcr; + val &= ~(0x7u << 21); /* Clear ETH_SEL bits */ + val |= (0x4u << 21); /* Set ETH_SEL = 100 for RMII */ + *sbs_pmcr = val; + for (volatile int i = 0; i < 1000; i++) { } + + uart_puts(" After RMW = "); + uart_puthex(*sbs_pmcr); + uart_puts("\n"); + + /* Configure RMII pins for NUCLEO-H563ZI (from ST HAL): + * PA1 - ETH_REF_CLK (AF11) + * PA2 - ETH_MDIO (AF11) + * PA7 - ETH_CRS_DV (AF11) + * PC1 - ETH_MDC (AF11) + * PC4 - ETH_RXD0 (AF11) + * PC5 - ETH_RXD1 (AF11) + * PB15 - ETH_TXD1 (AF11) + * PG11 - ETH_TX_EN (AF11) + * PG13 - ETH_TXD0 (AF11) + */ + gpio_eth_pin(GPIOA_BASE, 1); /* REF_CLK */ + gpio_eth_pin(GPIOA_BASE, 2); /* MDIO */ + gpio_eth_pin(GPIOA_BASE, 7); /* CRS_DV */ + gpio_eth_pin(GPIOC_BASE, 1); /* MDC */ + gpio_eth_pin(GPIOC_BASE, 4); /* RXD0 */ + gpio_eth_pin(GPIOC_BASE, 5); /* RXD1 */ + gpio_eth_pin(GPIOB_BASE, 15); /* TXD1 */ + gpio_eth_pin(GPIOG_BASE, 11); /* TX_EN */ + gpio_eth_pin(GPIOG_BASE, 13); /* TXD0 */ +} + static void echo_cb(int fd, uint16_t event, void *arg) { struct wolfIP *s = (struct wolfIP *)arg; @@ -78,17 +316,134 @@ int main(void) struct wolfIP_ll_dev *ll; struct wolfIP_sockaddr_in addr; uint64_t tick = 0; + int ret; + + /* Initialize LED first for debug - keep ON to confirm code is running */ + led_init(); + led_on(); /* LED ON = Reset_Handler ran, main() started */ + + /* Initialize UART for debug output */ + uart_init(); + + /* Blink to show UART init done */ + led_off(); + delay(200000); + led_on(); + delay(200000); + led_off(); + delay(200000); + led_on(); + + uart_puts("\n\n=== wolfIP STM32H563 Echo Server ===\n"); + + /* Check GTZC MPCBB status (read-only - writing causes fault with TZEN=1) */ + uart_puts("Checking GTZC MPCBB (read-only)...\n"); + { + volatile uint32_t *mpcbb1_seccfgr = (volatile uint32_t *)(GTZC1_BASE + 0x800u + 0x100u); + + uart_puts(" MPCBB1_CR = "); + uart_puthex(GTZC1_MPCBB1_CR); + uart_puts("\n"); + + /* Read first SECCFGR to see if SRAM is marked secure */ + uart_puts(" MPCBB1_SECCFGR[0] = "); + uart_puthex(mpcbb1_seccfgr[0]); + uart_puts("\n"); + + /* Note: If TZEN=1, we cannot modify GTZC from non-secure code! */ + /* The board needs TZEN=0 (disabled) or a secure supervisor. */ + } + uart_puts("Initializing wolfIP stack...\n"); wolfIP_init_static(&IPStack); + + /* Initialize GPIO pins for RMII - MUST happen before Ethernet clocks! */ + uart_puts("Configuring GPIO for RMII...\n"); + eth_gpio_init(); + + /* Debug: Print register values */ + uart_puts(" RCC_APB3ENR = "); + uart_puthex(RCC_APB3ENR); + uart_puts("\n"); + uart_puts(" SBS_PMCR = "); + uart_puthex(SBS_PMCR); + uart_puts("\n"); + uart_puts(" GPIOA_MODER = "); + uart_puthex(GPIO_MODER(GPIOA_BASE)); + uart_puts("\n"); + uart_puts(" GPIOG_MODER = "); + uart_puthex(GPIO_MODER(GPIOG_BASE)); + uart_puts("\n"); + uart_puts(" GPIOG_AFRH = "); + uart_puthex(GPIO_AFRH(GPIOG_BASE)); + uart_puts("\n"); + uart_puts(" GPIOB_MODER = "); + uart_puthex(GPIO_MODER(GPIOB_BASE)); + uart_puts("\n"); + uart_puts(" GPIOB_AFRH = "); + uart_puthex(GPIO_AFRH(GPIOB_BASE)); + uart_puts("\n"); + uart_puts(" GPIOC_MODER = "); + uart_puthex(GPIO_MODER(GPIOC_BASE)); + uart_puts("\n"); + uart_puts(" GPIOC_AFRL = "); + uart_puthex(GPIO_AFRL(GPIOC_BASE)); + uart_puts("\n"); + + /* Enable Ethernet MAC, TX, RX clocks AFTER RMII mode is selected */ + uart_puts("Enabling Ethernet clocks...\n"); RCC_AHB1ENR |= (1u << 19) | (1u << 20) | (1u << 21); + delay(10000); /* Allow clocks to stabilize */ + + /* Reset Ethernet MAC via RCC - this is CRITICAL! (from FrostZone) */ + uart_puts("Resetting Ethernet MAC via RCC...\n"); + RCC_AHB1RSTR |= RCC_AHB1RSTR_ETHRST; + __asm volatile ("dsb sy" ::: "memory"); + delay(1000); + RCC_AHB1RSTR &= ~RCC_AHB1RSTR_ETHRST; + __asm volatile ("dsb sy" ::: "memory"); + delay(10000); + + uart_puts(" RCC_AHB1ENR = "); + uart_puthex(RCC_AHB1ENR); + uart_puts("\n"); + + /* Check ETH registers before init */ + uart_puts(" ETH_DMAMR(0x1000) = "); + uart_puthex(*(volatile uint32_t *)(0x40028000u + 0x1000u)); + uart_puts("\n"); + uart_puts(" ETH_MACCR(0x0000) = "); + uart_puthex(*(volatile uint32_t *)(0x40028000u)); + uart_puts("\n"); + + uart_puts("Initializing Ethernet MAC...\n"); ll = wolfIP_getdev(IPStack); - (void)stm32h5_eth_init(ll, NULL); + ret = stm32h5_eth_init(ll, NULL); + uart_puts(" stm32h5_eth_init returned: "); + uart_puthex((uint32_t)ret); + uart_puts("\n"); + + /* Debug: Show ETH registers after init */ + uart_puts(" ETH_MACCR = "); + uart_puthex(*(volatile uint32_t *)(0x40028000u)); + uart_puts("\n"); + uart_puts(" ETH_DMASR = "); + uart_puthex(*(volatile uint32_t *)(0x40028000u + 0x1008u)); + uart_puts("\n"); + uart_puts(" ETH_DMACRXCR = "); + uart_puthex(*(volatile uint32_t *)(0x40028000u + 0x1108u)); + uart_puts("\n"); + uart_puts("Setting IP configuration:\n"); + uart_puts(" IP: " WOLFIP_IP "\n"); + uart_puts(" Mask: " WOLFIP_NETMASK "\n"); + uart_puts(" GW: " WOLFIP_GW "\n"); wolfIP_ipconfig_set(IPStack, atoip4(WOLFIP_IP), atoip4(WOLFIP_NETMASK), atoip4(WOLFIP_GW)); + uart_puts("Creating TCP socket on port 7...\n"); listen_fd = wolfIP_sock_socket(IPStack, AF_INET, IPSTACK_SOCK_STREAM, 0); wolfIP_register_callback(IPStack, listen_fd, echo_cb, IPStack); @@ -99,8 +454,32 @@ int main(void) (void)wolfIP_sock_bind(IPStack, listen_fd, (struct wolfIP_sockaddr *)&addr, sizeof(addr)); (void)wolfIP_sock_listen(IPStack, listen_fd, 1); + uart_puts("Entering main loop. Ready for connections!\n"); + uart_puts("Loop starting...\n"); + for (;;) { (void)wolfIP_poll(IPStack, tick++); + /* Toggle LED and print stats every 256K iterations */ + if ((tick & 0x3FFFF) == 0) { + uint32_t polls, pkts; + led_toggle(); + stm32h5_eth_get_stats(&polls, &pkts); + uart_puts("."); + if (pkts > 0) { + uart_puts(" RX! pkts="); + uart_puthex(pkts); + uart_puts("\n"); + } + /* Dump all 4 descriptors */ + { + volatile uint32_t *d = (volatile uint32_t *)stm32h5_eth_get_rx_ring_addr(); + uart_puts("\n"); + uart_puts("D0:"); uart_puthex(d[0]); uart_puts(","); uart_puthex(d[3]); uart_puts("\n"); + uart_puts("D1:"); uart_puthex(d[4]); uart_puts(","); uart_puthex(d[7]); uart_puts("\n"); + uart_puts("D2:"); uart_puthex(d[8]); uart_puts(","); uart_puthex(d[11]); uart_puts("\n"); + uart_puts("D3:"); uart_puthex(d[12]); uart_puts(","); uart_puthex(d[15]); uart_puts("\n"); + } + } } return 0; } diff --git a/src/port/stm32h563/stm32h5_eth.c b/src/port/stm32h563/stm32h5_eth.c index 4530338..67cb367 100644 --- a/src/port/stm32h563/stm32h5_eth.c +++ b/src/port/stm32h563/stm32h5_eth.c @@ -127,6 +127,7 @@ struct eth_desc { #define ETH_TDES3_FL_MASK (0x7FFFU) #define ETH_RDES3_OWN (1U << 31) +#define ETH_RDES3_IOC (1U << 30) #define ETH_RDES3_BUF1V (1U << 24) #define ETH_RDES3_FS (1U << 29) #define ETH_RDES3_LS (1U << 28) @@ -150,11 +151,16 @@ static uint32_t rx_idx; static uint32_t tx_idx; static int32_t phy_addr = -1; -static void eth_hw_reset(void) +static int eth_hw_reset(void) { + uint32_t timeout = 1000000U; + + /* DMA software reset */ ETH_DMAMR |= ETH_DMAMR_SWR; - while (ETH_DMAMR & ETH_DMAMR_SWR) { + while ((ETH_DMAMR & ETH_DMAMR_SWR) && (timeout > 0U)) { + timeout--; } + return (timeout > 0U) ? 0 : -1; } static void eth_trigger_tx(void) @@ -172,7 +178,8 @@ static void eth_config_mac(const uint8_t mac[6]) maccr &= ~(ETH_MACCR_DM | ETH_MACCR_FES); maccr |= ETH_MACCR_DM | ETH_MACCR_FES; ETH_MACCR = maccr; - ETH_MACPFR = 0U; + /* Enable promiscuous mode for debugging (bit 0 = PR) */ + ETH_MACPFR = (1u << 0); /* Promiscuous mode */ ETH_MACA0HR = ((uint32_t)mac[5] << 8) | (uint32_t)mac[4]; ETH_MACA0LR = ((uint32_t)mac[3] << 24) | ((uint32_t)mac[2] << 16) | @@ -219,44 +226,84 @@ static void eth_config_mtl(void) static void eth_init_desc(void) { uint32_t i; + + /* Step 1: Clear all descriptors (like HAL does) */ for (i = 0; i < TX_DESC_COUNT; i++) { - tx_ring[i].des0 = (uint32_t)tx_buffers[i]; + tx_ring[i].des0 = 0; tx_ring[i].des1 = 0; tx_ring[i].des2 = 0; tx_ring[i].des3 = 0; } for (i = 0; i < RX_DESC_COUNT; i++) { - rx_ring[i].des0 = (uint32_t)rx_buffers[i]; + rx_ring[i].des0 = 0; rx_ring[i].des1 = 0; rx_ring[i].des2 = 0; - rx_ring[i].des3 = (RX_BUF_SIZE & ETH_RDES3_PL_MASK) | - ETH_RDES3_OWN | - ETH_RDES3_BUF1V; + rx_ring[i].des3 = 0; } rx_idx = 0; tx_idx = 0; + + /* Step 2: Configure DMA registers */ + __asm volatile ("dsb sy" ::: "memory"); ETH_DMACTXDLAR = (uint32_t)&tx_ring[0]; ETH_DMACRXDLAR = (uint32_t)&rx_ring[0]; ETH_DMACTXRLR = TX_DESC_COUNT - 1U; ETH_DMACRXRLR = RX_DESC_COUNT - 1U; ETH_DMACTXDTPR = (uint32_t)&tx_ring[0]; ETH_DMACRXDTPR = (uint32_t)&rx_ring[RX_DESC_COUNT - 1U]; + __asm volatile ("dsb sy" ::: "memory"); + + /* Step 3: Now set buffer addresses and OWN bit */ + for (i = 0; i < TX_DESC_COUNT; i++) { + *(volatile uint32_t *)&tx_ring[i].des0 = (uint32_t)tx_buffers[i]; + } + for (i = 0; i < RX_DESC_COUNT; i++) { + *(volatile uint32_t *)&rx_ring[i].des0 = (uint32_t)rx_buffers[i]; + *(volatile uint32_t *)&rx_ring[i].des3 = ETH_RDES3_OWN | ETH_RDES3_IOC | ETH_RDES3_BUF1V; + } + + /* Data synchronization barrier before updating tail pointer */ + __asm volatile ("dsb sy" ::: "memory"); + __asm volatile ("isb sy" ::: "memory"); + + /* Step 4: Update tail pointer to signal DMA that descriptors are ready */ + ETH_DMACRXDTPR = (uint32_t)&rx_ring[RX_DESC_COUNT - 1U]; + + /* Final barrier */ + __asm volatile ("dsb sy" ::: "memory"); } +/* ETH_DMACCR - DMA Channel Control Register at offset 0x1100 */ +#define ETH_DMACCR (*(volatile uint32_t *)(ETH_BASE + 0x1100u)) +#define ETH_DMACCR_DSL_0BIT (0x00000000u) /* No skip between descriptors */ + static void eth_config_dma(void) { ETH_DMASBMR = ETH_DMASBMR_FB | ETH_DMASBMR_AAL; + /* Set DSL=0 for 16-byte descriptors (no skip) */ + ETH_DMACCR = ETH_DMACCR_DSL_0BIT; ETH_DMACRXCR = ((RX_BUF_SIZE & ETH_RDES3_PL_MASK) << ETH_DMACRXCR_RBSZ_SHIFT) | ETH_DMACRXCR_RPBL(DMA_RPBL); ETH_DMACTXCR = ETH_DMACTXCR_OSF | ETH_DMACTXCR_TPBL(DMA_TPBL); } +#define ETH_DMACSR_TPS (1U << 1) /* TX Process Stopped */ +#define ETH_DMACSR_RPS (1U << 8) /* RX Process Stopped */ + static void eth_start(void) { ETH_MACCR |= ETH_MACCR_TE | ETH_MACCR_RE; ETH_MTLTXQOMR |= ETH_MTLTXQOMR_FTQ; ETH_DMACTXCR |= ETH_DMACTXCR_ST; ETH_DMACRXCR |= ETH_DMACRXCR_SR; + + /* Clear TX and RX process stopped flags (like HAL does) */ + ETH_DMACSR = ETH_DMACSR_TPS | ETH_DMACSR_RPS; + + __asm volatile ("dsb sy" ::: "memory"); + + /* Write tail pointer to start RX DMA processing */ + ETH_DMACRXDTPR = (uint32_t)&rx_ring[RX_DESC_COUNT - 1U]; } static void eth_stop(void) @@ -349,6 +396,9 @@ static void eth_phy_init(void) } while ((bsr & PHY_BSR_LINK_STATUS) == 0U && --timeout != 0U); } +static uint32_t rx_poll_count = 0; +static uint32_t rx_pkt_count = 0; + static int eth_poll(struct wolfIP_ll_dev *dev, void *frame, uint32_t len) { struct eth_desc *desc; @@ -356,8 +406,10 @@ static int eth_poll(struct wolfIP_ll_dev *dev, void *frame, uint32_t len) uint32_t frame_len = 0; (void)dev; + rx_poll_count++; desc = &rx_ring[rx_idx]; if (desc->des3 & ETH_RDES3_OWN) return 0; + rx_pkt_count++; status = desc->des3; if ((status & (ETH_RDES3_FS | ETH_RDES3_LS)) == (ETH_RDES3_FS | ETH_RDES3_LS)) { @@ -367,9 +419,7 @@ static int eth_poll(struct wolfIP_ll_dev *dev, void *frame, uint32_t len) memcpy(frame, rx_staging_buffer, frame_len); } desc->des1 = 0; - desc->des3 = (RX_BUF_SIZE & ETH_RDES3_PL_MASK) | - ETH_RDES3_OWN | - ETH_RDES3_BUF1V; + desc->des3 = ETH_RDES3_OWN | ETH_RDES3_IOC | ETH_RDES3_BUF1V; __asm volatile ("dsb sy" ::: "memory"); ETH_DMACRXDTPR = (uint32_t)desc; rx_idx = (rx_idx + 1U) % RX_DESC_COUNT; @@ -416,9 +466,105 @@ static void stm32h5_eth_generate_mac(uint8_t mac[6]) mac[5] = 0x33; } +void stm32h5_eth_get_stats(uint32_t *polls, uint32_t *pkts) +{ + if (polls) *polls = rx_poll_count; + if (pkts) *pkts = rx_pkt_count; +} + +uint32_t stm32h5_eth_get_rx_des3(void) +{ + return rx_ring[0].des3; +} + +uint32_t stm32h5_eth_get_rx_des0(void) +{ + return rx_ring[0].des0; +} + +uint32_t stm32h5_eth_get_rx_ring_addr(void) +{ + return (uint32_t)&rx_ring[0]; +} + +uint32_t stm32h5_eth_get_dmacsr(void) +{ + /* ETH_DMAC0SR at offset 0x1160 - clear RBU by writing 1 to bit 7 */ + volatile uint32_t *csr = (volatile uint32_t *)(0x40028000u + 0x1160u); + uint32_t val = *csr; + if (val & 0x80) { + *csr = 0x80; /* Clear RBU by writing 1 */ + } + return val; +} + +uint32_t stm32h5_eth_get_rx_tail(void) +{ + /* ETH_DMAC0RXDTPR */ + return ETH_DMACRXDTPR; +} + +uint32_t stm32h5_eth_get_macpfr(void) +{ + return ETH_MACPFR; +} + +uint32_t stm32h5_eth_get_mac_debug(void) +{ + /* ETH_MTLRXQDR - MTL Rx Queue Debug */ + return *(volatile uint32_t *)(0x40028000u + 0x0C38u); +} + +uint32_t stm32h5_eth_get_dma_debug(void) +{ + /* ETH_DMADSR - DMA Debug Status */ + return *(volatile uint32_t *)(0x40028000u + 0x100Cu); +} + +uint32_t stm32h5_eth_get_rx_list_addr(void) +{ + /* ETH_DMAC0RXDLAR - RX Descriptor List Address */ + return ETH_DMACRXDLAR; +} + +uint32_t stm32h5_eth_get_rx_ring_len(void) +{ + /* ETH_DMAC0RXRLR - RX Ring Length */ + return ETH_DMACRXRLR; +} + +uint32_t stm32h5_eth_get_rx_curr_desc(void) +{ + /* ETH_DMAC0CXRXLAR - Current RX Descriptor, offset 0x114C */ + return *(volatile uint32_t *)(0x40028000u + 0x114Cu); +} + +uint32_t stm32h5_eth_read_desc_at_addr(uint32_t addr) +{ + /* Read DES3 at the given descriptor address + 12 bytes (offset of des3) */ + return *(volatile uint32_t *)(addr + 12u); +} + +void stm32h5_eth_kick_rx(void) +{ + uint32_t i; + /* Reinitialize all RX descriptors and kick DMA */ + for (i = 0; i < RX_DESC_COUNT; i++) { + *(volatile uint32_t *)&rx_ring[i].des0 = (uint32_t)rx_buffers[i]; + *(volatile uint32_t *)&rx_ring[i].des1 = 0; + *(volatile uint32_t *)&rx_ring[i].des2 = 0; + *(volatile uint32_t *)&rx_ring[i].des3 = ETH_RDES3_OWN | ETH_RDES3_IOC | ETH_RDES3_BUF1V; + } + __asm volatile ("dsb sy" ::: "memory"); + __asm volatile ("isb sy" ::: "memory"); + ETH_DMACRXDTPR = (uint32_t)&rx_ring[RX_DESC_COUNT - 1U]; +} + int stm32h5_eth_init(struct wolfIP_ll_dev *ll, const uint8_t *mac) { uint8_t local_mac[6]; + uint16_t phy_id1, phy_bsr; + if (ll == NULL) return -1; if (mac == NULL) { stm32h5_eth_generate_mac(local_mac); @@ -431,7 +577,9 @@ int stm32h5_eth_init(struct wolfIP_ll_dev *ll, const uint8_t *mac) ll->send = eth_send; eth_stop(); - eth_hw_reset(); + if (eth_hw_reset() != 0) { + return -2; /* DMA reset timeout - check RMII clock */ + } eth_config_mac(mac); eth_config_mtl(); eth_init_desc(); @@ -439,5 +587,10 @@ int stm32h5_eth_init(struct wolfIP_ll_dev *ll, const uint8_t *mac) eth_phy_init(); eth_config_speed_duplex(); eth_start(); - return 0; + + /* Read PHY info for debug */ + phy_id1 = eth_mdio_read((uint32_t)phy_addr, PHY_REG_ID1); + phy_bsr = eth_mdio_read((uint32_t)phy_addr, PHY_REG_BSR); + /* Pack debug info: PHY_ADDR in bits 0-7, link in bit 8, id1 high byte in 16-23 */ + return ((phy_id1 & 0xFF00u) << 8) | ((phy_bsr & 0x04u) ? 0x100 : 0) | (phy_addr & 0xFF); } diff --git a/src/port/stm32h563/stm32h5_eth.h b/src/port/stm32h563/stm32h5_eth.h index 0b31e11..fdb0a88 100644 --- a/src/port/stm32h563/stm32h5_eth.h +++ b/src/port/stm32h563/stm32h5_eth.h @@ -25,5 +25,19 @@ #include "wolfip.h" int stm32h5_eth_init(struct wolfIP_ll_dev *ll, const uint8_t *mac); +void stm32h5_eth_get_stats(uint32_t *polls, uint32_t *pkts); +uint32_t stm32h5_eth_get_rx_des3(void); +uint32_t stm32h5_eth_get_rx_des0(void); +uint32_t stm32h5_eth_get_rx_ring_addr(void); +uint32_t stm32h5_eth_get_dmacsr(void); +uint32_t stm32h5_eth_get_rx_tail(void); +uint32_t stm32h5_eth_get_macpfr(void); +uint32_t stm32h5_eth_get_mac_debug(void); +uint32_t stm32h5_eth_get_dma_debug(void); +uint32_t stm32h5_eth_get_rx_list_addr(void); +uint32_t stm32h5_eth_get_rx_ring_len(void); +uint32_t stm32h5_eth_get_rx_curr_desc(void); +uint32_t stm32h5_eth_read_desc_at_addr(uint32_t addr); +void stm32h5_eth_kick_rx(void); #endif diff --git a/src/port/stm32h563/target.ld b/src/port/stm32h563/target.ld index 32a273c..e909c56 100644 --- a/src/port/stm32h563/target.ld +++ b/src/port/stm32h563/target.ld @@ -1,7 +1,8 @@ MEMORY { - FLASH (rx) : ORIGIN = 0x0C000000, LENGTH = 0x00200000 - RAM (rwx) : ORIGIN = 0x30000000, LENGTH = 0x000A0000 + /* Non-secure addresses (TrustZone disabled) */ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x00200000 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x000A0000 } _estack = ORIGIN(RAM) + LENGTH(RAM); diff --git a/src/wolfip.c b/src/wolfip.c index 44a68d4..4fa4bb8 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -2925,12 +2925,12 @@ static int dhcp_poll(struct wolfIP *s) struct ipconf *primary = wolfIP_primary_ipconf(s); LOG("DHCP configuration received.\n"); if (primary) { - LOG("IP Address: %u.%u.%u.%u\n", (primary->ip >> 24) & 0xFF, (primary->ip >> 16) & 0xFF, (primary->ip >> 8) & 0xFF, (primary->ip >> 0) & 0xFF); - LOG("Subnet Mask: %u.%u.%u.%u\n", (primary->mask >> 24) & 0xFF, (primary->mask >> 16) & 0xFF, (primary->mask >> 8) & 0xFF, (primary->mask >> 0) & 0xFF); - LOG("Gateway: %u.%u.%u.%u\n", (primary->gw >> 24) & 0xFF, (primary->gw >> 16) & 0xFF, (primary->gw >> 8) & 0xFF, (primary->gw >> 0) & 0xFF); + LOG("IP Address: %u.%u.%u.%u\n", (unsigned int)((primary->ip >> 24) & 0xFF), (unsigned int)((primary->ip >> 16) & 0xFF), (unsigned int)((primary->ip >> 8) & 0xFF), (unsigned int)((primary->ip >> 0) & 0xFF)); + LOG("Subnet Mask: %u.%u.%u.%u\n", (unsigned int)((primary->mask >> 24) & 0xFF), (unsigned int)((primary->mask >> 16) & 0xFF), (unsigned int)((primary->mask >> 8) & 0xFF), (unsigned int)((primary->mask >> 0) & 0xFF)); + LOG("Gateway: %u.%u.%u.%u\n", (unsigned int)((primary->gw >> 24) & 0xFF), (unsigned int)((primary->gw >> 16) & 0xFF), (unsigned int)((primary->gw >> 8) & 0xFF), (unsigned int)((primary->gw >> 0) & 0xFF)); } if (s->dns_server) - LOG("DNS Server: %u.%u.%u.%u\n", (s->dns_server >> 24) & 0xFF, (s->dns_server >> 16) & 0xFF, (s->dns_server >> 8) & 0xFF, (s->dns_server >> 0) & 0xFF); + LOG("DNS Server: %u.%u.%u.%u\n", (unsigned int)((s->dns_server >> 24) & 0xFF), (unsigned int)((s->dns_server >> 16) & 0xFF), (unsigned int)((s->dns_server >> 8) & 0xFF), (unsigned int)((s->dns_server >> 0) & 0xFF)); } return 0; } @@ -3748,7 +3748,7 @@ int wolfIP_dns_ptr_lookup(struct wolfIP *s, uint32_t ip, uint16_t *id, void (*lo if (!s || !id || !lookup_cb) return -22; snprintf(ptr_name, sizeof(ptr_name), "%u.%u.%u.%u.in-addr.arpa", - ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF); + (unsigned int)(ip & 0xFF), (unsigned int)((ip >> 8) & 0xFF), (unsigned int)((ip >> 16) & 0xFF), (unsigned int)((ip >> 24) & 0xFF)); s->dns_ptr_cb = lookup_cb; s->dns_lookup_cb = NULL; s->dns_ptr_name[0] = '\0'; From 3abb04c54e6c0579835a0f8a616702948db12707 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 15 Jan 2026 13:03:11 -0800 Subject: [PATCH 3/4] Progress with TZEN=1 mode. --- src/port/stm32h563/Makefile | 19 ++- src/port/stm32h563/README.md | 207 ++++++++++++++++++++++++++++++ src/port/stm32h563/main.c | 173 ++++++++++--------------- src/port/stm32h563/stm32h5_eth.c | 32 +++-- src/port/stm32h563/target_tzen.ld | 85 ++++++++++++ 5 files changed, 401 insertions(+), 115 deletions(-) create mode 100644 src/port/stm32h563/README.md create mode 100644 src/port/stm32h563/target_tzen.ld diff --git a/src/port/stm32h563/Makefile b/src/port/stm32h563/Makefile index 026557d..a16c4e0 100644 --- a/src/port/stm32h563/Makefile +++ b/src/port/stm32h563/Makefile @@ -3,17 +3,32 @@ OBJCOPY ?= arm-none-eabi-objcopy ROOT := ../../.. +# TrustZone support: set TZEN=1 for TrustZone enabled builds +# Default is TZEN=0 (TrustZone disabled) +TZEN ?= 0 + CFLAGS := -mcpu=cortex-m33 -mthumb -mcmse -Os -ffreestanding -fdata-sections -ffunction-sections CFLAGS += -g -ggdb -Wall -Wextra -Werror -Wdeclaration-after-statement CFLAGS += -I. -I$(ROOT) -I$(ROOT)/src -LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections + +# Select linker script based on TZEN setting +ifeq ($(TZEN),1) + LDSCRIPT := target_tzen.ld + CFLAGS += -DTZEN_ENABLED=1 +else + LDSCRIPT := target.ld + CFLAGS += -DTZEN_ENABLED=0 +endif + +LDFLAGS := -nostdlib -T $(LDSCRIPT) -Wl,-gc-sections SRCS := startup.c ivt.c syscalls.c main.c stm32h5_eth.c $(ROOT)/src/wolfip.c OBJS := $(patsubst %.c,%.o,$(SRCS)) all: app.bin + @echo "Built with TZEN=$(TZEN) using $(LDSCRIPT)" -app.elf: $(OBJS) target.ld +app.elf: $(OBJS) $(LDSCRIPT) $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group -o $@ app.bin: app.elf diff --git a/src/port/stm32h563/README.md b/src/port/stm32h563/README.md new file mode 100644 index 0000000..c40c215 --- /dev/null +++ b/src/port/stm32h563/README.md @@ -0,0 +1,207 @@ +# wolfIP STM32H563 Port + +This directory contains a bare-metal port of wolfIP for the STM32H563 microcontroller, featuring an Ethernet driver and TCP/IP echo server example. + +## Hardware Requirements + +- STM32H563 development board (e.g., NUCLEO-H563ZI) +- Ethernet connection (RMII interface) +- ST-LINK debugger (built-in on NUCLEO boards) +- USB cable for serial output + +## Software Requirements + +- ARM GCC toolchain (`arm-none-eabi-gcc`) +- OpenOCD (STMicroelectronics fork recommended) +- Serial terminal (e.g., minicom, screen, or picocom) + +### Installing Dependencies (Ubuntu/Debian) + +```bash +sudo apt install gcc-arm-none-eabi openocd +``` + +## Building + +### Default Build (TrustZone Disabled - Recommended) + +```bash +cd src/port/stm32h563 +make TZEN=0 +``` + +This produces `app.elf` and `app.bin` for use with TZEN=0 (TrustZone disabled). + +### TrustZone Enabled Build (Experimental) + +```bash +make TZEN=1 +``` + +> **Note:** TZEN=1 support is experimental. The Ethernet driver currently has issues receiving packets when TrustZone is enabled. + +## Disabling TrustZone (Option Bytes) + +If your board has TrustZone enabled, you must disable it via option bytes before using the TZEN=0 build. Use STM32CubeProgrammer or OpenOCD: + +### Using STM32CubeProgrammer (Recommended) + +1. Open STM32CubeProgrammer +2. Connect to the target +3. Go to **Option Bytes** tab +4. Find **TZEN** under "User Configuration" +5. Set TZEN to **0xC3** (disabled) +6. Click **Apply** + +### Using OpenOCD + +```bash +openocd -f interface/stlink-dap.cfg -f target/stm32h5x.cfg -c "init" -c "halt" -c "stm32h5x option_write 0 0x5200201C 0xC3B6" -c "reset" -c "exit" +``` + +> **Warning:** Modifying option bytes can lock the device. Ensure you understand the process before proceeding. + +### Verifying TrustZone Status + +When flashing, OpenOCD will report TrustZone status: + +``` +Info : TZEN = 0xC3 : TrustZone disabled by option bytes # Good for TZEN=0 +Info : TZEN = 0xB4 : TrustZone enabled by option bytes # Requires TZEN=1 build +``` + +## Flashing + +```bash +openocd -f interface/stlink-dap.cfg -f target/stm32h5x.cfg \ + -c "program app.elf verify reset exit" +``` + +## Serial Console + +Connect to the USB serial port (typically `/dev/ttyACM0`) at 115200 baud: + +```bash +# Using screen +screen /dev/ttyACM0 115200 + +# Using minicom +minicom -D /dev/ttyACM0 -b 115200 + +# Using picocom +picocom -b 115200 /dev/ttyACM0 +``` + +## Example Output + +When the firmware boots successfully, you should see output similar to: + +``` +=== wolfIP STM32H563 Echo Server === +Initializing wolfIP stack... +Configuring GPIO for RMII... +Enabling Ethernet clocks... +Resetting Ethernet MAC... +Initializing Ethernet MAC... + PHY link: UP, PHY addr: 0x00000000 +Setting IP configuration: + IP: 192.168.12.11 + Mask: 255.255.255.0 + GW: 192.168.12.1 +Creating TCP socket on port 7... +Entering main loop. Ready for connections! +Loop starting... +``` + +The "PHY link: UP" message indicates the Ethernet PHY has established a link with the network. + +## Network Configuration + +The example configures the following static IP: + +| Setting | Value | +|---------|-------| +| IP Address | 192.168.12.11 | +| Subnet Mask | 255.255.255.0 | +| Gateway | 192.168.12.1 | + +Configure your host PC's Ethernet interface to be on the same subnet: + +```bash +sudo ip addr add 192.168.12.1/24 dev +sudo ip link set up +``` + +Replace `` with your Ethernet interface name (e.g., `eth0`, `enp5s0`). + +## Testing + +Once running, the echo server listens on TCP port 7: + +```bash +# Test with netcat +echo "Hello wolfIP!" | nc 192.168.12.11 7 + +# Test with ping +ping 192.168.12.11 +``` + +## Files + +| File | Description | +|------|-------------| +| `main.c` | Application entry point, wolfIP initialization, echo server | +| `stm32h5_eth.c` | Ethernet MAC/DMA driver for STM32H5 | +| `stm32h5_eth.h` | Ethernet driver header | +| `startup.c` | Startup code and data initialization | +| `ivt.c` | Interrupt vector table | +| `syscalls.c` | Newlib syscall stubs | +| `target.ld` | Linker script for TZEN=0 | +| `target_tzen.ld` | Linker script for TZEN=1 | +| `config.h` | Build configuration | +| `Makefile` | Build system | + +## TrustZone Support (TZEN=1) - Experimental + +The TZEN=1 build adds TrustZone support: + +- **SAU Configuration:** Marks memory regions for non-secure DMA access +- **GTZC/MPCBB:** Configures SRAM3 blocks for Ethernet DMA +- **Secure Aliases:** Uses secure peripheral addresses (0x5xxxxxxx) +- **Separate ETHMEM:** Places Ethernet buffers in dedicated non-secure SRAM + +### Current Limitations + +The TZEN=1 build compiles and runs, but the Ethernet driver experiences RBU (Receive Buffer Unavailable) errors. This appears to be a DMA access issue that requires further investigation. + +## Troubleshooting + +### No Serial Output + +- Check USB connection and correct serial port +- Verify baud rate is 115200 +- Try resetting the board + +### OpenOCD Connection Fails + +- Ensure ST-LINK drivers are installed +- Try `sudo` if permission denied +- Check that no other debugger is connected + +### Ethernet Not Responding + +- Verify physical Ethernet connection +- Check that host PC is on same subnet (192.168.12.x) +- Confirm PHY link is up (check serial output for "link" status) + +### TrustZone Errors + +If you see `stm32h5x.cpu in Secure state` but built with TZEN=0: +- The board has TrustZone enabled +- Either rebuild with `make TZEN=1` or disable TrustZone via option bytes + +## License + +This code is part of wolfIP and is licensed under GPLv3. See the LICENSE file in the repository root for details. + +Copyright (C) 2026 wolfSSL Inc. diff --git a/src/port/stm32h563/main.c b/src/port/stm32h563/main.c index 188a3f0..e50f9ef 100644 --- a/src/port/stm32h563/main.c +++ b/src/port/stm32h563/main.c @@ -27,24 +27,56 @@ #define ECHO_PORT 7 #define RX_BUF_SIZE 1024 -#define RCC_BASE 0x44020C00u +#if TZEN_ENABLED +#define RCC_BASE 0x54020C00u /* Secure alias */ +#define ETH_BASE_DBG 0x50028000u /* Secure ETH for debug */ +#else +#define RCC_BASE 0x44020C00u /* Non-secure alias */ +#define ETH_BASE_DBG 0x40028000u /* Non-secure ETH for debug */ +#endif #define RCC_AHB1ENR (*(volatile uint32_t *)(RCC_BASE + 0x88u)) #define RCC_AHB2ENR (*(volatile uint32_t *)(RCC_BASE + 0x8Cu)) #define RCC_APB3ENR (*(volatile uint32_t *)(RCC_BASE + 0xA8u)) #define RCC_AHB1RSTR (*(volatile uint32_t *)(RCC_BASE + 0x60u)) #define RCC_AHB1RSTR_ETHRST (1u << 19) +/* SAU (Security Attribution Unit) - mark memory regions as non-secure */ +#define SAU_CTRL (*(volatile uint32_t *)0xE000EDD0u) +#define SAU_RNR (*(volatile uint32_t *)0xE000EDD8u) +#define SAU_RBAR (*(volatile uint32_t *)0xE000EDDCu) +#define SAU_RLAR (*(volatile uint32_t *)0xE000EDE0u) + /* GTZC (Global TrustZone Controller) - unlock SRAM for DMA access */ +#if TZEN_ENABLED +/* Secure addresses when running in secure mode with TZEN=1 */ +#define GTZC1_BASE 0x50032400u /* Secure alias */ +#else #define GTZC1_BASE 0x40032400u /* Non-secure alias */ +#endif #define GTZC1_MPCBB1_CR (*(volatile uint32_t *)(GTZC1_BASE + 0x800u)) #define GTZC1_MPCBB2_CR (*(volatile uint32_t *)(GTZC1_BASE + 0xC00u)) #define GTZC1_MPCBB3_CR (*(volatile uint32_t *)(GTZC1_BASE + 0x1000u)) +/* MPCBB SECCFGR registers - each bit controls 256 bytes of SRAM */ +#define GTZC1_MPCBB3_SECCFGR(n) (*(volatile uint32_t *)(GTZC1_BASE + 0x1000u + 0x100u + ((n) * 4u))) +/* MPCBB PRIVCFGR registers - each bit controls privilege for 256 bytes of SRAM */ +#define GTZC1_MPCBB3_PRIVCFGR(n) (*(volatile uint32_t *)(GTZC1_BASE + 0x1000u + 0x200u + ((n) * 4u))) +/* TZSC SECCFGR registers - control peripheral security */ +#define GTZC1_TZSC_SECCFGR1 (*(volatile uint32_t *)(GTZC1_BASE + 0x010u)) +#define GTZC1_TZSC_SECCFGR2 (*(volatile uint32_t *)(GTZC1_BASE + 0x014u)) +#define GTZC1_TZSC_SECCFGR3 (*(volatile uint32_t *)(GTZC1_BASE + 0x018u)) /* GPIO base addresses */ -#define GPIOA_BASE 0x42020000u +#if TZEN_ENABLED +#define GPIOA_BASE 0x52020000u /* Secure alias */ +#define GPIOB_BASE 0x52020400u +#define GPIOC_BASE 0x52020800u +#define GPIOG_BASE 0x52021800u +#else +#define GPIOA_BASE 0x42020000u /* Non-secure alias */ #define GPIOB_BASE 0x42020400u #define GPIOC_BASE 0x42020800u #define GPIOG_BASE 0x42021800u +#endif /* GPIO register offsets */ #define GPIO_MODER(base) (*(volatile uint32_t *)((base) + 0x00u)) @@ -55,7 +87,11 @@ /* SBS (System Bus Security) for RMII selection */ /* SBS register definitions - PMCR is at offset 0x100 in SBS structure */ -#define SBS_BASE 0x44000400u +#if TZEN_ENABLED +#define SBS_BASE 0x54000400u /* Secure alias */ +#else +#define SBS_BASE 0x44000400u /* Non-secure alias */ +#endif #define SBS_PMCR (*(volatile uint32_t *)(SBS_BASE + 0x100u)) #define SBS_PMCR_ETH_SEL_RMII (4u << 21) @@ -238,17 +274,9 @@ static void eth_gpio_init(void) /* Enable SBS clock for RMII selection - bit 1 in APB3ENR (RCC_APB3ENR_SBSEN) */ RCC_APB3ENR |= (1u << 1); - /* Longer delay for clock to stabilize */ + /* Delay for clock to stabilize */ for (volatile int i = 0; i < 10000; i++) { } - /* Debug: read registers to verify structure layout */ - uart_puts(" SBS@0x500 (PMCR) = "); - uart_puthex(*(volatile uint32_t *)(0x44000500u)); - uart_puts("\n"); - uart_puts(" SBS@0x504 (FPUIMR) = "); - uart_puthex(*(volatile uint32_t *)(0x44000504u)); - uart_puts("\n"); - /* Set RMII mode: read-modify-write to preserve other bits */ val = *sbs_pmcr; val &= ~(0x7u << 21); /* Clear ETH_SEL bits */ @@ -256,10 +284,6 @@ static void eth_gpio_init(void) *sbs_pmcr = val; for (volatile int i = 0; i < 1000; i++) { } - uart_puts(" After RMW = "); - uart_puthex(*sbs_pmcr); - uart_puts("\n"); - /* Configure RMII pins for NUCLEO-H563ZI (from ST HAL): * PA1 - ETH_REF_CLK (AF11) * PA2 - ETH_MDIO (AF11) @@ -336,23 +360,29 @@ int main(void) uart_puts("\n\n=== wolfIP STM32H563 Echo Server ===\n"); - /* Check GTZC MPCBB status (read-only - writing causes fault with TZEN=1) */ - uart_puts("Checking GTZC MPCBB (read-only)...\n"); +#if TZEN_ENABLED + /* Configure TrustZone for Ethernet DMA access */ + uart_puts("Configuring TrustZone for Ethernet DMA...\n"); { - volatile uint32_t *mpcbb1_seccfgr = (volatile uint32_t *)(GTZC1_BASE + 0x800u + 0x100u); + uint32_t i; - uart_puts(" MPCBB1_CR = "); - uart_puthex(GTZC1_MPCBB1_CR); - uart_puts("\n"); + /* Enable SAU with ALLNS mode (all undefined regions are non-secure) */ + SAU_CTRL = 0x03u; /* ENABLE + ALLNS */ + __asm volatile ("dsb sy" ::: "memory"); + __asm volatile ("isb sy" ::: "memory"); - /* Read first SECCFGR to see if SRAM is marked secure */ - uart_puts(" MPCBB1_SECCFGR[0] = "); - uart_puthex(mpcbb1_seccfgr[0]); - uart_puts("\n"); + /* Mark MPCBB3 registers 36-39 as non-secure for ETHMEM */ + for (i = 36; i <= 39; i++) { + GTZC1_MPCBB3_SECCFGR(i) = 0x00000000u; + GTZC1_MPCBB3_PRIVCFGR(i) = 0x00000000u; + } + __asm volatile ("dsb sy" ::: "memory"); - /* Note: If TZEN=1, we cannot modify GTZC from non-secure code! */ - /* The board needs TZEN=0 (disabled) or a secure supervisor. */ + /* Mark Ethernet MAC as non-secure in TZSC */ + GTZC1_TZSC_SECCFGR3 &= ~(1u << 11); + __asm volatile ("dsb sy" ::: "memory"); } +#endif uart_puts("Initializing wolfIP stack...\n"); wolfIP_init_static(&IPStack); @@ -361,42 +391,13 @@ int main(void) uart_puts("Configuring GPIO for RMII...\n"); eth_gpio_init(); - /* Debug: Print register values */ - uart_puts(" RCC_APB3ENR = "); - uart_puthex(RCC_APB3ENR); - uart_puts("\n"); - uart_puts(" SBS_PMCR = "); - uart_puthex(SBS_PMCR); - uart_puts("\n"); - uart_puts(" GPIOA_MODER = "); - uart_puthex(GPIO_MODER(GPIOA_BASE)); - uart_puts("\n"); - uart_puts(" GPIOG_MODER = "); - uart_puthex(GPIO_MODER(GPIOG_BASE)); - uart_puts("\n"); - uart_puts(" GPIOG_AFRH = "); - uart_puthex(GPIO_AFRH(GPIOG_BASE)); - uart_puts("\n"); - uart_puts(" GPIOB_MODER = "); - uart_puthex(GPIO_MODER(GPIOB_BASE)); - uart_puts("\n"); - uart_puts(" GPIOB_AFRH = "); - uart_puthex(GPIO_AFRH(GPIOB_BASE)); - uart_puts("\n"); - uart_puts(" GPIOC_MODER = "); - uart_puthex(GPIO_MODER(GPIOC_BASE)); - uart_puts("\n"); - uart_puts(" GPIOC_AFRL = "); - uart_puthex(GPIO_AFRL(GPIOC_BASE)); - uart_puts("\n"); - /* Enable Ethernet MAC, TX, RX clocks AFTER RMII mode is selected */ uart_puts("Enabling Ethernet clocks...\n"); RCC_AHB1ENR |= (1u << 19) | (1u << 20) | (1u << 21); delay(10000); /* Allow clocks to stabilize */ /* Reset Ethernet MAC via RCC - this is CRITICAL! (from FrostZone) */ - uart_puts("Resetting Ethernet MAC via RCC...\n"); + uart_puts("Resetting Ethernet MAC...\n"); RCC_AHB1RSTR |= RCC_AHB1RSTR_ETHRST; __asm volatile ("dsb sy" ::: "memory"); delay(1000); @@ -404,35 +405,20 @@ int main(void) __asm volatile ("dsb sy" ::: "memory"); delay(10000); - uart_puts(" RCC_AHB1ENR = "); - uart_puthex(RCC_AHB1ENR); - uart_puts("\n"); - - /* Check ETH registers before init */ - uart_puts(" ETH_DMAMR(0x1000) = "); - uart_puthex(*(volatile uint32_t *)(0x40028000u + 0x1000u)); - uart_puts("\n"); - uart_puts(" ETH_MACCR(0x0000) = "); - uart_puthex(*(volatile uint32_t *)(0x40028000u)); - uart_puts("\n"); - uart_puts("Initializing Ethernet MAC...\n"); ll = wolfIP_getdev(IPStack); ret = stm32h5_eth_init(ll, NULL); - uart_puts(" stm32h5_eth_init returned: "); - uart_puthex((uint32_t)ret); - uart_puts("\n"); - - /* Debug: Show ETH registers after init */ - uart_puts(" ETH_MACCR = "); - uart_puthex(*(volatile uint32_t *)(0x40028000u)); - uart_puts("\n"); - uart_puts(" ETH_DMASR = "); - uart_puthex(*(volatile uint32_t *)(0x40028000u + 0x1008u)); - uart_puts("\n"); - uart_puts(" ETH_DMACRXCR = "); - uart_puthex(*(volatile uint32_t *)(0x40028000u + 0x1108u)); - uart_puts("\n"); + if (ret < 0) { + uart_puts(" ERROR: stm32h5_eth_init failed ("); + uart_puthex((uint32_t)ret); + uart_puts(")\n"); + } else { + uart_puts(" PHY link: "); + uart_puts((ret & 0x100) ? "UP" : "DOWN"); + uart_puts(", PHY addr: "); + uart_puthex(ret & 0xFF); + uart_puts("\n"); + } uart_puts("Setting IP configuration:\n"); uart_puts(" IP: " WOLFIP_IP "\n"); @@ -459,26 +445,9 @@ int main(void) for (;;) { (void)wolfIP_poll(IPStack, tick++); - /* Toggle LED and print stats every 256K iterations */ + /* Toggle LED every ~256K iterations as heartbeat */ if ((tick & 0x3FFFF) == 0) { - uint32_t polls, pkts; led_toggle(); - stm32h5_eth_get_stats(&polls, &pkts); - uart_puts("."); - if (pkts > 0) { - uart_puts(" RX! pkts="); - uart_puthex(pkts); - uart_puts("\n"); - } - /* Dump all 4 descriptors */ - { - volatile uint32_t *d = (volatile uint32_t *)stm32h5_eth_get_rx_ring_addr(); - uart_puts("\n"); - uart_puts("D0:"); uart_puthex(d[0]); uart_puts(","); uart_puthex(d[3]); uart_puts("\n"); - uart_puts("D1:"); uart_puthex(d[4]); uart_puts(","); uart_puthex(d[7]); uart_puts("\n"); - uart_puts("D2:"); uart_puthex(d[8]); uart_puts(","); uart_puthex(d[11]); uart_puts("\n"); - uart_puts("D3:"); uart_puthex(d[12]); uart_puts(","); uart_puthex(d[15]); uart_puts("\n"); - } } } return 0; diff --git a/src/port/stm32h563/stm32h5_eth.c b/src/port/stm32h563/stm32h5_eth.c index 67cb367..5fc302d 100644 --- a/src/port/stm32h563/stm32h5_eth.c +++ b/src/port/stm32h563/stm32h5_eth.c @@ -23,7 +23,11 @@ #include "config.h" #include "stm32h5_eth.h" -#define ETH_BASE 0x40028000UL +#if TZEN_ENABLED +#define ETH_BASE 0x50028000UL /* Secure alias */ +#else +#define ETH_BASE 0x40028000UL /* Non-secure alias */ +#endif #define ETH_REG(offset) (*(volatile uint32_t *)(ETH_BASE + (offset))) #define ETH_TPDR ETH_REG(0x1180U) @@ -141,10 +145,17 @@ struct eth_desc { #define DMA_TPBL 32U #define DMA_RPBL 32U -static struct eth_desc rx_ring[RX_DESC_COUNT] __attribute__((aligned(32))); -static struct eth_desc tx_ring[TX_DESC_COUNT] __attribute__((aligned(32))); -static uint8_t rx_buffers[RX_DESC_COUNT][RX_BUF_SIZE] __attribute__((aligned(32))); -static uint8_t tx_buffers[TX_DESC_COUNT][TX_BUF_SIZE] __attribute__((aligned(32))); +/* When TZEN=1, place Ethernet buffers in non-secure SRAM section for DMA access */ +#if TZEN_ENABLED +#define ETH_SECTION __attribute__((section(".eth_buffers"))) +#else +#define ETH_SECTION +#endif + +static struct eth_desc rx_ring[RX_DESC_COUNT] __attribute__((aligned(32))) ETH_SECTION; +static struct eth_desc tx_ring[TX_DESC_COUNT] __attribute__((aligned(32))) ETH_SECTION; +static uint8_t rx_buffers[RX_DESC_COUNT][RX_BUF_SIZE] __attribute__((aligned(32))) ETH_SECTION; +static uint8_t tx_buffers[TX_DESC_COUNT][TX_BUF_SIZE] __attribute__((aligned(32))) ETH_SECTION; static uint8_t rx_staging_buffer[RX_BUF_SIZE] __attribute__((aligned(32))); static uint32_t rx_idx; @@ -490,10 +501,9 @@ uint32_t stm32h5_eth_get_rx_ring_addr(void) uint32_t stm32h5_eth_get_dmacsr(void) { /* ETH_DMAC0SR at offset 0x1160 - clear RBU by writing 1 to bit 7 */ - volatile uint32_t *csr = (volatile uint32_t *)(0x40028000u + 0x1160u); - uint32_t val = *csr; + uint32_t val = ETH_DMACSR; if (val & 0x80) { - *csr = 0x80; /* Clear RBU by writing 1 */ + ETH_DMACSR = 0x80; /* Clear RBU by writing 1 */ } return val; } @@ -512,13 +522,13 @@ uint32_t stm32h5_eth_get_macpfr(void) uint32_t stm32h5_eth_get_mac_debug(void) { /* ETH_MTLRXQDR - MTL Rx Queue Debug */ - return *(volatile uint32_t *)(0x40028000u + 0x0C38u); + return *(volatile uint32_t *)(ETH_BASE + 0x0C38u); } uint32_t stm32h5_eth_get_dma_debug(void) { /* ETH_DMADSR - DMA Debug Status */ - return *(volatile uint32_t *)(0x40028000u + 0x100Cu); + return *(volatile uint32_t *)(ETH_BASE + 0x100Cu); } uint32_t stm32h5_eth_get_rx_list_addr(void) @@ -536,7 +546,7 @@ uint32_t stm32h5_eth_get_rx_ring_len(void) uint32_t stm32h5_eth_get_rx_curr_desc(void) { /* ETH_DMAC0CXRXLAR - Current RX Descriptor, offset 0x114C */ - return *(volatile uint32_t *)(0x40028000u + 0x114Cu); + return *(volatile uint32_t *)(ETH_BASE + 0x114Cu); } uint32_t stm32h5_eth_read_desc_at_addr(uint32_t addr) diff --git a/src/port/stm32h563/target_tzen.ld b/src/port/stm32h563/target_tzen.ld new file mode 100644 index 0000000..4898cf2 --- /dev/null +++ b/src/port/stm32h563/target_tzen.ld @@ -0,0 +1,85 @@ +/* Linker script for STM32H563 with TrustZone ENABLED (TZEN=1) + * + * When TrustZone is enabled: + * - Secure flash alias: 0x0C000000 + * - Secure SRAM alias: 0x30000000 + * - We run in secure mode and configure GTZC to allow DMA access + */ + +MEMORY +{ + /* Secure addresses (TrustZone enabled) */ + FLASH (rx) : ORIGIN = 0x0C000000, LENGTH = 0x00200000 + RAM (rwx) : ORIGIN = 0x30000000, LENGTH = 0x00090000 /* 576KB secure SRAM (SRAM1+SRAM2+part of SRAM3) */ + + /* Non-secure SRAM for Ethernet DMA buffers (must be marked NS in GTZC) */ + /* Using end of SRAM3 at 0x20098000 - 0x200A0000 (32KB for ETH) */ + ETHMEM (rwx) : ORIGIN = 0x20098000, LENGTH = 0x00008000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > 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 : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM + + /* Ethernet DMA buffers - placed in non-secure memory region */ + .eth_buffers (NOLOAD) : ALIGN(32) + { + _eth_start = .; + *(.eth_buffers*) + . = ALIGN(32); + _eth_end = .; + } > ETHMEM +} From 3be384cf45ed5abaaf6c54e9ee868f23ef24ce37 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 15 Jan 2026 13:50:29 -0800 Subject: [PATCH 4/4] Fix cppcheck --- Makefile | 2 ++ src/wolfip.c | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index e2e554e..9ba83b1 100644 --- a/Makefile +++ b/Makefile @@ -88,6 +88,8 @@ CPPCHECK_FLAGS=--enable=warning,performance,portability,missingInclude \ --suppress=constParameterCallback \ --suppress=toomanyconfigs \ --suppress=unmatchedSuppression --inconclusive \ + --suppress=comparePointers:src/port/stm32h563/startup.c \ + --suppress=comparePointers:src/port/stm32h563/syscalls.c \ --disable=style \ --std=c99 --language=c \ --platform=unix64 \ diff --git a/src/wolfip.c b/src/wolfip.c index 4fa4bb8..c4ccdb9 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -1067,14 +1067,13 @@ static int arp_lookup(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *ma static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *orig) { struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); - struct wolfIP_icmp_ttl_exceeded_packet icmp; + struct wolfIP_icmp_ttl_exceeded_packet icmp = {0}; struct wolfIP_icmp_packet *icmp_pkt = (struct wolfIP_icmp_packet *)&icmp; #if !CONFIG_IPFILTER (void)icmp_pkt; #endif if (!ll || !ll->send) return; - memset(&icmp, 0, sizeof(icmp)); icmp.type = ICMP_TTL_EXCEEDED; memcpy(icmp.orig_packet, ((uint8_t *)orig) + ETH_HEADER_LEN, TTL_EXCEEDED_ORIG_PACKET_SIZE);