Skip to content

Commit 655e1c9

Browse files
authored
Merge pull request #337 from bigbrett/async-crypto-v2
Async crypto v2
2 parents cf7ac38 + 97b9cd6 commit 655e1c9

20 files changed

Lines changed: 5519 additions & 1489 deletions

.github/workflows/code-coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545
run: |
4646
echo "=== Coverage Summary ==="
4747
cd test
48-
gcovr --gcov-ignore-parse-errors="negative_hits.warn" Build --root .. --filter '\.\./src/.*' --filter '\.\./wolfhsm/.*' --print-summary
48+
gcovr Build --root .. --gcov-ignore-parse-errors=negative_hits.warn_once_per_file --filter '\.\./src/.*' --filter '\.\./wolfhsm/.*' --print-summary
4949
5050
# Upload coverage report as artifact
5151
- name: Upload coverage report

docs/draft/async-crypto.md

Lines changed: 470 additions & 0 deletions
Large diffs are not rendered by default.

docs/draft/posix-shm.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# POSIX SHM DMA Transport
2+
3+
## Overview
4+
5+
There are two independent features at play in the POSIX SHM transport port. Understanding which is which is key.
6+
7+
## 1. The Transport: POSIX Shared Memory (`posix_transport_shm`)
8+
9+
This is purely a **transport layer** -- it moves request/response messages between client and server processes. It works like this:
10+
11+
- **Server** creates a POSIX shared memory object (`shm_open`) with a layout of:
12+
```
13+
[ 64-byte header | request buffer | response buffer | optional DMA section ]
14+
```
15+
- **Client** opens the same named object and `mmap`s it into its address space
16+
- Both sides then delegate to `wh_transport_mem` (the generic memory-based transport) for actual message passing via CSR registers in the request/response buffers
17+
- The header contains PIDs for RT-signal-based async notification
18+
19+
The transport's job is **only** to shuttle serialized request/response packets. It knows nothing about crypto, keys, or DMA semantics.
20+
21+
The optional **DMA section** at the end of the shared memory region is the transport providing a chunk of shared address space that *both* processes can access. This is just raw shared memory -- the transport allocates it but doesn't use it itself. It's plumbing for the DMA feature.
22+
23+
## 2. The Feature: DMA (`WOLFHSM_CFG_DMA`)
24+
25+
DMA is a **separate, transport-agnostic feature** in wolfHSM core (`wh_dma.h`, `wh_server_dma.c`, `wh_client_dma.c`). It allows crypto operations to reference client memory **by address** rather than copying data into the transport's request/response buffers. This matters because:
26+
27+
- Standard messages are limited by `WOLFHSM_CFG_COMM_DATA_LEN` (typically ~4KB)
28+
- DMA messages send *addresses* in the request, and the server reads/writes client memory directly
29+
30+
The DMA feature has a callback-based architecture:
31+
- `wh_Server_DmaProcessClientAddress()` -- server calls this with a client address, the registered callback transforms it to something the server can dereference
32+
- `wh_Client_DmaProcessClientAddress()` -- client calls this to transform its local address into whatever the server will receive in the message
33+
- PRE/POST operations handle setup and teardown (cache flush/invalidate, temporary buffer allocation, etc.)
34+
35+
On real hardware (e.g. Infineon TC3xx), this is literal hardware DMA -- client and server are on different cores with different address maps, and the callbacks handle the MMU/bus address translation.
36+
37+
## 3. The Glue: Static Memory Pool Allocator in the SHM DMA Callbacks
38+
39+
The `posixTransportShm_ClientStaticMemDmaCallback` and `posixTransportShm_ServerStaticMemDmaCallback` in `posix_transport_shm.c` are the **port-specific DMA callbacks** that bridge the POSIX SHM transport with the DMA feature. Here's the clever part:
40+
41+
**Problem:** On POSIX, client and server are separate processes with separate virtual address spaces. A raw client pointer like `0x7fff12345000` means nothing to the server. But the DMA section in shared memory is mapped into *both* processes (at potentially different virtual addresses).
42+
43+
**Solution using the pool allocator:**
44+
45+
1. wolfCrypt's `WOLFSSL_STATIC_MEMORY` pool allocator (`wc_LoadStaticMemory_ex`) is initialized with the DMA section as its backing memory pool
46+
2. When the client DMA callback gets a PRE operation with a client address that's **not** already in the DMA area, it:
47+
- Allocates a temporary buffer from the pool (`XMALLOC` with the heap hint)
48+
- Copies client data into it
49+
- Returns an **offset** from the DMA base (not a pointer) -- this is what gets sent to the server
50+
3. The server DMA callback simply takes that offset, validates it's in bounds, and returns `dma_base + offset`
51+
4. On POST, the client callback copies results back (for writes) and frees the temporary buffer
52+
53+
If the client address **is already** in the DMA section (the client allocated directly from the pool), it skips the copy and just computes the offset -- zero-copy.
54+
55+
The pool allocator here is used as a **bump/slab allocator for the shared DMA region**. It has nothing to do with the transport itself -- it's the DMA callback's strategy for managing the shared buffer. wolfHSM could use a different allocator; the pool allocator was chosen because it's already available in wolfCrypt and works without `malloc`.
56+
57+
## Summary Table
58+
59+
| Aspect | Transport (SHM) | DMA Feature | Pool Allocator |
60+
|--------|-----------------|-------------|----------------|
61+
| **Layer** | Communication | Application/Crypto | Memory management |
62+
| **Scope** | Port-specific (POSIX) | Core wolfHSM | DMA callback impl detail |
63+
| **Purpose** | Move request/response packets | Let server access client memory by address | Manage temporary buffers in shared DMA area |
64+
| **Config** | `posixTransportShmConfig` | `WOLFHSM_CFG_DMA` | `WOLFSSL_STATIC_MEMORY` |
65+
| **Without it** | No communication | Data must fit in request/response buffers | Would need a different allocator for DMA region |
66+
67+
The DMA section is **allocated by the transport** but **used by the DMA callbacks**. The pool allocator is **used by the DMA callbacks** to subdivide that DMA section. Three layers, three concerns.

examples/posix/wh_posix_cfg.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
* DMA AND BUFFER SIZES
2424
* =========================================== */
2525

26-
/* Request and Response Buffer Sizes */
27-
#define WH_POSIX_REQ_SIZE 2048
28-
#define WH_POSIX_RESP_SIZE 2048
26+
/* Request and Response Buffer Sizes. Must be at least
27+
* sizeof(whTransportMemCsr) + sizeof(whCommHeader) + WOLFHSM_CFG_COMM_DATA_LEN
28+
* to carry a full comm packet through the SHM transport. */
29+
#define WH_POSIX_REQ_SIZE (16 + (1024 * 8))
30+
#define WH_POSIX_RESP_SIZE (16 + (1024 * 8))
2931
#define WH_POSIX_DMA_SIZE 8000
3032

3133
/* Data Buffer Sizes */

examples/posix/wh_posix_client/wolfhsm_cfg.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
/** wolfHSM settings */
3333
#define WOLFHSM_CFG_ENABLE_CLIENT
3434
#define WOLFHSM_CFG_HEXDUMP
35-
#define WOLFHSM_CFG_COMM_DATA_LEN 5000
35+
#define WOLFHSM_CFG_COMM_DATA_LEN (1024 * 8)
3636
#ifndef WOLFHSM_CFG_NO_CRYPTO
3737
#define WOLFHSM_CFG_KEYWRAP
3838
#define WOLFHSM_CFG_GLOBAL_KEYS

examples/posix/wh_posix_server/wolfhsm_cfg.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434

3535
#define WOLFHSM_CFG_HEXDUMP
3636

37-
/* Large enough for ML-DSA level 5 key */
38-
#define WOLFHSM_CFG_COMM_DATA_LEN 5000
37+
/* Must match client WOLFHSM_CFG_COMM_DATA_LEN */
38+
#define WOLFHSM_CFG_COMM_DATA_LEN (1024 * 8)
3939

4040
#define WOLFHSM_CFG_NVM_OBJECT_COUNT 30
4141
#define WOLFHSM_CFG_SERVER_KEYCACHE_COUNT 9

src/wh_client.c

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -139,18 +139,18 @@ int wh_Client_SendRequest(whClientContext* c,
139139
uint16_t group, uint16_t action,
140140
uint16_t data_size, const void* data)
141141
{
142-
int rc = 0;
142+
int rc = 0;
143143
uint16_t req_id = 0;
144-
uint16_t kind = WH_MESSAGE_KIND(group, action);
144+
uint16_t kind = WH_MESSAGE_KIND(group, action);
145145

146146
if (c == NULL) {
147147
return WH_ERROR_BADARGS;
148148
}
149149
rc = wh_CommClient_SendRequest(c->comm, WH_COMM_MAGIC_NATIVE, kind, &req_id,
150-
data_size, data);
150+
data_size, data);
151151
if (rc == 0) {
152152
c->last_req_kind = kind;
153-
c->last_req_id = req_id;
153+
c->last_req_id = req_id;
154154
}
155155
return rc;
156156
}
@@ -159,28 +159,24 @@ int wh_Client_RecvResponse(whClientContext *c,
159159
uint16_t *out_group, uint16_t *out_action,
160160
uint16_t *out_size, void* data)
161161
{
162-
int rc = 0;
163-
uint16_t resp_magic = 0;
162+
int rc = 0;
164163
uint16_t resp_kind = 0;
165-
uint16_t resp_id = 0;
164+
uint16_t resp_id = 0;
166165
uint16_t resp_size = 0;
167166

168167
if (c == NULL) {
169168
return WH_ERROR_BADARGS;
170169
}
171170

172-
rc = wh_CommClient_RecvResponse(c->comm,
173-
&resp_magic, &resp_kind, &resp_id,
174-
&resp_size, data);
171+
/* Comm layer performs magic and sequence validation */
172+
rc = wh_CommClient_RecvResponse(c->comm, NULL, &resp_kind, &resp_id,
173+
&resp_size, data);
175174
if (rc == 0) {
176-
/* Validate response */
177-
if ( (resp_magic != WH_COMM_MAGIC_NATIVE) ||
178-
(resp_kind != c->last_req_kind) ||
179-
(resp_id != c->last_req_id) ){
180-
/* Invalid or unexpected message */
175+
if ((resp_kind != c->last_req_kind) || (resp_id != c->last_req_id)) {
176+
/* Response kind/id doesn't match outstanding request. */
181177
rc = WH_ERROR_ABORTED;
182-
} else {
183-
/* Valid and expected message. Set outputs */
178+
}
179+
else {
184180
if (out_group != NULL) {
185181
*out_group = WH_MESSAGE_GROUP(resp_kind);
186182
}
@@ -195,6 +191,14 @@ int wh_Client_RecvResponse(whClientContext *c,
195191
return rc;
196192
}
197193

194+
int wh_Client_IsRequestPending(const whClientContext* c)
195+
{
196+
if (c == NULL) {
197+
return WH_ERROR_BADARGS;
198+
}
199+
return wh_CommClient_IsRequestPending(c->comm);
200+
}
201+
198202
int wh_Client_CommInitRequest(whClientContext* c)
199203
{
200204
whMessageCommInitRequest msg = {0};

0 commit comments

Comments
 (0)