From 32f5f616199d04e3ae349d01a74ac8e60fd19b46 Mon Sep 17 00:00:00 2001 From: Harinath Nampally Date: Tue, 30 Dec 2025 23:00:34 -0500 Subject: [PATCH 1/4] port for RP2350 --- examples/pico/CMakeLists.txt | 35 ++ examples/pico/README.md | 66 ++++ examples/pico/pico2_demo_dual.c | 222 ++++++++++++ port/pico/pico2_transport_shm.c | 586 ++++++++++++++++++++++++++++++++ port/pico/pico2_transport_shm.h | 250 ++++++++++++++ 5 files changed, 1159 insertions(+) create mode 100644 examples/pico/CMakeLists.txt create mode 100644 examples/pico/README.md create mode 100644 examples/pico/pico2_demo_dual.c create mode 100644 port/pico/pico2_transport_shm.c create mode 100644 port/pico/pico2_transport_shm.h diff --git a/examples/pico/CMakeLists.txt b/examples/pico/CMakeLists.txt new file mode 100644 index 00000000..c66c3934 --- /dev/null +++ b/examples/pico/CMakeLists.txt @@ -0,0 +1,35 @@ +add_executable(pico2_demo_dual + pico2_demo_dual.c + ../../port/pico/pico2_transport_shm.c +) + +target_link_libraries(pico2_demo_dual + wolfssl + wolfhsm + pico_stdlib + pico_multicore +) + +target_compile_definitions(pico2_demo_dual PRIVATE + WOLFSSL_USER_SETTINGS + WOLFHSM_CFG_ENABLE_CLIENT + WOLFHSM_CFG_ENABLE_SERVER +) + +target_include_directories(pico2_demo_dual PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/config + ${CMAKE_SOURCE_DIR}/wolfHSM + ${CMAKE_SOURCE_DIR}/wolfHSM/wolfhsm + ${CMAKE_SOURCE_DIR}/wolfHSM/port/pico +) + +if (USE_UART) +pico_enable_stdio_usb(pico2_demo_dual 0) +pico_enable_stdio_uart(pico2_demo_dual 1) +else() +pico_enable_stdio_usb(pico2_demo_dual 1) +pico_enable_stdio_uart(pico2_demo_dual 0) +endif() + +pico_add_extra_outputs(pico2_demo_dual) diff --git a/examples/pico/README.md b/examples/pico/README.md new file mode 100644 index 00000000..e191aa25 --- /dev/null +++ b/examples/pico/README.md @@ -0,0 +1,66 @@ +# Pico-2 Dual-Core Echo Demo + +## Overview + +This demo shows dual-core communication using wolfHSM on the Raspberry Pi Pico-2: +- **Core 0**: Runs the wolfHSM server, receives requests and echoes responses +- **Core 1**: Runs the wolfHSM client, sends test messages and displays echoed responses + +## How It Works + +1. Core 0 initializes shared memory and starts the server +2. Core 1 connects to the shared memory transport and sends requests +3. Server receives "Hello from Core 1" and responds with "Echo: Hello from Core 1" +4. Client receives 5 additional echoed requests in a loop + +## Shared Memory Layout + +``` +Header (32 bytes) - Initialization flags and metadata +Request Buffer - 1KB, client to server +Response Buffer - 1KB, server to client +``` + +## Building + +```bash +cmake -S . -B build -G "Ninja" -DPICO_SDK_PATH=/path/to/pico-sdk -DBUILD_PICO2_DEMOS=ON +ninja -C build pico2_demo_dual +``` + +The UF2 file will be at `build/lib/pico2_demo_dual.uf2`. + +## Configuration + +Edit these values in `pico2_demo_dual.c` if needed: + +```c +#define SHARED_MEM_SIZE (4 * 1024) // Total shared memory +#define REQ_SIZE 1024 // Request buffer size +#define RESP_SIZE 1024 // Response buffer size +``` + +## Output + +Expected serial output: + +``` +=== Pico-2 Dual-Core wolfHSM Demo === +Shared memory @0x20040000 size 4096 +Server running on Core 0, client on Core 1 +Server handled message 1 +Server handled message 2 +... +Server handled message 6 +Client received response 0: Echo: Hello from Core 1 +Client received response 1: Echo: Request 0 from Core 1 +... +``` + +## Requirements + +- Raspberry Pi Pico-2 board +- Pico SDK 2.2.0+ +- wolfSSL and wolfHSM libraries +- ARM GCC toolchain + diff --git a/examples/pico/pico2_demo_dual.c b/examples/pico/pico2_demo_dual.c new file mode 100644 index 00000000..d9d7e852 --- /dev/null +++ b/examples/pico/pico2_demo_dual.c @@ -0,0 +1,222 @@ +/* + * Combined dual-core demo: server on Core 0, client on Core 1. + */ +#include +#include +#include "pico/stdlib.h" +#include "pico/multicore.h" + +#include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_server.h" +#include "wolfhsm/wh_client.h" +#include "pico2_transport_shm.h" + +#define SHARED_MEM_SIZE (4 * 1024) +__attribute__((section(".shared_ram"))) +static uint8_t pico2_shared_mem[SHARED_MEM_SIZE]; +static size_t pico2_shared_mem_size = SHARED_MEM_SIZE; + +#define SERVER_ID 1 +#define CLIENT_ID 2 +#define REQ_SIZE 1024 +#define RESP_SIZE 1024 +#define DMA_SIZE 1024 + +static int server_init(whCommServer *server, pico2TransportShmContext *ctx) +{ + static const whTransportServerCb server_cb = PICO2_TRANSPORT_SHM_SERVER_CB; + memset(ctx, 0, sizeof(*ctx)); + pico2TransportShmConfig cfg = { + .req_size = REQ_SIZE, + .resp_size = RESP_SIZE, + .dma_size = DMA_SIZE, + .shared_mem = pico2_shared_mem, + .shared_mem_size = pico2_shared_mem_size, + }; + whCommServerConfig scfg = { + .transport_cb = &server_cb, + .transport_context = ctx, + .transport_config = &cfg, + .server_id = SERVER_ID, + }; + int rc = wh_CommServer_Init(server, &scfg, NULL, NULL); + if (rc != WH_ERROR_OK) { + printf("ERROR: server init failed (rc=%d)\n", rc); + return rc; + } + return 0; +} + +static int server_handle_message(whCommServer *server, int *handled) +{ + uint8_t req_data[256]; + uint8_t resp_data[256]; + uint16_t resp_len = 0; + uint16_t magic = 0, kind = 0, seq = 0, req_len = 0; + int rc = wh_CommServer_RecvRequest(server, &magic, &kind, &seq, &req_len, req_data); + if (rc == WH_ERROR_NOTREADY) { + return 0; + } + if (rc != WH_ERROR_OK) { + printf("ERROR: recv request rc=%d\n", rc); + return rc; + } + memcpy(resp_data, "Echo: ", 6); + resp_len = 6; + if (req_len < sizeof(resp_data) - 6) { + memcpy(&resp_data[6], req_data, req_len); + resp_len += req_len; + } + rc = wh_CommServer_SendResponse(server, magic, kind, seq, resp_len, resp_data); + if (rc != WH_ERROR_OK) { + printf("ERROR: send response rc=%d\n", rc); + return rc; + } + (*handled)++; + printf("Server handled message %d\n", *handled); + return 0; +} + +static int client_init(whCommClient *client, pico2TransportShmContext *ctx) +{ + static const whTransportClientCb client_cb = PICO2_TRANSPORT_SHM_CLIENT_CB; + memset(ctx, 0, sizeof(*ctx)); + pico2TransportShmConfig cfg = { + .req_size = REQ_SIZE, + .resp_size = RESP_SIZE, + .dma_size = DMA_SIZE, + .shared_mem = pico2_shared_mem, + .shared_mem_size = pico2_shared_mem_size, + }; + whCommClientConfig ccfg = { + .transport_cb = &client_cb, + .transport_context = ctx, + .transport_config = &cfg, + .client_id = CLIENT_ID, + }; + int rc = wh_CommClient_Init(client, &ccfg); + if (rc != WH_ERROR_OK) { + printf("ERROR: client init failed (rc=%d)\n", rc); + return rc; + } + printf("Client initialized rc = %d\n", rc); + return 0; +} + +static int client_send_requests(whCommClient *client) +{ + uint8_t req[128]; + uint8_t resp[128]; + uint16_t resp_len = 128; + uint16_t magic = 0x1234; + uint16_t kind = 0; + uint16_t seq = 0; + int rc; + + memcpy(req, "Hello from Core 1", 17); + printf("Client sending first request\n"); + do { + rc = wh_CommClient_SendRequest(client, magic, kind, &seq, 17, req); + if (rc == WH_ERROR_NOTREADY) { + sleep_ms(1); + } + } while (rc == WH_ERROR_NOTREADY); + if (rc != WH_ERROR_OK) { + printf("ERROR: send request rc=%d\n", rc); + return rc; + } + printf("Client waiting for first response\n"); + do { + rc = wh_CommClient_RecvResponse(client, &magic, &kind, &seq, &resp_len, resp); + if (rc == WH_ERROR_NOTREADY) { + sleep_ms(1); + } + } while (rc == WH_ERROR_NOTREADY); + if (rc != WH_ERROR_OK) { + printf("ERROR: recv response rc=%d\n", rc); + return rc; + } + for (int i = 0; i < 5; i++) { + printf("Client sending request %d\n", i); + sprintf((char*)req, "Request %d from Core 1", i); + uint16_t req_len = strlen((char*)req); + do { + rc = wh_CommClient_SendRequest(client, magic, kind, &seq, req_len, req); + if (rc == WH_ERROR_NOTREADY) { + sleep_ms(1); + } + } while (rc == WH_ERROR_NOTREADY); + if (rc != WH_ERROR_OK) { + printf("ERROR: send request rc=%d\n", rc); + return rc; + } + resp_len = 128; + do { + rc = wh_CommClient_RecvResponse(client, &magic, &kind, &seq, &resp_len, resp); + if (rc == WH_ERROR_NOTREADY) { + sleep_ms(1); + } + } while (rc == WH_ERROR_NOTREADY); + if (rc != WH_ERROR_OK) { + printf("ERROR: recv response rc=%d\n", rc); + return rc; + } + sleep_ms(2000); + printf("Client received response %d: %.*s\n", i, resp_len, resp); + } + return 0; +} + +static void core1_entry(void) +{ + whCommClient client[1]; + pico2TransportShmContext ctx[1]; + sleep_ms(5000); + printf("\n=== Core 1: Client start ===\n"); + if (client_init(client, ctx) != 0) { + printf("Client init failed\n"); + multicore_fifo_push_blocking(0xDEAD0001); + return; + } + sleep_ms(500); + printf("Client initialized, sending requests\n"); + if (client_send_requests(client) != 0) { + printf("Client requests failed\n"); + } + pico2TransportShm_Cleanup(ctx); + multicore_fifo_push_blocking(0xC1E17E); + printf("Core 1 done\n"); +} +int main(void) +{ + whCommServer server[1]; + pico2TransportShmContext ctx[1]; + int handled = 0; + + stdio_init_all(); + sleep_ms(5000); + printf("\n=== Pico-2 Dual-Core wolfHSM Demo ===\n"); + printf("Shared memory @%p size %u\n", pico2_shared_mem, (unsigned)pico2_shared_mem_size); + + if (server_init(server, ctx) != 0) { + printf("Server init failed\n"); + return 1; + } + + multicore_launch_core1(core1_entry); + printf("Server running on Core 0, client on Core 1\n"); + + const int expected = 6; /* 1 echo + 5 looped */ + while (handled < expected) { + if (server_handle_message(server, &handled) != 0) { + printf("Server loop error\n"); + break; + } + sleep_ms(5000); + } + + pico2TransportShm_Cleanup(ctx); + multicore_fifo_pop_blocking(); /* wait for client */ + + return 0; +} diff --git a/port/pico/pico2_transport_shm.c b/port/pico/pico2_transport_shm.c new file mode 100644 index 00000000..4e0f17d7 --- /dev/null +++ b/port/pico/pico2_transport_shm.c @@ -0,0 +1,586 @@ +/* + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM 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. + * + * wolfHSM 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 wolfHSM. If not, see . + */ + +/* + * port/pico-2/pico2_transport_shm.c + * + * Implementation of transport callbacks for Raspberry Pi Pico-2 using + * shared memory between two cores. + */ + +#include +#include + +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_utils.h" +#include "wolfhsm/wh_comm.h" + +#include "pico2_transport_shm.h" + +/** Header structure for shared memory layout */ +#define PICO2_SHM_HEADER_SIZE 32 +typedef union { + struct { + uint32_t initialized; /* Set non-zero when setup complete */ + uint16_t req_size; /* Size of request buffer */ + uint16_t resp_size; /* Size of response buffer */ + size_t dma_size; /* Size of shared DMA space */ + }; + uint8_t WH_PAD[PICO2_SHM_HEADER_SIZE]; +} pico2ShmHeader; + +typedef struct { + void* ptr; + size_t size; + pico2ShmHeader* header; + uint8_t* req; + uint8_t* resp; + uint8_t* dma; + size_t dma_size; + uint16_t req_size; + uint16_t resp_size; +} pico2ShmMapping; + +enum { + PICO2_INITIALIZED_NONE = 0, + PICO2_INITIALIZED_CREATOR = 1, + PICO2_INITIALIZED_USER = 2, +}; + +/** + * @brief Initialize the header and buffers in shared memory + * + * This function calculates the layout of the shared memory region and + * initializes the header structure. + * + * @param[in] cfg Pointer to configuration structure + * @param[out] map Pointer to mapping structure to fill + * @return WH_ERROR_OK on success, or error code on failure + */ +static int pico2TransportShm_MapMemory(const pico2TransportShmConfig* cfg, + pico2ShmMapping* map) +{ + if ((cfg == NULL) || (map == NULL)) { + return WH_ERROR_BADARGS; + } + + if ((cfg->shared_mem == NULL) || (cfg->shared_mem_size == 0) || + (cfg->req_size == 0) || (cfg->resp_size == 0)) { + return WH_ERROR_BADARGS; + } + + /* Calculate required size */ + size_t required_size = PICO2_SHM_HEADER_SIZE + cfg->req_size + + cfg->resp_size + cfg->dma_size; + + if (cfg->shared_mem_size < required_size) { + return WH_ERROR_BADARGS; + } + + memset(map, 0, sizeof(*map)); + + /* Set up the mapping */ + map->ptr = (void*)cfg->shared_mem; + map->size = cfg->shared_mem_size; + map->header = (pico2ShmHeader*)map->ptr; + map->req = (uint8_t*)(map->header + 1); + map->resp = map->req + cfg->req_size; + map->dma = map->resp + cfg->resp_size; + map->dma_size = cfg->dma_size; + map->req_size = cfg->req_size; + map->resp_size = cfg->resp_size; + + return WH_ERROR_OK; +} + +/** Core synchronization primitives for Pico-2 */ + +/** + * @brief Memory barrier to ensure memory operations are visible across cores + * + * This is a simple implementation using volatile access and inline assembly. + * For Pico-2, we use a compiler barrier and optional hardware fence. + */ +static inline void pico2TransportShm_MemoryBarrier(void) +{ + /* Compiler barrier */ + asm volatile("" : : : "memory"); + + #ifdef WOLFHSM_CFG_PICO2_DMB + /* Optional data memory barrier for strict ordering */ + asm volatile("dmb" : : : "memory"); + #endif +} + +/** + * @brief Flush a region from cache (if applicable) + * + * On Pico-2, this is a no-op for non-cached memory, but included for + * compatibility with other ports. + */ +static inline void pico2TransportShm_CacheFlush(void* ptr, size_t len) +{ + (void)ptr; + (void)len; + /* Pico-2 cores typically don't have separate caches for shared SRAM */ +} + +/** + * @brief Invalidate cache for a region (if applicable) + * + * On Pico-2, this is a no-op for non-cached memory, but included for + * compatibility with other ports. + */ +static inline void pico2TransportShm_CacheInvalidate(void* ptr, size_t len) +{ + (void)ptr; + (void)len; + /* Pico-2 cores typically don't have separate caches for shared SRAM */ +} + +#if defined(WOLFHSM_CFG_ENABLE_SERVER) + +/** + * @brief Server initialization - creates the shared memory layout + * + * @param[in] c Pointer to the transport context + * @param[in] cf Pointer to the configuration structure + * @param[in] connectcb Connection callback (optional) + * @param[in] connectcb_arg Argument for connection callback + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_ServerInit(void* c, const void* cf, + whCommSetConnectedCb connectcb, + void* connectcb_arg) +{ + int ret = WH_ERROR_OK; + pico2TransportShmContext* ctx = (pico2TransportShmContext*)c; + const pico2TransportShmConfig* cfg = (const pico2TransportShmConfig*)cf; + pico2ShmMapping map[1] = {0}; + whTransportMemConfig tmcfg[1] = {0}; + + if ((ctx == NULL) || (cfg == NULL)) { + return WH_ERROR_BADARGS; + } + + /* Map the shared memory */ + ret = pico2TransportShm_MapMemory(cfg, map); + if (ret != WH_ERROR_OK) { + return ret; + } + + /* Initialize and clear the buffers */ + memset(map->header, 0, PICO2_SHM_HEADER_SIZE); + memset(map->req, 0, cfg->req_size); + memset(map->resp, 0, cfg->resp_size); + if (cfg->dma_size > 0) { + memset(map->dma, 0, cfg->dma_size); + } + + /* Set up the header */ + map->header->req_size = cfg->req_size; + map->header->resp_size = cfg->resp_size; + map->header->dma_size = cfg->dma_size; + pico2TransportShm_MemoryBarrier(); + map->header->initialized = PICO2_INITIALIZED_CREATOR; + + /* Configure the underlying transport context */ + tmcfg->req = map->req; + tmcfg->req_size = cfg->req_size; + tmcfg->resp = map->resp; + tmcfg->resp_size = cfg->resp_size; + + /* Initialize the shared memory transport */ + ret = wh_TransportMem_Init(ctx->transportMemCtx, tmcfg, NULL, NULL); + if (ret == WH_ERROR_OK) { + ctx->state = PICO2_SHM_STATE_INITIALIZED; + ctx->shared_mem = cfg->shared_mem; + ctx->shared_mem_size = cfg->shared_mem_size; + ctx->req = map->req; + ctx->resp = map->resp; + ctx->dma = map->dma; + ctx->dma_size = cfg->dma_size; + ctx->req_size = cfg->req_size; + ctx->resp_size = cfg->resp_size; + ctx->connectcb = connectcb; + ctx->connectcb_arg = connectcb_arg; + + /* Signal connection if callback is provided */ + if (connectcb != NULL) { + connectcb(connectcb_arg, WH_COMM_CONNECTED); + } + } + + return ret; +} + +#endif /* WOLFHSM_CFG_ENABLE_SERVER */ + +#if defined(WOLFHSM_CFG_ENABLE_CLIENT) + +/** + * @brief Client initialization - connects to existing shared memory + * + * The client waits for the server to initialize the shared memory layout. + * + * @param[in] c Pointer to the transport context + * @param[in] cf Pointer to the configuration structure + * @param[in] connectcb Connection callback (optional) + * @param[in] connectcb_arg Argument for connection callback + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_ClientInit(void* c, const void* cf, + whCommSetConnectedCb connectcb, + void* connectcb_arg) +{ + int ret = WH_ERROR_OK; + pico2TransportShmContext* ctx = (pico2TransportShmContext*)c; + const pico2TransportShmConfig* cfg = (const pico2TransportShmConfig*)cf; + pico2ShmMapping map[1] = {0}; + whTransportMemConfig tmcfg[1] = {0}; + uint32_t max_retries = 10000; /* Allow time for server to initialize */ + uint32_t retry_count = 0; + + if ((ctx == NULL) || (cfg == NULL)) { + return WH_ERROR_BADARGS; + } + + /* Map the shared memory */ + ret = pico2TransportShm_MapMemory(cfg, map); + if (ret != WH_ERROR_OK) { + return ret; + } + + /* Wait for server to initialize */ + while ((map->header->initialized != PICO2_INITIALIZED_CREATOR) && + (retry_count < max_retries)) { + retry_count++; + pico2TransportShm_MemoryBarrier(); + } + + if (map->header->initialized != PICO2_INITIALIZED_CREATOR) { + return WH_ERROR_NOTREADY; + } + + /* Configure the underlying transport context */ + tmcfg->req = map->req; + tmcfg->req_size = map->header->req_size; + tmcfg->resp = map->resp; + tmcfg->resp_size = map->header->resp_size; + + /* Initialize the shared memory transport with clear */ + ret = wh_TransportMem_InitClear(ctx->transportMemCtx, tmcfg, NULL, NULL); + if (ret == WH_ERROR_OK) { + ctx->state = PICO2_SHM_STATE_INITIALIZED; + ctx->shared_mem = cfg->shared_mem; + ctx->shared_mem_size = cfg->shared_mem_size; + ctx->req = map->req; + ctx->resp = map->resp; + ctx->dma = map->dma; + ctx->dma_size = map->header->dma_size; + ctx->req_size = map->header->req_size; + ctx->resp_size = map->header->resp_size; + ctx->connectcb = connectcb; + ctx->connectcb_arg = connectcb_arg; + + /* Mark as user initialized */ + pico2TransportShm_MemoryBarrier(); + map->header->initialized = PICO2_INITIALIZED_USER; + + /* Signal connection if callback is provided */ + if (connectcb != NULL) { + connectcb(connectcb_arg, WH_COMM_CONNECTED); + } + } + + return ret; +} + +#endif /* WOLFHSM_CFG_ENABLE_CLIENT */ + +/** + * @brief Cleanup the transport context + * + * @param[in] c Pointer to the transport context + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_Cleanup(void* c) +{ + pico2TransportShmContext* ctx = (pico2TransportShmContext*)c; + + if (ctx == NULL) { + return WH_ERROR_BADARGS; + } + + /* Clean up the underlying transport context */ + (void)wh_TransportMem_Cleanup(ctx->transportMemCtx); + + ctx->state = PICO2_SHM_STATE_DONE; + + return WH_ERROR_OK; +} + +#if defined(WOLFHSM_CFG_ENABLE_CLIENT) + +/** + * @brief Send a request from client to server + * + * @param[in] c Pointer to the transport context + * @param[in] len Length of the request data + * @param[in] data Pointer to the request data + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_SendRequest(void* c, uint16_t len, const void* data) +{ + pico2TransportShmContext* ctx = (pico2TransportShmContext*)c; + + if ((ctx == NULL) || (ctx->state != PICO2_SHM_STATE_INITIALIZED)) { + return WH_ERROR_BADARGS; + } + + /* Ensure memory operations are visible to the server */ + pico2TransportShm_MemoryBarrier(); + + return wh_TransportMem_SendRequest(ctx->transportMemCtx, len, data); +} + +/** + * @brief Receive a response from server to client + * + * @param[in] c Pointer to the transport context + * @param[out] out_len Pointer to store the response length + * @param[out] data Pointer to store the response data + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_RecvResponse(void* c, uint16_t* out_len, void* data) +{ + pico2TransportShmContext* ctx = (pico2TransportShmContext*)c; + + if ((ctx == NULL) || (ctx->state != PICO2_SHM_STATE_INITIALIZED)) { + return WH_ERROR_BADARGS; + } + + /* Ensure we see updates from the server */ + pico2TransportShm_CacheInvalidate(ctx->resp, ctx->resp_size); + pico2TransportShm_MemoryBarrier(); + + return wh_TransportMem_RecvResponse(ctx->transportMemCtx, out_len, data); +} + +#endif /* WOLFHSM_CFG_ENABLE_CLIENT */ + +#if defined(WOLFHSM_CFG_ENABLE_SERVER) + +/** + * @brief Receive a request from client on server + * + * @param[in] c Pointer to the transport context + * @param[out] out_len Pointer to store the request length + * @param[out] data Pointer to store the request data + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_RecvRequest(void* c, uint16_t* out_len, void* data) +{ + pico2TransportShmContext* ctx = (pico2TransportShmContext*)c; + + if ((ctx == NULL) || (ctx->state != PICO2_SHM_STATE_INITIALIZED)) { + return WH_ERROR_BADARGS; + } + + /* Ensure we see updates from the client */ + pico2TransportShm_CacheInvalidate(ctx->req, ctx->req_size); + pico2TransportShm_MemoryBarrier(); + + return wh_TransportMem_RecvRequest(ctx->transportMemCtx, out_len, data); +} + +/** + * @brief Send a response from server to client + * + * @param[in] c Pointer to the transport context + * @param[in] len Length of the response data + * @param[in] data Pointer to the response data + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_SendResponse(void* c, uint16_t len, const void* data) +{ + pico2TransportShmContext* ctx = (pico2TransportShmContext*)c; + + if ((ctx == NULL) || (ctx->state != PICO2_SHM_STATE_INITIALIZED)) { + return WH_ERROR_BADARGS; + } + + /* Ensure memory operations are visible to the client */ + pico2TransportShm_CacheFlush(ctx->resp, ctx->resp_size); + pico2TransportShm_MemoryBarrier(); + + return wh_TransportMem_SendResponse(ctx->transportMemCtx, len, data); +} + +#endif /* WOLFHSM_CFG_ENABLE_SERVER */ + +/** + * @brief Get DMA buffer information + * + * @param[in] ctx Pointer to the transport context + * @param[out] out_dma Pointer to store DMA buffer address + * @param[out] out_size Pointer to store DMA buffer size + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_GetDma(pico2TransportShmContext* ctx, + void* *out_dma, size_t *out_size) +{ + if ((ctx == NULL) || (out_dma == NULL) || (out_size == NULL)) { + return WH_ERROR_BADARGS; + } + + *out_dma = ctx->dma; + *out_size = ctx->dma_size; + + return WH_ERROR_OK; +} + +/** + * @brief Set heap hint for DMA operations + * + * @param[in] ctx Pointer to the transport context + * @param[in] heap Pointer to the heap hint + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_SetDmaHeap(pico2TransportShmContext* ctx, void* heap) +{ + if (ctx == NULL) { + return WH_ERROR_BADARGS; + } + + ctx->heap = heap; + return WH_ERROR_OK; +} + +/** + * @brief Get heap hint for DMA operations + * + * @param[in] ctx Pointer to the transport context + * @return Pointer to the heap hint or NULL + */ +void* pico2TransportShm_GetDmaHeap(pico2TransportShmContext* ctx) +{ + if (ctx == NULL) { + return NULL; + } + + return ctx->heap; +} + +/** DMA callback implementations */ +#ifdef WOLFHSM_CFG_DMA + +#include "wolfhsm/wh_dma.h" +#include "wolfhsm/wh_server.h" +#include "wolfhsm/wh_client.h" + +/** + * @brief Server DMA callback for static shared memory + * + * @param[in] server Pointer to server context + * @param[in] clientAddr Client address for DMA operation + * @param[out] xformedCliAddr Transformed client address + * @param[in] len Length of data for DMA operation + * @param[in] oper DMA operation type + * @param[in] flags DMA operation flags + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_ServerStaticMemDmaCallback( + whServerContext* server, uintptr_t clientAddr, void** xformedCliAddr, + size_t len, whServerDmaOper oper, whServerDmaFlags flags) +{ + pico2TransportShmContext* ctx = NULL; + + (void)oper; + (void)flags; + + if ((server == NULL) || (xformedCliAddr == NULL)) { + return WH_ERROR_BADARGS; + } + + /* Get transport context from server */ + ctx = (pico2TransportShmContext*)server->transport_context; + + if ((ctx == NULL) || (ctx->dma == NULL) || (ctx->dma_size == 0)) { + return WH_ERROR_BADARGS; + } + + /* Verify the address is within DMA buffer */ + if ((clientAddr < (uintptr_t)ctx->dma) || + ((clientAddr + len) > ((uintptr_t)ctx->dma + ctx->dma_size))) { + return WH_ERROR_BADARGS; + } + + /* Address is already in shared memory, no transformation needed */ + *xformedCliAddr = (void*)clientAddr; + + return WH_ERROR_OK; +} + +/** + * @brief Client DMA callback for static shared memory + * + * @param[in] client Pointer to client context + * @param[in] clientAddr Client address for DMA operation + * @param[out] xformedCliAddr Transformed client address + * @param[in] len Length of data for DMA operation + * @param[in] oper DMA operation type + * @param[in] flags DMA operation flags + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_ClientStaticMemDmaCallback(whClientContext* client, + uintptr_t clientAddr, + void** xformedCliAddr, + size_t len, whDmaOper oper, + whDmaFlags flags) +{ + pico2TransportShmContext* ctx = NULL; + + (void)oper; + (void)flags; + + if ((client == NULL) || (xformedCliAddr == NULL)) { + return WH_ERROR_BADARGS; + } + + /* Get transport context from client */ + ctx = (pico2TransportShmContext*)client->transport_context; + + if ((ctx == NULL) || (ctx->dma == NULL) || (ctx->dma_size == 0)) { + return WH_ERROR_BADARGS; + } + + /* Verify the address is within DMA buffer */ + if ((clientAddr < (uintptr_t)ctx->dma) || + ((clientAddr + len) > ((uintptr_t)ctx->dma + ctx->dma_size))) { + return WH_ERROR_BADARGS; + } + + /* Address is already in shared memory, no transformation needed */ + *xformedCliAddr = (void*)clientAddr; + + return WH_ERROR_OK; +} + +#endif /* WOLFHSM_CFG_DMA */ diff --git a/port/pico/pico2_transport_shm.h b/port/pico/pico2_transport_shm.h new file mode 100644 index 00000000..edd90823 --- /dev/null +++ b/port/pico/pico2_transport_shm.h @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM 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. + * + * wolfHSM 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 wolfHSM. If not, see . + */ + +/* + * port/pico-2/pico2_transport_shm.h + * + * wolfHSM Transport Mem binding using Raspberry Pi Pico-2 shared memory + * + * For this implementation, shared memory is accessed between two cores on the + * Pico-2 microcontroller. Each core has access to the same RAM regions. The + * server (typically Core 0) creates the shared memory buffers and the client + * (typically Core 1) connects to them. + * + * The implementation uses a header structure to store configuration and + * synchronization information, followed by request and response buffers. + * Optionally, a DMA section can be allocated for DMA operations. + * + * Core-to-core synchronization is handled through simple spinlock mechanisms + * and memory barriers to ensure coherence between cores. + */ + +#ifndef PORT_PICO2_PICO2_TRANSPORT_SHM_H_ +#define PORT_PICO2_PICO2_TRANSPORT_SHM_H_ + +#include +#include + +#include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_transport_mem.h" + +/** Pico-2 SHM configuration structure */ +typedef struct { + uint16_t req_size; /* Request buffer size */ + uint16_t resp_size; /* Response buffer size */ + size_t dma_size; /* DMA buffer size (optional) */ + void* shared_mem; /* Base address of shared memory region */ + size_t shared_mem_size; /* Total size of shared memory region */ +} pico2TransportShmConfig; + +/** Pico-2 SHM context state */ +typedef enum { + PICO2_SHM_STATE_NONE = 0, /* Not initialized */ + PICO2_SHM_STATE_INITIALIZED, /* Initialized and ready */ + PICO2_SHM_STATE_DONE, /* Cleanup complete */ +} pico2TransportShmState; + +/** Pico-2 SHM context */ +typedef struct { + pico2TransportShmState state; + void* shared_mem; + size_t shared_mem_size; + uint8_t* req; + uint8_t* resp; + uint8_t* dma; + size_t dma_size; + uint16_t req_size; + uint16_t resp_size; + whTransportMemContext transportMemCtx[1]; + whCommSetConnectedCb connectcb; + void* connectcb_arg; + void* heap; /* heap hint used in pass by reference */ +} pico2TransportShmContext; + +/** Type aliases for client and server contexts */ +typedef pico2TransportShmContext pico2TransportShmClientContext; +typedef pico2TransportShmContext pico2TransportShmServerContext; + +/** Custom getter functions */ + +/** + * @brief Get DMA buffer information from context + * + * @param[in] ctx Pointer to the transport context. + * @param[out] out_dma Pointer to store DMA buffer address + * @param[out] out_size Pointer to store DMA buffer size + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_GetDma(pico2TransportShmContext* ctx, + void* *out_dma, size_t *out_size); + +/** + * @brief Set heap hint for DMA operations + * + * @param[in] ctx Pointer to the transport context. + * @param[in] heap Pointer to the heap hint + * @return WH_ERROR_OK on success, or WH_ERROR_BADARGS on error + */ +int pico2TransportShm_SetDmaHeap(pico2TransportShmContext* ctx, void* heap); + +/** + * @brief Get heap hint for DMA operations + * + * @param[in] ctx Pointer to the transport context. + * @return Pointer to the heap hint or NULL + */ +void* pico2TransportShm_GetDmaHeap(pico2TransportShmContext* ctx); + +/** Transport callback function declarations */ + +/** + * @brief Client initialization callback + * + * @param[in] c Pointer to the transport context. + * @param[in] cf Pointer to the transport configuration. + * @param[in] connectcb Connection callback function (optional). + * @param[in] connectcb_arg Argument for connection callback. + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_ClientInit(void* c, const void* cf, + whCommSetConnectedCb connectcb, + void* connectcb_arg); + +/** + * @brief Server initialization callback + * + * @param[in] c Pointer to the transport context. + * @param[in] cf Pointer to the transport configuration. + * @param[in] connectcb Connection callback function (optional). + * @param[in] connectcb_arg Argument for connection callback. + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_ServerInit(void* c, const void* cf, + whCommSetConnectedCb connectcb, + void* connectcb_arg); + +/** + * @brief Cleanup callback + * + * @param[in] c Pointer to the transport context. + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_Cleanup(void* c); + +/** + * @brief Send request callback + * + * @param[in] c Pointer to the transport context. + * @param[in] len Length of the request data. + * @param[in] data Pointer to the request data. + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_SendRequest(void* c, uint16_t len, const void* data); + +/** + * @brief Receive request callback + * + * @param[in] c Pointer to the transport context. + * @param[out] out_len Pointer to store the received data length. + * @param[out] data Pointer to store the received data. + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_RecvRequest(void* c, uint16_t* out_len, void* data); + +/** + * @brief Send response callback + * + * @param[in] c Pointer to the transport context. + * @param[in] len Length of the response data. + * @param[in] data Pointer to the response data. + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_SendResponse(void* c, uint16_t len, const void* data); + +/** + * @brief Receive response callback + * + * @param[in] c Pointer to the transport context. + * @param[out] out_len Pointer to store the received data length. + * @param[out] data Pointer to store the received data. + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_RecvResponse(void* c, uint16_t* out_len, void* data); + +/** Callback macros for client and server configurations */ + +#define PICO2_TRANSPORT_SHM_CLIENT_CB \ + { \ + .Init = pico2TransportShm_ClientInit, \ + .Send = pico2TransportShm_SendRequest, \ + .Recv = pico2TransportShm_RecvResponse, \ + .Cleanup = pico2TransportShm_Cleanup, \ + } + +#define PICO2_TRANSPORT_SHM_SERVER_CB \ + { \ + .Init = pico2TransportShm_ServerInit, \ + .Recv = pico2TransportShm_RecvRequest, \ + .Send = pico2TransportShm_SendResponse, \ + .Cleanup = pico2TransportShm_Cleanup, \ + } + +/** DMA callback support */ +#ifdef WOLFHSM_CFG_DMA + +#include "wolfhsm/wh_dma.h" +#include "wolfhsm/wh_server.h" + +/** + * @brief Server DMA callback using static shared memory + * + * @param[in] server Pointer to server context. + * @param[in] clientAddr Client address for DMA operation. + * @param[out] xformedCliAddr Transformed client address. + * @param[in] len Length of data for DMA operation. + * @param[in] oper DMA operation type. + * @param[in] flags DMA operation flags. + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_ServerStaticMemDmaCallback( + whServerContext* server, uintptr_t clientAddr, void** xformedCliAddr, + size_t len, whServerDmaOper oper, whServerDmaFlags flags); + +#include "wolfhsm/wh_client.h" + +/** + * @brief Client DMA callback using static shared memory + * + * @param[in] client Pointer to client context. + * @param[in] clientAddr Client address for DMA operation. + * @param[out] xformedCliAddr Transformed client address. + * @param[in] len Length of data for DMA operation. + * @param[in] oper DMA operation type. + * @param[in] flags DMA operation flags. + * @return WH_ERROR_OK on success, or error code on failure + */ +int pico2TransportShm_ClientStaticMemDmaCallback(whClientContext* client, + uintptr_t clientAddr, + void** xformedCliAddr, + size_t len, whDmaOper oper, + whDmaFlags flags); + +#endif /* WOLFHSM_CFG_DMA */ + +#endif /* !PORT_PICO2_PICO2_TRANSPORT_SHM_H_ */ From b22c5e2709f6d27262252b04b7ab46826ed8eedf Mon Sep 17 00:00:00 2001 From: Harinath Nampally Date: Tue, 6 Jan 2026 22:34:10 -0500 Subject: [PATCH 2/4] add build files that were missed in the previous commit --- CMakeLists.txt | 90 +++++++++++++++++++++++++ examples/pico/CMakeLists.txt | 20 +++--- examples/pico/README.md | 4 +- examples/pico/user_settings.h | 52 +++++++++++++++ pico_sdk_import.cmake | 121 ++++++++++++++++++++++++++++++++++ 5 files changed, 273 insertions(+), 14 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 examples/pico/user_settings.h create mode 100644 pico_sdk_import.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..e82654a1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,90 @@ +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0-a4) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Handle platform configuration before SDK import +if(BUILD_PICO2_DEMOS) + if(NOT DEFINED PICO_PLATFORM) + set(PICO_PLATFORM "rp2350" CACHE STRING "Pico Platform" FORCE) + elseif(PICO_PLATFORM STREQUAL "RP2350") + set(PICO_PLATFORM "rp2350" CACHE STRING "Pico Platform" FORCE) + endif() +endif() + +# Include Pico SDK import if PICO_SDK_PATH is defined +if(BUILD_PICO2_DEMOS OR DEFINED PICO_SDK_PATH OR DEFINED ENV{PICO_SDK_PATH}) + include(${CMAKE_CURRENT_SOURCE_DIR}/pico_sdk_import.cmake) + + # Force usage of Pico toolchain if we found the SDK and no toolchain was specified + if(DEFINED PICO_SDK_PATH AND NOT CMAKE_TOOLCHAIN_FILE) + set(CMAKE_TOOLCHAIN_FILE ${PICO_SDK_PATH}/cmake/preload/toolchains/pico_arm_gcc.cmake) + endif() +endif() + +project(wolfHSM C CXX ASM) + +# Initialize Pico SDK immediately after project definition +if(DEFINED PICO_SDK_PATH) + pico_sdk_init() +endif() + +# Configure wolfSSL to use user_settings.h +set(WOLFSSL_USER_SETTINGS ON CACHE BOOL "Use user settings" FORCE) +set(WOLFSSL_INSTALL OFF CACHE BOOL "Disable wolfSSL install" FORCE) + +# Disable wolfSSL tests and examples when building for Pico +if(BUILD_PICO2_DEMOS) + set(WOLFSSL_EXAMPLES OFF CACHE BOOL "Disable wolfSSL examples" FORCE) + set(WOLFSSL_CRYPT_TESTS OFF CACHE BOOL "Disable wolfSSL crypt tests" FORCE) + set(WOLFSSL_TEST OFF CACHE BOOL "Disable wolfSSL tests" FORCE) +endif() + +# Add wolfSSL subdirectory +add_subdirectory(wolfssl) + +# If building for Pico demo, point wolfSSL to the example's user_settings.h +if(BUILD_PICO2_DEMOS) + target_include_directories(wolfssl PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/examples/pico) + target_compile_definitions(wolfssl PUBLIC WOLFSSL_USER_SETTINGS) + target_link_libraries(wolfssl PUBLIC pico_stdlib) +endif() + +# Create wolfHSM library +file(GLOB WOLFHSM_SOURCES "src/*.c") +add_library(wolfhsm STATIC ${WOLFHSM_SOURCES}) + +# Include directories for wolfHSM +target_include_directories(wolfhsm PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/wolfhsm + ${CMAKE_CURRENT_SOURCE_DIR}/wolfssl +) + +# Link wolfHSM against wolfSSL +target_link_libraries(wolfhsm PUBLIC wolfssl) + +if(BUILD_PICO2_DEMOS) + target_link_libraries(wolfhsm PUBLIC pico_stdlib) +endif() + +# Add examples subdirectory if building for Pico +if(BUILD_PICO2_DEMOS) + add_subdirectory(examples/pico) +endif() diff --git a/examples/pico/CMakeLists.txt b/examples/pico/CMakeLists.txt index c66c3934..d87e8849 100644 --- a/examples/pico/CMakeLists.txt +++ b/examples/pico/CMakeLists.txt @@ -1,13 +1,12 @@ add_executable(pico2_demo_dual pico2_demo_dual.c - ../../port/pico/pico2_transport_shm.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../port/pico/pico2_transport_shm.c ) target_link_libraries(pico2_demo_dual - wolfssl - wolfhsm pico_stdlib pico_multicore + wolfhsm ) target_compile_definitions(pico2_demo_dual PRIVATE @@ -18,18 +17,15 @@ target_compile_definitions(pico2_demo_dual PRIVATE target_include_directories(pico2_demo_dual PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/config - ${CMAKE_SOURCE_DIR}/wolfHSM - ${CMAKE_SOURCE_DIR}/wolfHSM/wolfhsm - ${CMAKE_SOURCE_DIR}/wolfHSM/port/pico + ${CMAKE_CURRENT_SOURCE_DIR}/../.. + ${CMAKE_CURRENT_SOURCE_DIR}/../../wolfhsm + ${CMAKE_CURRENT_SOURCE_DIR}/../../port/pico + ${CMAKE_CURRENT_SOURCE_DIR}/../../wolfssl ) -if (USE_UART) -pico_enable_stdio_usb(pico2_demo_dual 0) -pico_enable_stdio_uart(pico2_demo_dual 1) -else() +# Enable stdio over USB only pico_enable_stdio_usb(pico2_demo_dual 1) pico_enable_stdio_uart(pico2_demo_dual 0) -endif() +# Generate UF2 file for Pico pico_add_extra_outputs(pico2_demo_dual) diff --git a/examples/pico/README.md b/examples/pico/README.md index e191aa25..6fcd5287 100644 --- a/examples/pico/README.md +++ b/examples/pico/README.md @@ -24,8 +24,8 @@ Response Buffer - 1KB, server to client ## Building ```bash -cmake -S . -B build -G "Ninja" -DPICO_SDK_PATH=/path/to/pico-sdk -DBUILD_PICO2_DEMOS=ON -ninja -C build pico2_demo_dual +cd $WOLF_HSM_DIR +mkdir -p build && cd build && cmake -GNinja -DBUILD_PICO2_DEMOS=ON -DPICO_SDK_PATH=/path/to/pico-sdk .. && ninja ``` The UF2 file will be at `build/lib/pico2_demo_dual.uf2`. diff --git a/examples/pico/user_settings.h b/examples/pico/user_settings.h new file mode 100644 index 00000000..aa99f2ee --- /dev/null +++ b/examples/pico/user_settings.h @@ -0,0 +1,52 @@ +#ifndef USER_SETTINGS_H +#define USER_SETTINGS_H + +/* WolfHSM Configuration */ +#ifndef WOLFHSM_CFG_ENABLE_CLIENT +#define WOLFHSM_CFG_ENABLE_CLIENT +#endif + +#ifndef WOLFHSM_CFG_ENABLE_SERVER +#define WOLFHSM_CFG_ENABLE_SERVER +#endif + +/* Transport Configuration */ +#define WOLFHSM_CFG_TRANS_SHM + +/* Environment */ +#ifndef WOLFSSL_USER_SETTINGS + #define WOLFSSL_USER_SETTINGS +#endif +#define WOLFSSL_WOLFHSM + +#ifdef PICO_PLATFORM + #include +#endif + +#define NO_FILESYSTEM +#ifndef NO_MAIN_DRIVER + #define NO_MAIN_DRIVER +#endif +#define WOLFSSL_NO_SOCK + +/* Time function */ +#define WOLFHSM_CFG_PORT_GETTIME time_us_64 + +/* WolfCrypt Configuration */ +#define WOLF_CRYPTO_CB +#define HAVE_ANONYMOUS_INLINE_AGGREGATES 1 +#define WOLFSSL_WOLFHSM +#define WOLFSSL_KEY_GEN +#define WOLFSSL_CERT_GEN + + +/* Suppress hardened build warning */ +#define WC_NO_HARDEN + +#define NO_WRITEV +#define SINGLE_THREADED + +/* Use custom IO for wolfSSL */ +#define WOLFSSL_USER_IO + +#endif /* USER_SETTINGS_H */ diff --git a/pico_sdk_import.cmake b/pico_sdk_import.cmake new file mode 100644 index 00000000..d493cc23 --- /dev/null +++ b/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) From fc5ac82a1104b48a0b18538701a547c44d3db081 Mon Sep 17 00:00:00 2001 From: Harinath Nampally Date: Wed, 7 Jan 2026 21:50:40 -0500 Subject: [PATCH 3/4] add SHA256 demo --- examples/pico/CMakeLists.txt | 41 +++++ examples/pico/README.md | 133 +++++++++++----- examples/pico/pico2_demo_sha256.c | 254 ++++++++++++++++++++++++++++++ examples/pico/user_settings.h | 15 ++ 4 files changed, 406 insertions(+), 37 deletions(-) create mode 100644 examples/pico/pico2_demo_sha256.c diff --git a/examples/pico/CMakeLists.txt b/examples/pico/CMakeLists.txt index d87e8849..04357c95 100644 --- a/examples/pico/CMakeLists.txt +++ b/examples/pico/CMakeLists.txt @@ -1,3 +1,4 @@ +if (WOLFHSM_DEMO_DUAL) add_executable(pico2_demo_dual pico2_demo_dual.c ${CMAKE_CURRENT_SOURCE_DIR}/../../port/pico/pico2_transport_shm.c @@ -29,3 +30,43 @@ pico_enable_stdio_uart(pico2_demo_dual 0) # Generate UF2 file for Pico pico_add_extra_outputs(pico2_demo_dual) +endif() + +if (WOLFHSM_DEMO_SHA256) +# SHA256 Demo +add_executable(pico2_demo_sha256 + pico2_demo_sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../port/pico/pico2_transport_shm.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../wolfssl/wolfcrypt/src/port/rpi_pico/pico.c +) + +target_link_libraries(pico2_demo_sha256 + pico_stdlib + pico_multicore + pico_rand + wolfhsm + wolfssl +) + +target_compile_definitions(pico2_demo_sha256 PRIVATE + WOLFSSL_USER_SETTINGS + WOLFHSM_CFG_ENABLE_CLIENT + WOLFHSM_CFG_ENABLE_SERVER +) + +target_include_directories(pico2_demo_sha256 PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../.. + ${CMAKE_CURRENT_SOURCE_DIR}/../../wolfhsm + ${CMAKE_CURRENT_SOURCE_DIR}/../../port/pico + ${CMAKE_CURRENT_SOURCE_DIR}/../../wolfssl + ${CMAKE_CURRENT_SOURCE_DIR}/../../wolfssl/wolfssl +) + +# Enable stdio over USB only +pico_enable_stdio_usb(pico2_demo_sha256 1) +pico_enable_stdio_uart(pico2_demo_sha256 0) + +# Generate UF2 file for Pico +pico_add_extra_outputs(pico2_demo_sha256) +endif() diff --git a/examples/pico/README.md b/examples/pico/README.md index 6fcd5287..520223d6 100644 --- a/examples/pico/README.md +++ b/examples/pico/README.md @@ -1,20 +1,16 @@ -# Pico-2 Dual-Core Echo Demo +# Pico-2 Dual-Core wolfHSM Demos -## Overview +This directory contains examples demonstrating dual-core communication using wolfHSM on the Raspberry Pi Pico-2. +- **Echo Demo** (`pico2_demo_dual`): A simple client-server echo test. +- **SHA256 Demo** (`pico2_demo_sha256`): Offloading SHA256 hashing from the client (Core 1) to the server (Core 0). -This demo shows dual-core communication using wolfHSM on the Raspberry Pi Pico-2: -- **Core 0**: Runs the wolfHSM server, receives requests and echoes responses -- **Core 1**: Runs the wolfHSM client, sends test messages and displays echoed responses +## Shared Memory Transport -## How It Works - -1. Core 0 initializes shared memory and starts the server -2. Core 1 connects to the shared memory transport and sends requests -3. Server receives "Hello from Core 1" and responds with "Echo: Hello from Core 1" -4. Client receives 5 additional echoed requests in a loop - -## Shared Memory Layout +Both demos use a shared memory region to pass messages between cores: +- **Core 0**: Runs the wolfHSM server. +- **Core 1**: Runs the wolfHSM client. +**Memory Layout:** ``` Header (32 bytes) - Initialization flags and metadata Request Buffer - 1KB, client to server @@ -23,44 +19,107 @@ Response Buffer - 1KB, server to client ## Building -```bash -cd $WOLF_HSM_DIR -mkdir -p build && cd build && cmake -GNinja -DBUILD_PICO2_DEMOS=ON -DPICO_SDK_PATH=/path/to/pico-sdk .. && ninja -``` +You can choose which demo to build using CMake flags. -The UF2 file will be at `build/lib/pico2_demo_dual.uf2`. +1. **Setup environment** + ```bash + cd $WOLF_HSM_DIR + mkdir -p build && cd build + ``` -## Configuration +2. **Configure (Choose one)** -Edit these values in `pico2_demo_dual.c` if needed: + *For Echo Demo:* + ```bash + cmake -GNinja -DBUILD_PICO2_DEMOS=ON -DWOLFHSM_DEMO_DUAL=ON -DPICO_SDK_PATH=/path/to/pico-sdk .. + ``` -```c -#define SHARED_MEM_SIZE (4 * 1024) // Total shared memory -#define REQ_SIZE 1024 // Request buffer size -#define RESP_SIZE 1024 // Response buffer size -``` + *For SHA256 Demo:* + ```bash + cmake -GNinja -DBUILD_PICO2_DEMOS=ON -DWOLFHSM_DEMO_SHA256=ON -DPICO_SDK_PATH=/path/to/pico-sdk .. + ``` -## Output +3. **Build** + ```bash + ninja + ``` -Expected serial output: +The output UF2 file will be at `examples/pico/pico2_demo_dual.uf2` or `examples/pico/pico2_demo_sha256.uf2`. +## Demo 1: Echo Server/Client + +### Overview +- **Core 0** (Server): Initializes transport, listens for requests, and echoes the payload back with an "Echo: " prefix. +- **Core 1** (Client): Connects to the transport, sends test strings, and verifies the echoed response. + +### Expected Output ``` -=== Pico-2 Dual-Core wolfHSM Demo === -Shared memory @0x20040000 size 4096 Server running on Core 0, client on Core 1 -Server handled message 1 -Server handled message 2 -... -Server handled message 6 -Client received response 0: Echo: Hello from Core 1 -Client received response 1: Echo: Request 0 from Core 1 +Client initialized +Sent: Hello from Core 1 +Received: Echo: Hello from Core 1 ... ``` +## Demo 2: SHA256 Offload + +### Overview +- **Core 0** (Server): Runs the full wolfHSM server with a software crypto backend (using wolfCrypt). +- **Core 1** (Client): Uses the standard `wolfCrypt` API (e.g., `wc_InitSha256_ex`) with `WH_DEV_ID`. This transparently marshals the crypto operation to the server via the shared memory transport. + +### Configuration +Edit `pico2_demo_sha256.c` or `user_settings.h` to adjust buffer sizes or enable/disable specific algorithms. + +### Expected Output +``` +=== Pico-2 Dual-Core wolfHSM SHA256 Demo (wolfCrypt API) === +Shared memory @20001838 size 4096 +Server running on Core 0, client on Core 1 + +=== Core 1: Client start === +Client initializing... +Client initialized via wh_Client_Init + +--- Starting SHA256 Demo --- + +Input [0]: "Hello from Core 1" (17 bytes) +SHA256 Initialized Successfully +SHA256 Update Successful +SHA256 Finalizing... +SHA256 Hash: 975ddc4c55e2da9e7efdaffb72a1e221d67ade221e1767fe0e525e80d926ce02 + +Input [1]: "The quick brown fox" (19 bytes) +SHA256 Initialized Successfully +SHA256 Update Successful +SHA256 Finalizing... +SHA256 Hash: 5cac4f980fedc3d3f1f99b4be3472c9b30d56523e632d151237ec9309048bda9 + +Input [2]: "wolfHSM SHA256 Demo" (19 bytes) +SHA256 Initialized Successfully +SHA256 Update Successful +SHA256 Finalizing... +SHA256 Hash: df504e1687a32bf2389f3a07a99e845393d4b7fe40c26c88cca658e36717f73b + +Input [3]: "Pico2 Dual Core" (15 bytes) +SHA256 Initialized Successfully +SHA256 Update Successful +SHA256 Finalizing... +SHA256 Hash: 520283eac4ef94cbfdeee0c9c595aebae13499d0492fde20ce86424b913d23e9 + +Input [4]: "SHA256 Hash Test" (16 bytes) +SHA256 Initialized Successfully +SHA256 Update Successful +SHA256 Finalizing... +SHA256 Hash: b3a9b0be905013ea129ac28877883f8d68aa3df8b1df8a205023c608568c9cd3 + +--- Demo Complete --- +Core 1 done +``` + ## Requirements -- Raspberry Pi Pico-2 board -- Pico SDK 2.2.0+ +- Raspberry Pi Pico-2 board (RP2350) +- Pico SDK 2.0.0+ - wolfSSL and wolfHSM libraries - ARM GCC toolchain diff --git a/examples/pico/pico2_demo_sha256.c b/examples/pico/pico2_demo_sha256.c new file mode 100644 index 00000000..45794da2 --- /dev/null +++ b/examples/pico/pico2_demo_sha256.c @@ -0,0 +1,254 @@ +/* + * Combined dual-core demo: server on Core 0, client on Core 1. + * Demonstrates SHA256 hashing via wolfHSM using the wolfCrypt API. + */ +#include +#include +#include "pico/stdlib.h" +#include "pico/multicore.h" + +#include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_server.h" +#include "wolfhsm/wh_client.h" +#include "wolfhsm/wh_client_cryptocb.h" +#include "wolfhsm/wh_client_crypto.h" +#include "wolfcrypt/sha256.h" +#include "wolfcrypt/error-crypt.h" +#include "pico2_transport_shm.h" + +int rc; // Define rc as global or local as needed, but let's just make sure it's declared in functions where it's used. + +#define SHARED_MEM_SIZE (4 * 1024) +__attribute__((section(".shared_ram"))) +static uint8_t pico2_shared_mem[SHARED_MEM_SIZE]; +static size_t pico2_shared_mem_size = SHARED_MEM_SIZE; + +#define SERVER_ID 1 +#define CLIENT_ID 2 +#define REQ_SIZE 1024 +#define RESP_SIZE 1024 +#define DMA_SIZE 1024 + +/* + * Server Setup + */ +static int server_init(whServerContext *serverCtx, whCommServer *serverComm, whServerCryptoContext *cryptoCtx, pico2TransportShmContext *ctx) +{ + int rc; + static const whTransportServerCb server_cb = PICO2_TRANSPORT_SHM_SERVER_CB; + memset(ctx, 0, sizeof(*ctx)); + pico2TransportShmConfig cfg = { + .req_size = REQ_SIZE, + .resp_size = RESP_SIZE, + .dma_size = DMA_SIZE, + .shared_mem = pico2_shared_mem, + .shared_mem_size = pico2_shared_mem_size, + }; + whCommServerConfig scfg = { + .transport_cb = &server_cb, + .transport_context = ctx, + .transport_config = &cfg, + .server_id = SERVER_ID, + }; + + /* Initialize crypto context (RNG, etc.) */ + memset(cryptoCtx, 0, sizeof(*cryptoCtx)); + cryptoCtx->devId = -2; /* Use software crypto for the server's backend */ +#ifndef WC_NO_RNG + rc = wc_InitRng(cryptoCtx->rng); + if (rc != 0) { + printf("ERROR: server wc_InitRng failed (rc=%d)\n", rc); + return rc; + } +#endif + + /* Initialize the full Server Application */ + memset(serverCtx, 0, sizeof(*serverCtx)); + /* wh_Server_Init takes whServerConfig */ + whServerConfig serverCfg; + memset(&serverCfg, 0, sizeof(serverCfg)); + serverCfg.comm_config = &scfg; + serverCfg.crypto = cryptoCtx; + serverCfg.nvm = NULL; /* No NVM for this demo */ + + rc = wh_Server_Init(serverCtx, &serverCfg); + if (rc != WH_ERROR_OK) { + printf("ERROR: wh_Server_Init failed (rc=%d)\n", rc); + return rc; + } + + /* Set connected state */ + wh_Server_SetConnected(serverCtx, WH_COMM_CONNECTED); + + return 0; +} + +/* + * Client Setup + */ +static int client_init(whClientContext *clientCtx, pico2TransportShmContext *ctx) +{ + static const whTransportClientCb client_cb = PICO2_TRANSPORT_SHM_CLIENT_CB; + memset(ctx, 0, sizeof(*ctx)); + + /* Step 1: Allocate and initialize transport configuration */ + pico2TransportShmConfig cfg = { + .req_size = REQ_SIZE, + .resp_size = RESP_SIZE, + .dma_size = DMA_SIZE, + .shared_mem = pico2_shared_mem, + .shared_mem_size = pico2_shared_mem_size, + }; + + /* Step 2: Allocate comm client configuration and bind to the transport */ + whCommClientConfig commClientCfg = { + .transport_cb = &client_cb, + .transport_context = ctx, + .transport_config = &cfg, + .client_id = CLIENT_ID, + }; + + /* Step 3: Allocate and initialize the client configuration */ + whClientConfig clientCfg; + memset(&clientCfg, 0, sizeof(clientCfg)); + clientCfg.comm = &commClientCfg; + + /* Step 5: Init */ + printf("Client initializing...\n"); + int rc = wh_Client_Init(clientCtx, &clientCfg); + if (rc != 0) { + printf("ERROR: wh_Client_Init failed (rc=%d)\n", rc); + return rc; + } + printf("Client initialized via wh_Client_Init\n"); + + return 0; +} + +static void print_hash(const uint8_t *hash, size_t len) +{ + for (size_t i = 0; i < len; i++) { + printf("%02x", hash[i]); + } + printf("\n"); +} + +static int client_run_demo(void) +{ + int ret; + uint8_t hash[32]; + const char *test_inputs[] = { + "Hello from Core 1", + "The quick brown fox", + "wolfHSM SHA256 Demo", + "Pico2 Dual Core", + "SHA256 Hash Test" + }; + + printf("\n--- Starting SHA256 Demo ---\n"); + + for (int i = 0; i < 5; i++) { + const char *plaintext = test_inputs[i]; + size_t len = strlen(plaintext); + + printf("\nInput [%d]: \"%s\" (%zu bytes)\n", i, plaintext, len); + + /* Standard wolfCrypt API usage, but redirected to HSM via WH_DEV_ID */ + wc_Sha256 sha256[1]; + + /* Initialize with devId = WH_DEV_ID to trigger the callback */ + ret = wc_InitSha256_ex(sha256, NULL, WH_DEV_ID); + if (ret == 0) { + printf("SHA256 Initialized Successfully\n"); + ret = wc_Sha256Update(sha256, (const byte*)plaintext, (word32)len); + if (ret == 0) { + printf("SHA256 Update Successful\n"); + ret = wc_Sha256Final(sha256, hash); + if (ret != 0) { + printf("Error: wc_Sha256Final failed with %d\n", ret); + } + } else { + printf("Error: wc_Sha256Update failed with %d\n", ret); + } + printf("SHA256 Finalizing...\n"); + wc_Sha256Free(sha256); + } else { + printf("Error: wc_InitSha256_ex failed with %d\n", ret); + } + + if (ret == 0) { + printf("SHA256 Hash: "); + print_hash(hash, 32); + } else { + printf("Failed to compute hash\n"); + return ret; + } + + sleep_ms(1000); + } + printf("\n--- Demo Complete ---\n"); + return 0; +} + +static void core1_entry(void) +{ + static whClientContext clientCtx[1]; + static pico2TransportShmContext clientTransportCtx[1]; + + sleep_ms(2000); /* Wait for server to start */ + printf("\n=== Core 1: Client start ===\n"); + + if (client_init(clientCtx, clientTransportCtx) != 0) { + printf("Client init failed\n"); + multicore_fifo_push_blocking(0xDEAD0001); + return; + } + + if (client_run_demo() != 0) { + printf("Client demo failed\n"); + } + + pico2TransportShm_Cleanup(clientTransportCtx); + multicore_fifo_push_blocking(0xC1E17E); + printf("Core 1 done\n"); +} + +int main(void) +{ + whServerContext serverCtx[1]; + whCommServer serverComm[1]; + whServerCryptoContext cryptoCtx[1]; + pico2TransportShmContext serverTransportCtx[1]; + + stdio_init_all(); + sleep_ms(5000); + printf("\n=== Pico-2 Dual-Core wolfHSM SHA256 Demo (wolfCrypt API) ===\n"); + printf("Shared memory @%p size %u\n", pico2_shared_mem, (unsigned)pico2_shared_mem_size); + + /* Use serverComm wrapper in serverCtx if we use wh_Server_Init, + but here we passed scfg which uses a local transort context. + The server_init call handles internal wh_Server_Init. + */ + if (server_init(serverCtx, serverComm, cryptoCtx, serverTransportCtx) != 0) { + printf("Server init failed\n"); + return 1; + } + + /* Start client on core 1 */ + multicore_launch_core1(core1_entry); + printf("Server running on Core 0, client on Core 1\n"); + + /* + * Main Server Loop + */ + while (1) { + int ret = wh_Server_HandleRequestMessage(serverCtx); + if (ret == WH_ERROR_NOTREADY) { + /* No message, yield briefly */ + } else if (ret != WH_ERROR_OK) { + printf("Server loop error: %d\n", ret); + } + } + + return 0; +} diff --git a/examples/pico/user_settings.h b/examples/pico/user_settings.h index aa99f2ee..35dba47e 100644 --- a/examples/pico/user_settings.h +++ b/examples/pico/user_settings.h @@ -49,4 +49,19 @@ /* Use custom IO for wolfSSL */ #define WOLFSSL_USER_IO +#define WOLFSSL_RPIPICO +#define WOLFSSL_SP_ARM_CORTEX_M_ASM +#define WC_NO_HASHDRBG +#define CUSTOM_RAND_GENERATE_BLOCK wc_pico_rng_gen_block +#define WC_RESEED_INTERVAL (1000000) + +/* Ensure the prototype is visible for the implementation check, but avoid conflicts if it's already in the header */ +#ifdef __cplusplus +extern "C" { +#endif +int wc_pico_rng_gen_block(unsigned char *output, unsigned int sz); +#ifdef __cplusplus +} +#endif + #endif /* USER_SETTINGS_H */ From 1bc5b2a9c3cd53b3631c173dcd087f2910419842 Mon Sep 17 00:00:00 2001 From: Harinath Nampally Date: Sat, 24 Jan 2026 00:59:05 +0000 Subject: [PATCH 4/4] refactor and clean up --- examples/pico/pico2_demo_dual.c | 90 ++++++++++++++++++++----------- examples/pico/pico2_demo_sha256.c | 44 +++++++++++---- port/pico/pico2_transport_shm.c | 22 ++++++-- port/pico/pico2_transport_shm.h | 12 ++++- 4 files changed, 119 insertions(+), 49 deletions(-) diff --git a/examples/pico/pico2_demo_dual.c b/examples/pico/pico2_demo_dual.c index d9d7e852..1403291e 100644 --- a/examples/pico/pico2_demo_dual.c +++ b/examples/pico/pico2_demo_dual.c @@ -12,7 +12,7 @@ #include "pico2_transport_shm.h" #define SHARED_MEM_SIZE (4 * 1024) -__attribute__((section(".shared_ram"))) +__attribute__((section(".shared_ram"), aligned(4))) static uint8_t pico2_shared_mem[SHARED_MEM_SIZE]; static size_t pico2_shared_mem_size = SHARED_MEM_SIZE; @@ -21,6 +21,23 @@ static size_t pico2_shared_mem_size = SHARED_MEM_SIZE; #define REQ_SIZE 1024 #define RESP_SIZE 1024 #define DMA_SIZE 1024 +#define BUFFER_SIZE 256 +#define CLIENT_REQ_BUF_SIZE 128 +#define CLIENT_RESP_BUF_SIZE 128 +#define MAGIC_VALUE 0x1234 +#define ECHO_PREFIX "Echo: " +#define ECHO_PREFIX_LEN 6 +#define HELLO_MSG "Hello from Core 1" +#define HELLO_MSG_LEN 17 +#define REQUEST_FMT "Request %d from Core 1" +#define STARTUP_DELAY_MS 5000 +#define CLIENT_INIT_DELAY_MS 500 +#define REQUEST_LOOP_DELAY_MS 2000 +#define POLL_DELAY_MS 1 +#define NUM_LOOP_REQUESTS 5 +#define FIFO_ERROR_VAL 0xDEAD0001 +#define FIFO_SUCCESS_VAL 0xC1E17E +#define EXPECTED_HANDLED_COUNT (1 + NUM_LOOP_REQUESTS) static int server_init(whCommServer *server, pico2TransportShmContext *ctx) { @@ -49,8 +66,8 @@ static int server_init(whCommServer *server, pico2TransportShmContext *ctx) static int server_handle_message(whCommServer *server, int *handled) { - uint8_t req_data[256]; - uint8_t resp_data[256]; + uint8_t req_data[BUFFER_SIZE]; + uint8_t resp_data[BUFFER_SIZE]; uint16_t resp_len = 0; uint16_t magic = 0, kind = 0, seq = 0, req_len = 0; int rc = wh_CommServer_RecvRequest(server, &magic, &kind, &seq, &req_len, req_data); @@ -61,12 +78,14 @@ static int server_handle_message(whCommServer *server, int *handled) printf("ERROR: recv request rc=%d\n", rc); return rc; } - memcpy(resp_data, "Echo: ", 6); - resp_len = 6; - if (req_len < sizeof(resp_data) - 6) { - memcpy(&resp_data[6], req_data, req_len); - resp_len += req_len; + memcpy(resp_data, ECHO_PREFIX, ECHO_PREFIX_LEN); + uint16_t copy_len = req_len; + if (copy_len > sizeof(resp_data) - ECHO_PREFIX_LEN) { + copy_len = sizeof(resp_data) - ECHO_PREFIX_LEN; } + memcpy(&resp_data[ECHO_PREFIX_LEN], req_data, copy_len); + resp_len = ECHO_PREFIX_LEN + copy_len; + rc = wh_CommServer_SendResponse(server, magic, kind, seq, resp_len, resp_data); if (rc != WH_ERROR_OK) { printf("ERROR: send response rc=%d\n", rc); @@ -105,20 +124,20 @@ static int client_init(whCommClient *client, pico2TransportShmContext *ctx) static int client_send_requests(whCommClient *client) { - uint8_t req[128]; - uint8_t resp[128]; - uint16_t resp_len = 128; - uint16_t magic = 0x1234; + uint8_t req[CLIENT_REQ_BUF_SIZE]; + uint8_t resp[CLIENT_RESP_BUF_SIZE]; + uint16_t resp_len = CLIENT_RESP_BUF_SIZE; + uint16_t magic = MAGIC_VALUE; uint16_t kind = 0; uint16_t seq = 0; int rc; - memcpy(req, "Hello from Core 1", 17); + memcpy(req, HELLO_MSG, HELLO_MSG_LEN); printf("Client sending first request\n"); do { - rc = wh_CommClient_SendRequest(client, magic, kind, &seq, 17, req); + rc = wh_CommClient_SendRequest(client, magic, kind, &seq, HELLO_MSG_LEN, req); if (rc == WH_ERROR_NOTREADY) { - sleep_ms(1); + sleep_ms(POLL_DELAY_MS); } } while (rc == WH_ERROR_NOTREADY); if (rc != WH_ERROR_OK) { @@ -129,39 +148,39 @@ static int client_send_requests(whCommClient *client) do { rc = wh_CommClient_RecvResponse(client, &magic, &kind, &seq, &resp_len, resp); if (rc == WH_ERROR_NOTREADY) { - sleep_ms(1); + sleep_ms(POLL_DELAY_MS); } } while (rc == WH_ERROR_NOTREADY); if (rc != WH_ERROR_OK) { printf("ERROR: recv response rc=%d\n", rc); return rc; } - for (int i = 0; i < 5; i++) { + for (int i = 0; i < NUM_LOOP_REQUESTS; i++) { printf("Client sending request %d\n", i); - sprintf((char*)req, "Request %d from Core 1", i); + sprintf((char*)req, REQUEST_FMT, i); uint16_t req_len = strlen((char*)req); do { rc = wh_CommClient_SendRequest(client, magic, kind, &seq, req_len, req); if (rc == WH_ERROR_NOTREADY) { - sleep_ms(1); + sleep_ms(POLL_DELAY_MS); } } while (rc == WH_ERROR_NOTREADY); if (rc != WH_ERROR_OK) { printf("ERROR: send request rc=%d\n", rc); return rc; } - resp_len = 128; + resp_len = CLIENT_RESP_BUF_SIZE; do { rc = wh_CommClient_RecvResponse(client, &magic, &kind, &seq, &resp_len, resp); if (rc == WH_ERROR_NOTREADY) { - sleep_ms(1); + sleep_ms(POLL_DELAY_MS); } } while (rc == WH_ERROR_NOTREADY); if (rc != WH_ERROR_OK) { printf("ERROR: recv response rc=%d\n", rc); return rc; } - sleep_ms(2000); + sleep_ms(REQUEST_LOOP_DELAY_MS); printf("Client received response %d: %.*s\n", i, resp_len, resp); } return 0; @@ -171,20 +190,20 @@ static void core1_entry(void) { whCommClient client[1]; pico2TransportShmContext ctx[1]; - sleep_ms(5000); + sleep_ms(STARTUP_DELAY_MS); printf("\n=== Core 1: Client start ===\n"); if (client_init(client, ctx) != 0) { printf("Client init failed\n"); - multicore_fifo_push_blocking(0xDEAD0001); + multicore_fifo_push_blocking(FIFO_ERROR_VAL); return; } - sleep_ms(500); + sleep_ms(CLIENT_INIT_DELAY_MS); printf("Client initialized, sending requests\n"); if (client_send_requests(client) != 0) { printf("Client requests failed\n"); } pico2TransportShm_Cleanup(ctx); - multicore_fifo_push_blocking(0xC1E17E); + multicore_fifo_push_blocking(FIFO_SUCCESS_VAL); printf("Core 1 done\n"); } int main(void) @@ -194,7 +213,7 @@ int main(void) int handled = 0; stdio_init_all(); - sleep_ms(5000); + sleep_ms(STARTUP_DELAY_MS); printf("\n=== Pico-2 Dual-Core wolfHSM Demo ===\n"); printf("Shared memory @%p size %u\n", pico2_shared_mem, (unsigned)pico2_shared_mem_size); @@ -206,17 +225,26 @@ int main(void) multicore_launch_core1(core1_entry); printf("Server running on Core 0, client on Core 1\n"); - const int expected = 6; /* 1 echo + 5 looped */ + const int expected = EXPECTED_HANDLED_COUNT; while (handled < expected) { if (server_handle_message(server, &handled) != 0) { printf("Server loop error\n"); break; } - sleep_ms(5000); + sleep_ms(POLL_DELAY_MS); } pico2TransportShm_Cleanup(ctx); - multicore_fifo_pop_blocking(); /* wait for client */ + + while (!multicore_fifo_rvalid()) { + sleep_ms(POLL_DELAY_MS); + } + uint32_t popped_val = multicore_fifo_pop_blocking(); /* wait for client */ - return 0; + if (popped_val == FIFO_SUCCESS_VAL) { + return 0; + } + + printf("Core 1 reported error: 0x%x\n", (unsigned int)popped_val); + return -1; } diff --git a/examples/pico/pico2_demo_sha256.c b/examples/pico/pico2_demo_sha256.c index 45794da2..803dcda6 100644 --- a/examples/pico/pico2_demo_sha256.c +++ b/examples/pico/pico2_demo_sha256.c @@ -6,6 +6,7 @@ #include #include "pico/stdlib.h" #include "pico/multicore.h" +#include "pico/time.h" #include "wolfhsm/wh_comm.h" #include "wolfhsm/wh_server.h" @@ -16,10 +17,10 @@ #include "wolfcrypt/error-crypt.h" #include "pico2_transport_shm.h" -int rc; // Define rc as global or local as needed, but let's just make sure it's declared in functions where it's used. + #define SHARED_MEM_SIZE (4 * 1024) -__attribute__((section(".shared_ram"))) +__attribute__((section(".shared_ram"), aligned(4))) static uint8_t pico2_shared_mem[SHARED_MEM_SIZE]; static size_t pico2_shared_mem_size = SHARED_MEM_SIZE; @@ -28,6 +29,14 @@ static size_t pico2_shared_mem_size = SHARED_MEM_SIZE; #define REQ_SIZE 1024 #define RESP_SIZE 1024 #define DMA_SIZE 1024 +#define HASH_SIZE 32 +#define NUM_TEST_INPUTS 5 +#define DEMO_LOOP_DELAY_MS 1000 +#define CLIENT_STARTUP_DELAY_MS 2000 +#define SERVER_STARTUP_DELAY_MS 5000 +#define POLL_DELAY_MS 1 +#define FIFO_ERROR_VAL 0xDEAD0001 +#define FIFO_SUCCESS_VAL 0xC1E17E /* * Server Setup @@ -53,7 +62,7 @@ static int server_init(whServerContext *serverCtx, whCommServer *serverComm, whS /* Initialize crypto context (RNG, etc.) */ memset(cryptoCtx, 0, sizeof(*cryptoCtx)); - cryptoCtx->devId = -2; /* Use software crypto for the server's backend */ + cryptoCtx->devId = INVALID_DEVID; /* Use local software crypto for the server's backend */ #ifndef WC_NO_RNG rc = wc_InitRng(cryptoCtx->rng); if (rc != 0) { @@ -136,7 +145,7 @@ static void print_hash(const uint8_t *hash, size_t len) static int client_run_demo(void) { int ret; - uint8_t hash[32]; + uint8_t hash[HASH_SIZE]; const char *test_inputs[] = { "Hello from Core 1", "The quick brown fox", @@ -147,7 +156,7 @@ static int client_run_demo(void) printf("\n--- Starting SHA256 Demo ---\n"); - for (int i = 0; i < 5; i++) { + for (int i = 0; i < NUM_TEST_INPUTS; i++) { const char *plaintext = test_inputs[i]; size_t len = strlen(plaintext); @@ -178,13 +187,13 @@ static int client_run_demo(void) if (ret == 0) { printf("SHA256 Hash: "); - print_hash(hash, 32); + print_hash(hash, HASH_SIZE); } else { printf("Failed to compute hash\n"); return ret; } - sleep_ms(1000); + sleep_ms(DEMO_LOOP_DELAY_MS); } printf("\n--- Demo Complete ---\n"); return 0; @@ -195,12 +204,12 @@ static void core1_entry(void) static whClientContext clientCtx[1]; static pico2TransportShmContext clientTransportCtx[1]; - sleep_ms(2000); /* Wait for server to start */ + sleep_ms(CLIENT_STARTUP_DELAY_MS); /* Wait for server to start */ printf("\n=== Core 1: Client start ===\n"); if (client_init(clientCtx, clientTransportCtx) != 0) { printf("Client init failed\n"); - multicore_fifo_push_blocking(0xDEAD0001); + multicore_fifo_push_blocking(FIFO_ERROR_VAL); return; } @@ -209,7 +218,7 @@ static void core1_entry(void) } pico2TransportShm_Cleanup(clientTransportCtx); - multicore_fifo_push_blocking(0xC1E17E); + multicore_fifo_push_blocking(FIFO_SUCCESS_VAL); printf("Core 1 done\n"); } @@ -221,7 +230,7 @@ int main(void) pico2TransportShmContext serverTransportCtx[1]; stdio_init_all(); - sleep_ms(5000); + sleep_ms(SERVER_STARTUP_DELAY_MS); printf("\n=== Pico-2 Dual-Core wolfHSM SHA256 Demo (wolfCrypt API) ===\n"); printf("Shared memory @%p size %u\n", pico2_shared_mem, (unsigned)pico2_shared_mem_size); @@ -245,9 +254,22 @@ int main(void) int ret = wh_Server_HandleRequestMessage(serverCtx); if (ret == WH_ERROR_NOTREADY) { /* No message, yield briefly */ + sleep_ms(POLL_DELAY_MS); } else if (ret != WH_ERROR_OK) { printf("Server loop error: %d\n", ret); } + + /* Check if client is done */ + if (multicore_fifo_rvalid()) { + uint32_t val = multicore_fifo_pop_blocking(); + if (val == FIFO_SUCCESS_VAL) { + printf("Client completed successfully. Server shutting down.\n"); + break; + } else { + printf("Client reported error: 0x%08x. Server shutting down.\n", (unsigned int)val); + break; + } + } } return 0; diff --git a/port/pico/pico2_transport_shm.c b/port/pico/pico2_transport_shm.c index 4e0f17d7..fcc2b46d 100644 --- a/port/pico/pico2_transport_shm.c +++ b/port/pico/pico2_transport_shm.c @@ -85,7 +85,12 @@ static int pico2TransportShm_MapMemory(const pico2TransportShmConfig* cfg, return WH_ERROR_BADARGS; } - /* Calculate required size */ + /* Calculate required size with overflow check */ + if ((SIZE_MAX - PICO2_SHM_HEADER_SIZE < cfg->req_size) || + (SIZE_MAX - PICO2_SHM_HEADER_SIZE - cfg->req_size < cfg->resp_size) || + (SIZE_MAX - PICO2_SHM_HEADER_SIZE - cfg->req_size - cfg->resp_size < cfg->dma_size)) { + return WH_ERROR_BADARGS; + } size_t required_size = PICO2_SHM_HEADER_SIZE + cfg->req_size + cfg->resp_size + cfg->dma_size; @@ -278,6 +283,13 @@ int pico2TransportShm_ClientInit(void* c, const void* cf, return WH_ERROR_NOTREADY; } + /* Validate server configuration matches client configuration */ + if ((map->header->req_size != cfg->req_size) || + (map->header->resp_size != cfg->resp_size) || + (map->header->dma_size != cfg->dma_size)) { + return WH_ERROR_BADARGS; + } + /* Configure the underlying transport context */ tmcfg->req = map->req; tmcfg->req_size = map->header->req_size; @@ -527,8 +539,8 @@ int pico2TransportShm_ServerStaticMemDmaCallback( } /* Verify the address is within DMA buffer */ - if ((clientAddr < (uintptr_t)ctx->dma) || - ((clientAddr + len) > ((uintptr_t)ctx->dma + ctx->dma_size))) { + if ((clientAddr < (uintptr_t)ctx->dma) || (len > ctx->dma_size) || + ((clientAddr - (uintptr_t)ctx->dma) > (ctx->dma_size - len))) { return WH_ERROR_BADARGS; } @@ -572,8 +584,8 @@ int pico2TransportShm_ClientStaticMemDmaCallback(whClientContext* client, } /* Verify the address is within DMA buffer */ - if ((clientAddr < (uintptr_t)ctx->dma) || - ((clientAddr + len) > ((uintptr_t)ctx->dma + ctx->dma_size))) { + if ((clientAddr < (uintptr_t)ctx->dma) || (len > ctx->dma_size) || + ((clientAddr - (uintptr_t)ctx->dma) > (ctx->dma_size - len))) { return WH_ERROR_BADARGS; } diff --git a/port/pico/pico2_transport_shm.h b/port/pico/pico2_transport_shm.h index edd90823..8e7299b8 100644 --- a/port/pico/pico2_transport_shm.h +++ b/port/pico/pico2_transport_shm.h @@ -44,12 +44,16 @@ #include "wolfhsm/wh_comm.h" #include "wolfhsm/wh_transport_mem.h" +#ifdef __cplusplus +extern "C" { +#endif + /** Pico-2 SHM configuration structure */ typedef struct { uint16_t req_size; /* Request buffer size */ uint16_t resp_size; /* Response buffer size */ size_t dma_size; /* DMA buffer size (optional) */ - void* shared_mem; /* Base address of shared memory region */ + void* shared_mem; /* Base address of shared memory region (must be 4-byte aligned) */ size_t shared_mem_size; /* Total size of shared memory region */ } pico2TransportShmConfig; @@ -92,7 +96,7 @@ typedef pico2TransportShmContext pico2TransportShmServerContext; * @return WH_ERROR_OK on success, or error code on failure */ int pico2TransportShm_GetDma(pico2TransportShmContext* ctx, - void* *out_dma, size_t *out_size); + void** out_dma, size_t *out_size); /** * @brief Set heap hint for DMA operations @@ -247,4 +251,8 @@ int pico2TransportShm_ClientStaticMemDmaCallback(whClientContext* client, #endif /* WOLFHSM_CFG_DMA */ +#ifdef __cplusplus +} +#endif + #endif /* !PORT_PICO2_PICO2_TRANSPORT_SHM_H_ */