diff --git a/arch/risc-v/src/common/riscv_initialize.c b/arch/risc-v/src/common/riscv_initialize.c index 604e1a7541c..1202d767c56 100644 --- a/arch/risc-v/src/common/riscv_initialize.c +++ b/arch/risc-v/src/common/riscv_initialize.c @@ -116,6 +116,14 @@ void up_initialize(void) devnull_register(); /* Standard /dev/null */ #endif +#if defined(CONFIG_DEV_RANDOM) + devrandom_register(); /* Standard /dev/random */ +#endif + +#if defined(CONFIG_DEV_URANDOM) + devurandom_register(); /* Standard /dev/urandom */ +#endif + #if defined(CONFIG_DEV_ZERO) devzero_register(); /* Standard /dev/zero */ #endif diff --git a/arch/risc-v/src/esp32c3/Kconfig b/arch/risc-v/src/esp32c3/Kconfig index 4650c2d82af..346c5bc7867 100644 --- a/arch/risc-v/src/esp32c3/Kconfig +++ b/arch/risc-v/src/esp32c3/Kconfig @@ -202,6 +202,13 @@ config ESP32C3_I2C0 default n select ESP32C3_I2C +config ESP32C3_RNG + bool "Random Number Generator (RNG)" + default n + select ARCH_HAVE_RNG + ---help--- + ESP32-C3 supports an RNG that passed on Dieharder test suite. + config ESP32C3_TIMER0 bool "54-bit Timer 0 (Group 0 Timer 0)" default n diff --git a/arch/risc-v/src/esp32c3/Make.defs b/arch/risc-v/src/esp32c3/Make.defs index 831dce6915f..b732b13f99a 100644 --- a/arch/risc-v/src/esp32c3/Make.defs +++ b/arch/risc-v/src/esp32c3/Make.defs @@ -59,6 +59,10 @@ ifeq ($(CONFIG_ESP32C3_UART),y) CHIP_CSRCS += esp32c3_serial.c endif +ifeq ($(CONFIG_ESP32C3_RNG),y) +CHIP_CSRCS += esp32c3_rng.c +endif + ifeq ($(CONFIG_ESP32C3_I2C),y) CHIP_CSRCS += esp32c3_i2c.c endif diff --git a/arch/risc-v/src/esp32c3/esp32c3_clockconfig.c b/arch/risc-v/src/esp32c3/esp32c3_clockconfig.c index 94ee5f580ec..b4cff433dd1 100644 --- a/arch/risc-v/src/esp32c3/esp32c3_clockconfig.c +++ b/arch/risc-v/src/esp32c3/esp32c3_clockconfig.c @@ -158,6 +158,19 @@ void esp32c3_clockconfig(void) } } +/**************************************************************************** + * Name: esp32c3_clk_cpu_freq + * + * Description: + * Get CPU frequency in Hz. + * + ****************************************************************************/ + +int esp32c3_clk_cpu_freq(void) +{ + return CONFIG_ESP32C3_CPU_FREQ_MHZ * 1000000; +} + /**************************************************************************** * Name: esp32c3_clk_apb_freq * @@ -196,3 +209,19 @@ int esp32c3_clk_crypto_freq(void) return (cpufreq == 40) ? (40 * 1000000) : (160 * 1000000); } +/**************************************************************************** + * Name: esp32c3_cpu_cycle_count + * + * Description: + * Get the current value of the internal counter that increments + * every processor-clock cycle. + * + ****************************************************************************/ + +uint32_t IRAM_ATTR esp32c3_cpu_cycle_count(void) +{ + uint32_t result; + + result = READ_CSR(CSR_PCCR_MACHINE); + return result; +} diff --git a/arch/risc-v/src/esp32c3/esp32c3_clockconfig.h b/arch/risc-v/src/esp32c3/esp32c3_clockconfig.h index 50482393934..297a95ad964 100644 --- a/arch/risc-v/src/esp32c3/esp32c3_clockconfig.h +++ b/arch/risc-v/src/esp32c3/esp32c3_clockconfig.h @@ -27,6 +27,8 @@ #include +#include "esp32c3_attr.h" + #ifndef __ASSEMBLY__ /**************************************************************************** @@ -51,6 +53,16 @@ extern "C" void esp32c3_clockconfig(void); +/**************************************************************************** + * Name: esp32c3_clk_cpu_freq + * + * Description: + * Returns CPU frequency in Hz. + * + ****************************************************************************/ + +int esp32c3_clk_cpu_freq(void); + /**************************************************************************** * Name: esp32c3_clk_apb_freq * @@ -71,6 +83,17 @@ int esp32c3_clk_apb_freq(void); int esp32c3_clk_crypto_freq(void); +/**************************************************************************** + * Name: esp32c3_cpu_cycle_count + * + * Description: + * Get the current value of the internal counter that increments + * every processor-clock cycle. + * + ****************************************************************************/ + +uint32_t IRAM_ATTR esp32c3_cpu_cycle_count(void); + #if defined(__cplusplus) } #endif diff --git a/arch/risc-v/src/esp32c3/esp32c3_rng.c b/arch/risc-v/src/esp32c3/esp32c3_rng.c new file mode 100644 index 00000000000..ce046aed1d5 --- /dev/null +++ b/arch/risc-v/src/esp32c3/esp32c3_rng.c @@ -0,0 +1,273 @@ +/**************************************************************************** + * arch/risc-v/src/esp32c3/esp32c3_rng.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "riscv_arch.h" +#include "esp32c3_attr.h" +#include "hardware/wdev_reg.h" +#include "esp32c3_clockconfig.h" + +#if defined(CONFIG_ESP32C3_RNG) +#if defined(CONFIG_DEV_RANDOM) || defined(CONFIG_DEV_URANDOM_ARCH) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int esp32c3_rng_initialize(void); +static ssize_t esp32c3_rng_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static int esp32c3_rng_open(FAR struct file *filep); + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct rng_dev_s +{ + uint8_t *rd_buf; + sem_t rd_sem; /* semaphore for read RNG data */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct rng_dev_s g_rngdev; + +static const struct file_operations g_rngops = +{ + .open = esp32c3_rng_open, /* open */ + .read = esp32c3_rng_read, /* read */ +}; + +/**************************************************************************** + * Private functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32c3_random + ****************************************************************************/ + +uint32_t IRAM_ATTR esp_random(void) +{ + /* The PRNG which implements WDEV_RANDOM register gets 2 bits + * of extra entropy from a hardware randomness source every APB clock cycle + * (provided WiFi or BT are enabled). To make sure entropy is not drained + * faster than it is added, this function needs to wait for at least 16 APB + * clock cycles after reading previous word. This implementation may + * actually wait a bit longer due to extra time spent in arithmetic and + * branch statements. + * + * As a (probably unnecessary) precaution to avoid returning the + * RNG state as-is, the result is XORed with additional + * WDEV_RND_REG reads while waiting. + */ + + uint32_t cpu_to_apb_freq_ratio = esp32c3_clk_cpu_freq() / + esp32c3_clk_apb_freq(); + + static uint32_t last_ccount = 0; + uint32_t ccount; + uint32_t result = 0; + + do + { + ccount = esp32c3_cpu_cycle_count(); + result ^= getreg32(WDEV_RND_REG); + } + while (ccount - last_ccount < cpu_to_apb_freq_ratio * 16); + + last_ccount = ccount; + return result ^ getreg32(WDEV_RND_REG); +} + +/**************************************************************************** + * Name: esp32c3_rng_start + ****************************************************************************/ + +static void esp32c3_rng_start(void) +{ + /* Nothing to do, bootloader already did it */ +} + +/**************************************************************************** + * Name: esp32c3_rng_stop + ****************************************************************************/ + +static void esp32c3_rng_stop(void) +{ + /* Nothing to do */ +} + +/**************************************************************************** + * Name: esp32c3_rng_initialize + ****************************************************************************/ + +static int esp32c3_rng_initialize(void) +{ + _info("Initializing RNG\n"); + + memset(&g_rngdev, 0, sizeof(struct rng_dev_s)); + + nxsem_init(&g_rngdev.rd_sem, 0, 1); + nxsem_set_protocol(&g_rngdev.rd_sem, SEM_PRIO_NONE); + + esp32c3_rng_stop(); + + return OK; +} + +/**************************************************************************** + * Name: esp32c3_rng_open + ****************************************************************************/ + +static int esp32c3_rng_open(FAR struct file *filep) +{ + /* O_NONBLOCK is not supported */ + + if (filep->f_oflags & O_NONBLOCK) + { + _err("ESP32-C3 RNG doesn't support O_NONBLOCK mode.\n"); + return -EPERM; + } + + return OK; +} + +/**************************************************************************** + * Name: esp32c3_rng_read + ****************************************************************************/ + +static ssize_t esp32c3_rng_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct rng_dev_s *priv = (struct rng_dev_s *)&g_rngdev; + ssize_t read_len; + uint8_t *rd_buf = (uint8_t *)buffer; + + if (nxsem_wait(&priv->rd_sem) != OK) + { + return -EBUSY; + } + + read_len = buflen; + + /* start RNG and wait until the buffer is filled */ + + esp32c3_rng_start(); + + /* Now, got data */ + + while (buflen > 0) + { + uint32_t word = esp_random(); + uint32_t to_copy = MIN(sizeof(word), buflen); + + memcpy(rd_buf, &word, to_copy); + rd_buf += to_copy; + buflen -= to_copy; + } + + /* Release rd_sem for next read */ + + nxsem_post(&priv->rd_sem); + + return read_len; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: devrandom_register + * + * Description: + * Initialize the RNG hardware and register the /dev/random driver. + * Must be called BEFORE devurandom_register. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_DEV_RANDOM +void devrandom_register(void) +{ + esp32c3_rng_initialize(); + register_driver("/dev/random", &g_rngops, 0444, NULL); +} +#endif + +/**************************************************************************** + * Name: devurandom_register + * + * Description: + * Register /dev/urandom + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_DEV_URANDOM_ARCH +void devurandom_register(void) +{ +#ifndef CONFIG_DEV_RANDOM + esp32c3_rng_initialize(); +#endif + register_driver("dev/urandom", &g_rngops, 0444, NULL); +} +#endif + +#endif /* CONFIG_DEV_RANDOM || CONFIG_DEV_URANDOM_ARCH */ +#endif /* CONFIG_ESP32C3_RNG */ diff --git a/arch/risc-v/src/esp32c3/hardware/esp32c3_system.h b/arch/risc-v/src/esp32c3/hardware/esp32c3_system.h index bac37bc24f7..8e8dd9a18ae 100644 --- a/arch/risc-v/src/esp32c3/hardware/esp32c3_system.h +++ b/arch/risc-v/src/esp32c3/hardware/esp32c3_system.h @@ -31,6 +31,12 @@ * Pre-processor Definitions ****************************************************************************/ +/* Performance Counter */ + +#define CSR_PCER_MACHINE 0x7e0 +#define CSR_PCMR_MACHINE 0x7e1 +#define CSR_PCCR_MACHINE 0x7e2 + #define SYSTEM_CPU_PERI_CLK_EN_REG (DR_REG_SYSTEM_BASE + 0x000) /* SYSTEM_CLK_EN_DEDICATED_GPIO : R/W [7] : 1'b0 ; */ diff --git a/arch/risc-v/src/esp32c3/hardware/wdev_reg.h b/arch/risc-v/src/esp32c3/hardware/wdev_reg.h new file mode 100644 index 00000000000..a25d3ac2bbe --- /dev/null +++ b/arch/risc-v/src/esp32c3/hardware/wdev_reg.h @@ -0,0 +1,34 @@ +/**************************************************************************** + * arch/risc-v/src/esp32c3/hardware/wdev_reg.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_RISCV_SRC_ESP32C3_HARDWARE_WDEV_REG_H +#define __ARCH_RISCV_SRC_ESP32C3_HARDWARE_WDEV_REG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "esp32c3_soc.h" + +/* Hardware random number generator register */ + +#define WDEV_RND_REG 0x600260b0 + +#endif /* __ARCH_RISCV_SRC_ESP32C3_HARDWARE_WDEV_REG_H */ diff --git a/arch/xtensa/src/esp32/esp32_rng.c b/arch/xtensa/src/esp32/esp32_rng.c index 9383b166315..1a1da920dcd 100644 --- a/arch/xtensa/src/esp32/esp32_rng.c +++ b/arch/xtensa/src/esp32/esp32_rng.c @@ -201,8 +201,6 @@ static ssize_t esp32_rng_read(FAR struct file *filep, FAR char *buffer, esp32_rng_start(); - /* Now, got data */ - while (buflen > 0) { uint32_t word = esp_random();