From 6057a830602fcab7f1b8206be5c4ee3102763e4e Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Wed, 7 Feb 2024 11:30:58 +0800 Subject: [PATCH] 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 --- drivers/crypto/crypto_npcx_sha.c | 20 +- drivers/entropy/CMakeLists.txt | 1 + drivers/entropy/Kconfig | 1 + drivers/entropy/Kconfig.npcx | 59 ++++++ drivers/entropy/entropy_npcx_drbg.c | 234 ++++++++++++++++++++++++ dts/arm/nuvoton/npcx9mfp.dtsi | 13 ++ dts/bindings/rng/nuvoton,npcx-drbg.yaml | 19 ++ soc/nuvoton/npcx/common/soc_ncl.h | 56 ++++++ 8 files changed, 385 insertions(+), 18 deletions(-) create mode 100644 drivers/entropy/Kconfig.npcx create mode 100644 drivers/entropy/entropy_npcx_drbg.c create mode 100644 dts/bindings/rng/nuvoton,npcx-drbg.yaml create mode 100644 soc/nuvoton/npcx/common/soc_ncl.h diff --git a/drivers/crypto/crypto_npcx_sha.c b/drivers/crypto/crypto_npcx_sha.c index 7354ea5877b..8aa30846ae2 100644 --- a/drivers/crypto/crypto_npcx_sha.c +++ b/drivers/crypto/crypto_npcx_sha.c @@ -13,28 +13,12 @@ #include 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. */ diff --git a/drivers/entropy/CMakeLists.txt b/drivers/entropy/CMakeLists.txt index 11e361517c2..02a32ed252a 100644 --- a/drivers/entropy/CMakeLists.txt +++ b/drivers/entropy/CMakeLists.txt @@ -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 diff --git a/drivers/entropy/Kconfig b/drivers/entropy/Kconfig index e932f62c6bf..34c020256bf 100644 --- a/drivers/entropy/Kconfig +++ b/drivers/entropy/Kconfig @@ -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 diff --git a/drivers/entropy/Kconfig.npcx b/drivers/entropy/Kconfig.npcx new file mode 100644 index 00000000000..fd4c91d82d9 --- /dev/null +++ b/drivers/entropy/Kconfig.npcx @@ -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 diff --git a/drivers/entropy/entropy_npcx_drbg.c b/drivers/entropy/entropy_npcx_drbg.c new file mode 100644 index 00000000000..d00ee532d00 --- /dev/null +++ b/drivers/entropy/entropy_npcx_drbg.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2024 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_npcx_drbg + +#include +#include +#include +#include + +#include +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); diff --git a/dts/arm/nuvoton/npcx9mfp.dtsi b/dts/arm/nuvoton/npcx9mfp.dtsi index fb646513f43..ea605873eb5 100644 --- a/dts/arm/nuvoton/npcx9mfp.dtsi +++ b/dts/arm/nuvoton/npcx9mfp.dtsi @@ -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>; }; diff --git a/dts/bindings/rng/nuvoton,npcx-drbg.yaml b/dts/bindings/rng/nuvoton,npcx-drbg.yaml new file mode 100644 index 00000000000..462d743ad85 --- /dev/null +++ b/dts/bindings/rng/nuvoton,npcx-drbg.yaml @@ -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. diff --git a/soc/nuvoton/npcx/common/soc_ncl.h b/soc/nuvoton/npcx/common/soc_ncl.h new file mode 100644 index 00000000000..dcdbe19fd9b --- /dev/null +++ b/soc/nuvoton/npcx/common/soc_ncl.h @@ -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_ */