From 03738622a164334c4943a9723a91e98053c32616 Mon Sep 17 00:00:00 2001 From: "Alan C. Assis" Date: Tue, 21 Sep 2021 15:36:44 -0300 Subject: [PATCH] esp32s2: Add RNG driver support and board profile example --- arch/xtensa/src/esp32s2/Make.defs | 4 + arch/xtensa/src/esp32s2/esp32s2_rng.c | 228 ++++++++++++++++++ arch/xtensa/src/esp32s2/hardware/wdev_reg.h | 34 +++ .../esp32s2-saola-1/configs/random/defconfig | 48 ++++ 4 files changed, 314 insertions(+) create mode 100644 arch/xtensa/src/esp32s2/esp32s2_rng.c create mode 100644 arch/xtensa/src/esp32s2/hardware/wdev_reg.h create mode 100644 boards/xtensa/esp32s2/esp32s2-saola-1/configs/random/defconfig diff --git a/arch/xtensa/src/esp32s2/Make.defs b/arch/xtensa/src/esp32s2/Make.defs index 84e2d78522..e7d44f12a8 100644 --- a/arch/xtensa/src/esp32s2/Make.defs +++ b/arch/xtensa/src/esp32s2/Make.defs @@ -77,6 +77,10 @@ ifeq ($(CONFIG_ESP32S2_UART),y) CMN_CSRCS += esp32s2_serial.c endif +ifeq ($(CONFIG_ESP32S2_RNG),y) +CMN_CSRCS += esp32s2_rng.c +endif + ifeq ($(CONFIG_ESP32S2_TIMER),y) CHIP_CSRCS += esp32s2_tim.c ifeq ($(CONFIG_TIMER),y) diff --git a/arch/xtensa/src/esp32s2/esp32s2_rng.c b/arch/xtensa/src/esp32s2/esp32s2_rng.c new file mode 100644 index 0000000000..85389c7996 --- /dev/null +++ b/arch/xtensa/src/esp32s2/esp32s2_rng.c @@ -0,0 +1,228 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s2/esp32s2_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 + +#include + +#include "xtensa.h" +#include "xtensa_attr.h" +#include "hardware/wdev_reg.h" +#include "esp32s2_clockconfig.h" + +#if defined(CONFIG_ESP32S2_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 esp32s2_rng_initialize(void); +static ssize_t esp32s2_rng_read(struct file *filep, char *buffer, + size_t buflen); + +/**************************************************************************** + * 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 = +{ + .read = esp32s2_rng_read, /* read */ +}; + +/**************************************************************************** + * Private functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32s2_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 = esp_clk_cpu_freq() / esp_clk_apb_freq(); + + static uint32_t last_ccount = 0; + uint32_t ccount; + uint32_t result = 0; + + do + { + ccount = XTHAL_GET_CCOUNT(); + result ^= getreg32(WDEV_RND_REG); + } + while (ccount - last_ccount < cpu_to_apb_freq_ratio * 16); + + last_ccount = ccount; + return result ^ getreg32(WDEV_RND_REG); +} + +static int esp32s2_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); + + return OK; +} + +/**************************************************************************** + * Name: esp32s2_rng_read + ****************************************************************************/ + +static ssize_t esp32s2_rng_read(struct file *filep, char *buffer, + size_t buflen) +{ + 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; + + /* Wait until the buffer is filled */ + + 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) +{ + esp32s2_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 + esp32s2_rng_initialize(); +#endif + register_driver("dev/urandom", &g_rngops, 0444, NULL); +} +#endif + +#endif /* CONFIG_DEV_RANDOM || CONFIG_DEV_URANDOM_ARCH */ +#endif /* CONFIG_ESP32S2_RNG */ diff --git a/arch/xtensa/src/esp32s2/hardware/wdev_reg.h b/arch/xtensa/src/esp32s2/hardware/wdev_reg.h new file mode 100644 index 0000000000..778352c916 --- /dev/null +++ b/arch/xtensa/src/esp32s2/hardware/wdev_reg.h @@ -0,0 +1,34 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s2/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_XTENSA_SRC_ESP32S2_HARDWARE_WDEV_REG_H +#define __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_WDEV_REG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "esp32s2_soc.h" + +/* Hardware random number generator register */ + +#define WDEV_RND_REG 0x60035110 + +#endif /* __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_WDEV_REG_H */ diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/configs/random/defconfig b/boards/xtensa/esp32s2/esp32s2-saola-1/configs/random/defconfig new file mode 100644 index 0000000000..55de81e89a --- /dev/null +++ b/boards/xtensa/esp32s2/esp32s2-saola-1/configs/random/defconfig @@ -0,0 +1,48 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_LEDS is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_CMDPARMS is not set +CONFIG_ARCH="xtensa" +CONFIG_ARCH_BOARD="esp32s2-saola-1" +CONFIG_ARCH_BOARD_ESP32S2_SAOLA_1=y +CONFIG_ARCH_CHIP="esp32s2" +CONFIG_ARCH_CHIP_ESP32S2=y +CONFIG_ARCH_CHIP_ESP32S2WROVER=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_XTENSA=y +CONFIG_BOARD_LOOPSPERMSEC=16717 +CONFIG_BUILTIN=y +CONFIG_ESP32S2_DATA_CACHE_0KB=y +CONFIG_ESP32S2_RNG=y +CONFIG_ESP32S2_UART0=y +CONFIG_EXAMPLES_RANDOM=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=3072 +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=114688 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_SYSTEM_NSH=y +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_USER_ENTRYPOINT="nsh_main"