Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ CPPCHECK_FLAGS=--enable=warning,performance,portability,missingInclude \
--suppress=constParameterCallback \
--suppress=toomanyconfigs \
--suppress=unmatchedSuppression --inconclusive \
--suppress=comparePointers:src/port/stm32c5a3/startup.c \
--suppress=comparePointers:src/port/stm32c5a3/syscalls.c \
--suppress=comparePointers:src/port/stm32h563/startup.c \
--suppress=comparePointers:src/port/stm32h563/syscalls.c \
--suppress=comparePointers:src/port/stm32h753/startup.c \
Expand All @@ -149,6 +151,7 @@ CPPCHECK_FLAGS=--enable=warning,performance,portability,missingInclude \
--suppress=comparePointers:src/port/rp2350_cyw43439/startup_hazard3.c \
--suppress=comparePointers:src/port/rp2350_cyw43439/syscalls.c \
--suppress=unknownMacro:src/port/stm32h563/dot1x_client.c \
--suppress=unknownMacro:src/port/stm32c5a3/startup.c \
--suppress=preprocessorErrorDirective:src/supplicant/supplicant_features.h \
--disable=style \
--std=c99 --language=c \
Expand Down
65 changes: 65 additions & 0 deletions src/port/stm32/PORTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Porting wolfIP to a new STM32

This tree is layered so a new STM32 wolfIP port is a small set of per-chip
files plus shared infrastructure. Existing ports: `stm32c5a3` (M33, TLS 1.3 +
DHUK), `stm32h753` (M7, TLS + HTTPS), `stm32h563` (M33, TLS + SSH + MQTT +
dot1x + FreeRTOS), `stm32f439` (M4, network only), `stm32n6` (M55, network
only).

## Shared -- reuse as-is

| File | What it gives you |
|------|-------------------|
| `src/port/stm32/stm32_eth.c` / `.h` | Synopsys DWC GMAC MAC+DMA+PHY driver for H5/H7/N6 (and C5, via a one-line `STM32C5 -> STM32H5` alias). ETH1 at `0x40028000` on H5/C5. |
| `src/port/stm32/wolfssl.mk` | `WOLFSSL_ROOT`/`WOLFMQTT_ROOT` defaults, the `WOLFSSL_SRCS` TLS-1.3 source list, the optional `WOLFSSL_LOG_SRCS` (logging/error/wc_encrypt) group, and the `$(WOLFSSL_ROOT)/%.o` relaxed-warning rule. `include` it from a port Makefile. |
| `src/port/wolfssl_io.c` | wolfIP <-> wolfSSL I/O callbacks (EAGAIN -> WANT_READ/WRITE, `-1` -> CONN_CLOSE). |
| `src/port/tls_client.c` / `.h` | Shared TLS 1.3 client state machine. Build knobs (per-port `-D`): `TLS_CLIENT_MUTUAL_AUTH` (present a client cert from the port's `tls_certs.h`), `ENABLE_DHUK_KEY` (sign CertificateVerify via the DHUK PK callback), `TLS_CLIENT_CIPHER` (force one suite), `TLS_CLIENT_SETTLE_POLLS` (post-connect settle, default 10). Without `MUTUAL_AUTH` it is a plain one-way client (SNI via `tls_client_set_sni()`). |
| `src/port/certs.h` | Embedded test certificates (for the HTTPS/server ports). |
| `src/wolfip.c` | The stack itself. |

## Per-chip -- supply these

| File | Notes |
|------|-------|
| `startup.c` (+ `ivt.c`) | Vendor vector table + reset. Genuinely per-silicon (different peripheral IRQ set). C5A3 folds the full M33 vector table into `startup.c` (no separate `ivt.c`). |
| `target.ld` | Memory map (flash/RAM addresses + sizes). Add an `.eth_buffers` output section in RAM for the GMAC descriptors + RX/TX buffers. |
| `main.c` | The per-chip register sequences: `clock_init`, `uart_init`, `eth_gpio_init` (RMII pinmux + SYSCFG/SBS PHY-interface select + RCC ETH gates), `rng_init`. Plus the wolfIP init + poll loop (mostly copyable between ports). |
| `config.h` | wolfIP sizing (sockets, buffers, static IP). |
| `user_settings.h` | wolfSSL config: the shared TLS-1.3 base + a per-chip HW-crypto arm (`STM32_HASH` / `STM32_CRYPTO` / `WOLFSSL_STM32_PKA` / RNG, gated on the chip define). |
| `Makefile` | Thin: CPU flags, device `-D`, includes, `include ../stm32/wolfssl.mk`, board sources, feature source lists, flash command. |

## Makefile pattern

```make
CFLAGS := -mcpu=cortex-mXX ... -D<CHIP>
CFLAGS_WOLFSSL := $(filter-out -Werror,$(CFLAGS)) -Wno-unused-variable -Wno-unused-function
include $(ROOT)/src/port/stm32/wolfssl.mk # WOLFSSL_SRCS + %.o rule + defaults
...
ifeq ($(ENABLE_TLS),1)
WOLFSSL_SRCS += $(WOLFSSL_LOG_SRCS) # unless you strip logging/error to save flash
SRCS += $(WOLFSSL_SRCS)
endif
```

- A port that needs feature defines on the wolfSSL objects (e.g. SSH/dot1x) sets `WOLFSSL_EXTRA_DEFS` -- the shared `%.o` rule appends it (see `stm32h563/Makefile`).
- Keep `all:`/`clean:`/`size:`/`flash:` in the port; `wolfssl.mk` intentionally defines only variables and the `%.o` pattern rule so it never hijacks the default goal.

## New-port checklist (things that bite)

- **`_sbrk` must use the linker `.heap` region**, not `_ebss.._estack`. On a port whose linker places `.eth_buffers` after `.bss`, an `_ebss`-based heap hands out malloc memory that overlaps the Ethernet DMA buffers, and packet DMA silently corrupts heap objects (seen on C5A3: garbage `WOLFSSL_CTX->method` -> bus fault deep in TLS).
- **Add the port to the root `Makefile` cppcheck suppression list** (`comparePointers` for `startup.c`/`syscalls.c`, and `unknownMacro` for a CMSIS vendor `startup.c`). A cleaner alternative for new code: cast the `_sbrk` bounds compare to `uintptr_t` so no `comparePointers` suppression is needed.
- **RMII alternate-function numbers are not uniform** -- check each pin against the CubeMX/HAL board example (on C5A3, RXD0/RXD1 are AF12/AF13 while the rest are AF10). A wrong AF on an RX pin leaves the link up (MDIO works) but drops all RX.
- **DMA buffers must be in DMA-reachable RAM** (not DTCM on H7); place them via the `.eth_buffers` section.
- **Wire MSPLIM** to the linker's real stack-limit symbol (`PROVIDE(__STACK_LIMIT = __StackLimit)` if the CMSIS startup uses `__STACK_LIMIT`) so a stack overflow faults cleanly instead of corrupting the heap.
- The `../wolfssl` object tree is shared: ports at different FP ABIs (hard vs soft float) clobber each other's `.o` files. `make clean` (or delete `$(WOLFSSL_ROOT)/**/*.o`) between such builds.

## Shared TLS client

`tls_client.c`/`.h` moved to `src/port/` (see the shared table above). The three
TLS ports now compile the single `$(ROOT)/src/port/tls_client.c` and select
behavior with `-D` knobs: `stm32c5a3` sets `TLS_CLIENT_MUTUAL_AUTH` +
`TLS_CLIENT_CIPHER` (+ `ENABLE_DHUK_KEY`) for its mutual-auth DHUK demo, while
`stm32h753`/`stm32h563` build it as a plain one-way client (H753 keeps its
historical `TLS_CLIENT_SETTLE_POLLS=100`). C5A3's mutual-auth + DHUK build is
verified on hardware; H753/H563 are build-verified (boards not testable here --
no H753 on the bench, H563 is provisioned TZEN=1).
10 changes: 9 additions & 1 deletion src/port/stm32/stm32_eth.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,16 @@
#include "config.h"
#include "stm32_eth.h"

/* STM32C5 (Cortex-M33) uses a DWC GMAC that is byte-for-byte identical to
* the STM32H5: same ETH_BASE (0x40028000), same register layout, same NS
* access model, and the same MDIO clock-range divider (CR=4) at HCLK 144MHz.
* Alias it onto the H5 path so it reuses every H5 value and code arm. */
#if defined(STM32C5) && !defined(STM32H5)
#define STM32H5
#endif

#if !defined(STM32H5) && !defined(STM32H7) && !defined(STM32N6)
#error "Define STM32H5, STM32H7 or STM32N6 for stm32_eth.c"
#error "Define STM32C5, STM32H5, STM32H7 or STM32N6 for stm32_eth.c"
#endif

#if defined(STM32H5)
Expand Down
74 changes: 74 additions & 0 deletions src/port/stm32/wolfssl.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# wolfssl.mk -- shared wolfSSL/wolfCrypt build plumbing for the STM32 bare-metal
# wolfIP ports (stm32c5a3, stm32h753, stm32h563, ...).
#
# Copyright (C) 2026 wolfSSL Inc.
#
# `include $(ROOT)/src/port/stm32/wolfssl.mk` from a port Makefile. Provides:
# - WOLFSSL_ROOT / WOLFMQTT_ROOT sibling defaults (a port may set WOLFSSL_ROOT
# earlier with ?= to point at a worktree; that still wins).
# - WOLFSSL_SRCS: the minimal wolfSSL/wolfCrypt source set for a TLS 1.3 client
# (ECC + AES-GCM) plus the ChaCha20-Poly1305 / RSA-verify / logging groups
# the ports share. Add to SRCS from inside the port's ENABLE_TLS block.
# - the $(WOLFSSL_ROOT)/%.o relaxed-warning compile rule (uses the port's
# CFLAGS_WOLFSSL, which the port defines and appends its own -D flags to).
#
# Only variables and a pattern rule live here -- no explicit targets -- so the
# including Makefile keeps ownership of the default goal and of all/clean/size/
# flash. Include it AFTER the port has set CFLAGS (and, if used, its own
# WOLFSSL_ROOT ?= override); the port defines CFLAGS_WOLFSSL itself.

WOLFSSL_ROOT ?= $(ROOT)/../wolfssl
WOLFMQTT_ROOT ?= $(ROOT)/../wolfmqtt

# Minimal wolfSSL/wolfCrypt source set for a TLS 1.3 client with ECC + AES-GCM.
WOLFSSL_SRCS := \
$(WOLFSSL_ROOT)/wolfcrypt/src/aes.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/sha.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/sha256.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/sha512.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/hmac.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/hash.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/kdf.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/random.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/ecc.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/asn.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/coding.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/wc_port.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/memory.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/wolfmath.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/sp_int.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/sp_c32.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/sp_cortexm.c \
$(WOLFSSL_ROOT)/src/ssl.c \
$(WOLFSSL_ROOT)/src/tls.c \
$(WOLFSSL_ROOT)/src/tls13.c \
$(WOLFSSL_ROOT)/src/internal.c \
$(WOLFSSL_ROOT)/src/keys.c \
$(WOLFSSL_ROOT)/src/wolfio.c

# ChaCha20-Poly1305 (fallback suite).
WOLFSSL_SRCS += \
$(WOLFSSL_ROOT)/wolfcrypt/src/chacha.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/chacha20_poly1305.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/poly1305.c

# RSA for peer certificate verification.
WOLFSSL_SRCS += \
$(WOLFSSL_ROOT)/wolfcrypt/src/rsa.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/signature.c

# Logging / error-strings / encrypt-helpers group. Kept separate because a
# size-tight port may omit it (e.g. with NO_ERROR_STRINGS + logging off). Ports
# that want it do: WOLFSSL_SRCS += $(WOLFSSL_LOG_SRCS)
WOLFSSL_LOG_SRCS := \
$(WOLFSSL_ROOT)/wolfcrypt/src/logging.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/error.c \
$(WOLFSSL_ROOT)/wolfcrypt/src/wc_encrypt.c

# wolfSSL objects build with relaxed warnings (third-party, heavily #ifdef'd).
# CFLAGS_WOLFSSL is defined by the including port Makefile. WOLFSSL_EXTRA_DEFS
# lets a port add feature defines that the wolfSSL objects need (e.g. H563's
# -DWOLFSSL_WOLFSSH / -DHAVE_PBKDF2 for its SSH / dot1x builds); it is empty by
# default.
$(WOLFSSL_ROOT)/%.o: $(WOLFSSL_ROOT)/%.c
$(CC) $(CFLAGS_WOLFSSL) -DWOLFSSL_USER_SETTINGS $(WOLFSSL_EXTRA_DEFS) -I$(WOLFSSL_ROOT) -c $< -o $@
8 changes: 8 additions & 0 deletions src/port/stm32c5a3/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Build artifacts
*.o
app.elf
app.bin

# Generated TLS test host material (contains a throwaway test private key).
# Regenerate with: python3 gen_certs.py (also rewrites tls_certs.h)
tls-certs/
Loading
Loading