From 38dc29b059dae5cf5f4a4af0db692b81f780f104 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Wed, 14 Oct 2026 18:02:41 +0200 Subject: [PATCH 1/4] wolfHSM: add DMA_NONCOHERENT macro and support --- .github/workflows/build-and-bench.yml | 4 + .github/workflows/build-and-test-refactor.yml | 6 + .github/workflows/build-and-test.yml | 6 + benchmark/Makefile | 8 + benchmark/bench_modules/wh_bench_mod_aes.c | 51 +-- benchmark/bench_modules/wh_bench_mod_cmac.c | 8 +- benchmark/bench_modules/wh_bench_mod_hmac.c | 14 +- benchmark/bench_modules/wh_bench_mod_lms.c | 10 +- benchmark/bench_modules/wh_bench_mod_mldsa.c | 26 +- benchmark/bench_modules/wh_bench_mod_mlkem.c | 4 +- benchmark/bench_modules/wh_bench_mod_sha2.c | 18 +- benchmark/bench_modules/wh_bench_mod_sha3.c | 10 +- benchmark/bench_modules/wh_bench_mod_xmss.c | 10 +- benchmark/wh_bench_data.c | 3 +- benchmark/wh_bench_data.h | 14 +- benchmark/wh_bench_utils.h | 7 + docs/src/5-Features.md | 23 +- docs/src/6-Utilities.md | 2 + docs/src/9-Configuration.md | 7 +- port/posix/posix_transport_shm.c | 20 +- src/wh_client.c | 14 + src/wh_client_crypto.c | 54 ++- src/wh_client_cryptocb.c | 33 +- src/wh_client_dma.c | 65 +++ src/wh_utils.c | 117 +++++- test-refactor/README.md | 4 +- .../client-server/wh_test_crypto_aes.c | 8 +- .../client-server/wh_test_crypto_ecc.c | 2 +- .../client-server/wh_test_crypto_ed25519.c | 2 +- .../client-server/wh_test_crypto_keystore.c | 19 +- .../client-server/wh_test_crypto_lms.c | 6 +- .../client-server/wh_test_crypto_mldsa.c | 20 +- .../client-server/wh_test_crypto_rng.c | 8 +- .../client-server/wh_test_crypto_xmss.c | 6 +- test-refactor/client-server/wh_test_nvm_ops.c | 2 +- test-refactor/config/wolfhsm_cfg.h | 10 + test-refactor/misc/wh_test_cache.c | 144 +++++++ test-refactor/misc/wh_test_crypto_affinity.c | 6 +- test-refactor/misc/wh_test_dma_noncoherent.c | 207 +++++++++ test-refactor/misc/wh_test_multiclient.c | 10 +- test-refactor/posix/Makefile | 26 ++ test-refactor/posix/wh_test_posix_main.c | 8 + test-refactor/posix/wh_test_posix_shm_dma.c | 153 +++++++ test-refactor/wh_test_list.c | 32 +- test/Makefile | 25 ++ test/wh_test_cert.c | 4 +- test/wh_test_clientserver.c | 10 +- test/wh_test_common.h | 4 +- test/wh_test_crypto.c | 397 +++++++++++++++--- test/wh_test_dma.c | 18 +- test/wh_test_multiclient.c | 10 +- test/wh_test_nvmflags.c | 53 +-- test/wh_test_posix_threadsafe_stress.c | 24 +- wolfhsm/wh_client.h | 12 +- wolfhsm/wh_client_cryptocb.h | 3 +- wolfhsm/wh_settings.h | 82 ++++ wolfhsm/wh_utils.h | 17 +- 57 files changed, 1580 insertions(+), 286 deletions(-) create mode 100644 test-refactor/misc/wh_test_cache.c create mode 100644 test-refactor/misc/wh_test_dma_noncoherent.c create mode 100644 test-refactor/posix/wh_test_posix_shm_dma.c diff --git a/.github/workflows/build-and-bench.yml b/.github/workflows/build-and-bench.yml index e3d203acf..cea3fdf59 100644 --- a/.github/workflows/build-and-bench.yml +++ b/.github/workflows/build-and-bench.yml @@ -50,6 +50,10 @@ jobs: - name: Benchmark All run: cd benchmark && make clean && make WOLFSSL_DIR=../wolfssl DMA=1 && make run + # Benchmark DMA with non-coherent client caches (wolfCrypt DMA refused) + - name: Benchmark DMA NONCOHERENT + run: cd benchmark && make clean && make WOLFSSL_DIR=../wolfssl DMA=1 DMA_NONCOHERENT=1 && make run + # Benchmark with DEBUG_VERBOSE=1 (includes DEBUG) - name: Benchmark with DEBUG_VERBOSE run: cd benchmark && make clean && make -j DEBUG_VERBOSE=1 WOLFSSL_DIR=../wolfssl && make run diff --git a/.github/workflows/build-and-test-refactor.yml b/.github/workflows/build-and-test-refactor.yml index 365539319..357f74853 100644 --- a/.github/workflows/build-and-test-refactor.yml +++ b/.github/workflows/build-and-test-refactor.yml @@ -77,6 +77,12 @@ jobs: if: matrix.group == 'pq-dma' run: cd test-refactor/posix && make clean && make -j DMA=1 ASAN=1 WOLFSSL_DIR=../../wolfssl && make run + # Build and test DMA with non-coherent client caches (wolfCrypt DMA refused), + # aborting on DMA output buffers that are not aligned and padded. + - name: Build and test refactor DMA NONCOHERENT THREADSAFE ASAN + if: matrix.group == 'pq-dma' + run: cd test-refactor/posix && make clean && make -j THREADSAFE=1 DMA=1 DMA_NONCOHERENT=1 DMA_ALIGN_CHECK=1 ASAN=1 WOLFSSL_DIR=../../wolfssl && make run + # Build and test with NVM flash CRC16 integrity checking enabled - name: Build and test refactor NVM flash CRC ASAN run: cd test-refactor/posix && make clean && make -j NVM_FLASH_CRC=1 ASAN=1 WOLFSSL_DIR=../../wolfssl && make run diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 25171bfeb..86a02647e 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -77,6 +77,12 @@ jobs: if: matrix.group == 'pq-dma' run: cd test && make clean && make -j DMA=1 ASAN=1 WOLFSSL_DIR=../wolfssl && make run + # Build and test DMA with non-coherent client caches (wolfCrypt DMA refused), + # aborting on DMA output buffers that are not aligned and padded + - name: Build and test DMA NONCOHERENT ASAN + if: matrix.group == 'pq-dma' + run: cd test && make clean && make -j DMA=1 DMA_NONCOHERENT=1 DMA_ALIGN_CHECK=1 ASAN=1 WOLFSSL_DIR=../wolfssl && make run + # Build and test with NVM flash CRC16 integrity checking enabled - name: Build and test NVM flash CRC ASAN run: cd test && make clean && make -j NVM_FLASH_CRC=1 ASAN=1 WOLFSSL_DIR=../wolfssl && make run diff --git a/benchmark/Makefile b/benchmark/Makefile index 96ad846b7..717e453d5 100644 --- a/benchmark/Makefile +++ b/benchmark/Makefile @@ -121,6 +121,14 @@ ifeq ($(DMA),1) DEF += -DWOLFHSM_CFG_DMA endif +# DMA with non-coherent client caches (requires DMA=1) +ifeq ($(DMA_NONCOHERENT),1) + ifneq ($(DMA),1) + $(error "DMA_NONCOHERENT=1 requires DMA=1 to be set") + endif + DEF += -DWOLFHSM_CFG_DMA_NONCOHERENT +endif + # Support a SHE-capable build ifeq ($(SHE),1) DEF += -DWOLFHSM_CFG_SHE_EXTENSION diff --git a/benchmark/bench_modules/wh_bench_mod_aes.c b/benchmark/bench_modules/wh_bench_mod_aes.c index 50380fa56..3f097058b 100644 --- a/benchmark/bench_modules/wh_bench_mod_aes.c +++ b/benchmark/bench_modules/wh_bench_mod_aes.c @@ -25,6 +25,7 @@ #include "wolfssl/wolfcrypt/aes.h" #if defined(WOLFHSM_CFG_DMA) && defined(WOLFHSM_CFG_TEST_POSIX) +#include "wolfhsm/wh_utils.h" #include "port/posix/posix_transport_shm.h" #endif /* WOLFHSM_CFG_DMA && WOLFHSM_CFG_TEST_POSIX */ @@ -43,7 +44,7 @@ static const byte key256[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, enum { DECRYPT = 0, ENCRYPT = 1 }; #if defined(WOLFSSL_AES_COUNTER) -#ifdef WOLFHSM_CFG_DMA +#ifdef WH_BENCH_CRYPTOCB_DMA static int _benchAesCtrDma(whClientContext* client, whBenchOpContext* ctx, int id, const uint8_t* key, size_t keyLen, int encrypt) @@ -172,7 +173,7 @@ static int _benchAesCtrDma(whClientContext* client, whBenchOpContext* ctx, return ret; } -#endif /* WOLFHSM_CFG_DMA */ +#endif /* WH_BENCH_CRYPTOCB_DMA */ static int _benchAesCtr(whClientContext* client, whBenchOpContext* ctx, int id, const uint8_t* key, size_t keyLen, int encrypt) @@ -305,7 +306,7 @@ int wh_Bench_Mod_Aes128CTREncryptDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchAesCtrDma(client, ctx, id, (uint8_t*)key128, sizeof(key128), ENCRYPT); @@ -322,7 +323,7 @@ int wh_Bench_Mod_Aes128CTRDecryptDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchAesCtrDma(client, ctx, id, (uint8_t*)key128, sizeof(key128), DECRYPT); @@ -339,7 +340,7 @@ int wh_Bench_Mod_Aes256CTREncryptDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchAesCtrDma(client, ctx, id, (uint8_t*)key256, sizeof(key256), ENCRYPT); @@ -356,7 +357,7 @@ int wh_Bench_Mod_Aes256CTRDecryptDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchAesCtrDma(client, ctx, id, (uint8_t*)key256, sizeof(key256), DECRYPT); @@ -371,7 +372,7 @@ int wh_Bench_Mod_Aes256CTRDecryptDma(whClientContext* client, #endif /* WOLFSSL_AES_COUNTER */ #if defined(HAVE_AES_ECB) -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) static int _benchAesEcbDma(whClientContext* client, whBenchOpContext* ctx, int id, const uint8_t* key, size_t keyLen, int encrypt) @@ -503,7 +504,7 @@ static int _benchAesEcbDma(whClientContext* client, whBenchOpContext* ctx, return ret; } -#endif /* WOLFHSM_CFG_DMA */ +#endif /* WH_BENCH_CRYPTOCB_DMA */ static int _benchAesEcb(whClientContext* client, whBenchOpContext* ctx, int id, const uint8_t* key, size_t keyLen, int encrypt) @@ -642,7 +643,7 @@ int wh_Bench_Mod_Aes128ECBEncryptDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchAesEcbDma(client, ctx, id, (uint8_t*)key128, sizeof(key128), ENCRYPT); @@ -659,7 +660,7 @@ int wh_Bench_Mod_Aes128ECBDecryptDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchAesEcbDma(client, ctx, id, (uint8_t*)key128, sizeof(key128), DECRYPT); @@ -676,7 +677,7 @@ int wh_Bench_Mod_Aes256ECBEncryptDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchAesEcbDma(client, ctx, id, (uint8_t*)key256, sizeof(key256), ENCRYPT); @@ -693,7 +694,7 @@ int wh_Bench_Mod_Aes256ECBDecryptDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchAesEcbDma(client, ctx, id, (uint8_t*)key256, sizeof(key256), DECRYPT); @@ -708,7 +709,7 @@ int wh_Bench_Mod_Aes256ECBDecryptDma(whClientContext* client, #endif /* HAVE_AES_ECB */ #if defined(HAVE_AES_CBC) -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) static int _benchAesCbcDma(whClientContext* client, whBenchOpContext* ctx, int id, const uint8_t* key, size_t keyLen, int encrypt) @@ -849,7 +850,7 @@ static int _benchAesCbcDma(whClientContext* client, whBenchOpContext* ctx, return ret; } -#endif /* WOLFHSM_CFG_DMA */ +#endif /* WH_BENCH_CRYPTOCB_DMA */ static int _benchAesCbc(whClientContext* client, whBenchOpContext* ctx, int id, const uint8_t* key, size_t keyLen, int encrypt) @@ -998,7 +999,7 @@ int wh_Bench_Mod_Aes128CBCEncryptDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchAesCbcDma(client, ctx, id, (uint8_t*)key128, sizeof(key128), ENCRYPT); @@ -1015,7 +1016,7 @@ int wh_Bench_Mod_Aes128CBCDecryptDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchAesCbcDma(client, ctx, id, (uint8_t*)key128, sizeof(key128), DECRYPT); @@ -1032,7 +1033,7 @@ int wh_Bench_Mod_Aes256CBCEncryptDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchAesCbcDma(client, ctx, id, (uint8_t*)key256, sizeof(key256), ENCRYPT); @@ -1049,7 +1050,7 @@ int wh_Bench_Mod_Aes256CBCDecryptDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchAesCbcDma(client, ctx, id, (uint8_t*)key256, sizeof(key256), DECRYPT); @@ -1088,20 +1089,20 @@ static int _benchAesGcmDma(whClientContext* client, whBenchOpContext* ctx, (void)wh_Client_SetDmaMode(client, 1); #if defined(WOLFHSM_CFG_TEST_POSIX) - /* Allocate buffers using XMALLOC with heap hints for DMA */ + /* Allocate aligned, padded buffers from the DMA heap */ if (ctx->transportType == WH_BENCH_TRANSPORT_POSIX_DMA) { void* heap = posixTransportShm_GetDmaHeap(client->comm->transport_context); - in = XMALLOC(inLen, heap, DYNAMIC_TYPE_TMP_BUFFER); + in = wh_Utils_DmaAlloc(inLen, heap); if (in == NULL) { WH_BENCH_PRINTF("Failed to allocate memory for DMA input\n"); return WH_ERROR_NOSPACE; } - out = XMALLOC(inLen, heap, DYNAMIC_TYPE_TMP_BUFFER); + out = wh_Utils_DmaAlloc(inLen, heap); if (out == NULL) { WH_BENCH_PRINTF("Failed to allocate memory for DMA output\n"); - XFREE((uint8_t*)in, heap, DYNAMIC_TYPE_TMP_BUFFER); + wh_Utils_DmaFree((uint8_t*)in, heap); return WH_ERROR_NOSPACE; } } @@ -1212,11 +1213,11 @@ static int _benchAesGcmDma(whClientContext* client, whBenchOpContext* ctx, #if defined(WOLFHSM_CFG_TEST_POSIX) if (ctx->transportType == WH_BENCH_TRANSPORT_POSIX_DMA) { - /* if static memory was used with DMA then use XFREE */ + /* free the buffers allocated from the DMA heap */ void* heap = posixTransportShm_GetDmaHeap(client->comm->transport_context); - XFREE((uint8_t*)in, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(out, heap, DYNAMIC_TYPE_TMP_BUFFER); + wh_Utils_DmaFree((uint8_t*)in, heap); + wh_Utils_DmaFree(out, heap); } #endif /* WOLFHSM_CFG_TEST_POSIX */ diff --git a/benchmark/bench_modules/wh_bench_mod_cmac.c b/benchmark/bench_modules/wh_bench_mod_cmac.c index c5fe990df..a4fe7767b 100644 --- a/benchmark/bench_modules/wh_bench_mod_cmac.c +++ b/benchmark/bench_modules/wh_bench_mod_cmac.c @@ -65,7 +65,7 @@ int _benchCmacAes(whClientContext* client, whBenchOpContext* ctx, int id, } out = tag; /* default to using tag buffer on the stack */ -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) if (useDma) { inLen = WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE; #if defined(WOLFHSM_CFG_TEST_POSIX) @@ -161,7 +161,7 @@ int _benchCmacAes(whClientContext* client, whBenchOpContext* ctx, int id, ret = evictRet; } } -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) #if defined(WOLFHSM_CFG_TEST_POSIX) if (useDma && ctx->transportType == WH_BENCH_TRANSPORT_POSIX_DMA) { /* if static memory was used with DMA then use XFREE */ @@ -186,7 +186,7 @@ int wh_Bench_Mod_CmacAes128(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_CmacAes128Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchCmacAes(client, ctx, id, key128, sizeof(key128), 1); #else @@ -208,7 +208,7 @@ int wh_Bench_Mod_CmacAes256(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_CmacAes256Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchCmacAes(client, ctx, id, key256, sizeof(key256), 1); #else diff --git a/benchmark/bench_modules/wh_bench_mod_hmac.c b/benchmark/bench_modules/wh_bench_mod_hmac.c index 27bff6aab..f65c7ff63 100644 --- a/benchmark/bench_modules/wh_bench_mod_hmac.c +++ b/benchmark/bench_modules/wh_bench_mod_hmac.c @@ -45,7 +45,7 @@ int _benchHmacSha256(whClientContext* client, whBenchOpContext* ctx, int id, (void)wh_Client_SetDmaMode(client, useDma); -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) if (useDma) { in = WH_BENCH_DMA_BUFFER; inLen = WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE; @@ -136,7 +136,7 @@ int wh_Bench_Mod_HmacSha256(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_HmacSha256Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchHmacSha256(client, ctx, id, 1); #else @@ -168,7 +168,7 @@ static int _benchHmacSha3(whClientContext* client, whBenchOpContext* ctx, (void)wh_Client_SetDmaMode(client, useDma); -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) if (useDma) { in = WH_BENCH_DMA_BUFFER; inLen = WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE; @@ -261,7 +261,7 @@ int wh_Bench_Mod_HmacSha3224(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_HmacSha3224Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchHmacSha3(client, ctx, id, 1, WC_SHA3_224); #else @@ -287,7 +287,7 @@ int wh_Bench_Mod_HmacSha3256(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_HmacSha3256Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchHmacSha3(client, ctx, id, 1, WC_SHA3_256); #else @@ -313,7 +313,7 @@ int wh_Bench_Mod_HmacSha3384(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_HmacSha3384Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchHmacSha3(client, ctx, id, 1, WC_SHA3_384); #else @@ -339,7 +339,7 @@ int wh_Bench_Mod_HmacSha3512(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_HmacSha3512Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchHmacSha3(client, ctx, id, 1, WC_SHA3_512); #else diff --git a/benchmark/bench_modules/wh_bench_mod_lms.c b/benchmark/bench_modules/wh_bench_mod_lms.c index d4c0d1505..0c58fa043 100644 --- a/benchmark/bench_modules/wh_bench_mod_lms.c +++ b/benchmark/bench_modules/wh_bench_mod_lms.c @@ -30,7 +30,7 @@ * (see the vectors below) instead of generating them. The verify path is * therefore guarded only by WOLFSSL_HAVE_LMS, while keygen/sign additionally * require !WOLFSSL_LMS_VERIFY_ONLY. */ -#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_LMS) +#if defined(WH_BENCH_CRYPTOCB_DMA) && defined(WOLFSSL_HAVE_LMS) #include #include "wolfssl/wolfcrypt/random.h" @@ -563,13 +563,13 @@ static int _benchLmsSign(whClientContext* client, whBenchOpContext* ctx, int id) #endif /* !WOLFSSL_LMS_VERIFY_ONLY */ -#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_LMS */ +#endif /* WH_BENCH_CRYPTOCB_DMA && WOLFSSL_HAVE_LMS */ /* Public benchmark module functions for LMS */ int wh_Bench_Mod_LmsKeyGen(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_LMS) && \ +#if defined(WH_BENCH_CRYPTOCB_DMA) && defined(WOLFSSL_HAVE_LMS) && \ !defined(WOLFSSL_LMS_VERIFY_ONLY) (void)params; return _benchLmsKeyGen(client, ctx, id); @@ -585,7 +585,7 @@ int wh_Bench_Mod_LmsKeyGen(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_LmsSign(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_LMS) && \ +#if defined(WH_BENCH_CRYPTOCB_DMA) && defined(WOLFSSL_HAVE_LMS) && \ !defined(WOLFSSL_LMS_VERIFY_ONLY) (void)params; return _benchLmsSign(client, ctx, id); @@ -601,7 +601,7 @@ int wh_Bench_Mod_LmsSign(whClientContext* client, whBenchOpContext* ctx, int id, int wh_Bench_Mod_LmsVerify(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_LMS) +#if defined(WH_BENCH_CRYPTOCB_DMA) && defined(WOLFSSL_HAVE_LMS) (void)params; return _benchLmsVerify(client, ctx, id); #else diff --git a/benchmark/bench_modules/wh_bench_mod_mldsa.c b/benchmark/bench_modules/wh_bench_mod_mldsa.c index 2ef651610..9ab6fd117 100644 --- a/benchmark/bench_modules/wh_bench_mod_mldsa.c +++ b/benchmark/bench_modules/wh_bench_mod_mldsa.c @@ -2514,14 +2514,14 @@ static int _benchMlDsaSign(whClientContext* client, whBenchOpContext* ctx, } /* Import key to the HSM */ -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) if (useDma) { ret = wh_Client_MlDsaImportKeyDma(client, &key, &keyId, WH_NVM_FLAGS_USAGE_ANY, strlen(keyLabel), (uint8_t*)keyLabel); } else -#endif /* !(WOLFHSM_CFG_DMA) */ +#endif /* !(WH_BENCH_CRYPTOCB_DMA) */ { ret = wh_Client_MlDsaImportKey(client, &key, &keyId, WH_NVM_FLAGS_USAGE_ANY, strlen(keyLabel), @@ -2700,14 +2700,14 @@ static int _benchMlDsaVerify(whClientContext* client, whBenchOpContext* ctx, } /* Import key to the HSM */ -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) if (useDma) { ret = wh_Client_MlDsaImportKeyDma(client, &key, &keyId, WH_NVM_FLAGS_USAGE_ANY, strlen(keyLabel), (uint8_t*)keyLabel); } else -#endif /* !(WOLFHSM_CFG_DMA) */ +#endif /* !(WH_BENCH_CRYPTOCB_DMA) */ { ret = wh_Client_MlDsaImportKey(client, &key, &keyId, WH_NVM_FLAGS_USAGE_ANY, strlen(keyLabel), @@ -2887,7 +2887,7 @@ int wh_Bench_Mod_MlDsa44Sign(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_MlDsa44SignDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFSSL_MLDSA_NO_SIGN) +#if defined(WH_BENCH_CRYPTOCB_DMA) && !defined(WOLFSSL_MLDSA_NO_SIGN) (void)params; return _benchMlDsaSign(client, ctx, id, WC_ML_DSA_44, 1); #else @@ -2918,7 +2918,7 @@ int wh_Bench_Mod_MlDsa44Verify(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_MlDsa44VerifyDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFSSL_MLDSA_NO_VERIFY) +#if defined(WH_BENCH_CRYPTOCB_DMA) && !defined(WOLFSSL_MLDSA_NO_VERIFY) (void)params; return _benchMlDsaVerify(client, ctx, id, WC_ML_DSA_44, 1); #else @@ -2949,7 +2949,7 @@ int wh_Bench_Mod_MlDsa44KeyGen(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_MlDsa44KeyGenDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) +#if defined(WH_BENCH_CRYPTOCB_DMA) && !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) (void)params; return _benchMlDsaKeyGen(client, ctx, id, WC_ML_DSA_44, 1); #else @@ -2983,7 +2983,7 @@ int wh_Bench_Mod_MlDsa65Sign(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_MlDsa65SignDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFSSL_MLDSA_NO_SIGN) +#if defined(WH_BENCH_CRYPTOCB_DMA) && !defined(WOLFSSL_MLDSA_NO_SIGN) (void)params; return _benchMlDsaSign(client, ctx, id, WC_ML_DSA_65, 1); #else @@ -3014,7 +3014,7 @@ int wh_Bench_Mod_MlDsa65Verify(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_MlDsa65VerifyDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFSSL_MLDSA_NO_VERIFY) +#if defined(WH_BENCH_CRYPTOCB_DMA) && !defined(WOLFSSL_MLDSA_NO_VERIFY) (void)params; return _benchMlDsaVerify(client, ctx, id, WC_ML_DSA_65, 1); #else @@ -3045,7 +3045,7 @@ int wh_Bench_Mod_MlDsa65KeyGen(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_MlDsa65KeyGenDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) +#if defined(WH_BENCH_CRYPTOCB_DMA) && !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) (void)params; return _benchMlDsaKeyGen(client, ctx, id, WC_ML_DSA_65, 1); #else @@ -3079,7 +3079,7 @@ int wh_Bench_Mod_MlDsa87Sign(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_MlDsa87SignDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFSSL_MLDSA_NO_SIGN) +#if defined(WH_BENCH_CRYPTOCB_DMA) && !defined(WOLFSSL_MLDSA_NO_SIGN) (void)params; return _benchMlDsaSign(client, ctx, id, WC_ML_DSA_87, 1); #else @@ -3110,7 +3110,7 @@ int wh_Bench_Mod_MlDsa87Verify(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_MlDsa87VerifyDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFSSL_MLDSA_NO_VERIFY) +#if defined(WH_BENCH_CRYPTOCB_DMA) && !defined(WOLFSSL_MLDSA_NO_VERIFY) (void)params; return _benchMlDsaVerify(client, ctx, id, WC_ML_DSA_87, 1); #else @@ -3141,7 +3141,7 @@ int wh_Bench_Mod_MlDsa87KeyGen(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_MlDsa87KeyGenDma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) +#if defined(WH_BENCH_CRYPTOCB_DMA) && !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) (void)params; return _benchMlDsaKeyGen(client, ctx, id, WC_ML_DSA_87, 1); #else diff --git a/benchmark/bench_modules/wh_bench_mod_mlkem.c b/benchmark/bench_modules/wh_bench_mod_mlkem.c index 165f18581..7bc7620c7 100644 --- a/benchmark/bench_modules/wh_bench_mod_mlkem.c +++ b/benchmark/bench_modules/wh_bench_mod_mlkem.c @@ -142,7 +142,7 @@ static int _benchMlKemEncaps(whClientContext* client, whBenchOpContext* ctx, int ret = WH_ERROR_OK; int i; MlKemKey key[1]; - byte ct[WC_ML_KEM_MAX_CIPHER_TEXT_SIZE]; + WH_DMA_ALIGNED byte ct[WH_DMA_PAD_SIZE(WC_ML_KEM_MAX_CIPHER_TEXT_SIZE)]; byte ss[WC_ML_KEM_SS_SZ]; whKeyId keyId = WH_KEYID_ERASED; @@ -206,7 +206,7 @@ static int _benchMlKemDecaps(whClientContext* client, whBenchOpContext* ctx, int ret = WH_ERROR_OK; int i; MlKemKey key[1]; - byte ct[WC_ML_KEM_MAX_CIPHER_TEXT_SIZE]; + WH_DMA_ALIGNED byte ct[WH_DMA_PAD_SIZE(WC_ML_KEM_MAX_CIPHER_TEXT_SIZE)]; byte ssEnc[WC_ML_KEM_SS_SZ]; byte ssDec[WC_ML_KEM_SS_SZ]; uint32_t ctLen = sizeof(ct); diff --git a/benchmark/bench_modules/wh_bench_mod_sha2.c b/benchmark/bench_modules/wh_bench_mod_sha2.c index 53b31f5a2..9e15b86ed 100644 --- a/benchmark/bench_modules/wh_bench_mod_sha2.c +++ b/benchmark/bench_modules/wh_bench_mod_sha2.c @@ -49,7 +49,7 @@ int _benchSha256(whClientContext* client, whBenchOpContext* ctx, int id, (void)wh_Client_SetDmaMode(client, useDma); -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) if (useDma) { inLen = WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE; #if defined(WOLFHSM_CFG_TEST_POSIX) @@ -142,7 +142,7 @@ int _benchSha256(whClientContext* client, whBenchOpContext* ctx, int id, (void)wc_Sha256Free(sha256); } -#if defined(WOLFHSM_CFG_DMA) && defined(WOLFHSM_CFG_TEST_POSIX) +#if defined(WH_BENCH_CRYPTOCB_DMA) && defined(WOLFHSM_CFG_TEST_POSIX) if (useDma && ctx->transportType == WH_BENCH_TRANSPORT_POSIX_DMA) { /* if static memory was used with DMA then use XFREE */ void* heap = @@ -164,7 +164,7 @@ int wh_Bench_Mod_Sha256(whClientContext* client, whBenchOpContext* ctx, int id, int wh_Bench_Mod_Sha256Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchSha256(client, ctx, id, 1); #else @@ -194,7 +194,7 @@ int _benchSha224(whClientContext* client, whBenchOpContext* ctx, int id, (void)wh_Client_SetDmaMode(client, useDma); -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) if (useDma) { in = WH_BENCH_DMA_BUFFER; inLen = WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE; @@ -278,7 +278,7 @@ int wh_Bench_Mod_Sha224(whClientContext* client, whBenchOpContext* ctx, int id, int wh_Bench_Mod_Sha224Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchSha224(client, ctx, id, 1); #else @@ -307,7 +307,7 @@ int _benchSha384(whClientContext* client, whBenchOpContext* ctx, int id, (void)wh_Client_SetDmaMode(client, useDma); -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) if (useDma) { in = WH_BENCH_DMA_BUFFER; inLen = WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE; @@ -391,7 +391,7 @@ int wh_Bench_Mod_Sha384(whClientContext* client, whBenchOpContext* ctx, int id, int wh_Bench_Mod_Sha384Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchSha384(client, ctx, id, 1); #else @@ -419,7 +419,7 @@ int _benchSha512(whClientContext* client, whBenchOpContext* ctx, int id, (void)wh_Client_SetDmaMode(client, useDma); -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) if (useDma) { in = WH_BENCH_DMA_BUFFER; inLen = WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE; @@ -503,7 +503,7 @@ int wh_Bench_Mod_Sha512(whClientContext* client, whBenchOpContext* ctx, int id, int wh_Bench_Mod_Sha512Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchSha512(client, ctx, id, 1); #else diff --git a/benchmark/bench_modules/wh_bench_mod_sha3.c b/benchmark/bench_modules/wh_bench_mod_sha3.c index fe9073ef3..7e29f0801 100644 --- a/benchmark/bench_modules/wh_bench_mod_sha3.c +++ b/benchmark/bench_modules/wh_bench_mod_sha3.c @@ -73,7 +73,7 @@ static int _benchSha3(whClientContext* client, whBenchOpContext* ctx, int id, (void)wh_Client_SetDmaMode(client, useDma); -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) if (useDma) { in = WH_BENCH_DMA_BUFFER; inLen = WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE; @@ -159,7 +159,7 @@ int wh_Bench_Mod_Sha3224(whClientContext* client, whBenchOpContext* ctx, int id, int wh_Bench_Mod_Sha3224Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchSha3(client, ctx, id, 1, &benchSha3_224); #else @@ -185,7 +185,7 @@ int wh_Bench_Mod_Sha3256(whClientContext* client, whBenchOpContext* ctx, int id, int wh_Bench_Mod_Sha3256Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchSha3(client, ctx, id, 1, &benchSha3_256); #else @@ -211,7 +211,7 @@ int wh_Bench_Mod_Sha3384(whClientContext* client, whBenchOpContext* ctx, int id, int wh_Bench_Mod_Sha3384Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchSha3(client, ctx, id, 1, &benchSha3_384); #else @@ -237,7 +237,7 @@ int wh_Bench_Mod_Sha3512(whClientContext* client, whBenchOpContext* ctx, int id, int wh_Bench_Mod_Sha3512Dma(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) +#if defined(WH_BENCH_CRYPTOCB_DMA) (void)params; return _benchSha3(client, ctx, id, 1, &benchSha3_512); #else diff --git a/benchmark/bench_modules/wh_bench_mod_xmss.c b/benchmark/bench_modules/wh_bench_mod_xmss.c index eb61b07d3..df3d7e235 100644 --- a/benchmark/bench_modules/wh_bench_mod_xmss.c +++ b/benchmark/bench_modules/wh_bench_mod_xmss.c @@ -30,7 +30,7 @@ * (see the vectors below) instead of generating them. The verify path is * therefore guarded only by WOLFSSL_HAVE_XMSS, while keygen/sign additionally * require !WOLFSSL_XMSS_VERIFY_ONLY. */ -#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_XMSS) +#if defined(WH_BENCH_CRYPTOCB_DMA) && defined(WOLFSSL_HAVE_XMSS) #include #include "wolfssl/wolfcrypt/random.h" @@ -663,13 +663,13 @@ static int _benchXmssSign(whClientContext* client, whBenchOpContext* ctx, #endif /* !WOLFSSL_XMSS_VERIFY_ONLY */ -#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_XMSS */ +#endif /* WH_BENCH_CRYPTOCB_DMA && WOLFSSL_HAVE_XMSS */ /* Public benchmark module functions for XMSS */ int wh_Bench_Mod_XmssKeyGen(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_XMSS) && \ +#if defined(WH_BENCH_CRYPTOCB_DMA) && defined(WOLFSSL_HAVE_XMSS) && \ !defined(WOLFSSL_XMSS_VERIFY_ONLY) (void)params; return _benchXmssKeyGen(client, ctx, id); @@ -685,7 +685,7 @@ int wh_Bench_Mod_XmssKeyGen(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_XmssSign(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_XMSS) && \ +#if defined(WH_BENCH_CRYPTOCB_DMA) && defined(WOLFSSL_HAVE_XMSS) && \ !defined(WOLFSSL_XMSS_VERIFY_ONLY) (void)params; return _benchXmssSign(client, ctx, id); @@ -701,7 +701,7 @@ int wh_Bench_Mod_XmssSign(whClientContext* client, whBenchOpContext* ctx, int wh_Bench_Mod_XmssVerify(whClientContext* client, whBenchOpContext* ctx, int id, void* params) { -#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_XMSS) +#if defined(WH_BENCH_CRYPTOCB_DMA) && defined(WOLFSSL_HAVE_XMSS) (void)params; return _benchXmssVerify(client, ctx, id); #else diff --git a/benchmark/wh_bench_data.c b/benchmark/wh_bench_data.c index 1103bc2d8..2ef889606 100644 --- a/benchmark/wh_bench_data.c +++ b/benchmark/wh_bench_data.c @@ -28,7 +28,8 @@ uint8_t wh_bench_data_out_buffer[WOLFHSM_CFG_BENCH_DATA_BUFFER_SIZE] = {0}; #if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_BENCH_CUSTOM_DMA_BUFFER) /* Define the DMA buffer if using built-in buffer */ -uint8_t wh_bench_data_dma_buffer[WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE] = {0}; +WH_DMA_ALIGNED uint8_t + wh_bench_data_dma_buffer[WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE] = {0}; #endif #endif /* WOLFHSM_CFG_BENCH_ENABLE */ \ No newline at end of file diff --git a/benchmark/wh_bench_data.h b/benchmark/wh_bench_data.h index 12b7f5a72..2893a02b9 100644 --- a/benchmark/wh_bench_data.h +++ b/benchmark/wh_bench_data.h @@ -45,13 +45,23 @@ extern uint8_t wh_bench_data_out_buffer[WOLFHSM_CFG_BENCH_DATA_BUFFER_SIZE]; #define WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE 0x8000 #endif +/* The AES modules split the buffer into an input half and an output half, each + * of which must start on a line boundary with non-coherent DMA */ +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#if (WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE % (2 * WOLFHSM_CFG_DMA_ALIGN)) != 0 +#error \ + "WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE must be a multiple of 2 * WOLFHSM_CFG_DMA_ALIGN" +#endif +#endif + /* Allow the user to define a custom DMA buffer of size - * WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE */ + * WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE, aligned to WOLFHSM_CFG_DMA_ALIGN */ #if defined(WOLFHSM_CFG_BENCH_CUSTOM_DMA_BUFFER) #define WH_BENCH_DMA_BUFFER ((void*)WOLFHSM_CFG_BENCH_CUSTOM_DMA_BUFFER) #else /* built-in buffer for DMA operations */ -extern uint8_t wh_bench_data_dma_buffer[WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE]; +extern WH_DMA_ALIGNED uint8_t + wh_bench_data_dma_buffer[WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE]; #define WH_BENCH_DMA_BUFFER wh_bench_data_dma_buffer #endif diff --git a/benchmark/wh_bench_utils.h b/benchmark/wh_bench_utils.h index a2a2f158d..f79553f0d 100644 --- a/benchmark/wh_bench_utils.h +++ b/benchmark/wh_bench_utils.h @@ -31,4 +31,11 @@ #define WH_BENCH_SNPRINTF snprintf #endif +/* wolfHSM refuses DMA through wolfCrypt with WOLFHSM_CFG_DMA_NONCOHERENT, so + * the benchmarks of that path are only built without it. Benchmarks of the + * direct wh_Client_*Dma APIs only depend on WOLFHSM_CFG_DMA. */ +#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_DMA_NONCOHERENT) +#define WH_BENCH_CRYPTOCB_DMA +#endif + #endif /* WH_BENCH_UTILS_H_ */ \ No newline at end of file diff --git a/docs/src/5-Features.md b/docs/src/5-Features.md index 1712db43e..11461cd6b 100644 --- a/docs/src/5-Features.md +++ b/docs/src/5-Features.md @@ -39,6 +39,7 @@ This chapter provides a detailed overview of the high level features that wolfHS - [DMA Dispatch Mode (`wh_Client_SetDmaMode`)](#dma-dispatch-mode-wh_client_setdmamode) - [Pre-Access and Post-Access Callbacks](#pre-access-and-post-access-callbacks) - [Address Allowlisting](#address-allowlisting) + - [Non-Coherent Caches and Buffer Alignment](#non-coherent-caches-and-buffer-alignment) - [32-bit vs. 64-bit Address Handling](#32-bit-vs-64-bit-address-handling) - [AUTOSAR SHE Subsystem](#autosar-she-subsystem) - [Client API and Command Set](#client-api-and-command-set) @@ -91,7 +92,7 @@ The wolfHSM client library registers a crypto callback that turns each supported In addition to the configured per-client ID, every `wh_Client_Init()` registers the two process-global device IDs: - `WH_DEV_ID` is registered with the same unified callback as a configured `devId`, so it behaves identically — including honoring the [DMA dispatch mode](#dma-dispatch-mode-wh_client_setdmamode). It is also the ID a client is bound to when its config leaves `.devId` 0. -- `WH_DEV_ID_DMA` (present only with `WOLFHSM_CFG_DMA`) is registered with the DMA-only callback: operations always use the DMA request forms, and algorithms without a DMA variant fail rather than falling back to the standard path. It is reserved for this purpose and is not valid as a configured `.devId`. +- `WH_DEV_ID_DMA` (present only with `WOLFHSM_CFG_DMA`) is registered with the DMA-only callback: operations always use the DMA request forms, and algorithms without a DMA variant fail rather than falling back to the standard path. It is reserved for this purpose and is not valid as a configured `.devId`. With `WOLFHSM_CFG_DMA_NONCOHERENT` every operation on it fails (see [Non-Coherent Caches and Buffer Alignment](#non-coherent-caches-and-buffer-alignment)). The global IDs preserve the behavior of earlier wolfHSM releases: an application with a **single client per process** needs no devId configuration at all and can keep passing `WH_DEV_ID` (or `WH_DEV_ID_DMA`) straight to wolfCrypt functions, exactly as before — they are always registered and available after `wh_Client_Init()`. Because these registrations are process-global and keyed on the integer value, each `wh_Client_Init()` rebinds them to the most recently initialized client, and **any** client's `wh_Client_Cleanup()` unregisters them. In a multi-client process they are therefore unreliable and should not be passed to wolfCrypt; use the per-client configured IDs instead. Both values are overridable at compile time (see [Configuration](9-Configuration.md#cryptography-features)). @@ -642,7 +643,7 @@ The motivating use cases all involve payloads that are either too large or too i ### DMA Dispatch Mode (`wh_Client_SetDmaMode`) -For wolfCrypt-mediated operations, opt-in to DMA is a per-client dispatch mode rather than a separate device ID: the application calls `wh_Client_SetDmaMode(client, 1)` (or sets `.preferDma` in the client's `whClientDmaConfig` at init), and subsequent wolfCrypt calls made with `WH_CLIENT_DEVID(client)` construct DMA-flavored requests whose payloads carry pointers and lengths into the client's address space rather than inline data. The server-side dispatcher recognizes the DMA request kind and, for each referenced buffer, hands the pointer to the server's DMA address-processing path (described below) before invoking the underlying wolfCrypt primitive. The set of algorithms that have a DMA path mirrors the most performance-sensitive subset of the supported algorithms; with DMA mode preferred, an algorithm without a DMA path automatically falls back to the standard (non-DMA) request, so no call-site changes are needed. The mode can be toggled at any time — `wh_Client_SetDmaMode(client, 0)` returns the client to standard dispatch, and `wh_Client_GetDmaMode()` reads the current setting. +For wolfCrypt-mediated operations, opt-in to DMA is a per-client dispatch mode rather than a separate device ID: the application calls `wh_Client_SetDmaMode(client, 1)` (or sets `.preferDma` in the client's `whClientDmaConfig` at init), and subsequent wolfCrypt calls made with `WH_CLIENT_DEVID(client)` construct DMA-flavored requests whose payloads carry pointers and lengths into the client's address space rather than inline data. The server-side dispatcher recognizes the DMA request kind and, for each referenced buffer, hands the pointer to the server's DMA address-processing path (described below) before invoking the underlying wolfCrypt primitive. The set of algorithms that have a DMA path mirrors the most performance-sensitive subset of the supported algorithms; with DMA mode preferred, an algorithm without a DMA path automatically falls back to the standard (non-DMA) request, so no call-site changes are needed. The mode can be toggled at any time — `wh_Client_SetDmaMode(client, 0)` returns the client to standard dispatch, and `wh_Client_GetDmaMode()` reads the current setting. With `WOLFHSM_CFG_DMA_NONCOHERENT` the DMA dispatch mode cannot be enabled (see [Non-Coherent Caches and Buffer Alignment](#non-coherent-caches-and-buffer-alignment)). The global `WH_DEV_ID_DMA` device ID is also always registered when `WOLFHSM_CFG_DMA` is enabled and always produces DMA-flavored requests for the most recently initialized client; unlike the DMA dispatch mode, it does not fall back to the standard path for algorithms without a DMA variant. See [Transparent Offload via Crypto Callbacks](#transparent-offload-via-crypto-callbacks) for the global device IDs' single-client-per-process scope. @@ -688,6 +689,24 @@ When the allowlist is not registered the server allows every address, which is a A symmetric `whDmaAddrAllowList` is also available on the client side for clients that wish to validate addresses locally before issuing a DMA request (`whClientDmaConfig::dmaAddrAllowList`). Client-side validation is advisory — the server's check is the authoritative one — but it lets a client fail fast when its own code accidentally constructs an out-of-range pointer. +### Non-Coherent Caches and Buffer Alignment + +When the client's memory is cached and the hardware does not keep that cache coherent with the server's accesses, the port's client DMA callback has to clean the cache lines before the server accesses a buffer and invalidate them after the server has written it (`WH_DMA_OPER_CLIENT_WRITE_POST`). Cache maintenance works on whole lines, so a buffer the server writes must not share a line with other data: an invalidate would discard the CPU's writes to that data, and an eviction could overwrite the server's. + +Define `WOLFHSM_CFG_DMA_NONCOHERENT` for these targets. Every buffer the server writes must then start on a `WOLFHSM_CFG_DMA_ALIGN` boundary (default `XCACHELINE`) and be padded to a multiple of it. The length passed to the API stays the real length: + +```c +WH_DMA_ALIGNED uint8_t cipher[WH_DMA_PAD_SIZE(sizeof(plain))]; + +ret = wh_Client_AesCtrDma(client, aes, 1, plain, sizeof(plain), cipher); +``` + +`WH_DMA_ALIGNED` and `WH_DMA_PAD_SIZE()` are no-ops without `WOLFHSM_CFG_DMA_NONCOHERENT`. wolfHSM's own internal output buffers follow the rule. For caller buffers, the port's callback can check the start with `WH_DMA_IS_ALIGNED()` (as `posixTransportShm_ClientStaticMemDmaCallback` does for buffers it uses in place) or copy through a bounce buffer from `wh_Utils_DmaAlloc()`; padding cannot be checked. + +Test builds can define `WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK` (`make DMA_ALIGN_CHECK=1` in `test/` and `test-refactor/posix/`) to abort on any output buffer that does not start on a `WOLFHSM_CFG_DMA_ALIGN` boundary or, in ASAN builds, is not padded to a multiple of it. The check runs in `wh_Client_DmaProcessClientAddress`, so it covers wolfHSM's own buffers and every buffer the tests pass, whatever DMA callback the client registers. The make option also raises `WOLFHSM_CFG_DMA_ALIGN` to 256, so a buffer missing `WH_DMA_ALIGNED` does not pass by being aligned by chance. + +wolfCrypt passes the crypto callback buffers it does not control, such as its own stack and structure buffers, so with `WOLFHSM_CFG_DMA_NONCOHERENT` wolfHSM refuses DMA through wolfCrypt: every operation on `WH_DEV_ID_DMA` fails with `WC_HW_E`, and `whClientDmaConfig::preferDma` and `wh_Client_SetDmaMode(client, 1)` fail with `WH_ERROR_BADARGS`. Use `WH_DEV_ID` (or the client's configured devId) for wolfCrypt, and call the `wh_Client_*Dma` APIs directly where zero-copy matters. LMS and XMSS have no non-DMA path, so with this option they are available only through the `wh_Client_Lms*Dma` and `wh_Client_Xmss*Dma` APIs. + ### 32-bit vs. 64-bit Address Handling The DMA path is designed so that a 32-bit client can interoperate with a 64-bit server, and vice versa, without either side losing information. All DMA pointers on the wire are 64-bit (`uint64_t`) regardless of the native pointer size on either endpoint: the client zero-extends its address into the request and the server narrows on receipt if its pointers are 32-bit (with an overflow check that rejects out-of-range values). The runtime callback signatures use `uintptr_t` so the platform's native pointer width drives address translation. The build distinguishes the two cases via `WH_DMA_IS_32BIT` and `WH_DMA_IS_64BIT`, derived automatically from the system pointer size or set explicitly via `WOLFHSM_CFG_DMA_PTR_SIZE` when the build needs to override that default. diff --git a/docs/src/6-Utilities.md b/docs/src/6-Utilities.md index ac3b578d1..2aa1564ea 100644 --- a/docs/src/6-Utilities.md +++ b/docs/src/6-Utilities.md @@ -53,6 +53,8 @@ make DMA=1 make run ``` +Add `DMA_NONCOHERENT=1` (with `DMA=1`) to build with `WOLFHSM_CFG_DMA_NONCOHERENT`; the benchmarks of DMA through wolfCrypt are then skipped. + ### Running Benchmarks on Real Hardware diff --git a/docs/src/9-Configuration.md b/docs/src/9-Configuration.md index 75f843737..1927d624c 100644 --- a/docs/src/9-Configuration.md +++ b/docs/src/9-Configuration.md @@ -141,6 +141,8 @@ These macros gate and tune DMA-mode crypto and large-buffer operations. | `WOLFHSM_CFG_DMA_PTR_SIZE` | Compiler-detected (`__SIZEOF_POINTER__`) | Override the assumed DMA pointer size, in bytes (must be `4` or `8`). Auto-detection works for GCC/Clang and IAR; define this explicitly for any toolchain that does not provide `__SIZEOF_POINTER__`. | | `WOLFHSM_CFG_DMA_ALT_PTR_SIZE` | Undefined | If defined, allows the DMA pointer size to differ from the native CPU pointer size (e.g. a 32-bit-pointer server reachable from a 64-bit-pointer client). When undefined, wh_settings.h refuses to build with a mismatched `WOLFHSM_CFG_DMA_PTR_SIZE`. | | `WOLFHSM_CFG_DMA_INLINE_AAD_MAX_SIZE` | `128` | Largest additional authenticated data, in bytes, that a DMA AEAD request can carry inside the message (through the transport) instead of over DMA. An AAD above this size is passed as a DMA buffer. | +| `WOLFHSM_CFG_DMA_NONCOHERENT` | Undefined | Define when client memory the server writes over DMA is cached and not kept coherent by the hardware. Output buffers of the `wh_Client_*Dma` APIs must then be aligned and padded to `WOLFHSM_CFG_DMA_ALIGN`, and DMA through wolfCrypt is refused (`WH_DEV_ID_DMA` fails with `WC_HW_E`, `preferDma` cannot be enabled). Requires `WOLFHSM_CFG_DMA`. Set by `DMA_NONCOHERENT=1` in the test and benchmark builds. See [Non-Coherent Caches and Buffer Alignment](5-Features.md#non-coherent-caches-and-buffer-alignment). | +| `WOLFHSM_CFG_DMA_ALIGN` | `XCACHELINE` | Alignment and padding, in bytes, of client buffers the server writes over DMA. A power of two and a multiple of `XCACHELINE`. Only used with `WOLFHSM_CFG_DMA_NONCOHERENT`. | | `WOLFHSM_CFG_DMA_CUSTOM_CLIENT_COPY` | Undefined | If defined, expose hooks that let the integrator override the client-to-server and server-to-client memory copy used during DMA requests. Useful when DMA buffers live in shared memory that requires custom invalidation or cache maintenance beyond the standard `XCACHE*` macros. | ## Authentication @@ -202,7 +204,7 @@ These macros are consumed only when building the wolfHSM benchmark suite (`bench ## Test Harness -These macros are consumed only by the wolfHSM test suite (`test/`) and its supporting infrastructure. They have no effect on a release build of the library. Most are toggled by `make` variables in `test/Makefile` (e.g. `make DMA=1 THREADSAFE=1 STRESS=1`). +These macros are only meant for the wolfHSM test suites (`test/`, `test-refactor/`) and their supporting infrastructure, and are never defined in a release build of the library. Most are toggled by `make` variables in `test/Makefile` (e.g. `make DMA=1 THREADSAFE=1 STRESS=1`). | Macro | Default | Description | |---|---|---| @@ -219,6 +221,7 @@ These macros are consumed only by the wolfHSM test suite (`test/`) and its suppo | `WOLFHSM_CFG_TEST_ASSERT_FUNC` | stdlib `assert()` | If defined, overrides the macro used by the test harness to evaluate `WH_TEST_ASSERT(...)`. Useful for redirecting assertion failures into a target-specific failure reporter. | | `WOLFHSM_CFG_TEST_ALLOW_PERSISTENT_NVM_ARTIFACTS` | Undefined | If defined, NVM-touching tests are allowed to leave persistent artifacts behind (objects, counters, keys) between runs, which lets a separate test phase verify them. Otherwise NVM is reset between tests. Used by the POSIX test build. | | `WOLFHSM_CFG_TEST_CRYPTSVR_CFG` | Implicitly defined | The crypto-server test pulls in its standard wolfCrypt test configuration unless `NO_WOLFHSM_CFG_TEST_CRYPTSVR_CFG` is defined at build time, in which case the integrator must supply their own configuration. | +| `WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK` | Undefined | If defined, `wh_Client_DmaProcessClientAddress` aborts when a client buffer the server writes over DMA does not start on a `WOLFHSM_CFG_DMA_ALIGN` boundary or, in ASAN builds, is not padded to a multiple of it, printing the buffer and the call that passed it. Requires `WOLFHSM_CFG_DMA_NONCOHERENT`. Set, together with `WOLFHSM_CFG_DMA_ALIGN=256`, by the `DMA_ALIGN_CHECK=1` make variable. See [Non-Coherent Caches and Buffer Alignment](5-Features.md#non-coherent-caches-and-buffer-alignment). | | `WOLFHSM_CFG_IS_TEST_SERVER` | Undefined | If defined, the client-side unit tests assume they are talking to a server that is running additional test-only instrumentation (exercising edge cases that cannot be triggered against a standard server). Set automatically for the combined client/server POSIX test build; should not be defined outside of that harness. | ## Memory and Cache Porting Macros @@ -226,7 +229,7 @@ These macros are consumed only by the wolfHSM test suite (`test/`) and its suppo For completeness, wolfHSM also relies on a small number of `X*` porting macros that are normally supplied alongside the `WOLFHSM_CFG_*` macros in `wolfhsm_cfg.h` even though they do not share the prefix: - `XMEMFENCE()` — sequential memory fence (defaults to `__atomic_thread_fence(__ATOMIC_SEQ_CST)` on GCC/Clang; otherwise a no-op with a build warning). -- `XCACHELINE` — cache-line size in bytes (default `32`). +- `XCACHELINE` — cache-line size in bytes (default `32`). Must be usable in `#if` with `WOLFHSM_CFG_DMA_NONCOHERENT`. - `XCACHEFLUSH(p)` / `XCACHEFLUSHBLK(p, n)` — flush one line / a range; defaults are no-op and `wh_Utils_CacheFlush` respectively. - `XCACHEINVLD(p)` / `XCACHEINVLDBLK(p, n)` — invalidate one line / a range; defaults are no-op and `wh_Utils_CacheInvalidate` respectively. diff --git a/port/posix/posix_transport_shm.c b/port/posix/posix_transport_shm.c index e982a4640..c29d43389 100644 --- a/port/posix/posix_transport_shm.c +++ b/port/posix/posix_transport_shm.c @@ -604,6 +604,13 @@ int posixTransportShm_RecvResponse(void* c, uint16_t* out_len, void* data) * the POSIX shared memory transport. */ +/* Client buffers outside the DMA area are copied through a bounce buffer: + * from wh_Utils_DmaAlloc for output, which the server writes, and from XMALLOC + * for input, which needs no cache-line isolation. Buffers in the DMA area are + * used in place; with WOLFHSM_CFG_DMA_NONCOHERENT an in-place output buffer + * must be aligned to WOLFHSM_CFG_DMA_ALIGN (its padding cannot be checked). + * POSIX needs no cache maintenance. */ + int posixTransportShm_ClientStaticMemDmaCallback( struct whClientContext_t* client, uintptr_t clientAddr, void** xformedCliAddr, size_t len, whDmaOper oper, whDmaFlags flags) @@ -645,7 +652,10 @@ int posixTransportShm_ClientStaticMemDmaCallback( if (oper == WH_DMA_OPER_CLIENT_READ_PRE || oper == WH_DMA_OPER_CLIENT_WRITE_PRE) { if (isInDma == 0) { - dmaBuffer = (uintptr_t)XMALLOC(len, heap, DYNAMIC_TYPE_TMP_BUFFER); + dmaBuffer = + (oper == WH_DMA_OPER_CLIENT_WRITE_PRE) + ? (uintptr_t)wh_Utils_DmaAlloc(len, heap) + : (uintptr_t)XMALLOC(len, heap, DYNAMIC_TYPE_TMP_BUFFER); if (dmaBuffer == 0) { return WH_ERROR_NOSPACE; } @@ -653,6 +663,12 @@ int posixTransportShm_ClientStaticMemDmaCallback( memcpy((void*)dmaBuffer, (void*)clientAddr, len); } else { +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT + if ((oper == WH_DMA_OPER_CLIENT_WRITE_PRE) && + !WH_DMA_IS_ALIGNED(clientAddr)) { + return WH_ERROR_BADARGS; + } +#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ dmaOffset = clientAddr - (uintptr_t)dmaPtr; } /* return an offset into the DMA area */ @@ -669,7 +685,7 @@ int posixTransportShm_ClientStaticMemDmaCallback( uint8_t* ptr = (uint8_t*)dmaPtr + (uintptr_t)*xformedCliAddr; memcpy((void*)clientAddr, ptr, len); /* copy results of what server wrote */ - XFREE(ptr, heap, DYNAMIC_TYPE_TMP_BUFFER); + wh_Utils_DmaFree(ptr, heap); } } diff --git a/src/wh_client.c b/src/wh_client.c index c4aa20e65..0d36eddbe 100644 --- a/src/wh_client.c +++ b/src/wh_client.c @@ -91,6 +91,13 @@ int wh_Client_Init(whClientContext* c, const whClientConfig* config) if (config->devId == WH_DEV_ID_DMA) { return WH_ERROR_BADARGS; } +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT + /* wolfCrypt cannot use DMA with non-coherent caches, see + * wh_Client_CryptoCbDma */ + if ((config->dmaConfig != NULL) && (config->dmaConfig->preferDma != 0)) { + return WH_ERROR_BADARGS; + } +#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ #endif /* WOLFHSM_CFG_DMA */ #endif /* !WOLFHSM_CFG_NO_CRYPTO */ @@ -536,6 +543,13 @@ int wh_Client_SetDmaMode(whClientContext* c, int useDma) return WH_ERROR_BADARGS; } #ifdef WOLFHSM_CFG_DMA +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT + /* wolfCrypt cannot use DMA with non-coherent caches, see + * wh_Client_CryptoCbDma */ + if (useDma) { + return WH_ERROR_BADARGS; + } +#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ c->dma.preferDma = (uint32_t)(useDma ? 1 : 0); #else (void)useDma; diff --git a/src/wh_client_crypto.c b/src/wh_client_crypto.c index dd06c6152..0091bc0f9 100644 --- a/src/wh_client_crypto.c +++ b/src/wh_client_crypto.c @@ -10777,7 +10777,8 @@ int wh_Client_MlDsaExportKeyDma(whClientContext* ctx, whKeyId keyId, uint8_t* label) { int ret = WH_ERROR_OK; - byte buffer[MLDSA_MAX_BOTH_KEY_DER_SIZE] = {0}; + WH_DMA_ALIGNED byte buffer[WH_DMA_PAD_SIZE(MLDSA_MAX_BOTH_KEY_DER_SIZE)] = { + 0}; uint16_t buffer_len = sizeof(buffer); if ((ctx == NULL) || WH_KEYID_ISERASED(keyId) || (key == NULL)) { @@ -10800,7 +10801,8 @@ int wh_Client_MlDsaExportPublicKeyDma(whClientContext* ctx, whKeyId keyId, uint8_t* label) { int ret; - byte buffer[MLDSA_MAX_BOTH_KEY_DER_SIZE] = {0}; + WH_DMA_ALIGNED byte buffer[WH_DMA_PAD_SIZE(MLDSA_MAX_BOTH_KEY_DER_SIZE)] = { + 0}; uint16_t buffer_len = sizeof(buffer); if ((ctx == NULL) || WH_KEYID_ISERASED(keyId) || (key == NULL)) { @@ -10822,7 +10824,7 @@ static int _MlDsaMakeKeyDma(whClientContext* ctx, int level, { int ret = WH_ERROR_OK; whKeyId key_id = WH_KEYID_ERASED; - byte buffer[MLDSA_MAX_BOTH_KEY_DER_SIZE]; + WH_DMA_ALIGNED byte buffer[WH_DMA_PAD_SIZE(MLDSA_MAX_BOTH_KEY_DER_SIZE)]; uint8_t* dataPtr = NULL; whMessageCrypto_MlDsaKeyGenDmaRequest* req = NULL; whMessageCrypto_MlDsaKeyGenDmaResponse* res = NULL; @@ -11916,7 +11918,8 @@ int wh_Client_MlKemExportKeyDma(whClientContext* ctx, whKeyId keyId, uint8_t* label) { int ret = WH_ERROR_OK; - uint8_t buffer[WC_ML_KEM_MAX_PRIVATE_KEY_SIZE] = {0}; + WH_DMA_ALIGNED uint8_t + buffer[WH_DMA_PAD_SIZE(WC_ML_KEM_MAX_PRIVATE_KEY_SIZE)] = {0}; uint16_t buffer_len = sizeof(buffer); if ((ctx == NULL) || WH_KEYID_ISERASED(keyId) || (key == NULL)) { @@ -11942,7 +11945,8 @@ int wh_Client_MlKemExportPublicKeyDma(whClientContext* ctx, whKeyId keyId, uint8_t* label) { int ret; - uint8_t buffer[WC_ML_KEM_MAX_PUBLIC_KEY_SIZE] = {0}; + WH_DMA_ALIGNED uint8_t + buffer[WH_DMA_PAD_SIZE(WC_ML_KEM_MAX_PUBLIC_KEY_SIZE)] = {0}; uint16_t buffer_len = sizeof(buffer); if ((ctx == NULL) || WH_KEYID_ISERASED(keyId) || (key == NULL)) { @@ -11969,7 +11973,8 @@ static int _MlKemMakeKeyDma(whClientContext* ctx, int level, whMessageCrypto_MlKemKeyGenDmaResponse* res = NULL; uintptr_t keyAddr = 0; - uint8_t buffer[WC_ML_KEM_MAX_PRIVATE_KEY_SIZE]; + WH_DMA_ALIGNED uint8_t + buffer[WH_DMA_PAD_SIZE(WC_ML_KEM_MAX_PRIVATE_KEY_SIZE)]; uint16_t buffer_len = sizeof(buffer); uint16_t res_len = 0; @@ -12419,6 +12424,9 @@ int wh_Client_LmsMakeKeyDma(whClientContext* ctx, LmsKey* key, whMessageCrypto_PqcStatefulSigKeyGenDmaResponse* res; word32 pubLen32 = 0; uintptr_t pubAddr = 0; + /* The server writes the public key here, not into key->pub, which shares + * cache lines with the rest of the key struct */ + WH_DMA_ALIGNED uint8_t pub[WH_DMA_PAD_SIZE(sizeof(key->pub))]; if ((ctx == NULL) || (key == NULL) || (key->params == NULL)) { return WH_ERROR_BADARGS; @@ -12430,7 +12438,7 @@ int wh_Client_LmsMakeKeyDma(whClientContext* ctx, LmsKey* key, } ret = wc_LmsKey_GetPubLen(key, &pubLen32); - if (ret != 0) { + if ((ret != 0) || (pubLen32 > sizeof(key->pub))) { return WH_ERROR_BADARGS; } @@ -12469,7 +12477,7 @@ int wh_Client_LmsMakeKeyDma(whClientContext* ctx, LmsKey* key, req->pub.sz = pubLen32; ret = wh_Client_DmaProcessClientAddress( - ctx, (uintptr_t)key->pub, (void**)&pubAddr, pubLen32, + ctx, (uintptr_t)pub, (void**)&pubAddr, pubLen32, WH_DMA_OPER_CLIENT_WRITE_PRE, (whDmaFlags){0}); if (ret == WH_ERROR_OK) { req->pub.addr = (uint64_t)(uintptr_t)pubAddr; @@ -12496,7 +12504,7 @@ int wh_Client_LmsMakeKeyDma(whClientContext* ctx, LmsKey* key, } postRet = wh_Client_DmaProcessClientAddress( - ctx, (uintptr_t)key->pub, (void**)&pubAddr, pubLen32, + ctx, (uintptr_t)pub, (void**)&pubAddr, pubLen32, WH_DMA_OPER_CLIENT_WRITE_POST, (whDmaFlags){0}); if (ret == WH_ERROR_OK) { @@ -12524,6 +12532,13 @@ int wh_Client_LmsMakeKeyDma(whClientContext* ctx, LmsKey* key, if (ret == WH_ERROR_OK) { ret = postRet; } + /* pub is only valid if the server wrote the whole public key */ + if ((ret == WH_ERROR_OK) && (res->pubSize != pubLen32)) { + ret = WH_ERROR_ABORTED; + } + if (ret == WH_ERROR_OK) { + memcpy(key->pub, pub, pubLen32); + } } return ret; @@ -12890,6 +12905,11 @@ int wh_Client_XmssMakeKeyDma(whClientContext* ctx, XmssKey* key, whMessageCrypto_PqcStatefulSigKeyGenDmaResponse* res; word32 pubLen32 = 0; uintptr_t pubAddr = 0; + /* The server writes the public key here, not into key->pk, which shares + * cache lines with the rest of the key struct. wc_XmssKey_GetPubLen() + * returns the encoded length, XMSS_OID_LEN more than the raw key that + * key->pk holds, and the server transfers that many bytes. */ + WH_DMA_ALIGNED uint8_t pub[WH_DMA_PAD_SIZE(XMSS_OID_LEN + sizeof(key->pk))]; if ((ctx == NULL) || (key == NULL) || (key->params == NULL)) { return WH_ERROR_BADARGS; @@ -12901,7 +12921,8 @@ int wh_Client_XmssMakeKeyDma(whClientContext* ctx, XmssKey* key, } ret = wc_XmssKey_GetPubLen(key, &pubLen32); - if (ret != 0) { + if ((ret != 0) || (pubLen32 < XMSS_OID_LEN) || + (pubLen32 - XMSS_OID_LEN > sizeof(key->pk))) { return WH_ERROR_BADARGS; } @@ -12950,7 +12971,7 @@ int wh_Client_XmssMakeKeyDma(whClientContext* ctx, XmssKey* key, } ret = wh_Client_DmaProcessClientAddress( - ctx, (uintptr_t)key->pk, (void**)&pubAddr, pubLen32, + ctx, (uintptr_t)pub, (void**)&pubAddr, pubLen32, WH_DMA_OPER_CLIENT_WRITE_PRE, (whDmaFlags){0}); if (ret == WH_ERROR_OK) { req->pub.addr = (uint64_t)(uintptr_t)pubAddr; @@ -12977,7 +12998,7 @@ int wh_Client_XmssMakeKeyDma(whClientContext* ctx, XmssKey* key, } postRet = wh_Client_DmaProcessClientAddress( - ctx, (uintptr_t)key->pk, (void**)&pubAddr, pubLen32, + ctx, (uintptr_t)pub, (void**)&pubAddr, pubLen32, WH_DMA_OPER_CLIENT_WRITE_POST, (whDmaFlags){0}); if (ret == WH_ERROR_OK) { @@ -13005,6 +13026,15 @@ int wh_Client_XmssMakeKeyDma(whClientContext* ctx, XmssKey* key, if (ret == WH_ERROR_OK) { ret = postRet; } + /* pub is only valid if the server wrote the whole encoded public key */ + if ((ret == WH_ERROR_OK) && (res->pubSize != pubLen32)) { + ret = WH_ERROR_ABORTED; + } + if (ret == WH_ERROR_OK) { + /* key->pk only holds the raw key, the first + * pubLen32 - XMSS_OID_LEN bytes */ + memcpy(key->pk, pub, pubLen32 - XMSS_OID_LEN); + } } return ret; diff --git a/src/wh_client_cryptocb.c b/src/wh_client_cryptocb.c index 8046503b6..2a91cec42 100644 --- a/src/wh_client_cryptocb.c +++ b/src/wh_client_cryptocb.c @@ -100,7 +100,7 @@ int wh_Client_CryptoCb(int devId, wc_CryptoInfo* info, void* inCtx) return BAD_FUNC_ARG; } -#ifdef WOLFHSM_CFG_DMA +#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_DMA_NONCOHERENT) /* If the client prefers DMA operations, dispatch to the DMA callback first * and fall back to the standard (non-DMA) callback if the algorithm is not * supported by the DMA callback. */ @@ -111,7 +111,7 @@ int wh_Client_CryptoCb(int devId, wc_CryptoInfo* info, void* inCtx) } } else -#endif /* WOLFHSM_CFG_DMA */ +#endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_DMA_NONCOHERENT */ { /* DMA not preferred (or not compiled in); use the standard callback */ ret = wh_Client_CryptoCbStd(devId, info, inCtx); @@ -1422,7 +1422,32 @@ static int _handlePqcSigCheckPrivKey(whClientContext* ctx, wc_CryptoInfo* info, #endif /* HAVE_FALCON || WOLFSSL_HAVE_MLDSA */ -#ifdef WOLFHSM_CFG_DMA +#if defined(WOLFHSM_CFG_DMA) && defined(WOLFHSM_CFG_DMA_NONCOHERENT) +/* With non-coherent DMA the server may only write into buffers that are + * aligned and padded to whole cache lines, which wolfCrypt cannot guarantee + * for the buffers it passes in. Fail every operation instead of letting + * wolfCrypt fall back to software, so misuse of WH_DEV_ID_DMA shows up. */ +int wh_Client_CryptoCbDma(int devId, wc_CryptoInfo* info, void* inCtx) +{ + if ((devId == INVALID_DEVID) || (info == NULL) || (inCtx == NULL)) { + return BAD_FUNC_ARG; + } + + switch (info->algo_type) { + /* Commands and object lifecycle, nothing is transferred */ + case WC_ALGO_TYPE_NONE: + case WC_ALGO_TYPE_COPY: + case WC_ALGO_TYPE_FREE: + return CRYPTOCB_UNAVAILABLE; + + default: + WH_DEBUG_CLIENT("DMA cryptoCb disabled (non-coherent DMA): " + "algo->type:%d\n", + info->algo_type); + return WC_HW_E; + } +} +#elif defined(WOLFHSM_CFG_DMA) int wh_Client_CryptoCbDma(int devId, wc_CryptoInfo* info, void* inCtx) { /* III When possible, return wolfCrypt-enumerated errors */ @@ -1774,6 +1799,6 @@ int wh_Client_CryptoCbDma(int devId, wc_CryptoInfo* info, void* inCtx) } return ret; } -#endif /* WOLFHSM_CFG_DMA */ +#endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_DMA_NONCOHERENT */ #endif /* !WOLFHSM_CFG_NO_CRYPTO && WOLFHSM_CFG_ENABLE_CLIENT */ diff --git a/src/wh_client_dma.c b/src/wh_client_dma.c index 61c9df261..895614dfa 100644 --- a/src/wh_client_dma.c +++ b/src/wh_client_dma.c @@ -32,6 +32,63 @@ #include "wolfhsm/wh_error.h" #include "wolfhsm/wh_client.h" +#ifdef WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK +#include +#include + +#if defined(__SANITIZE_ADDRESS__) +#define WH_DMA_ALIGN_CHECK_ASAN +#elif defined(__has_feature) +#if __has_feature(address_sanitizer) +#define WH_DMA_ALIGN_CHECK_ASAN +#endif +#endif + +#ifdef WH_DMA_ALIGN_CHECK_ASAN +#include +#include +#endif + +/* Abort when a buffer the server writes shares a cache line with other data. + * The start is checked directly. The padding is only checked under ASAN, which + * keeps the bytes around each stack, heap and global object unaddressable. A + * buffer inside a larger object, such as a struct member, only gets the start + * check. */ +static void _CheckDmaWriteBuffer(uintptr_t addr, size_t len) +{ + const void* bad = NULL; + + if (len == 0) { + return; + } + if (!WH_DMA_IS_ALIGNED(addr)) { + bad = (const void*)addr; + } +#ifdef WH_DMA_ALIGN_CHECK_ASAN + else { + bad = __asan_region_is_poisoned((void*)addr, WH_DMA_PAD_SIZE(len)); + } +#endif + if (bad == NULL) { + return; + } + + WOLFHSM_CFG_PRINTF("DMA output buffer %p (len %u) is not aligned and " + "padded to WOLFHSM_CFG_DMA_ALIGN (%u), first bad byte " + "%p\n", + (void*)addr, (unsigned)len, + (unsigned)WOLFHSM_CFG_DMA_ALIGN, bad); + /* abort() does not flush stdio, and a piped stdout is buffered */ + (void)fflush(NULL); +#ifdef WH_DMA_ALIGN_CHECK_ASAN + /* Names the offending variable and the call that passed it */ + __asan_describe_address((void*)bad); + __sanitizer_print_stack_trace(); +#endif + abort(); +} +#endif /* WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK */ + int wh_Client_DmaRegisterAllowList(whClientContext* client, const whDmaAddrAllowList* allowlist) @@ -76,6 +133,14 @@ int wh_Client_DmaProcessClientAddress(whClientContext* client, return WH_ERROR_BADARGS; } +#ifdef WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK + /* Every buffer the server writes passes through here, whatever the port + * callback does with it */ + if (oper == WH_DMA_OPER_CLIENT_WRITE_PRE) { + _CheckDmaWriteBuffer(clientAddr, len); + } +#endif + /* Perform user-supplied address transformation, cache manipulation, etc */ if (NULL != client->dma.cb) { rc = client->dma.cb(client, clientAddr, xformedCliAddr, len, oper, diff --git a/src/wh_utils.c b/src/wh_utils.c index 634204118..9439bed4a 100644 --- a/src/wh_utils.c +++ b/src/wh_utils.c @@ -148,27 +148,61 @@ int wh_Utils_ConstantCompare(const uint8_t* a, const uint8_t* b, size_t length) } /** Cache helper functions */ + +/* Round x down to a multiple of align. Cannot overflow. */ +static uintptr_t _AlignDown(uintptr_t x, uintptr_t align) +{ + return x - (x % align); +} + +/* Get the first and last cache lines holding a byte of [p, p + n), n > 0. A + * range reaching the top of the address space stops at the last line there. */ +static void _CacheLineRange(const void* p, size_t n, uintptr_t* first, + uintptr_t* last) +{ + uintptr_t start = (uintptr_t)p; + uintptr_t end = ((uintptr_t)(n - 1) > UINTPTR_MAX - start) + ? UINTPTR_MAX + : start + (uintptr_t)(n - 1); + + *first = _AlignDown(start, XCACHELINE); + *last = _AlignDown(end, XCACHELINE); +} + +/* The loops stop on the last line before stepping, so they cannot wrap */ const void* wh_Utils_CacheInvalidate(const void* p, size_t n) { - int len = (int)n; - const uint8_t* ptr = (const uint8_t*)p; - do { - XCACHEINVLD(ptr); - ptr += XCACHELINE; - len -= XCACHELINE; - } while (len > 0); + uintptr_t line; + uintptr_t last; + + if (n > 0) { + _CacheLineRange(p, n, &line, &last); + while (1) { + XCACHEINVLD((const uint8_t*)line); + if (line >= last) { + break; + } + line += XCACHELINE; + } + } return p; } void* wh_Utils_CacheFlush(void* p, size_t n) { - int len = (int)n; - uint8_t* ptr = (uint8_t*)p; - do { - XCACHEFLUSH(ptr); - ptr += XCACHELINE; - len -= XCACHELINE; - } while (len > 0); + uintptr_t line; + uintptr_t last; + + if (n > 0) { + _CacheLineRange(p, n, &line, &last); + while (1) { + XCACHEFLUSH((uint8_t*)line); + if (line >= last) { + break; + } + line += XCACHELINE; + } + } return p; } @@ -191,6 +225,61 @@ void* wh_Utils_memcpy_flush(void* dst, const void* src , size_t n) return XCACHEFLUSHBLK(dst, n); } +#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_NO_CRYPTO) +/** DMA buffer helpers */ +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +/* The allocator only guarantees its own alignment, so over-allocate and keep + * the raw pointer just before the aligned start */ +void* wh_Utils_DmaAlloc(size_t len, void* heap) +{ + uintptr_t raw; + uintptr_t aligned; + + (void)heap; + /* Fail like XMALLOC, rather than wrap to a short buffer, when the size + * below does not fit in a size_t: padding and over-allocation each add up + * to WOLFHSM_CFG_DMA_ALIGN - 1 bytes, plus the stored pointer */ + if (len > SIZE_MAX - sizeof(uintptr_t) - + 2 * ((size_t)WOLFHSM_CFG_DMA_ALIGN - 1)) { + return NULL; + } + raw = (uintptr_t)XMALLOC(sizeof(uintptr_t) + (WOLFHSM_CFG_DMA_ALIGN - 1) + + WH_DMA_PAD_SIZE(len), + heap, DYNAMIC_TYPE_TMP_BUFFER); + if (raw == 0) { + return NULL; + } + aligned = (raw + sizeof(uintptr_t) + (WOLFHSM_CFG_DMA_ALIGN - 1)) & + ~((uintptr_t)WOLFHSM_CFG_DMA_ALIGN - 1); + memcpy((void*)(aligned - sizeof(uintptr_t)), &raw, sizeof(raw)); + return (void*)aligned; +} + +void wh_Utils_DmaFree(void* ptr, void* heap) +{ + uintptr_t raw; + + if (ptr == NULL) { + return; + } + (void)heap; + memcpy(&raw, (uint8_t*)ptr - sizeof(uintptr_t), sizeof(raw)); + XFREE((void*)raw, heap, DYNAMIC_TYPE_TMP_BUFFER); +} +#else +void* wh_Utils_DmaAlloc(size_t len, void* heap) +{ + (void)heap; + return XMALLOC(len, heap, DYNAMIC_TYPE_TMP_BUFFER); +} + +void wh_Utils_DmaFree(void* ptr, void* heap) +{ + (void)heap; + XFREE(ptr, heap, DYNAMIC_TYPE_TMP_BUFFER); +} +#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_NO_CRYPTO */ #if defined(WOLFHSM_CFG_HEXDUMP) void wh_Utils_Hexdump(const char* initial, const uint8_t* ptr, size_t size) diff --git a/test-refactor/README.md b/test-refactor/README.md index 681061f9d..bd28fa6ea 100644 --- a/test-refactor/README.md +++ b/test-refactor/README.md @@ -85,8 +85,8 @@ Translated tests: | `wh_test_cert.c::whTest_CertRamSim` | `server/wh_test_cert.c::whTest_CertVerify` | Server | remove ramsim coupling and migrate to server group. Legacy ran FLASH and FLASH_LOG backends; the port runs the plain flash backend only -- FLASH_LOG re-run pending (see Known coverage gaps) | | `wh_test_crypto.c::whTest_Crypto` | `client-server/wh_test_crypto_{aes,cmac,curve25519,ecc,ed25519,kdf,keypolicy,mldsa,rng,rsa,sha}.c::whTest_Crypto_*` | Client | Split into per-algorithm suites; key revocation is gated by `WOLFHSM_CFG_TEST_ALLOW_PERSISTENT_NVM_ARTIFACTS`. Legacy ran FLASH and FLASH_LOG backends; the port runs the plain flash backend only -- FLASH_LOG re-run pending (see Known coverage gaps) | | `wh_test_crypto.c::whTest_CryptoKeyUsagePolicies` (AES CTR/ECB/GCM subset) | `client-server/wh_test_crypto_aes.c::whTest_CryptoAesKeyUsagePolicies` | Client | AES-CTR/ECB/GCM key usage enforcement (non-DMA and DMA variants) | -| `wh_test_crypto.c::whTestCrypto_LmsCryptoCb` | `client-server/wh_test_crypto_lms.c::whTest_Crypto_Lms` | Client | DMA-only LMS generate/durability/sign/verify, public-key export+import, private export/import rejection, and the server-only `WH_NVM_FLAGS_TRUSTED` keygen strip regression. Gated by `WOLFHSM_CFG_DMA && WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY`; reports SKIPPED otherwise | -| `wh_test_crypto.c::whTestCrypto_XmssCryptoCb` | `client-server/wh_test_crypto_xmss.c::whTest_Crypto_Xmss` | Client | DMA-only XMSS generate/durability/sign/verify, public-key export+import, private export/import rejection, and the server-only `WH_NVM_FLAGS_TRUSTED` keygen strip regression. Gated by `WOLFHSM_CFG_DMA && WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY`; reports SKIPPED otherwise | +| `wh_test_crypto.c::whTestCrypto_LmsCryptoCb` | `client-server/wh_test_crypto_lms.c::whTest_Crypto_Lms` | Client | DMA-only LMS generate/durability/sign/verify, public-key export+import, private export/import rejection, and the server-only `WH_NVM_FLAGS_TRUSTED` keygen strip regression. Gated by `WOLFHSM_CFG_DMA && !WOLFHSM_CFG_DMA_NONCOHERENT && WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY` (it runs through wolfCrypt on `WH_DEV_ID_DMA`, which non-coherent DMA builds refuse); reports SKIPPED otherwise | +| `wh_test_crypto.c::whTestCrypto_XmssCryptoCb` | `client-server/wh_test_crypto_xmss.c::whTest_Crypto_Xmss` | Client | DMA-only XMSS generate/durability/sign/verify, public-key export+import, private export/import rejection, and the server-only `WH_NVM_FLAGS_TRUSTED` keygen strip regression. Gated by `WOLFHSM_CFG_DMA && !WOLFHSM_CFG_DMA_NONCOHERENT && WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY` (it runs through wolfCrypt on `WH_DEV_ID_DMA`, which non-coherent DMA builds refuse); reports SKIPPED otherwise | | `wh_test_crypto.c::{whTest_KeyCache, whTest_NonExportableKeystore}` | `client-server/wh_test_crypto_keystore.c::whTest_Crypto_Keystore` | Client | Key-cache lifecycle (cache/export, evict, commit/erase, cross-cache eviction/replacement, NVM-backed eviction) and non-exportable-flag enforcement; std and DMA export paths. The `WOLFHSM_CFG_IS_TEST_SERVER` multi-client user-exclusion path is dropped (needs two client contexts) | | `wh_test_clientserver.c` (echo and server-info paths) | `client-server/wh_test_echo.c::whTest_Echo`, `client-server/wh_test_server_info.c::whTest_ServerInfo` | Client | pthread test ported, sequential test dropped | | `wh_test_clientserver.c` (NVM CRUD + OOB read clamping paths) | `client-server/wh_test_nvm_ops.c::{whTest_NvmCrud, whTest_NvmReadOob}` | Client | each test cleans up its own slots; OOB test covers UINT16_MAX overflow regression | diff --git a/test-refactor/client-server/wh_test_crypto_aes.c b/test-refactor/client-server/wh_test_crypto_aes.c index 45d298e57..541c7c351 100644 --- a/test-refactor/client-server/wh_test_crypto_aes.c +++ b/test-refactor/client-server/wh_test_crypto_aes.c @@ -455,7 +455,7 @@ static int whTest_CryptoAesCtrLeftOob(whClientContext* ctx) int ret = 0; int tmp; Aes aes[1]; - uint8_t cipher[AES_BLOCK_SIZE] = {0}; + WH_DMA_ALIGNED uint8_t cipher[WH_DMA_PAD_SIZE(AES_BLOCK_SIZE)] = {0}; const uint8_t key[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, @@ -782,7 +782,9 @@ int whTest_CryptoAesKeyUsagePolicies(whClientContext* ctx) } #endif /* HAVE_AESGCM */ -#ifdef WOLFHSM_CFG_DMA +/* These go through wolfCrypt on WH_DEV_ID_DMA, which non-coherent DMA builds + * refuse */ +#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_DMA_NONCOHERENT) #ifdef WOLFSSL_AES_COUNTER /* AES-CTR DMA: encrypt without ENCRYPT flag */ { @@ -1092,7 +1094,7 @@ int whTest_CryptoAesKeyUsagePolicies(whClientContext* ctx) goto done; } #endif /* HAVE_AESGCM */ -#endif /* WOLFHSM_CFG_DMA */ +#endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_DMA_NONCOHERENT */ done: wc_FreeRng(rng); diff --git a/test-refactor/client-server/wh_test_crypto_ecc.c b/test-refactor/client-server/wh_test_crypto_ecc.c index ed84629b1..8bbed2fe3 100644 --- a/test-refactor/client-server/wh_test_crypto_ecc.c +++ b/test-refactor/client-server/wh_test_crypto_ecc.c @@ -2297,7 +2297,7 @@ static int _whTest_CryptoEccExportPublicKeyDma(whClientContext* ctx) uint8_t sig[ECC_MAX_SIG_SIZE]; word32 sigLen = sizeof(sig); int verify = 0; - uint8_t derBuf[256]; + WH_DMA_ALIGNED uint8_t derBuf[WH_DMA_PAD_SIZE(256)]; uint16_t derSz = sizeof(derBuf); ret = wc_InitRng_ex(rng, NULL, WH_CLIENT_DEVID(ctx)); diff --git a/test-refactor/client-server/wh_test_crypto_ed25519.c b/test-refactor/client-server/wh_test_crypto_ed25519.c index 7807416df..1caf3f2dd 100644 --- a/test-refactor/client-server/wh_test_crypto_ed25519.c +++ b/test-refactor/client-server/wh_test_crypto_ed25519.c @@ -372,7 +372,7 @@ static int _whTest_CryptoEd25519Dma(whClientContext* ctx) whKeyId signKeyId = WH_KEYID_ERASED; whKeyId verifyKeyId = WH_KEYID_ERASED; byte msg[] = "Ed25519 DMA message"; - byte sig[ED25519_SIG_SIZE]; + WH_DMA_ALIGNED byte sig[WH_DMA_PAD_SIZE(ED25519_SIG_SIZE)]; uint32_t sigSz = sizeof(sig); int verified = 0; uint8_t label[] = "Ed25519 DMA Key"; diff --git a/test-refactor/client-server/wh_test_crypto_keystore.c b/test-refactor/client-server/wh_test_crypto_keystore.c index 604026e3a..c2c563919 100644 --- a/test-refactor/client-server/wh_test_crypto_keystore.c +++ b/test-refactor/client-server/wh_test_crypto_keystore.c @@ -132,9 +132,11 @@ static int _whTest_KeyCache(whClientContext* ctx) uint16_t keyId; WC_RNG rng[1]; uint8_t key[WH_TEST_KEYCACHE_KEYSIZE]; - uint8_t keyOut[WH_TEST_KEYCACHE_KEYSIZE] = {0}; - uint8_t labelIn[WH_NVM_LABEL_LEN] = "KeyCache Test Label"; - uint8_t labelOut[WH_NVM_LABEL_LEN] = {0}; + uint8_t labelIn[WH_NVM_LABEL_LEN] = "KeyCache Test Label"; + uint8_t labelOut[WH_NVM_LABEL_LEN] = {0}; + + WH_DMA_ALIGNED uint8_t keyOut[WH_DMA_PAD_SIZE(WH_TEST_KEYCACHE_KEYSIZE)] = { + 0}; ret = wc_InitRng_ex(rng, NULL, devId); if (ret != 0) { @@ -466,7 +468,8 @@ static int _whTest_KeyCache(whClientContext* ctx) uint8_t labelBig[WH_NVM_LABEL_LEN] = "Big DMA Key Label"; /* Buffer for exported key and metadata */ - uint8_t exportedKey[WOLFHSM_CFG_SERVER_KEYCACHE_BUFSIZE + 100]; + WH_DMA_ALIGNED uint8_t exportedKey[WH_DMA_PAD_SIZE( + WOLFHSM_CFG_SERVER_KEYCACHE_BUFSIZE + 100)]; uint8_t exportedLabel[WH_NVM_LABEL_LEN]; uint16_t exportedKeySize; @@ -707,11 +710,13 @@ static int _whTest_NonExportableKeystore(whClientContext* ctx) 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00}; - uint8_t exportedKey[WH_TEST_KEYSTORE_TEST_SZ] = {0}; - uint8_t label[WH_NVM_LABEL_LEN] = "NonExportableTestKey"; - uint8_t exportedLabel[WH_NVM_LABEL_LEN] = {0}; + uint8_t label[WH_NVM_LABEL_LEN] = "NonExportableTestKey"; + uint8_t exportedLabel[WH_NVM_LABEL_LEN] = {0}; uint16_t exportedKeySize; + WH_DMA_ALIGNED uint8_t + exportedKey[WH_DMA_PAD_SIZE(WH_TEST_KEYSTORE_TEST_SZ)] = {0}; + WH_TEST_PRINT("Testing non-exportable keystore enforcement...\n"); /* Test 1: Cache a key with non-exportable flag and try to export it */ diff --git a/test-refactor/client-server/wh_test_crypto_lms.c b/test-refactor/client-server/wh_test_crypto_lms.c index 181fd5556..aa9042232 100644 --- a/test-refactor/client-server/wh_test_crypto_lms.c +++ b/test-refactor/client-server/wh_test_crypto_lms.c @@ -48,7 +48,9 @@ #include "wh_test_common.h" #include "wh_test_list.h" -#if defined(WOLFHSM_CFG_DMA) && \ +/* Runs through wolfCrypt on WH_DEV_ID_DMA, which non-coherent DMA builds + * refuse, so the test is skipped there. */ +#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_DMA_NONCOHERENT) && \ defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) /* L=1, H=5, W=8 keeps the signature ~1.3 KB and gives 2^5 = 32 signatures. */ @@ -493,6 +495,6 @@ int whTest_Crypto_Lms(whClientContext* ctx) return ret; } -#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ +#endif /* DMA && !DMA_NONCOHERENT && LMS && !LMS_VERIFY_ONLY */ #endif /* !WOLFHSM_CFG_NO_CRYPTO */ diff --git a/test-refactor/client-server/wh_test_crypto_mldsa.c b/test-refactor/client-server/wh_test_crypto_mldsa.c index b2cb274f6..6a0f811c7 100644 --- a/test-refactor/client-server/wh_test_crypto_mldsa.c +++ b/test-refactor/client-server/wh_test_crypto_mldsa.c @@ -438,7 +438,7 @@ static int _whTest_CryptoMlDsaDmaClient(whClientContext* ctx) if (ret == 0) { byte msg[] = "Test message to sign"; - byte sig[DILITHIUM_MAX_SIG_SIZE]; + WH_DMA_ALIGNED byte sig[WH_DMA_PAD_SIZE(DILITHIUM_MAX_SIG_SIZE)]; word32 sigLen = sizeof(sig); int verified = 0; @@ -497,7 +497,7 @@ static int _whTest_CryptoMlDsaDmaClient(whClientContext* ctx) if (ret == 0) { byte msg[] = "Context test message"; - byte sig[DILITHIUM_MAX_SIG_SIZE]; + WH_DMA_ALIGNED byte sig[WH_DMA_PAD_SIZE(DILITHIUM_MAX_SIG_SIZE)]; word32 sigLen = sizeof(sig); int verified = 0; const byte ctx_str[] = "test-context"; @@ -567,12 +567,14 @@ static int _whTest_CryptoMlDsaDmaClient(whClientContext* ctx) * public-only key. */ static int _whTest_CryptoMlDsaExportPublicKeyDma(whClientContext* ctx) { - int devId = WH_CLIENT_DEVID(ctx); - int ret = 0; - MlDsaKey pub[1] = {0}; - whKeyId keyId = WH_KEYID_ERASED; - uint8_t denyBuf[DILITHIUM_MAX_BOTH_KEY_DER_SIZE]; - uint16_t denyLen = sizeof(denyBuf); + int devId = WH_CLIENT_DEVID(ctx); + int ret = 0; + MlDsaKey pub[1] = {0}; + whKeyId keyId = WH_KEYID_ERASED; + uint16_t denyLen = 0; + + WH_DMA_ALIGNED uint8_t + denyBuf[WH_DMA_PAD_SIZE(DILITHIUM_MAX_BOTH_KEY_DER_SIZE)]; ret = wh_Client_MlDsaMakeCacheKey( ctx, 0, WC_ML_DSA_44, &keyId, @@ -643,7 +645,7 @@ static int _whTest_CryptoMlDsaCacheKeyAndExportPublicDma(whClientContext* ctx) MlDsaKey refPub[1] = {0}; whKeyId keyId = WH_KEYID_ERASED; byte msg[] = "ML-DSA DMA cache-export-public message"; - byte sig[DILITHIUM_MAX_SIG_SIZE]; + WH_DMA_ALIGNED byte sig[WH_DMA_PAD_SIZE(DILITHIUM_MAX_SIG_SIZE)]; word32 sigLen = sizeof(sig); int verified = 0; byte genDer[DILITHIUM_MAX_PUB_KEY_DER_SIZE]; diff --git a/test-refactor/client-server/wh_test_crypto_rng.c b/test-refactor/client-server/wh_test_crypto_rng.c index 779bd70af..820585332 100644 --- a/test-refactor/client-server/wh_test_crypto_rng.c +++ b/test-refactor/client-server/wh_test_crypto_rng.c @@ -279,7 +279,7 @@ static int _whTest_CryptoRngDmaAsync(whClientContext* ctx) int ret = WH_ERROR_OK; /* DMA bypasses the comm buffer so we can request more than COMM_DATA_LEN * in a single round trip. */ - uint8_t big[WOLFHSM_CFG_COMM_DATA_LEN * 2]; + WH_DMA_ALIGNED uint8_t big[WH_DMA_PAD_SIZE(WOLFHSM_CFG_COMM_DATA_LEN * 2)]; /* Case A: basic DMA Request -> Response */ if (ret == 0) { @@ -304,15 +304,15 @@ static int _whTest_CryptoRngDmaAsync(whClientContext* ctx) /* Case B: small DMA request still works (no chunking semantics). */ if (ret == 0) { - uint8_t small[32]; + WH_DMA_ALIGNED uint8_t small[WH_DMA_PAD_SIZE(32)]; memset(small, 0, sizeof(small)); - ret = wh_Client_RngGenerateDmaRequest(ctx, small, sizeof(small)); + ret = wh_Client_RngGenerateDmaRequest(ctx, small, 32); if (ret == 0) { do { ret = wh_Client_RngGenerateDmaResponse(ctx); } while (ret == WH_ERROR_NOTREADY); } - if (ret == 0 && whTest_RngBufNonZero(small, sizeof(small)) != 0) { + if (ret == 0 && whTest_RngBufNonZero(small, 32) != 0) { WH_ERROR_PRINT("Async RNG DMA: small buffer all zeros\n"); ret = -1; } diff --git a/test-refactor/client-server/wh_test_crypto_xmss.c b/test-refactor/client-server/wh_test_crypto_xmss.c index 0b6621c03..9990da14f 100644 --- a/test-refactor/client-server/wh_test_crypto_xmss.c +++ b/test-refactor/client-server/wh_test_crypto_xmss.c @@ -48,7 +48,9 @@ #include "wh_test_common.h" #include "wh_test_list.h" -#if defined(WOLFHSM_CFG_DMA) && \ +/* Runs through wolfCrypt on WH_DEV_ID_DMA, which non-coherent DMA builds + * refuse, so the test is skipped there. */ +#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_DMA_NONCOHERENT) && \ defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) /* "XMSS-SHA2_10_256" is the smallest standardized XMSS parameter set @@ -479,6 +481,6 @@ int whTest_Crypto_Xmss(whClientContext* ctx) return ret; } -#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */ +#endif /* DMA && !DMA_NONCOHERENT && XMSS && !XMSS_VERIFY_ONLY */ #endif /* !WOLFHSM_CFG_NO_CRYPTO */ diff --git a/test-refactor/client-server/wh_test_nvm_ops.c b/test-refactor/client-server/wh_test_nvm_ops.c index 105aec5fa..6cddb0614 100644 --- a/test-refactor/client-server/wh_test_nvm_ops.c +++ b/test-refactor/client-server/wh_test_nvm_ops.c @@ -116,7 +116,7 @@ static int _addAndVerifyOne(whClientContext* ctx, whNvmFlags gflags = 0; whNvmSize glen = 0; char glabel[WH_NVM_LABEL_LEN] = {0}; - uint8_t buf[WOLFHSM_CFG_COMM_DATA_LEN]; + WH_DMA_ALIGNED uint8_t buf[WH_DMA_PAD_SIZE(WOLFHSM_CFG_COMM_DATA_LEN)]; whNvmSize rlen = 0; WH_TEST_RETURN_ON_FAIL(wh_Client_NvmGetAvailable( diff --git a/test-refactor/config/wolfhsm_cfg.h b/test-refactor/config/wolfhsm_cfg.h index b0df37934..8f4eda94c 100644 --- a/test-refactor/config/wolfhsm_cfg.h +++ b/test-refactor/config/wolfhsm_cfg.h @@ -66,4 +66,14 @@ #define WOLFHSM_CFG_ENABLE_TIMEOUT +/* Route the single-line cache operations to a recorder, so + * misc/wh_test_cache.c can check which lines wh_Utils_CacheFlush and + * wh_Utils_CacheInvalidate visit. The recorder only stores addresses while + * that test runs, otherwise these are no-ops like the defaults. */ +#define WOLFHSM_CFG_TEST_CACHE_RECORD +#include +void whTest_CacheRecord(int invalidate, uintptr_t addr); +#define XCACHEFLUSH(_p) whTest_CacheRecord(0, (uintptr_t)(_p)) +#define XCACHEINVLD(_p) whTest_CacheRecord(1, (uintptr_t)(_p)) + #endif /* WOLFHSM_CFG_H_ */ diff --git a/test-refactor/misc/wh_test_cache.c b/test-refactor/misc/wh_test_cache.c new file mode 100644 index 000000000..816a7321b --- /dev/null +++ b/test-refactor/misc/wh_test_cache.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2026 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 . + */ +/* + * test-refactor/misc/wh_test_cache.c + * + * Cache line coverage of wh_Utils_CacheFlush and wh_Utils_CacheInvalidate, + * the default XCACHEFLUSHBLK and XCACHEINVLDBLK. The test config + * (WOLFHSM_CFG_TEST_CACHE_RECORD) routes XCACHEFLUSH and XCACHEINVLD to + * whTest_CacheRecord, which records each line address without touching it, + * so the ranges are synthetic addresses, up to the top of the address space. + * Needs no client, server, or port fixture. + */ + +#include "wolfhsm/wh_settings.h" + +#ifdef WOLFHSM_CFG_TEST_CACHE_RECORD + +#include +#include + +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_utils.h" + +#include "wh_test_common.h" +#include "wh_test_list.h" + +#define CACHE_RECORD_MAX 8 + +static int _cacheRecording; +static int _cacheCount; +static int _cacheOps[CACHE_RECORD_MAX]; +static uintptr_t _cacheLines[CACHE_RECORD_MAX]; + +/* XCACHEFLUSH and XCACHEINVLD in this build. Only records while a check below + * runs, so the cache operations of the transports in other tests stay no-ops. + * Counts one call past CACHE_RECORD_MAX so too many calls fail the check. */ +void whTest_CacheRecord(int invalidate, uintptr_t addr) +{ + if (_cacheRecording == 0) { + return; + } + if (_cacheCount < CACHE_RECORD_MAX) { + _cacheOps[_cacheCount] = invalidate; + _cacheLines[_cacheCount] = addr; + _cacheCount++; + } + else { + _cacheCount = CACHE_RECORD_MAX + 1; + } +} + +/* Run the flush or invalidate helper over [p, p + n) and check that it + * visited count lines in order, starting at the line address first */ +static int _whTest_CacheCheck(int invalidate, uintptr_t p, size_t n, + uintptr_t first, int count) +{ + const void* ret; + int i; + + _cacheCount = 0; + _cacheRecording = 1; + if (invalidate != 0) { + ret = wh_Utils_CacheInvalidate((const void*)p, n); + } + else { + ret = wh_Utils_CacheFlush((void*)p, n); + } + _cacheRecording = 0; + + WH_TEST_ASSERT_RETURN(ret == (const void*)p); + if (_cacheCount != count) { + WH_ERROR_PRINT("%s(%p, %lu) visited %d lines, expected %d\n", + (invalidate != 0) ? "invalidate" : "flush", (void*)p, + (unsigned long)n, _cacheCount, count); + return WH_TEST_FAIL; + } + for (i = 0; i < count; i++) { + WH_TEST_ASSERT_RETURN(_cacheOps[i] == invalidate); + WH_TEST_ASSERT_RETURN(_cacheLines[i] == + first + (uintptr_t)i * XCACHELINE); + } + return WH_ERROR_OK; +} + +/* Check one range with both helpers */ +static int _whTest_CacheRange(uintptr_t p, size_t n, uintptr_t first, int count) +{ + WH_TEST_RETURN_ON_FAIL(_whTest_CacheCheck(0, p, n, first, count)); + WH_TEST_RETURN_ON_FAIL(_whTest_CacheCheck(1, p, n, first, count)); + return WH_ERROR_OK; +} + +int whTest_CacheHelpers(void* ctx) +{ + const uintptr_t line = XCACHELINE; + /* Any line aligned address, nothing is dereferenced */ + const uintptr_t base = 1024 * line; + /* Start of the last line of the address space */ + const uintptr_t top = UINTPTR_MAX - (UINTPTR_MAX % line); + + (void)ctx; + + /* Aligned start, exact multiple of the line size */ + WH_TEST_RETURN_ON_FAIL(_whTest_CacheRange(base, 3 * line, base, 3)); + /* Unaligned start, the range spills one byte into the next line */ + WH_TEST_RETURN_ON_FAIL(_whTest_CacheRange(base + 1, line, base, 2)); + /* n == 0 visits nothing */ + WH_TEST_RETURN_ON_FAIL(_whTest_CacheRange(base, 0, 0, 0)); + WH_TEST_RETURN_ON_FAIL(_whTest_CacheRange(base + 1, 0, 0, 0)); + /* n == 1 at the last byte of a line visits only that line */ + WH_TEST_RETURN_ON_FAIL(_whTest_CacheRange(base + line - 1, 1, base, 1)); + + /* A range reaching the top of the address space stops at its last line: + * ending exactly at the top, ending inside the last line (rounding the + * end up would wrap), running past the top, and the very last byte */ + WH_TEST_RETURN_ON_FAIL( + _whTest_CacheRange(top - line, 2 * line, top - line, 2)); + WH_TEST_RETURN_ON_FAIL( + _whTest_CacheRange(top - line + 1, line, top - line, 2)); + WH_TEST_RETURN_ON_FAIL( + _whTest_CacheRange(top - line, 3 * line, top - line, 2)); + WH_TEST_RETURN_ON_FAIL(_whTest_CacheRange(UINTPTR_MAX, 1, top, 1)); + + WH_TEST_PRINT("Cache line helpers SUCCESS\n"); + return WH_ERROR_OK; +} + +#endif /* WOLFHSM_CFG_TEST_CACHE_RECORD */ diff --git a/test-refactor/misc/wh_test_crypto_affinity.c b/test-refactor/misc/wh_test_crypto_affinity.c index 52cbddb41..354f03c72 100644 --- a/test-refactor/misc/wh_test_crypto_affinity.c +++ b/test-refactor/misc/wh_test_crypto_affinity.c @@ -316,7 +316,7 @@ static int _whTest_CryptoAffinityWithCb(void) uint8_t key[AES_BLOCK_SIZE] = {0x01}; uint8_t iv[AES_BLOCK_SIZE] = {0x02}; uint8_t plainIn[AES_BLOCK_SIZE] = {0x03}; - uint8_t cipherOut[AES_BLOCK_SIZE] = {0}; + WH_DMA_ALIGNED uint8_t cipherOut[WH_DMA_PAD_SIZE(AES_BLOCK_SIZE)] = {0}; WH_TEST_RETURN_ON_FAIL(wc_AesInit(aes, NULL, INVALID_DEVID)); WH_TEST_RETURN_ON_FAIL( @@ -339,7 +339,7 @@ static int _whTest_CryptoAffinityWithCb(void) uint8_t key[AES_BLOCK_SIZE] = {0x01}; uint8_t iv[AES_BLOCK_SIZE] = {0x02}; uint8_t plainIn[AES_BLOCK_SIZE] = {0x03}; - uint8_t cipherOut[AES_BLOCK_SIZE] = {0}; + WH_DMA_ALIGNED uint8_t cipherOut[WH_DMA_PAD_SIZE(AES_BLOCK_SIZE)] = {0}; WH_TEST_RETURN_ON_FAIL(wc_AesInit(aes, NULL, INVALID_DEVID)); WH_TEST_RETURN_ON_FAIL( @@ -569,7 +569,7 @@ static int _whTest_CryptoAffinityNoCb(void) uint8_t key[AES_BLOCK_SIZE] = {0x01}; uint8_t iv[AES_BLOCK_SIZE] = {0x02}; uint8_t plainIn[AES_BLOCK_SIZE] = {0x03}; - uint8_t cipherOut[AES_BLOCK_SIZE] = {0}; + WH_DMA_ALIGNED uint8_t cipherOut[WH_DMA_PAD_SIZE(AES_BLOCK_SIZE)] = {0}; WH_TEST_RETURN_ON_FAIL(wc_AesInit(aes, NULL, INVALID_DEVID)); WH_TEST_RETURN_ON_FAIL( diff --git a/test-refactor/misc/wh_test_dma_noncoherent.c b/test-refactor/misc/wh_test_dma_noncoherent.c new file mode 100644 index 000000000..b2f6c81c5 --- /dev/null +++ b/test-refactor/misc/wh_test_dma_noncoherent.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2026 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 . + */ + +/* + * test-refactor/misc/wh_test_dma_noncoherent.c + * + * WOLFHSM_CFG_DMA_NONCOHERENT refusals: wolfCrypt cannot use DMA when client + * caches are not coherent, so the client must refuse preferDma (at init and + * through wh_Client_SetDmaMode) and every wolfCrypt operation on + * WH_DEV_ID_DMA must fail with WC_HW_E instead of falling back to software. + * None of this reaches the server, so the test runs a client with no server. + * Also checks the aligned, padded buffers from wh_Utils_DmaAlloc. + */ + +#include "wolfhsm/wh_settings.h" + +#if defined(WOLFHSM_CFG_DMA) && defined(WOLFHSM_CFG_DMA_NONCOHERENT) && \ + defined(WOLFHSM_CFG_ENABLE_CLIENT) && !defined(WOLFHSM_CFG_NO_CRYPTO) + +#include +#include + +#include "wolfssl/wolfcrypt/settings.h" +#include "wolfssl/wolfcrypt/types.h" +#include "wolfssl/wolfcrypt/error-crypt.h" +#include "wolfssl/wolfcrypt/sha256.h" + +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_transport_mem.h" +#include "wolfhsm/wh_client.h" +#include "wolfhsm/wh_utils.h" + +#include "wh_test_common.h" +#include "wh_test_list.h" + +#define BUFFER_SIZE 4096 + +/* wh_Utils_DmaAlloc must return a buffer aligned to WOLFHSM_CFG_DMA_ALIGN with + * WH_DMA_PAD_SIZE(len) usable bytes, and wh_Utils_DmaFree must free it through + * the raw pointer stored before it. Writing every padded byte and freeing lets + * ASAN catch a short buffer or a wrong offset. */ +static int _whTest_DmaNonCoherentAlloc(void) +{ + static const size_t lens[] = { + 0, + 1, + WOLFHSM_CFG_DMA_ALIGN - 1, + WOLFHSM_CFG_DMA_ALIGN, + WOLFHSM_CFG_DMA_ALIGN + 1, + 3 * WOLFHSM_CFG_DMA_ALIGN, + 10 * WOLFHSM_CFG_DMA_ALIGN + 3, + }; + /* Allocation sizes that would wrap without the overflow check: + * WH_DMA_PAD_SIZE(SIZE_MAX) wraps to 0, and SIZE_MAX - + * WOLFHSM_CFG_DMA_ALIGN + 1 pads without wrapping but the over-allocation + * then does */ + static const size_t hugeLens[] = { + SIZE_MAX, + SIZE_MAX - WOLFHSM_CFG_DMA_ALIGN + 1, + }; + uint8_t* buf; + size_t i; + + for (i = 0; i < sizeof(lens) / sizeof(lens[0]); i++) { + buf = (uint8_t*)wh_Utils_DmaAlloc(lens[i], NULL); + WH_TEST_ASSERT_RETURN(buf != NULL); + if (!WH_DMA_IS_ALIGNED(buf)) { + WH_ERROR_PRINT("wh_Utils_DmaAlloc(%u) returned unaligned %p\n", + (unsigned)lens[i], (void*)buf); + wh_Utils_DmaFree(buf, NULL); + return WH_TEST_FAIL; + } + memset(buf, 0xA5, WH_DMA_PAD_SIZE(lens[i])); + wh_Utils_DmaFree(buf, NULL); + } + + for (i = 0; i < sizeof(hugeLens) / sizeof(hugeLens[0]); i++) { + buf = (uint8_t*)wh_Utils_DmaAlloc(hugeLens[i], NULL); + if (buf != NULL) { + WH_ERROR_PRINT("wh_Utils_DmaAlloc(SIZE_MAX - %u) did not fail\n", + (unsigned)(SIZE_MAX - hugeLens[i])); + wh_Utils_DmaFree(buf, NULL); + return WH_TEST_FAIL; + } + } + + /* NULL is ignored */ + wh_Utils_DmaFree(NULL, NULL); + + WH_TEST_PRINT("DMA non-coherent wh_Utils_DmaAlloc SUCCESS\n"); + return WH_ERROR_OK; +} + +static int _whTest_DmaNonCoherentRefusals(void) +{ + static uint8_t req[BUFFER_SIZE]; + static uint8_t resp[BUFFER_SIZE]; + whTransportMemConfig tmcf[1] = {{ + .req = (whTransportMemCsr*)req, + .req_size = sizeof(req), + .resp = (whTransportMemCsr*)resp, + .resp_size = sizeof(resp), + }}; + + whTransportClientCb tccb[1] = {WH_TRANSPORT_MEM_CLIENT_CB}; + whTransportMemClientContext tmcc[1] = {0}; + whCommClientConfig cc_conf[1] = {{ + .transport_cb = tccb, + .transport_context = (void*)tmcc, + .transport_config = (void*)tmcf, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, + }}; + whClientDmaConfig dmaCfg[1] = {{0}}; + whClientContext client[1] = {0}; + whClientConfig c_conf[1] = {{ + .comm = cc_conf, + .dmaConfig = dmaCfg, + }}; + int useDma = -1; + int ret = 0; + + /* preferDma in the config is refused before any initialization */ + dmaCfg[0].preferDma = 1; + WH_TEST_ASSERT_RETURN(WH_ERROR_BADARGS == wh_Client_Init(client, c_conf)); + + dmaCfg[0].preferDma = 0; + WH_TEST_RETURN_ON_FAIL(wh_Client_Init(client, c_conf)); + + /* Turning DMA mode on is refused and leaves it off; turning it off is + * still accepted */ + if (wh_Client_SetDmaMode(client, 1) != WH_ERROR_BADARGS) { + WH_ERROR_PRINT("wh_Client_SetDmaMode(1) was not refused\n"); + ret = -1; + } + if ((ret == 0) && ((wh_Client_GetDmaMode(client, &useDma) != WH_ERROR_OK) || + (useDma != 0))) { + WH_ERROR_PRINT("DMA mode is on after a refused SetDmaMode: %d\n", + useDma); + ret = -1; + } + if ((ret == 0) && (wh_Client_SetDmaMode(client, 0) != WH_ERROR_OK)) { + WH_ERROR_PRINT("wh_Client_SetDmaMode(0) failed\n"); + ret = -1; + } + +#ifndef NO_SHA256 + /* A wolfCrypt operation on WH_DEV_ID_DMA fails with WC_HW_E (no software + * fallback), and freeing the object afterwards still works */ + if (ret == 0) { + wc_Sha256 sha[1]; + const uint8_t data[] = "noncoherent"; + int rc; + + rc = wc_InitSha256_ex(sha, NULL, WH_DEV_ID_DMA); + if (rc != 0) { + WH_ERROR_PRINT("wc_InitSha256_ex on WH_DEV_ID_DMA failed %d\n", rc); + ret = -1; + } + else { + rc = wc_Sha256Update(sha, data, (word32)sizeof(data)); + if (rc != WC_HW_E) { + WH_ERROR_PRINT("SHA256 on WH_DEV_ID_DMA returned %d, expected " + "WC_HW_E\n", + rc); + ret = -1; + } + wc_Sha256Free(sha); + } + } +#endif /* !NO_SHA256 */ + + WH_TEST_RETURN_ON_FAIL(wh_Client_Cleanup(client)); + + if (ret == 0) { + WH_TEST_PRINT("DMA non-coherent refusals SUCCESS\n"); + } + return ret; +} + +int whTest_DmaNonCoherent(void* ctx) +{ + (void)ctx; + + WH_TEST_RETURN_ON_FAIL(_whTest_DmaNonCoherentAlloc()); + WH_TEST_RETURN_ON_FAIL(_whTest_DmaNonCoherentRefusals()); + + return WH_ERROR_OK; +} + +#endif /* DMA && DMA_NONCOHERENT && ENABLE_CLIENT && !NO_CRYPTO */ diff --git a/test-refactor/misc/wh_test_multiclient.c b/test-refactor/misc/wh_test_multiclient.c index 6eb4b620b..9bf60ee69 100644 --- a/test-refactor/misc/wh_test_multiclient.c +++ b/test-refactor/misc/wh_test_multiclient.c @@ -531,7 +531,7 @@ static int _testGlobalKeyDma(whClientContext* client1, whServerContext* server1, whKeyId keyId2 = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_2); uint8_t keyData1[32] = "GlobalDmaCacheTestKey123456!"; uint8_t keyData2[32] = "GlobalDmaExportTestKey12345!"; - uint8_t outBuf[32] = {0}; + WH_DMA_ALIGNED uint8_t outBuf[WH_DMA_PAD_SIZE(32)] = {0}; uint8_t label[WH_NVM_LABEL_LEN]; uint16_t labelSz = sizeof(label); uint16_t outSz; @@ -1636,7 +1636,7 @@ static int _testNvmUnboundClientRejected(whClientContext* client1, whNvmId count = 0; whNvmId list_id = 0; whNvmSize out_len = 0; - uint8_t buf[64] = {0}; + WH_DMA_ALIGNED uint8_t buf[WH_DMA_PAD_SIZE(64)] = {0}; (void)client2; (void)server2; @@ -1908,7 +1908,7 @@ static int _testNvmGlobalFlagDisabled(whClientContext* client1, whNvmId count = 0; whNvmId cur = 0; whNvmSize out_len = 0; - uint8_t buf[64] = {0}; + WH_DMA_ALIGNED uint8_t buf[WH_DMA_PAD_SIZE(64)] = {0}; (void)client2; (void)server2; @@ -2051,7 +2051,7 @@ static int _testNvmNonAddVerbRejections(whClientContext* client1, whNvmSize out_len = 0; whNvmId list_id = 0; whNvmId count = 0; - uint8_t buf[64] = {0}; + WH_DMA_ALIGNED uint8_t buf[WH_DMA_PAD_SIZE(64)] = {0}; (void)client2; (void)server2; @@ -2220,7 +2220,7 @@ static int _testKeystoreUnboundClientRejected(whClientContext* client1, const whKeyId globalId = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, WH_KEYUSER_GLOBAL, keyId); uint8_t keyData[32] = "UnboundKeystoreRejectKey12!"; - uint8_t outBuf[32] = {0}; + WH_DMA_ALIGNED uint8_t outBuf[WH_DMA_PAD_SIZE(32)] = {0}; uint8_t label[WH_NVM_LABEL_LEN] = {0}; uint32_t readSz = sizeof(outBuf); uint16_t outSz = 0; diff --git a/test-refactor/posix/Makefile b/test-refactor/posix/Makefile index b5979e2b9..a5b232ce1 100644 --- a/test-refactor/posix/Makefile +++ b/test-refactor/posix/Makefile @@ -112,6 +112,24 @@ ifeq ($(DMA),1) DEF += -DWOLFHSM_CFG_DMA endif +# DMA with non-coherent client caches (requires DMA=1) +ifeq ($(DMA_NONCOHERENT),1) + ifneq ($(DMA),1) + $(error "DMA_NONCOHERENT=1 requires DMA=1 to be set") + endif + DEF += -DWOLFHSM_CFG_DMA_NONCOHERENT +endif + +# Abort on DMA output buffers that are not aligned and padded (requires +# DMA_NONCOHERENT=1; padding is only checked with ASAN=1). The large +# alignment keeps a buffer missing WH_DMA_ALIGNED from being aligned by luck. +ifeq ($(DMA_ALIGN_CHECK),1) + ifneq ($(DMA_NONCOHERENT),1) + $(error "DMA_ALIGN_CHECK=1 requires DMA_NONCOHERENT=1 to be set") + endif + DEF += -DWOLFHSM_CFG_TEST_DMA_ALIGN_CHECK -DWOLFHSM_CFG_DMA_ALIGN=256 +endif + # Enable CRC16 integrity checking in the NVM flash backend ifeq ($(NVM_FLASH_CRC),1) DEF += -DWOLFHSM_CFG_NVM_FLASH_CRC16 @@ -209,6 +227,14 @@ ifeq ($(TESTWOLFCRYPT),1) endif endif + # wolfCrypt cannot use DMA with non-coherent caches (WH_DEV_ID_DMA fails + # every operation), so the suite cannot run against WH_DEV_ID_DMA + ifneq ($(TESTWOLFCRYPT_DMA),) + ifeq ($(DMA_NONCOHERENT),1) + $(error "TESTWOLFCRYPT_DMA=1 cannot be used with DMA_NONCOHERENT=1") + endif + endif + # TESTWOLFCRYPT_DEVID and TESTWOLFCRYPT_DMA are mutually exclusive ifneq ($(TESTWOLFCRYPT_DMA),) ifneq ($(TESTWOLFCRYPT_DEVID),) diff --git a/test-refactor/posix/wh_test_posix_main.c b/test-refactor/posix/wh_test_posix_main.c index 079f31554..8b1284b89 100644 --- a/test-refactor/posix/wh_test_posix_main.c +++ b/test-refactor/posix/wh_test_posix_main.c @@ -92,6 +92,9 @@ int whTest_LogPosixFile(void* ctx); int whTest_LogPosixFileConcurrent(void* ctx); int whTest_LogClientServerMemTransport(void* ctx); +/* POSIX shared memory DMA callback: client buffers used in place */ +int whTest_PosixShmDmaInPlace(void* ctx); + /* * Port-owned contexts. The thread functions fill these in and * hand them to the group functions, paralleling the firmware @@ -342,6 +345,11 @@ int main(void) if (rc != 0 && rc != WH_TEST_SKIPPED && miscRc == 0) { miscRc = rc; } + rc = whTestGroup_RunOne("whTest_PosixShmDmaInPlace", + whTest_PosixShmDmaInPlace, NULL); + if (rc != 0 && rc != WH_TEST_SKIPPED && miscRc == 0) { + miscRc = rc; + } /* Concurrent keygen and cached-key read tests. Both are * self-contained (own shared NVM + client/server pairs), so they run * in this pre-server slot rather than against the live diff --git a/test-refactor/posix/wh_test_posix_shm_dma.c b/test-refactor/posix/wh_test_posix_shm_dma.c new file mode 100644 index 000000000..b5d46c3c9 --- /dev/null +++ b/test-refactor/posix/wh_test_posix_shm_dma.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2026 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 . + */ +/* + * test-refactor/posix/wh_test_posix_shm_dma.c + * + * In-place buffers in the POSIX shared memory client DMA callback. A client + * buffer already inside the DMA area is passed to the server as its offset, + * without a bounce copy; with WOLFHSM_CFG_DMA_NONCOHERENT a buffer the server + * writes must also be aligned. The object is mapped twice, as server and as + * client, so the two mappings sit at different addresses as in two processes. + */ + +#include "wolfhsm/wh_settings.h" + +#include "wh_test_common.h" +#include "wh_test_list.h" /* WH_TEST_SKIPPED */ + +#if !defined(WOLFHSM_CFG_DMA) || defined(WOLFHSM_CFG_NO_CRYPTO) || \ + !defined(WOLFHSM_CFG_ENABLE_CLIENT) || !defined(WOLFHSM_CFG_ENABLE_SERVER) + +int whTest_PosixShmDmaInPlace(void* ctx) +{ + (void)ctx; + return WH_TEST_SKIPPED; +} + +#else + +#include +#include +#include +#include +#include + +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_client.h" +#include "port/posix/posix_transport_shm.h" + +/* Without NONCOHERENT any alignment is accepted; 64 just exercises the path */ +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#define SHMDMA_ALIGN WOLFHSM_CFG_DMA_ALIGN +#else +#define SHMDMA_ALIGN 64 +#endif +#define SHMDMA_LEN 64 + +static int _ShmDmaInPlace(whClientContext* client, uint8_t* cliDma, + uint8_t* srvDma) +{ + whDmaFlags flags; + void* off = NULL; + uint8_t* buf; + int ret; + + memset(&flags, 0, sizeof(flags)); + buf = (uint8_t*)(((uintptr_t)cliDma + SHMDMA_ALIGN - 1) & + ~((uintptr_t)SHMDMA_ALIGN - 1)); + WH_TEST_ASSERT_RETURN(srvDma != cliDma); + + /* Aligned output: used in place, the server reaches it by offset */ + ret = posixTransportShm_ClientStaticMemDmaCallback( + client, (uintptr_t)buf, &off, SHMDMA_LEN, WH_DMA_OPER_CLIENT_WRITE_PRE, + flags); + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_OK); + WH_TEST_ASSERT_RETURN((uintptr_t)off == (uintptr_t)(buf - cliDma)); + memset(srvDma + (uintptr_t)off, 0xA5, SHMDMA_LEN); + WH_TEST_ASSERT_RETURN(buf[0] == 0xA5 && buf[SHMDMA_LEN - 1] == 0xA5); + ret = posixTransportShm_ClientStaticMemDmaCallback( + client, (uintptr_t)buf, &off, SHMDMA_LEN, WH_DMA_OPER_CLIENT_WRITE_POST, + flags); + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_OK); + + /* Unaligned output: shares a cache line, refused when non-coherent */ + ret = posixTransportShm_ClientStaticMemDmaCallback( + client, (uintptr_t)(buf + 1), &off, SHMDMA_LEN, + WH_DMA_OPER_CLIENT_WRITE_PRE, flags); +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_BADARGS); +#else + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_OK); +#endif + + /* Unaligned input: the server only reads it, so always accepted */ + ret = posixTransportShm_ClientStaticMemDmaCallback( + client, (uintptr_t)(buf + 1), &off, SHMDMA_LEN, + WH_DMA_OPER_CLIENT_READ_PRE, flags); + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_OK); + WH_TEST_ASSERT_RETURN((uintptr_t)off == (uintptr_t)(buf + 1 - cliDma)); + ret = posixTransportShm_ClientStaticMemDmaCallback( + client, (uintptr_t)(buf + 1), &off, SHMDMA_LEN, + WH_DMA_OPER_CLIENT_READ_POST, flags); + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_OK); + + return 0; +} + +int whTest_PosixShmDmaInPlace(void* ctx) +{ + char name[32]; + posixTransportShmConfig cfg; + posixTransportShmServerContext srvShm[1]; + posixTransportShmClientContext cliShm[1]; + whClientContext client[1]; + void* cliDma = NULL; + void* srvDma = NULL; + int ret; + + (void)ctx; + /* Per-process name, so concurrent test runs do not share the object */ + (void)snprintf(name, sizeof(name), "/wh_test_shmdma_%d", (int)getpid()); + memset(&cfg, 0, sizeof(cfg)); + cfg.name = name; + cfg.req_size = 256; + cfg.resp_size = 256; + cfg.dma_size = 4 * SHMDMA_ALIGN; + + memset(client, 0, sizeof(client)); + client->comm->transport_context = cliShm; + + ret = posixTransportShm_ServerInit(srvShm, &cfg, NULL, NULL); + if (ret == 0) { + ret = posixTransportShm_ClientInit(cliShm, &cfg, NULL, NULL); + if (ret == 0) { + (void)posixTransportShm_GetDma(cliShm, &cliDma, NULL); + (void)posixTransportShm_GetDma(srvShm, &srvDma, NULL); + ret = (cliDma == NULL || srvDma == NULL) + ? WH_ERROR_NOTREADY + : _ShmDmaInPlace(client, cliDma, srvDma); + (void)posixTransportShm_Cleanup(cliShm); + } + (void)posixTransportShm_Cleanup(srvShm); + (void)shm_unlink(name); /* normally already unlinked by the client */ + } + return ret; +} + +#endif diff --git a/test-refactor/wh_test_list.c b/test-refactor/wh_test_list.c index cfd5d09b7..754c0d53f 100644 --- a/test-refactor/wh_test_list.c +++ b/test-refactor/wh_test_list.c @@ -40,11 +40,13 @@ #endif /* Test declarations and weak skip implementations. */ +WH_TEST_DECL(whTest_CacheHelpers); WH_TEST_DECL(whTest_ClientDevId); WH_TEST_DECL(whTest_Comm); WH_TEST_DECL(whTest_CryptoAffinity); WH_TEST_DECL(whTest_CryptoAesGcmDmaAad); WH_TEST_DECL(whTest_Dma); +WH_TEST_DECL(whTest_DmaNonCoherent); WH_TEST_DECL(whTest_HwKeystore); WH_TEST_DECL(whTest_KeystoreReqSize); WH_TEST_DECL(whTest_MessageNvmTranslate); @@ -115,20 +117,22 @@ WH_TEST_DECL(whTest_AuthSetCredentials); WH_TEST_DECL(whTest_AuthRequestAuthorization); const whTestCase whTestsMisc[] = { - { "whTest_ClientDevId", whTest_ClientDevId }, - { "whTest_Comm", whTest_Comm }, - { "whTest_Dma", whTest_Dma }, - { "whTest_CryptoAffinity", whTest_CryptoAffinity }, - { "whTest_CryptoAesGcmDmaAad", whTest_CryptoAesGcmDmaAad }, - { "whTest_KeystoreReqSize", whTest_KeystoreReqSize }, - { "whTest_MessageNvmTranslate", whTest_MessageNvmTranslate }, - { "whTest_MultiClient", whTest_MultiClient }, - { "whTest_HwKeystore", whTest_HwKeystore }, - { "whTest_Lock", whTest_Lock }, - { "whTest_Log", whTest_Log }, - { "whTest_SheKeywrapInterop", whTest_SheKeywrapInterop }, - { "whTest_SheNoNvm", whTest_SheNoNvm }, - { "whTest_SheUidCb", whTest_SheUidCb }, + {"whTest_CacheHelpers", whTest_CacheHelpers}, + {"whTest_ClientDevId", whTest_ClientDevId}, + {"whTest_Comm", whTest_Comm}, + {"whTest_Dma", whTest_Dma}, + {"whTest_DmaNonCoherent", whTest_DmaNonCoherent}, + {"whTest_CryptoAffinity", whTest_CryptoAffinity}, + {"whTest_CryptoAesGcmDmaAad", whTest_CryptoAesGcmDmaAad}, + {"whTest_KeystoreReqSize", whTest_KeystoreReqSize}, + {"whTest_MessageNvmTranslate", whTest_MessageNvmTranslate}, + {"whTest_MultiClient", whTest_MultiClient}, + {"whTest_HwKeystore", whTest_HwKeystore}, + {"whTest_Lock", whTest_Lock}, + {"whTest_Log", whTest_Log}, + {"whTest_SheKeywrapInterop", whTest_SheKeywrapInterop}, + {"whTest_SheNoNvm", whTest_SheNoNvm}, + {"whTest_SheUidCb", whTest_SheUidCb}, }; const size_t whTestsMiscCount = ARRAY_SIZE(whTestsMisc); diff --git a/test/Makefile b/test/Makefile index f2ed29d33..3b0205dff 100644 --- a/test/Makefile +++ b/test/Makefile @@ -142,6 +142,24 @@ ifeq ($(DMA),1) DEF += -DWOLFHSM_CFG_DMA endif +# DMA with non-coherent client caches (requires DMA=1) +ifeq ($(DMA_NONCOHERENT),1) + ifneq ($(DMA),1) + $(error "DMA_NONCOHERENT=1 requires DMA=1 to be set") + endif + DEF += -DWOLFHSM_CFG_DMA_NONCOHERENT +endif + +# Abort on DMA output buffers that are not aligned and padded (requires +# DMA_NONCOHERENT=1; padding is only checked with ASAN=1). The large +# alignment keeps a buffer missing WH_DMA_ALIGNED from being aligned by luck. +ifeq ($(DMA_ALIGN_CHECK),1) + ifneq ($(DMA_NONCOHERENT),1) + $(error "DMA_ALIGN_CHECK=1 requires DMA_NONCOHERENT=1 to be set") + endif + DEF += -DWOLFHSM_CFG_TEST_DMA_ALIGN_CHECK -DWOLFHSM_CFG_DMA_ALIGN=256 +endif + # Enable CRC16 integrity checking in the NVM flash backend ifeq ($(NVM_FLASH_CRC),1) DEF += -DWOLFHSM_CFG_NVM_FLASH_CRC16 @@ -285,6 +303,13 @@ ifeq ($(TESTWOLFCRYPT),1) endif endif + # wolfCrypt cannot use DMA with non-coherent caches (WH_DEV_ID_DMA fails) + ifneq ($(TESTWOLFCRYPT_DMA),) + ifeq ($(DMA_NONCOHERENT),1) + $(error "TESTWOLFCRYPT_DMA=1 cannot be used with DMA_NONCOHERENT=1") + endif + endif + # TESTWOLFCRYPT_DEVID and TESTWOLFCRYPT_DMA are mutually exclusive ifneq ($(TESTWOLFCRYPT_DMA),) ifneq ($(TESTWOLFCRYPT_DEVID),) diff --git a/test/wh_test_cert.c b/test/wh_test_cert.c index 4ca7ec5f0..8e476711a 100644 --- a/test/wh_test_cert.c +++ b/test/wh_test_cert.c @@ -1968,7 +1968,7 @@ int whTest_CertClientDma_ClientServerTestInternal(whClientContext* client) whNvmId rootCertA_id = 1; whNvmId rootCertB_id = 2; whKeyId out_keyId = WH_KEYID_ERASED; - uint8_t exportedPubKey[LEAF_A_PUBKEY_len]; + WH_DMA_ALIGNED uint8_t exportedPubKey[WH_DMA_PAD_SIZE(LEAF_A_PUBKEY_len)]; uint16_t exportedPubKeyLen = sizeof(exportedPubKey); WH_TEST_PRINT("Starting certificate client DMA test...\n"); @@ -2261,7 +2261,7 @@ static int whTest_CertNonExportable(whClientContext* client) int32_t out_rc = 0; whNvmId exportable_cert_id = 101; whNvmId nonexportable_cert_id = 102; - uint8_t cert_buffer[2048] = {0}; + WH_DMA_ALIGNED uint8_t cert_buffer[WH_DMA_PAD_SIZE(2048)] = {0}; uint32_t cert_len = sizeof(cert_buffer); WH_TEST_PRINT("Testing non-exportable certificate functionality...\n"); diff --git a/test/wh_test_clientserver.c b/test/wh_test_clientserver.c index 994720c96..6a8f21e33 100644 --- a/test/wh_test_clientserver.c +++ b/test/wh_test_clientserver.c @@ -447,7 +447,7 @@ static int _testClientDmaBounce(whServerContext* server, whClientContext* client /* key material to cache + export back */ uint8_t keyIn[32]; - uint8_t keyOut[32]; + WH_DMA_ALIGNED uint8_t keyOut[WH_DMA_PAD_SIZE(32)]; uint8_t labelIn[WH_NVM_LABEL_LEN]; uint8_t labelOut[WH_NVM_LABEL_LEN]; uint16_t keyIdIn = (uint16_t)WH_KEYID_ERASED; @@ -458,7 +458,7 @@ static int _testClientDmaBounce(whServerContext* server, whClientContext* client whNvmMetadata meta = {0}; const char* dataIn = "bounce-pool-payload"; whNvmSize dataLen = (whNvmSize)strlen(dataIn); - uint8_t dataOut[64]; + WH_DMA_ALIGNED uint8_t dataOut[WH_DMA_PAD_SIZE(64)]; WH_TEST_PRINT( "Testing client *Dma APIs through a translating DMA callback...\n"); @@ -950,7 +950,8 @@ int whTest_ClientServerSequential(whTestNvmBackendType nvmType) WH_TEST_ASSERT_RETURN(WH_COMM_CONNECTED == server_connected); int counter = 1; - char recv_buffer[WOLFHSM_CFG_COMM_DATA_LEN] = {0}; + WH_DMA_ALIGNED char + recv_buffer[WH_DMA_PAD_SIZE(WOLFHSM_CFG_COMM_DATA_LEN)] = {0}; char send_buffer[WOLFHSM_CFG_COMM_DATA_LEN] = {0}; uint16_t send_len = 0; uint16_t recv_len = 0; @@ -1444,7 +1445,8 @@ int whTest_ClientServerClientConfig(whClientConfig* clientCfg) WH_TEST_RETURN_ON_FAIL(wh_Client_Init(client, clientCfg)); int counter = 1; - char recv_buffer[WOLFHSM_CFG_COMM_DATA_LEN] = {0}; + WH_DMA_ALIGNED char + recv_buffer[WH_DMA_PAD_SIZE(WOLFHSM_CFG_COMM_DATA_LEN)] = {0}; char send_buffer[WOLFHSM_CFG_COMM_DATA_LEN] = {0}; uint16_t send_len = 0; uint16_t recv_len = 0; diff --git a/test/wh_test_common.h b/test/wh_test_common.h index 42989c0cc..bf1145a73 100644 --- a/test/wh_test_common.h +++ b/test/wh_test_common.h @@ -92,9 +92,11 @@ * WH_DEV_ID. The DMA-only WH_DEV_ID_DMA is exercised by running the * wolfCrypt test suite against it (TESTWOLFCRYPT=1 defaults WC_USE_DEVID to * WH_DEV_ID; TESTWOLFCRYPT_DMA=1 uses WH_DEV_ID_DMA). */ -#ifdef WOLFHSM_CFG_DMA +#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_DMA_NONCOHERENT) #define WH_TEST_DMA_MODE_CNT 2 #else +/* Without DMA, or with WOLFHSM_CFG_DMA_NONCOHERENT (wolfCrypt cannot use DMA + * there, so wh_Client_SetDmaMode(client, 1) is refused) */ #define WH_TEST_DMA_MODE_CNT 1 #endif diff --git a/test/wh_test_crypto.c b/test/wh_test_crypto.c index 4e2e8af02..4972f9697 100644 --- a/test/wh_test_crypto.c +++ b/test/wh_test_crypto.c @@ -369,7 +369,7 @@ static int whTest_CryptoRngDmaAsync(whClientContext* ctx) int ret = WH_ERROR_OK; /* DMA bypasses the comm buffer so we can request more than COMM_DATA_LEN * in a single round trip. */ - uint8_t big[WOLFHSM_CFG_COMM_DATA_LEN * 2]; + WH_DMA_ALIGNED uint8_t big[WH_DMA_PAD_SIZE(WOLFHSM_CFG_COMM_DATA_LEN * 2)]; /* Case A: basic DMA Request -> Response */ if (ret == 0) { @@ -394,7 +394,7 @@ static int whTest_CryptoRngDmaAsync(whClientContext* ctx) /* Case B: small DMA request still works (no chunking semantics). */ if (ret == 0) { - uint8_t small[32]; + WH_DMA_ALIGNED uint8_t small[WH_DMA_PAD_SIZE(32)]; memset(small, 0, sizeof(small)); ret = wh_Client_RngGenerateDmaRequest(ctx, small, sizeof(small)); if (ret == 0) { @@ -450,6 +450,111 @@ static int whTest_CryptoRngDmaAsync(whClientContext* ctx) } #endif /* WOLFHSM_CFG_DMA */ +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +/* With non-coherent DMA, wolfCrypt must not reach the DMA path: operations on + * WH_DEV_ID_DMA fail with WC_HW_E (no silent software fallback), objects + * created with it can still be freed, and DMA-preferred mode is refused. */ +static int whTest_CryptoDmaNoncoherentRefusal(whClientContext* ctx, + whClientConfig* config) +{ + int ret = 0; + int rc; + int mode = -1; + +/* Needs a cipher operation that always reaches the cryptoCb: SetKey alone only + * does so on builds that route it there, otherwise it returns 0 */ +#if !defined(NO_AES) && defined(HAVE_AES_CBC) + if (ret == 0) { + Aes aes[1]; + const uint8_t key[AES_128_KEY_SIZE] = {0}; + const uint8_t iv[AES_BLOCK_SIZE] = {0}; + uint8_t in[AES_BLOCK_SIZE] = {0}; + uint8_t out[AES_BLOCK_SIZE] = {0}; + + ret = wc_AesInit(aes, NULL, WH_DEV_ID_DMA); + if (ret == 0) { + /* The key may be handed to the cryptoCb already (SETKEY) */ + rc = wc_AesSetKey(aes, key, sizeof(key), iv, AES_ENCRYPTION); + if (rc == 0) { + rc = wc_AesCbcEncrypt(aes, out, in, sizeof(in)); + } + if (rc != WC_HW_E) { + WH_ERROR_PRINT("AES on WH_DEV_ID_DMA returned %d, expected " + "WC_HW_E\n", + rc); + ret = WH_ERROR_ABORTED; + } + wc_AesFree(aes); + } + } +#endif /* !NO_AES && HAVE_AES_CBC */ + +#ifndef NO_SHA256 + if (ret == 0) { + wc_Sha256 sha[1]; + const uint8_t msg[] = "noncoherent"; + + ret = wc_InitSha256_ex(sha, NULL, WH_DEV_ID_DMA); + if (ret == 0) { + rc = wc_Sha256Update(sha, msg, sizeof(msg)); + if (rc != WC_HW_E) { + WH_ERROR_PRINT("SHA256 on WH_DEV_ID_DMA returned %d, expected " + "WC_HW_E\n", + rc); + ret = WH_ERROR_ABORTED; + } + wc_Sha256Free(sha); + } + } +#endif /* !NO_SHA256 */ + + /* DMA-preferred mode is refused and the mode stays standard */ + if (ret == 0) { + rc = wh_Client_SetDmaMode(ctx, 1); + if ((rc != WH_ERROR_BADARGS) || + (wh_Client_GetDmaMode(ctx, &mode) != WH_ERROR_OK) || (mode != 0)) { + WH_ERROR_PRINT("SetDmaMode(1) returned %d (mode %d), expected " + "WH_ERROR_BADARGS (mode 0)\n", + rc, mode); + ret = WH_ERROR_ABORTED; + } + } + if (ret == 0) { + ret = wh_Client_SetDmaMode(ctx, 0); + } + + /* A config preferring DMA is refused before anything is initialized */ + if (ret == 0) { + whClientContext other[1]; + whClientConfig otherCfg = *config; + whClientDmaConfig dmaCfg; + + memset(&dmaCfg, 0, sizeof(dmaCfg)); + if (config->dmaConfig != NULL) { + dmaCfg = *config->dmaConfig; + } + dmaCfg.preferDma = 1; + otherCfg.dmaConfig = &dmaCfg; + + rc = wh_Client_Init(other, &otherCfg); + if (rc != WH_ERROR_BADARGS) { + WH_ERROR_PRINT("wh_Client_Init with preferDma returned %d, " + "expected WH_ERROR_BADARGS\n", + rc); + if (rc == WH_ERROR_OK) { + (void)wh_Client_Cleanup(other); + } + ret = WH_ERROR_ABORTED; + } + } + + if (ret == 0) { + WH_TEST_PRINT("DMA NONCOHERENT REFUSAL SUCCESS\n"); + } + return ret; +} +#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ + #ifndef NO_RSA static int whTest_CryptoRsa(whClientContext* ctx, int devId, WC_RNG* rng) { @@ -2222,7 +2327,7 @@ static int whTest_CryptoEccExportPublicDma(whClientContext* ctx, int devId, uint8_t sig[ECC_MAX_SIG_SIZE] = {0}; word32 sigLen = sizeof(sig); int verified = 0; - byte derBuf[ECC_BUFSIZE]; + WH_DMA_ALIGNED byte derBuf[WH_DMA_PAD_SIZE(ECC_BUFSIZE)]; uint16_t derSz = sizeof(derBuf); word32 i; @@ -4388,7 +4493,7 @@ static int whTest_CryptoEd25519Dma(whClientContext* ctx, int devId, WC_RNG* rng) whKeyId signKeyId = WH_KEYID_ERASED; whKeyId verifyKeyId = WH_KEYID_ERASED; byte msg[] = "Ed25519 DMA message"; - byte sig[ED25519_SIG_SIZE]; + WH_DMA_ALIGNED byte sig[WH_DMA_PAD_SIZE(ED25519_SIG_SIZE)]; uint32_t sigSz = sizeof(sig); int verified = 0; uint8_t label[] = "Ed25519 DMA Key"; @@ -8506,7 +8611,8 @@ static int whTest_KeyCache(whClientContext* ctx, int devId, WC_RNG* rng) uint16_t outLen; uint16_t keyId; uint8_t key[WH_TEST_KEYCACHE_KEYSIZE]; - uint8_t keyOut[WH_TEST_KEYCACHE_KEYSIZE] = {0}; + WH_DMA_ALIGNED uint8_t keyOut[WH_DMA_PAD_SIZE(WH_TEST_KEYCACHE_KEYSIZE)] = { + 0}; uint8_t labelIn[WH_NVM_LABEL_LEN] = "KeyCache Test Label"; uint8_t labelOut[WH_NVM_LABEL_LEN] = {0}; @@ -8889,7 +8995,7 @@ static int whTest_KeyCache(whClientContext* ctx, int devId, WC_RNG* rng) uint8_t labelBig[WH_NVM_LABEL_LEN] = "Big DMA Key Label"; /* Buffer for exported key and metadata */ - uint8_t exportedKey[bigKeySize]; + WH_DMA_ALIGNED uint8_t exportedKey[WH_DMA_PAD_SIZE(bigKeySize)]; uint8_t exportedLabel[WH_NVM_LABEL_LEN]; uint16_t exportedKeySize; @@ -9133,7 +9239,8 @@ static int whTest_NonExportableKeystore(whClientContext* ctx, int devId, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00}; - uint8_t exportedKey[WH_TEST_KEYSTORE_TEST_SZ] = {0}; + WH_DMA_ALIGNED uint8_t + exportedKey[WH_DMA_PAD_SIZE(WH_TEST_KEYSTORE_TEST_SZ)] = {0}; uint8_t label[WH_NVM_LABEL_LEN] = "NonExportableTestKey"; uint8_t exportedLabel[WH_NVM_LABEL_LEN] = {0}; uint16_t exportedKeySize; @@ -11131,8 +11238,9 @@ static int whTest_CryptoAesDmaAsync(whClientContext* ctx, int devId, uint8_t key[WH_TEST_AES_ASYNC_DMA_KEYSZ]; uint8_t iv[AES_BLOCK_SIZE]; uint8_t plainIn[WH_TEST_AES_ASYNC_DMA_BUFSZ]; - uint8_t cipher[WH_TEST_AES_ASYNC_DMA_BUFSZ]; - uint8_t plainOut[WH_TEST_AES_ASYNC_DMA_BUFSZ]; + WH_DMA_ALIGNED uint8_t cipher[WH_DMA_PAD_SIZE(WH_TEST_AES_ASYNC_DMA_BUFSZ)]; + WH_DMA_ALIGNED uint8_t + plainOut[WH_DMA_PAD_SIZE(WH_TEST_AES_ASYNC_DMA_BUFSZ)]; memset(plainIn, 0xBB, sizeof(plainIn)); memset(cipher, 0, sizeof(cipher)); @@ -11165,7 +11273,7 @@ static int whTest_CryptoAesDmaAsync(whClientContext* ctx, int devId, } if (ret == 0) { ret = wh_Client_AesCbcDmaRequest(ctx, aes, 0, cipher, - sizeof(cipher), plainOut); + sizeof(plainIn), plainOut); } if (ret == 0) { do { @@ -11206,7 +11314,7 @@ static int whTest_CryptoAesDmaAsync(whClientContext* ctx, int devId, } if (ret == 0) { ret = wh_Client_AesCtrDmaRequest(ctx, aes, 1, cipher, - sizeof(cipher), plainOut); + sizeof(plainIn), plainOut); } if (ret == 0) { do { @@ -11269,7 +11377,7 @@ static int whTest_CryptoAesDmaAsync(whClientContext* ctx, int devId, } if (ret == 0) { ret = wh_Client_AesEcbDmaRequest(ctx, aes, 0, cipher, - sizeof(cipher), plainOut); + sizeof(plainIn), plainOut); } if (ret == 0) { do { @@ -11358,9 +11466,8 @@ static int whTest_CryptoAesDmaAsync(whClientContext* ctx, int devId, if (ret == 0) { memcpy(dec_tag, enc_tag, sizeof(dec_tag)); ret = wh_Client_AesGcmDmaRequest( - ctx, aes, 0, cipher, sizeof(cipher), plainOut, iv, - AES_BLOCK_SIZE, authin, aadSz[i], dec_tag, - sizeof(dec_tag)); + ctx, aes, 0, cipher, sizeof(plainIn), plainOut, iv, + AES_BLOCK_SIZE, authin, aadSz[i], dec_tag, sizeof(dec_tag)); } if (ret == 0) { do { @@ -11395,7 +11502,7 @@ static int whTest_CryptoAesDmaAsyncKat(whClientContext* ctx, int devId) { int ret = 0; Aes aes[1]; - uint8_t outBuf[64]; + WH_DMA_ALIGNED uint8_t outBuf[WH_DMA_PAD_SIZE(64)]; #ifdef HAVE_AES_CBC { @@ -11794,8 +11901,8 @@ static int whTest_CryptoAesDmaAsyncKat(whClientContext* ctx, int devId) {gcm256Key, 32, gcm256Plain, sizeof(gcm256Plain), gcm256Aad, sizeof(gcm256Aad), gcm256Cipher, gcm256Tag}, }; - uint8_t cipherBuf[64]; - uint8_t plainBuf[64]; + WH_DMA_ALIGNED uint8_t cipherBuf[WH_DMA_PAD_SIZE(64)]; + WH_DMA_ALIGNED uint8_t plainBuf[WH_DMA_PAD_SIZE(64)]; uint8_t tagBuf[AES_BLOCK_SIZE]; size_t i; for (i = 0; i < sizeof(v) / sizeof(v[0]) && ret == 0; i++) { @@ -13819,7 +13926,7 @@ static int whTestCrypto_MlDsaDmaClient(whClientContext* ctx, int devId, /* Test signing and verification */ if (ret == 0) { byte msg[] = "Test message to sign"; - byte sig[MLDSA_MAX_SIG_SIZE]; + WH_DMA_ALIGNED byte sig[WH_DMA_PAD_SIZE(MLDSA_MAX_SIG_SIZE)]; word32 sigLen = sizeof(sig); int verified = 0; @@ -13882,7 +13989,7 @@ static int whTestCrypto_MlDsaDmaClient(whClientContext* ctx, int devId, /* Test signing and verification with a FIPS 204 context string */ if (ret == 0) { byte msg[] = "Context test message"; - byte sig[MLDSA_MAX_SIG_SIZE]; + WH_DMA_ALIGNED byte sig[WH_DMA_PAD_SIZE(MLDSA_MAX_SIG_SIZE)]; word32 sigLen = sizeof(sig); int verified = 0; const byte ctx_str[] = "test-context"; @@ -13980,7 +14087,8 @@ static int whTestCrypto_MlDsaExportPublicDma(whClientContext* ctx, int devId, /* Full DMA export must be denied */ { - byte fullBuf[MLDSA_MAX_BOTH_KEY_DER_SIZE]; + WH_DMA_ALIGNED byte + fullBuf[WH_DMA_PAD_SIZE(MLDSA_MAX_BOTH_KEY_DER_SIZE)]; uint16_t fullLen = sizeof(fullBuf); int denyRet = wh_Client_KeyExportDma(ctx, keyId, fullBuf, fullLen, NULL, 0, &denyLen); @@ -14019,7 +14127,7 @@ static int whTestCrypto_MlDsaExportPublicDma(whClientContext* ctx, int devId, * key. This cross-validates that the DMA path isn't producing * subtly different output. */ if (ret == 0) { - byte dmaDer[MLDSA_MAX_PUB_KEY_DER_SIZE]; + WH_DMA_ALIGNED byte dmaDer[WH_DMA_PAD_SIZE(MLDSA_MAX_PUB_KEY_DER_SIZE)]; byte nonDmaDer[MLDSA_MAX_PUB_KEY_DER_SIZE]; uint16_t dmaSz = sizeof(dmaDer); uint16_t nonDmaSz = sizeof(nonDmaDer); @@ -14050,10 +14158,12 @@ static int whTestCrypto_MlDsaExportPublicDma(whClientContext* ctx, int devId, } } - /* Negative: a too-small client buffer must yield WH_ERROR_NOSPACE. */ + /* Negative: a too-small client buffer must yield WH_ERROR_NOSPACE. Pass its + * real size: sizeof(tinyBuf) is padded to the DMA alignment. */ if (ret == 0) { - byte tinyBuf[8]; - uint16_t tinySz = sizeof(tinyBuf); + WH_DMA_ALIGNED byte tinyBuf[WH_DMA_PAD_SIZE(8)]; + + uint16_t tinySz = 8; int negRet = wh_Client_KeyExportPublicDma( ctx, keyId, WH_KEY_ALGO_MLDSA, tinyBuf, tinySz, NULL, 0, &tinySz); if (negRet != WH_ERROR_NOSPACE) { @@ -14085,7 +14195,7 @@ static int whTestCrypto_MlDsaCacheKeyAndExportPublicDma(whClientContext* ctx, wc_MlDsaKey genPub[1] = {0}; wc_MlDsaKey refPub[1] = {0}; byte msg[] = "ML-DSA DMA cache-export-public message"; - byte sig[MLDSA_MAX_SIG_SIZE]; + WH_DMA_ALIGNED byte sig[WH_DMA_PAD_SIZE(MLDSA_MAX_SIG_SIZE)]; word32 sigLen = sizeof(sig); int verified = 0; byte genDer[MLDSA_MAX_PUB_KEY_DER_SIZE]; @@ -15354,7 +15464,8 @@ static int whTestCrypto_MlKemExportPublicDma(whClientContext* ctx, int devId, /* Full DMA export must be denied. */ { - byte fullBuf[WC_ML_KEM_MAX_PRIVATE_KEY_SIZE]; + WH_DMA_ALIGNED byte + fullBuf[WH_DMA_PAD_SIZE(WC_ML_KEM_MAX_PRIVATE_KEY_SIZE)]; uint16_t fullLen = sizeof(fullBuf); int denyRet = wh_Client_KeyExportDma(ctx, keyId, fullBuf, fullLen, NULL, 0, &fullLen); @@ -15433,7 +15544,8 @@ static int whTestCrypto_MlKemExportPublicDma(whClientContext* ctx, int devId, /* Byte-identity check: DMA and non-DMA paths must produce the * same public bytes for the same cached key. */ if (ret == 0) { - byte dmaBuf[WC_ML_KEM_MAX_PUBLIC_KEY_SIZE]; + WH_DMA_ALIGNED byte + dmaBuf[WH_DMA_PAD_SIZE(WC_ML_KEM_MAX_PUBLIC_KEY_SIZE)]; byte nonDmaBuf[WC_ML_KEM_MAX_PUBLIC_KEY_SIZE]; uint16_t dmaSz = sizeof(dmaBuf); uint16_t nonDmaSz = sizeof(nonDmaBuf); @@ -15464,10 +15576,13 @@ static int whTestCrypto_MlKemExportPublicDma(whClientContext* ctx, int devId, } } - /* Negative: a too-small client buffer must yield WH_ERROR_NOSPACE. */ + /* Negative: a too-small client buffer must yield WH_ERROR_NOSPACE. + * Pass its real size: sizeof(tinyBuf) is padded to the DMA alignment. + */ if (ret == 0) { - byte tinyBuf[8]; - uint16_t tinySz = sizeof(tinyBuf); + WH_DMA_ALIGNED byte tinyBuf[WH_DMA_PAD_SIZE(8)]; + + uint16_t tinySz = 8; int negRet = wh_Client_KeyExportPublicDma( ctx, keyId, WH_KEY_ALGO_MLKEM, tinyBuf, tinySz, NULL, 0, &tinySz); @@ -15633,7 +15748,7 @@ static int whTestCrypto_MlKemDmaClient(whClientContext* ctx, int devId, int levels[3]; int levelCnt = 0; int i; - byte ct[WC_ML_KEM_MAX_CIPHER_TEXT_SIZE]; + WH_DMA_ALIGNED byte ct[WH_DMA_PAD_SIZE(WC_ML_KEM_MAX_CIPHER_TEXT_SIZE)]; byte ssEnc[WC_ML_KEM_SS_SZ]; byte ssDec[WC_ML_KEM_SS_SZ]; byte ssWrong[WC_ML_KEM_SS_SZ]; @@ -16024,7 +16139,77 @@ static int whTestCrypto_MlKemDmaClient(whClientContext* ctx, int devId, #define WH_TEST_LMS_WINTERNITZ (8) /* Generous buffer that fits L1_H5_W8 (~1328) and any W<8 variant of the same * height (W=1 ~8688). Keeps off the stack so ASAN builds stay happy. */ -static byte whTest_LmsSigBuf[8800]; +static WH_DMA_ALIGNED byte whTest_LmsSigBuf[WH_DMA_PAD_SIZE(8800)]; + +/* Key operations under test. wolfCrypt cannot use DMA with non-coherent + * caches, so there the wh_Client_Lms*Dma APIs are driven directly instead of + * going through the cryptoCb (devId is then INVALID_DEVID). */ +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +static int _whTestLms_MakeKey(whClientContext* ctx, LmsKey* key, WC_RNG* rng) +{ + int ret; + (void)rng; + ret = wh_Client_LmsMakeExportKeyDma(ctx, key); + if (ret == 0) { + /* wh_Client_LmsMakeExportKeyDma only fills in the public key and + * keyId, it does not mark the key usable (this predates + * WOLFHSM_CFG_DMA_NONCOHERENT). Set what wc_LmsKey_MakeKey + * sets after a cryptoCb keygen. */ + key->state = WC_LMS_STATE_OK; + key->pubSet = 1; + } + return ret; +} + +static int _whTestLms_SigsLeft(whClientContext* ctx, LmsKey* key) +{ + return (wh_Client_LmsSigsLeftDma(ctx, key) > 0) ? 1 : 0; +} + +static int _whTestLms_Sign(whClientContext* ctx, LmsKey* key, byte* sig, + word32* sigLen, const byte* msg, int msgSz) +{ + return wh_Client_LmsSignDma(ctx, msg, (word32)msgSz, sig, sigLen, key); +} + +static int _whTestLms_Verify(whClientContext* ctx, LmsKey* key, const byte* sig, + word32 sigLen, const byte* msg, int msgSz) +{ + int res = 0; + int ret = + wh_Client_LmsVerifyDma(ctx, sig, sigLen, msg, (word32)msgSz, &res, key); + if ((ret == 0) && (res != 1)) { + ret = SIG_VERIFY_E; + } + return ret; +} +#else +static int _whTestLms_MakeKey(whClientContext* ctx, LmsKey* key, WC_RNG* rng) +{ + (void)ctx; + return wc_LmsKey_MakeKey(key, rng); +} + +static int _whTestLms_SigsLeft(whClientContext* ctx, LmsKey* key) +{ + (void)ctx; + return wc_LmsKey_SigsLeft(key); +} + +static int _whTestLms_Sign(whClientContext* ctx, LmsKey* key, byte* sig, + word32* sigLen, const byte* msg, int msgSz) +{ + (void)ctx; + return wc_LmsKey_Sign(key, sig, sigLen, msg, msgSz); +} + +static int _whTestLms_Verify(whClientContext* ctx, LmsKey* key, const byte* sig, + word32 sigLen, const byte* msg, int msgSz) +{ + (void)ctx; + return wc_LmsKey_Verify(key, sig, sigLen, msg, msgSz); +} +#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ static int whTestCrypto_LmsCryptoCb(whClientContext* ctx, int devId, WC_RNG* rng) @@ -16073,7 +16258,7 @@ static int whTestCrypto_LmsCryptoCb(whClientContext* ctx, int devId, /* MakeKey via cryptocb: the server commits the key to NVM before * returning the public key over DMA. */ if (ret == 0) { - ret = wc_LmsKey_MakeKey(key, rng); + ret = _whTestLms_MakeKey(ctx, key, rng); if (ret != 0) { WH_ERROR_PRINT("Failed LMS MakeKey ret=%d\n", ret); } @@ -16082,7 +16267,7 @@ static int whTestCrypto_LmsCryptoCb(whClientContext* ctx, int devId, /* wc_LmsKey_SigsLeft returns a boolean: nonzero = signatures available, * 0 = exhausted. Fresh key should report nonzero. */ if (ret == 0) { - if (wc_LmsKey_SigsLeft(key) == 0) { + if (_whTestLms_SigsLeft(ctx, key) == 0) { WH_ERROR_PRINT("LMS reported exhausted on fresh key\n"); ret = -1; } @@ -16205,7 +16390,8 @@ static int whTestCrypto_LmsCryptoCb(whClientContext* ctx, int devId, /* Sign via cryptocb. */ if (ret == 0) { sigLen = sigCap; - ret = wc_LmsKey_Sign(key, whTest_LmsSigBuf, &sigLen, msg, (int)msgSz); + ret = _whTestLms_Sign(ctx, key, whTest_LmsSigBuf, &sigLen, msg, + (int)msgSz); if (ret != 0) { WH_ERROR_PRINT("Failed LMS Sign ret=%d\n", ret); } @@ -16218,7 +16404,8 @@ static int whTestCrypto_LmsCryptoCb(whClientContext* ctx, int devId, /* Verify the signature via cryptocb. */ if (ret == 0) { - ret = wc_LmsKey_Verify(key, whTest_LmsSigBuf, sigLen, msg, (int)msgSz); + ret = _whTestLms_Verify(ctx, key, whTest_LmsSigBuf, sigLen, msg, + (int)msgSz); if (ret != 0) { WH_ERROR_PRINT("Failed LMS Verify ret=%d\n", ret); } @@ -16227,7 +16414,8 @@ static int whTestCrypto_LmsCryptoCb(whClientContext* ctx, int devId, /* Tampered signature must fail to verify. */ if (ret == 0) { whTest_LmsSigBuf[0] ^= 0xFF; - ret = wc_LmsKey_Verify(key, whTest_LmsSigBuf, sigLen, msg, (int)msgSz); + ret = _whTestLms_Verify(ctx, key, whTest_LmsSigBuf, sigLen, msg, + (int)msgSz); whTest_LmsSigBuf[0] ^= 0xFF; if (ret == 0) { WH_ERROR_PRINT("LMS Verify unexpectedly accepted tampered sig\n"); @@ -16241,8 +16429,8 @@ static int whTestCrypto_LmsCryptoCb(whClientContext* ctx, int devId, /* Wrong message must also fail to verify. */ if (ret == 0) { const byte wrongMsg[] = "wolfHSM LMS cryptocb wrong"; - ret = wc_LmsKey_Verify(key, whTest_LmsSigBuf, sigLen, wrongMsg, - (int)(sizeof(wrongMsg) - 1)); + ret = _whTestLms_Verify(ctx, key, whTest_LmsSigBuf, sigLen, wrongMsg, + (int)(sizeof(wrongMsg) - 1)); if (ret == 0) { WH_ERROR_PRINT("LMS Verify unexpectedly accepted wrong message\n"); ret = -1; @@ -16255,7 +16443,7 @@ static int whTestCrypto_LmsCryptoCb(whClientContext* ctx, int devId, /* H=5 means 32 sigs total; after one sign, the key is still not * exhausted. */ if (ret == 0) { - if (wc_LmsKey_SigsLeft(key) == 0) { + if (_whTestLms_SigsLeft(ctx, key) == 0) { WH_ERROR_PRINT("LMS reported exhausted after one sign\n"); ret = -1; } @@ -16441,7 +16629,79 @@ static int whTestCrypto_LmsCryptoCb(whClientContext* ctx, int devId, /* "XMSS-SHA2_10_256" is the smallest standardized XMSS parameter set * (height 10, 1024 signatures). pubLen=68, sigLen=2500. */ #define WH_TEST_XMSS_PARAM_STR "XMSS-SHA2_10_256" -static byte whTest_XmssSigBuf[2500]; +static WH_DMA_ALIGNED byte whTest_XmssSigBuf[WH_DMA_PAD_SIZE(2500)]; + +/* Key operations under test. wolfCrypt cannot use DMA with non-coherent + * caches, so there the wh_Client_Xmss*Dma APIs are driven directly instead of + * going through the cryptoCb (devId is then INVALID_DEVID). */ +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +static int _whTestXmss_MakeKey(whClientContext* ctx, XmssKey* key, WC_RNG* rng) +{ + int ret; + (void)rng; + ret = wh_Client_XmssMakeExportKeyDma(ctx, key); + if (ret == 0) { + /* wh_Client_XmssMakeExportKeyDma only fills in the public key and + * keyId, it does not mark the key usable (this predates + * WOLFHSM_CFG_DMA_NONCOHERENT). Set what wc_XmssKey_MakeKey + * sets after a cryptoCb keygen. */ + key->state = WC_XMSS_STATE_OK; + key->pubSet = 1; + } + return ret; +} + +static int _whTestXmss_SigsLeft(whClientContext* ctx, XmssKey* key) +{ + return (wh_Client_XmssSigsLeftDma(ctx, key) > 0) ? 1 : 0; +} + +static int _whTestXmss_Sign(whClientContext* ctx, XmssKey* key, byte* sig, + word32* sigLen, const byte* msg, int msgSz) +{ + return wh_Client_XmssSignDma(ctx, msg, (word32)msgSz, sig, sigLen, key); +} + +static int _whTestXmss_Verify(whClientContext* ctx, XmssKey* key, + const byte* sig, word32 sigLen, const byte* msg, + int msgSz) +{ + int res = 0; + int ret = wh_Client_XmssVerifyDma(ctx, sig, sigLen, msg, (word32)msgSz, + &res, key); + if ((ret == 0) && (res != 1)) { + ret = SIG_VERIFY_E; + } + return ret; +} +#else +static int _whTestXmss_MakeKey(whClientContext* ctx, XmssKey* key, WC_RNG* rng) +{ + (void)ctx; + return wc_XmssKey_MakeKey(key, rng); +} + +static int _whTestXmss_SigsLeft(whClientContext* ctx, XmssKey* key) +{ + (void)ctx; + return wc_XmssKey_SigsLeft(key); +} + +static int _whTestXmss_Sign(whClientContext* ctx, XmssKey* key, byte* sig, + word32* sigLen, const byte* msg, int msgSz) +{ + (void)ctx; + return wc_XmssKey_Sign(key, sig, sigLen, msg, msgSz); +} + +static int _whTestXmss_Verify(whClientContext* ctx, XmssKey* key, + const byte* sig, word32 sigLen, const byte* msg, + int msgSz) +{ + (void)ctx; + return wc_XmssKey_Verify(key, sig, sigLen, msg, msgSz); +} +#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ static int whTestCrypto_XmssCryptoCb(whClientContext* ctx, int devId, WC_RNG* rng) @@ -16489,7 +16749,7 @@ static int whTestCrypto_XmssCryptoCb(whClientContext* ctx, int devId, /* MakeKey via cryptocb: the server commits the key to NVM before * returning the public key over DMA. */ if (ret == 0) { - ret = wc_XmssKey_MakeKey(key, rng); + ret = _whTestXmss_MakeKey(ctx, key, rng); if (ret != 0) { WH_ERROR_PRINT("Failed XMSS MakeKey ret=%d\n", ret); } @@ -16498,7 +16758,7 @@ static int whTestCrypto_XmssCryptoCb(whClientContext* ctx, int devId, /* wc_XmssKey_SigsLeft returns a boolean: nonzero = signatures available, * 0 = exhausted. */ if (ret == 0) { - if (wc_XmssKey_SigsLeft(key) == 0) { + if (_whTestXmss_SigsLeft(ctx, key) == 0) { WH_ERROR_PRINT("XMSS reported exhausted on fresh key\n"); ret = -1; } @@ -16616,7 +16876,8 @@ static int whTestCrypto_XmssCryptoCb(whClientContext* ctx, int devId, if (ret == 0) { sigLen = sigCap; - ret = wc_XmssKey_Sign(key, whTest_XmssSigBuf, &sigLen, msg, (int)msgSz); + ret = _whTestXmss_Sign(ctx, key, whTest_XmssSigBuf, &sigLen, msg, + (int)msgSz); if (ret != 0) { WH_ERROR_PRINT("Failed XMSS Sign ret=%d\n", ret); } @@ -16628,7 +16889,8 @@ static int whTestCrypto_XmssCryptoCb(whClientContext* ctx, int devId, } if (ret == 0) { - ret = wc_XmssKey_Verify(key, whTest_XmssSigBuf, sigLen, msg, (int)msgSz); + ret = _whTestXmss_Verify(ctx, key, whTest_XmssSigBuf, sigLen, msg, + (int)msgSz); if (ret != 0) { WH_ERROR_PRINT("Failed XMSS Verify ret=%d\n", ret); } @@ -16636,7 +16898,8 @@ static int whTestCrypto_XmssCryptoCb(whClientContext* ctx, int devId, if (ret == 0) { whTest_XmssSigBuf[0] ^= 0xFF; - ret = wc_XmssKey_Verify(key, whTest_XmssSigBuf, sigLen, msg, (int)msgSz); + ret = _whTestXmss_Verify(ctx, key, whTest_XmssSigBuf, sigLen, msg, + (int)msgSz); whTest_XmssSigBuf[0] ^= 0xFF; if (ret == 0) { WH_ERROR_PRINT("XMSS Verify unexpectedly accepted tampered sig\n"); @@ -16649,8 +16912,8 @@ static int whTestCrypto_XmssCryptoCb(whClientContext* ctx, int devId, if (ret == 0) { const byte wrongMsg[] = "wolfHSM XMSS cryptocb wrong"; - ret = wc_XmssKey_Verify(key, whTest_XmssSigBuf, sigLen, wrongMsg, - (int)(sizeof(wrongMsg) - 1)); + ret = _whTestXmss_Verify(ctx, key, whTest_XmssSigBuf, sigLen, wrongMsg, + (int)(sizeof(wrongMsg) - 1)); if (ret == 0) { WH_ERROR_PRINT("XMSS Verify unexpectedly accepted wrong message\n"); ret = -1; @@ -16663,7 +16926,7 @@ static int whTestCrypto_XmssCryptoCb(whClientContext* ctx, int devId, /* H=10 means 1024 sigs total; after one sign, the key is still not * exhausted. */ if (ret == 0) { - if (wc_XmssKey_SigsLeft(key) == 0) { + if (_whTestXmss_SigsLeft(ctx, key) == 0) { WH_ERROR_PRINT("XMSS reported exhausted after one sign\n"); ret = -1; } @@ -17235,7 +17498,7 @@ int whTest_CryptoKeyUsagePolicies(whClientContext* client, WC_RNG* rng) { Aes aes[1]; uint8_t iv[AES_BLOCK_SIZE] = {0}; - uint8_t ctrCipher[16] = {0}; + WH_DMA_ALIGNED uint8_t ctrCipher[WH_DMA_PAD_SIZE(16)] = {0}; keyId = WH_KEYID_ERASED; ret = wh_Client_KeyCache(client, WH_NVM_FLAGS_NONE, @@ -17275,7 +17538,7 @@ int whTest_CryptoKeyUsagePolicies(whClientContext* client, WC_RNG* rng) { Aes aes[1]; uint8_t iv[AES_BLOCK_SIZE] = {0}; - uint8_t ctrOut[16] = {0}; + WH_DMA_ALIGNED uint8_t ctrOut[WH_DMA_PAD_SIZE(16)] = {0}; keyId = WH_KEYID_ERASED; ret = wh_Client_KeyCache(client, WH_NVM_FLAGS_USAGE_ENCRYPT, @@ -17316,7 +17579,7 @@ int whTest_CryptoKeyUsagePolicies(whClientContext* client, WC_RNG* rng) WH_TEST_PRINT(" Testing AES ECB DMA encrypt without ENCRYPT flag...\n"); { Aes aes[1]; - uint8_t ecbCipher[16] = {0}; + WH_DMA_ALIGNED uint8_t ecbCipher[WH_DMA_PAD_SIZE(16)] = {0}; keyId = WH_KEYID_ERASED; ret = wh_Client_KeyCache(client, WH_NVM_FLAGS_NONE, @@ -17352,7 +17615,7 @@ int whTest_CryptoKeyUsagePolicies(whClientContext* client, WC_RNG* rng) WH_TEST_PRINT(" Testing AES ECB DMA decrypt without DECRYPT flag...\n"); { Aes aes[1]; - uint8_t ecbOut[16] = {0}; + WH_DMA_ALIGNED uint8_t ecbOut[WH_DMA_PAD_SIZE(16)] = {0}; keyId = WH_KEYID_ERASED; ret = wh_Client_KeyCache(client, WH_NVM_FLAGS_USAGE_ENCRYPT, @@ -17391,7 +17654,7 @@ int whTest_CryptoKeyUsagePolicies(whClientContext* client, WC_RNG* rng) { Aes aes[1]; uint8_t iv[AES_BLOCK_SIZE] = {0}; - uint8_t cbcCipher[16] = {0}; + WH_DMA_ALIGNED uint8_t cbcCipher[WH_DMA_PAD_SIZE(16)] = {0}; keyId = WH_KEYID_ERASED; ret = wh_Client_KeyCache(client, WH_NVM_FLAGS_NONE, @@ -17431,7 +17694,7 @@ int whTest_CryptoKeyUsagePolicies(whClientContext* client, WC_RNG* rng) { Aes aes[1]; uint8_t iv[AES_BLOCK_SIZE] = {0}; - uint8_t cbcOut[16] = {0}; + WH_DMA_ALIGNED uint8_t cbcOut[WH_DMA_PAD_SIZE(16)] = {0}; keyId = WH_KEYID_ERASED; ret = wh_Client_KeyCache(client, WH_NVM_FLAGS_USAGE_ENCRYPT, @@ -17473,7 +17736,7 @@ int whTest_CryptoKeyUsagePolicies(whClientContext* client, WC_RNG* rng) { Aes aes[1]; uint8_t gcmIv[12] = {0}; - uint8_t gcmCipher[16] = {0}; + WH_DMA_ALIGNED uint8_t gcmCipher[WH_DMA_PAD_SIZE(16)] = {0}; uint8_t gcmTag[16] = {0}; keyId = WH_KEYID_ERASED; @@ -17514,7 +17777,7 @@ int whTest_CryptoKeyUsagePolicies(whClientContext* client, WC_RNG* rng) { Aes aes[1]; uint8_t gcmIv[12] = {0}; - uint8_t gcmOut[16] = {0}; + WH_DMA_ALIGNED uint8_t gcmOut[WH_DMA_PAD_SIZE(16)] = {0}; uint8_t gcmTag[16] = {0}; keyId = WH_KEYID_ERASED; @@ -18326,6 +18589,11 @@ int whTest_CryptoClientConfig(whClientConfig* config) ret = whTest_CryptoRngDmaAsync(client); } #endif /* WOLFHSM_CFG_DMA */ +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT + if (ret == WH_ERROR_OK) { + ret = whTest_CryptoDmaNoncoherentRefusal(client, config); + } +#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ /* The remaining once-run tests below historically used the non-DMA devId; * select the std (non-DMA) dispatch mode for them. Reinitialize the default @@ -18887,14 +19155,22 @@ int whTest_CryptoClientConfig(whClientConfig* config) #if defined(WOLFHSM_CFG_DMA) && \ defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) if (ret == 0) { +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT + ret = whTestCrypto_LmsCryptoCb(client, INVALID_DEVID, rng); +#else ret = whTestCrypto_LmsCryptoCb(client, WH_DEV_ID_DMA, rng); +#endif } #endif #if defined(WOLFHSM_CFG_DMA) && \ defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) if (ret == 0) { +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT + ret = whTestCrypto_XmssCryptoCb(client, INVALID_DEVID, rng); +#else ret = whTestCrypto_XmssCryptoCb(client, WH_DEV_ID_DMA, rng); +#endif } #endif @@ -19075,8 +19351,11 @@ static int wh_ClientServer_MemThreadTest(whTestNvmBackendType nvmType) * missing translation is rejected (see test/wh_test_dma.c); the * use-after-free class is covered by the single-thread harness. */ whClientDmaConfig clientDmaConfig = { - .cb = whTestDma_BounceClientCb, + .cb = whTestDma_BounceClientCb, +#ifndef WOLFHSM_CFG_DMA_NONCOHERENT + /* Refused with non-coherent DMA (no DMA through wolfCrypt) */ .preferDma = 1, +#endif }; #endif whClientConfig c_conf[1] = {{ diff --git a/test/wh_test_dma.c b/test/wh_test_dma.c index 554ebd731..4d9fa21da 100644 --- a/test/wh_test_dma.c +++ b/test/wh_test_dma.c @@ -72,7 +72,9 @@ typedef struct { size_t len; } bounceSlot; -static uint8_t g_bouncePool[BOUNCE_POOL_SIZE]; +/* With non-coherent DMA, slices start on a cache line and are padded to whole + * lines, as a port bouncing through non-coherent memory must do */ +static WH_DMA_ALIGNED uint8_t g_bouncePool[BOUNCE_POOL_SIZE]; static bounceSlot g_bounceSlots[BOUNCE_POOL_SLOTS]; static size_t g_bounceUsed; /* bump offset into the pool */ static int g_bounceOutstanding; /* slots currently allocated */ @@ -107,7 +109,8 @@ void whTestDma_BounceSetAllocBudget(int allocs) static bounceSlot* _bounceAlloc(size_t len) { int i; - size_t aligned = (len + 7u) & ~(size_t)7u; /* 8-byte align slices */ + /* 8-byte align slices, whole cache lines with non-coherent DMA */ + size_t aligned = WH_DMA_PAD_SIZE((len + 7u) & ~(size_t)7u); /* Injected failure for exercising leak-recovery paths; no diagnostic. */ if (g_bounceAllocBudget == 0) { @@ -196,6 +199,17 @@ int whTestDma_BounceClientCb(struct whClientContext_t* client, break; case WH_DMA_OPER_CLIENT_WRITE_PRE: +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT + /* Behave like a zero-copy port on a non-coherent target, which + * can only accept output buffers starting on a cache line. This + * catches test buffers that are not declared WH_DMA_ALIGNED. */ + if (!WH_DMA_IS_ALIGNED(clientAddr)) { + WH_ERROR_PRINT("wh_test bounce: output buffer %p (len %u) is " + "not aligned to WOLFHSM_CFG_DMA_ALIGN\n", + (void*)clientAddr, (unsigned)len); + return WH_ERROR_BADARGS; + } +#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ /* Server is about to write client memory: give it a pool slot to * write into. */ s = _bounceAlloc(len); diff --git a/test/wh_test_multiclient.c b/test/wh_test_multiclient.c index 596cbe58a..61ffae787 100644 --- a/test/wh_test_multiclient.c +++ b/test/wh_test_multiclient.c @@ -528,7 +528,7 @@ static int _testGlobalKeyDma(whClientContext* client1, whServerContext* server1, whKeyId keyId2 = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_2); uint8_t keyData1[32] = "GlobalDmaCacheTestKey123456!"; uint8_t keyData2[32] = "GlobalDmaExportTestKey12345!"; - uint8_t outBuf[32] = {0}; + WH_DMA_ALIGNED uint8_t outBuf[WH_DMA_PAD_SIZE(32)] = {0}; uint8_t label[WH_NVM_LABEL_LEN]; uint16_t labelSz = sizeof(label); uint16_t outSz; @@ -1707,7 +1707,7 @@ static int _testNvmUnboundClientRejected(whClientContext* client1, whNvmId count = 0; whNvmId list_id = 0; whNvmSize out_len = 0; - uint8_t buf[64] = {0}; + WH_DMA_ALIGNED uint8_t buf[WH_DMA_PAD_SIZE(64)] = {0}; (void)client2; (void)server2; @@ -1979,7 +1979,7 @@ static int _testNvmGlobalFlagDisabled(whClientContext* client1, whNvmId count = 0; whNvmId cur = 0; whNvmSize out_len = 0; - uint8_t buf[64] = {0}; + WH_DMA_ALIGNED uint8_t buf[WH_DMA_PAD_SIZE(64)] = {0}; (void)client2; (void)server2; @@ -2122,7 +2122,7 @@ static int _testNvmNonAddVerbRejections(whClientContext* client1, whNvmSize out_len = 0; whNvmId list_id = 0; whNvmId count = 0; - uint8_t buf[64] = {0}; + WH_DMA_ALIGNED uint8_t buf[WH_DMA_PAD_SIZE(64)] = {0}; (void)client2; (void)server2; @@ -2292,7 +2292,7 @@ static int _testKeystoreUnboundClientRejected(whClientContext* client1, const whKeyId globalId = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, WH_KEYUSER_GLOBAL, keyId); uint8_t keyData[32] = "UnboundKeystoreRejectKey12!"; - uint8_t outBuf[32] = {0}; + WH_DMA_ALIGNED uint8_t outBuf[WH_DMA_PAD_SIZE(32)] = {0}; uint8_t label[WH_NVM_LABEL_LEN] = {0}; uint32_t readSz = sizeof(outBuf); uint16_t outSz = 0; diff --git a/test/wh_test_nvmflags.c b/test/wh_test_nvmflags.c index b327c9159..49ce4a5ca 100644 --- a/test/wh_test_nvmflags.c +++ b/test/wh_test_nvmflags.c @@ -48,7 +48,8 @@ static int _testNonExportableNvmAccess(whClientContext* client) int ret = 0; whNvmId nvmId = 2; /* Arbitrary NVM ID */ uint8_t nvmData[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; - uint8_t exportedNvmData[sizeof(nvmData)] = {0}; + WH_DMA_ALIGNED uint8_t exportedNvmData[WH_DMA_PAD_SIZE(sizeof(nvmData))] = { + 0}; uint8_t nvmLabel[WH_NVM_LABEL_LEN] = "NonExportableNvmObj"; int32_t out_rc = 0; whNvmSize out_len = 0; @@ -69,8 +70,8 @@ static int _testNonExportableNvmAccess(whClientContext* client) /* Try to read the non-exportable NVM object - should fail */ out_rc = 0; - ret = wh_Client_NvmRead(client, nvmId, 0, sizeof(exportedNvmData), &out_rc, - &out_len, exportedNvmData); + ret = wh_Client_NvmRead(client, nvmId, 0, sizeof(nvmData), &out_rc, + &out_len, exportedNvmData); if (ret != 0 || out_rc != WH_ERROR_ACCESS) { WH_ERROR_PRINT("Non-exportable NVM object was read unexpectedly: " "ret=%d, out_rc=%d\n", @@ -102,8 +103,8 @@ static int _testNonExportableNvmAccess(whClientContext* client) memset(exportedNvmData, 0, sizeof(exportedNvmData)); out_rc = 0; out_len = 0; - ret = wh_Client_NvmRead(client, nvmId, 0, sizeof(exportedNvmData), &out_rc, - &out_len, exportedNvmData); + ret = wh_Client_NvmRead(client, nvmId, 0, sizeof(nvmData), &out_rc, + &out_len, exportedNvmData); if (ret != 0 || out_rc != 0) { WH_ERROR_PRINT( "Failed to read exportable NVM object: ret=%d, out_rc=%d\n", ret, @@ -144,7 +145,7 @@ static int _testNonExportableNvmAccess(whClientContext* client) /* Try to read the non-exportable NVM object via DMA - should fail */ memset(exportedNvmData, 0, sizeof(exportedNvmData)); out_rc = 0; - ret = wh_Client_NvmReadDma(client, nvmId, 0, sizeof(exportedNvmData), + ret = wh_Client_NvmReadDma(client, nvmId, 0, sizeof(nvmData), exportedNvmData, &out_rc); if (ret != 0 || out_rc != WH_ERROR_ACCESS) { WH_ERROR_PRINT("Non-exportable NVM object was read via DMA " @@ -175,7 +176,7 @@ static int _testNonExportableNvmAccess(whClientContext* client) /* Try to read the exportable NVM object via DMA - should succeed */ memset(exportedNvmData, 0, sizeof(exportedNvmData)); out_rc = 0; - ret = wh_Client_NvmReadDma(client, nvmId, 0, sizeof(exportedNvmData), + ret = wh_Client_NvmReadDma(client, nvmId, 0, sizeof(nvmData), exportedNvmData, &out_rc); if (ret != 0 || out_rc != 0) { WH_ERROR_PRINT( @@ -388,12 +389,13 @@ static int _testNvmNondestroyableModifyNoDestroy(whClientContext* client) static int _testNvmNonmodifiableNoOverwriteDma(whClientContext* client) { int32_t server_rc; - uint8_t data1[] = {0x11, 0x22, 0x33, 0x44}; - uint8_t data2[] = {0xAA, 0xBB, 0xCC, 0xDD}; - uint8_t readData[sizeof(data1)] = {0}; - whNvmSize readLen = sizeof(readData); - whNvmId list[1] = {TEST_NVM_ID_NONMOD_DMA}; - whNvmMetadata meta = {0}; + uint8_t data1[] = {0x11, 0x22, 0x33, 0x44}; + uint8_t data2[] = {0xAA, 0xBB, 0xCC, 0xDD}; + whNvmSize readLen = sizeof(data1); + whNvmId list[1] = {TEST_NVM_ID_NONMOD_DMA}; + whNvmMetadata meta = {0}; + + WH_DMA_ALIGNED uint8_t readData[WH_DMA_PAD_SIZE(sizeof(data1))] = {0}; WH_TEST_PRINT("Testing NVM DMA NONMODIFIABLE: no overwrite...\n"); @@ -408,7 +410,7 @@ static int _testNvmNonmodifiableNoOverwriteDma(whClientContext* client) WH_TEST_ASSERT_RETURN(server_rc == WH_ERROR_OK); WH_TEST_RETURN_ON_FAIL(wh_Client_NvmReadDma(client, TEST_NVM_ID_NONMOD_DMA, - 0, sizeof(readData), readData, + 0, sizeof(data1), readData, &server_rc)); WH_TEST_ASSERT_RETURN(server_rc == WH_ERROR_OK); WH_TEST_ASSERT_RETURN(memcmp(readData, data1, sizeof(data1)) == 0); @@ -419,7 +421,7 @@ static int _testNvmNonmodifiableNoOverwriteDma(whClientContext* client) WH_TEST_ASSERT_RETURN(server_rc == WH_ERROR_ACCESS); memset(readData, 0, sizeof(readData)); - readLen = sizeof(readData); + readLen = sizeof(data1); WH_TEST_RETURN_ON_FAIL(wh_Client_NvmReadDma( client, TEST_NVM_ID_NONMOD_DMA, 0, readLen, readData, &server_rc)); WH_TEST_ASSERT_RETURN(server_rc == WH_ERROR_OK); @@ -435,7 +437,7 @@ static int _testNvmNonmodifiableNoOverwriteDma(whClientContext* client) WH_TEST_ASSERT_RETURN(server_rc == WH_ERROR_ACCESS); WH_TEST_RETURN_ON_FAIL(wh_Client_NvmReadDma(client, TEST_NVM_ID_NONMOD_DMA, - 0, sizeof(readData), readData, + 0, sizeof(data1), readData, &server_rc)); WH_TEST_ASSERT_RETURN(server_rc == WH_ERROR_OK); @@ -446,12 +448,13 @@ static int _testNvmNonmodifiableNoOverwriteDma(whClientContext* client) static int _testNvmNondestroyableModifyNoDestroyDma(whClientContext* client) { int32_t server_rc; - uint8_t data1[] = {0x55, 0x66, 0x77, 0x88}; - uint8_t data2[] = {0x99, 0xAA, 0xBB, 0xCC}; - uint8_t readData[sizeof(data2)] = {0}; - whNvmSize readLen = sizeof(readData); - whNvmId list[1] = {TEST_NVM_ID_NONDESTROYABLE_DMA}; - whNvmMetadata meta = {0}; + uint8_t data1[] = {0x55, 0x66, 0x77, 0x88}; + uint8_t data2[] = {0x99, 0xAA, 0xBB, 0xCC}; + whNvmSize readLen = sizeof(data2); + whNvmId list[1] = {TEST_NVM_ID_NONDESTROYABLE_DMA}; + whNvmMetadata meta = {0}; + + WH_DMA_ALIGNED uint8_t readData[WH_DMA_PAD_SIZE(sizeof(data2))] = {0}; WH_TEST_PRINT( "Testing NVM DMA NONDESTROYABLE: modify allowed, destroy denied...\n"); @@ -474,7 +477,7 @@ static int _testNvmNondestroyableModifyNoDestroyDma(whClientContext* client) WH_TEST_RETURN_ON_FAIL( wh_Client_NvmReadDma(client, TEST_NVM_ID_NONDESTROYABLE_DMA, 0, - sizeof(readData), readData, &server_rc)); + sizeof(data2), readData, &server_rc)); WH_TEST_ASSERT_RETURN(server_rc == WH_ERROR_OK); WH_TEST_ASSERT_RETURN(memcmp(readData, data2, sizeof(data2)) == 0); @@ -483,7 +486,7 @@ static int _testNvmNondestroyableModifyNoDestroyDma(whClientContext* client) WH_TEST_ASSERT_RETURN(server_rc == WH_ERROR_ACCESS); memset(readData, 0, sizeof(readData)); - readLen = sizeof(readData); + readLen = sizeof(data2); WH_TEST_RETURN_ON_FAIL( wh_Client_NvmReadDma(client, TEST_NVM_ID_NONDESTROYABLE_DMA, 0, readLen, readData, &server_rc)); @@ -704,7 +707,7 @@ static int _testKeyNondestroyableNoEraseDma(whClientContext* client) 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE}; uint8_t key2[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00}; - uint8_t exported[sizeof(key2)] = {0}; + WH_DMA_ALIGNED uint8_t exported[WH_DMA_PAD_SIZE(sizeof(key2))] = {0}; uint16_t exportedLen = sizeof(exported); uint8_t label[WH_NVM_LABEL_LEN] = "nondestroyable_dma"; diff --git a/test/wh_test_posix_threadsafe_stress.c b/test/wh_test_posix_threadsafe_stress.c index 938b21ee5..cd83f876e 100644 --- a/test/wh_test_posix_threadsafe_stress.c +++ b/test/wh_test_posix_threadsafe_stress.c @@ -541,8 +541,8 @@ typedef struct { #ifdef WOLFHSM_CFG_DMA /* Per-client DMA buffers */ - uint8_t dmaKeyBuffer[KEY_DATA_SIZE]; - uint8_t dmaNvmBuffer[NVM_OBJECT_DATA_SIZE]; + WH_DMA_ALIGNED uint8_t dmaKeyBuffer[WH_DMA_PAD_SIZE(KEY_DATA_SIZE)]; + WH_DMA_ALIGNED uint8_t dmaNvmBuffer[WH_DMA_PAD_SIZE(NVM_OBJECT_DATA_SIZE)]; #endif } ClientServerPair; @@ -1313,14 +1313,12 @@ static int doKeyCacheDma(ClientServerPair* pair, whKeyId keyId, int iteration) int rc; /* Fill key data with pattern */ - memset(pair->dmaKeyBuffer, (uint8_t)(iteration & 0xFF), - sizeof(pair->dmaKeyBuffer)); + memset(pair->dmaKeyBuffer, (uint8_t)(iteration & 0xFF), KEY_DATA_SIZE); snprintf((char*)label, sizeof(label), "DmaKey%04X", keyId); /* Send DMA request */ rc = wh_Client_KeyCacheDmaRequest(&pair->client, 0, label, sizeof(label), - pair->dmaKeyBuffer, - sizeof(pair->dmaKeyBuffer), keyId); + pair->dmaKeyBuffer, KEY_DATA_SIZE, keyId); if (rc != WH_ERROR_OK) { return rc; } @@ -1344,7 +1342,7 @@ static int doKeyExportDma(ClientServerPair* pair, whKeyId keyId) /* Send DMA request - provide buffer for DMA export */ rc = wh_Client_KeyExportDmaRequest(&pair->client, keyId, pair->dmaKeyBuffer, - sizeof(pair->dmaKeyBuffer)); + KEY_DATA_SIZE); if (rc != WH_ERROR_OK) { return rc; } @@ -1369,18 +1367,18 @@ static int doNvmAddObjectDma(ClientServerPair* pair, whNvmId id, int rc; /* Fill DMA buffer with writer pattern */ - memset(pair->dmaNvmBuffer, pattern, sizeof(pair->dmaNvmBuffer)); + memset(pair->dmaNvmBuffer, pattern, NVM_OBJECT_DATA_SIZE); /* Set up metadata */ memset(&meta, 0, sizeof(meta)); meta.id = id; meta.access = WH_NVM_ACCESS_ANY; meta.flags = WH_NVM_FLAGS_USAGE_ANY; - meta.len = sizeof(pair->dmaNvmBuffer); + meta.len = NVM_OBJECT_DATA_SIZE; /* Send DMA request */ rc = wh_Client_NvmAddObjectDmaRequest( - &pair->client, &meta, sizeof(pair->dmaNvmBuffer), pair->dmaNvmBuffer); + &pair->client, &meta, NVM_OBJECT_DATA_SIZE, pair->dmaNvmBuffer); if (rc != WH_ERROR_OK) { return rc; } @@ -1407,8 +1405,8 @@ static int doNvmReadDma(ClientServerPair* pair, whNvmId id, int expect) int rc; /* Send DMA request */ - rc = wh_Client_NvmReadDmaRequest( - &pair->client, id, 0, sizeof(pair->dmaNvmBuffer), pair->dmaNvmBuffer); + rc = wh_Client_NvmReadDmaRequest(&pair->client, id, 0, NVM_OBJECT_DATA_SIZE, + pair->dmaNvmBuffer); if (rc != WH_ERROR_OK) { return rc; } @@ -1428,7 +1426,7 @@ static int doNvmReadDma(ClientServerPair* pair, whNvmId id, int expect) return out_rc; } - return checkNvmData(pair->dmaNvmBuffer, sizeof(pair->dmaNvmBuffer), expect); + return checkNvmData(pair->dmaNvmBuffer, NVM_OBJECT_DATA_SIZE, expect); } #endif /* WOLFHSM_CFG_DMA */ diff --git a/wolfhsm/wh_client.h b/wolfhsm/wh_client.h index 209aa9485..824f82dce 100644 --- a/wolfhsm/wh_client.h +++ b/wolfhsm/wh_client.h @@ -29,7 +29,8 @@ * the wolfCrypt init functions. Set the devId in whClientConfig.devId (0 picks * the default WH_DEV_ID) and read it back with WH_CLIENT_DEVID(c). With a * single client you can just pass the global WH_DEV_ID (or WH_DEV_ID_DMA for - * DMA only). With more than one client, give each its own devId. See + * DMA only; with WOLFHSM_CFG_DMA_NONCOHERENT every WH_DEV_ID_DMA operation + * fails). With more than one client, give each its own devId. See * WH_CLIENT_DEVID and WH_DEV_ID below. * * In addition to the offload of cryptographic functions, the WolfHSM Client @@ -132,7 +133,8 @@ typedef int (*whClientDmaClientMemCb)(struct whClientContext_t* client, typedef struct { whClientDmaClientMemCb cb; const whDmaAddrAllowList* dmaAddrAllowList; /* allowed addresses */ - /* nonzero to prefer the DMA path */ + /* nonzero to prefer the DMA path; must be 0 with + * WOLFHSM_CFG_DMA_NONCOHERENT */ uint32_t preferDma; } whClientDmaConfig; @@ -520,12 +522,14 @@ int wh_Client_GetCryptoAffinity(whClientContext* c, uint32_t* out_affinity); * not contact the server. * * Always available: without WOLFHSM_CFG_DMA it does nothing and returns - * success, so you need not guard the call with #ifdef. + * success, so you need not guard the call with #ifdef. With + * WOLFHSM_CFG_DMA_NONCOHERENT, turning DMA on is refused. * * @param[in] c Pointer to the client context. * @param[in] useDma Nonzero to use DMA where supported, zero for the normal * path. - * @return int 0 on success, or WH_ERROR_BADARGS on invalid input. + * @return int 0 on success, or WH_ERROR_BADARGS on invalid input or when + * turning DMA on with WOLFHSM_CFG_DMA_NONCOHERENT. */ int wh_Client_SetDmaMode(whClientContext* c, int useDma); diff --git a/wolfhsm/wh_client_cryptocb.h b/wolfhsm/wh_client_cryptocb.h index db4f34bf0..7c225c03e 100644 --- a/wolfhsm/wh_client_cryptocb.h +++ b/wolfhsm/wh_client_cryptocb.h @@ -47,7 +47,8 @@ int wh_Client_CryptoCbStd(int devId, wc_CryptoInfo* info, void* ctx); #ifdef WOLFHSM_CFG_DMA /* DMA-only cryptoCb, registered for WH_DEV_ID_DMA. No standard-path fallback: - * algorithms without a DMA variant return CRYPTOCB_UNAVAILABLE. + * algorithms without a DMA variant return CRYPTOCB_UNAVAILABLE. With + * WOLFHSM_CFG_DMA_NONCOHERENT every operation fails with WC_HW_E. */ int wh_Client_CryptoCbDma(int devId, wc_CryptoInfo* info, void* inCtx); #endif /* WOLFHSM_CFG_DMA */ diff --git a/wolfhsm/wh_settings.h b/wolfhsm/wh_settings.h index 5381eb014..2509dccda 100644 --- a/wolfhsm/wh_settings.h +++ b/wolfhsm/wh_settings.h @@ -166,6 +166,28 @@ * AEAD request carries inside the message instead of over DMA. * Default: 128 * + * WOLFHSM_CFG_DMA_NONCOHERENT - Define when client memory the server writes + * over DMA is cached and not kept coherent by the hardware. Output buffers + * of the wh_Client_*Dma APIs must then start on a WOLFHSM_CFG_DMA_ALIGN + * boundary and be padded to a multiple of it (WH_DMA_ALIGNED, + * WH_DMA_PAD_SIZE()). wolfCrypt cannot guarantee that for the buffers it + * passes, so every operation on WH_DEV_ID_DMA fails with WC_HW_E and + * preferDma cannot be enabled. Requires WOLFHSM_CFG_DMA. + * Default: Not defined + * + * WOLFHSM_CFG_DMA_ALIGN - Alignment and padding, in bytes, of client buffers + * the server writes over DMA. A power of two and a multiple of XCACHELINE. + * Only used with WOLFHSM_CFG_DMA_NONCOHERENT. + * Default: XCACHELINE + * + * WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK - Test builds only. Abort when a client + * buffer the server writes over DMA does not start on a + * WOLFHSM_CFG_DMA_ALIGN boundary or, in ASAN builds, is not padded to a + * multiple of it. Checked in wh_Client_DmaProcessClientAddress, so it covers + * wolfHSM's own buffers and those passed to the wh_Client_*Dma APIs. + * Requires WOLFHSM_CFG_DMA_NONCOHERENT. + * Default: Not defined + * * WOLFHSM_CFG_CERT_MAX_VERIFY_ROOTS - Maximum number of trusted root NVM IDs * accepted in a single wh_Server_CertVerifyMultiRoot request. Bounded so the * non-DMA wire request fits within WOLFHSM_CFG_COMM_DATA_LEN alongside the @@ -737,6 +759,15 @@ /* DMA Configuration */ +#if defined(WOLFHSM_CFG_DMA_NONCOHERENT) && !defined(WOLFHSM_CFG_DMA) +#error "WOLFHSM_CFG_DMA_NONCOHERENT requires WOLFHSM_CFG_DMA" +#endif + +#if defined(WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK) && \ + !defined(WOLFHSM_CFG_DMA_NONCOHERENT) +#error "WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK requires WOLFHSM_CFG_DMA_NONCOHERENT" +#endif + #ifdef WOLFHSM_CFG_DMA /* Attempt to discover pointer size from build system/architecture */ @@ -798,4 +829,55 @@ #endif /* WOLFHSM_CFG_DMA */ +/* Alignment and padding of client buffers the server writes into over DMA. + * Only needed with non-coherent DMA, no-ops otherwise. */ +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT + +#ifndef WOLFHSM_CFG_DMA_ALIGN +#define WOLFHSM_CFG_DMA_ALIGN XCACHELINE +#endif + +#if (WOLFHSM_CFG_DMA_ALIGN <= 0) || \ + ((WOLFHSM_CFG_DMA_ALIGN & (WOLFHSM_CFG_DMA_ALIGN - 1)) != 0) +#error "WOLFHSM_CFG_DMA_ALIGN must be a power of two" +#endif + +#if (WOLFHSM_CFG_DMA_ALIGN % XCACHELINE) != 0 +#error "WOLFHSM_CFG_DMA_ALIGN must be a multiple of XCACHELINE" +#endif + +/* Round a buffer size up to a multiple of WOLFHSM_CFG_DMA_ALIGN */ +#define WH_DMA_PAD_SIZE(_n) \ + ((((size_t)(_n)) + ((size_t)WOLFHSM_CFG_DMA_ALIGN - 1)) & \ + ~((size_t)WOLFHSM_CFG_DMA_ALIGN - 1)) + +/* Nonzero if the address is aligned to WOLFHSM_CFG_DMA_ALIGN */ +#define WH_DMA_IS_ALIGNED(_p) \ + ((((uintptr_t)(_p)) & ((uintptr_t)WOLFHSM_CFG_DMA_ALIGN - 1)) == 0) + +/* Compiler-specific attribute aligning a buffer to WOLFHSM_CFG_DMA_ALIGN. + * wolfHSM's own DMA buffers rely on it, so an unknown compiler must provide + * its own definition rather than silently get unaligned buffers. */ +#ifndef WH_DMA_ALIGNED +#if defined(__GNUC__) || defined(__clang__) || defined(__IAR_SYSTEMS_ICC__) +#define WH_DMA_ALIGNED __attribute__((aligned(WOLFHSM_CFG_DMA_ALIGN))) +#elif defined(_MSC_VER) +#define WH_DMA_ALIGNED __declspec(align(WOLFHSM_CFG_DMA_ALIGN)) +#elif defined(__CC_ARM) +#define WH_DMA_ALIGNED __align(WOLFHSM_CFG_DMA_ALIGN) +#else +#error "Define WH_DMA_ALIGNED for this compiler (see WOLFHSM_CFG_DMA_ALIGN)" +#endif +#endif + +#else + +#define WH_DMA_PAD_SIZE(_n) (_n) +#define WH_DMA_IS_ALIGNED(_p) ((void)(_p), 1) +#ifndef WH_DMA_ALIGNED +#define WH_DMA_ALIGNED +#endif + +#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ + #endif /* !WOLFHSM_WH_SETTINGS_H_ */ diff --git a/wolfhsm/wh_utils.h b/wolfhsm/wh_utils.h index 9b7d3e8eb..f8b78d270 100644 --- a/wolfhsm/wh_utils.h +++ b/wolfhsm/wh_utils.h @@ -86,10 +86,11 @@ void wh_Utils_ForceZero(void* mem, uint32_t size); int wh_Utils_ConstantCompare(const uint8_t* a, const uint8_t* b, size_t length); /** Cache helper functions */ -/* Flush the cache lines starting at p for at least n bytes */ +/* Flush every cache line holding a byte of [p, p + n). No-op when n is 0 */ void* wh_Utils_CacheFlush(void* p, size_t n); -/* Invalidate the cache lines starting at p for at least n bytes */ +/* Invalidate every cache line holding a byte of [p, p + n). No-op when n is + * 0 */ const void* wh_Utils_CacheInvalidate(const void* p, size_t n); /* Perform memset followed by a cache flush */ @@ -101,6 +102,18 @@ void* wh_Utils_memcpy_invalidate(void* dst, const void* src, size_t n); /* Perform memcpy followed by a cache flush of dst */ void* wh_Utils_memcpy_flush(void* dst, const void* src , size_t n); +#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_NO_CRYPTO) +/** DMA buffer helpers */ +/* XMALLOC/XFREE replacements for heap buffers the server writes over DMA. + * With WOLFHSM_CFG_DMA_NONCOHERENT the buffer starts on a + * WOLFHSM_CFG_DMA_ALIGN boundary and is padded to a multiple of it; otherwise + * these are plain XMALLOC/XFREE. Returns NULL when the allocation fails. */ +void* wh_Utils_DmaAlloc(size_t len, void* heap); + +/* Free a buffer from wh_Utils_DmaAlloc. NULL is ignored */ +void wh_Utils_DmaFree(void* ptr, void* heap); +#endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_NO_CRYPTO */ + #if defined(WOLFHSM_CFG_HEXDUMP) void wh_Utils_Hexdump(const char* initial, const uint8_t* ptr, size_t size); From 43a2866d816cb0ab4cc9fc5233d43495ced957aa Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Fri, 23 Oct 2026 09:47:15 +0200 Subject: [PATCH 2/4] test: uniform added test/ coverage to test-refactor/ --- test-refactor/README.md | 4 +- .../client-server/wh_test_crypto_lms.c | 106 ++++++++++++++--- .../client-server/wh_test_crypto_xmss.c | 109 +++++++++++++++--- test-refactor/misc/wh_test_dma_noncoherent.c | 41 ++++++- 4 files changed, 227 insertions(+), 33 deletions(-) diff --git a/test-refactor/README.md b/test-refactor/README.md index bd28fa6ea..0f285d358 100644 --- a/test-refactor/README.md +++ b/test-refactor/README.md @@ -85,8 +85,8 @@ Translated tests: | `wh_test_cert.c::whTest_CertRamSim` | `server/wh_test_cert.c::whTest_CertVerify` | Server | remove ramsim coupling and migrate to server group. Legacy ran FLASH and FLASH_LOG backends; the port runs the plain flash backend only -- FLASH_LOG re-run pending (see Known coverage gaps) | | `wh_test_crypto.c::whTest_Crypto` | `client-server/wh_test_crypto_{aes,cmac,curve25519,ecc,ed25519,kdf,keypolicy,mldsa,rng,rsa,sha}.c::whTest_Crypto_*` | Client | Split into per-algorithm suites; key revocation is gated by `WOLFHSM_CFG_TEST_ALLOW_PERSISTENT_NVM_ARTIFACTS`. Legacy ran FLASH and FLASH_LOG backends; the port runs the plain flash backend only -- FLASH_LOG re-run pending (see Known coverage gaps) | | `wh_test_crypto.c::whTest_CryptoKeyUsagePolicies` (AES CTR/ECB/GCM subset) | `client-server/wh_test_crypto_aes.c::whTest_CryptoAesKeyUsagePolicies` | Client | AES-CTR/ECB/GCM key usage enforcement (non-DMA and DMA variants) | -| `wh_test_crypto.c::whTestCrypto_LmsCryptoCb` | `client-server/wh_test_crypto_lms.c::whTest_Crypto_Lms` | Client | DMA-only LMS generate/durability/sign/verify, public-key export+import, private export/import rejection, and the server-only `WH_NVM_FLAGS_TRUSTED` keygen strip regression. Gated by `WOLFHSM_CFG_DMA && !WOLFHSM_CFG_DMA_NONCOHERENT && WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY` (it runs through wolfCrypt on `WH_DEV_ID_DMA`, which non-coherent DMA builds refuse); reports SKIPPED otherwise | -| `wh_test_crypto.c::whTestCrypto_XmssCryptoCb` | `client-server/wh_test_crypto_xmss.c::whTest_Crypto_Xmss` | Client | DMA-only XMSS generate/durability/sign/verify, public-key export+import, private export/import rejection, and the server-only `WH_NVM_FLAGS_TRUSTED` keygen strip regression. Gated by `WOLFHSM_CFG_DMA && !WOLFHSM_CFG_DMA_NONCOHERENT && WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY` (it runs through wolfCrypt on `WH_DEV_ID_DMA`, which non-coherent DMA builds refuse); reports SKIPPED otherwise | +| `wh_test_crypto.c::whTestCrypto_LmsCryptoCb` | `client-server/wh_test_crypto_lms.c::whTest_Crypto_Lms` | Client | DMA-only LMS generate/durability/sign/verify, public-key export+import, private export/import rejection, and the server-only `WH_NVM_FLAGS_TRUSTED` keygen strip regression. Gated by `WOLFHSM_CFG_DMA && WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY`; reports SKIPPED otherwise. With `WOLFHSM_CFG_DMA_NONCOHERENT` (wolfCrypt refuses `WH_DEV_ID_DMA`) the keygen/sign/verify/sigs-left steps call the `wh_Client_Lms*Dma` APIs directly instead of the cryptoCb | +| `wh_test_crypto.c::whTestCrypto_XmssCryptoCb` | `client-server/wh_test_crypto_xmss.c::whTest_Crypto_Xmss` | Client | DMA-only XMSS generate/durability/sign/verify, public-key export+import, private export/import rejection, and the server-only `WH_NVM_FLAGS_TRUSTED` keygen strip regression. Gated by `WOLFHSM_CFG_DMA && WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY`; reports SKIPPED otherwise. With `WOLFHSM_CFG_DMA_NONCOHERENT` (wolfCrypt refuses `WH_DEV_ID_DMA`) the keygen/sign/verify/sigs-left steps call the `wh_Client_Xmss*Dma` APIs directly instead of the cryptoCb | | `wh_test_crypto.c::{whTest_KeyCache, whTest_NonExportableKeystore}` | `client-server/wh_test_crypto_keystore.c::whTest_Crypto_Keystore` | Client | Key-cache lifecycle (cache/export, evict, commit/erase, cross-cache eviction/replacement, NVM-backed eviction) and non-exportable-flag enforcement; std and DMA export paths. The `WOLFHSM_CFG_IS_TEST_SERVER` multi-client user-exclusion path is dropped (needs two client contexts) | | `wh_test_clientserver.c` (echo and server-info paths) | `client-server/wh_test_echo.c::whTest_Echo`, `client-server/wh_test_server_info.c::whTest_ServerInfo` | Client | pthread test ported, sequential test dropped | | `wh_test_clientserver.c` (NVM CRUD + OOB read clamping paths) | `client-server/wh_test_nvm_ops.c::{whTest_NvmCrud, whTest_NvmReadOob}` | Client | each test cleans up its own slots; OOB test covers UINT16_MAX overflow regression | diff --git a/test-refactor/client-server/wh_test_crypto_lms.c b/test-refactor/client-server/wh_test_crypto_lms.c index aa9042232..c37f0df24 100644 --- a/test-refactor/client-server/wh_test_crypto_lms.c +++ b/test-refactor/client-server/wh_test_crypto_lms.c @@ -23,6 +23,9 @@ * _whTest_CryptoLmsCryptoCb - generate / durability / sign / verify, public * key export and import, and enforcement of the * no-private-export / no-private-import policy + * + * With WOLFHSM_CFG_DMA_NONCOHERENT wolfCrypt cannot use DMA, so the key + * operations drive the wh_Client_Lms*Dma APIs directly instead of the cryptoCb. */ #include "wolfhsm/wh_settings.h" @@ -48,10 +51,8 @@ #include "wh_test_common.h" #include "wh_test_list.h" -/* Runs through wolfCrypt on WH_DEV_ID_DMA, which non-coherent DMA builds - * refuse, so the test is skipped there. */ -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_DMA_NONCOHERENT) && \ - defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) +#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_LMS) && \ + !defined(WOLFSSL_LMS_VERIFY_ONLY) /* L=1, H=5, W=8 keeps the signature ~1.3 KB and gives 2^5 = 32 signatures. */ #define WH_TEST_LMS_LEVELS (1) @@ -59,7 +60,76 @@ #define WH_TEST_LMS_WINTERNITZ (8) /* Generous buffer that fits L1_H5_W8 (~1328) and any W<8 variant of the same * height (W=1 ~8688). Keeps off the stack so ASAN builds stay happy. */ -static byte whTest_LmsSigBuf[8800]; +static WH_DMA_ALIGNED byte whTest_LmsSigBuf[WH_DMA_PAD_SIZE(8800)]; + +/* Key operations under test. wolfCrypt cannot use DMA with non-coherent + * caches, so there the wh_Client_Lms*Dma APIs are driven directly instead of + * going through the cryptoCb (devId is then INVALID_DEVID). */ +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +static int _whTest_LmsMakeKey(whClientContext* ctx, LmsKey* key, WC_RNG* rng) +{ + int ret; + (void)rng; + ret = wh_Client_LmsMakeExportKeyDma(ctx, key); + if (ret == 0) { + /* wh_Client_LmsMakeExportKeyDma only fills in the public key and + * keyId, it does not mark the key usable. Set what wc_LmsKey_MakeKey + * sets after a cryptoCb keygen. */ + key->state = WC_LMS_STATE_OK; + key->pubSet = 1; + } + return ret; +} + +static int _whTest_LmsSigsLeft(whClientContext* ctx, LmsKey* key) +{ + return (wh_Client_LmsSigsLeftDma(ctx, key) > 0) ? 1 : 0; +} + +static int _whTest_LmsSign(whClientContext* ctx, LmsKey* key, byte* sig, + word32* sigLen, const byte* msg, int msgSz) +{ + return wh_Client_LmsSignDma(ctx, msg, (word32)msgSz, sig, sigLen, key); +} + +static int _whTest_LmsVerify(whClientContext* ctx, LmsKey* key, const byte* sig, + word32 sigLen, const byte* msg, int msgSz) +{ + int res = 0; + int ret = + wh_Client_LmsVerifyDma(ctx, sig, sigLen, msg, (word32)msgSz, &res, key); + if ((ret == 0) && (res != 1)) { + ret = SIG_VERIFY_E; + } + return ret; +} +#else +static int _whTest_LmsMakeKey(whClientContext* ctx, LmsKey* key, WC_RNG* rng) +{ + (void)ctx; + return wc_LmsKey_MakeKey(key, rng); +} + +static int _whTest_LmsSigsLeft(whClientContext* ctx, LmsKey* key) +{ + (void)ctx; + return wc_LmsKey_SigsLeft(key); +} + +static int _whTest_LmsSign(whClientContext* ctx, LmsKey* key, byte* sig, + word32* sigLen, const byte* msg, int msgSz) +{ + (void)ctx; + return wc_LmsKey_Sign(key, sig, sigLen, msg, msgSz); +} + +static int _whTest_LmsVerify(whClientContext* ctx, LmsKey* key, const byte* sig, + word32 sigLen, const byte* msg, int msgSz) +{ + (void)ctx; + return wc_LmsKey_Verify(key, sig, sigLen, msg, msgSz); +} +#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ static int _whTest_CryptoLmsCryptoCb(whClientContext* ctx, int devId, WC_RNG* rng) @@ -108,7 +178,7 @@ static int _whTest_CryptoLmsCryptoCb(whClientContext* ctx, int devId, /* MakeKey via cryptocb: the server commits the key to NVM before * returning the public key over DMA. */ if (ret == 0) { - ret = wc_LmsKey_MakeKey(key, rng); + ret = _whTest_LmsMakeKey(ctx, key, rng); if (ret != 0) { WH_ERROR_PRINT("Failed LMS MakeKey ret=%d\n", ret); } @@ -117,7 +187,7 @@ static int _whTest_CryptoLmsCryptoCb(whClientContext* ctx, int devId, /* wc_LmsKey_SigsLeft returns a boolean: nonzero = signatures available, * 0 = exhausted. Fresh key should report nonzero. */ if (ret == 0) { - if (wc_LmsKey_SigsLeft(key) == 0) { + if (_whTest_LmsSigsLeft(ctx, key) == 0) { WH_ERROR_PRINT("LMS reported exhausted on fresh key\n"); ret = -1; } @@ -240,7 +310,8 @@ static int _whTest_CryptoLmsCryptoCb(whClientContext* ctx, int devId, /* Sign via cryptocb. */ if (ret == 0) { sigLen = sigCap; - ret = wc_LmsKey_Sign(key, whTest_LmsSigBuf, &sigLen, msg, (int)msgSz); + ret = _whTest_LmsSign(ctx, key, whTest_LmsSigBuf, &sigLen, msg, + (int)msgSz); if (ret != 0) { WH_ERROR_PRINT("Failed LMS Sign ret=%d\n", ret); } @@ -253,7 +324,8 @@ static int _whTest_CryptoLmsCryptoCb(whClientContext* ctx, int devId, /* Verify the signature via cryptocb. */ if (ret == 0) { - ret = wc_LmsKey_Verify(key, whTest_LmsSigBuf, sigLen, msg, (int)msgSz); + ret = _whTest_LmsVerify(ctx, key, whTest_LmsSigBuf, sigLen, msg, + (int)msgSz); if (ret != 0) { WH_ERROR_PRINT("Failed LMS Verify ret=%d\n", ret); } @@ -262,7 +334,8 @@ static int _whTest_CryptoLmsCryptoCb(whClientContext* ctx, int devId, /* Tampered signature must fail to verify. */ if (ret == 0) { whTest_LmsSigBuf[0] ^= 0xFF; - ret = wc_LmsKey_Verify(key, whTest_LmsSigBuf, sigLen, msg, (int)msgSz); + ret = _whTest_LmsVerify(ctx, key, whTest_LmsSigBuf, sigLen, msg, + (int)msgSz); whTest_LmsSigBuf[0] ^= 0xFF; if (ret == 0) { WH_ERROR_PRINT("LMS Verify unexpectedly accepted tampered sig\n"); @@ -276,8 +349,8 @@ static int _whTest_CryptoLmsCryptoCb(whClientContext* ctx, int devId, /* Wrong message must also fail to verify. */ if (ret == 0) { const byte wrongMsg[] = "wolfHSM LMS cryptocb wrong"; - ret = wc_LmsKey_Verify(key, whTest_LmsSigBuf, sigLen, wrongMsg, - (int)(sizeof(wrongMsg) - 1)); + ret = _whTest_LmsVerify(ctx, key, whTest_LmsSigBuf, sigLen, wrongMsg, + (int)(sizeof(wrongMsg) - 1)); if (ret == 0) { WH_ERROR_PRINT("LMS Verify unexpectedly accepted wrong message\n"); ret = -1; @@ -290,7 +363,7 @@ static int _whTest_CryptoLmsCryptoCb(whClientContext* ctx, int devId, /* H=5 means 32 sigs total; after one sign, the key is still not * exhausted. */ if (ret == 0) { - if (wc_LmsKey_SigsLeft(key) == 0) { + if (_whTest_LmsSigsLeft(ctx, key) == 0) { WH_ERROR_PRINT("LMS reported exhausted after one sign\n"); ret = -1; } @@ -483,10 +556,15 @@ int whTest_Crypto_Lms(whClientContext* ctx) } rngInited = 1; +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT + /* No DMA through wolfCrypt: the test drives the DMA APIs directly */ + ret = _whTest_CryptoLmsCryptoCb(ctx, INVALID_DEVID, rng); +#else /* LMS dispatches through the DMA-only cryptocb. */ (void)wh_Client_SetDmaMode(ctx, 1); ret = _whTest_CryptoLmsCryptoCb(ctx, WH_DEV_ID_DMA, rng); (void)wh_Client_SetDmaMode(ctx, 0); +#endif if (rngInited) { (void)wc_FreeRng(rng); @@ -495,6 +573,6 @@ int whTest_Crypto_Lms(whClientContext* ctx) return ret; } -#endif /* DMA && !DMA_NONCOHERENT && LMS && !LMS_VERIFY_ONLY */ +#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ #endif /* !WOLFHSM_CFG_NO_CRYPTO */ diff --git a/test-refactor/client-server/wh_test_crypto_xmss.c b/test-refactor/client-server/wh_test_crypto_xmss.c index 9990da14f..244556ada 100644 --- a/test-refactor/client-server/wh_test_crypto_xmss.c +++ b/test-refactor/client-server/wh_test_crypto_xmss.c @@ -23,6 +23,10 @@ * _whTest_CryptoXmssCryptoCb - generate / durability / sign / verify, public * key export and import, and enforcement of the * no-private-export / no-private-import policy + * + * With WOLFHSM_CFG_DMA_NONCOHERENT wolfCrypt cannot use DMA, so the key + * operations drive the wh_Client_Xmss*Dma APIs directly instead of the + * cryptoCb. */ #include "wolfhsm/wh_settings.h" @@ -48,15 +52,84 @@ #include "wh_test_common.h" #include "wh_test_list.h" -/* Runs through wolfCrypt on WH_DEV_ID_DMA, which non-coherent DMA builds - * refuse, so the test is skipped there. */ -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_DMA_NONCOHERENT) && \ - defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) +#if defined(WOLFHSM_CFG_DMA) && defined(WOLFSSL_HAVE_XMSS) && \ + !defined(WOLFSSL_XMSS_VERIFY_ONLY) /* "XMSS-SHA2_10_256" is the smallest standardized XMSS parameter set * (height 10, 1024 signatures). pubLen=68, sigLen=2500. */ #define WH_TEST_XMSS_PARAM_STR "XMSS-SHA2_10_256" -static byte whTest_XmssSigBuf[2500]; +static WH_DMA_ALIGNED byte whTest_XmssSigBuf[WH_DMA_PAD_SIZE(2500)]; + +/* Key operations under test. wolfCrypt cannot use DMA with non-coherent + * caches, so there the wh_Client_Xmss*Dma APIs are driven directly instead of + * going through the cryptoCb (devId is then INVALID_DEVID). */ +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +static int _whTest_XmssMakeKey(whClientContext* ctx, XmssKey* key, WC_RNG* rng) +{ + int ret; + (void)rng; + ret = wh_Client_XmssMakeExportKeyDma(ctx, key); + if (ret == 0) { + /* wh_Client_XmssMakeExportKeyDma only fills in the public key and + * keyId, it does not mark the key usable. Set what wc_XmssKey_MakeKey + * sets after a cryptoCb keygen. */ + key->state = WC_XMSS_STATE_OK; + key->pubSet = 1; + } + return ret; +} + +static int _whTest_XmssSigsLeft(whClientContext* ctx, XmssKey* key) +{ + return (wh_Client_XmssSigsLeftDma(ctx, key) > 0) ? 1 : 0; +} + +static int _whTest_XmssSign(whClientContext* ctx, XmssKey* key, byte* sig, + word32* sigLen, const byte* msg, int msgSz) +{ + return wh_Client_XmssSignDma(ctx, msg, (word32)msgSz, sig, sigLen, key); +} + +static int _whTest_XmssVerify(whClientContext* ctx, XmssKey* key, + const byte* sig, word32 sigLen, const byte* msg, + int msgSz) +{ + int res = 0; + int ret = wh_Client_XmssVerifyDma(ctx, sig, sigLen, msg, (word32)msgSz, + &res, key); + if ((ret == 0) && (res != 1)) { + ret = SIG_VERIFY_E; + } + return ret; +} +#else +static int _whTest_XmssMakeKey(whClientContext* ctx, XmssKey* key, WC_RNG* rng) +{ + (void)ctx; + return wc_XmssKey_MakeKey(key, rng); +} + +static int _whTest_XmssSigsLeft(whClientContext* ctx, XmssKey* key) +{ + (void)ctx; + return wc_XmssKey_SigsLeft(key); +} + +static int _whTest_XmssSign(whClientContext* ctx, XmssKey* key, byte* sig, + word32* sigLen, const byte* msg, int msgSz) +{ + (void)ctx; + return wc_XmssKey_Sign(key, sig, sigLen, msg, msgSz); +} + +static int _whTest_XmssVerify(whClientContext* ctx, XmssKey* key, + const byte* sig, word32 sigLen, const byte* msg, + int msgSz) +{ + (void)ctx; + return wc_XmssKey_Verify(key, sig, sigLen, msg, msgSz); +} +#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ static int _whTest_CryptoXmssCryptoCb(whClientContext* ctx, int devId, WC_RNG* rng) @@ -104,7 +177,7 @@ static int _whTest_CryptoXmssCryptoCb(whClientContext* ctx, int devId, /* MakeKey via cryptocb: the server commits the key to NVM before * returning the public key over DMA. */ if (ret == 0) { - ret = wc_XmssKey_MakeKey(key, rng); + ret = _whTest_XmssMakeKey(ctx, key, rng); if (ret != 0) { WH_ERROR_PRINT("Failed XMSS MakeKey ret=%d\n", ret); } @@ -113,7 +186,7 @@ static int _whTest_CryptoXmssCryptoCb(whClientContext* ctx, int devId, /* wc_XmssKey_SigsLeft returns a boolean: nonzero = signatures available, * 0 = exhausted. */ if (ret == 0) { - if (wc_XmssKey_SigsLeft(key) == 0) { + if (_whTest_XmssSigsLeft(ctx, key) == 0) { WH_ERROR_PRINT("XMSS reported exhausted on fresh key\n"); ret = -1; } @@ -231,7 +304,8 @@ static int _whTest_CryptoXmssCryptoCb(whClientContext* ctx, int devId, if (ret == 0) { sigLen = sigCap; - ret = wc_XmssKey_Sign(key, whTest_XmssSigBuf, &sigLen, msg, (int)msgSz); + ret = _whTest_XmssSign(ctx, key, whTest_XmssSigBuf, &sigLen, msg, + (int)msgSz); if (ret != 0) { WH_ERROR_PRINT("Failed XMSS Sign ret=%d\n", ret); } @@ -243,7 +317,8 @@ static int _whTest_CryptoXmssCryptoCb(whClientContext* ctx, int devId, } if (ret == 0) { - ret = wc_XmssKey_Verify(key, whTest_XmssSigBuf, sigLen, msg, (int)msgSz); + ret = _whTest_XmssVerify(ctx, key, whTest_XmssSigBuf, sigLen, msg, + (int)msgSz); if (ret != 0) { WH_ERROR_PRINT("Failed XMSS Verify ret=%d\n", ret); } @@ -251,7 +326,8 @@ static int _whTest_CryptoXmssCryptoCb(whClientContext* ctx, int devId, if (ret == 0) { whTest_XmssSigBuf[0] ^= 0xFF; - ret = wc_XmssKey_Verify(key, whTest_XmssSigBuf, sigLen, msg, (int)msgSz); + ret = _whTest_XmssVerify(ctx, key, whTest_XmssSigBuf, sigLen, msg, + (int)msgSz); whTest_XmssSigBuf[0] ^= 0xFF; if (ret == 0) { WH_ERROR_PRINT("XMSS Verify unexpectedly accepted tampered sig\n"); @@ -264,8 +340,8 @@ static int _whTest_CryptoXmssCryptoCb(whClientContext* ctx, int devId, if (ret == 0) { const byte wrongMsg[] = "wolfHSM XMSS cryptocb wrong"; - ret = wc_XmssKey_Verify(key, whTest_XmssSigBuf, sigLen, wrongMsg, - (int)(sizeof(wrongMsg) - 1)); + ret = _whTest_XmssVerify(ctx, key, whTest_XmssSigBuf, sigLen, wrongMsg, + (int)(sizeof(wrongMsg) - 1)); if (ret == 0) { WH_ERROR_PRINT("XMSS Verify unexpectedly accepted wrong message\n"); ret = -1; @@ -278,7 +354,7 @@ static int _whTest_CryptoXmssCryptoCb(whClientContext* ctx, int devId, /* H=10 means 1024 sigs total; after one sign, the key is still not * exhausted. */ if (ret == 0) { - if (wc_XmssKey_SigsLeft(key) == 0) { + if (_whTest_XmssSigsLeft(ctx, key) == 0) { WH_ERROR_PRINT("XMSS reported exhausted after one sign\n"); ret = -1; } @@ -469,10 +545,15 @@ int whTest_Crypto_Xmss(whClientContext* ctx) } rngInited = 1; +#ifdef WOLFHSM_CFG_DMA_NONCOHERENT + /* No DMA through wolfCrypt: the test drives the DMA APIs directly */ + ret = _whTest_CryptoXmssCryptoCb(ctx, INVALID_DEVID, rng); +#else /* XMSS dispatches through the DMA-only cryptocb. */ (void)wh_Client_SetDmaMode(ctx, 1); ret = _whTest_CryptoXmssCryptoCb(ctx, WH_DEV_ID_DMA, rng); (void)wh_Client_SetDmaMode(ctx, 0); +#endif if (rngInited) { (void)wc_FreeRng(rng); @@ -481,6 +562,6 @@ int whTest_Crypto_Xmss(whClientContext* ctx) return ret; } -#endif /* DMA && !DMA_NONCOHERENT && XMSS && !XMSS_VERIFY_ONLY */ +#endif /* WOLFHSM_CFG_DMA && WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */ #endif /* !WOLFHSM_CFG_NO_CRYPTO */ diff --git a/test-refactor/misc/wh_test_dma_noncoherent.c b/test-refactor/misc/wh_test_dma_noncoherent.c index b2f6c81c5..7b5bd09a6 100644 --- a/test-refactor/misc/wh_test_dma_noncoherent.c +++ b/test-refactor/misc/wh_test_dma_noncoherent.c @@ -23,7 +23,8 @@ * WOLFHSM_CFG_DMA_NONCOHERENT refusals: wolfCrypt cannot use DMA when client * caches are not coherent, so the client must refuse preferDma (at init and * through wh_Client_SetDmaMode) and every wolfCrypt operation on - * WH_DEV_ID_DMA must fail with WC_HW_E instead of falling back to software. + * WH_DEV_ID_DMA (AES-CBC and SHA-256 here) must fail with WC_HW_E instead of + * falling back to software. * None of this reaches the server, so the test runs a client with no server. * Also checks the aligned, padded buffers from wh_Utils_DmaAlloc. */ @@ -39,6 +40,7 @@ #include "wolfssl/wolfcrypt/settings.h" #include "wolfssl/wolfcrypt/types.h" #include "wolfssl/wolfcrypt/error-crypt.h" +#include "wolfssl/wolfcrypt/aes.h" #include "wolfssl/wolfcrypt/sha256.h" #include "wolfhsm/wh_error.h" @@ -160,9 +162,42 @@ static int _whTest_DmaNonCoherentRefusals(void) ret = -1; } -#ifndef NO_SHA256 - /* A wolfCrypt operation on WH_DEV_ID_DMA fails with WC_HW_E (no software + /* wolfCrypt operations on WH_DEV_ID_DMA fail with WC_HW_E (no software * fallback), and freeing the object afterwards still works */ +#if !defined(NO_AES) && defined(HAVE_AES_CBC) + /* Needs a cipher operation that always reaches the cryptoCb: SetKey alone + * only does so on builds that route it there, otherwise it returns 0 */ + if (ret == 0) { + Aes aes[1]; + const uint8_t key[AES_128_KEY_SIZE] = {0}; + const uint8_t iv[AES_BLOCK_SIZE] = {0}; + uint8_t in[AES_BLOCK_SIZE] = {0}; + uint8_t out[AES_BLOCK_SIZE] = {0}; + int rc; + + rc = wc_AesInit(aes, NULL, WH_DEV_ID_DMA); + if (rc != 0) { + WH_ERROR_PRINT("wc_AesInit on WH_DEV_ID_DMA failed %d\n", rc); + ret = -1; + } + else { + /* The key may be handed to the cryptoCb already (SETKEY) */ + rc = wc_AesSetKey(aes, key, sizeof(key), iv, AES_ENCRYPTION); + if (rc == 0) { + rc = wc_AesCbcEncrypt(aes, out, in, sizeof(in)); + } + if (rc != WC_HW_E) { + WH_ERROR_PRINT("AES on WH_DEV_ID_DMA returned %d, expected " + "WC_HW_E\n", + rc); + ret = -1; + } + wc_AesFree(aes); + } + } +#endif /* !NO_AES && HAVE_AES_CBC */ + +#ifndef NO_SHA256 if (ret == 0) { wc_Sha256 sha[1]; const uint8_t data[] = "noncoherent"; From 1cbf2c4f47f49c2f8c2137d29633444b0d573d62 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Mon, 26 Oct 2026 17:04:10 +0000 Subject: [PATCH 3/4] wolfHSM: rename DMA_NONCOHERENT to DMA_REQUIRE_ALIGNED_PADDED_OUTPUT --- .github/workflows/build-and-bench.yml | 4 +-- .github/workflows/build-and-test-refactor.yml | 4 +-- .github/workflows/build-and-test.yml | 4 +-- benchmark/Makefile | 6 ++-- benchmark/wh_bench_data.h | 2 +- benchmark/wh_bench_utils.h | 10 +++--- docs/src/5-Features.md | 10 +++--- docs/src/6-Utilities.md | 2 +- docs/src/9-Configuration.md | 8 ++--- port/posix/posix_transport_shm.c | 10 +++--- src/wh_client.c | 8 ++--- src/wh_client_cryptocb.c | 10 +++--- src/wh_utils.c | 4 +-- test-refactor/README.md | 4 +-- .../client-server/wh_test_crypto_aes.c | 5 +-- .../client-server/wh_test_crypto_lms.c | 11 ++++--- .../client-server/wh_test_crypto_xmss.c | 12 +++---- test-refactor/misc/wh_test_dma_noncoherent.c | 11 ++++--- test-refactor/posix/Makefile | 16 +++++----- test-refactor/posix/wh_test_posix_shm_dma.c | 13 ++++---- test/Makefile | 16 +++++----- test/wh_test_common.h | 7 ++-- test/wh_test_crypto.c | 32 +++++++++---------- test/wh_test_dma.c | 4 +-- wolfhsm/wh_client.h | 12 +++---- wolfhsm/wh_client_cryptocb.h | 3 +- wolfhsm/wh_settings.h | 32 ++++++++++--------- wolfhsm/wh_utils.h | 2 +- 28 files changed, 137 insertions(+), 125 deletions(-) diff --git a/.github/workflows/build-and-bench.yml b/.github/workflows/build-and-bench.yml index cea3fdf59..8730feeee 100644 --- a/.github/workflows/build-and-bench.yml +++ b/.github/workflows/build-and-bench.yml @@ -51,8 +51,8 @@ jobs: run: cd benchmark && make clean && make WOLFSSL_DIR=../wolfssl DMA=1 && make run # Benchmark DMA with non-coherent client caches (wolfCrypt DMA refused) - - name: Benchmark DMA NONCOHERENT - run: cd benchmark && make clean && make WOLFSSL_DIR=../wolfssl DMA=1 DMA_NONCOHERENT=1 && make run + - name: Benchmark DMA ALIGNED_PADDED_OUTPUT + run: cd benchmark && make clean && make WOLFSSL_DIR=../wolfssl DMA=1 DMA_ALIGNED_PADDED_OUTPUT=1 && make run # Benchmark with DEBUG_VERBOSE=1 (includes DEBUG) - name: Benchmark with DEBUG_VERBOSE diff --git a/.github/workflows/build-and-test-refactor.yml b/.github/workflows/build-and-test-refactor.yml index 357f74853..ba5a75b31 100644 --- a/.github/workflows/build-and-test-refactor.yml +++ b/.github/workflows/build-and-test-refactor.yml @@ -79,9 +79,9 @@ jobs: # Build and test DMA with non-coherent client caches (wolfCrypt DMA refused), # aborting on DMA output buffers that are not aligned and padded. - - name: Build and test refactor DMA NONCOHERENT THREADSAFE ASAN + - name: Build and test refactor DMA ALIGNED_PADDED_OUTPUT THREADSAFE ASAN if: matrix.group == 'pq-dma' - run: cd test-refactor/posix && make clean && make -j THREADSAFE=1 DMA=1 DMA_NONCOHERENT=1 DMA_ALIGN_CHECK=1 ASAN=1 WOLFSSL_DIR=../../wolfssl && make run + run: cd test-refactor/posix && make clean && make -j THREADSAFE=1 DMA=1 DMA_ALIGNED_PADDED_OUTPUT=1 DMA_ALIGN_CHECK=1 ASAN=1 WOLFSSL_DIR=../../wolfssl && make run # Build and test with NVM flash CRC16 integrity checking enabled - name: Build and test refactor NVM flash CRC ASAN diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 86a02647e..4d52a9281 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -79,9 +79,9 @@ jobs: # Build and test DMA with non-coherent client caches (wolfCrypt DMA refused), # aborting on DMA output buffers that are not aligned and padded - - name: Build and test DMA NONCOHERENT ASAN + - name: Build and test DMA ALIGNED_PADDED_OUTPUT ASAN if: matrix.group == 'pq-dma' - run: cd test && make clean && make -j DMA=1 DMA_NONCOHERENT=1 DMA_ALIGN_CHECK=1 ASAN=1 WOLFSSL_DIR=../wolfssl && make run + run: cd test && make clean && make -j DMA=1 DMA_ALIGNED_PADDED_OUTPUT=1 DMA_ALIGN_CHECK=1 ASAN=1 WOLFSSL_DIR=../wolfssl && make run # Build and test with NVM flash CRC16 integrity checking enabled - name: Build and test NVM flash CRC ASAN diff --git a/benchmark/Makefile b/benchmark/Makefile index 717e453d5..1640359c8 100644 --- a/benchmark/Makefile +++ b/benchmark/Makefile @@ -122,11 +122,11 @@ ifeq ($(DMA),1) endif # DMA with non-coherent client caches (requires DMA=1) -ifeq ($(DMA_NONCOHERENT),1) +ifeq ($(DMA_ALIGNED_PADDED_OUTPUT),1) ifneq ($(DMA),1) - $(error "DMA_NONCOHERENT=1 requires DMA=1 to be set") + $(error "DMA_ALIGNED_PADDED_OUTPUT=1 requires DMA=1 to be set") endif - DEF += -DWOLFHSM_CFG_DMA_NONCOHERENT + DEF += -DWOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT endif # Support a SHE-capable build diff --git a/benchmark/wh_bench_data.h b/benchmark/wh_bench_data.h index 2893a02b9..624b3fe7b 100644 --- a/benchmark/wh_bench_data.h +++ b/benchmark/wh_bench_data.h @@ -47,7 +47,7 @@ extern uint8_t wh_bench_data_out_buffer[WOLFHSM_CFG_BENCH_DATA_BUFFER_SIZE]; /* The AES modules split the buffer into an input half and an output half, each * of which must start on a line boundary with non-coherent DMA */ -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT #if (WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE % (2 * WOLFHSM_CFG_DMA_ALIGN)) != 0 #error \ "WOLFHSM_CFG_BENCH_DMA_BUFFER_SIZE must be a multiple of 2 * WOLFHSM_CFG_DMA_ALIGN" diff --git a/benchmark/wh_bench_utils.h b/benchmark/wh_bench_utils.h index f79553f0d..929c76a41 100644 --- a/benchmark/wh_bench_utils.h +++ b/benchmark/wh_bench_utils.h @@ -31,10 +31,12 @@ #define WH_BENCH_SNPRINTF snprintf #endif -/* wolfHSM refuses DMA through wolfCrypt with WOLFHSM_CFG_DMA_NONCOHERENT, so - * the benchmarks of that path are only built without it. Benchmarks of the - * direct wh_Client_*Dma APIs only depend on WOLFHSM_CFG_DMA. */ -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_DMA_NONCOHERENT) +/* wolfHSM refuses DMA through wolfCrypt with + * WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT, so the benchmarks of that path + * are only built without it. Benchmarks of the direct wh_Client_*Dma APIs only + * depend on WOLFHSM_CFG_DMA. */ +#if defined(WOLFHSM_CFG_DMA) && \ + !defined(WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT) #define WH_BENCH_CRYPTOCB_DMA #endif diff --git a/docs/src/5-Features.md b/docs/src/5-Features.md index 11461cd6b..884e45b49 100644 --- a/docs/src/5-Features.md +++ b/docs/src/5-Features.md @@ -92,7 +92,7 @@ The wolfHSM client library registers a crypto callback that turns each supported In addition to the configured per-client ID, every `wh_Client_Init()` registers the two process-global device IDs: - `WH_DEV_ID` is registered with the same unified callback as a configured `devId`, so it behaves identically — including honoring the [DMA dispatch mode](#dma-dispatch-mode-wh_client_setdmamode). It is also the ID a client is bound to when its config leaves `.devId` 0. -- `WH_DEV_ID_DMA` (present only with `WOLFHSM_CFG_DMA`) is registered with the DMA-only callback: operations always use the DMA request forms, and algorithms without a DMA variant fail rather than falling back to the standard path. It is reserved for this purpose and is not valid as a configured `.devId`. With `WOLFHSM_CFG_DMA_NONCOHERENT` every operation on it fails (see [Non-Coherent Caches and Buffer Alignment](#non-coherent-caches-and-buffer-alignment)). +- `WH_DEV_ID_DMA` (present only with `WOLFHSM_CFG_DMA`) is registered with the DMA-only callback: operations always use the DMA request forms, and algorithms without a DMA variant fail rather than falling back to the standard path. It is reserved for this purpose and is not valid as a configured `.devId`. With `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT` every operation on it fails (see [Non-Coherent Caches and Buffer Alignment](#non-coherent-caches-and-buffer-alignment)). The global IDs preserve the behavior of earlier wolfHSM releases: an application with a **single client per process** needs no devId configuration at all and can keep passing `WH_DEV_ID` (or `WH_DEV_ID_DMA`) straight to wolfCrypt functions, exactly as before — they are always registered and available after `wh_Client_Init()`. Because these registrations are process-global and keyed on the integer value, each `wh_Client_Init()` rebinds them to the most recently initialized client, and **any** client's `wh_Client_Cleanup()` unregisters them. In a multi-client process they are therefore unreliable and should not be passed to wolfCrypt; use the per-client configured IDs instead. Both values are overridable at compile time (see [Configuration](9-Configuration.md#cryptography-features)). @@ -643,7 +643,7 @@ The motivating use cases all involve payloads that are either too large or too i ### DMA Dispatch Mode (`wh_Client_SetDmaMode`) -For wolfCrypt-mediated operations, opt-in to DMA is a per-client dispatch mode rather than a separate device ID: the application calls `wh_Client_SetDmaMode(client, 1)` (or sets `.preferDma` in the client's `whClientDmaConfig` at init), and subsequent wolfCrypt calls made with `WH_CLIENT_DEVID(client)` construct DMA-flavored requests whose payloads carry pointers and lengths into the client's address space rather than inline data. The server-side dispatcher recognizes the DMA request kind and, for each referenced buffer, hands the pointer to the server's DMA address-processing path (described below) before invoking the underlying wolfCrypt primitive. The set of algorithms that have a DMA path mirrors the most performance-sensitive subset of the supported algorithms; with DMA mode preferred, an algorithm without a DMA path automatically falls back to the standard (non-DMA) request, so no call-site changes are needed. The mode can be toggled at any time — `wh_Client_SetDmaMode(client, 0)` returns the client to standard dispatch, and `wh_Client_GetDmaMode()` reads the current setting. With `WOLFHSM_CFG_DMA_NONCOHERENT` the DMA dispatch mode cannot be enabled (see [Non-Coherent Caches and Buffer Alignment](#non-coherent-caches-and-buffer-alignment)). +For wolfCrypt-mediated operations, opt-in to DMA is a per-client dispatch mode rather than a separate device ID: the application calls `wh_Client_SetDmaMode(client, 1)` (or sets `.preferDma` in the client's `whClientDmaConfig` at init), and subsequent wolfCrypt calls made with `WH_CLIENT_DEVID(client)` construct DMA-flavored requests whose payloads carry pointers and lengths into the client's address space rather than inline data. The server-side dispatcher recognizes the DMA request kind and, for each referenced buffer, hands the pointer to the server's DMA address-processing path (described below) before invoking the underlying wolfCrypt primitive. The set of algorithms that have a DMA path mirrors the most performance-sensitive subset of the supported algorithms; with DMA mode preferred, an algorithm without a DMA path automatically falls back to the standard (non-DMA) request, so no call-site changes are needed. The mode can be toggled at any time — `wh_Client_SetDmaMode(client, 0)` returns the client to standard dispatch, and `wh_Client_GetDmaMode()` reads the current setting. With `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT` the DMA dispatch mode cannot be enabled (see [Non-Coherent Caches and Buffer Alignment](#non-coherent-caches-and-buffer-alignment)). The global `WH_DEV_ID_DMA` device ID is also always registered when `WOLFHSM_CFG_DMA` is enabled and always produces DMA-flavored requests for the most recently initialized client; unlike the DMA dispatch mode, it does not fall back to the standard path for algorithms without a DMA variant. See [Transparent Offload via Crypto Callbacks](#transparent-offload-via-crypto-callbacks) for the global device IDs' single-client-per-process scope. @@ -693,7 +693,7 @@ A symmetric `whDmaAddrAllowList` is also available on the client side for client When the client's memory is cached and the hardware does not keep that cache coherent with the server's accesses, the port's client DMA callback has to clean the cache lines before the server accesses a buffer and invalidate them after the server has written it (`WH_DMA_OPER_CLIENT_WRITE_POST`). Cache maintenance works on whole lines, so a buffer the server writes must not share a line with other data: an invalidate would discard the CPU's writes to that data, and an eviction could overwrite the server's. -Define `WOLFHSM_CFG_DMA_NONCOHERENT` for these targets. Every buffer the server writes must then start on a `WOLFHSM_CFG_DMA_ALIGN` boundary (default `XCACHELINE`) and be padded to a multiple of it. The length passed to the API stays the real length: +Define `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT` for these targets. Every buffer the server writes must then start on a `WOLFHSM_CFG_DMA_ALIGN` boundary (default `XCACHELINE`) and be padded to a multiple of it. The length passed to the API stays the real length: ```c WH_DMA_ALIGNED uint8_t cipher[WH_DMA_PAD_SIZE(sizeof(plain))]; @@ -701,11 +701,11 @@ WH_DMA_ALIGNED uint8_t cipher[WH_DMA_PAD_SIZE(sizeof(plain))]; ret = wh_Client_AesCtrDma(client, aes, 1, plain, sizeof(plain), cipher); ``` -`WH_DMA_ALIGNED` and `WH_DMA_PAD_SIZE()` are no-ops without `WOLFHSM_CFG_DMA_NONCOHERENT`. wolfHSM's own internal output buffers follow the rule. For caller buffers, the port's callback can check the start with `WH_DMA_IS_ALIGNED()` (as `posixTransportShm_ClientStaticMemDmaCallback` does for buffers it uses in place) or copy through a bounce buffer from `wh_Utils_DmaAlloc()`; padding cannot be checked. +`WH_DMA_ALIGNED` and `WH_DMA_PAD_SIZE()` are no-ops without `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT`. wolfHSM's own internal output buffers follow the rule. For caller buffers, the port's callback can check the start with `WH_DMA_IS_ALIGNED()` (as `posixTransportShm_ClientStaticMemDmaCallback` does for buffers it uses in place) or copy through a bounce buffer from `wh_Utils_DmaAlloc()`; padding cannot be checked. Test builds can define `WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK` (`make DMA_ALIGN_CHECK=1` in `test/` and `test-refactor/posix/`) to abort on any output buffer that does not start on a `WOLFHSM_CFG_DMA_ALIGN` boundary or, in ASAN builds, is not padded to a multiple of it. The check runs in `wh_Client_DmaProcessClientAddress`, so it covers wolfHSM's own buffers and every buffer the tests pass, whatever DMA callback the client registers. The make option also raises `WOLFHSM_CFG_DMA_ALIGN` to 256, so a buffer missing `WH_DMA_ALIGNED` does not pass by being aligned by chance. -wolfCrypt passes the crypto callback buffers it does not control, such as its own stack and structure buffers, so with `WOLFHSM_CFG_DMA_NONCOHERENT` wolfHSM refuses DMA through wolfCrypt: every operation on `WH_DEV_ID_DMA` fails with `WC_HW_E`, and `whClientDmaConfig::preferDma` and `wh_Client_SetDmaMode(client, 1)` fail with `WH_ERROR_BADARGS`. Use `WH_DEV_ID` (or the client's configured devId) for wolfCrypt, and call the `wh_Client_*Dma` APIs directly where zero-copy matters. LMS and XMSS have no non-DMA path, so with this option they are available only through the `wh_Client_Lms*Dma` and `wh_Client_Xmss*Dma` APIs. +wolfCrypt passes the crypto callback buffers it does not control, such as its own stack and structure buffers, so with `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT` wolfHSM refuses DMA through wolfCrypt: every operation on `WH_DEV_ID_DMA` fails with `WC_HW_E`, and `whClientDmaConfig::preferDma` and `wh_Client_SetDmaMode(client, 1)` fail with `WH_ERROR_BADARGS`. Use `WH_DEV_ID` (or the client's configured devId) for wolfCrypt, and call the `wh_Client_*Dma` APIs directly where zero-copy matters. LMS and XMSS have no non-DMA path, so with this option they are available only through the `wh_Client_Lms*Dma` and `wh_Client_Xmss*Dma` APIs. ### 32-bit vs. 64-bit Address Handling diff --git a/docs/src/6-Utilities.md b/docs/src/6-Utilities.md index 2aa1564ea..f728e206c 100644 --- a/docs/src/6-Utilities.md +++ b/docs/src/6-Utilities.md @@ -53,7 +53,7 @@ make DMA=1 make run ``` -Add `DMA_NONCOHERENT=1` (with `DMA=1`) to build with `WOLFHSM_CFG_DMA_NONCOHERENT`; the benchmarks of DMA through wolfCrypt are then skipped. +Add `DMA_ALIGNED_PADDED_OUTPUT=1` (with `DMA=1`) to build with `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT`; the benchmarks of DMA through wolfCrypt are then skipped. ### Running Benchmarks on Real Hardware diff --git a/docs/src/9-Configuration.md b/docs/src/9-Configuration.md index 1927d624c..591913825 100644 --- a/docs/src/9-Configuration.md +++ b/docs/src/9-Configuration.md @@ -141,8 +141,8 @@ These macros gate and tune DMA-mode crypto and large-buffer operations. | `WOLFHSM_CFG_DMA_PTR_SIZE` | Compiler-detected (`__SIZEOF_POINTER__`) | Override the assumed DMA pointer size, in bytes (must be `4` or `8`). Auto-detection works for GCC/Clang and IAR; define this explicitly for any toolchain that does not provide `__SIZEOF_POINTER__`. | | `WOLFHSM_CFG_DMA_ALT_PTR_SIZE` | Undefined | If defined, allows the DMA pointer size to differ from the native CPU pointer size (e.g. a 32-bit-pointer server reachable from a 64-bit-pointer client). When undefined, wh_settings.h refuses to build with a mismatched `WOLFHSM_CFG_DMA_PTR_SIZE`. | | `WOLFHSM_CFG_DMA_INLINE_AAD_MAX_SIZE` | `128` | Largest additional authenticated data, in bytes, that a DMA AEAD request can carry inside the message (through the transport) instead of over DMA. An AAD above this size is passed as a DMA buffer. | -| `WOLFHSM_CFG_DMA_NONCOHERENT` | Undefined | Define when client memory the server writes over DMA is cached and not kept coherent by the hardware. Output buffers of the `wh_Client_*Dma` APIs must then be aligned and padded to `WOLFHSM_CFG_DMA_ALIGN`, and DMA through wolfCrypt is refused (`WH_DEV_ID_DMA` fails with `WC_HW_E`, `preferDma` cannot be enabled). Requires `WOLFHSM_CFG_DMA`. Set by `DMA_NONCOHERENT=1` in the test and benchmark builds. See [Non-Coherent Caches and Buffer Alignment](5-Features.md#non-coherent-caches-and-buffer-alignment). | -| `WOLFHSM_CFG_DMA_ALIGN` | `XCACHELINE` | Alignment and padding, in bytes, of client buffers the server writes over DMA. A power of two and a multiple of `XCACHELINE`. Only used with `WOLFHSM_CFG_DMA_NONCOHERENT`. | +| `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT` | Undefined | Define when client memory the server writes over DMA is cached and not kept coherent by the hardware. Output buffers of the `wh_Client_*Dma` APIs must then be aligned and padded to `WOLFHSM_CFG_DMA_ALIGN`, and DMA through wolfCrypt is refused (`WH_DEV_ID_DMA` fails with `WC_HW_E`, `preferDma` cannot be enabled). Requires `WOLFHSM_CFG_DMA`. Set by `DMA_ALIGNED_PADDED_OUTPUT=1` in the test and benchmark builds. See [Non-Coherent Caches and Buffer Alignment](5-Features.md#non-coherent-caches-and-buffer-alignment). | +| `WOLFHSM_CFG_DMA_ALIGN` | `XCACHELINE` | Alignment and padding, in bytes, of client buffers the server writes over DMA. A power of two and a multiple of `XCACHELINE`. Only used with `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT`. | | `WOLFHSM_CFG_DMA_CUSTOM_CLIENT_COPY` | Undefined | If defined, expose hooks that let the integrator override the client-to-server and server-to-client memory copy used during DMA requests. Useful when DMA buffers live in shared memory that requires custom invalidation or cache maintenance beyond the standard `XCACHE*` macros. | ## Authentication @@ -221,7 +221,7 @@ These macros are only meant for the wolfHSM test suites (`test/`, `test-refactor | `WOLFHSM_CFG_TEST_ASSERT_FUNC` | stdlib `assert()` | If defined, overrides the macro used by the test harness to evaluate `WH_TEST_ASSERT(...)`. Useful for redirecting assertion failures into a target-specific failure reporter. | | `WOLFHSM_CFG_TEST_ALLOW_PERSISTENT_NVM_ARTIFACTS` | Undefined | If defined, NVM-touching tests are allowed to leave persistent artifacts behind (objects, counters, keys) between runs, which lets a separate test phase verify them. Otherwise NVM is reset between tests. Used by the POSIX test build. | | `WOLFHSM_CFG_TEST_CRYPTSVR_CFG` | Implicitly defined | The crypto-server test pulls in its standard wolfCrypt test configuration unless `NO_WOLFHSM_CFG_TEST_CRYPTSVR_CFG` is defined at build time, in which case the integrator must supply their own configuration. | -| `WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK` | Undefined | If defined, `wh_Client_DmaProcessClientAddress` aborts when a client buffer the server writes over DMA does not start on a `WOLFHSM_CFG_DMA_ALIGN` boundary or, in ASAN builds, is not padded to a multiple of it, printing the buffer and the call that passed it. Requires `WOLFHSM_CFG_DMA_NONCOHERENT`. Set, together with `WOLFHSM_CFG_DMA_ALIGN=256`, by the `DMA_ALIGN_CHECK=1` make variable. See [Non-Coherent Caches and Buffer Alignment](5-Features.md#non-coherent-caches-and-buffer-alignment). | +| `WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK` | Undefined | If defined, `wh_Client_DmaProcessClientAddress` aborts when a client buffer the server writes over DMA does not start on a `WOLFHSM_CFG_DMA_ALIGN` boundary or, in ASAN builds, is not padded to a multiple of it, printing the buffer and the call that passed it. Requires `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT`. Set, together with `WOLFHSM_CFG_DMA_ALIGN=256`, by the `DMA_ALIGN_CHECK=1` make variable. See [Non-Coherent Caches and Buffer Alignment](5-Features.md#non-coherent-caches-and-buffer-alignment). | | `WOLFHSM_CFG_IS_TEST_SERVER` | Undefined | If defined, the client-side unit tests assume they are talking to a server that is running additional test-only instrumentation (exercising edge cases that cannot be triggered against a standard server). Set automatically for the combined client/server POSIX test build; should not be defined outside of that harness. | ## Memory and Cache Porting Macros @@ -229,7 +229,7 @@ These macros are only meant for the wolfHSM test suites (`test/`, `test-refactor For completeness, wolfHSM also relies on a small number of `X*` porting macros that are normally supplied alongside the `WOLFHSM_CFG_*` macros in `wolfhsm_cfg.h` even though they do not share the prefix: - `XMEMFENCE()` — sequential memory fence (defaults to `__atomic_thread_fence(__ATOMIC_SEQ_CST)` on GCC/Clang; otherwise a no-op with a build warning). -- `XCACHELINE` — cache-line size in bytes (default `32`). Must be usable in `#if` with `WOLFHSM_CFG_DMA_NONCOHERENT`. +- `XCACHELINE` — cache-line size in bytes (default `32`). Must be usable in `#if` with `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT`. - `XCACHEFLUSH(p)` / `XCACHEFLUSHBLK(p, n)` — flush one line / a range; defaults are no-op and `wh_Utils_CacheFlush` respectively. - `XCACHEINVLD(p)` / `XCACHEINVLDBLK(p, n)` — invalidate one line / a range; defaults are no-op and `wh_Utils_CacheInvalidate` respectively. diff --git a/port/posix/posix_transport_shm.c b/port/posix/posix_transport_shm.c index c29d43389..afaab74a6 100644 --- a/port/posix/posix_transport_shm.c +++ b/port/posix/posix_transport_shm.c @@ -607,9 +607,9 @@ int posixTransportShm_RecvResponse(void* c, uint16_t* out_len, void* data) /* Client buffers outside the DMA area are copied through a bounce buffer: * from wh_Utils_DmaAlloc for output, which the server writes, and from XMALLOC * for input, which needs no cache-line isolation. Buffers in the DMA area are - * used in place; with WOLFHSM_CFG_DMA_NONCOHERENT an in-place output buffer - * must be aligned to WOLFHSM_CFG_DMA_ALIGN (its padding cannot be checked). - * POSIX needs no cache maintenance. */ + * used in place; with WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT an in-place + * output buffer must be aligned to WOLFHSM_CFG_DMA_ALIGN (its padding cannot be + * checked). POSIX needs no cache maintenance. */ int posixTransportShm_ClientStaticMemDmaCallback( struct whClientContext_t* client, uintptr_t clientAddr, @@ -663,12 +663,12 @@ int posixTransportShm_ClientStaticMemDmaCallback( memcpy((void*)dmaBuffer, (void*)clientAddr, len); } else { -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT if ((oper == WH_DMA_OPER_CLIENT_WRITE_PRE) && !WH_DMA_IS_ALIGNED(clientAddr)) { return WH_ERROR_BADARGS; } -#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ dmaOffset = clientAddr - (uintptr_t)dmaPtr; } /* return an offset into the DMA area */ diff --git a/src/wh_client.c b/src/wh_client.c index 0d36eddbe..205bc9adf 100644 --- a/src/wh_client.c +++ b/src/wh_client.c @@ -91,13 +91,13 @@ int wh_Client_Init(whClientContext* c, const whClientConfig* config) if (config->devId == WH_DEV_ID_DMA) { return WH_ERROR_BADARGS; } -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT /* wolfCrypt cannot use DMA with non-coherent caches, see * wh_Client_CryptoCbDma */ if ((config->dmaConfig != NULL) && (config->dmaConfig->preferDma != 0)) { return WH_ERROR_BADARGS; } -#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ #endif /* WOLFHSM_CFG_DMA */ #endif /* !WOLFHSM_CFG_NO_CRYPTO */ @@ -543,13 +543,13 @@ int wh_Client_SetDmaMode(whClientContext* c, int useDma) return WH_ERROR_BADARGS; } #ifdef WOLFHSM_CFG_DMA -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT /* wolfCrypt cannot use DMA with non-coherent caches, see * wh_Client_CryptoCbDma */ if (useDma) { return WH_ERROR_BADARGS; } -#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ c->dma.preferDma = (uint32_t)(useDma ? 1 : 0); #else (void)useDma; diff --git a/src/wh_client_cryptocb.c b/src/wh_client_cryptocb.c index 2a91cec42..ec58f19f1 100644 --- a/src/wh_client_cryptocb.c +++ b/src/wh_client_cryptocb.c @@ -100,7 +100,8 @@ int wh_Client_CryptoCb(int devId, wc_CryptoInfo* info, void* inCtx) return BAD_FUNC_ARG; } -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_DMA_NONCOHERENT) +#if defined(WOLFHSM_CFG_DMA) && \ + !defined(WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT) /* If the client prefers DMA operations, dispatch to the DMA callback first * and fall back to the standard (non-DMA) callback if the algorithm is not * supported by the DMA callback. */ @@ -111,7 +112,7 @@ int wh_Client_CryptoCb(int devId, wc_CryptoInfo* info, void* inCtx) } } else -#endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ { /* DMA not preferred (or not compiled in); use the standard callback */ ret = wh_Client_CryptoCbStd(devId, info, inCtx); @@ -1422,7 +1423,8 @@ static int _handlePqcSigCheckPrivKey(whClientContext* ctx, wc_CryptoInfo* info, #endif /* HAVE_FALCON || WOLFSSL_HAVE_MLDSA */ -#if defined(WOLFHSM_CFG_DMA) && defined(WOLFHSM_CFG_DMA_NONCOHERENT) +#if defined(WOLFHSM_CFG_DMA) && \ + defined(WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT) /* With non-coherent DMA the server may only write into buffers that are * aligned and padded to whole cache lines, which wolfCrypt cannot guarantee * for the buffers it passes in. Fail every operation instead of letting @@ -1799,6 +1801,6 @@ int wh_Client_CryptoCbDma(int devId, wc_CryptoInfo* info, void* inCtx) } return ret; } -#endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ #endif /* !WOLFHSM_CFG_NO_CRYPTO && WOLFHSM_CFG_ENABLE_CLIENT */ diff --git a/src/wh_utils.c b/src/wh_utils.c index 9439bed4a..1393ef5d8 100644 --- a/src/wh_utils.c +++ b/src/wh_utils.c @@ -227,7 +227,7 @@ void* wh_Utils_memcpy_flush(void* dst, const void* src , size_t n) #if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_NO_CRYPTO) /** DMA buffer helpers */ -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT /* The allocator only guarantees its own alignment, so over-allocate and keep * the raw pointer just before the aligned start */ void* wh_Utils_DmaAlloc(size_t len, void* heap) @@ -278,7 +278,7 @@ void wh_Utils_DmaFree(void* ptr, void* heap) (void)heap; XFREE(ptr, heap, DYNAMIC_TYPE_TMP_BUFFER); } -#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ #endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_NO_CRYPTO */ #if defined(WOLFHSM_CFG_HEXDUMP) diff --git a/test-refactor/README.md b/test-refactor/README.md index 0f285d358..27a01132e 100644 --- a/test-refactor/README.md +++ b/test-refactor/README.md @@ -85,8 +85,8 @@ Translated tests: | `wh_test_cert.c::whTest_CertRamSim` | `server/wh_test_cert.c::whTest_CertVerify` | Server | remove ramsim coupling and migrate to server group. Legacy ran FLASH and FLASH_LOG backends; the port runs the plain flash backend only -- FLASH_LOG re-run pending (see Known coverage gaps) | | `wh_test_crypto.c::whTest_Crypto` | `client-server/wh_test_crypto_{aes,cmac,curve25519,ecc,ed25519,kdf,keypolicy,mldsa,rng,rsa,sha}.c::whTest_Crypto_*` | Client | Split into per-algorithm suites; key revocation is gated by `WOLFHSM_CFG_TEST_ALLOW_PERSISTENT_NVM_ARTIFACTS`. Legacy ran FLASH and FLASH_LOG backends; the port runs the plain flash backend only -- FLASH_LOG re-run pending (see Known coverage gaps) | | `wh_test_crypto.c::whTest_CryptoKeyUsagePolicies` (AES CTR/ECB/GCM subset) | `client-server/wh_test_crypto_aes.c::whTest_CryptoAesKeyUsagePolicies` | Client | AES-CTR/ECB/GCM key usage enforcement (non-DMA and DMA variants) | -| `wh_test_crypto.c::whTestCrypto_LmsCryptoCb` | `client-server/wh_test_crypto_lms.c::whTest_Crypto_Lms` | Client | DMA-only LMS generate/durability/sign/verify, public-key export+import, private export/import rejection, and the server-only `WH_NVM_FLAGS_TRUSTED` keygen strip regression. Gated by `WOLFHSM_CFG_DMA && WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY`; reports SKIPPED otherwise. With `WOLFHSM_CFG_DMA_NONCOHERENT` (wolfCrypt refuses `WH_DEV_ID_DMA`) the keygen/sign/verify/sigs-left steps call the `wh_Client_Lms*Dma` APIs directly instead of the cryptoCb | -| `wh_test_crypto.c::whTestCrypto_XmssCryptoCb` | `client-server/wh_test_crypto_xmss.c::whTest_Crypto_Xmss` | Client | DMA-only XMSS generate/durability/sign/verify, public-key export+import, private export/import rejection, and the server-only `WH_NVM_FLAGS_TRUSTED` keygen strip regression. Gated by `WOLFHSM_CFG_DMA && WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY`; reports SKIPPED otherwise. With `WOLFHSM_CFG_DMA_NONCOHERENT` (wolfCrypt refuses `WH_DEV_ID_DMA`) the keygen/sign/verify/sigs-left steps call the `wh_Client_Xmss*Dma` APIs directly instead of the cryptoCb | +| `wh_test_crypto.c::whTestCrypto_LmsCryptoCb` | `client-server/wh_test_crypto_lms.c::whTest_Crypto_Lms` | Client | DMA-only LMS generate/durability/sign/verify, public-key export+import, private export/import rejection, and the server-only `WH_NVM_FLAGS_TRUSTED` keygen strip regression. Gated by `WOLFHSM_CFG_DMA && WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY`; reports SKIPPED otherwise. With `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT` (wolfCrypt refuses `WH_DEV_ID_DMA`) the keygen/sign/verify/sigs-left steps call the `wh_Client_Lms*Dma` APIs directly instead of the cryptoCb | +| `wh_test_crypto.c::whTestCrypto_XmssCryptoCb` | `client-server/wh_test_crypto_xmss.c::whTest_Crypto_Xmss` | Client | DMA-only XMSS generate/durability/sign/verify, public-key export+import, private export/import rejection, and the server-only `WH_NVM_FLAGS_TRUSTED` keygen strip regression. Gated by `WOLFHSM_CFG_DMA && WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY`; reports SKIPPED otherwise. With `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT` (wolfCrypt refuses `WH_DEV_ID_DMA`) the keygen/sign/verify/sigs-left steps call the `wh_Client_Xmss*Dma` APIs directly instead of the cryptoCb | | `wh_test_crypto.c::{whTest_KeyCache, whTest_NonExportableKeystore}` | `client-server/wh_test_crypto_keystore.c::whTest_Crypto_Keystore` | Client | Key-cache lifecycle (cache/export, evict, commit/erase, cross-cache eviction/replacement, NVM-backed eviction) and non-exportable-flag enforcement; std and DMA export paths. The `WOLFHSM_CFG_IS_TEST_SERVER` multi-client user-exclusion path is dropped (needs two client contexts) | | `wh_test_clientserver.c` (echo and server-info paths) | `client-server/wh_test_echo.c::whTest_Echo`, `client-server/wh_test_server_info.c::whTest_ServerInfo` | Client | pthread test ported, sequential test dropped | | `wh_test_clientserver.c` (NVM CRUD + OOB read clamping paths) | `client-server/wh_test_nvm_ops.c::{whTest_NvmCrud, whTest_NvmReadOob}` | Client | each test cleans up its own slots; OOB test covers UINT16_MAX overflow regression | diff --git a/test-refactor/client-server/wh_test_crypto_aes.c b/test-refactor/client-server/wh_test_crypto_aes.c index 541c7c351..6c801c6c5 100644 --- a/test-refactor/client-server/wh_test_crypto_aes.c +++ b/test-refactor/client-server/wh_test_crypto_aes.c @@ -784,7 +784,8 @@ int whTest_CryptoAesKeyUsagePolicies(whClientContext* ctx) /* These go through wolfCrypt on WH_DEV_ID_DMA, which non-coherent DMA builds * refuse */ -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_DMA_NONCOHERENT) +#if defined(WOLFHSM_CFG_DMA) && \ + !defined(WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT) #ifdef WOLFSSL_AES_COUNTER /* AES-CTR DMA: encrypt without ENCRYPT flag */ { @@ -1094,7 +1095,7 @@ int whTest_CryptoAesKeyUsagePolicies(whClientContext* ctx) goto done; } #endif /* HAVE_AESGCM */ -#endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ done: wc_FreeRng(rng); diff --git a/test-refactor/client-server/wh_test_crypto_lms.c b/test-refactor/client-server/wh_test_crypto_lms.c index c37f0df24..65fe1ede3 100644 --- a/test-refactor/client-server/wh_test_crypto_lms.c +++ b/test-refactor/client-server/wh_test_crypto_lms.c @@ -24,8 +24,9 @@ * key export and import, and enforcement of the * no-private-export / no-private-import policy * - * With WOLFHSM_CFG_DMA_NONCOHERENT wolfCrypt cannot use DMA, so the key - * operations drive the wh_Client_Lms*Dma APIs directly instead of the cryptoCb. + * With WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT wolfCrypt cannot use DMA, + * so the key operations drive the wh_Client_Lms*Dma APIs directly instead of + * the cryptoCb. */ #include "wolfhsm/wh_settings.h" @@ -65,7 +66,7 @@ static WH_DMA_ALIGNED byte whTest_LmsSigBuf[WH_DMA_PAD_SIZE(8800)]; /* Key operations under test. wolfCrypt cannot use DMA with non-coherent * caches, so there the wh_Client_Lms*Dma APIs are driven directly instead of * going through the cryptoCb (devId is then INVALID_DEVID). */ -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT static int _whTest_LmsMakeKey(whClientContext* ctx, LmsKey* key, WC_RNG* rng) { int ret; @@ -129,7 +130,7 @@ static int _whTest_LmsVerify(whClientContext* ctx, LmsKey* key, const byte* sig, (void)ctx; return wc_LmsKey_Verify(key, sig, sigLen, msg, msgSz); } -#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ static int _whTest_CryptoLmsCryptoCb(whClientContext* ctx, int devId, WC_RNG* rng) @@ -556,7 +557,7 @@ int whTest_Crypto_Lms(whClientContext* ctx) } rngInited = 1; -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT /* No DMA through wolfCrypt: the test drives the DMA APIs directly */ ret = _whTest_CryptoLmsCryptoCb(ctx, INVALID_DEVID, rng); #else diff --git a/test-refactor/client-server/wh_test_crypto_xmss.c b/test-refactor/client-server/wh_test_crypto_xmss.c index 244556ada..6471d747c 100644 --- a/test-refactor/client-server/wh_test_crypto_xmss.c +++ b/test-refactor/client-server/wh_test_crypto_xmss.c @@ -24,9 +24,9 @@ * key export and import, and enforcement of the * no-private-export / no-private-import policy * - * With WOLFHSM_CFG_DMA_NONCOHERENT wolfCrypt cannot use DMA, so the key - * operations drive the wh_Client_Xmss*Dma APIs directly instead of the - * cryptoCb. + * With WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT wolfCrypt cannot use DMA, + * so the key operations drive the wh_Client_Xmss*Dma APIs directly instead of + * the cryptoCb. */ #include "wolfhsm/wh_settings.h" @@ -63,7 +63,7 @@ static WH_DMA_ALIGNED byte whTest_XmssSigBuf[WH_DMA_PAD_SIZE(2500)]; /* Key operations under test. wolfCrypt cannot use DMA with non-coherent * caches, so there the wh_Client_Xmss*Dma APIs are driven directly instead of * going through the cryptoCb (devId is then INVALID_DEVID). */ -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT static int _whTest_XmssMakeKey(whClientContext* ctx, XmssKey* key, WC_RNG* rng) { int ret; @@ -129,7 +129,7 @@ static int _whTest_XmssVerify(whClientContext* ctx, XmssKey* key, (void)ctx; return wc_XmssKey_Verify(key, sig, sigLen, msg, msgSz); } -#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ static int _whTest_CryptoXmssCryptoCb(whClientContext* ctx, int devId, WC_RNG* rng) @@ -545,7 +545,7 @@ int whTest_Crypto_Xmss(whClientContext* ctx) } rngInited = 1; -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT /* No DMA through wolfCrypt: the test drives the DMA APIs directly */ ret = _whTest_CryptoXmssCryptoCb(ctx, INVALID_DEVID, rng); #else diff --git a/test-refactor/misc/wh_test_dma_noncoherent.c b/test-refactor/misc/wh_test_dma_noncoherent.c index 7b5bd09a6..bd86b1386 100644 --- a/test-refactor/misc/wh_test_dma_noncoherent.c +++ b/test-refactor/misc/wh_test_dma_noncoherent.c @@ -20,9 +20,9 @@ /* * test-refactor/misc/wh_test_dma_noncoherent.c * - * WOLFHSM_CFG_DMA_NONCOHERENT refusals: wolfCrypt cannot use DMA when client - * caches are not coherent, so the client must refuse preferDma (at init and - * through wh_Client_SetDmaMode) and every wolfCrypt operation on + * WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT refusals: wolfCrypt cannot use + * DMA when client caches are not coherent, so the client must refuse preferDma + * (at init and through wh_Client_SetDmaMode) and every wolfCrypt operation on * WH_DEV_ID_DMA (AES-CBC and SHA-256 here) must fail with WC_HW_E instead of * falling back to software. * None of this reaches the server, so the test runs a client with no server. @@ -31,7 +31,8 @@ #include "wolfhsm/wh_settings.h" -#if defined(WOLFHSM_CFG_DMA) && defined(WOLFHSM_CFG_DMA_NONCOHERENT) && \ +#if defined(WOLFHSM_CFG_DMA) && \ + defined(WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT) && \ defined(WOLFHSM_CFG_ENABLE_CLIENT) && !defined(WOLFHSM_CFG_NO_CRYPTO) #include @@ -239,4 +240,4 @@ int whTest_DmaNonCoherent(void* ctx) return WH_ERROR_OK; } -#endif /* DMA && DMA_NONCOHERENT && ENABLE_CLIENT && !NO_CRYPTO */ +#endif /* DMA && DMA_ALIGNED_PADDED_OUTPUT && ENABLE_CLIENT && !NO_CRYPTO */ diff --git a/test-refactor/posix/Makefile b/test-refactor/posix/Makefile index a5b232ce1..d548effb0 100644 --- a/test-refactor/posix/Makefile +++ b/test-refactor/posix/Makefile @@ -113,19 +113,19 @@ ifeq ($(DMA),1) endif # DMA with non-coherent client caches (requires DMA=1) -ifeq ($(DMA_NONCOHERENT),1) +ifeq ($(DMA_ALIGNED_PADDED_OUTPUT),1) ifneq ($(DMA),1) - $(error "DMA_NONCOHERENT=1 requires DMA=1 to be set") + $(error "DMA_ALIGNED_PADDED_OUTPUT=1 requires DMA=1 to be set") endif - DEF += -DWOLFHSM_CFG_DMA_NONCOHERENT + DEF += -DWOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT endif # Abort on DMA output buffers that are not aligned and padded (requires -# DMA_NONCOHERENT=1; padding is only checked with ASAN=1). The large +# DMA_ALIGNED_PADDED_OUTPUT=1; padding is only checked with ASAN=1). The large # alignment keeps a buffer missing WH_DMA_ALIGNED from being aligned by luck. ifeq ($(DMA_ALIGN_CHECK),1) - ifneq ($(DMA_NONCOHERENT),1) - $(error "DMA_ALIGN_CHECK=1 requires DMA_NONCOHERENT=1 to be set") + ifneq ($(DMA_ALIGNED_PADDED_OUTPUT),1) + $(error "DMA_ALIGN_CHECK=1 requires DMA_ALIGNED_PADDED_OUTPUT=1 to be set") endif DEF += -DWOLFHSM_CFG_TEST_DMA_ALIGN_CHECK -DWOLFHSM_CFG_DMA_ALIGN=256 endif @@ -230,8 +230,8 @@ ifeq ($(TESTWOLFCRYPT),1) # wolfCrypt cannot use DMA with non-coherent caches (WH_DEV_ID_DMA fails # every operation), so the suite cannot run against WH_DEV_ID_DMA ifneq ($(TESTWOLFCRYPT_DMA),) - ifeq ($(DMA_NONCOHERENT),1) - $(error "TESTWOLFCRYPT_DMA=1 cannot be used with DMA_NONCOHERENT=1") + ifeq ($(DMA_ALIGNED_PADDED_OUTPUT),1) + $(error "TESTWOLFCRYPT_DMA=1 cannot be used with DMA_ALIGNED_PADDED_OUTPUT=1") endif endif diff --git a/test-refactor/posix/wh_test_posix_shm_dma.c b/test-refactor/posix/wh_test_posix_shm_dma.c index b5d46c3c9..e9c566cef 100644 --- a/test-refactor/posix/wh_test_posix_shm_dma.c +++ b/test-refactor/posix/wh_test_posix_shm_dma.c @@ -21,9 +21,10 @@ * * In-place buffers in the POSIX shared memory client DMA callback. A client * buffer already inside the DMA area is passed to the server as its offset, - * without a bounce copy; with WOLFHSM_CFG_DMA_NONCOHERENT a buffer the server - * writes must also be aligned. The object is mapped twice, as server and as - * client, so the two mappings sit at different addresses as in two processes. + * without a bounce copy; with WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT a + * buffer the server writes must also be aligned. The object is mapped twice, as + * server and as client, so the two mappings sit at different addresses as in + * two processes. */ #include "wolfhsm/wh_settings.h" @@ -52,8 +53,8 @@ int whTest_PosixShmDmaInPlace(void* ctx) #include "wolfhsm/wh_client.h" #include "port/posix/posix_transport_shm.h" -/* Without NONCOHERENT any alignment is accepted; 64 just exercises the path */ -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +/* Without the rule any alignment is accepted; 64 just exercises the path */ +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT #define SHMDMA_ALIGN WOLFHSM_CFG_DMA_ALIGN #else #define SHMDMA_ALIGN 64 @@ -90,7 +91,7 @@ static int _ShmDmaInPlace(whClientContext* client, uint8_t* cliDma, ret = posixTransportShm_ClientStaticMemDmaCallback( client, (uintptr_t)(buf + 1), &off, SHMDMA_LEN, WH_DMA_OPER_CLIENT_WRITE_PRE, flags); -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT WH_TEST_ASSERT_RETURN(ret == WH_ERROR_BADARGS); #else WH_TEST_ASSERT_RETURN(ret == WH_ERROR_OK); diff --git a/test/Makefile b/test/Makefile index 3b0205dff..28e506ea1 100644 --- a/test/Makefile +++ b/test/Makefile @@ -143,19 +143,19 @@ ifeq ($(DMA),1) endif # DMA with non-coherent client caches (requires DMA=1) -ifeq ($(DMA_NONCOHERENT),1) +ifeq ($(DMA_ALIGNED_PADDED_OUTPUT),1) ifneq ($(DMA),1) - $(error "DMA_NONCOHERENT=1 requires DMA=1 to be set") + $(error "DMA_ALIGNED_PADDED_OUTPUT=1 requires DMA=1 to be set") endif - DEF += -DWOLFHSM_CFG_DMA_NONCOHERENT + DEF += -DWOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT endif # Abort on DMA output buffers that are not aligned and padded (requires -# DMA_NONCOHERENT=1; padding is only checked with ASAN=1). The large +# DMA_ALIGNED_PADDED_OUTPUT=1; padding is only checked with ASAN=1). The large # alignment keeps a buffer missing WH_DMA_ALIGNED from being aligned by luck. ifeq ($(DMA_ALIGN_CHECK),1) - ifneq ($(DMA_NONCOHERENT),1) - $(error "DMA_ALIGN_CHECK=1 requires DMA_NONCOHERENT=1 to be set") + ifneq ($(DMA_ALIGNED_PADDED_OUTPUT),1) + $(error "DMA_ALIGN_CHECK=1 requires DMA_ALIGNED_PADDED_OUTPUT=1 to be set") endif DEF += -DWOLFHSM_CFG_TEST_DMA_ALIGN_CHECK -DWOLFHSM_CFG_DMA_ALIGN=256 endif @@ -305,8 +305,8 @@ ifeq ($(TESTWOLFCRYPT),1) # wolfCrypt cannot use DMA with non-coherent caches (WH_DEV_ID_DMA fails) ifneq ($(TESTWOLFCRYPT_DMA),) - ifeq ($(DMA_NONCOHERENT),1) - $(error "TESTWOLFCRYPT_DMA=1 cannot be used with DMA_NONCOHERENT=1") + ifeq ($(DMA_ALIGNED_PADDED_OUTPUT),1) + $(error "TESTWOLFCRYPT_DMA=1 cannot be used with DMA_ALIGNED_PADDED_OUTPUT=1") endif endif diff --git a/test/wh_test_common.h b/test/wh_test_common.h index bf1145a73..f02eb75c5 100644 --- a/test/wh_test_common.h +++ b/test/wh_test_common.h @@ -92,11 +92,12 @@ * WH_DEV_ID. The DMA-only WH_DEV_ID_DMA is exercised by running the * wolfCrypt test suite against it (TESTWOLFCRYPT=1 defaults WC_USE_DEVID to * WH_DEV_ID; TESTWOLFCRYPT_DMA=1 uses WH_DEV_ID_DMA). */ -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_DMA_NONCOHERENT) +#if defined(WOLFHSM_CFG_DMA) && \ + !defined(WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT) #define WH_TEST_DMA_MODE_CNT 2 #else -/* Without DMA, or with WOLFHSM_CFG_DMA_NONCOHERENT (wolfCrypt cannot use DMA - * there, so wh_Client_SetDmaMode(client, 1) is refused) */ +/* Without DMA, or with WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT (wolfCrypt + * cannot use DMA there, so wh_Client_SetDmaMode(client, 1) is refused) */ #define WH_TEST_DMA_MODE_CNT 1 #endif diff --git a/test/wh_test_crypto.c b/test/wh_test_crypto.c index 4972f9697..2a9099bde 100644 --- a/test/wh_test_crypto.c +++ b/test/wh_test_crypto.c @@ -450,7 +450,7 @@ static int whTest_CryptoRngDmaAsync(whClientContext* ctx) } #endif /* WOLFHSM_CFG_DMA */ -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT /* With non-coherent DMA, wolfCrypt must not reach the DMA path: operations on * WH_DEV_ID_DMA fail with WC_HW_E (no silent software fallback), objects * created with it can still be freed, and DMA-preferred mode is refused. */ @@ -549,11 +549,11 @@ static int whTest_CryptoDmaNoncoherentRefusal(whClientContext* ctx, } if (ret == 0) { - WH_TEST_PRINT("DMA NONCOHERENT REFUSAL SUCCESS\n"); + WH_TEST_PRINT("DMA ALIGNED PADDED OUTPUT REFUSAL SUCCESS\n"); } return ret; } -#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ #ifndef NO_RSA static int whTest_CryptoRsa(whClientContext* ctx, int devId, WC_RNG* rng) @@ -16144,7 +16144,7 @@ static WH_DMA_ALIGNED byte whTest_LmsSigBuf[WH_DMA_PAD_SIZE(8800)]; /* Key operations under test. wolfCrypt cannot use DMA with non-coherent * caches, so there the wh_Client_Lms*Dma APIs are driven directly instead of * going through the cryptoCb (devId is then INVALID_DEVID). */ -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT static int _whTestLms_MakeKey(whClientContext* ctx, LmsKey* key, WC_RNG* rng) { int ret; @@ -16153,8 +16153,8 @@ static int _whTestLms_MakeKey(whClientContext* ctx, LmsKey* key, WC_RNG* rng) if (ret == 0) { /* wh_Client_LmsMakeExportKeyDma only fills in the public key and * keyId, it does not mark the key usable (this predates - * WOLFHSM_CFG_DMA_NONCOHERENT). Set what wc_LmsKey_MakeKey - * sets after a cryptoCb keygen. */ + * WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT). Set what + * wc_LmsKey_MakeKey sets after a cryptoCb keygen. */ key->state = WC_LMS_STATE_OK; key->pubSet = 1; } @@ -16209,7 +16209,7 @@ static int _whTestLms_Verify(whClientContext* ctx, LmsKey* key, const byte* sig, (void)ctx; return wc_LmsKey_Verify(key, sig, sigLen, msg, msgSz); } -#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ static int whTestCrypto_LmsCryptoCb(whClientContext* ctx, int devId, WC_RNG* rng) @@ -16634,7 +16634,7 @@ static WH_DMA_ALIGNED byte whTest_XmssSigBuf[WH_DMA_PAD_SIZE(2500)]; /* Key operations under test. wolfCrypt cannot use DMA with non-coherent * caches, so there the wh_Client_Xmss*Dma APIs are driven directly instead of * going through the cryptoCb (devId is then INVALID_DEVID). */ -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT static int _whTestXmss_MakeKey(whClientContext* ctx, XmssKey* key, WC_RNG* rng) { int ret; @@ -16643,8 +16643,8 @@ static int _whTestXmss_MakeKey(whClientContext* ctx, XmssKey* key, WC_RNG* rng) if (ret == 0) { /* wh_Client_XmssMakeExportKeyDma only fills in the public key and * keyId, it does not mark the key usable (this predates - * WOLFHSM_CFG_DMA_NONCOHERENT). Set what wc_XmssKey_MakeKey - * sets after a cryptoCb keygen. */ + * WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT). Set what + * wc_XmssKey_MakeKey sets after a cryptoCb keygen. */ key->state = WC_XMSS_STATE_OK; key->pubSet = 1; } @@ -16701,7 +16701,7 @@ static int _whTestXmss_Verify(whClientContext* ctx, XmssKey* key, (void)ctx; return wc_XmssKey_Verify(key, sig, sigLen, msg, msgSz); } -#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ static int whTestCrypto_XmssCryptoCb(whClientContext* ctx, int devId, WC_RNG* rng) @@ -18589,11 +18589,11 @@ int whTest_CryptoClientConfig(whClientConfig* config) ret = whTest_CryptoRngDmaAsync(client); } #endif /* WOLFHSM_CFG_DMA */ -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT if (ret == WH_ERROR_OK) { ret = whTest_CryptoDmaNoncoherentRefusal(client, config); } -#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ /* The remaining once-run tests below historically used the non-DMA devId; * select the std (non-DMA) dispatch mode for them. Reinitialize the default @@ -19155,7 +19155,7 @@ int whTest_CryptoClientConfig(whClientConfig* config) #if defined(WOLFHSM_CFG_DMA) && \ defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) if (ret == 0) { -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT ret = whTestCrypto_LmsCryptoCb(client, INVALID_DEVID, rng); #else ret = whTestCrypto_LmsCryptoCb(client, WH_DEV_ID_DMA, rng); @@ -19166,7 +19166,7 @@ int whTest_CryptoClientConfig(whClientConfig* config) #if defined(WOLFHSM_CFG_DMA) && \ defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) if (ret == 0) { -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT ret = whTestCrypto_XmssCryptoCb(client, INVALID_DEVID, rng); #else ret = whTestCrypto_XmssCryptoCb(client, WH_DEV_ID_DMA, rng); @@ -19352,7 +19352,7 @@ static int wh_ClientServer_MemThreadTest(whTestNvmBackendType nvmType) * use-after-free class is covered by the single-thread harness. */ whClientDmaConfig clientDmaConfig = { .cb = whTestDma_BounceClientCb, -#ifndef WOLFHSM_CFG_DMA_NONCOHERENT +#ifndef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT /* Refused with non-coherent DMA (no DMA through wolfCrypt) */ .preferDma = 1, #endif diff --git a/test/wh_test_dma.c b/test/wh_test_dma.c index 4d9fa21da..9e5c9dd32 100644 --- a/test/wh_test_dma.c +++ b/test/wh_test_dma.c @@ -199,7 +199,7 @@ int whTestDma_BounceClientCb(struct whClientContext_t* client, break; case WH_DMA_OPER_CLIENT_WRITE_PRE: -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT /* Behave like a zero-copy port on a non-coherent target, which * can only accept output buffers starting on a cache line. This * catches test buffers that are not declared WH_DMA_ALIGNED. */ @@ -209,7 +209,7 @@ int whTestDma_BounceClientCb(struct whClientContext_t* client, (void*)clientAddr, (unsigned)len); return WH_ERROR_BADARGS; } -#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ /* Server is about to write client memory: give it a pool slot to * write into. */ s = _bounceAlloc(len); diff --git a/wolfhsm/wh_client.h b/wolfhsm/wh_client.h index 824f82dce..a5b8aa048 100644 --- a/wolfhsm/wh_client.h +++ b/wolfhsm/wh_client.h @@ -29,9 +29,9 @@ * the wolfCrypt init functions. Set the devId in whClientConfig.devId (0 picks * the default WH_DEV_ID) and read it back with WH_CLIENT_DEVID(c). With a * single client you can just pass the global WH_DEV_ID (or WH_DEV_ID_DMA for - * DMA only; with WOLFHSM_CFG_DMA_NONCOHERENT every WH_DEV_ID_DMA operation - * fails). With more than one client, give each its own devId. See - * WH_CLIENT_DEVID and WH_DEV_ID below. + * DMA only; with WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT every + * WH_DEV_ID_DMA operation fails). With more than one client, give each its own + * devId. See WH_CLIENT_DEVID and WH_DEV_ID below. * * In addition to the offload of cryptographic functions, the WolfHSM Client * also exposes WolfHSM Server key management, non-volatile memory, and protocol @@ -134,7 +134,7 @@ typedef struct { whClientDmaClientMemCb cb; const whDmaAddrAllowList* dmaAddrAllowList; /* allowed addresses */ /* nonzero to prefer the DMA path; must be 0 with - * WOLFHSM_CFG_DMA_NONCOHERENT */ + * WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ uint32_t preferDma; } whClientDmaConfig; @@ -523,13 +523,13 @@ int wh_Client_GetCryptoAffinity(whClientContext* c, uint32_t* out_affinity); * * Always available: without WOLFHSM_CFG_DMA it does nothing and returns * success, so you need not guard the call with #ifdef. With - * WOLFHSM_CFG_DMA_NONCOHERENT, turning DMA on is refused. + * WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT, turning DMA on is refused. * * @param[in] c Pointer to the client context. * @param[in] useDma Nonzero to use DMA where supported, zero for the normal * path. * @return int 0 on success, or WH_ERROR_BADARGS on invalid input or when - * turning DMA on with WOLFHSM_CFG_DMA_NONCOHERENT. + * turning DMA on with WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT. */ int wh_Client_SetDmaMode(whClientContext* c, int useDma); diff --git a/wolfhsm/wh_client_cryptocb.h b/wolfhsm/wh_client_cryptocb.h index 7c225c03e..6cb8b8fef 100644 --- a/wolfhsm/wh_client_cryptocb.h +++ b/wolfhsm/wh_client_cryptocb.h @@ -48,7 +48,8 @@ int wh_Client_CryptoCbStd(int devId, wc_CryptoInfo* info, void* ctx); #ifdef WOLFHSM_CFG_DMA /* DMA-only cryptoCb, registered for WH_DEV_ID_DMA. No standard-path fallback: * algorithms without a DMA variant return CRYPTOCB_UNAVAILABLE. With - * WOLFHSM_CFG_DMA_NONCOHERENT every operation fails with WC_HW_E. + * WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT every operation fails with + * WC_HW_E. */ int wh_Client_CryptoCbDma(int devId, wc_CryptoInfo* info, void* inCtx); #endif /* WOLFHSM_CFG_DMA */ diff --git a/wolfhsm/wh_settings.h b/wolfhsm/wh_settings.h index 2509dccda..83c4bc395 100644 --- a/wolfhsm/wh_settings.h +++ b/wolfhsm/wh_settings.h @@ -166,18 +166,18 @@ * AEAD request carries inside the message instead of over DMA. * Default: 128 * - * WOLFHSM_CFG_DMA_NONCOHERENT - Define when client memory the server writes - * over DMA is cached and not kept coherent by the hardware. Output buffers - * of the wh_Client_*Dma APIs must then start on a WOLFHSM_CFG_DMA_ALIGN - * boundary and be padded to a multiple of it (WH_DMA_ALIGNED, - * WH_DMA_PAD_SIZE()). wolfCrypt cannot guarantee that for the buffers it - * passes, so every operation on WH_DEV_ID_DMA fails with WC_HW_E and - * preferDma cannot be enabled. Requires WOLFHSM_CFG_DMA. + * WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT - Define when client memory + * the server writes over DMA is cached and not kept coherent by the + * hardware. Output buffers of the wh_Client_*Dma APIs must then start on a + * WOLFHSM_CFG_DMA_ALIGN boundary and be padded to a multiple of it + * (WH_DMA_ALIGNED, WH_DMA_PAD_SIZE()). wolfCrypt cannot guarantee that for + * the buffers it passes, so every operation on WH_DEV_ID_DMA fails with + * WC_HW_E and preferDma cannot be enabled. Requires WOLFHSM_CFG_DMA. * Default: Not defined * * WOLFHSM_CFG_DMA_ALIGN - Alignment and padding, in bytes, of client buffers * the server writes over DMA. A power of two and a multiple of XCACHELINE. - * Only used with WOLFHSM_CFG_DMA_NONCOHERENT. + * Only used with WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT. * Default: XCACHELINE * * WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK - Test builds only. Abort when a client @@ -185,7 +185,7 @@ * WOLFHSM_CFG_DMA_ALIGN boundary or, in ASAN builds, is not padded to a * multiple of it. Checked in wh_Client_DmaProcessClientAddress, so it covers * wolfHSM's own buffers and those passed to the wh_Client_*Dma APIs. - * Requires WOLFHSM_CFG_DMA_NONCOHERENT. + * Requires WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT. * Default: Not defined * * WOLFHSM_CFG_CERT_MAX_VERIFY_ROOTS - Maximum number of trusted root NVM IDs @@ -759,13 +759,15 @@ /* DMA Configuration */ -#if defined(WOLFHSM_CFG_DMA_NONCOHERENT) && !defined(WOLFHSM_CFG_DMA) -#error "WOLFHSM_CFG_DMA_NONCOHERENT requires WOLFHSM_CFG_DMA" +#if defined(WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT) && \ + !defined(WOLFHSM_CFG_DMA) +#error "WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT requires WOLFHSM_CFG_DMA" #endif #if defined(WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK) && \ - !defined(WOLFHSM_CFG_DMA_NONCOHERENT) -#error "WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK requires WOLFHSM_CFG_DMA_NONCOHERENT" + !defined(WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT) +#error \ + "WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK requires WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT" #endif #ifdef WOLFHSM_CFG_DMA @@ -831,7 +833,7 @@ /* Alignment and padding of client buffers the server writes into over DMA. * Only needed with non-coherent DMA, no-ops otherwise. */ -#ifdef WOLFHSM_CFG_DMA_NONCOHERENT +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT #ifndef WOLFHSM_CFG_DMA_ALIGN #define WOLFHSM_CFG_DMA_ALIGN XCACHELINE @@ -878,6 +880,6 @@ #define WH_DMA_ALIGNED #endif -#endif /* WOLFHSM_CFG_DMA_NONCOHERENT */ +#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ #endif /* !WOLFHSM_WH_SETTINGS_H_ */ diff --git a/wolfhsm/wh_utils.h b/wolfhsm/wh_utils.h index f8b78d270..cf5388057 100644 --- a/wolfhsm/wh_utils.h +++ b/wolfhsm/wh_utils.h @@ -105,7 +105,7 @@ void* wh_Utils_memcpy_flush(void* dst, const void* src , size_t n); #if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_NO_CRYPTO) /** DMA buffer helpers */ /* XMALLOC/XFREE replacements for heap buffers the server writes over DMA. - * With WOLFHSM_CFG_DMA_NONCOHERENT the buffer starts on a + * With WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT the buffer starts on a * WOLFHSM_CFG_DMA_ALIGN boundary and is padded to a multiple of it; otherwise * these are plain XMALLOC/XFREE. Returns NULL when the allocation fails. */ void* wh_Utils_DmaAlloc(size_t len, void* heap); From 0bba6e305065c5fee23c54f1783a79930c5ed6c2 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Mon, 26 Oct 2026 18:06:53 +0100 Subject: [PATCH 4/4] wolfHSM: address reviewer's comments on DMA_REQUIRE_ALIGNED_PADDED --- benchmark/bench_modules/wh_bench_mod_aes.c | 11 ++- docs/src/5-Features.md | 4 +- docs/src/9-Configuration.md | 2 +- port/posix/posix_transport_shm.c | 67 ++++++++++++++++-- port/posix/posix_transport_shm.h | 10 +++ src/wh_client.c | 4 +- src/wh_utils.c | 56 --------------- test-refactor/misc/wh_test_dma_noncoherent.c | 67 +----------------- test-refactor/posix/wh_test_posix_main.c | 9 ++- test-refactor/posix/wh_test_posix_shm_dma.c | 73 +++++++++++++++++++- test/wh_test_crypto.c | 8 +-- wolfhsm/wh_client.h | 5 +- wolfhsm/wh_settings.h | 14 ++-- wolfhsm/wh_utils.h | 13 ---- 14 files changed, 177 insertions(+), 166 deletions(-) diff --git a/benchmark/bench_modules/wh_bench_mod_aes.c b/benchmark/bench_modules/wh_bench_mod_aes.c index 3f097058b..c338e1cb1 100644 --- a/benchmark/bench_modules/wh_bench_mod_aes.c +++ b/benchmark/bench_modules/wh_bench_mod_aes.c @@ -25,7 +25,6 @@ #include "wolfssl/wolfcrypt/aes.h" #if defined(WOLFHSM_CFG_DMA) && defined(WOLFHSM_CFG_TEST_POSIX) -#include "wolfhsm/wh_utils.h" #include "port/posix/posix_transport_shm.h" #endif /* WOLFHSM_CFG_DMA && WOLFHSM_CFG_TEST_POSIX */ @@ -1093,16 +1092,16 @@ static int _benchAesGcmDma(whClientContext* client, whBenchOpContext* ctx, if (ctx->transportType == WH_BENCH_TRANSPORT_POSIX_DMA) { void* heap = posixTransportShm_GetDmaHeap(client->comm->transport_context); - in = wh_Utils_DmaAlloc(inLen, heap); + in = posixTransportShm_DmaAlloc(inLen, heap); if (in == NULL) { WH_BENCH_PRINTF("Failed to allocate memory for DMA input\n"); return WH_ERROR_NOSPACE; } - out = wh_Utils_DmaAlloc(inLen, heap); + out = posixTransportShm_DmaAlloc(inLen, heap); if (out == NULL) { WH_BENCH_PRINTF("Failed to allocate memory for DMA output\n"); - wh_Utils_DmaFree((uint8_t*)in, heap); + posixTransportShm_DmaFree((uint8_t*)in, heap); return WH_ERROR_NOSPACE; } } @@ -1216,8 +1215,8 @@ static int _benchAesGcmDma(whClientContext* client, whBenchOpContext* ctx, /* free the buffers allocated from the DMA heap */ void* heap = posixTransportShm_GetDmaHeap(client->comm->transport_context); - wh_Utils_DmaFree((uint8_t*)in, heap); - wh_Utils_DmaFree(out, heap); + posixTransportShm_DmaFree((uint8_t*)in, heap); + posixTransportShm_DmaFree(out, heap); } #endif /* WOLFHSM_CFG_TEST_POSIX */ diff --git a/docs/src/5-Features.md b/docs/src/5-Features.md index 884e45b49..1fcefc81e 100644 --- a/docs/src/5-Features.md +++ b/docs/src/5-Features.md @@ -701,11 +701,11 @@ WH_DMA_ALIGNED uint8_t cipher[WH_DMA_PAD_SIZE(sizeof(plain))]; ret = wh_Client_AesCtrDma(client, aes, 1, plain, sizeof(plain), cipher); ``` -`WH_DMA_ALIGNED` and `WH_DMA_PAD_SIZE()` are no-ops without `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT`. wolfHSM's own internal output buffers follow the rule. For caller buffers, the port's callback can check the start with `WH_DMA_IS_ALIGNED()` (as `posixTransportShm_ClientStaticMemDmaCallback` does for buffers it uses in place) or copy through a bounce buffer from `wh_Utils_DmaAlloc()`; padding cannot be checked. +`WH_DMA_ALIGNED` and `WH_DMA_PAD_SIZE()` are no-ops without `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT`. wolfHSM's own internal output buffers follow the rule. For caller buffers, the port's callback can check the start with `WH_DMA_IS_ALIGNED()` (as `posixTransportShm_ClientStaticMemDmaCallback` does for buffers it uses in place) or copy through an aligned, padded bounce buffer (as that callback does with `posixTransportShm_DmaAlloc()` for buffers outside the DMA area); padding cannot be checked. Test builds can define `WOLFHSM_CFG_TEST_DMA_ALIGN_CHECK` (`make DMA_ALIGN_CHECK=1` in `test/` and `test-refactor/posix/`) to abort on any output buffer that does not start on a `WOLFHSM_CFG_DMA_ALIGN` boundary or, in ASAN builds, is not padded to a multiple of it. The check runs in `wh_Client_DmaProcessClientAddress`, so it covers wolfHSM's own buffers and every buffer the tests pass, whatever DMA callback the client registers. The make option also raises `WOLFHSM_CFG_DMA_ALIGN` to 256, so a buffer missing `WH_DMA_ALIGNED` does not pass by being aligned by chance. -wolfCrypt passes the crypto callback buffers it does not control, such as its own stack and structure buffers, so with `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT` wolfHSM refuses DMA through wolfCrypt: every operation on `WH_DEV_ID_DMA` fails with `WC_HW_E`, and `whClientDmaConfig::preferDma` and `wh_Client_SetDmaMode(client, 1)` fail with `WH_ERROR_BADARGS`. Use `WH_DEV_ID` (or the client's configured devId) for wolfCrypt, and call the `wh_Client_*Dma` APIs directly where zero-copy matters. LMS and XMSS have no non-DMA path, so with this option they are available only through the `wh_Client_Lms*Dma` and `wh_Client_Xmss*Dma` APIs. +wolfCrypt passes the crypto callback buffers it does not control, such as its own stack and structure buffers, so with `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT` wolfHSM refuses DMA through wolfCrypt: every operation on `WH_DEV_ID_DMA` fails with `WC_HW_E`, and `whClientDmaConfig::preferDma` and `wh_Client_SetDmaMode(client, 1)` fail with `WH_ERROR_NOTIMPL`. Use `WH_DEV_ID` (or the client's configured devId) for wolfCrypt, and call the `wh_Client_*Dma` APIs directly where zero-copy matters. LMS and XMSS have no non-DMA path, so with this option they are available only through the `wh_Client_Lms*Dma` and `wh_Client_Xmss*Dma` APIs. ### 32-bit vs. 64-bit Address Handling diff --git a/docs/src/9-Configuration.md b/docs/src/9-Configuration.md index 591913825..91ed0b00b 100644 --- a/docs/src/9-Configuration.md +++ b/docs/src/9-Configuration.md @@ -141,7 +141,7 @@ These macros gate and tune DMA-mode crypto and large-buffer operations. | `WOLFHSM_CFG_DMA_PTR_SIZE` | Compiler-detected (`__SIZEOF_POINTER__`) | Override the assumed DMA pointer size, in bytes (must be `4` or `8`). Auto-detection works for GCC/Clang and IAR; define this explicitly for any toolchain that does not provide `__SIZEOF_POINTER__`. | | `WOLFHSM_CFG_DMA_ALT_PTR_SIZE` | Undefined | If defined, allows the DMA pointer size to differ from the native CPU pointer size (e.g. a 32-bit-pointer server reachable from a 64-bit-pointer client). When undefined, wh_settings.h refuses to build with a mismatched `WOLFHSM_CFG_DMA_PTR_SIZE`. | | `WOLFHSM_CFG_DMA_INLINE_AAD_MAX_SIZE` | `128` | Largest additional authenticated data, in bytes, that a DMA AEAD request can carry inside the message (through the transport) instead of over DMA. An AAD above this size is passed as a DMA buffer. | -| `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT` | Undefined | Define when client memory the server writes over DMA is cached and not kept coherent by the hardware. Output buffers of the `wh_Client_*Dma` APIs must then be aligned and padded to `WOLFHSM_CFG_DMA_ALIGN`, and DMA through wolfCrypt is refused (`WH_DEV_ID_DMA` fails with `WC_HW_E`, `preferDma` cannot be enabled). Requires `WOLFHSM_CFG_DMA`. Set by `DMA_ALIGNED_PADDED_OUTPUT=1` in the test and benchmark builds. See [Non-Coherent Caches and Buffer Alignment](5-Features.md#non-coherent-caches-and-buffer-alignment). | +| `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT` | Undefined | Client buffers the server writes over DMA, including output buffers of the `wh_Client_*Dma` APIs, must be aligned and padded to `WOLFHSM_CFG_DMA_ALIGN`. Define it when that client memory is cached and the hardware does not keep it coherent with DMA. DMA through wolfCrypt is refused (`WH_DEV_ID_DMA` fails with `WC_HW_E`, `preferDma` cannot be enabled). Requires `WOLFHSM_CFG_DMA`. Set by `DMA_ALIGNED_PADDED_OUTPUT=1` in the test and benchmark builds. See [Non-Coherent Caches and Buffer Alignment](5-Features.md#non-coherent-caches-and-buffer-alignment). | | `WOLFHSM_CFG_DMA_ALIGN` | `XCACHELINE` | Alignment and padding, in bytes, of client buffers the server writes over DMA. A power of two and a multiple of `XCACHELINE`. Only used with `WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT`. | | `WOLFHSM_CFG_DMA_CUSTOM_CLIENT_COPY` | Undefined | If defined, expose hooks that let the integrator override the client-to-server and server-to-client memory copy used during DMA requests. Useful when DMA buffers live in shared memory that requires custom invalidation or cache maintenance beyond the standard `XCACHE*` macros. | diff --git a/port/posix/posix_transport_shm.c b/port/posix/posix_transport_shm.c index afaab74a6..0bc3707ce 100644 --- a/port/posix/posix_transport_shm.c +++ b/port/posix/posix_transport_shm.c @@ -604,12 +604,65 @@ int posixTransportShm_RecvResponse(void* c, uint16_t* out_len, void* data) * the POSIX shared memory transport. */ +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT +/* The allocator only guarantees its own alignment, so over-allocate and keep + * the raw pointer just before the aligned start */ +void* posixTransportShm_DmaAlloc(size_t len, void* heap) +{ + uintptr_t raw; + uintptr_t aligned; + + (void)heap; + /* Fail like XMALLOC, rather than wrap to a short buffer, when the size + * below does not fit in a size_t: padding and over-allocation each add up + * to WOLFHSM_CFG_DMA_ALIGN - 1 bytes, plus the stored pointer */ + if (len > SIZE_MAX - sizeof(uintptr_t) - + 2 * ((size_t)WOLFHSM_CFG_DMA_ALIGN - 1)) { + return NULL; + } + raw = (uintptr_t)XMALLOC(sizeof(uintptr_t) + (WOLFHSM_CFG_DMA_ALIGN - 1) + + WH_DMA_PAD_SIZE(len), + heap, DYNAMIC_TYPE_TMP_BUFFER); + if (raw == 0) { + return NULL; + } + aligned = (raw + sizeof(uintptr_t) + (WOLFHSM_CFG_DMA_ALIGN - 1)) & + ~((uintptr_t)WOLFHSM_CFG_DMA_ALIGN - 1); + memcpy((void*)(aligned - sizeof(uintptr_t)), &raw, sizeof(raw)); + return (void*)aligned; +} + +void posixTransportShm_DmaFree(void* ptr, void* heap) +{ + uintptr_t raw; + + if (ptr == NULL) { + return; + } + (void)heap; + memcpy(&raw, (uint8_t*)ptr - sizeof(uintptr_t), sizeof(raw)); + XFREE((void*)raw, heap, DYNAMIC_TYPE_TMP_BUFFER); +} +#else +void* posixTransportShm_DmaAlloc(size_t len, void* heap) +{ + (void)heap; + return XMALLOC(len, heap, DYNAMIC_TYPE_TMP_BUFFER); +} + +void posixTransportShm_DmaFree(void* ptr, void* heap) +{ + (void)heap; + XFREE(ptr, heap, DYNAMIC_TYPE_TMP_BUFFER); +} +#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ + /* Client buffers outside the DMA area are copied through a bounce buffer: - * from wh_Utils_DmaAlloc for output, which the server writes, and from XMALLOC - * for input, which needs no cache-line isolation. Buffers in the DMA area are - * used in place; with WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT an in-place - * output buffer must be aligned to WOLFHSM_CFG_DMA_ALIGN (its padding cannot be - * checked). POSIX needs no cache maintenance. */ + * from posixTransportShm_DmaAlloc for output, which the server writes, and from + * XMALLOC for input, which needs no cache-line isolation. Buffers in the DMA + * area are used in place; with WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT an + * in-place output buffer must be aligned to WOLFHSM_CFG_DMA_ALIGN (its padding + * cannot be checked). POSIX needs no cache maintenance. */ int posixTransportShm_ClientStaticMemDmaCallback( struct whClientContext_t* client, uintptr_t clientAddr, @@ -654,7 +707,7 @@ int posixTransportShm_ClientStaticMemDmaCallback( if (isInDma == 0) { dmaBuffer = (oper == WH_DMA_OPER_CLIENT_WRITE_PRE) - ? (uintptr_t)wh_Utils_DmaAlloc(len, heap) + ? (uintptr_t)posixTransportShm_DmaAlloc(len, heap) : (uintptr_t)XMALLOC(len, heap, DYNAMIC_TYPE_TMP_BUFFER); if (dmaBuffer == 0) { return WH_ERROR_NOSPACE; @@ -685,7 +738,7 @@ int posixTransportShm_ClientStaticMemDmaCallback( uint8_t* ptr = (uint8_t*)dmaPtr + (uintptr_t)*xformedCliAddr; memcpy((void*)clientAddr, ptr, len); /* copy results of what server wrote */ - wh_Utils_DmaFree(ptr, heap); + posixTransportShm_DmaFree(ptr, heap); } } diff --git a/port/posix/posix_transport_shm.h b/port/posix/posix_transport_shm.h index f2767740d..8611eb65b 100644 --- a/port/posix/posix_transport_shm.h +++ b/port/posix/posix_transport_shm.h @@ -205,6 +205,16 @@ int posixTransportShm_ServerStaticMemDmaCallback( size_t len, whServerDmaOper oper, whServerDmaFlags flags); #include "wolfhsm/wh_client.h" +/* XMALLOC/XFREE replacements for buffers the server writes over DMA, from the + * DMA heap (posixTransportShm_GetDmaHeap). With + * WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT the buffer starts on a + * WOLFHSM_CFG_DMA_ALIGN boundary and is padded to a multiple of it; otherwise + * these are plain XMALLOC/XFREE. Returns NULL when the allocation fails. */ +void* posixTransportShm_DmaAlloc(size_t len, void* heap); + +/* Free a buffer from posixTransportShm_DmaAlloc. NULL is ignored */ +void posixTransportShm_DmaFree(void* ptr, void* heap); + int posixTransportShm_ClientStaticMemDmaCallback(whClientContext* client, uintptr_t clientAddr, void** xformedCliAddr, diff --git a/src/wh_client.c b/src/wh_client.c index 205bc9adf..b859e40d8 100644 --- a/src/wh_client.c +++ b/src/wh_client.c @@ -95,7 +95,7 @@ int wh_Client_Init(whClientContext* c, const whClientConfig* config) /* wolfCrypt cannot use DMA with non-coherent caches, see * wh_Client_CryptoCbDma */ if ((config->dmaConfig != NULL) && (config->dmaConfig->preferDma != 0)) { - return WH_ERROR_BADARGS; + return WH_ERROR_NOTIMPL; } #endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ #endif /* WOLFHSM_CFG_DMA */ @@ -547,7 +547,7 @@ int wh_Client_SetDmaMode(whClientContext* c, int useDma) /* wolfCrypt cannot use DMA with non-coherent caches, see * wh_Client_CryptoCbDma */ if (useDma) { - return WH_ERROR_BADARGS; + return WH_ERROR_NOTIMPL; } #endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ c->dma.preferDma = (uint32_t)(useDma ? 1 : 0); diff --git a/src/wh_utils.c b/src/wh_utils.c index 1393ef5d8..9917c6afb 100644 --- a/src/wh_utils.c +++ b/src/wh_utils.c @@ -225,62 +225,6 @@ void* wh_Utils_memcpy_flush(void* dst, const void* src , size_t n) return XCACHEFLUSHBLK(dst, n); } -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_NO_CRYPTO) -/** DMA buffer helpers */ -#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT -/* The allocator only guarantees its own alignment, so over-allocate and keep - * the raw pointer just before the aligned start */ -void* wh_Utils_DmaAlloc(size_t len, void* heap) -{ - uintptr_t raw; - uintptr_t aligned; - - (void)heap; - /* Fail like XMALLOC, rather than wrap to a short buffer, when the size - * below does not fit in a size_t: padding and over-allocation each add up - * to WOLFHSM_CFG_DMA_ALIGN - 1 bytes, plus the stored pointer */ - if (len > SIZE_MAX - sizeof(uintptr_t) - - 2 * ((size_t)WOLFHSM_CFG_DMA_ALIGN - 1)) { - return NULL; - } - raw = (uintptr_t)XMALLOC(sizeof(uintptr_t) + (WOLFHSM_CFG_DMA_ALIGN - 1) + - WH_DMA_PAD_SIZE(len), - heap, DYNAMIC_TYPE_TMP_BUFFER); - if (raw == 0) { - return NULL; - } - aligned = (raw + sizeof(uintptr_t) + (WOLFHSM_CFG_DMA_ALIGN - 1)) & - ~((uintptr_t)WOLFHSM_CFG_DMA_ALIGN - 1); - memcpy((void*)(aligned - sizeof(uintptr_t)), &raw, sizeof(raw)); - return (void*)aligned; -} - -void wh_Utils_DmaFree(void* ptr, void* heap) -{ - uintptr_t raw; - - if (ptr == NULL) { - return; - } - (void)heap; - memcpy(&raw, (uint8_t*)ptr - sizeof(uintptr_t), sizeof(raw)); - XFREE((void*)raw, heap, DYNAMIC_TYPE_TMP_BUFFER); -} -#else -void* wh_Utils_DmaAlloc(size_t len, void* heap) -{ - (void)heap; - return XMALLOC(len, heap, DYNAMIC_TYPE_TMP_BUFFER); -} - -void wh_Utils_DmaFree(void* ptr, void* heap) -{ - (void)heap; - XFREE(ptr, heap, DYNAMIC_TYPE_TMP_BUFFER); -} -#endif /* WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT */ -#endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_NO_CRYPTO */ - #if defined(WOLFHSM_CFG_HEXDUMP) void wh_Utils_Hexdump(const char* initial, const uint8_t* ptr, size_t size) { diff --git a/test-refactor/misc/wh_test_dma_noncoherent.c b/test-refactor/misc/wh_test_dma_noncoherent.c index bd86b1386..988efb7f9 100644 --- a/test-refactor/misc/wh_test_dma_noncoherent.c +++ b/test-refactor/misc/wh_test_dma_noncoherent.c @@ -26,7 +26,6 @@ * WH_DEV_ID_DMA (AES-CBC and SHA-256 here) must fail with WC_HW_E instead of * falling back to software. * None of this reaches the server, so the test runs a client with no server. - * Also checks the aligned, padded buffers from wh_Utils_DmaAlloc. */ #include "wolfhsm/wh_settings.h" @@ -48,69 +47,12 @@ #include "wolfhsm/wh_comm.h" #include "wolfhsm/wh_transport_mem.h" #include "wolfhsm/wh_client.h" -#include "wolfhsm/wh_utils.h" #include "wh_test_common.h" #include "wh_test_list.h" #define BUFFER_SIZE 4096 -/* wh_Utils_DmaAlloc must return a buffer aligned to WOLFHSM_CFG_DMA_ALIGN with - * WH_DMA_PAD_SIZE(len) usable bytes, and wh_Utils_DmaFree must free it through - * the raw pointer stored before it. Writing every padded byte and freeing lets - * ASAN catch a short buffer or a wrong offset. */ -static int _whTest_DmaNonCoherentAlloc(void) -{ - static const size_t lens[] = { - 0, - 1, - WOLFHSM_CFG_DMA_ALIGN - 1, - WOLFHSM_CFG_DMA_ALIGN, - WOLFHSM_CFG_DMA_ALIGN + 1, - 3 * WOLFHSM_CFG_DMA_ALIGN, - 10 * WOLFHSM_CFG_DMA_ALIGN + 3, - }; - /* Allocation sizes that would wrap without the overflow check: - * WH_DMA_PAD_SIZE(SIZE_MAX) wraps to 0, and SIZE_MAX - - * WOLFHSM_CFG_DMA_ALIGN + 1 pads without wrapping but the over-allocation - * then does */ - static const size_t hugeLens[] = { - SIZE_MAX, - SIZE_MAX - WOLFHSM_CFG_DMA_ALIGN + 1, - }; - uint8_t* buf; - size_t i; - - for (i = 0; i < sizeof(lens) / sizeof(lens[0]); i++) { - buf = (uint8_t*)wh_Utils_DmaAlloc(lens[i], NULL); - WH_TEST_ASSERT_RETURN(buf != NULL); - if (!WH_DMA_IS_ALIGNED(buf)) { - WH_ERROR_PRINT("wh_Utils_DmaAlloc(%u) returned unaligned %p\n", - (unsigned)lens[i], (void*)buf); - wh_Utils_DmaFree(buf, NULL); - return WH_TEST_FAIL; - } - memset(buf, 0xA5, WH_DMA_PAD_SIZE(lens[i])); - wh_Utils_DmaFree(buf, NULL); - } - - for (i = 0; i < sizeof(hugeLens) / sizeof(hugeLens[0]); i++) { - buf = (uint8_t*)wh_Utils_DmaAlloc(hugeLens[i], NULL); - if (buf != NULL) { - WH_ERROR_PRINT("wh_Utils_DmaAlloc(SIZE_MAX - %u) did not fail\n", - (unsigned)(SIZE_MAX - hugeLens[i])); - wh_Utils_DmaFree(buf, NULL); - return WH_TEST_FAIL; - } - } - - /* NULL is ignored */ - wh_Utils_DmaFree(NULL, NULL); - - WH_TEST_PRINT("DMA non-coherent wh_Utils_DmaAlloc SUCCESS\n"); - return WH_ERROR_OK; -} - static int _whTest_DmaNonCoherentRefusals(void) { static uint8_t req[BUFFER_SIZE]; @@ -141,14 +83,14 @@ static int _whTest_DmaNonCoherentRefusals(void) /* preferDma in the config is refused before any initialization */ dmaCfg[0].preferDma = 1; - WH_TEST_ASSERT_RETURN(WH_ERROR_BADARGS == wh_Client_Init(client, c_conf)); + WH_TEST_ASSERT_RETURN(WH_ERROR_NOTIMPL == wh_Client_Init(client, c_conf)); dmaCfg[0].preferDma = 0; WH_TEST_RETURN_ON_FAIL(wh_Client_Init(client, c_conf)); /* Turning DMA mode on is refused and leaves it off; turning it off is * still accepted */ - if (wh_Client_SetDmaMode(client, 1) != WH_ERROR_BADARGS) { + if (wh_Client_SetDmaMode(client, 1) != WH_ERROR_NOTIMPL) { WH_ERROR_PRINT("wh_Client_SetDmaMode(1) was not refused\n"); ret = -1; } @@ -234,10 +176,7 @@ int whTest_DmaNonCoherent(void* ctx) { (void)ctx; - WH_TEST_RETURN_ON_FAIL(_whTest_DmaNonCoherentAlloc()); - WH_TEST_RETURN_ON_FAIL(_whTest_DmaNonCoherentRefusals()); - - return WH_ERROR_OK; + return _whTest_DmaNonCoherentRefusals(); } #endif /* DMA && DMA_ALIGNED_PADDED_OUTPUT && ENABLE_CLIENT && !NO_CRYPTO */ diff --git a/test-refactor/posix/wh_test_posix_main.c b/test-refactor/posix/wh_test_posix_main.c index 8b1284b89..44b0f5d43 100644 --- a/test-refactor/posix/wh_test_posix_main.c +++ b/test-refactor/posix/wh_test_posix_main.c @@ -92,8 +92,10 @@ int whTest_LogPosixFile(void* ctx); int whTest_LogPosixFileConcurrent(void* ctx); int whTest_LogClientServerMemTransport(void* ctx); -/* POSIX shared memory DMA callback: client buffers used in place */ +/* POSIX shared memory DMA callback: client buffers used in place, and the + * aligned bounce buffer allocator */ int whTest_PosixShmDmaInPlace(void* ctx); +int whTest_PosixShmDmaAlloc(void* ctx); /* * Port-owned contexts. The thread functions fill these in and @@ -350,6 +352,11 @@ int main(void) if (rc != 0 && rc != WH_TEST_SKIPPED && miscRc == 0) { miscRc = rc; } + rc = whTestGroup_RunOne("whTest_PosixShmDmaAlloc", + whTest_PosixShmDmaAlloc, NULL); + if (rc != 0 && rc != WH_TEST_SKIPPED && miscRc == 0) { + miscRc = rc; + } /* Concurrent keygen and cached-key read tests. Both are * self-contained (own shared NVM + client/server pairs), so they run * in this pre-server slot rather than against the live diff --git a/test-refactor/posix/wh_test_posix_shm_dma.c b/test-refactor/posix/wh_test_posix_shm_dma.c index e9c566cef..1ae362187 100644 --- a/test-refactor/posix/wh_test_posix_shm_dma.c +++ b/test-refactor/posix/wh_test_posix_shm_dma.c @@ -19,7 +19,8 @@ /* * test-refactor/posix/wh_test_posix_shm_dma.c * - * In-place buffers in the POSIX shared memory client DMA callback. A client + * In-place buffers in the POSIX shared memory client DMA callback, and the + * bounce buffers it allocates with posixTransportShm_DmaAlloc. A client * buffer already inside the DMA area is passed to the server as its offset, * without a bounce copy; with WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT a * buffer the server writes must also be aligned. The object is mapped twice, as @@ -41,6 +42,12 @@ int whTest_PosixShmDmaInPlace(void* ctx) return WH_TEST_SKIPPED; } +int whTest_PosixShmDmaAlloc(void* ctx) +{ + (void)ctx; + return WH_TEST_SKIPPED; +} + #else #include @@ -151,4 +158,68 @@ int whTest_PosixShmDmaInPlace(void* ctx) return ret; } +/* posixTransportShm_DmaAlloc must return a buffer aligned to SHMDMA_ALIGN with + * WH_DMA_PAD_SIZE(len) usable bytes, and posixTransportShm_DmaFree must free it + * through the raw pointer stored before it. Writing every padded byte and + * freeing lets ASAN catch a short buffer or a wrong offset. */ +int whTest_PosixShmDmaAlloc(void* ctx) +{ + static const size_t lens[] = { + 0, + 1, + SHMDMA_ALIGN - 1, + SHMDMA_ALIGN, + SHMDMA_ALIGN + 1, + 3 * SHMDMA_ALIGN, + 10 * SHMDMA_ALIGN + 3, + }; +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT + /* Allocation sizes that would wrap without the overflow check: + * WH_DMA_PAD_SIZE(SIZE_MAX) wraps to 0, and SIZE_MAX - + * WOLFHSM_CFG_DMA_ALIGN + 1 pads without wrapping but the over-allocation + * then does */ + static const size_t hugeLens[] = { + SIZE_MAX, + SIZE_MAX - WOLFHSM_CFG_DMA_ALIGN + 1, + }; +#endif + uint8_t* buf; + size_t i; + + (void)ctx; + for (i = 0; i < sizeof(lens) / sizeof(lens[0]); i++) { + buf = (uint8_t*)posixTransportShm_DmaAlloc(lens[i], NULL); + WH_TEST_ASSERT_RETURN(buf != NULL || lens[i] == 0); + if (!WH_DMA_IS_ALIGNED(buf)) { + WH_ERROR_PRINT("posixTransportShm_DmaAlloc(%u) returned unaligned " + "%p\n", + (unsigned)lens[i], (void*)buf); + posixTransportShm_DmaFree(buf, NULL); + return WH_TEST_FAIL; + } + if (buf != NULL) { + memset(buf, 0xA5, WH_DMA_PAD_SIZE(lens[i])); + } + posixTransportShm_DmaFree(buf, NULL); + } + +#ifdef WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT + for (i = 0; i < sizeof(hugeLens) / sizeof(hugeLens[0]); i++) { + buf = (uint8_t*)posixTransportShm_DmaAlloc(hugeLens[i], NULL); + if (buf != NULL) { + WH_ERROR_PRINT("posixTransportShm_DmaAlloc(SIZE_MAX - %u) did not " + "fail\n", + (unsigned)(SIZE_MAX - hugeLens[i])); + posixTransportShm_DmaFree(buf, NULL); + return WH_TEST_FAIL; + } + } +#endif + + /* NULL is ignored */ + posixTransportShm_DmaFree(NULL, NULL); + + return 0; +} + #endif diff --git a/test/wh_test_crypto.c b/test/wh_test_crypto.c index 2a9099bde..9e795f151 100644 --- a/test/wh_test_crypto.c +++ b/test/wh_test_crypto.c @@ -511,10 +511,10 @@ static int whTest_CryptoDmaNoncoherentRefusal(whClientContext* ctx, /* DMA-preferred mode is refused and the mode stays standard */ if (ret == 0) { rc = wh_Client_SetDmaMode(ctx, 1); - if ((rc != WH_ERROR_BADARGS) || + if ((rc != WH_ERROR_NOTIMPL) || (wh_Client_GetDmaMode(ctx, &mode) != WH_ERROR_OK) || (mode != 0)) { WH_ERROR_PRINT("SetDmaMode(1) returned %d (mode %d), expected " - "WH_ERROR_BADARGS (mode 0)\n", + "WH_ERROR_NOTIMPL (mode 0)\n", rc, mode); ret = WH_ERROR_ABORTED; } @@ -537,9 +537,9 @@ static int whTest_CryptoDmaNoncoherentRefusal(whClientContext* ctx, otherCfg.dmaConfig = &dmaCfg; rc = wh_Client_Init(other, &otherCfg); - if (rc != WH_ERROR_BADARGS) { + if (rc != WH_ERROR_NOTIMPL) { WH_ERROR_PRINT("wh_Client_Init with preferDma returned %d, " - "expected WH_ERROR_BADARGS\n", + "expected WH_ERROR_NOTIMPL\n", rc); if (rc == WH_ERROR_OK) { (void)wh_Client_Cleanup(other); diff --git a/wolfhsm/wh_client.h b/wolfhsm/wh_client.h index a5b8aa048..69a507451 100644 --- a/wolfhsm/wh_client.h +++ b/wolfhsm/wh_client.h @@ -528,8 +528,9 @@ int wh_Client_GetCryptoAffinity(whClientContext* c, uint32_t* out_affinity); * @param[in] c Pointer to the client context. * @param[in] useDma Nonzero to use DMA where supported, zero for the normal * path. - * @return int 0 on success, or WH_ERROR_BADARGS on invalid input or when - * turning DMA on with WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT. + * @return int 0 on success, WH_ERROR_BADARGS on invalid input, or + * WH_ERROR_NOTIMPL when turning DMA on with + * WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT. */ int wh_Client_SetDmaMode(whClientContext* c, int useDma); diff --git a/wolfhsm/wh_settings.h b/wolfhsm/wh_settings.h index 83c4bc395..0bd8f111a 100644 --- a/wolfhsm/wh_settings.h +++ b/wolfhsm/wh_settings.h @@ -166,13 +166,13 @@ * AEAD request carries inside the message instead of over DMA. * Default: 128 * - * WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT - Define when client memory - * the server writes over DMA is cached and not kept coherent by the - * hardware. Output buffers of the wh_Client_*Dma APIs must then start on a - * WOLFHSM_CFG_DMA_ALIGN boundary and be padded to a multiple of it - * (WH_DMA_ALIGNED, WH_DMA_PAD_SIZE()). wolfCrypt cannot guarantee that for - * the buffers it passes, so every operation on WH_DEV_ID_DMA fails with - * WC_HW_E and preferDma cannot be enabled. Requires WOLFHSM_CFG_DMA. + * WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT - Client buffers the server + * writes over DMA must start on a WOLFHSM_CFG_DMA_ALIGN boundary and be + * padded to a multiple of it (WH_DMA_ALIGNED, WH_DMA_PAD_SIZE()). Define it + * when that client memory is cached and the hardware does not keep it + * coherent with DMA. wolfCrypt cannot guarantee the rule for the buffers it + * passes, so every operation on WH_DEV_ID_DMA fails with WC_HW_E and + * preferDma cannot be enabled. Requires WOLFHSM_CFG_DMA. * Default: Not defined * * WOLFHSM_CFG_DMA_ALIGN - Alignment and padding, in bytes, of client buffers diff --git a/wolfhsm/wh_utils.h b/wolfhsm/wh_utils.h index cf5388057..a3a9d6749 100644 --- a/wolfhsm/wh_utils.h +++ b/wolfhsm/wh_utils.h @@ -102,19 +102,6 @@ void* wh_Utils_memcpy_invalidate(void* dst, const void* src, size_t n); /* Perform memcpy followed by a cache flush of dst */ void* wh_Utils_memcpy_flush(void* dst, const void* src , size_t n); -#if defined(WOLFHSM_CFG_DMA) && !defined(WOLFHSM_CFG_NO_CRYPTO) -/** DMA buffer helpers */ -/* XMALLOC/XFREE replacements for heap buffers the server writes over DMA. - * With WOLFHSM_CFG_DMA_REQUIRE_ALIGNED_PADDED_OUTPUT the buffer starts on a - * WOLFHSM_CFG_DMA_ALIGN boundary and is padded to a multiple of it; otherwise - * these are plain XMALLOC/XFREE. Returns NULL when the allocation fails. */ -void* wh_Utils_DmaAlloc(size_t len, void* heap); - -/* Free a buffer from wh_Utils_DmaAlloc. NULL is ignored */ -void wh_Utils_DmaFree(void* ptr, void* heap); -#endif /* WOLFHSM_CFG_DMA && !WOLFHSM_CFG_NO_CRYPTO */ - - #if defined(WOLFHSM_CFG_HEXDUMP) void wh_Utils_Hexdump(const char* initial, const uint8_t* ptr, size_t size); #endif