From d09bfc021d56584d720d92df45d90cefb69f6ba9 Mon Sep 17 00:00:00 2001 From: karaketir16 Date: Mon, 6 Apr 2026 19:43:47 +0100 Subject: [PATCH] rp23xx: add hardware SHA-256 cryptodev support Add an RP23xx hardware crypto driver for /dev/crypto with SHA-256 support backed by the RP2350 SHA accelerator. Wire the new driver into the RP23xx ARM build and register CRYPTO_SHA2_256 through cryptodev. Also fix the RP23xx SHA256 CSR BSWAP bit definition in both the ARM and RISC-V RP23xx headers. The previous value used bit 18, but the RP2350 hardware uses bit 12. Without this fix, the accelerator hashed input words with the wrong byte order and produced incorrect digests. Signed-off-by: karaketir16 --- arch/arm/src/rp23xx/CMakeLists.txt | 4 + arch/arm/src/rp23xx/Make.defs | 4 + arch/arm/src/rp23xx/hardware/rp23xx_sha256.h | 2 +- arch/arm/src/rp23xx/rp23xx_crypto.c | 629 ++++++++++++++++++ .../src/rp23xx-rv/hardware/rp23xx_sha256.h | 2 +- 5 files changed, 639 insertions(+), 2 deletions(-) create mode 100644 arch/arm/src/rp23xx/rp23xx_crypto.c diff --git a/arch/arm/src/rp23xx/CMakeLists.txt b/arch/arm/src/rp23xx/CMakeLists.txt index 1b54235cc60..b67f08039aa 100644 --- a/arch/arm/src/rp23xx/CMakeLists.txt +++ b/arch/arm/src/rp23xx/CMakeLists.txt @@ -85,4 +85,8 @@ if(CONFIG_WATCHDOG) list(APPEND SRCS rp23xx_wdt.c) endif() +if(CONFIG_CRYPTO_CRYPTODEV_HARDWARE) + list(APPEND SRCS rp23xx_crypto.c) +endif() + target_sources(arch PRIVATE ${SRCS}) diff --git a/arch/arm/src/rp23xx/Make.defs b/arch/arm/src/rp23xx/Make.defs index 9a94796a0d9..00421248049 100644 --- a/arch/arm/src/rp23xx/Make.defs +++ b/arch/arm/src/rp23xx/Make.defs @@ -88,3 +88,7 @@ endif ifeq ($(CONFIG_WATCHDOG),y) CHIP_CSRCS += rp23xx_wdt.c endif + +ifeq ($(CONFIG_CRYPTO_CRYPTODEV_HARDWARE),y) +CHIP_CSRCS += rp23xx_crypto.c +endif diff --git a/arch/arm/src/rp23xx/hardware/rp23xx_sha256.h b/arch/arm/src/rp23xx/hardware/rp23xx_sha256.h index 3c063de7ce3..353adae9fe8 100644 --- a/arch/arm/src/rp23xx/hardware/rp23xx_sha256.h +++ b/arch/arm/src/rp23xx/hardware/rp23xx_sha256.h @@ -48,7 +48,7 @@ /* Register bit definitions *************************************************/ #define RP23XX_SHA256_CSR_MASK (0x00001317) -#define RP23XX_SHA256_CSR_BSWAP (1 << 18) +#define RP23XX_SHA256_CSR_BSWAP (1 << 12) #define RP23XX_SHA256_CSR_DMA_SIZE_MASK (0x00000300) #define RP23XX_SHA256_CSR_ERR_WDATA_NOT_RDY (1 << 4) #define RP23XX_SHA256_CSR_SUM_VLD (1 << 2) diff --git a/arch/arm/src/rp23xx/rp23xx_crypto.c b/arch/arm/src/rp23xx/rp23xx_crypto.c new file mode 100644 index 00000000000..adec32a2505 --- /dev/null +++ b/arch/arm/src/rp23xx/rp23xx_crypto.c @@ -0,0 +1,629 @@ +/**************************************************************************** + * arch/arm/src/rp23xx/rp23xx_crypto.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_CRYPTO_CRYPTODEV_HARDWARE + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "arm_internal.h" +#include "hardware/rp23xx_sha256.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define RP23XX_SHA256_BLOCK_SIZE 64 +#define RP23XX_SHA256_PADDING_SIZE 9 +#define RP23XX_SHA256_RESULT_SIZE 32 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct rp23xx_sha256_context_s +{ + bool started; + uint8_t cache_used; + size_t total_data_size; + union + { + uint32_t word; + uint8_t bytes[4]; + } cache; +}; + +struct rp23xx_crypto_data +{ + int alg; + union + { + struct + { + FAR struct rp23xx_sha256_context_s *ictx; + FAR const struct auth_hash *axf; + } auth; + } u; + +#define hw_ictx u.auth.ictx +#define hw_axf u.auth.axf + + SLIST_ENTRY(rp23xx_crypto_data) next; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void sha256_init(FAR void *ctx); +static int sha256_update(FAR void *ctx, FAR const uint8_t *in, size_t len); +static void sha256_final(FAR uint8_t *out, FAR void *ctx); +static int rp23xx_freesession(uint64_t tid); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +SLIST_HEAD(rp23xx_crypto_list, rp23xx_crypto_data); +static FAR struct rp23xx_crypto_list *g_rp23xx_sessions; +static uint32_t g_rp23xx_sesnum; +static mutex_t g_rp23xx_sha_lock = NXMUTEX_INITIALIZER; +static FAR struct rp23xx_sha256_context_s *g_rp23xx_active_ctx; + +static const struct auth_hash g_auth_hash_sha256_rp23xx = +{ + CRYPTO_SHA2_256, "SHA256", + 0, 32, 12, sizeof(struct rp23xx_sha256_context_s), + 0, + sha256_init, NULL, NULL, + sha256_update, + sha256_final +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline bool rp23xx_sha256_is_ready(void) +{ + return (getreg32(RP23XX_SHA256_CSR) & RP23XX_SHA256_CSR_WDATA_RDY) != 0; +} + +static inline bool rp23xx_sha256_is_valid(void) +{ + return (getreg32(RP23XX_SHA256_CSR) & RP23XX_SHA256_CSR_SUM_VLD) != 0; +} + +static inline bool rp23xx_sha256_err_not_ready(void) +{ + return (getreg32(RP23XX_SHA256_CSR) & + RP23XX_SHA256_CSR_ERR_WDATA_NOT_RDY) != 0; +} + +static inline void rp23xx_sha256_wait_ready(void) +{ + while (!rp23xx_sha256_is_ready()) + { + } +} + +static inline void rp23xx_sha256_wait_valid(void) +{ + while (!rp23xx_sha256_is_valid()) + { + } +} + +static inline void rp23xx_sha256_start_engine(void) +{ + uint32_t regval; + + /* The CSR contains a mix of write-one-to-clear and self-clearing control + * bits, so avoid atomic alias writes here. Preserve the writable config + * fields, clear any stale not-ready error, force big-endian SHA word + * ordering via BSWAP, and pulse START in one direct write. + */ + + regval = getreg32(RP23XX_SHA256_CSR); + regval &= (RP23XX_SHA256_CSR_BSWAP | RP23XX_SHA256_CSR_DMA_SIZE_MASK); + regval |= (RP23XX_SHA256_CSR_ERR_WDATA_NOT_RDY | + RP23XX_SHA256_CSR_BSWAP | + RP23XX_SHA256_CSR_START); + putreg32(regval, RP23XX_SHA256_CSR); +} + +static void rp23xx_sha256_get_result(FAR uint8_t *out) +{ + int i; + + for (i = 0; i < RP23XX_SHA256_RESULT_SIZE / 4; i++) + { + uint32_t data = getreg32(RP23XX_SHA256_SUM(i)); + data = __builtin_bswap32(data); + memcpy(out + i * sizeof(uint32_t), &data, sizeof(uint32_t)); + } +} + +static int rp23xx_sha256_try_start(FAR struct rp23xx_sha256_context_s *ctx) +{ + if (g_rp23xx_active_ctx != NULL && g_rp23xx_active_ctx != ctx) + { + return -EBUSY; + } + + rp23xx_sha256_start_engine(); + ctx->started = true; + g_rp23xx_active_ctx = ctx; + return OK; +} + +static void rp23xx_sha256_write_to_hardware( + FAR struct rp23xx_sha256_context_s *ctx, + FAR const uint8_t *data, size_t data_size_bytes) +{ + /* Mirror the Pico SDK's non-DMA flow: use aligned word writes when + * possible, otherwise accumulate bytes into a 32-bit cache and write full + * words once available. + */ + + if (ctx->cache_used == 0 && (((uintptr_t)data) & 3) == 0) + { + FAR const uint32_t *data32 = (FAR const uint32_t *)data; + + while (data_size_bytes >= sizeof(uint32_t)) + { + rp23xx_sha256_wait_ready(); + putreg32(*data32++, RP23XX_SHA256_WDATA); + data_size_bytes -= sizeof(uint32_t); + } + + data = (FAR const uint8_t *)data32; + } + + while (data_size_bytes-- > 0) + { + ctx->cache.bytes[ctx->cache_used++] = *data++; + if (ctx->cache_used == sizeof(uint32_t)) + { + ctx->cache_used = 0; + rp23xx_sha256_wait_ready(); + putreg32(ctx->cache.word, RP23XX_SHA256_WDATA); + } + } +} + +static int rp23xx_sha256_update_internal( + FAR struct rp23xx_sha256_context_s *ctx, + FAR const uint8_t *data, size_t data_size_bytes) +{ + size_t bytes_left; + + if (data_size_bytes == 0 || data == NULL) + { + return OK; + } + + if (!ctx->started) + { + int ret = rp23xx_sha256_try_start(ctx); + + if (ret < 0) + { + return ret; + } + } + else if (g_rp23xx_active_ctx != ctx) + { + return -EBUSY; + } + + /* Keep the same block-boundary handling as the Pico SDK: finish the + * current 64-byte hardware block first, otherwise the peripheral reports + * WDATA-not-ready if we run past the boundary without waiting. + */ + + bytes_left = ((ctx->total_data_size + + (RP23XX_SHA256_BLOCK_SIZE - 1)) & + ~(RP23XX_SHA256_BLOCK_SIZE - 1)) - ctx->total_data_size; + if (bytes_left > data_size_bytes) + { + bytes_left = data_size_bytes; + } + + if (bytes_left > 0) + { + rp23xx_sha256_write_to_hardware(ctx, data, bytes_left); + ctx->total_data_size += bytes_left; + data += bytes_left; + data_size_bytes -= bytes_left; + } + + if (data_size_bytes > 0) + { + rp23xx_sha256_write_to_hardware(ctx, data, data_size_bytes); + ctx->total_data_size += data_size_bytes; + } + + if (rp23xx_sha256_err_not_ready()) + { + return -EIO; + } + + return OK; +} + +static int rp23xx_sha256_add_zero_bytes( + FAR struct rp23xx_sha256_context_s *ctx, size_t len) +{ + static const uint32_t zero = 0; + int ret; + + while (len > 0) + { + size_t chunk = len > sizeof(zero) ? sizeof(zero) : len; + + ret = rp23xx_sha256_update_internal(ctx, (FAR const uint8_t *)&zero, + chunk); + if (ret < 0) + { + return ret; + } + + len -= chunk; + } + + return OK; +} + +static int rp23xx_sha256_write_padding( + FAR struct rp23xx_sha256_context_s *ctx) +{ + uint64_t size; + size_t user_data_size; + size_t padding_size_bytes; + uint8_t one_bit = 0x80; + int ret; + + size = (ctx->total_data_size + RP23XX_SHA256_PADDING_SIZE + + (RP23XX_SHA256_BLOCK_SIZE - 1)) & + ~(RP23XX_SHA256_BLOCK_SIZE - 1); + user_data_size = ctx->total_data_size; + padding_size_bytes = size - ctx->total_data_size; + + /* Keep padding byte-for-byte consistent with the Pico SDK flow. */ + + ret = rp23xx_sha256_update_internal(ctx, &one_bit, 1); + if (ret < 0) + { + return ret; + } + + ret = rp23xx_sha256_add_zero_bytes( + ctx, padding_size_bytes - RP23XX_SHA256_PADDING_SIZE); + if (ret < 0) + { + return ret; + } + + size = __builtin_bswap64((uint64_t)user_data_size * 8); + return rp23xx_sha256_update_internal(ctx, (FAR const uint8_t *)&size, + sizeof(size)); +} + +static void sha256_init(FAR void *ctx) +{ + memset(ctx, 0, sizeof(struct rp23xx_sha256_context_s)); +} + +static int sha256_update(FAR void *ctx, FAR const uint8_t *in, size_t len) +{ + FAR struct rp23xx_sha256_context_s *sha = + (FAR struct rp23xx_sha256_context_s *)ctx; + int ret; + + ret = nxmutex_lock(&g_rp23xx_sha_lock); + if (ret < 0) + { + return ret; + } + + ret = rp23xx_sha256_update_internal(sha, in, len); + nxmutex_unlock(&g_rp23xx_sha_lock); + return ret; +} + +static void sha256_final(FAR uint8_t *out, FAR void *ctx) +{ + FAR struct rp23xx_sha256_context_s *sha = + (FAR struct rp23xx_sha256_context_s *)ctx; + int ret; + + if (nxmutex_lock(&g_rp23xx_sha_lock) < 0) + { + return; + } + + if (!sha->started) + { + ret = rp23xx_sha256_try_start(sha); + if (ret < 0) + { + goto out; + } + } + + if (g_rp23xx_active_ctx != sha) + { + goto out; + } + + ret = rp23xx_sha256_write_padding(sha); + if (ret < 0) + { + goto out; + } + + rp23xx_sha256_wait_valid(); + if (out != NULL) + { + rp23xx_sha256_get_result(out); + } + +out: + memset(sha, 0, sizeof(*sha)); + if (g_rp23xx_active_ctx == sha) + { + g_rp23xx_active_ctx = NULL; + } + + nxmutex_unlock(&g_rp23xx_sha_lock); +} + +static int rp23xx_hash(FAR struct cryptop *crp, + FAR struct cryptodesc *crd, + FAR struct rp23xx_crypto_data *data, + caddr_t buf) +{ + FAR const struct auth_hash *axf = data->hw_axf; + + if (data->hw_ictx == NULL) + { + return -EINVAL; + } + + if (crd->crd_flags & CRD_F_UPDATE) + { + return axf->update(data->hw_ictx, + (FAR uint8_t *)buf + crd->crd_skip, + crd->crd_len); + } + + axf->final((FAR uint8_t *)crp->crp_mac, data->hw_ictx); + return OK; +} + +static int rp23xx_newsession(uint32_t *sid, FAR struct cryptoini *cri) +{ + FAR struct rp23xx_crypto_list *session; + FAR struct rp23xx_crypto_data *data; + FAR const struct auth_hash *axf; + int i; + + if (sid == NULL || cri == NULL) + { + return -EINVAL; + } + + for (i = 0; i < g_rp23xx_sesnum; i++) + { + if (SLIST_EMPTY(&g_rp23xx_sessions[i])) + { + break; + } + } + + if (i >= g_rp23xx_sesnum) + { + FAR struct rp23xx_crypto_list *new_sessions; + uint32_t new_count = + g_rp23xx_sessions == NULL ? 1 : g_rp23xx_sesnum * 2; + + new_sessions = kmm_calloc(new_count, sizeof(*new_sessions)); + if (new_sessions == NULL) + { + return -ENOBUFS; + } + + if (g_rp23xx_sessions != NULL) + { + memcpy(new_sessions, g_rp23xx_sessions, + g_rp23xx_sesnum * sizeof(*new_sessions)); + kmm_free(g_rp23xx_sessions); + } + + g_rp23xx_sessions = new_sessions; + g_rp23xx_sesnum = new_count; + } + + session = &g_rp23xx_sessions[i]; + *sid = i; + + while (cri != NULL) + { + data = kmm_zalloc(sizeof(*data)); + if (data == NULL) + { + rp23xx_freesession(i); + return -ENOBUFS; + } + + switch (cri->cri_alg) + { + case CRYPTO_SHA2_256: + axf = &g_auth_hash_sha256_rp23xx; + data->hw_ictx = kmm_zalloc(axf->ctxsize); + if (data->hw_ictx == NULL) + { + kmm_free(data); + rp23xx_freesession(i); + return -ENOBUFS; + } + + axf->init(data->hw_ictx); + data->hw_axf = axf; + data->alg = cri->cri_alg; + SLIST_INSERT_HEAD(session, data, next); + break; + + default: + kmm_free(data); + rp23xx_freesession(i); + return -EINVAL; + } + + cri = cri->cri_next; + } + + return OK; +} + +static int rp23xx_freesession(uint64_t tid) +{ + uint32_t sid = tid & 0xffffffff; + FAR struct rp23xx_crypto_data *data; + FAR struct rp23xx_crypto_data *next; + + if (sid >= g_rp23xx_sesnum) + { + return -EINVAL; + } + + data = SLIST_FIRST(&g_rp23xx_sessions[sid]); + while (data != NULL) + { + next = SLIST_NEXT(data, next); + + if (data->hw_ictx != NULL) + { + nxmutex_lock(&g_rp23xx_sha_lock); + if (g_rp23xx_active_ctx == data->hw_ictx) + { + g_rp23xx_active_ctx = NULL; + } + + nxmutex_unlock(&g_rp23xx_sha_lock); + kmm_free(data->hw_ictx); + } + + kmm_free(data); + data = next; + } + + SLIST_INIT(&g_rp23xx_sessions[sid]); + return OK; +} + +static int rp23xx_process(FAR struct cryptop *crp) +{ + uint32_t lid; + FAR struct cryptodesc *crd; + FAR struct rp23xx_crypto_list *session; + FAR struct rp23xx_crypto_data *data; + + lid = crp->crp_sid & 0xffffffff; + if (lid >= g_rp23xx_sesnum) + { + return -EINVAL; + } + + session = &g_rp23xx_sessions[lid]; + + for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) + { + SLIST_FOREACH(data, session, next) + { + if (data->alg == crd->crd_alg) + { + break; + } + } + + if (data == NULL) + { + crp->crp_etype = EINVAL; + return -EINVAL; + } + + switch (data->alg) + { + case CRYPTO_SHA2_256: + crp->crp_etype = rp23xx_hash(crp, crd, data, crp->crp_buf); + if (crp->crp_etype != 0) + { + return crp->crp_etype; + } + break; + + default: + return -EINVAL; + } + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void hwcr_init(void) +{ + int hwcr_id; + int algs[CRYPTO_ALGORITHM_MAX + 1]; + + hwcr_id = crypto_get_driverid(0); + DEBUGASSERT(hwcr_id >= 0); + + memset(algs, 0, sizeof(algs)); + algs[CRYPTO_SHA2_256] = CRYPTO_ALG_FLAG_SUPPORTED; + + crypto_register(hwcr_id, algs, rp23xx_newsession, + rp23xx_freesession, rp23xx_process); +} + +#endif /* CONFIG_CRYPTO_CRYPTODEV_HARDWARE */ diff --git a/arch/risc-v/src/rp23xx-rv/hardware/rp23xx_sha256.h b/arch/risc-v/src/rp23xx-rv/hardware/rp23xx_sha256.h index 0459b9408d9..283f7c354ed 100644 --- a/arch/risc-v/src/rp23xx-rv/hardware/rp23xx_sha256.h +++ b/arch/risc-v/src/rp23xx-rv/hardware/rp23xx_sha256.h @@ -48,7 +48,7 @@ /* Register bit definitions *************************************************/ #define RP23XX_SHA256_CSR_MASK (0x00001317) -#define RP23XX_SHA256_CSR_BSWAP (1 << 18) +#define RP23XX_SHA256_CSR_BSWAP (1 << 12) #define RP23XX_SHA256_CSR_DMA_SIZE_MASK (0x00000300) #define RP23XX_SHA256_CSR_ERR_WDATA_NOT_RDY (1 << 4) #define RP23XX_SHA256_CSR_SUM_VLD (1 << 2)