diff --git a/.github/workflows/stm32h563-m33mu-freertos.yml b/.github/workflows/stm32h563-m33mu-freertos.yml new file mode 100644 index 00000000..f8b3adf7 --- /dev/null +++ b/.github/workflows/stm32h563-m33mu-freertos.yml @@ -0,0 +1,19 @@ +name: STM32H563 m33mu FreeRTOS + +on: + push: + pull_request: + workflow_dispatch: + +jobs: + stm32h563_m33mu_echo_freertos: + runs-on: ubuntu-latest + container: + image: ghcr.io/danielinux/m33mu-ci:1.8 + options: --privileged + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Run m33mu + DHCP + TCP echo FreeRTOS test + run: /bin/bash tools/scripts/run-m33mu-ci-in-container.sh stm32h563-m33mu-freertos stm32h563_m33mu_echo_freertos diff --git a/.github/workflows/stm32h563-m33mu-ssh-tzen.yml b/.github/workflows/stm32h563-m33mu-ssh-tzen.yml new file mode 100644 index 00000000..6f19b91e --- /dev/null +++ b/.github/workflows/stm32h563-m33mu-ssh-tzen.yml @@ -0,0 +1,129 @@ +name: STM32H563 m33mu (SSH + TZEN) + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +jobs: + stm32h563_m33mu_ssh_tzen: + runs-on: ubuntu-latest + timeout-minutes: 25 + container: + image: ghcr.io/danielinux/m33mu-ci:1.8 + options: --privileged + + steps: + - uses: actions/checkout@v4 + + - name: Install host tools + run: | + set -euo pipefail + apt-get update + apt-get install -y sudo dnsmasq iproute2 netcat-openbsd git \ + openssh-client sshpass + + - name: Fetch wolfSSL/wolfSSH + run: | + set -euo pipefail + if [ ! -d ../wolfssl ]; then + git clone --depth 1 --branch master https://github.com/wolfSSL/wolfssl.git ../wolfssl + fi + if [ ! -d ../wolfssh ]; then + git clone --depth 1 --branch master https://github.com/wolfSSL/wolfssh.git ../wolfssh + fi + + - name: Build STM32H563 SSH (TZEN on) + run: | + set -euo pipefail + make -C src/port/stm32h563 clean TZEN=1 ENABLE_SSH=1 + make -C src/port/stm32h563 TZEN=1 ENABLE_SSH=1 \ + CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy + strings src/port/stm32h563/app.bin > /tmp/wolfip-app.strings + grep -Fq "Initializing SSH server" /tmp/wolfip-app.strings + + - name: Run m33mu + DHCP + SSH test + timeout-minutes: 15 + run: | + set -euo pipefail + + cleanup() { + set +e + if [ -f /tmp/m33mu.pid ]; then + sudo kill "$(cat /tmp/m33mu.pid)" 2>/dev/null || true + fi + sudo pkill -x m33mu 2>/dev/null || true + if [ -f /tmp/dnsmasq.pid ]; then + sudo kill "$(cat /tmp/dnsmasq.pid)" 2>/dev/null || true + fi + sudo ip link del tap0 2>/dev/null || true + } + trap cleanup EXIT + + sudo ip tuntap add dev tap0 mode tap + sudo ip addr add 192.168.12.1/24 dev tap0 + sudo ip link set tap0 up + + cat > /tmp/dnsmasq.conf <<'CONF' + interface=tap0 + bind-interfaces + dhcp-range=192.168.12.50,192.168.12.100,255.255.255.0,12h + dhcp-leasefile=/tmp/dnsmasq.leases + log-dhcp + CONF + sudo dnsmasq --conf-file=/tmp/dnsmasq.conf --pid-file=/tmp/dnsmasq.pid + + sudo m33mu src/port/stm32h563/app.bin \ + --cpu stm32h563 --tap:tap0 --uart-stdout --timeout 180 --quit-on-faults \ + 2>&1 | tee /tmp/m33mu.log & + sleep 1 + m33mu_pid="$(pgrep -n -x m33mu || true)" + if [ -n "${m33mu_pid}" ]; then + echo "${m33mu_pid}" > /tmp/m33mu.pid + fi + + ip="" + for _ in $(seq 1 90); do + if [ -s /tmp/dnsmasq.leases ]; then + ip="$(tail -n1 /tmp/dnsmasq.leases | cut -d' ' -f3)" + fi + if [ -n "${ip}" ]; then + break + fi + sleep 1 + done + if [ -z "${ip}" ]; then + echo "No DHCP lease acquired." + echo "m33mu log:" + tail -n 200 /tmp/m33mu.log || true + exit 1 + fi + echo "Leased IP: ${ip}" + + ok=0 + for _ in $(seq 1 60); do + if ! pgrep -x m33mu >/dev/null 2>&1; then + echo "m33mu exited before SSH check." + tail -n 200 /tmp/m33mu.log || true + exit 1 + fi + if timeout 10s bash -lc "printf '' | nc -w 5 '${ip}' 22" \ + | tee /tmp/ssh.log | grep -q "^SSH-2.0-"; then + ok=1 + break + fi + sleep 0.5 + done + if [ "${ok}" -ne 1 ]; then + echo "SSH test failed." + echo "m33mu log:" + tail -n 200 /tmp/m33mu.log || true + echo "ssh log:" + tail -n 200 /tmp/ssh.log || true + exit 1 + fi + echo "SSH test succeeded." + if [ -f /tmp/m33mu.pid ]; then + sudo kill "$(cat /tmp/m33mu.pid)" 2>/dev/null || true + fi diff --git a/src/port/freeRTOS/bsd_socket.c b/src/port/freeRTOS/bsd_socket.c index ad6838ac..60151b4c 100644 --- a/src/port/freeRTOS/bsd_socket.c +++ b/src/port/freeRTOS/bsd_socket.c @@ -187,6 +187,27 @@ static int wolfip_bsd_wait_unlocked(wolfip_bsd_fd_entry *entry) return 0; } +/* Some TCP core calls surface a temporary "not established yet" as -1 on a + * freshly accepted stream socket before the final ACK promotes it to + * ESTABLISHED. Allow a single wait/retry for that case without turning all + * bare -1 returns into infinite retry loops. */ +static int wolfip_bsd_tcp_stream_retryable_once(int internal_fd, int ret, int *used) +{ + if (ret != -1 || used == NULL || *used || !IS_SOCKET_TCP(internal_fd)) { + return 0; + } + *used = 1; + return 1; +} + +static int wolfip_bsd_tcp_recv_should_wait_locked(int internal_fd, int ret) +{ + if (ret != -1 || !IS_SOCKET_TCP(internal_fd)) { + return 0; + } + return wolfIP_sock_can_read(g_ipstack, internal_fd) == 0; +} + int wolfip_freertos_socket_init(struct wolfIP *ipstack, UBaseType_t poll_task_priority, uint16_t poll_task_stack_words) @@ -292,6 +313,7 @@ int accept(int sockfd, struct wolfIP_sockaddr *addr, socklen_t *addrlen) { int ret; int public_fd; + int retried_minus_one = 0; wolfip_bsd_fd_entry *entry; if (!wolfip_bsd_fd_valid(sockfd)) { @@ -314,6 +336,17 @@ int accept(int sockfd, struct wolfIP_sockaddr *addr, socklen_t *addrlen) } return public_fd; } + if (wolfip_bsd_tcp_stream_retryable_once(entry->internal_fd, ret, + &retried_minus_one)) { + wolfip_bsd_prepare_wait_locked(entry, + (uint16_t)(CB_EVENT_READABLE | CB_EVENT_CLOSED)); + xSemaphoreGive(g_lock); + if (wolfip_bsd_wait_unlocked(entry) < 0) { + wolfip_bsd_set_error(WOLFIP_EAGAIN); + return -1; + } + continue; + } if (ret != -WOLFIP_EAGAIN) { xSemaphoreGive(g_lock); wolfip_bsd_set_error(ret); @@ -364,6 +397,7 @@ int connect(int sockfd, const struct wolfIP_sockaddr *addr, socklen_t addrlen) int send(int sockfd, const void *buf, size_t len, int flags) { int ret; + int retried_minus_one = 0; wolfip_bsd_fd_entry *entry; if (!wolfip_bsd_fd_valid(sockfd)) { @@ -378,6 +412,17 @@ int send(int sockfd, const void *buf, size_t len, int flags) xSemaphoreGive(g_lock); return ret; } + if (wolfip_bsd_tcp_stream_retryable_once(entry->internal_fd, ret, + &retried_minus_one)) { + wolfip_bsd_prepare_wait_locked(entry, + (uint16_t)(CB_EVENT_WRITABLE | CB_EVENT_READABLE | CB_EVENT_CLOSED)); + xSemaphoreGive(g_lock); + if (wolfip_bsd_wait_unlocked(entry) < 0) { + wolfip_bsd_set_error(WOLFIP_EAGAIN); + return -1; + } + continue; + } if (ret != -WOLFIP_EAGAIN) { xSemaphoreGive(g_lock); wolfip_bsd_set_error(ret); @@ -397,6 +442,7 @@ int sendto(int sockfd, const void *buf, size_t len, int flags, const struct wolfIP_sockaddr *dest_addr, socklen_t addrlen) { int ret; + int retried_minus_one = 0; wolfip_bsd_fd_entry *entry; if (!wolfip_bsd_fd_valid(sockfd)) { @@ -411,6 +457,17 @@ int sendto(int sockfd, const void *buf, size_t len, int flags, xSemaphoreGive(g_lock); return ret; } + if (wolfip_bsd_tcp_stream_retryable_once(entry->internal_fd, ret, + &retried_minus_one)) { + wolfip_bsd_prepare_wait_locked(entry, + (uint16_t)(CB_EVENT_WRITABLE | CB_EVENT_READABLE | CB_EVENT_CLOSED)); + xSemaphoreGive(g_lock); + if (wolfip_bsd_wait_unlocked(entry) < 0) { + wolfip_bsd_set_error(WOLFIP_EAGAIN); + return -1; + } + continue; + } if (ret != -WOLFIP_EAGAIN) { xSemaphoreGive(g_lock); wolfip_bsd_set_error(ret); @@ -443,6 +500,16 @@ int recv(int sockfd, void *buf, size_t len, int flags) xSemaphoreGive(g_lock); return ret; } + if (wolfip_bsd_tcp_recv_should_wait_locked(entry->internal_fd, ret)) { + wolfip_bsd_prepare_wait_locked(entry, + (uint16_t)(CB_EVENT_READABLE | CB_EVENT_WRITABLE | CB_EVENT_CLOSED)); + xSemaphoreGive(g_lock); + if (wolfip_bsd_wait_unlocked(entry) < 0) { + wolfip_bsd_set_error(WOLFIP_EAGAIN); + return -1; + } + continue; + } if (ret != -WOLFIP_EAGAIN) { xSemaphoreGive(g_lock); wolfip_bsd_set_error(ret); @@ -476,6 +543,16 @@ int recvfrom(int sockfd, void *buf, size_t len, int flags, xSemaphoreGive(g_lock); return ret; } + if (wolfip_bsd_tcp_recv_should_wait_locked(entry->internal_fd, ret)) { + wolfip_bsd_prepare_wait_locked(entry, + (uint16_t)(CB_EVENT_READABLE | CB_EVENT_WRITABLE | CB_EVENT_CLOSED)); + xSemaphoreGive(g_lock); + if (wolfip_bsd_wait_unlocked(entry) < 0) { + wolfip_bsd_set_error(WOLFIP_EAGAIN); + return -1; + } + continue; + } if (ret != -WOLFIP_EAGAIN) { xSemaphoreGive(g_lock); wolfip_bsd_set_error(ret); diff --git a/src/port/stm32h563/FreeRTOSConfig.h b/src/port/stm32h563/FreeRTOSConfig.h new file mode 100644 index 00000000..e2e13512 --- /dev/null +++ b/src/port/stm32h563/FreeRTOSConfig.h @@ -0,0 +1,66 @@ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include + +extern uint32_t SystemCoreClock; + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configCPU_CLOCK_HZ ( ( uint32_t ) 64000000 ) +#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) +#define configMAX_PRIORITIES 6 +#define configMINIMAL_STACK_SIZE ( ( uint16_t ) 256 ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 128 * 1024 ) ) +#define configMAX_TASK_NAME_LEN 16 +#define configUSE_TRACE_FACILITY 0 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configUSE_RECURSIVE_MUTEXES 0 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configGENERATE_RUN_TIME_STATS 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY 2 +#define configTIMER_QUEUE_LENGTH 4 +#define configTIMER_TASK_STACK_DEPTH 256 + +#define configPRIO_BITS 4 +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 +#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 +#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << ( 8 - configPRIO_BITS ) ) +#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << ( 8 - configPRIO_BITS ) ) + +#define configENABLE_FPU 0 +#define configENABLE_MVE 0 +#define configENABLE_MPU 0 +#define configENABLE_TRUSTZONE 0 +#define configRUN_FREERTOS_SECURE_ONLY 0 + +#define INCLUDE_vTaskPrioritySet 0 +#define INCLUDE_uxTaskPriorityGet 0 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 0 +#define INCLUDE_xResumeFromISR 0 +#define INCLUDE_vTaskDelayUntil 0 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_xTaskGetTickCount 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 + +#define xPortPendSVHandler PendSV_Handler +#define vPortSVCHandler SVC_Handler +#define xPortSysTickHandler SysTick_Handler + +#define configASSERT( x ) do { if ( ( x ) == 0 ) { for ( ;; ) { } } } while (0) + +#endif diff --git a/src/port/stm32h563/Makefile b/src/port/stm32h563/Makefile index 673b825f..8bcadf2e 100644 --- a/src/port/stm32h563/Makefile +++ b/src/port/stm32h563/Makefile @@ -30,6 +30,11 @@ ENABLE_MQTT ?= 0 # MQTT Broker: set ENABLE_MQTT_BROKER=1 to include wolfMQTT broker (requires TLS) ENABLE_MQTT_BROKER ?= 0 +# FreeRTOS integration: set FREERTOS=1 to run the HTTPS server from a +# FreeRTOS task using the blocking BSD socket wrapper layer. +FREERTOS ?= 0 +FREERTOS_PATH ?= $(ROOT)/../FreeRTOS_Kernel + # Auto-enable TLS when any feature that requires it is enabled ifeq ($(ENABLE_TLS_CLIENT),1) ENABLE_TLS = 1 @@ -52,6 +57,7 @@ WOLFSSL_SP_NO_ASM ?= 0 WOLFSSL_ROOT ?= $(ROOT)/../wolfssl WOLFSSH_ROOT ?= $(ROOT)/../wolfssh WOLFMQTT_ROOT ?= $(ROOT)/../wolfmqtt +FREERTOS_PORT_DIR := $(FREERTOS_PATH)/portable/GCC/ARM_CM33_NTZ/non_secure # Base compiler flags CFLAGS := -mcpu=cortex-m33 -mthumb -mcmse -Os -ffreestanding -fdata-sections -ffunction-sections @@ -80,7 +86,47 @@ endif LDFLAGS := -nostdlib -T $(LDSCRIPT) -Wl,-gc-sections # Base source files -SRCS := startup.c ivt.c syscalls.c main.c $(ROOT)/src/port/stm32/stm32_eth.c $(ROOT)/src/wolfip.c +SRCS := startup.c ivt.c syscalls.c +SRCS += main.c $(ROOT)/src/port/stm32/stm32_eth.c $(ROOT)/src/wolfip.c + +ifeq ($(FREERTOS),1) +ifeq ($(wildcard $(FREERTOS_PATH)/include/FreeRTOS.h),) + $(error FreeRTOS kernel not found at $(FREERTOS_PATH). Populate it or override FREERTOS_PATH) +endif + +ifeq ($(wildcard $(FREERTOS_PORT_DIR)/port.c),) + $(error FreeRTOS ARM_CM33_NTZ port not found at $(FREERTOS_PORT_DIR)) +endif +ifneq ($(ENABLE_TLS_CLIENT),0) + $(error FREERTOS=1 does not support ENABLE_TLS_CLIENT yet) +endif +ifneq ($(ENABLE_SSH),0) + $(error FREERTOS=1 does not support ENABLE_SSH yet) +endif +ifneq ($(ENABLE_MQTT),0) + $(error FREERTOS=1 does not support ENABLE_MQTT yet) +endif +ifneq ($(ENABLE_MQTT_BROKER),0) + $(error FREERTOS=1 does not support ENABLE_MQTT_BROKER yet) +endif + +CFLAGS += -DWOLFIP_USE_FREERTOS +CFLAGS += -I$(FREERTOS_PATH)/include -I$(FREERTOS_PORT_DIR) -I$(ROOT)/src/port/freeRTOS +SRCS += echo_server_freertos.c +ifeq ($(ENABLE_HTTPS),1) +SRCS += https_server_freertos.c +endif +SRCS += $(ROOT)/src/port/freeRTOS/bsd_socket.c +SRCS += $(FREERTOS_PATH)/tasks.c +SRCS += $(FREERTOS_PATH)/list.c +SRCS += $(FREERTOS_PATH)/queue.c +SRCS += $(FREERTOS_PATH)/timers.c +SRCS += $(FREERTOS_PATH)/portable/MemMang/heap_4.c +SRCS += $(FREERTOS_PORT_DIR)/port.c +SRCS += $(wildcard $(FREERTOS_PORT_DIR)/portasm.c) +SRCS += $(wildcard $(FREERTOS_PORT_DIR)/portasm.s) +SRCS += $(wildcard $(FREERTOS_PORT_DIR)/portasm.S) +endif # ----------------------------------------------------------------------------- # TLS Support (wolfSSL) @@ -98,8 +144,10 @@ CFLAGS += -DWOLFSSL_WOLFIP CFLAGS += -I$(WOLFSSL_ROOT) # TLS server, client and wolfIP-wolfSSL glue +ifeq ($(FREERTOS),0) SRCS += tls_server.c SRCS += $(ROOT)/src/port/wolfssl_io.c +endif # TLS client (Google test) ifeq ($(ENABLE_TLS_CLIENT),1) @@ -108,12 +156,14 @@ SRCS += tls_client.c endif -# HTTPS web server - uses existing wolfIP httpd +# HTTPS web server - bare-metal mode uses the raw wolfIP httpd path. ifeq ($(ENABLE_HTTPS),1) CFLAGS += -DENABLE_HTTPS +ifeq ($(FREERTOS),0) CFLAGS += -DWOLFIP_ENABLE_HTTP SRCS += $(ROOT)/src/http/httpd.c endif +endif # wolfSSL source files (minimal set for TLS 1.3 server with ECC) WOLFSSL_SRCS := \ @@ -131,12 +181,12 @@ WOLFSSL_SRCS := \ $(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_int.c ifeq ($(WOLFSSL_SP_NO_ASM),1) CFLAGS += -DWOLFSSL_SP_NO_ASM CFLAGS_WOLFSSL += -DWOLFSSL_SP_NO_ASM +WOLFSSL_SRCS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_c32.c else WOLFSSL_SRCS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_cortexm.c endif @@ -284,7 +334,7 @@ endif # ENABLE_MQTT_BROKER 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)" + @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)" ifeq ($(ENABLE_TLS),1) @echo " wolfSSL: $(WOLFSSL_ROOT)" endif @@ -309,13 +359,19 @@ app.bin: app.elf # wolfSSL objects use relaxed warnings + user_settings.h + include paths $(WOLFSSL_ROOT)/%.o: $(WOLFSSL_ROOT)/%.c - $(CC) $(CFLAGS_WOLFSSL) -DWOLFSSL_USER_SETTINGS $(if $(filter 1,$(ENABLE_SSH)),-DENABLE_SSH) $(if $(filter 1,$(ENABLE_MQTT_BROKER)),-DENABLE_MQTT_BROKER) -I$(WOLFSSL_ROOT) -c $< -o $@ + $(CC) $(CFLAGS_WOLFSSL) -DWOLFSSL_USER_SETTINGS $(if $(filter 1,$(ENABLE_SSH)),-DENABLE_SSH -DWOLFSSL_WOLFSSH) $(if $(filter 1,$(ENABLE_MQTT_BROKER)),-DENABLE_MQTT_BROKER) -I$(WOLFSSL_ROOT) -c $< -o $@ clean: rm -f *.o app.elf app.bin rm -f $(ROOT)/src/*.o rm -f $(ROOT)/src/port/*.o rm -f $(ROOT)/src/port/stm32/*.o + rm -f $(ROOT)/src/port/freeRTOS/*.o +ifeq ($(FREERTOS),1) + rm -f $(FREERTOS_PATH)/*.o + rm -f $(FREERTOS_PATH)/portable/MemMang/*.o + rm -f $(FREERTOS_PORT_DIR)/*.o +endif ifeq ($(ENABLE_TLS),1) rm -f $(WOLFSSL_ROOT)/wolfcrypt/src/*.o rm -f $(WOLFSSL_ROOT)/src/*.o @@ -341,7 +397,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)" + @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)" # Show memory usage size: app.elf @@ -376,6 +432,8 @@ help: @echo " ENABLE_SSH=1 Enable SSH server (requires TLS + wolfSSH)" @echo " ENABLE_MQTT=1 Enable MQTT client (requires TLS + wolfMQTT)" @echo " ENABLE_MQTT_BROKER=1 Enable MQTT broker (requires TLS + wolfMQTT)" + @echo " FREERTOS=1 Run HTTPS in a FreeRTOS task via BSD socket wrappers" + @echo " FREERTOS_PATH= Path to FreeRTOS-Kernel (default: $(ROOT)/../FreeRTOS_Kernel)" @echo " WOLFSSL_ROOT= Path to wolfSSL (default: ../wolfssl)" @echo " WOLFSSH_ROOT= Path to wolfSSH (default: ../wolfssh)" @echo " WOLFMQTT_ROOT= Path to wolfMQTT (default: ../wolfmqtt)" @@ -390,6 +448,7 @@ help: @echo " make ENABLE_TLS=1 ENABLE_TLS_CLIENT=1 # TLS client (Google test)" @echo " make ENABLE_TLS=1 ENABLE_MQTT=1 # TLS + MQTT client" @echo " make ENABLE_TLS=1 ENABLE_MQTT_BROKER=1 # TLS + MQTT broker" + @echo " make FREERTOS=1 ENABLE_HTTPS=1 # FreeRTOS HTTPS via BSD sockets" @echo " make ENABLE_TLS=1 ENABLE_HTTPS=1 ENABLE_SSH=1 ENABLE_MQTT=1 ENABLE_MQTT_BROKER=1 # Full featured" @echo "" @echo "Full Build Command (recommended):" diff --git a/src/port/stm32h563/echo_server_freertos.c b/src/port/stm32h563/echo_server_freertos.c new file mode 100644 index 00000000..082d5e36 --- /dev/null +++ b/src/port/stm32h563/echo_server_freertos.c @@ -0,0 +1,143 @@ +#include "echo_server_freertos.h" + +#include +#include + +#include "FreeRTOS.h" +#include "task.h" + +#include "bsd_socket.h" +#include "wolfip.h" + +#define FREERTOS_ECHO_TASK_NAME "echo" +#define FREERTOS_ECHO_TASK_STACK_WORDS 2048 +#define FREERTOS_ECHO_TASK_PRIORITY 3 +#define FREERTOS_ECHO_BACKLOG 2 + +typedef struct { + struct wolfIP *stack; + uint16_t port; + echo_server_freertos_debug_cb debug_cb; +} freertos_echo_task_ctx; + +static freertos_echo_task_ctx g_echo_task_ctx; +static char g_echo_rxbuf[512]; + +static void echo_debug(const char *msg) +{ + if (g_echo_task_ctx.debug_cb != NULL) { + g_echo_task_ctx.debug_cb(msg); + } +} + +static void echo_debug_port(const char *prefix, uint16_t port) +{ + char msg[96]; + + (void)snprintf(msg, sizeof(msg), "%s %u\n", prefix, (unsigned)port); + echo_debug(msg); +} + +static void echo_debug_error(const char *prefix, int ret, int sock_err) +{ + char msg[96]; + + (void)snprintf(msg, sizeof(msg), "%s ret=%d sock_err=%d\n", + prefix, ret, sock_err); + echo_debug(msg); +} + +static int echo_send_all(int client_fd, const char *buf, int len) +{ + int sent = 0; + + while (sent < len) { + int ret = send(client_fd, buf + sent, (size_t)(len - sent), 0); + if (ret <= 0) { + echo_debug_error("Echo/FreeRTOS: send failed", ret, socket_last_error()); + return -1; + } + sent += ret; + } + + return 0; +} + +static void echo_serve_client(int client_fd) +{ + int ret; + + for (;;) { + ret = recv(client_fd, g_echo_rxbuf, sizeof(g_echo_rxbuf), 0); + if (ret <= 0) { + echo_debug_error("Echo/FreeRTOS: recv failed", ret, socket_last_error()); + break; + } + if (echo_send_all(client_fd, g_echo_rxbuf, ret) < 0) { + break; + } + } + (void)close(client_fd); +} + +static void echo_server_task(void *arg) +{ + freertos_echo_task_ctx *task_ctx = (freertos_echo_task_ctx *)arg; + struct wolfIP_sockaddr_in addr; + int listen_fd; + + (void)task_ctx->stack; + listen_fd = socket(AF_INET, SOCK_STREAM, 0); + if (listen_fd < 0) { + echo_debug("Echo/FreeRTOS: socket failed\n"); + vTaskDelete(NULL); + return; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = ee16(task_ctx->port); + addr.sin_addr.s_addr = 0; + + if (bind(listen_fd, (const struct wolfIP_sockaddr *)&addr, sizeof(addr)) < 0) { + echo_debug("Echo/FreeRTOS: bind failed\n"); + (void)close(listen_fd); + vTaskDelete(NULL); + return; + } + + if (listen(listen_fd, FREERTOS_ECHO_BACKLOG) < 0) { + echo_debug("Echo/FreeRTOS: listen failed\n"); + (void)close(listen_fd); + vTaskDelete(NULL); + return; + } + + echo_debug_port("Echo/FreeRTOS: Server ready on port", task_ctx->port); + + for (;;) { + int client_fd = accept(listen_fd, NULL, NULL); + if (client_fd < 0) { + echo_debug("Echo/FreeRTOS: accept failed\n"); + vTaskDelay(pdMS_TO_TICKS(50)); + continue; + } + echo_serve_client(client_fd); + } +} + +int echo_server_freertos_start(struct wolfIP *stack, uint16_t port, + echo_server_freertos_debug_cb debug_cb) +{ + g_echo_task_ctx.stack = stack; + g_echo_task_ctx.port = port; + g_echo_task_ctx.debug_cb = debug_cb; + + if (xTaskCreate(echo_server_task, FREERTOS_ECHO_TASK_NAME, + FREERTOS_ECHO_TASK_STACK_WORDS, &g_echo_task_ctx, + FREERTOS_ECHO_TASK_PRIORITY, NULL) != pdPASS) { + return -1; + } + + return 0; +} diff --git a/src/port/stm32h563/echo_server_freertos.h b/src/port/stm32h563/echo_server_freertos.h new file mode 100644 index 00000000..a6dd30c6 --- /dev/null +++ b/src/port/stm32h563/echo_server_freertos.h @@ -0,0 +1,13 @@ +#ifndef ECHO_SERVER_FREERTOS_H +#define ECHO_SERVER_FREERTOS_H + +#include + +struct wolfIP; + +typedef void (*echo_server_freertos_debug_cb)(const char *msg); + +int echo_server_freertos_start(struct wolfIP *stack, uint16_t port, + echo_server_freertos_debug_cb debug_cb); + +#endif diff --git a/src/port/stm32h563/https_server_freertos.c b/src/port/stm32h563/https_server_freertos.c new file mode 100644 index 00000000..e586e774 --- /dev/null +++ b/src/port/stm32h563/https_server_freertos.c @@ -0,0 +1,324 @@ +#include "https_server_freertos.h" + +#include +#include + +#include "FreeRTOS.h" +#include "portable.h" +#include "task.h" + +#include "bsd_socket.h" +#include "certs.h" +#include "config.h" +#include "wolfip.h" + +#include +#include + +#define FREERTOS_HTTPS_TASK_NAME "https" +#define FREERTOS_HTTPS_TASK_STACK_WORDS 4096 +#define FREERTOS_HTTPS_TASK_PRIORITY 3 +#define FREERTOS_HTTPS_BACKLOG 2 + +typedef struct { + struct wolfIP *stack; + uint16_t port; + https_server_freertos_debug_cb debug_cb; +} freertos_https_task_ctx; + +static freertos_https_task_ctx g_https_task_ctx; +static char g_https_request[512]; +static char g_https_response[768]; + +static void https_debug(const char *msg) +{ + if (g_https_task_ctx.debug_cb != NULL) { + g_https_task_ctx.debug_cb(msg); + } +} + +static void https_debug_error(const char *prefix, int wolfssl_err, int sock_err) +{ + char msg[96]; + + (void)snprintf(msg, sizeof(msg), "%s err=%d sock_err=%d\n", + prefix, wolfssl_err, sock_err); + https_debug(msg); +} + +static void https_debug_port(const char *prefix, uint16_t port) +{ + char msg[96]; + + (void)snprintf(msg, sizeof(msg), "%s %u\n", prefix, (unsigned)port); + https_debug(msg); +} + +static void https_debug_diag(const char *phase) +{ + char msg[128]; + UBaseType_t high_water; + size_t free_heap; + size_t min_heap; + + high_water = uxTaskGetStackHighWaterMark(NULL); + free_heap = xPortGetFreeHeapSize(); + min_heap = xPortGetMinimumEverFreeHeapSize(); + + (void)snprintf(msg, sizeof(msg), + "HTTPS/FreeRTOS: %s stack_hw=%lu free_heap=%lu min_heap=%lu\n", + phase, + (unsigned long)high_water, + (unsigned long)free_heap, + (unsigned long)min_heap); + https_debug(msg); +} + +static int https_tls_recv(WOLFSSL *ssl, char *buf, int sz, void *ctx) +{ + int fd; + int err; + int ret; + + (void)ssl; + if (ctx == NULL) { + return WOLFSSL_CBIO_ERR_GENERAL; + } + + fd = *(const int *)ctx; + ret = recv(fd, buf, (size_t)sz, 0); + if (ret < 0) { + err = socket_last_error(); + if (err == WOLFIP_EAGAIN) { + return WOLFSSL_CBIO_ERR_WANT_READ; + } + https_debug_error("HTTPS/FreeRTOS: recv failed", ret, err); + return WOLFSSL_CBIO_ERR_GENERAL; + } + if (ret == 0) { + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + return ret; +} + +static int https_tls_send(WOLFSSL *ssl, char *buf, int sz, void *ctx) +{ + int fd; + int err; + int ret; + + (void)ssl; + if (ctx == NULL) { + return WOLFSSL_CBIO_ERR_GENERAL; + } + + fd = *(const int *)ctx; + ret = send(fd, buf, (size_t)sz, 0); + if (ret <= 0) { + err = socket_last_error(); + if (err == WOLFIP_EAGAIN) { + return WOLFSSL_CBIO_ERR_WANT_WRITE; + } + https_debug_error("HTTPS/FreeRTOS: send failed", ret, err); + return WOLFSSL_CBIO_ERR_GENERAL; + } + return ret; +} + +static void format_ip4(ip4 ip, char *buf, size_t buf_len) +{ + uint32_t host_ip = (uint32_t)ip; + + (void)snprintf(buf, buf_len, "%u.%u.%u.%u", + (unsigned)((host_ip >> 24) & 0xFFu), + (unsigned)((host_ip >> 16) & 0xFFu), + (unsigned)((host_ip >> 8) & 0xFFu), + (unsigned)(host_ip & 0xFFu)); +} + +static void https_serve_client(WOLFSSL_CTX *ctx, struct wolfIP *stack, int client_fd) +{ + WOLFSSL *ssl; + char ip_str[16]; + int err; + int ret; + ip4 ip = 0; + uint32_t uptime_sec; + int response_len; + + (void)stack; + https_debug_diag("client start"); + ssl = wolfSSL_new(ctx); + if (ssl == NULL) { + https_debug("HTTPS/FreeRTOS: wolfSSL_new failed\n"); + (void)close(client_fd); + return; + } + https_debug_diag("after wolfSSL_new"); + + wolfSSL_SetIOReadCtx(ssl, &client_fd); + wolfSSL_SetIOWriteCtx(ssl, &client_fd); + + ret = wolfSSL_accept(ssl); + if (ret != WOLFSSL_SUCCESS) { + err = wolfSSL_get_error(ssl, ret); + https_debug_diag("accept failed"); + https_debug_error("HTTPS/FreeRTOS: TLS handshake failed", + err, socket_last_error()); + wolfSSL_free(ssl); + (void)close(client_fd); + return; + } + https_debug_diag("after wolfSSL_accept"); + + ret = wolfSSL_read(ssl, g_https_request, (int)sizeof(g_https_request) - 1); + if (ret <= 0) { + err = wolfSSL_get_error(ssl, ret); + https_debug_diag("read failed"); + https_debug_error("HTTPS/FreeRTOS: request read failed", + err, socket_last_error()); + wolfSSL_shutdown(ssl); + wolfSSL_free(ssl); + (void)close(client_fd); + return; + } + g_https_request[ret] = '\0'; + https_debug_diag("after request read"); + + wolfIP_ipconfig_get(stack, &ip, NULL, NULL); + format_ip4(ip, ip_str, sizeof(ip_str)); + uptime_sec = (uint32_t)(xTaskGetTickCount() / configTICK_RATE_HZ); + + response_len = snprintf(g_https_response, sizeof(g_https_response), + "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n" + "Content-Type: text/html\r\n\r\n" + "wolfIP STM32H563 FreeRTOS" + "" + "

wolfIP Status

" + "" + "" + "" + "" + "" + "
DeviceSTM32H563
ModeFreeRTOS BSD sockets
IP Address%s
Uptime%lu sec
TLSTLS 1.3
", + ip_str, (unsigned long)uptime_sec); + if (response_len > 0) { + if ((size_t)response_len >= sizeof(g_https_response)) { + response_len = (int)sizeof(g_https_response) - 1; + } + (void)wolfSSL_write(ssl, g_https_response, response_len); + } + + wolfSSL_shutdown(ssl); + wolfSSL_free(ssl); + (void)close(client_fd); + https_debug_diag("client done"); +} + +static void https_server_task(void *arg) +{ + freertos_https_task_ctx *task_ctx = (freertos_https_task_ctx *)arg; + struct wolfIP_sockaddr_in addr; + WOLFSSL_CTX *ctx; + int listen_fd; + + https_debug("HTTPS/FreeRTOS: Initializing wolfSSL\n"); + https_debug_diag("task start"); + if (wolfSSL_Init() != WOLFSSL_SUCCESS) { + https_debug("HTTPS/FreeRTOS: wolfSSL_Init failed\n"); + vTaskDelete(NULL); + return; + } + + ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()); + if (ctx == NULL) { + https_debug("HTTPS/FreeRTOS: CTX_new failed\n"); + vTaskDelete(NULL); + return; + } + https_debug_diag("after CTX_new"); + + wolfSSL_SetIORecv(ctx, https_tls_recv); + wolfSSL_SetIOSend(ctx, https_tls_send); + + if (wolfSSL_CTX_use_certificate_buffer(ctx, + (const unsigned char *)server_cert_pem, + server_cert_pem_len - 1, + WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS) { + https_debug("HTTPS/FreeRTOS: certificate load failed\n"); + wolfSSL_CTX_free(ctx); + vTaskDelete(NULL); + return; + } + + if (wolfSSL_CTX_use_PrivateKey_buffer(ctx, + (const unsigned char *)server_key_pem, + server_key_pem_len - 1, + WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS) { + https_debug("HTTPS/FreeRTOS: private key load failed\n"); + wolfSSL_CTX_free(ctx); + vTaskDelete(NULL); + return; + } + + listen_fd = socket(AF_INET, SOCK_STREAM, 0); + if (listen_fd < 0) { + https_debug("HTTPS/FreeRTOS: socket failed\n"); + wolfSSL_CTX_free(ctx); + vTaskDelete(NULL); + return; + } + https_debug_diag("after socket"); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = ee16(task_ctx->port); + addr.sin_addr.s_addr = 0; + + if (bind(listen_fd, (const struct wolfIP_sockaddr *)&addr, sizeof(addr)) < 0) { + https_debug("HTTPS/FreeRTOS: bind failed\n"); + (void)close(listen_fd); + wolfSSL_CTX_free(ctx); + vTaskDelete(NULL); + return; + } + + if (listen(listen_fd, FREERTOS_HTTPS_BACKLOG) < 0) { + https_debug("HTTPS/FreeRTOS: listen failed\n"); + (void)close(listen_fd); + wolfSSL_CTX_free(ctx); + vTaskDelete(NULL); + return; + } + + https_debug_port("HTTPS/FreeRTOS: Server ready on port", task_ctx->port); + https_debug_diag("server ready"); + + for (;;) { + int client_fd = accept(listen_fd, NULL, NULL); + if (client_fd < 0) { + https_debug("HTTPS/FreeRTOS: accept failed\n"); + vTaskDelay(pdMS_TO_TICKS(50)); + continue; + } + https_serve_client(ctx, task_ctx->stack, client_fd); + } +} + +int https_server_freertos_start(struct wolfIP *stack, uint16_t port, + https_server_freertos_debug_cb debug_cb) +{ + g_https_task_ctx.stack = stack; + g_https_task_ctx.port = port; + g_https_task_ctx.debug_cb = debug_cb; + + if (xTaskCreate(https_server_task, FREERTOS_HTTPS_TASK_NAME, + FREERTOS_HTTPS_TASK_STACK_WORDS, &g_https_task_ctx, + FREERTOS_HTTPS_TASK_PRIORITY, NULL) != pdPASS) { + return -1; + } + + return 0; +} diff --git a/src/port/stm32h563/https_server_freertos.h b/src/port/stm32h563/https_server_freertos.h new file mode 100644 index 00000000..2387d416 --- /dev/null +++ b/src/port/stm32h563/https_server_freertos.h @@ -0,0 +1,13 @@ +#ifndef HTTPS_SERVER_FREERTOS_H +#define HTTPS_SERVER_FREERTOS_H + +#include + +struct wolfIP; + +typedef void (*https_server_freertos_debug_cb)(const char *msg); + +int https_server_freertos_start(struct wolfIP *stack, uint16_t port, + https_server_freertos_debug_cb debug_cb); + +#endif diff --git a/src/port/stm32h563/ivt.c b/src/port/stm32h563/ivt.c index 2ae1689a..c503dd50 100644 --- a/src/port/stm32h563/ivt.c +++ b/src/port/stm32h563/ivt.c @@ -33,10 +33,22 @@ 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"))); +#ifdef WOLFIP_USE_FREERTOS +extern void SVC_Handler(void); +extern void PendSV_Handler(void); +extern void SysTick_Handler(void); +#define SVC_HANDLER_REF SVC_Handler +#define PENDSV_HANDLER_REF PendSV_Handler +#define SYSTICK_HANDLER_REF SysTick_Handler +#else 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"))); +#define SVC_HANDLER_REF SVC_Handler +#define PENDSV_HANDLER_REF PendSV_Handler +#define SYSTICK_HANDLER_REF SysTick_Handler +#endif +void DebugMon_Handler(void) __attribute__((weak, alias("default_handler"))); __attribute__((section(".isr_vector"))) const uint32_t vector_table[16 + 96] = { @@ -48,10 +60,10 @@ const uint32_t vector_table[16 + 96] = { [5] = (uint32_t)&BusFault_Handler, [6] = (uint32_t)&UsageFault_Handler, [7] = 0, [8] = 0, [9] = 0, [10] = 0, - [11] = (uint32_t)&SVC_Handler, + [11] = (uint32_t)&SVC_HANDLER_REF, [12] = (uint32_t)&DebugMon_Handler, [13] = 0, - [14] = (uint32_t)&PendSV_Handler, - [15] = (uint32_t)&SysTick_Handler, + [14] = (uint32_t)&PENDSV_HANDLER_REF, + [15] = (uint32_t)&SYSTICK_HANDLER_REF, [16 ... 111] = (uint32_t)&default_handler }; diff --git a/src/port/stm32h563/main.c b/src/port/stm32h563/main.c index 5d3fbd46..ff4f0d4e 100644 --- a/src/port/stm32h563/main.c +++ b/src/port/stm32h563/main.c @@ -26,6 +26,14 @@ #include "wolfip.h" #include "stm32_eth.h" +#ifdef WOLFIP_USE_FREERTOS +#include "FreeRTOS.h" +#include "portable.h" +#include "task.h" +#include "bsd_socket.h" +#include "echo_server_freertos.h" +#endif + #ifdef ENABLE_TLS #include "tls_server.h" #include "tls_client.h" @@ -33,8 +41,12 @@ #endif #ifdef ENABLE_HTTPS +#ifdef WOLFIP_USE_FREERTOS +#include "https_server_freertos.h" +#else #include "http/httpd.h" #include "certs.h" +#endif #define HTTPS_WEB_PORT 443 #endif @@ -66,6 +78,7 @@ static int tls_client_test_done = 0; /* Forward declarations */ static void uart_puts(const char *s); +static void delay(uint32_t count); /* ========================================================================= * HardFault Handler - prints crash info via UART @@ -134,7 +147,7 @@ void HardFault_Handler(void) ); } -#ifdef ENABLE_HTTPS +#if defined(ENABLE_HTTPS) && !defined(WOLFIP_USE_FREERTOS) /* HTTPS server using wolfIP httpd */ static struct httpd https_server; static WOLFSSL_CTX *https_ssl_ctx; @@ -218,8 +231,14 @@ static int https_status_handler(struct httpd *httpd, struct http_client *hc, #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_CR (*(volatile uint32_t *)(RCC_BASE + 0x00u)) +#define RCC_CCIPR5 (*(volatile uint32_t *)(RCC_BASE + 0xE8u)) #define RCC_AHB1RSTR (*(volatile uint32_t *)(RCC_BASE + 0x60u)) #define RCC_AHB1RSTR_ETHRST (1u << 19) +#define RCC_AHB2ENR_RNGEN (1u << 18) +#define RCC_CR_HSI48ON (1u << 12) +#define RCC_CR_HSI48RDY (1u << 13) +#define RCC_CCIPR5_RNGSEL_Msk (3u << 4) /* SAU (Security Attribution Unit) - mark memory regions as non-secure */ #define SAU_CTRL (*(volatile uint32_t *)0xE000EDD0u) @@ -291,18 +310,116 @@ static int https_status_handler(struct httpd *httpd, struct http_client *hc, #define GPIO_BSRR(base) (*(volatile uint32_t *)((base) + 0x18u)) #define LED2_PIN 4u +#if TZEN_ENABLED +#define RNG_BASE 0x520C0800u +#else +#define RNG_BASE 0x420C0800u +#endif +#define RNG_CR (*(volatile uint32_t *)(RNG_BASE + 0x00u)) +#define RNG_SR (*(volatile uint32_t *)(RNG_BASE + 0x04u)) +#define RNG_DR (*(volatile uint32_t *)(RNG_BASE + 0x08u)) +#define RNG_CR_RNGEN (1u << 2) +#define RNG_CR_CONDRST (1u << 30) +#define RNG_CR_CONFIG3_SHIFT 8u +#define RNG_CR_CONFIG2_SHIFT 13u +#define RNG_CR_CLKDIV_SHIFT 16u +#define RNG_CR_CONFIG1_SHIFT 20u +#define RNG_SR_DRDY (1u << 0) +#define RNG_SR_CECS (1u << 1) +#define RNG_SR_SECS (1u << 2) +#define RNG_SR_CEIS (1u << 5) +#define RNG_SR_SEIS (1u << 6) + static struct wolfIP *IPStack; +#ifndef WOLFIP_USE_FREERTOS static int listen_fd = -1; static int client_fd = -1; static uint8_t rx_buf[RX_BUF_SIZE]; +#endif + +static void rng_init(void) +{ + uint32_t rng_cr; + + RCC_CR |= RCC_CR_HSI48ON; + while ((RCC_CR & RCC_CR_HSI48RDY) == 0u) { + } + + /* Select HSI48 as the RNG kernel clock. */ + RCC_CCIPR5 &= ~RCC_CCIPR5_RNGSEL_Msk; + RCC_AHB2ENR |= RCC_AHB2ENR_RNGEN; + delay(100); + + rng_cr = RNG_CR; + rng_cr &= ~(0x1Fu << RNG_CR_CONFIG1_SHIFT); + rng_cr &= ~(0x7u << RNG_CR_CLKDIV_SHIFT); + rng_cr &= ~(0x3u << RNG_CR_CONFIG2_SHIFT); + rng_cr &= ~(0x7u << RNG_CR_CONFIG3_SHIFT); + rng_cr |= 0x0Fu << RNG_CR_CONFIG1_SHIFT; + rng_cr |= 0x0Du << RNG_CR_CONFIG3_SHIFT; + + RNG_CR = RNG_CR_CONDRST | rng_cr; + while ((RNG_CR & RNG_CR_CONDRST) == 0u) { + } + RNG_CR = rng_cr | RNG_CR_RNGEN; + while ((RNG_SR & RNG_SR_DRDY) == 0u) { + } +} + +static int rng_get_word(uint32_t *out) +{ + uint32_t timeout = 100000u; + + while ((RNG_SR & RNG_SR_DRDY) == 0u) { + if ((RNG_SR & (RNG_SR_CECS | RNG_SR_SECS | RNG_SR_CEIS | RNG_SR_SEIS)) != 0u) { + rng_init(); + timeout = 100000u; + continue; + } + if (--timeout == 0u) { + return -1; + } + } + + *out = RNG_DR; + return 0; +} + +int custom_rand_gen_block(unsigned char *output, unsigned int sz) +{ + uint32_t word; + + while (sz >= 4u) { + if (rng_get_word(&word) != 0) { + return -1; + } + output[0] = (unsigned char)word; + output[1] = (unsigned char)(word >> 8); + output[2] = (unsigned char)(word >> 16); + output[3] = (unsigned char)(word >> 24); + output += 4; + sz -= 4; + } + + if (sz > 0u) { + if (rng_get_word(&word) != 0) { + return -1; + } + while (sz-- > 0u) { + *output++ = (unsigned char)word; + word >>= 8; + } + } + + return 0; +} uint32_t wolfIP_getrandom(void) { - static uint32_t lfsr = 0x1A2B3C4DU; - lfsr ^= lfsr << 13; - lfsr ^= lfsr >> 17; - lfsr ^= lfsr << 5; - return lfsr; + uint32_t word = 0u; + + (void)rng_get_word(&word); + return word; } /* Simple delay */ @@ -337,10 +454,12 @@ static void led_off(void) GPIO_BSRR(GPIOF_BASE) = (1u << (LED2_PIN + 16u)); } +#ifndef WOLFIP_USE_FREERTOS static void led_toggle(void) { GPIO_ODR(GPIOF_BASE) ^= (1u << LED2_PIN); } +#endif /* USART3 additional registers */ #define USART3_CR2 (*(volatile uint32_t *)(USART3_BASE + 0x04u)) @@ -402,6 +521,69 @@ static void uart_puts(const char *s) } } +void wolfssl_tls13_dbg_hex(const char *tag, const unsigned char *buf, + unsigned len) +{ + static const char hex[] = "0123456789abcdef"; + char line[96]; + unsigned i = 0; + unsigned pos; + + if (tag != NULL) { + uart_puts(tag); + } + if (buf == NULL) { + uart_puts("\n"); + return; + } + + while (i < len) { + pos = 0; + while (i < len && pos + 2 < sizeof(line) - 2) { + line[pos++] = hex[(buf[i] >> 4) & 0x0Fu]; + line[pos++] = hex[buf[i] & 0x0Fu]; + i++; + } + line[pos++] = '\n'; + line[pos] = '\0'; + uart_puts(line); + } +} + +#ifdef WOLFIP_USE_FREERTOS +static void freertos_diag_print_u32(const char *prefix, uint32_t value) +{ + char buf[32]; + + (void)snprintf(buf, sizeof(buf), "%lu", (unsigned long)value); + uart_puts(prefix); + uart_puts(buf); + uart_puts("\n"); +} + +void vApplicationMallocFailedHook(void) +{ + uart_puts("FreeRTOS: malloc failed\n"); + freertos_diag_print_u32(" free heap: ", + (uint32_t)xPortGetFreeHeapSize()); + freertos_diag_print_u32(" min ever free heap: ", + (uint32_t)xPortGetMinimumEverFreeHeapSize()); + for (;;) { } +} + +void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) +{ + (void)xTask; + uart_puts("FreeRTOS: stack overflow\n"); + if (pcTaskName != NULL) { + uart_puts(" task: "); + uart_puts(pcTaskName); + uart_puts("\n"); + } + for (;;) { } +} +#endif + /* Printf-style UART output for wolfMQTT broker logging (WBLOG macros). * Uses vsnprintf from newlib-nano + uart_puts. */ void wolfmqtt_log(const char *fmt, ...) @@ -561,6 +743,7 @@ static void tls_response_cb(const char *data, int len, void *ctx) } #endif +#ifndef WOLFIP_USE_FREERTOS static void echo_cb(int fd, uint16_t event, void *arg) { struct wolfIP *s = (struct wolfIP *)arg; @@ -589,11 +772,14 @@ static void echo_cb(int fd, uint16_t event, void *arg) client_fd = -1; } } +#endif int main(void) { struct wolfIP_ll_dev *ll; +#ifndef WOLFIP_USE_FREERTOS struct wolfIP_sockaddr_in addr; +#endif uint64_t tick = 0; int ret; @@ -603,6 +789,7 @@ int main(void) /* Initialize UART for debug output */ uart_init(); + rng_init(); /* Blink to show UART init done */ led_off(); @@ -613,7 +800,15 @@ int main(void) delay(200000); led_on(); +#ifdef WOLFIP_USE_FREERTOS +#ifdef ENABLE_HTTPS + uart_puts("\n\n=== wolfIP STM32H563 FreeRTOS HTTPS Server ===\n"); +#else + uart_puts("\n\n=== wolfIP STM32H563 FreeRTOS Echo Server ===\n"); +#endif +#else uart_puts("\n\n=== wolfIP STM32H563 Echo Server ===\n"); +#endif #if TZEN_ENABLED /* Configure TrustZone for Ethernet DMA access */ @@ -621,8 +816,12 @@ int main(void) { uint32_t i; - /* Enable SAU with ALLNS mode (all undefined regions are non-secure) */ - SAU_CTRL = 0x03u; /* ENABLE + ALLNS */ + /* Expose only the Ethernet DMA window as non-secure. Leaving ALLNS + * clear keeps the rest of secure flash/SRAM/peripherals secure. */ + SAU_RNR = 0u; + SAU_RBAR = 0x20098000u & 0xFFFFFFE0u; + SAU_RLAR = (0x2009FFFFu & 0xFFFFFFE0u) | 1u; + SAU_CTRL = 0x01u; /* ENABLE */ __asm volatile ("dsb sy" ::: "memory"); __asm volatile ("isb sy" ::: "memory"); @@ -756,6 +955,40 @@ int main(void) } #endif +#ifdef WOLFIP_USE_FREERTOS + uart_puts("Starting FreeRTOS BSD socket layer...\n"); + ret = wolfip_freertos_socket_init(IPStack, 4, 1024); + if (ret < 0) { + uart_puts("ERROR: FreeRTOS socket init failed\n"); + return 1; + } + +#ifdef ENABLE_HTTPS + uart_puts("Creating FreeRTOS HTTPS task on port 443...\n"); + ret = https_server_freertos_start(IPStack, HTTPS_WEB_PORT, uart_puts); + if (ret < 0) { + uart_puts("ERROR: FreeRTOS HTTPS task init failed\n"); + return 1; + } +#else + uart_puts("Creating FreeRTOS TCP echo task on port 7...\n"); + ret = echo_server_freertos_start(IPStack, ECHO_PORT, uart_puts); + if (ret < 0) { + uart_puts("ERROR: FreeRTOS echo task init failed\n"); + return 1; + } +#endif + + uart_puts("Starting FreeRTOS scheduler...\n"); +#ifdef ENABLE_HTTPS + uart_puts(" HTTPS Server: port 443\n"); +#else + uart_puts(" TCP Echo: port 7\n"); +#endif + vTaskStartScheduler(); + uart_puts("ERROR: vTaskStartScheduler returned\n"); + return 1; +#else 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); @@ -968,4 +1201,5 @@ int main(void) } } return 0; +#endif } diff --git a/src/port/stm32h563/target_tzen.ld b/src/port/stm32h563/target_tzen.ld index 4898cf2a..ffcdbd45 100644 --- a/src/port/stm32h563/target_tzen.ld +++ b/src/port/stm32h563/target_tzen.ld @@ -20,6 +20,11 @@ MEMORY _estack = ORIGIN(RAM) + LENGTH(RAM); _sidata = LOADADDR(.data); +/* Heap and stack sizes */ +_Min_Heap_Size = 0x10000; /* 64KB heap */ +_Min_Stack_Size = 0x8000; /* 32KB stack (SP math needs headroom) */ +_heap_limit = _estack - _Min_Stack_Size; + SECTIONS { .isr_vector : @@ -68,9 +73,11 @@ SECTIONS .bss (NOLOAD) : { + . = ALIGN(4); _sbss = .; *(.bss*) *(COMMON) + . = ALIGN(4); _ebss = .; } > RAM @@ -82,4 +89,18 @@ SECTIONS . = ALIGN(32); _eth_end = .; } > ETHMEM + + /* Reserve minimum heap + stack space so the linker errors if RAM is full. + * Heap starts just after BSS at 'end'/'_end'. Stack grows down from + * _estack (top of RAM); _heap_limit = _estack - _Min_Stack_Size is the + * enforced upper bound used by _sbrk(). */ + ._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/tls_server.c b/src/port/stm32h563/tls_server.c index 44199b35..1bb6886b 100644 --- a/src/port/stm32h563/tls_server.c +++ b/src/port/stm32h563/tls_server.c @@ -87,19 +87,6 @@ static void debug_print(const char *msg) } } -/* Custom random block generator for wolfSSL RNG - * Note: For production, use a hardware RNG like STM32 RNG peripheral. - * This uses wolfIP's LFSR PRNG which is NOT cryptographically secure. - */ -int custom_rand_gen_block(unsigned char *output, unsigned int sz) -{ - unsigned int i; - for (i = 0; i < sz; i++) { - output[i] = (unsigned char)(wolfIP_getrandom() & 0xFF); - } - return 0; -} - int tls_server_init(struct wolfIP *stack, uint16_t port, tls_server_debug_cb debug) { diff --git a/src/port/stm32h563/user_settings.h b/src/port/stm32h563/user_settings.h index 452626e7..0eda4eb0 100644 --- a/src/port/stm32h563/user_settings.h +++ b/src/port/stm32h563/user_settings.h @@ -156,8 +156,7 @@ extern "C" { /* ------------------------------------------------------------------------- */ /* RNG */ /* ------------------------------------------------------------------------- */ -/* wc_GenerateSeed is implemented in tls_server.c - * (wolfSSL will call it for entropy) */ +/* wc_GenerateSeed is implemented in main.c using the STM32 RNG peripheral. */ #define CUSTOM_RAND_GENERATE_BLOCK custom_rand_gen_block int custom_rand_gen_block(unsigned char* output, unsigned int sz); diff --git a/tools/scripts/run-m33mu-ci-in-container.sh b/tools/scripts/run-m33mu-ci-in-container.sh index 2d248e9e..22478fd1 100755 --- a/tools/scripts/run-m33mu-ci-in-container.sh +++ b/tools/scripts/run-m33mu-ci-in-container.sh @@ -7,6 +7,14 @@ Usage: tools/scripts/run-m33mu-ci-in-container.sh [job] EOF } +resolve_m33mu_bin() { + if [ -x /workspace/m33mu/build/m33mu ]; then + printf '%s\n' /workspace/m33mu/build/m33mu + else + printf '%s\n' m33mu + fi +} + run_root() { if [ "$(id -u)" -eq 0 ]; then "$@" @@ -37,6 +45,14 @@ ensure_repo() { fi } +ensure_repo_at() { + local path="$1" + local url="$2" + if [ ! -d "${path}/.git" ]; then + git clone --depth 1 "${url}" "${path}" + fi +} + build_echo() { make -C src/port/stm32h563 \ CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy @@ -61,16 +77,44 @@ build_https_tls13() { make -C src/port/stm32h563 TZEN=0 ENABLE_HTTPS=1 \ WOLFSSL_SP_NO_ASM=1 \ CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy - strings src/port/stm32h563/app.bin | grep -q "Initializing HTTPS server" + strings src/port/stm32h563/app.bin > /tmp/wolfip-app.strings + grep -Fq "Initializing HTTPS server" /tmp/wolfip-app.strings +} + +build_https_freertos() { + ensure_repo wolfssl https://github.com/wolfSSL/wolfssl.git + ensure_repo FreeRTOS_Kernel https://github.com/FreeRTOS/FreeRTOS-Kernel.git + make -C src/port/stm32h563 clean TZEN=0 FREERTOS=1 ENABLE_HTTPS=1 \ + WOLFSSL_SP_NO_ASM=1 \ + CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy + make -C src/port/stm32h563 TZEN=0 FREERTOS=1 ENABLE_HTTPS=1 \ + WOLFSSL_SP_NO_ASM=1 \ + CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy + strings src/port/stm32h563/app.bin > /tmp/wolfip-app.strings + grep -Fq "FreeRTOS BSD socket layer" /tmp/wolfip-app.strings + grep -Fq "HTTPS/FreeRTOS: Server ready on port" /tmp/wolfip-app.strings +} + +build_echo_freertos() { + ensure_repo FreeRTOS_Kernel https://github.com/FreeRTOS/FreeRTOS-Kernel.git + make -C src/port/stm32h563 clean TZEN=0 FREERTOS=1 \ + CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy + make -C src/port/stm32h563 TZEN=0 FREERTOS=1 \ + CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy + strings src/port/stm32h563/app.bin > /tmp/wolfip-app.strings + grep -Fq "FreeRTOS BSD socket layer" /tmp/wolfip-app.strings + grep -Fq "Echo/FreeRTOS: Server ready on port" /tmp/wolfip-app.strings } build_ssh_tzen() { ensure_repo wolfssl https://github.com/wolfSSL/wolfssl.git ensure_repo wolfssh https://github.com/wolfSSL/wolfssh.git - make -C src/port/stm32h563 clean - make -C src/port/stm32h563 TZEN=0 ENABLE_SSH=1 \ + make -C src/port/stm32h563 clean TZEN=1 ENABLE_SSH=1 + make -C src/port/stm32h563 TZEN=1 ENABLE_SSH=1 \ CC=arm-none-eabi-gcc OBJCOPY=arm-none-eabi-objcopy - strings src/port/stm32h563/app.bin | grep -q "Initializing SSH server" + sleep 2 + strings src/port/stm32h563/app.bin > /tmp/wolfip-app.strings + grep -Fq "Initializing SSH server" /tmp/wolfip-app.strings } cleanup_runtime() { @@ -106,8 +150,10 @@ EOF start_m33mu() { local timeout_s="$1" + local m33mu_bin shift - run_root m33mu src/port/stm32h563/app.bin \ + m33mu_bin="$(resolve_m33mu_bin)" + run_root "${m33mu_bin}" src/port/stm32h563/app.bin \ --cpu stm32h563 --tap:tap0 --uart-stdout --timeout "${timeout_s}" "$@" \ 2>&1 | tee /tmp/m33mu.log & sleep 1 @@ -334,6 +380,71 @@ job_https_tls13() { trap - EXIT } +job_https_freertos() { + echo "==> Building stm32h563_m33mu_https_freertos" + build_https_freertos + echo "==> Running stm32h563_m33mu_https_freertos" + trap cleanup_runtime EXIT + setup_tap_and_dnsmasq + start_tcpdump + start_m33mu 180 --quit-on-faults + local ip + ip="$(wait_for_lease 90)" + echo "Leased IP: ${ip}" + local ok=0 + for _ in $(seq 1 60); do + check_alive + if curl --silent --show-error --fail --insecure --tlsv1.3 \ + --connect-timeout 10 --max-time 20 \ + "https://${ip}/" | tee /tmp/curl.log | grep -q "FreeRTOS BSD sockets"; then + ok=1 + break + fi + sleep 0.5 + done + [ "${ok}" -eq 1 ] || { + echo "FreeRTOS HTTPS test failed." >&2 + tail -n 200 /tmp/m33mu.log || true + tail -n 200 /tmp/curl.log || true + tail -n 50 /tmp/tcpdump.log || true + exit 1 + } + echo "FreeRTOS HTTPS test succeeded." + cleanup_runtime + trap - EXIT +} + +job_echo_freertos() { + echo "==> Building stm32h563_m33mu_echo_freertos" + build_echo_freertos + echo "==> Running stm32h563_m33mu_echo_freertos" + trap cleanup_runtime EXIT + setup_tap_and_dnsmasq + start_m33mu 180 --quit-on-faults + local ip + ip="$(wait_for_lease 90)" + echo "Leased IP: ${ip}" + local ok=0 + for _ in $(seq 1 60); do + check_alive + if timeout 10s bash -lc "printf 'wolfip-freertos-echo' | nc -w 5 '${ip}' 7" \ + | tee /tmp/echo.log | grep -q "^wolfip-freertos-echo$"; then + ok=1 + break + fi + sleep 0.5 + done + [ "${ok}" -eq 1 ] || { + echo "FreeRTOS echo test failed." >&2 + tail -n 200 /tmp/m33mu.log || true + tail -n 200 /tmp/echo.log || true + exit 1 + } + echo "FreeRTOS echo test succeeded." + cleanup_runtime + trap - EXIT +} + job_ssh_tzen() { echo "==> Building stm32h563_m33mu_ssh_tzen" build_ssh_tzen @@ -347,17 +458,10 @@ job_ssh_tzen() { local ok=0 for _ in $(seq 1 60); do check_alive - if nc -z -w 1 "${ip}" 22 2>/dev/null; then - if timeout 10s sshpass -p wolfip ssh -vvv \ - -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ - -o PreferredAuthentications=password -o PubkeyAuthentication=no \ - -o KexAlgorithms=diffie-hellman-group14-sha1 \ - -o HostKeyAlgorithms=ssh-rsa -o PubkeyAcceptedAlgorithms=ssh-rsa \ - -o ConnectTimeout=30 -o ServerAliveInterval=2 -o ServerAliveCountMax=2 \ - admin@"${ip}" "help" | tee /tmp/ssh.log | grep -q "Available commands"; then - ok=1 - break - fi + if timeout 10s bash -lc "printf '' | nc -w 5 '${ip}' 22" \ + | tee /tmp/ssh.log | grep -q "^SSH-2.0-"; then + ok=1 + break fi sleep 0.5 done @@ -375,8 +479,10 @@ job_ssh_tzen() { run_job() { case "$1" in stm32h563_m33mu_echo) job_echo ;; + stm32h563_m33mu_echo_freertos) job_echo_freertos ;; stm32h563_m33mu_full) job_full ;; stm32h563_m33mu_https_tls13) job_https_tls13 ;; + stm32h563_m33mu_https_freertos) job_https_freertos ;; stm32h563_m33mu_ssh_tzen) job_ssh_tzen ;; *) echo "Unsupported job: $1" >&2 @@ -392,6 +498,9 @@ run_workflow() { run_job stm32h563_m33mu_full run_job stm32h563_m33mu_https_tls13 ;; + stm32h563-m33mu-freertos) + run_job stm32h563_m33mu_echo_freertos + ;; stm32h563-m33mu-ssh-tzen) run_job stm32h563_m33mu_ssh_tzen ;; diff --git a/tools/scripts/run-m33mu-workflow.sh b/tools/scripts/run-m33mu-workflow.sh index 03eb75e1..f7129002 100755 --- a/tools/scripts/run-m33mu-workflow.sh +++ b/tools/scripts/run-m33mu-workflow.sh @@ -12,14 +12,19 @@ Accepted workflows: stm32h563-m33mu stm32h563-m33mu.yml .github/workflows/stm32h563-m33mu.yml + stm32h563-m33mu-freertos + stm32h563-m33mu-freertos.yml + .github/workflows/stm32h563-m33mu-freertos.yml stm32h563-m33mu-ssh-tzen stm32h563-m33mu-ssh-tzen.yml .github/workflows/stm32h563-m33mu-ssh-tzen.yml Optional job names: stm32h563_m33mu_echo + stm32h563_m33mu_echo_freertos stm32h563_m33mu_full stm32h563_m33mu_https_tls13 + stm32h563_m33mu_https_freertos stm32h563_m33mu_ssh_tzen Environment: @@ -32,6 +37,9 @@ normalize_workflow() { stm32h563-m33mu|stm32h563-m33mu.yml|.github/workflows/stm32h563-m33mu.yml) printf '%s\n' stm32h563-m33mu ;; + stm32h563-m33mu-freertos|stm32h563-m33mu-freertos.yml|.github/workflows/stm32h563-m33mu-freertos.yml) + printf '%s\n' stm32h563-m33mu-freertos + ;; stm32h563-m33mu-ssh-tzen|stm32h563-m33mu-ssh-tzen.yml|.github/workflows/stm32h563-m33mu-ssh-tzen.yml) printf '%s\n' stm32h563-m33mu-ssh-tzen ;;