drivers: entropy: npcx: add rng driver support

This commit add the rng driver support by using the npcx drgb API.

Signed-off-by: Jun Lin <CHLin56@nuvoton.com>
This commit is contained in:
Jun Lin 2024-02-07 11:30:58 +08:00 committed by Fabio Baltieri
parent 3c3bee96ef
commit 6057a83060
8 changed files with 385 additions and 18 deletions

View file

@ -13,28 +13,12 @@
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(sha_npcx, CONFIG_CRYPTO_LOG_LEVEL);
#include "soc_ncl.h"
#define NPCX_HASH_CAPS_SUPPORT (CAP_SEPARATE_IO_BUFS | CAP_SYNC_OPS)
#define NPCX_SHA256_HANDLE_SIZE DT_INST_PROP(0, context_buffer_size)
#define NPCX_SHA_MAX_SESSION 1
/* The status code returns from Nuvoton Cryptographic Library ROM APIs */
enum ncl_status {
NCL_STATUS_OK = 0xA5A5,
NCL_STATUS_FAIL = 0x5A5A,
NCL_STATUS_INVALID_PARAM = 0x02,
NCL_STATUS_PARAM_NOT_SUPPORTED,
NCL_STATUS_SYSTEM_BUSY,
NCL_STATUS_AUTHENTICATION_FAIL,
NCL_STATUS_NO_RESPONSE,
NCL_STATUS_HARDWARE_ERROR,
};
enum ncl_sha_type {
NCL_SHA_TYPE_2_256 = 0,
NCL_SHA_TYPE_2_384 = 1,
NCL_SHA_TYPE_2_512 = 2,
NCL_SHA_TYPE_NUM
};
/* The following table holds the function pointer for each SHA API in NPCX ROM. */
struct npcx_ncl_sha {
/* Get the SHA context size required by SHA APIs. */

View file

@ -33,6 +33,7 @@ zephyr_library_sources_ifdef(CONFIG_ENTROPY_NEORV32_TRNG entropy_neorv32_t
zephyr_library_sources_ifdef(CONFIG_ENTROPY_BT_HCI entropy_bt_hci.c)
zephyr_library_sources_ifdef(CONFIG_ENTROPY_GECKO_SE entropy_gecko_se.c)
zephyr_library_sources_ifdef(CONFIG_ENTROPY_PSA_CRYPTO_RNG entropy_psa_crypto.c)
zephyr_library_sources_ifdef(CONFIG_ENTROPY_NPCX_DRBG entropy_npcx_drbg.c)
if (CONFIG_BUILD_WITH_TFM)
target_include_directories(${ZEPHYR_CURRENT_LIBRARY} PRIVATE

View file

@ -35,6 +35,7 @@ source "drivers/entropy/Kconfig.gecko"
source "drivers/entropy/Kconfig.neorv32"
source "drivers/entropy/Kconfig.bt_hci"
source "drivers/entropy/Kconfig.psa_crypto"
source "drivers/entropy/Kconfig.npcx"
config ENTROPY_HAS_DRIVER
bool

View file

@ -0,0 +1,59 @@
# NPCX DRBG driver configuration options
# Copyright (c) 2024 Nuvoton Technology Corporation.
# SPDX-License-Identifier: Apache-2.0
menuconfig ENTROPY_NPCX_DRBG
bool "NPCX DRBG driver"
default y
depends on DT_HAS_NUVOTON_NPCX_DRBG_ENABLED && SOC_NPCX9MFP
select ENTROPY_HAS_DRIVER
help
This option enables the deterministic random bit generator (DRBG)
driver for NPCX family of processors.
if ENTROPY_NPCX_DRBG
choice
prompt "DRBG Security Strength Selection"
default ENTROPY_NPCX_DRBG_SECURITY_STRENGTH_128B
help
The chosen security strength defines the amount of entropy bits
generated internally and passed to the conditioning component.
config ENTROPY_NPCX_DRBG_SECURITY_STRENGTH_112B
bool "DRBG security strength 112 bits"
config ENTROPY_NPCX_DRBG_SECURITY_STRENGTH_128B
bool "DRBG security strength 128 bits"
config ENTROPY_NPCX_DRBG_SECURITY_STRENGTH_192B
bool "DRBG security strength 192 bits"
config ENTROPY_NPCX_DRBG_SECURITY_STRENGTH_256B
bool "DRBG security strength 256 bits"
config ENTROPY_NPCX_DRBG_SECURITY_STRENGTH_128B_TEST
bool "DRBG security strength 12b bits test"
config ENTROPY_NPCX_DRBG_SECURITY_STRENGTH_256B_TEST
bool "DRBG security strength 256 bits test"
endchoice
config ENTROPY_NPCX_DRBG_SECURITY_STRENGTH
int
default 0 if ENTROPY_NPCX_DRBG_SECURITY_STRENGTH_112B
default 1 if ENTROPY_NPCX_DRBG_SECURITY_STRENGTH_128B
default 2 if ENTROPY_NPCX_DRBG_SECURITY_STRENGTH_192B
default 3 if ENTROPY_NPCX_DRBG_SECURITY_STRENGTH_256B
default 4 if ENTROPY_NPCX_DRBG_SECURITY_STRENGTH_128B_TEST
default 5 if ENTROPY_NPCX_DRBG_SECURITY_STRENGTH_256B_TEST
config ENTROPY_NPCX_DRBG_RESEED_INTERVAL
int "DRBG Reseed Interval"
default 100
help
Number of gererations allowed until next reseeding.
endif

View file

@ -0,0 +1,234 @@
/*
* Copyright (c) 2024 Nuvoton Technology Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT nuvoton_npcx_drbg
#include <errno.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/entropy.h>
#include <zephyr/pm/device.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(entropy_npcx_drbg, CONFIG_ENTROPY_LOG_LEVEL);
#include "soc_ncl.h"
/* Reseed after 100 number generations */
#define NPCX_DRBG_SECURITY_STRENGTH \
((enum ncl_drbg_security_strength)CONFIG_ENTROPY_NPCX_DRBG_SECURITY_STRENGTH)
#define NPCX_DRBG_RESEED_INTERVAL CONFIG_ENTROPY_NPCX_DRBG_RESEED_INTERVAL
#define NPCX_DRBG_HANDLE_SIZE DT_INST_PROP(0, context_buffer_size)
struct entropy_npcx_drbg_dev_data {
struct k_sem sem_lock;
uint8_t handle[NPCX_DRBG_HANDLE_SIZE] __aligned(4);
};
/*
* The base address of the table that holds the function pointer for each
* DRBG API in ROM.
*/
#define NPCX_NCL_DRBG_BASE_ADDR ((const struct npcx_ncl_drbg *)DT_INST_REG_ADDR_BY_IDX(0, 0))
/* The following table holds the function pointer for each DRBG API in NPCX ROM. */
struct npcx_ncl_drbg {
/* Get the DRBG context size required by DRBG APIs. */
uint32_t (*get_context_size)(void);
/* Initialize DRBG context. */
enum ncl_status (*init_context)(void *ctx);
/* Power on/off DRBG module. */
enum ncl_status (*power)(void *ctx, uint8_t enable);
/* Finalize DRBG context. */
enum ncl_status (*finalize_context)(void *ctx);
/* Initialize the DRBG hardware module and enable interrupts. */
enum ncl_status (*init)(void *ctx, bool int_enable);
/*
* Configure DRBG, pres_resistance enables/disables (1/0) prediction
* resistance
*/
enum ncl_status (*config)(void *ctx, uint32_t reseed_interval, uint8_t pred_resistance);
/*
* This routine creates a first instantiation of the DRBG mechanism
* parameters. The routine pulls an initial seed from the HW RNG module
* and resets the reseed counter. DRBG and SHA modules should be
* activated prior to the this operation.
*/
enum ncl_status (*instantiate)(void *ctx, enum ncl_drbg_security_strength sec_strength,
const uint8_t *pers_string, uint32_t pers_string_len);
/* Uninstantiate DRBG module */
enum ncl_status (*uninstantiate)(void *ctx);
/* Reseeds the internal state of the given instantce */
enum ncl_status (*reseed)(void *ctc, uint8_t *add_data, uint32_t add_data_len);
/* Generates a random number from the current internal state. */
enum ncl_status (*generate)(void *ctx, const uint8_t *add_data, uint32_t add_data_len,
uint8_t *out_buff, uint32_t out_buff_len);
/* Clear all DRBG SSPs (Sensitive Security Parameters) in HW & driver */
enum ncl_status (*clear)(void *ctx);
};
#define NPCX_NCL_DRBG ((const struct npcx_ncl_drbg *)NPCX_NCL_DRBG_BASE_ADDR)
/* The 2nd index of the reg property holds the address of NCL_SHA_Power ROM API */
#define NPCX_NCL_SHA_POWER_ADDR ((const struct npcx_ncl_drbg *)DT_INST_REG_ADDR_BY_IDX(0, 1))
struct npcx_ncl_sha {
/* Power on/off SHA module. */
enum ncl_status (*power)(void *ctx, uint8_t on);
};
#define NPCX_NCL_SHA_POWER ((const struct npcx_ncl_sha *)NPCX_NCL_SHA_POWER_ADDR)
static int entropy_npcx_drbg_enable_sha_power(void *ctx, bool enable)
{
enum ncl_status ncl_ret;
ncl_ret = NPCX_NCL_SHA_POWER->power(ctx, enable);
if (ncl_ret != NCL_STATUS_OK) {
LOG_ERR("Fail to %s SHA power: err 0x%02x", enable ? "enable" : "disable", ncl_ret);
return -EIO;
}
return 0;
}
static int entropy_npcx_drbg_enable_drbg_power(void *ctx, bool enable)
{
enum ncl_status ncl_ret;
ncl_ret = NPCX_NCL_DRBG->power(ctx, enable);
if (ncl_ret != NCL_STATUS_OK) {
LOG_ERR("Fail to %s DRBG power: err 0x%02x", enable ? "enable" : "disable",
ncl_ret);
return -EIO;
}
return 0;
}
static int entropy_npcx_drbg_get_entropy(const struct device *dev, uint8_t *buf, uint16_t len)
{
struct entropy_npcx_drbg_dev_data *const data = dev->data;
enum ncl_status ncl_ret;
void *ctx = data->handle;
int ret = 0;
k_sem_take(&data->sem_lock, K_FOREVER);
ret = entropy_npcx_drbg_enable_sha_power(ctx, true);
if (ret != 0) {
goto err_exit;
}
ncl_ret = NPCX_NCL_DRBG->generate(ctx, NULL, 0, buf, len);
if (ncl_ret != NCL_STATUS_OK) {
LOG_ERR("Fail to generate: err 0x%02x", ncl_ret);
ret = -EIO;
goto err_exit;
}
ret = entropy_npcx_drbg_enable_sha_power(ctx, false);
err_exit:
k_sem_give(&data->sem_lock);
return ret;
}
static int entropy_npcx_drbg_init(const struct device *dev)
{
struct entropy_npcx_drbg_dev_data *const data = dev->data;
uint32_t handle_size_required;
enum ncl_status ncl_ret;
void *ctx = data->handle;
int ret;
handle_size_required = NPCX_NCL_DRBG->get_context_size();
if (handle_size_required != NPCX_DRBG_HANDLE_SIZE) {
LOG_ERR("Unexpected NCL DRBG context_size = %d", handle_size_required);
return -ENOSR;
}
ret = entropy_npcx_drbg_enable_sha_power(ctx, true);
if (ret != 0) {
return ret;
}
ret = entropy_npcx_drbg_enable_drbg_power(ctx, true);
if (ret != 0) {
return ret;
}
ncl_ret = NPCX_NCL_DRBG->init_context(ctx);
if (ncl_ret != NCL_STATUS_OK) {
LOG_ERR("Fail to init ctx: err 0x%02x", ncl_ret);
return -EIO;
}
ncl_ret = NPCX_NCL_DRBG->init(ctx, false);
if (ncl_ret != NCL_STATUS_OK) {
LOG_ERR("Fail to init: err 0x%02x", ncl_ret);
return -EIO;
}
ncl_ret = NPCX_NCL_DRBG->config(ctx, NPCX_DRBG_RESEED_INTERVAL, false);
if (ncl_ret != NCL_STATUS_OK) {
LOG_ERR("Fail to config: err 0x%02x", ncl_ret);
return -EIO;
}
ncl_ret = NPCX_NCL_DRBG->instantiate(ctx, NPCX_DRBG_SECURITY_STRENGTH, NULL, 0);
if (ncl_ret != NCL_STATUS_OK) {
LOG_ERR("Fail to config: err 0x%02x", ncl_ret);
return -EIO;
}
ret = entropy_npcx_drbg_enable_sha_power(ctx, false);
if (ret != 0) {
return ret;
}
/* Locking semaphore initialized to 1 (unlocked) */
k_sem_init(&data->sem_lock, 1, 1);
return 0;
}
#ifdef CONFIG_PM_DEVICE
static int entropy_npcx_drbg_suspend(const struct device *dev)
{
struct entropy_npcx_drbg_dev_data *const data = dev->data;
void *ctx = data->handle;
return entropy_npcx_drbg_enable_drbg_power(ctx, false);
}
static int entropy_npcx_drbg_resume(const struct device *dev)
{
struct entropy_npcx_drbg_dev_data *const data = dev->data;
void *ctx = data->handle;
return entropy_npcx_drbg_enable_drbg_power(ctx, true);
}
static int entropy_npcx_drbg_pm_action(const struct device *dev, enum pm_device_action action)
{
switch (action) {
case PM_DEVICE_ACTION_SUSPEND:
return entropy_npcx_drbg_suspend(dev);
case PM_DEVICE_ACTION_RESUME:
return entropy_npcx_drbg_resume(dev);
default:
return -ENOTSUP;
}
}
#endif /* CONFIG_PM_DEVICE */
static const struct entropy_driver_api entropy_npcx_drbg_api = {
.get_entropy = entropy_npcx_drbg_get_entropy,
};
static struct entropy_npcx_drbg_dev_data entropy_npcx_drbg_data;
PM_DEVICE_DT_INST_DEFINE(0, entropy_npcx_drbg_pm_action);
DEVICE_DT_INST_DEFINE(0, entropy_npcx_drbg_init, PM_DEVICE_DT_INST_GET(0), &entropy_npcx_drbg_data,
NULL, PRE_KERNEL_1, CONFIG_ENTROPY_INIT_PRIORITY, &entropy_npcx_drbg_api);

View file

@ -8,6 +8,10 @@
#include "npcx/npcx9.dtsi"
/ {
chosen {
zephyr,entropy = &drbg0;
};
flash0: flash@10058000 {
reg = <0x10058000 DT_SIZE_K(416)>;
};
@ -27,6 +31,15 @@
reg = <0x200D7000 DT_SIZE_K(4)>;
};
soc {
drbg0: drbg@110 {
compatible = "nuvoton,npcx-drbg";
reg = <0x110 0x2c 0x15c 0x04>;
context-buffer-size = <240>;
status = "disabled";
};
};
soc-id {
device-id = <0x2b>;
};

View file

@ -0,0 +1,19 @@
# Copyright (c) 2024 Nuvoton Technology Corporation.
# SPDX-License-Identifier: Apache-2.0
description: NPCX Deterministic Random Bit Generator
compatible: "nuvoton,npcx-drbg"
include: base.yaml
properties:
reg:
required: true
context-buffer-size:
type: int
required: true
description: |
Size of the pre-allocated buffer for the DRBG ROM API to store the
intermediate/final computation result.

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2024 Nuvoton Technology Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _NUVOTON_NPCX_SOC_NCL_H_
#define _NUVOTON_NPCX_SOC_NCL_H_
#ifdef __cplusplus
extern "C" {
#endif
/* The status code returns from Nuvoton Cryptographic Library ROM APIs */
enum ncl_status {
NCL_STATUS_OK = 0xA5A5,
NCL_STATUS_FAIL = 0x5A5A,
NCL_STATUS_INVALID_PARAM = 0x02,
NCL_STATUS_PARAM_NOT_SUPPORTED = 0x03,
NCL_STATUS_SYSTEM_BUSY = 0x04,
NCL_STATUS_AUTHENTICATION_FAIL = 0x05,
NCL_STATUS_NO_RESPONSE = 0x06,
NCL_STATUS_HARDWARE_ERROR = 0x07
};
enum ncl_sha_type {
NCL_SHA_TYPE_2_256 = 0,
NCL_SHA_TYPE_2_384 = 1,
NCL_SHA_TYPE_2_512 = 2,
NCL_SHA_TYPE_NUM
};
/*
* This enum defines the security strengths supported by this DRBG mechanism.
* The internally generated entropy and nonce sizes are derived from these
* values. The supported actual sizes:
* Security strength (bits) 112 128 192 256 128_Test 256_Test
*
* Entropy size (Bytes) 32 48 64 96 111 128
* Nonce size (Bytes) 16 16 24 32 16 0
*/
enum ncl_drbg_security_strength {
NCL_DRBG_SECURITY_STRENGTH_112B = 0,
NCL_DRBG_SECURITY_STRENGTH_128B,
NCL_DRBG_SECURITY_STRENGTH_192B,
NCL_DRBG_SECURITY_STRENGTH_256B,
NCL_DRBG_SECURITY_STRENGTH_128B_TEST,
NCL_DRBG_SECURITY_STRENGTH_256B_TEST,
NCL_DRBG_MAX_SECURITY_STRENGTH
};
#ifdef __cplusplus
}
#endif
#endif /* _NUVOTON_NPCX_SOC_NCL_H_ */