From 52e84e0c0a4be5dfad8c16577bea4f30f27aeaa2 Mon Sep 17 00:00:00 2001 From: Marco Casaroli Date: Fri, 24 Jul 2026 22:06:29 +0200 Subject: [PATCH] arch/arm/rp23xx: Add hardware TRNG driver for /dev/random. Add a driver for the rp2350 hardware true random number generator. Enabling CONFIG_RP23XX_RNG selects ARCH_HAVE_RNG and builds the driver, which registers /dev/random (and /dev/urandom when CONFIG_DEV_URANDOM selects the architecture source, DEV_URANDOM_ARCH). Each read enables the entropy source, waits for a valid 192-bit entropy holding register (EHR) sample, reads the six 32-bit EHR words, and repeats until the request is satisfied. Document the TRNG on the rp23xx platform page. Assisted-by: Claude Opus 4.8 (1M context) Signed-off-by: Marco Casaroli --- .codespellrc | 1 + Documentation/platforms/arm/rp23xx/index.rst | 19 ++ arch/arm/src/rp23xx/CMakeLists.txt | 4 + arch/arm/src/rp23xx/Kconfig | 9 + arch/arm/src/rp23xx/Make.defs | 4 + arch/arm/src/rp23xx/rp23xx_rng.c | 185 +++++++++++++++++++ 6 files changed, 222 insertions(+) create mode 100644 arch/arm/src/rp23xx/rp23xx_rng.c diff --git a/.codespellrc b/.codespellrc index d22ff556a14..14770824d32 100644 --- a/.codespellrc +++ b/.codespellrc @@ -26,6 +26,7 @@ ignore-words-list = BU, DAA, dout, + ehr, emac, eeeprom, extint, diff --git a/Documentation/platforms/arm/rp23xx/index.rst b/Documentation/platforms/arm/rp23xx/index.rst index 779c8f4e1be..d91ad4cade5 100644 --- a/Documentation/platforms/arm/rp23xx/index.rst +++ b/Documentation/platforms/arm/rp23xx/index.rst @@ -41,6 +41,7 @@ Flash ROM Boot Working Does not require boot2 from pico-sdk If picotool is available a nuttx.uf2 file will be created SRAM Boot Working Requires external SWD debugger PSRAM Working Three modes of heap allocation described below +TRNG Working Hardware RNG at /dev/random and /dev/urandom ============== ============ ===== Installation @@ -203,6 +204,24 @@ GPIO 0 and 1 pins must be connected to the device such as USB-serial converter. The `usbnsh` configuration provides the console access by USB CDC/ACM serial device. The console is available by using a terminal software on the USB host. +TRNG +==== + +The rp2350 has a hardware true random number generator (TRNG). Enabling +``RP23XX_RNG`` builds the driver and selects ``ARCH_HAVE_RNG``, which in turn +makes ``DEV_RANDOM`` available. + +With ``DEV_RANDOM`` enabled the driver registers ``/dev/random``. Enabling +``DEV_URANDOM`` additionally registers ``/dev/urandom``; when a hardware RNG is +present the architecture source (``DEV_URANDOM_ARCH``) is selected by default, +so ``/dev/urandom`` is served from the same TRNG rather than a software PRNG. + +Each read collects entropy from the TRNG's 192-bit entropy holding register +(EHR): the source is enabled, the driver waits for ``TRNG_VALID``, reads the +six 32-bit EHR words, and repeats until the request is satisfied. For example:: + + nsh> dd if=/dev/random of=/dev/console bs=16 count=1 + Supported Boards ================ diff --git a/arch/arm/src/rp23xx/CMakeLists.txt b/arch/arm/src/rp23xx/CMakeLists.txt index b67f08039aa..77449ea491d 100644 --- a/arch/arm/src/rp23xx/CMakeLists.txt +++ b/arch/arm/src/rp23xx/CMakeLists.txt @@ -60,6 +60,10 @@ if(CONFIG_RP23XX_I2C) list(APPEND SRCS rp23xx_i2c.c) endif() +if(CONFIG_RP23XX_RNG) + list(APPEND SRCS rp23xx_rng.c) +endif() + if(CONFIG_RP23XX_I2C_SLAVE) list(APPEND SRCS rp23xx_i2c_slave.c) endif() diff --git a/arch/arm/src/rp23xx/Kconfig b/arch/arm/src/rp23xx/Kconfig index cbeba7bbaa7..05907356d4c 100644 --- a/arch/arm/src/rp23xx/Kconfig +++ b/arch/arm/src/rp23xx/Kconfig @@ -740,6 +740,15 @@ endif # SPISD Configuration # ADC Configuration ##################################################################### +config RP23XX_RNG + bool "Enable hardware TRNG (/dev/random)" + default n + select ARCH_HAVE_RNG + ---help--- + Enable the RP2350 hardware true random number generator. Provides + /dev/random (and /dev/urandom when CONFIG_DEV_URANDOM selects the + architecture source) via the TRNG entropy register (EHR). + config RP23XX_ADC bool "Enable ADC Support" default n diff --git a/arch/arm/src/rp23xx/Make.defs b/arch/arm/src/rp23xx/Make.defs index 00421248049..36100cd47f7 100644 --- a/arch/arm/src/rp23xx/Make.defs +++ b/arch/arm/src/rp23xx/Make.defs @@ -64,6 +64,10 @@ ifeq ($(CONFIG_RP23XX_I2C),y) CHIP_CSRCS += rp23xx_i2c.c endif +ifeq ($(CONFIG_RP23XX_RNG),y) +CHIP_CSRCS += rp23xx_rng.c +endif + ifeq ($(CONFIG_RP23XX_I2C_SLAVE),y) CHIP_CSRCS += rp23xx_i2c_slave.c endif diff --git a/arch/arm/src/rp23xx/rp23xx_rng.c b/arch/arm/src/rp23xx/rp23xx_rng.c new file mode 100644 index 00000000000..e2c7bca54f0 --- /dev/null +++ b/arch/arm/src/rp23xx/rp23xx_rng.c @@ -0,0 +1,185 @@ +/**************************************************************************** + * arch/arm/src/rp23xx/rp23xx_rng.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 "arm_internal.h" +#include "hardware/rp23xx_trng.h" + +#if defined(CONFIG_DEV_RANDOM) || defined(CONFIG_DEV_URANDOM_ARCH) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The TRNG delivers entropy 192 bits (six 32-bit EHR words) at a time. */ + +#define RP23XX_TRNG_EHR_WORDS 6 +#define RP23XX_TRNG_EHR_BYTES (RP23XX_TRNG_EHR_WORDS * sizeof(uint32_t)) + +/* TRNG_VALID.EHR_VALID: the EHR holds a fresh 192-bit sample. */ + +#define RP23XX_TRNG_EHR_VALID (1 << 0) + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static ssize_t rp23xx_rng_read(struct file *filep, char *buffer, + size_t buflen); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static mutex_t g_rng_lock = NXMUTEX_INITIALIZER; + +static const struct file_operations g_rngops = +{ + NULL, /* open */ + NULL, /* close */ + rp23xx_rng_read, /* read */ + NULL, /* write */ + NULL, /* seek */ + NULL, /* ioctl */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rp23xx_rng_read + * + * Description: + * Fill 'buffer' with 'buflen' bytes of hardware entropy. Enables the ring + * -oscillator source, then repeatedly waits for a valid 192-bit EHR and + * copies it out until the request is satisfied. + * + ****************************************************************************/ + +static ssize_t rp23xx_rng_read(struct file *filep, char *buffer, + size_t buflen) +{ + size_t nread = 0; + int ret; + + ret = nxmutex_lock(&g_rng_lock); + if (ret < 0) + { + return ret; + } + + /* Enable the entropy source. */ + + putreg32(1, RP23XX_TRNG_RND_SOURCE_ENABLE); + + while (nread < buflen) + { + uint32_t ehr[RP23XX_TRNG_EHR_WORDS]; + size_t chunk; + int i; + + /* Wait for the next 192-bit sample to become valid. */ + + while ((getreg32(RP23XX_TRNG_TRNG_VALID) & RP23XX_TRNG_EHR_VALID) == 0) + { + } + + for (i = 0; i < RP23XX_TRNG_EHR_WORDS; i++) + { + ehr[i] = getreg32(RP23XX_TRNG_EHR_DATA(i)); + } + + /* Acknowledge the sample so the engine collects the next one. */ + + putreg32(0xffffffff, RP23XX_TRNG_RNG_ICR); + + chunk = buflen - nread; + if (chunk > RP23XX_TRNG_EHR_BYTES) + { + chunk = RP23XX_TRNG_EHR_BYTES; + } + + memcpy(buffer + nread, ehr, chunk); + nread += chunk; + } + + /* Leave the source disabled to save power. */ + + putreg32(0, RP23XX_TRNG_RND_SOURCE_ENABLE); + + nxmutex_unlock(&g_rng_lock); + return (ssize_t)nread; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: devrandom_register + * + * Description: + * Register /dev/random, backed by the RP2350 hardware TRNG. Called + * automatically from drivers_initialize() when CONFIG_DEV_RANDOM is set. + * + ****************************************************************************/ + +#ifdef CONFIG_DEV_RANDOM +void devrandom_register(void) +{ + register_driver("/dev/random", &g_rngops, 0444, NULL); +} +#endif + +/**************************************************************************** + * Name: devurandom_register + * + * Description: + * Register /dev/urandom, backed by the same hardware TRNG. Called from + * drivers_initialize() when CONFIG_DEV_URANDOM selects the arch source. + * + ****************************************************************************/ + +#ifdef CONFIG_DEV_URANDOM_ARCH +void devurandom_register(void) +{ + register_driver("/dev/urandom", &g_rngops, 0444, NULL); +} +#endif + +#endif /* CONFIG_DEV_RANDOM || CONFIG_DEV_URANDOM_ARCH */