diff --git a/cores/arduino/WMath.cpp b/cores/arduino/WMath.cpp index 9e1c2103a..aec2b4d6d 100644 --- a/cores/arduino/WMath.cpp +++ b/cores/arduino/WMath.cpp @@ -25,8 +25,8 @@ extern "C" { #include "stdlib.h" #include "hal/trng_api.h" } - -#if defined(ARDUINO_PORTENTA_H7_M7) || \ +#if defined(ARDUINO_NANO_RP2040_CONNECT) || \ + defined(ARDUINO_PORTENTA_H7_M7) || \ defined(ARDUINO_NICLA_VISION) || \ defined(ARDUINO_OPTA) || \ defined(ARDUINO_GIGA) diff --git a/patches/0230-RP2040-add-pico_rand-support.patch b/patches/0230-RP2040-add-pico_rand-support.patch new file mode 100644 index 000000000..9afe7ca99 --- /dev/null +++ b/patches/0230-RP2040-add-pico_rand-support.patch @@ -0,0 +1,725 @@ +From ac5c21fad54214e10a3558f29195d7ea70b4ccec Mon Sep 17 00:00:00 2001 +From: pennam +Date: Mon, 17 Jun 2024 10:19:14 +0200 +Subject: [PATCH] RP2040: add pico_rand support + +--- + .../TARGET_RP2040/CMakeLists.txt | 2 + + .../TARGET_RP2040/objects.h | 7 + + .../pico-sdk/rp2_common/CMakeLists.txt | 1 + + .../hardware_sync/include/hardware/sync.h | 5 + + .../pico_platform/include/pico/platform.h | 6 +- + .../rp2_common/pico_rand/CMakeLists.txt | 13 + + .../rp2_common/pico_rand/include/pico/rand.h | 185 +++++++++++ + .../pico-sdk/rp2_common/pico_rand/rand.c | 305 ++++++++++++++++++ + .../TARGET_RP2040/trng_api.c | 64 ++++ + targets/targets.json | 3 +- + 10 files changed, 587 insertions(+), 4 deletions(-) + create mode 100644 targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/CMakeLists.txt + create mode 100644 targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/include/pico/rand.h + create mode 100644 targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/rand.c + create mode 100644 targets/TARGET_RASPBERRYPI/TARGET_RP2040/trng_api.c + +diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/CMakeLists.txt +index 4fadf6091e..4e9bae47ce 100644 +--- a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/CMakeLists.txt ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/CMakeLists.txt +@@ -36,6 +36,7 @@ target_include_directories(mbed-rp2040 + pico-sdk/common/pico_base/include + pico-sdk/common/pico_binary_info/include + pico-sdk/common/pico_util/include ++ pico-sdk/common/pico_rand/include + pico-sdk/boards/include + pico-sdk/generated + . +@@ -71,6 +72,7 @@ target_sources(mbed-rp2040 + pico-sdk/rp2_common/pico_bootrom/bootrom.c + pico-sdk/rp2_common/pico_runtime/runtime.c + pico-sdk/rp2_common/pico_platform/platform.c ++ pico-sdk/rp2_common/pico_rand/rand.c + pico-sdk/common/pico_sync/mutex.c + pico-sdk/common/pico_time/time.c + pico-sdk/common/pico_sync/lock_core.c +diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/objects.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/objects.h +index f5f44a58f4..0231968bb5 100644 +--- a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/objects.h ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/objects.h +@@ -33,6 +33,7 @@ extern "C" { + #include "pico/assert.h" + #include "pico/time.h" + #include "pico/types.h" ++#include "pico/rand.h" + #include "hardware/pwm.h" + #include "hardware/adc.h" + #include "hardware/resets.h" +@@ -122,6 +123,12 @@ struct flash_s { + uint32_t dummy; + }; + ++#if DEVICE_TRNG ++struct trng_s { ++ uint8_t not_used; ++}; ++#endif ++ + typedef struct gpio_s gpio_t; + typedef struct serial_s serial_t; + +diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/CMakeLists.txt +index 4ca55becba..ec89c3ff71 100644 +--- a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/CMakeLists.txt ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/CMakeLists.txt +@@ -49,6 +49,7 @@ if (NOT PICO_BARE_METAL) + pico_add_subdirectory(pico_mem_ops) + pico_add_subdirectory(pico_malloc) + pico_add_subdirectory(pico_printf) ++ pico_add_subdirectory(pico_rand) + + pico_add_subdirectory(pico_stdio) + pico_add_subdirectory(pico_stdio_semihosting) +diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/include/hardware/sync.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/include/hardware/sync.h +index 8f91d55955..4f076aba02 100644 +--- a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/include/hardware/sync.h ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/include/hardware/sync.h +@@ -70,6 +70,11 @@ typedef volatile uint32_t spin_lock_t; + #define PICO_SPINLOCK_ID_HARDWARE_CLAIM 11 + #endif + ++// PICO_CONFIG: PICO_SPINLOCK_ID_RAND, Spinlock ID for Random Number Generator, min=0, max=31, default=12, group=hardware_sync ++#ifndef PICO_SPINLOCK_ID_RAND ++#define PICO_SPINLOCK_ID_RAND 12 ++#endif ++ + // PICO_CONFIG: PICO_SPINLOCK_ID_OS1, First Spinlock ID reserved for use by low level OS style software, min=0, max=31, default=14, group=hardware_sync + #ifndef PICO_SPINLOCK_ID_OS1 + #define PICO_SPINLOCK_ID_OS1 14 +diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/include/pico/platform.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/include/pico/platform.h +index ee1d360cee..ea16d9734e 100644 +--- a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/include/pico/platform.h ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/include/pico/platform.h +@@ -151,14 +151,14 @@ extern "C" { + * + * For example a `uint32_t` foo that will retain its value if the program is restarted by reset. + * +- * uint32_t __uninitialized_ram("my_group_name") foo; ++ * uint32_t __uninitialized_ram(foo); + * +- * The section attribute is `.uninitialized_ram.` ++ * The section attribute is `.uninitialized_data.` + * + * \param group a string suffix to use in the section name to distinguish groups that can be linker + * garbage-collected independently + */ +-#define __uninitialized_ram(group) __attribute__((section(".uninitialized_ram." #group))) group ++#define __uninitialized_ram(group) __attribute__((section(".uninitialized_data." #group))) group + + /*! \brief Section attribute macro for placement in flash even in a COPY_TO_RAM binary + * \ingroup pico_platform +diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/CMakeLists.txt +new file mode 100644 +index 0000000000..0e72bb5ab6 +--- /dev/null ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/CMakeLists.txt +@@ -0,0 +1,13 @@ ++pico_add_library(pico_rand) ++ ++target_sources(pico_rand INTERFACE ++ ${CMAKE_CURRENT_LIST_DIR}/rand.c ++) ++ ++target_include_directories(pico_rand_headers INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) ++ ++pico_mirrored_target_link_libraries(pico_rand INTERFACE ++ pico_unique_id ++ hardware_clocks ++ hardware_timer ++ hardware_sync) +diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/include/pico/rand.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/include/pico/rand.h +new file mode 100644 +index 0000000000..20fc6d6cb1 +--- /dev/null ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/include/pico/rand.h +@@ -0,0 +1,185 @@ ++/* ++ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef _PICO_RAND_H ++#define _PICO_RAND_H ++ ++#include "pico.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/** \file pico/rand.h ++ * \defgroup pico_rand pico_rand ++ * ++ * Random Number Generator API ++ * ++ * This module generates random numbers at runtime utilizing a number of possible entropy ++ * sources and uses those sources to modify the state of a 128-bit 'Pseudo ++ * Random Number Generator' implemented in software. ++ * ++ * The random numbers (32 to 128 bit) to be supplied are read from the PRNG which is used ++ * to help provide a large number space. ++ * ++ * The following (multiple) sources of entropy are available (of varying quality), each enabled by a #define: ++ * ++ * - The Ring Oscillator (ROSC) (\ref PICO_RAND_ENTROPY_SRC_ROSC == 1): ++ * \ref PICO_RAND_ROSC_BIT_SAMPLE_COUNT bits are gathered from the ring oscillator "random bit" and mixed in each ++ * time. This should not be used if the ROSC is off, or the processor is running from ++ * the ROSC. ++ * \note the maximum throughput of ROSC bit sampling is controlled by PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US which defaults ++ * to 10us, i.e. 100,000 bits per second. ++ * - Time (\ref PICO_RAND_ENTROPY_SRC_TIME == 1): The 64-bit microsecond timer is mixed in each time. ++ * - Bus Performance Counter (\ref PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER == 1): One of the bus fabric's performance ++ * counters is mixed in each time. ++ * ++ * \note All entropy sources are hashed before application to the PRNG state machine. ++ * ++ * The \em first time a random number is requested, the 128-bit PRNG state ++ * must be seeded. Multiple entropy sources are also available for the seeding operation: ++ * ++ * - The Ring Oscillator (ROSC) (\ref PICO_RAND_SEED_ENTROPY_SRC_ROSC == 1): ++ * 64 bits are gathered from the ring oscillator "random bit" and mixed into the seed. ++ * - Time (\ref PICO_RAND_SEED_ENTROPY_SRC_TIME == 1): The 64-bit microsecond timer is mixed into the seed. ++ * - Board Identifier (PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID == 1): The board id via \ref pico_get_unique_board_id ++ * is mixed into the seed. ++ * - RAM hash (\ref PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH (\ref PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH): The hashed contents of a ++ * subset of RAM are mixed in. Initial RAM contents are undefined on power up, so provide a reasonable source of entropy. ++ * By default the last 1K of RAM (which usually contains the core 0 stack) is hashed, which may also provide for differences ++ * after each warm reset. ++ * ++ * With default settings, the seed generation takes approximately 1 millisecond while ++ * subsequent random numbers generally take between 10 and 20 microseconds to generate. ++ * ++ * pico_rand methods may be safely called from either core or from an IRQ, but be careful in the latter case as ++ * the calls may block for a number of microseconds waiting on more entropy. ++ */ ++ ++// --------------- ++// ENTROPY SOURCES ++// --------------- ++ ++// PICO_CONFIG: PICO_RAND_ENTROPY_SRC_ROSC, Enable/disable use of ROSC as an entropy source, type=bool, default=1, group=pico_rand ++#ifndef PICO_RAND_ENTROPY_SRC_ROSC ++#define PICO_RAND_ENTROPY_SRC_ROSC 1 ++#endif ++ ++// PICO_CONFIG: PICO_RAND_ENTROPY_SRC_TIME, Enable/disable use of hardware timestamp as an entropy source, type=bool, default=1, group=pico_rand ++#ifndef PICO_RAND_ENTROPY_SRC_TIME ++#define PICO_RAND_ENTROPY_SRC_TIME 1 ++#endif ++ ++// PICO_CONFIG: PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER, Enable/disable use of a bus performance counter as an entropy source, type=bool, default=1, group=pico_rand ++#ifndef PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER ++#define PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER 1 ++#endif ++ ++// -------------------- ++// SEED ENTROPY SOURCES ++// -------------------- ++ ++// PICO_CONFIG: PICO_RAND_SEED_ENTROPY_SRC_ROSC, Enable/disable use of ROSC as an entropy source for the random seed, type=bool, default=1, group=pico_rand ++#ifndef PICO_RAND_SEED_ENTROPY_SRC_ROSC ++#define PICO_RAND_SEED_ENTROPY_SRC_ROSC PICO_RAND_ENTROPY_SRC_ROSC ++#endif ++ ++// PICO_CONFIG: PICO_RAND_SEED_ENTROPY_SRC_TIME, Enable/disable use of hardware timestamp as an entropy source for the random seed, type=bool, default=1, group=pico_rand ++#ifndef PICO_RAND_SEED_ENTROPY_SRC_TIME ++#define PICO_RAND_SEED_ENTROPY_SRC_TIME PICO_RAND_ENTROPY_SRC_TIME ++#endif ++ ++// PICO_CONFIG: PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID, Enable/disable use of board id as part of the random seed, type=bool, default=1, group=pico_rand ++#ifndef PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID ++#define PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID 0 ++#endif ++ ++// PICO_CONFIG: PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH, Enable/disable use of a RAM hash as an entropy source for the random seed, type=bool, default=1, group=pico_rand ++#ifndef PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH ++#define PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH 1 ++#endif ++ ++// --------------------------------- ++// PICO_RAND_ENTROPY_SRC_ROSC CONFIG ++// --------------------------------- ++ ++// PICO_CONFIG: PICO_RAND_ROSC_BIT_SAMPLE_COUNT, Number of samples to take of the ROSC random bit per random number generation , min=1, max=64, default=1, group=pico_rand ++#ifndef PICO_RAND_ROSC_BIT_SAMPLE_COUNT ++#define PICO_RAND_ROSC_BIT_SAMPLE_COUNT 1 ++#endif ++ ++// PICO_CONFIG: PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US, Define a default minimum time between sampling the ROSC random bit, min=5, max=20, default=10, group=pico_rand ++#ifndef PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US ++// (Arbitrary / tested) minimum time between sampling the ROSC random bit ++#define PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US 10u ++#endif ++ ++// --------------------------------------------- ++// PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER CONFIG ++// --------------------------------------------- ++ ++// PICO_CONFIG: PICO_RAND_BUS_PERF_COUNTER_INDEX, Bus performance counter index to use for sourcing entropy, min=0, max=3, group=pico_rand ++// this is deliberately undefined by default, meaning the code will pick that appears unused ++//#define PICO_RAND_BUS_PERF_COUNTER_INDEX 0 ++ ++// PICO_CONFIG: PICO_RAND_BUS_PERF_COUNTER_EVENT, Bus performance counter event to use for sourcing entropy, default=arbiter_sram5_perf_event_access, group=pico_rand ++#ifndef PICO_RAND_BUS_PERF_COUNTER_EVENT ++#define PICO_RAND_BUS_PERF_COUNTER_EVENT arbiter_sram5_perf_event_access ++#endif ++ ++// ------------------------------------------ ++// PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH CONFIG ++// ------------------------------------------ ++ ++// PICO_CONFIG: PICO_RAND_RAM_HASH_END, end of address in RAM (non-inclusive) to hash during pico_rand seed initialization, default=SRAM_END, group=pico_rand ++#ifndef PICO_RAND_RAM_HASH_END ++#define PICO_RAND_RAM_HASH_END SRAM_END ++#endif ++// PICO_CONFIG: PICO_RAND_RAM_HASH_START, start of address in RAM (inclusive) to hash during pico_rand seed initialization, default=PICO_RAND_RAM_HASH_END - 1024, group=pico_rand ++#ifndef PICO_RAND_RAM_HASH_START ++#define PICO_RAND_RAM_HASH_START (PICO_RAND_RAM_HASH_END - 1024u) ++#endif ++ ++// We provide a maximum of 128 bits entropy in one go ++typedef struct rng_128 { ++ uint64_t r[2]; ++} rng_128_t; ++ ++/*! \brief Get 128-bit random number ++ * \ingroup pico_rand ++ * ++ * This method may be safely called from either core or from an IRQ, but be careful in the latter case as ++ * the call may block for a number of microseconds waiting on more entropy. ++ * ++ * \param rand128 Pointer to storage to accept a 128-bit random number ++ */ ++void get_rand_128(rng_128_t *rand128); ++ ++/*! \brief Get 64-bit random number ++ * \ingroup pico_rand ++ * ++ * This method may be safely called from either core or from an IRQ, but be careful in the latter case as ++ * the call may block for a number of microseconds waiting on more entropy. ++ * ++ * \return 64-bit random number ++ */ ++uint64_t get_rand_64(void); ++ ++/*! \brief Get 32-bit random number ++ * \ingroup pico_rand ++ * ++ * This method may be safely called from either core or from an IRQ, but be careful in the latter case as ++ * the call may block for a number of microseconds waiting on more entropy. ++ * ++ * \return 32-bit random number ++ */ ++uint32_t get_rand_32(void); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/rand.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/rand.c +new file mode 100644 +index 0000000000..c73b80321e +--- /dev/null ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/rand.c +@@ -0,0 +1,305 @@ ++/* ++ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++/* xoroshiro128ss(), rotl(): ++ ++ Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) ++ ++ To the extent possible under law, the author has dedicated all copyright ++ and related and neighboring rights to this software to the public domain ++ worldwide. This software is distributed without any warranty. ++ ++ See ++ ++ splitmix64() implementation: ++ ++ Written in 2015 by Sebastiano Vigna (vigna@acm.org) ++ To the extent possible under law, the author has dedicated all copyright ++ and related and neighboring rights to this software to the public domain ++ worldwide. This software is distributed without any warranty. ++ ++ See ++*/ ++ ++#include "pico/rand.h" ++#if PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID ++#include "pico/unique_id.h" ++#endif ++#include "pico/time.h" ++#include "hardware/clocks.h" ++#include "hardware/structs/rosc.h" ++#include "hardware/structs/bus_ctrl.h" ++#include "hardware/sync.h" ++ ++static bool rng_initialised = false; ++ ++// Note: By design, do not initialise any of the variables that hold entropy, ++// they may have useful junk in them, either from power-up or a previous boot. ++static rng_128_t __uninitialized_ram(rng_state); ++#if PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH ++static uint64_t __uninitialized_ram(ram_hash); ++#endif ++ ++#if PICO_RAND_ENTROPY_SRC_ROSC | PICO_RAND_SEED_ENTROPY_SRC_ROSC ++static uint64_t __uninitialized_ram(rosc_samples); ++#endif ++ ++#if PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER ++static uint8_t bus_counter_idx; ++#endif ++ ++/* From the original source: ++ ++ This is a fixed-increment version of Java 8's SplittableRandom generator ++ See http://dx.doi.org/10.1145/2714064.2660195 and ++ http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html ++ ++ It is a very fast generator passing BigCrush, and it can be useful if ++ for some reason you absolutely want 64 bits of state; otherwise, we ++ rather suggest to use a xoroshiro128+ (for moderately parallel ++ computations) or xorshift1024* (for massively parallel computations) ++ generator. ++ ++ Note: This can be called with any value (i.e. including 0) ++*/ ++static __noinline uint64_t splitmix64(uint64_t x) { ++ uint64_t z = x + 0x9E3779B97F4A7C15ull; ++ z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ull; ++ z = (z ^ (z >> 27)) * 0x94D049BB133111EBull; ++ return z ^ (z >> 31); ++} ++ ++/* From the original source: ++ ++ This is xoroshiro128** 1.0, one of our all-purpose, rock-solid, ++ small-state generators. It is extremely (sub-ns) fast and it passes all ++ tests we are aware of, but its state space is large enough only for ++ mild parallelism. ++ ++ For generating just floating-point numbers, xoroshiro128+ is even ++ faster (but it has a very mild bias, see notes in the comments). ++ ++ The state must be seeded so that it is not everywhere zero. If you have ++ a 64-bit seed, we suggest to seed a splitmix64 generator and use its ++ output to fill s. ++*/ ++static inline uint64_t rotl(const uint64_t x, int k) { ++ return (x << k) | (x >> (64 - k)); ++} ++ ++static __noinline uint64_t xoroshiro128ss(rng_128_t *local_rng_state) { ++ const uint64_t s0 = local_rng_state->r[0]; ++ uint64_t s1 = local_rng_state->r[1]; ++ ++ // Because the state is *modified* outside of this function, there is a ++ // 1 in 2^128 chance that it could be all zeroes (which is not allowed). ++ while (s0 == 0 && s1 == 0) { ++ s1 = time_us_64(); // should not be 0, but loop anyway ++ } ++ ++ const uint64_t result = rotl(s0 * 5, 7) * 9; ++ ++ s1 ^= s0; ++ local_rng_state->r[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b ++ local_rng_state->r[1] = rotl(s1, 37); // c ++ ++ return result; ++} ++ ++#if PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH ++static uint64_t sdbm_hash64_sram(uint64_t hash) { ++ // save some time by hashing a word at a time ++ for (uint i = (PICO_RAND_RAM_HASH_START + 3) & ~3; i < PICO_RAND_RAM_HASH_END; i+=4) { ++ uint32_t c = *(uint32_t *) i; ++ hash = (uint64_t) c + (hash << 6) + (hash << 16) - hash; ++ } ++ return hash; ++} ++#endif ++ ++#if PICO_RAND_SEED_ENTROPY_SRC_ROSC | PICO_RAND_ENTROPY_SRC_ROSC ++/* gather an additional n bits of entropy, and shift them into the 64 bit entropy counter */ ++static uint64_t capture_additional_rosc_samples(uint n) { ++ static absolute_time_t next_sample_time; ++ ++ // provide an override if someone really wants it, but disabling ROSC as an entropy source makes more sense ++#if !PICO_RAND_DISABLE_ROSC_CHECK ++ // check that the ROSC is running but that the processors are NOT running from it ++ hard_assert((rosc_hw->status & ROSC_STATUS_ENABLED_BITS) && ++ ((clocks_hw->clk[clk_sys].ctrl & CLOCKS_CLK_SYS_CTRL_AUXSRC_BITS) != (CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_ROSC_CLKSRC << CLOCKS_CLK_SYS_CTRL_AUXSRC_LSB))); ++#endif ++ ++ bool in_exception = __get_current_exception(); ++ assert(n); // save us having to special case samples for this ++ uint64_t samples = 0; ++ for(uint i=0; irandombit & 1u; ++ // use of relative time to now, rather than offset from before makes things ++ // a bit less predictable at the cost of some speed. ++ next_sample_time = make_timeout_time_us(PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US); ++ bit_done = true; ++ if (i == n - 1) { ++ // samples has our random bits, so let's mix them in now ++ samples = rosc_samples = (rosc_samples << n) | samples; ++ } ++ } ++ spin_unlock(lock, save); ++ } while (!bit_done); ++ } ++ return samples; ++} ++#endif ++ ++static void initialise_rand(void) { ++ rng_128_t local_rng_state = local_rng_state; ++ uint which = 0; ++#if PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH ++ ram_hash = sdbm_hash64_sram(ram_hash); ++ local_rng_state.r[which] ^= splitmix64(ram_hash); ++ which ^= 1; ++#endif ++ ++#if PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID ++ static_assert(PICO_UNIQUE_BOARD_ID_SIZE_BYTES == sizeof(uint64_t), ++ "Code below requires that 'board_id' is 64-bits in size"); ++ ++ // Note! The safety of the length assumption here is protected by a 'static_assert' above ++ union unique_id_u { ++ pico_unique_board_id_t board_id_native; ++ uint64_t board_id_u64; ++ } unique_id; ++ // Note! The safety of the length assumption here is protected by a 'static_assert' above ++ pico_get_unique_board_id(&unique_id.board_id_native); ++ local_rng_state.r[which] ^= splitmix64(unique_id.board_id_u64); ++ which ^= 1; ++#endif ++ ++#if PICO_RAND_SEED_ENTROPY_SRC_ROSC ++ // this is really quite slow (10ms per iteration), and I'm not sure that it adds value over the 64 random bits ++// uint ref_khz = clock_get_hz(clk_ref) / 100; ++// for (int i = 0; i < 5; i++) { ++// // Apply hash of the rosc frequency, limited but still 'extra' entropy ++// uint measurement = frequency_count_raw(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC, ref_khz); ++// local_rng_state.r[which] ^= splitmix64(measurement); ++// (void) xoroshiro128ss(&local_rng_state); //churn to mix seed sources ++// } ++ ++ // Gather a full ROSC sample array with sample bits ++ local_rng_state.r[which] ^= splitmix64(capture_additional_rosc_samples(8 * sizeof(rosc_samples))); ++ which ^= 1; ++#endif ++ ++#if PICO_RAND_SEED_ENTROPY_SRC_TIME ++ // Mix in hashed time. This is [possibly] predictable boot-to-boot ++ // but will vary application-to-application. ++ local_rng_state.r[which] ^= splitmix64(time_us_64()); ++ which ^= 1; ++#endif ++ ++ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_RAND); ++ uint32_t save = spin_lock_blocking(lock); ++ if (!rng_initialised) { ++#if PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER ++#if !PICO_RAND_BUSCTRL_COUNTER_INDEX ++ int idx = -1; ++ for(uint i = 0; i < count_of(bus_ctrl_hw->counter); i++) { ++ if (bus_ctrl_hw->counter[i].sel == BUSCTRL_PERFSEL0_RESET) { ++ idx = (int)i; ++ break; ++ } ++ } ++ hard_assert(idx != -1); ++ bus_counter_idx = (uint8_t)idx; ++#else ++ bus_counter_idx = (uint8_t)PICO_RAND_BUSCTRL_COUNTER_INDEX; ++#endif ++ bus_ctrl_hw->counter[bus_counter_idx].sel = PICO_RAND_BUS_PERF_COUNTER_EVENT; ++#endif ++ (void) xoroshiro128ss(&local_rng_state); ++ rng_state = local_rng_state; ++ rng_initialised = true; ++ } ++ spin_unlock(lock, save); ++} ++ ++uint64_t get_rand_64(void) { ++ if (!rng_initialised) { ++ // Do not provide 'RNs' until the system has been initialised. Note: ++ // The first initialisation can be quite time-consuming depending on ++ // the amount of RAM hashed, see RAM_HASH_START and RAM_HASH_END ++ initialise_rand(); ++ } ++ ++ static volatile uint8_t check_byte; ++ rng_128_t local_rng_state = rng_state; ++ uint8_t local_check_byte = check_byte; ++ // Modify PRNG state with the run-time entropy sources, ++ // hashed to reduce correlation with previous modifications. ++ uint which = 0; ++#if PICO_RAND_ENTROPY_SRC_TIME ++ local_rng_state.r[which] ^= splitmix64(time_us_64()); ++ which ^= 1; ++#endif ++#if PICO_RAND_ENTROPY_SRC_ROSC ++ local_rng_state.r[which] ^= splitmix64(capture_additional_rosc_samples(PICO_RAND_ROSC_BIT_SAMPLE_COUNT)); ++ which ^= 1; ++#endif ++#if PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER ++ uint32_t bus_counter_value = bus_ctrl_hw->counter[bus_counter_idx].value; ++ // counter is saturating, so clear it if it has reached saturation ++ if (bus_counter_value == BUSCTRL_PERFCTR0_BITS) { ++ bus_ctrl_hw->counter[bus_counter_idx].value = 0; ++ } ++ local_rng_state.r[which] ^= splitmix64(bus_counter_value); ++ which ^= 1; ++#endif ++ ++ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_RAND); ++ uint32_t save = spin_lock_blocking(lock); ++ if (local_check_byte != check_byte) { ++ // someone got a random number in the interim, so mix it in ++ local_rng_state.r[0] ^= rng_state.r[0]; ++ local_rng_state.r[1] ^= rng_state.r[1]; ++ } ++ // Generate a 64-bit RN from the modified PRNG state. ++ // Note: This also "churns" the 128-bit state for next time. ++ uint64_t rand64 = xoroshiro128ss(&local_rng_state); ++ rng_state = local_rng_state; ++ check_byte++; ++ spin_unlock(lock, save); ++ ++ return rand64; ++} ++ ++void get_rand_128(rng_128_t *ptr128) { ++ ptr128->r[0] = get_rand_64(); ++ ptr128->r[1] = get_rand_64(); ++} ++ ++uint32_t get_rand_32(void) { ++ return (uint32_t) get_rand_64(); ++} +diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/trng_api.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/trng_api.c +new file mode 100644 +index 0000000000..b0886badcc +--- /dev/null ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/trng_api.c +@@ -0,0 +1,64 @@ ++/* mbed Microcontroller Library ++ * Copyright (c) 2018 GigaDevice Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: Apache-2.0 ++ * ++ * 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. ++ */ ++#if DEVICE_TRNG ++ ++#include "trng_api.h" ++ ++/** Initialize the TRNG peripheral ++ * ++ * @param obj The TRNG object ++ */ ++void trng_init(trng_t *obj) ++{ ++ (void)obj; ++} ++ ++/** Deinitialize the TRNG peripheral ++ * ++ * @param obj The TRNG object ++ */ ++void trng_free(trng_t *obj) ++{ ++ (void)obj; ++} ++ ++/** Get random data from TRNG peripheral ++ * ++ * @param obj The TRNG object ++ * @param output The pointer to an output array ++ * @param length The size of output data, to avoid buffer overwrite ++ * @param output_length The length of generated data ++ * @return 0 success, -1 fail ++ */ ++int trng_get_bytes(trng_t *obj, uint8_t *output, size_t length, size_t *output_length) ++{ ++ (void)obj; ++ *output_length = 0; ++ uint32_t random[16]; ++ ++ while (*output_length < length) { ++ get_rand_128((rng_128_t*)random); ++ for (uint8_t i = 0; (i < 16) && (*output_length < length) ; i++) { ++ *output++ = random[i]; ++ *output_length += 1; ++ random[i] = 0; ++ } ++ } ++ return 0; ++} ++#endif /* DEVICE_TRNG */ +diff --git a/targets/targets.json b/targets/targets.json +index 9a12422336..83fa8c930a 100644 +--- a/targets/targets.json ++++ b/targets/targets.json +@@ -9700,7 +9700,8 @@ + "USTICKER", + "WATCHDOG", + "USBDEVICE", +- "RESET_REASON" ++ "RESET_REASON", ++ "TRNG" + ] + }, + "NANO_RP2040_CONNECT": { +-- +2.43.0 +