diff --git a/arch/xtensa/include/xtensa/core_macros.h b/arch/xtensa/include/xtensa/core_macros.h new file mode 100644 index 00000000000..5a8c2ad3657 --- /dev/null +++ b/arch/xtensa/include/xtensa/core_macros.h @@ -0,0 +1,39 @@ +/**************************************************************************** + * arch/xtensa/include/xtensa/core_macros.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_INCUDE_XTENSA_CORE_MACRO_H +#define __ARCH_XTENSA_INCUDE_XTENSA_CORE_MACRO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define XTHAL_GET_CCOUNT() ({ int __ccount; \ + __asm__ __volatile__("rsr.ccount %0" : \ + "=a"(__ccount)); __ccount; }) + +#endif /* __ARCH_XTENSA_INCUDE_XTENSA_CORE_H */ diff --git a/arch/xtensa/src/esp32/Kconfig b/arch/xtensa/src/esp32/Kconfig index c6c58342084..786596c5476 100644 --- a/arch/xtensa/src/esp32/Kconfig +++ b/arch/xtensa/src/esp32/Kconfig @@ -84,6 +84,14 @@ config ESP32_RMT ---help--- No yet implemented +config ESP32_RNG + bool "Random Number Generator (RNG)" + default n + depends on EXPERIMENTAL + select ARCH_HAVE_RNG + ---help--- + ESP32 supports a RNG that passed on Dieharder test suite. + config ESP32_SDIO_SAVE bool "SDIO Slave" default n diff --git a/arch/xtensa/src/esp32/Make.defs b/arch/xtensa/src/esp32/Make.defs index 3216e886f2d..ce750f8d82f 100644 --- a/arch/xtensa/src/esp32/Make.defs +++ b/arch/xtensa/src/esp32/Make.defs @@ -119,6 +119,10 @@ ifeq ($(CONFIG_ESP32_UART),y) CMN_CSRCS += esp32_serial.c endif +ifeq ($(CONFIG_ESP32_RNG),y) +CMN_CSRCS += esp32_rng.c +endif + ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y) CHIP_CSRCS += esp32_modtext.c CMN_ASRCS += xtensa_loadstore.S diff --git a/arch/xtensa/src/esp32/esp32_clockconfig.c b/arch/xtensa/src/esp32/esp32_clockconfig.c index a48e288e9d1..ef24715c527 100644 --- a/arch/xtensa/src/esp32/esp32_clockconfig.c +++ b/arch/xtensa/src/esp32/esp32_clockconfig.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/xtensa/src/esp32/esp32_clockconfig.C + * arch/xtensa/src/esp32/esp32_clockconfig.c * * Mofidifed by use in NuttX by: * @@ -30,10 +30,19 @@ #include #include "xtensa.h" +#include "xtensa_attr.h" #include "hardware/esp32_dport.h" #include "hardware/esp32_soc.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + /**************************************************************************** * Private Types ****************************************************************************/ @@ -57,7 +66,8 @@ enum cpu_freq_e * Private Functions ****************************************************************************/ -extern void ets_delay_us(int delay_us); +extern uint32_t g_ticks_per_us_pro; +extern void ets_delay_us(int delay_us); /**************************************************************************** * Name: esp32_set_cpu_freq @@ -368,3 +378,14 @@ void esp32_clockconfig(void) esp32_bbpll_configure(xtal_freq, source_freq_mhz); esp32_set_cpu_freq(freq_mhz); } + +int IRAM_ATTR esp_clk_cpu_freq(void) +{ + return g_ticks_per_us_pro * MHZ; +} + +int IRAM_ATTR esp_clk_apb_freq(void) +{ + return MIN(g_ticks_per_us_pro, 80) * MHZ; +} + diff --git a/arch/xtensa/src/esp32/esp32_clockconfig.h b/arch/xtensa/src/esp32/esp32_clockconfig.h index a552f9b33d2..60e8e599484 100644 --- a/arch/xtensa/src/esp32/esp32_clockconfig.h +++ b/arch/xtensa/src/esp32/esp32_clockconfig.h @@ -33,10 +33,6 @@ * ****************************************************************************/ -/**************************************************************************** - * Included Files - ****************************************************************************/ - #ifndef __ARCH_XTENSA_SRC_ESP32_ESP32_CLOCKCONFIG_H #define __ARCH_XTENSA_SRC_ESP32_ESP32_CLOCKCONFIG_H @@ -44,6 +40,8 @@ * Included Files ****************************************************************************/ +#include "xtensa_attr.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -60,4 +58,8 @@ void esp32_clockconfig(void); +int IRAM_ATTR esp_clk_cpu_freq(void); + +int IRAM_ATTR esp_clk_apb_freq(void); + #endif /* __ARCH_XTENSA_SRC_ESP32_ESP32_CLOCKCONFIG_H */ diff --git a/arch/xtensa/src/esp32/esp32_rng.c b/arch/xtensa/src/esp32/esp32_rng.c new file mode 100644 index 00000000000..f0561a17a86 --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_rng.c @@ -0,0 +1,273 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_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 "xtensa.h" +#include "xtensa_attr.h" +#include "hardware/wdev_reg.h" +#include "esp32_clockconfig.h" + +#if defined(CONFIG_ESP32_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 esp32_rng_initialize(void); +static ssize_t esp32_rng_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static int esp32_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 = esp32_rng_open, /* open */ + .read = esp32_rng_read, /* read */ +}; + +/**************************************************************************** + * Private functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32_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 unncessary) 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); +} + +/**************************************************************************** + * Name: esp32_rng_open + ****************************************************************************/ + +static void esp32_rng_start(void) +{ + /* Nothing to do, bootloader already did it */ +} + +static void esp32_rng_stop(void) +{ + /* Nothing to do */ +} + +static int esp32_rng_initialize(void) +{ + static bool first_flag = true; + + if (false == first_flag) + return OK; + + first_flag = false; + + _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); + + esp32_rng_stop(); + + return OK; +} + +/**************************************************************************** + * Name: esp32_rng_open + ****************************************************************************/ + +static int esp32_rng_open(FAR struct file *filep) +{ + /* O_NONBLOCK is not supported */ + + if (filep->f_oflags & O_NONBLOCK) + { + _err("ESP32 RNG didn't support O_NONBLOCK mode.\n"); + return -EPERM; + } + + return OK; +} + +/**************************************************************************** + * Name: esp32_rng_read + ****************************************************************************/ + +static ssize_t esp32_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 */ + + esp32_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) +{ + esp32_rng_initialize(); + register_driver("/dev/random", FAR & 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 + esp32_rng_initialize(); +#endif + register_driver("dev/urandom", FAR & g_rngops, 0444, NULL); +} +#endif + +#endif /* CONFIG_DEV_RANDOM || CONFIG_DEV_URANDOM_ARCH */ +#endif /* CONFIG_ESP32_RNG */ diff --git a/arch/xtensa/src/esp32/hardware/wdev_reg.h b/arch/xtensa/src/esp32/hardware/wdev_reg.h new file mode 100644 index 00000000000..c6539530244 --- /dev/null +++ b/arch/xtensa/src/esp32/hardware/wdev_reg.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/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. + * + ****************************************************************************/ + +/**************************************************************************** + * Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD + * + * Licensed 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_ESP32_HARDWARE_WDEV_REG_H +#define __ARCH_XTENSA_SRC_ESP32_HARDWARE_WDEV_REG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "esp32_soc.h" + +/* Hardware random number generator register */ + +#define WDEV_RND_REG 0x60035144 + +#endif /* __ARCH_XTENSA_SRC_ESP32_HARDWARE_WDEV_REG_H */ diff --git a/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld b/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld index 6541caa98bf..d9278d1352c 100644 --- a/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld +++ b/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld @@ -186,6 +186,7 @@ PROVIDE ( ets_isr_mask = 0x400067fc ); PROVIDE ( ets_isr_unmask = 0x40006808 ); PROVIDE ( ets_post = 0x4000673c ); PROVIDE ( ets_printf = 0x40007d54 ); +PROVIDE ( g_ticks_per_us_pro = 0x3ffe01e0 ); PROVIDE ( ets_readySet_ = 0x3ffe01f0 ); PROVIDE ( ets_run = 0x400066bc ); PROVIDE ( ets_secure_boot_check = 0x4005cb40 );