|
| 1 | +/* |
| 2 | + * Copyright (c) 2025 Bayrem Gharsellaoui |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#include <zephyr/init.h> |
| 8 | +#include <zephyr/kernel.h> |
| 9 | +#include <zephyr/device.h> |
| 10 | +#include <zephyr/crypto/crypto.h> |
| 11 | +#include <zephyr/drivers/clock_control/stm32_clock_control.h> |
| 12 | +#include <zephyr/drivers/clock_control.h> |
| 13 | +#include <zephyr/drivers/reset.h> |
| 14 | +#include <soc.h> |
| 15 | + |
| 16 | +#include "crypto_stm32_hash_priv.h" |
| 17 | + |
| 18 | +#define LOG_LEVEL CONFIG_CRYPTO_LOG_LEVEL |
| 19 | +#include <zephyr/logging/log.h> |
| 20 | +LOG_MODULE_REGISTER(crypto_stm32_hash); |
| 21 | + |
| 22 | +#define DT_DRV_COMPAT st_stm32_hash |
| 23 | + |
| 24 | +static struct crypto_stm32_hash_session stm32_hash_sessions[CONFIG_CRYPTO_STM32_HASH_MAX_SESSIONS]; |
| 25 | + |
| 26 | +static int crypto_stm32_hash_get_unused_session_index(const struct device *dev) |
| 27 | +{ |
| 28 | + struct crypto_stm32_hash_data *data = CRYPTO_STM32_HASH_DATA(dev); |
| 29 | + |
| 30 | + k_sem_take(&data->session_sem, K_FOREVER); |
| 31 | + |
| 32 | + for (int i = 0; i < CONFIG_CRYPTO_STM32_HASH_MAX_SESSIONS; i++) { |
| 33 | + if (!stm32_hash_sessions[i].in_use) { |
| 34 | + stm32_hash_sessions[i].in_use = true; |
| 35 | + k_sem_give(&data->session_sem); |
| 36 | + return i; |
| 37 | + } |
| 38 | + } |
| 39 | + |
| 40 | + k_sem_give(&data->session_sem); |
| 41 | + return -1; |
| 42 | +} |
| 43 | + |
| 44 | +static int stm32_hash_handler(struct hash_ctx *ctx, struct hash_pkt *pkt, bool finish) |
| 45 | +{ |
| 46 | + const struct device *dev = ctx->device; |
| 47 | + struct crypto_stm32_hash_data *data = CRYPTO_STM32_HASH_DATA(dev); |
| 48 | + struct crypto_stm32_hash_session *session = CRYPTO_STM32_HASH_SESSN(ctx); |
| 49 | + HAL_StatusTypeDef status; |
| 50 | + |
| 51 | + if (!pkt || !pkt->in_buf || !pkt->out_buf) { |
| 52 | + LOG_ERR("Invalid packet buffers"); |
| 53 | + return -EINVAL; |
| 54 | + } |
| 55 | + |
| 56 | + if (!finish) { |
| 57 | + LOG_ERR("Multipart hashing not supported yet"); |
| 58 | + return -ENOTSUP; |
| 59 | + } |
| 60 | + |
| 61 | + k_sem_take(&data->device_sem, K_FOREVER); |
| 62 | + |
| 63 | + switch (session->algo) { |
| 64 | + case CRYPTO_HASH_ALGO_SHA224: |
| 65 | + status = HAL_HASHEx_SHA224_Start(&data->hhash, pkt->in_buf, pkt->in_len, |
| 66 | + pkt->out_buf, HAL_MAX_DELAY); |
| 67 | + break; |
| 68 | + case CRYPTO_HASH_ALGO_SHA256: |
| 69 | + status = HAL_HASHEx_SHA256_Start(&data->hhash, pkt->in_buf, pkt->in_len, |
| 70 | + pkt->out_buf, HAL_MAX_DELAY); |
| 71 | + break; |
| 72 | + default: |
| 73 | + k_sem_give(&data->device_sem); |
| 74 | + LOG_ERR("Unsupported algorithm in handler: %d", session->algo); |
| 75 | + return -EINVAL; |
| 76 | + } |
| 77 | + |
| 78 | + k_sem_give(&data->device_sem); |
| 79 | + |
| 80 | + if (status != HAL_OK) { |
| 81 | + LOG_ERR("HAL HASH computation failed (status=%d)", status); |
| 82 | + return -EIO; |
| 83 | + } |
| 84 | + |
| 85 | + LOG_DBG("Hash computation successful"); |
| 86 | + return 0; |
| 87 | +} |
| 88 | + |
| 89 | +static int stm32_hash_begin_session(const struct device *dev, struct hash_ctx *ctx, |
| 90 | + enum hash_algo algo) |
| 91 | +{ |
| 92 | + int ctx_idx; |
| 93 | + struct crypto_stm32_hash_session *session; |
| 94 | + |
| 95 | + switch (algo) { |
| 96 | + case CRYPTO_HASH_ALGO_SHA224: |
| 97 | + case CRYPTO_HASH_ALGO_SHA256: |
| 98 | + break; |
| 99 | + default: |
| 100 | + LOG_ERR("Unsupported hash algorithm: %d", algo); |
| 101 | + return -EINVAL; |
| 102 | + } |
| 103 | + |
| 104 | + ctx_idx = crypto_stm32_hash_get_unused_session_index(dev); |
| 105 | + if (ctx_idx < 0) { |
| 106 | + LOG_ERR("No free session for now"); |
| 107 | + return -ENOSPC; |
| 108 | + } |
| 109 | + |
| 110 | + session = &stm32_hash_sessions[ctx_idx]; |
| 111 | + memset(&session->config, 0, sizeof(session->config)); |
| 112 | + memset(session->digest, 0, sizeof(session->digest)); |
| 113 | + session->in_use = true; |
| 114 | + session->algo = algo; |
| 115 | + |
| 116 | + ctx->drv_sessn_state = session; |
| 117 | + ctx->hash_hndlr = stm32_hash_handler; |
| 118 | + ctx->started = false; |
| 119 | + |
| 120 | + LOG_DBG("begin_session (algo=%d)", algo); |
| 121 | + return 0; |
| 122 | +} |
| 123 | + |
| 124 | +static int stm32_hash_free_session(const struct device *dev, struct hash_ctx *ctx) |
| 125 | +{ |
| 126 | + struct crypto_stm32_hash_session *session = CRYPTO_STM32_HASH_SESSN(ctx); |
| 127 | + |
| 128 | + if (!session) { |
| 129 | + LOG_ERR("Tried to free a NULL session"); |
| 130 | + return -EINVAL; |
| 131 | + } |
| 132 | + |
| 133 | + memset(session, 0, sizeof(*session)); |
| 134 | + |
| 135 | + LOG_DBG("Session freed"); |
| 136 | + return 0; |
| 137 | +} |
| 138 | + |
| 139 | +static int stm32_hash_query_caps(const struct device *dev) |
| 140 | +{ |
| 141 | + return (CAP_SYNC_OPS | CAP_SEPARATE_IO_BUFS); |
| 142 | +} |
| 143 | + |
| 144 | +static int crypto_stm32_hash_init(const struct device *dev) |
| 145 | +{ |
| 146 | + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); |
| 147 | + const struct crypto_stm32_hash_config *cfg = CRYPTO_STM32_HASH_CFG(dev); |
| 148 | + struct crypto_stm32_hash_data *data = CRYPTO_STM32_HASH_DATA(dev); |
| 149 | + |
| 150 | + if (!device_is_ready(clk)) { |
| 151 | + LOG_ERR("Clock control device not ready"); |
| 152 | + return -ENODEV; |
| 153 | + } |
| 154 | + |
| 155 | + if (clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken) != 0) { |
| 156 | + LOG_ERR("Clock op failed\n"); |
| 157 | + return -EIO; |
| 158 | + } |
| 159 | + |
| 160 | + k_sem_init(&data->device_sem, 1, 1); |
| 161 | + k_sem_init(&data->session_sem, 1, 1); |
| 162 | + |
| 163 | + data->hhash.Init.DataType = HASH_DATATYPE_8B; |
| 164 | + if (HAL_HASH_Init(&data->hhash) != HAL_OK) { |
| 165 | + LOG_ERR("Peripheral init error"); |
| 166 | + return -EIO; |
| 167 | + } |
| 168 | + |
| 169 | + return 0; |
| 170 | +} |
| 171 | + |
| 172 | +static DEVICE_API(crypto, stm32_hash_funcs) = { |
| 173 | + .hash_begin_session = stm32_hash_begin_session, |
| 174 | + .hash_free_session = stm32_hash_free_session, |
| 175 | + .query_hw_caps = stm32_hash_query_caps, |
| 176 | +}; |
| 177 | + |
| 178 | +static struct crypto_stm32_hash_data crypto_stm32_hash_dev_data = {0}; |
| 179 | + |
| 180 | +static const struct crypto_stm32_hash_config crypto_stm32_hash_dev_config = { |
| 181 | + .reset = RESET_DT_SPEC_INST_GET(0), |
| 182 | + .pclken = {.enr = DT_INST_CLOCKS_CELL(0, bits), .bus = DT_INST_CLOCKS_CELL(0, bus)}}; |
| 183 | + |
| 184 | +DEVICE_DT_INST_DEFINE(0, crypto_stm32_hash_init, NULL, &crypto_stm32_hash_dev_data, |
| 185 | + &crypto_stm32_hash_dev_config, POST_KERNEL, CONFIG_CRYPTO_INIT_PRIORITY, |
| 186 | + &stm32_hash_funcs); |
0 commit comments