blob: b563ed899cef8895acc1a9938d47287e71b79deb [file] [log] [blame]
/*
* Copyright (c) 2025 Bayrem Gharsellaoui
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/init.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/crypto/crypto.h>
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/reset.h>
#include <soc.h>
#include "crypto_stm32_hash_priv.h"
#define LOG_LEVEL CONFIG_CRYPTO_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(crypto_stm32_hash);
#define DT_DRV_COMPAT st_stm32_hash
static struct crypto_stm32_hash_session stm32_hash_sessions[CONFIG_CRYPTO_STM32_HASH_MAX_SESSIONS];
static int crypto_stm32_hash_get_unused_session_index(const struct device *dev)
{
struct crypto_stm32_hash_data *data = CRYPTO_STM32_HASH_DATA(dev);
k_sem_take(&data->session_sem, K_FOREVER);
for (int i = 0; i < CONFIG_CRYPTO_STM32_HASH_MAX_SESSIONS; i++) {
if (!stm32_hash_sessions[i].in_use) {
stm32_hash_sessions[i].in_use = true;
k_sem_give(&data->session_sem);
return i;
}
}
k_sem_give(&data->session_sem);
return -1;
}
static int stm32_hash_handler(struct hash_ctx *ctx, struct hash_pkt *pkt, bool finish)
{
const struct device *dev = ctx->device;
struct crypto_stm32_hash_data *data = CRYPTO_STM32_HASH_DATA(dev);
struct crypto_stm32_hash_session *session = CRYPTO_STM32_HASH_SESSN(ctx);
HAL_StatusTypeDef status;
if (!pkt || !pkt->in_buf || !pkt->out_buf) {
LOG_ERR("Invalid packet buffers");
return -EINVAL;
}
if (!finish) {
LOG_ERR("Multipart hashing not supported yet");
return -ENOTSUP;
}
k_sem_take(&data->device_sem, K_FOREVER);
switch (session->algo) {
case CRYPTO_HASH_ALGO_SHA224:
status = HAL_HASHEx_SHA224_Start(&data->hhash, pkt->in_buf, pkt->in_len,
pkt->out_buf, HAL_MAX_DELAY);
break;
case CRYPTO_HASH_ALGO_SHA256:
status = HAL_HASHEx_SHA256_Start(&data->hhash, pkt->in_buf, pkt->in_len,
pkt->out_buf, HAL_MAX_DELAY);
break;
default:
k_sem_give(&data->device_sem);
LOG_ERR("Unsupported algorithm in handler: %d", session->algo);
return -EINVAL;
}
k_sem_give(&data->device_sem);
if (status != HAL_OK) {
LOG_ERR("HAL HASH computation failed (status=%d)", status);
return -EIO;
}
LOG_DBG("Hash computation successful");
return 0;
}
static int stm32_hash_begin_session(const struct device *dev, struct hash_ctx *ctx,
enum hash_algo algo)
{
int ctx_idx;
struct crypto_stm32_hash_session *session;
switch (algo) {
case CRYPTO_HASH_ALGO_SHA224:
case CRYPTO_HASH_ALGO_SHA256:
break;
default:
LOG_ERR("Unsupported hash algorithm: %d", algo);
return -EINVAL;
}
ctx_idx = crypto_stm32_hash_get_unused_session_index(dev);
if (ctx_idx < 0) {
LOG_ERR("No free session for now");
return -ENOSPC;
}
session = &stm32_hash_sessions[ctx_idx];
memset(&session->config, 0, sizeof(session->config));
memset(session->digest, 0, sizeof(session->digest));
session->in_use = true;
session->algo = algo;
ctx->drv_sessn_state = session;
ctx->hash_hndlr = stm32_hash_handler;
ctx->started = false;
LOG_DBG("begin_session (algo=%d)", algo);
return 0;
}
static int stm32_hash_free_session(const struct device *dev, struct hash_ctx *ctx)
{
struct crypto_stm32_hash_session *session = CRYPTO_STM32_HASH_SESSN(ctx);
if (!session) {
LOG_ERR("Tried to free a NULL session");
return -EINVAL;
}
memset(session, 0, sizeof(*session));
LOG_DBG("Session freed");
return 0;
}
static int stm32_hash_query_caps(const struct device *dev)
{
return (CAP_SYNC_OPS | CAP_SEPARATE_IO_BUFS);
}
static int crypto_stm32_hash_init(const struct device *dev)
{
const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
const struct crypto_stm32_hash_config *cfg = CRYPTO_STM32_HASH_CFG(dev);
struct crypto_stm32_hash_data *data = CRYPTO_STM32_HASH_DATA(dev);
if (!device_is_ready(clk)) {
LOG_ERR("Clock control device not ready");
return -ENODEV;
}
if (clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken) != 0) {
LOG_ERR("Clock op failed\n");
return -EIO;
}
k_sem_init(&data->device_sem, 1, 1);
k_sem_init(&data->session_sem, 1, 1);
data->hhash.Init.DataType = HASH_DATATYPE_8B;
if (HAL_HASH_Init(&data->hhash) != HAL_OK) {
LOG_ERR("Peripheral init error");
return -EIO;
}
return 0;
}
static DEVICE_API(crypto, stm32_hash_funcs) = {
.hash_begin_session = stm32_hash_begin_session,
.hash_free_session = stm32_hash_free_session,
.query_hw_caps = stm32_hash_query_caps,
};
static struct crypto_stm32_hash_data crypto_stm32_hash_dev_data = {0};
static const struct crypto_stm32_hash_config crypto_stm32_hash_dev_config = {
.reset = RESET_DT_SPEC_INST_GET(0),
.pclken = {.enr = DT_INST_CLOCKS_CELL(0, bits), .bus = DT_INST_CLOCKS_CELL(0, bus)}};
DEVICE_DT_INST_DEFINE(0, crypto_stm32_hash_init, NULL, &crypto_stm32_hash_dev_data,
&crypto_stm32_hash_dev_config, POST_KERNEL, CONFIG_CRYPTO_INIT_PRIORITY,
&stm32_hash_funcs);