-
Notifications
You must be signed in to change notification settings - Fork 8.1k
drivers: crypto: Add STM32 HASH hardware driver #93923
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
/* | ||
* 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)); | ||
Comment on lines
+111
to
+112
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry if I'm not understanding, but I could not find where these two are used in the driver. Could you please elaborate where those are used? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, those fields aren’t actively used in the current implementation. I initially added them to align with how the STM32 HAL handles staged digests and configuration (especially for future support of multipart operations). I can to remove them for now if that’s preferred. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not one who sets preferences here. Let's wait for maintainers' reviews |
||
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); |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,40 @@ | ||||||||||||||||||||||||||
/* | ||||||||||||||||||||||||||
* Copyright (c) 2025 Bayrem Gharsellaoui | ||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||
* SPDX-License-Identifier: Apache-2.0 | ||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
#ifndef ZEPHYR_DRIVERS_CRYPTO_CRYPTO_STM32_HASH_PRIV_H_ | ||||||||||||||||||||||||||
#define ZEPHYR_DRIVERS_CRYPTO_CRYPTO_STM32_HASH_PRIV_H_ | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
#define hash_config_t HASH_InitTypeDef | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
/* Max digest length: SHA256 = 32 bytes */ | ||||||||||||||||||||||||||
#define STM32_HASH_MAX_DIGEST_SIZE (32) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
struct crypto_stm32_hash_config { | ||||||||||||||||||||||||||
const struct reset_dt_spec reset; | ||||||||||||||||||||||||||
struct stm32_pclken pclken; | ||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
struct crypto_stm32_hash_data { | ||||||||||||||||||||||||||
HASH_HandleTypeDef hhash; | ||||||||||||||||||||||||||
struct k_sem device_sem; | ||||||||||||||||||||||||||
struct k_sem session_sem; | ||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
struct crypto_stm32_hash_session { | ||||||||||||||||||||||||||
hash_config_t config; | ||||||||||||||||||||||||||
uint8_t digest[STM32_HASH_MAX_DIGEST_SIZE]; | ||||||||||||||||||||||||||
bool in_use; | ||||||||||||||||||||||||||
enum hash_algo algo; | ||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
#define CRYPTO_STM32_HASH_CFG(dev) ((const struct crypto_stm32_hash_config *const)(dev)->config) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
#define CRYPTO_STM32_HASH_DATA(dev) ((struct crypto_stm32_hash_data *const)(dev)->data) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
#define CRYPTO_STM32_HASH_SESSN(ctx) \ | ||||||||||||||||||||||||||
((struct crypto_stm32_hash_session *const)(ctx)->drv_sessn_state) | ||||||||||||||||||||||||||
Comment on lines
+33
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are the parentheses useful here?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, I just followed the below implementation as reference. |
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
#endif /* ZEPHYR_DRIVERS_CRYPTO_CRYPTO_STM32_HASH_PRIV_H_ */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Copyright (c) 2025 Bayrem Gharsellaoui | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
JarmouniA marked this conversation as resolved.
Show resolved
Hide resolved
|
||
title: STM32 HASH Processor | ||
|
||
description: | | ||
STM32 hardware hash accelerator supporting SHA-224 and SHA-256 | ||
hashing algorithms. | ||
|
||
compatible: "st,stm32-hash" | ||
|
||
include: [base.yaml, reset-device.yaml] | ||
|
||
properties: | ||
reg: | ||
required: true | ||
|
||
clocks: | ||
required: true | ||
|
||
resets: | ||
required: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we enable this by default? Might be a thing to keep off by default to avoid inflating build sizes. Might be okay though, let maintainers say is it or not
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I inspired from the STM32
aes
/cryp
driver which is enabled by default on the boards