|
| 1 | +From ac5c21fad54214e10a3558f29195d7ea70b4ccec Mon Sep 17 00:00:00 2001 |
| 2 | +From: pennam <m.pennasilico@arduino.cc> |
| 3 | +Date: Mon, 17 Jun 2024 10:19:14 +0200 |
| 4 | +Subject: [PATCH] RP2040: add pico_rand support |
| 5 | + |
| 6 | +--- |
| 7 | + .../TARGET_RP2040/CMakeLists.txt | 2 + |
| 8 | + .../TARGET_RP2040/objects.h | 7 + |
| 9 | + .../pico-sdk/rp2_common/CMakeLists.txt | 1 + |
| 10 | + .../hardware_sync/include/hardware/sync.h | 5 + |
| 11 | + .../pico_platform/include/pico/platform.h | 6 +- |
| 12 | + .../rp2_common/pico_rand/CMakeLists.txt | 13 + |
| 13 | + .../rp2_common/pico_rand/include/pico/rand.h | 185 +++++++++++ |
| 14 | + .../pico-sdk/rp2_common/pico_rand/rand.c | 305 ++++++++++++++++++ |
| 15 | + .../TARGET_RP2040/trng_api.c | 64 ++++ |
| 16 | + targets/targets.json | 3 +- |
| 17 | + 10 files changed, 587 insertions(+), 4 deletions(-) |
| 18 | + create mode 100644 targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/CMakeLists.txt |
| 19 | + create mode 100644 targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/include/pico/rand.h |
| 20 | + create mode 100644 targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/rand.c |
| 21 | + create mode 100644 targets/TARGET_RASPBERRYPI/TARGET_RP2040/trng_api.c |
| 22 | + |
| 23 | +diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/CMakeLists.txt |
| 24 | +index 4fadf6091e..4e9bae47ce 100644 |
| 25 | +--- a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/CMakeLists.txt |
| 26 | ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/CMakeLists.txt |
| 27 | +@@ -36,6 +36,7 @@ target_include_directories(mbed-rp2040 |
| 28 | + pico-sdk/common/pico_base/include |
| 29 | + pico-sdk/common/pico_binary_info/include |
| 30 | + pico-sdk/common/pico_util/include |
| 31 | ++ pico-sdk/common/pico_rand/include |
| 32 | + pico-sdk/boards/include |
| 33 | + pico-sdk/generated |
| 34 | + . |
| 35 | +@@ -71,6 +72,7 @@ target_sources(mbed-rp2040 |
| 36 | + pico-sdk/rp2_common/pico_bootrom/bootrom.c |
| 37 | + pico-sdk/rp2_common/pico_runtime/runtime.c |
| 38 | + pico-sdk/rp2_common/pico_platform/platform.c |
| 39 | ++ pico-sdk/rp2_common/pico_rand/rand.c |
| 40 | + pico-sdk/common/pico_sync/mutex.c |
| 41 | + pico-sdk/common/pico_time/time.c |
| 42 | + pico-sdk/common/pico_sync/lock_core.c |
| 43 | +diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/objects.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/objects.h |
| 44 | +index f5f44a58f4..0231968bb5 100644 |
| 45 | +--- a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/objects.h |
| 46 | ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/objects.h |
| 47 | +@@ -33,6 +33,7 @@ extern "C" { |
| 48 | + #include "pico/assert.h" |
| 49 | + #include "pico/time.h" |
| 50 | + #include "pico/types.h" |
| 51 | ++#include "pico/rand.h" |
| 52 | + #include "hardware/pwm.h" |
| 53 | + #include "hardware/adc.h" |
| 54 | + #include "hardware/resets.h" |
| 55 | +@@ -122,6 +123,12 @@ struct flash_s { |
| 56 | + uint32_t dummy; |
| 57 | + }; |
| 58 | + |
| 59 | ++#if DEVICE_TRNG |
| 60 | ++struct trng_s { |
| 61 | ++ uint8_t not_used; |
| 62 | ++}; |
| 63 | ++#endif |
| 64 | ++ |
| 65 | + typedef struct gpio_s gpio_t; |
| 66 | + typedef struct serial_s serial_t; |
| 67 | + |
| 68 | +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 |
| 69 | +index 4ca55becba..ec89c3ff71 100644 |
| 70 | +--- a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/CMakeLists.txt |
| 71 | ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/CMakeLists.txt |
| 72 | +@@ -49,6 +49,7 @@ if (NOT PICO_BARE_METAL) |
| 73 | + pico_add_subdirectory(pico_mem_ops) |
| 74 | + pico_add_subdirectory(pico_malloc) |
| 75 | + pico_add_subdirectory(pico_printf) |
| 76 | ++ pico_add_subdirectory(pico_rand) |
| 77 | + |
| 78 | + pico_add_subdirectory(pico_stdio) |
| 79 | + pico_add_subdirectory(pico_stdio_semihosting) |
| 80 | +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 |
| 81 | +index 8f91d55955..4f076aba02 100644 |
| 82 | +--- a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/include/hardware/sync.h |
| 83 | ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/include/hardware/sync.h |
| 84 | +@@ -70,6 +70,11 @@ typedef volatile uint32_t spin_lock_t; |
| 85 | + #define PICO_SPINLOCK_ID_HARDWARE_CLAIM 11 |
| 86 | + #endif |
| 87 | + |
| 88 | ++// PICO_CONFIG: PICO_SPINLOCK_ID_RAND, Spinlock ID for Random Number Generator, min=0, max=31, default=12, group=hardware_sync |
| 89 | ++#ifndef PICO_SPINLOCK_ID_RAND |
| 90 | ++#define PICO_SPINLOCK_ID_RAND 12 |
| 91 | ++#endif |
| 92 | ++ |
| 93 | + // 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 |
| 94 | + #ifndef PICO_SPINLOCK_ID_OS1 |
| 95 | + #define PICO_SPINLOCK_ID_OS1 14 |
| 96 | +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 |
| 97 | +index ee1d360cee..ea16d9734e 100644 |
| 98 | +--- a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/include/pico/platform.h |
| 99 | ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/include/pico/platform.h |
| 100 | +@@ -151,14 +151,14 @@ extern "C" { |
| 101 | + * |
| 102 | + * For example a `uint32_t` foo that will retain its value if the program is restarted by reset. |
| 103 | + * |
| 104 | +- * uint32_t __uninitialized_ram("my_group_name") foo; |
| 105 | ++ * uint32_t __uninitialized_ram(foo); |
| 106 | + * |
| 107 | +- * The section attribute is `.uninitialized_ram.<group>` |
| 108 | ++ * The section attribute is `.uninitialized_data.<group>` |
| 109 | + * |
| 110 | + * \param group a string suffix to use in the section name to distinguish groups that can be linker |
| 111 | + * garbage-collected independently |
| 112 | + */ |
| 113 | +-#define __uninitialized_ram(group) __attribute__((section(".uninitialized_ram." #group))) group |
| 114 | ++#define __uninitialized_ram(group) __attribute__((section(".uninitialized_data." #group))) group |
| 115 | + |
| 116 | + /*! \brief Section attribute macro for placement in flash even in a COPY_TO_RAM binary |
| 117 | + * \ingroup pico_platform |
| 118 | +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 |
| 119 | +new file mode 100644 |
| 120 | +index 0000000000..0e72bb5ab6 |
| 121 | +--- /dev/null |
| 122 | ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/CMakeLists.txt |
| 123 | +@@ -0,0 +1,13 @@ |
| 124 | ++pico_add_library(pico_rand) |
| 125 | ++ |
| 126 | ++target_sources(pico_rand INTERFACE |
| 127 | ++ ${CMAKE_CURRENT_LIST_DIR}/rand.c |
| 128 | ++) |
| 129 | ++ |
| 130 | ++target_include_directories(pico_rand_headers INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) |
| 131 | ++ |
| 132 | ++pico_mirrored_target_link_libraries(pico_rand INTERFACE |
| 133 | ++ pico_unique_id |
| 134 | ++ hardware_clocks |
| 135 | ++ hardware_timer |
| 136 | ++ hardware_sync) |
| 137 | +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 |
| 138 | +new file mode 100644 |
| 139 | +index 0000000000..20fc6d6cb1 |
| 140 | +--- /dev/null |
| 141 | ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/include/pico/rand.h |
| 142 | +@@ -0,0 +1,185 @@ |
| 143 | ++/* |
| 144 | ++ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd. |
| 145 | ++ * |
| 146 | ++ * SPDX-License-Identifier: BSD-3-Clause |
| 147 | ++ */ |
| 148 | ++ |
| 149 | ++#ifndef _PICO_RAND_H |
| 150 | ++#define _PICO_RAND_H |
| 151 | ++ |
| 152 | ++#include "pico.h" |
| 153 | ++ |
| 154 | ++#ifdef __cplusplus |
| 155 | ++extern "C" { |
| 156 | ++#endif |
| 157 | ++ |
| 158 | ++/** \file pico/rand.h |
| 159 | ++ * \defgroup pico_rand pico_rand |
| 160 | ++ * |
| 161 | ++ * Random Number Generator API |
| 162 | ++ * |
| 163 | ++ * This module generates random numbers at runtime utilizing a number of possible entropy |
| 164 | ++ * sources and uses those sources to modify the state of a 128-bit 'Pseudo |
| 165 | ++ * Random Number Generator' implemented in software. |
| 166 | ++ * |
| 167 | ++ * The random numbers (32 to 128 bit) to be supplied are read from the PRNG which is used |
| 168 | ++ * to help provide a large number space. |
| 169 | ++ * |
| 170 | ++ * The following (multiple) sources of entropy are available (of varying quality), each enabled by a #define: |
| 171 | ++ * |
| 172 | ++ * - The Ring Oscillator (ROSC) (\ref PICO_RAND_ENTROPY_SRC_ROSC == 1): |
| 173 | ++ * \ref PICO_RAND_ROSC_BIT_SAMPLE_COUNT bits are gathered from the ring oscillator "random bit" and mixed in each |
| 174 | ++ * time. This should not be used if the ROSC is off, or the processor is running from |
| 175 | ++ * the ROSC. |
| 176 | ++ * \note the maximum throughput of ROSC bit sampling is controlled by PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US which defaults |
| 177 | ++ * to 10us, i.e. 100,000 bits per second. |
| 178 | ++ * - Time (\ref PICO_RAND_ENTROPY_SRC_TIME == 1): The 64-bit microsecond timer is mixed in each time. |
| 179 | ++ * - Bus Performance Counter (\ref PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER == 1): One of the bus fabric's performance |
| 180 | ++ * counters is mixed in each time. |
| 181 | ++ * |
| 182 | ++ * \note All entropy sources are hashed before application to the PRNG state machine. |
| 183 | ++ * |
| 184 | ++ * The \em first time a random number is requested, the 128-bit PRNG state |
| 185 | ++ * must be seeded. Multiple entropy sources are also available for the seeding operation: |
| 186 | ++ * |
| 187 | ++ * - The Ring Oscillator (ROSC) (\ref PICO_RAND_SEED_ENTROPY_SRC_ROSC == 1): |
| 188 | ++ * 64 bits are gathered from the ring oscillator "random bit" and mixed into the seed. |
| 189 | ++ * - Time (\ref PICO_RAND_SEED_ENTROPY_SRC_TIME == 1): The 64-bit microsecond timer is mixed into the seed. |
| 190 | ++ * - Board Identifier (PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID == 1): The board id via \ref pico_get_unique_board_id |
| 191 | ++ * is mixed into the seed. |
| 192 | ++ * - RAM hash (\ref PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH (\ref PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH): The hashed contents of a |
| 193 | ++ * subset of RAM are mixed in. Initial RAM contents are undefined on power up, so provide a reasonable source of entropy. |
| 194 | ++ * By default the last 1K of RAM (which usually contains the core 0 stack) is hashed, which may also provide for differences |
| 195 | ++ * after each warm reset. |
| 196 | ++ * |
| 197 | ++ * With default settings, the seed generation takes approximately 1 millisecond while |
| 198 | ++ * subsequent random numbers generally take between 10 and 20 microseconds to generate. |
| 199 | ++ * |
| 200 | ++ * pico_rand methods may be safely called from either core or from an IRQ, but be careful in the latter case as |
| 201 | ++ * the calls may block for a number of microseconds waiting on more entropy. |
| 202 | ++ */ |
| 203 | ++ |
| 204 | ++// --------------- |
| 205 | ++// ENTROPY SOURCES |
| 206 | ++// --------------- |
| 207 | ++ |
| 208 | ++// PICO_CONFIG: PICO_RAND_ENTROPY_SRC_ROSC, Enable/disable use of ROSC as an entropy source, type=bool, default=1, group=pico_rand |
| 209 | ++#ifndef PICO_RAND_ENTROPY_SRC_ROSC |
| 210 | ++#define PICO_RAND_ENTROPY_SRC_ROSC 1 |
| 211 | ++#endif |
| 212 | ++ |
| 213 | ++// PICO_CONFIG: PICO_RAND_ENTROPY_SRC_TIME, Enable/disable use of hardware timestamp as an entropy source, type=bool, default=1, group=pico_rand |
| 214 | ++#ifndef PICO_RAND_ENTROPY_SRC_TIME |
| 215 | ++#define PICO_RAND_ENTROPY_SRC_TIME 1 |
| 216 | ++#endif |
| 217 | ++ |
| 218 | ++// 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 |
| 219 | ++#ifndef PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER |
| 220 | ++#define PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER 1 |
| 221 | ++#endif |
| 222 | ++ |
| 223 | ++// -------------------- |
| 224 | ++// SEED ENTROPY SOURCES |
| 225 | ++// -------------------- |
| 226 | ++ |
| 227 | ++// 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 |
| 228 | ++#ifndef PICO_RAND_SEED_ENTROPY_SRC_ROSC |
| 229 | ++#define PICO_RAND_SEED_ENTROPY_SRC_ROSC PICO_RAND_ENTROPY_SRC_ROSC |
| 230 | ++#endif |
| 231 | ++ |
| 232 | ++// 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 |
| 233 | ++#ifndef PICO_RAND_SEED_ENTROPY_SRC_TIME |
| 234 | ++#define PICO_RAND_SEED_ENTROPY_SRC_TIME PICO_RAND_ENTROPY_SRC_TIME |
| 235 | ++#endif |
| 236 | ++ |
| 237 | ++// 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 |
| 238 | ++#ifndef PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID |
| 239 | ++#define PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID 0 |
| 240 | ++#endif |
| 241 | ++ |
| 242 | ++// 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 |
| 243 | ++#ifndef PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH |
| 244 | ++#define PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH 1 |
| 245 | ++#endif |
| 246 | ++ |
| 247 | ++// --------------------------------- |
| 248 | ++// PICO_RAND_ENTROPY_SRC_ROSC CONFIG |
| 249 | ++// --------------------------------- |
| 250 | ++ |
| 251 | ++// 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 |
| 252 | ++#ifndef PICO_RAND_ROSC_BIT_SAMPLE_COUNT |
| 253 | ++#define PICO_RAND_ROSC_BIT_SAMPLE_COUNT 1 |
| 254 | ++#endif |
| 255 | ++ |
| 256 | ++// 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 |
| 257 | ++#ifndef PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US |
| 258 | ++// (Arbitrary / tested) minimum time between sampling the ROSC random bit |
| 259 | ++#define PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US 10u |
| 260 | ++#endif |
| 261 | ++ |
| 262 | ++// --------------------------------------------- |
| 263 | ++// PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER CONFIG |
| 264 | ++// --------------------------------------------- |
| 265 | ++ |
| 266 | ++// PICO_CONFIG: PICO_RAND_BUS_PERF_COUNTER_INDEX, Bus performance counter index to use for sourcing entropy, min=0, max=3, group=pico_rand |
| 267 | ++// this is deliberately undefined by default, meaning the code will pick that appears unused |
| 268 | ++//#define PICO_RAND_BUS_PERF_COUNTER_INDEX 0 |
| 269 | ++ |
| 270 | ++// 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 |
| 271 | ++#ifndef PICO_RAND_BUS_PERF_COUNTER_EVENT |
| 272 | ++#define PICO_RAND_BUS_PERF_COUNTER_EVENT arbiter_sram5_perf_event_access |
| 273 | ++#endif |
| 274 | ++ |
| 275 | ++// ------------------------------------------ |
| 276 | ++// PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH CONFIG |
| 277 | ++// ------------------------------------------ |
| 278 | ++ |
| 279 | ++// 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 |
| 280 | ++#ifndef PICO_RAND_RAM_HASH_END |
| 281 | ++#define PICO_RAND_RAM_HASH_END SRAM_END |
| 282 | ++#endif |
| 283 | ++// 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 |
| 284 | ++#ifndef PICO_RAND_RAM_HASH_START |
| 285 | ++#define PICO_RAND_RAM_HASH_START (PICO_RAND_RAM_HASH_END - 1024u) |
| 286 | ++#endif |
| 287 | ++ |
| 288 | ++// We provide a maximum of 128 bits entropy in one go |
| 289 | ++typedef struct rng_128 { |
| 290 | ++ uint64_t r[2]; |
| 291 | ++} rng_128_t; |
| 292 | ++ |
| 293 | ++/*! \brief Get 128-bit random number |
| 294 | ++ * \ingroup pico_rand |
| 295 | ++ * |
| 296 | ++ * This method may be safely called from either core or from an IRQ, but be careful in the latter case as |
| 297 | ++ * the call may block for a number of microseconds waiting on more entropy. |
| 298 | ++ * |
| 299 | ++ * \param rand128 Pointer to storage to accept a 128-bit random number |
| 300 | ++ */ |
| 301 | ++void get_rand_128(rng_128_t *rand128); |
| 302 | ++ |
| 303 | ++/*! \brief Get 64-bit random number |
| 304 | ++ * \ingroup pico_rand |
| 305 | ++ * |
| 306 | ++ * This method may be safely called from either core or from an IRQ, but be careful in the latter case as |
| 307 | ++ * the call may block for a number of microseconds waiting on more entropy. |
| 308 | ++ * |
| 309 | ++ * \return 64-bit random number |
| 310 | ++ */ |
| 311 | ++uint64_t get_rand_64(void); |
| 312 | ++ |
| 313 | ++/*! \brief Get 32-bit random number |
| 314 | ++ * \ingroup pico_rand |
| 315 | ++ * |
| 316 | ++ * This method may be safely called from either core or from an IRQ, but be careful in the latter case as |
| 317 | ++ * the call may block for a number of microseconds waiting on more entropy. |
| 318 | ++ * |
| 319 | ++ * \return 32-bit random number |
| 320 | ++ */ |
| 321 | ++uint32_t get_rand_32(void); |
| 322 | ++ |
| 323 | ++#ifdef __cplusplus |
| 324 | ++} |
| 325 | ++#endif |
| 326 | ++ |
| 327 | ++#endif |
| 328 | +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 |
| 329 | +new file mode 100644 |
| 330 | +index 0000000000..c73b80321e |
| 331 | +--- /dev/null |
| 332 | ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_rand/rand.c |
| 333 | +@@ -0,0 +1,305 @@ |
| 334 | ++/* |
| 335 | ++ * Copyright (c) 2022 Raspberry Pi (Trading) Ltd. |
| 336 | ++ * |
| 337 | ++ * SPDX-License-Identifier: BSD-3-Clause |
| 338 | ++ */ |
| 339 | ++ |
| 340 | ++/* xoroshiro128ss(), rotl(): |
| 341 | ++ |
| 342 | ++ Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) |
| 343 | ++ |
| 344 | ++ To the extent possible under law, the author has dedicated all copyright |
| 345 | ++ and related and neighboring rights to this software to the public domain |
| 346 | ++ worldwide. This software is distributed without any warranty. |
| 347 | ++ |
| 348 | ++ See <http://creativecommons.org/publicdomain/zero/1.0/> |
| 349 | ++ |
| 350 | ++ splitmix64() implementation: |
| 351 | ++ |
| 352 | ++ Written in 2015 by Sebastiano Vigna (vigna@acm.org) |
| 353 | ++ To the extent possible under law, the author has dedicated all copyright |
| 354 | ++ and related and neighboring rights to this software to the public domain |
| 355 | ++ worldwide. This software is distributed without any warranty. |
| 356 | ++ |
| 357 | ++ See <http://creativecommons.org/publicdomain/zero/1.0/> |
| 358 | ++*/ |
| 359 | ++ |
| 360 | ++#include "pico/rand.h" |
| 361 | ++#if PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID |
| 362 | ++#include "pico/unique_id.h" |
| 363 | ++#endif |
| 364 | ++#include "pico/time.h" |
| 365 | ++#include "hardware/clocks.h" |
| 366 | ++#include "hardware/structs/rosc.h" |
| 367 | ++#include "hardware/structs/bus_ctrl.h" |
| 368 | ++#include "hardware/sync.h" |
| 369 | ++ |
| 370 | ++static bool rng_initialised = false; |
| 371 | ++ |
| 372 | ++// Note: By design, do not initialise any of the variables that hold entropy, |
| 373 | ++// they may have useful junk in them, either from power-up or a previous boot. |
| 374 | ++static rng_128_t __uninitialized_ram(rng_state); |
| 375 | ++#if PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH |
| 376 | ++static uint64_t __uninitialized_ram(ram_hash); |
| 377 | ++#endif |
| 378 | ++ |
| 379 | ++#if PICO_RAND_ENTROPY_SRC_ROSC | PICO_RAND_SEED_ENTROPY_SRC_ROSC |
| 380 | ++static uint64_t __uninitialized_ram(rosc_samples); |
| 381 | ++#endif |
| 382 | ++ |
| 383 | ++#if PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER |
| 384 | ++static uint8_t bus_counter_idx; |
| 385 | ++#endif |
| 386 | ++ |
| 387 | ++/* From the original source: |
| 388 | ++ |
| 389 | ++ This is a fixed-increment version of Java 8's SplittableRandom generator |
| 390 | ++ See http://dx.doi.org/10.1145/2714064.2660195 and |
| 391 | ++ http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html |
| 392 | ++ |
| 393 | ++ It is a very fast generator passing BigCrush, and it can be useful if |
| 394 | ++ for some reason you absolutely want 64 bits of state; otherwise, we |
| 395 | ++ rather suggest to use a xoroshiro128+ (for moderately parallel |
| 396 | ++ computations) or xorshift1024* (for massively parallel computations) |
| 397 | ++ generator. |
| 398 | ++ |
| 399 | ++ Note: This can be called with any value (i.e. including 0) |
| 400 | ++*/ |
| 401 | ++static __noinline uint64_t splitmix64(uint64_t x) { |
| 402 | ++ uint64_t z = x + 0x9E3779B97F4A7C15ull; |
| 403 | ++ z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ull; |
| 404 | ++ z = (z ^ (z >> 27)) * 0x94D049BB133111EBull; |
| 405 | ++ return z ^ (z >> 31); |
| 406 | ++} |
| 407 | ++ |
| 408 | ++/* From the original source: |
| 409 | ++ |
| 410 | ++ This is xoroshiro128** 1.0, one of our all-purpose, rock-solid, |
| 411 | ++ small-state generators. It is extremely (sub-ns) fast and it passes all |
| 412 | ++ tests we are aware of, but its state space is large enough only for |
| 413 | ++ mild parallelism. |
| 414 | ++ |
| 415 | ++ For generating just floating-point numbers, xoroshiro128+ is even |
| 416 | ++ faster (but it has a very mild bias, see notes in the comments). |
| 417 | ++ |
| 418 | ++ The state must be seeded so that it is not everywhere zero. If you have |
| 419 | ++ a 64-bit seed, we suggest to seed a splitmix64 generator and use its |
| 420 | ++ output to fill s. |
| 421 | ++*/ |
| 422 | ++static inline uint64_t rotl(const uint64_t x, int k) { |
| 423 | ++ return (x << k) | (x >> (64 - k)); |
| 424 | ++} |
| 425 | ++ |
| 426 | ++static __noinline uint64_t xoroshiro128ss(rng_128_t *local_rng_state) { |
| 427 | ++ const uint64_t s0 = local_rng_state->r[0]; |
| 428 | ++ uint64_t s1 = local_rng_state->r[1]; |
| 429 | ++ |
| 430 | ++ // Because the state is *modified* outside of this function, there is a |
| 431 | ++ // 1 in 2^128 chance that it could be all zeroes (which is not allowed). |
| 432 | ++ while (s0 == 0 && s1 == 0) { |
| 433 | ++ s1 = time_us_64(); // should not be 0, but loop anyway |
| 434 | ++ } |
| 435 | ++ |
| 436 | ++ const uint64_t result = rotl(s0 * 5, 7) * 9; |
| 437 | ++ |
| 438 | ++ s1 ^= s0; |
| 439 | ++ local_rng_state->r[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b |
| 440 | ++ local_rng_state->r[1] = rotl(s1, 37); // c |
| 441 | ++ |
| 442 | ++ return result; |
| 443 | ++} |
| 444 | ++ |
| 445 | ++#if PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH |
| 446 | ++static uint64_t sdbm_hash64_sram(uint64_t hash) { |
| 447 | ++ // save some time by hashing a word at a time |
| 448 | ++ for (uint i = (PICO_RAND_RAM_HASH_START + 3) & ~3; i < PICO_RAND_RAM_HASH_END; i+=4) { |
| 449 | ++ uint32_t c = *(uint32_t *) i; |
| 450 | ++ hash = (uint64_t) c + (hash << 6) + (hash << 16) - hash; |
| 451 | ++ } |
| 452 | ++ return hash; |
| 453 | ++} |
| 454 | ++#endif |
| 455 | ++ |
| 456 | ++#if PICO_RAND_SEED_ENTROPY_SRC_ROSC | PICO_RAND_ENTROPY_SRC_ROSC |
| 457 | ++/* gather an additional n bits of entropy, and shift them into the 64 bit entropy counter */ |
| 458 | ++static uint64_t capture_additional_rosc_samples(uint n) { |
| 459 | ++ static absolute_time_t next_sample_time; |
| 460 | ++ |
| 461 | ++ // provide an override if someone really wants it, but disabling ROSC as an entropy source makes more sense |
| 462 | ++#if !PICO_RAND_DISABLE_ROSC_CHECK |
| 463 | ++ // check that the ROSC is running but that the processors are NOT running from it |
| 464 | ++ hard_assert((rosc_hw->status & ROSC_STATUS_ENABLED_BITS) && |
| 465 | ++ ((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))); |
| 466 | ++#endif |
| 467 | ++ |
| 468 | ++ bool in_exception = __get_current_exception(); |
| 469 | ++ assert(n); // save us having to special case samples for this |
| 470 | ++ uint64_t samples = 0; |
| 471 | ++ for(uint i=0; i<n; i++) { |
| 472 | ++ bool bit_done = false; |
| 473 | ++ do { |
| 474 | ++ // Ensure that the ROSC random bit is not sampled too quickly, |
| 475 | ++ // ROSC may be ticking only a few times a microsecond. |
| 476 | ++ // Note: In general (i.e. sporadic) use, very often there will be no delay here. |
| 477 | ++ |
| 478 | ++ // note this is not read under lock, so the two 32 bit halves could be skewed, but in that |
| 479 | ++ // case we'll fail the check later, which is fine in this rare case |
| 480 | ++ absolute_time_t cached_next_sample_time = next_sample_time; |
| 481 | ++ // we support being called from IRQ, so be careful about sleeping... still not |
| 482 | ++ // ideal, but not much that can be done |
| 483 | ++ if (in_exception) { |
| 484 | ++ busy_wait_until(next_sample_time); |
| 485 | ++ } else { |
| 486 | ++ sleep_until(next_sample_time); |
| 487 | ++ } |
| 488 | ++ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_RAND); |
| 489 | ++ uint32_t save = spin_lock_blocking(lock); |
| 490 | ++ if (!absolute_time_diff_us(cached_next_sample_time, next_sample_time)) { |
| 491 | ++ // we won the race (if any) for the bit, so we collect it locally |
| 492 | ++ samples <<= 1; |
| 493 | ++ samples |= rosc_hw->randombit & 1u; |
| 494 | ++ // use of relative time to now, rather than offset from before makes things |
| 495 | ++ // a bit less predictable at the cost of some speed. |
| 496 | ++ next_sample_time = make_timeout_time_us(PICO_RAND_MIN_ROSC_BIT_SAMPLE_TIME_US); |
| 497 | ++ bit_done = true; |
| 498 | ++ if (i == n - 1) { |
| 499 | ++ // samples has our random bits, so let's mix them in now |
| 500 | ++ samples = rosc_samples = (rosc_samples << n) | samples; |
| 501 | ++ } |
| 502 | ++ } |
| 503 | ++ spin_unlock(lock, save); |
| 504 | ++ } while (!bit_done); |
| 505 | ++ } |
| 506 | ++ return samples; |
| 507 | ++} |
| 508 | ++#endif |
| 509 | ++ |
| 510 | ++static void initialise_rand(void) { |
| 511 | ++ rng_128_t local_rng_state = local_rng_state; |
| 512 | ++ uint which = 0; |
| 513 | ++#if PICO_RAND_SEED_ENTROPY_SRC_RAM_HASH |
| 514 | ++ ram_hash = sdbm_hash64_sram(ram_hash); |
| 515 | ++ local_rng_state.r[which] ^= splitmix64(ram_hash); |
| 516 | ++ which ^= 1; |
| 517 | ++#endif |
| 518 | ++ |
| 519 | ++#if PICO_RAND_SEED_ENTROPY_SRC_BOARD_ID |
| 520 | ++ static_assert(PICO_UNIQUE_BOARD_ID_SIZE_BYTES == sizeof(uint64_t), |
| 521 | ++ "Code below requires that 'board_id' is 64-bits in size"); |
| 522 | ++ |
| 523 | ++ // Note! The safety of the length assumption here is protected by a 'static_assert' above |
| 524 | ++ union unique_id_u { |
| 525 | ++ pico_unique_board_id_t board_id_native; |
| 526 | ++ uint64_t board_id_u64; |
| 527 | ++ } unique_id; |
| 528 | ++ // Note! The safety of the length assumption here is protected by a 'static_assert' above |
| 529 | ++ pico_get_unique_board_id(&unique_id.board_id_native); |
| 530 | ++ local_rng_state.r[which] ^= splitmix64(unique_id.board_id_u64); |
| 531 | ++ which ^= 1; |
| 532 | ++#endif |
| 533 | ++ |
| 534 | ++#if PICO_RAND_SEED_ENTROPY_SRC_ROSC |
| 535 | ++ // this is really quite slow (10ms per iteration), and I'm not sure that it adds value over the 64 random bits |
| 536 | ++// uint ref_khz = clock_get_hz(clk_ref) / 100; |
| 537 | ++// for (int i = 0; i < 5; i++) { |
| 538 | ++// // Apply hash of the rosc frequency, limited but still 'extra' entropy |
| 539 | ++// uint measurement = frequency_count_raw(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC, ref_khz); |
| 540 | ++// local_rng_state.r[which] ^= splitmix64(measurement); |
| 541 | ++// (void) xoroshiro128ss(&local_rng_state); //churn to mix seed sources |
| 542 | ++// } |
| 543 | ++ |
| 544 | ++ // Gather a full ROSC sample array with sample bits |
| 545 | ++ local_rng_state.r[which] ^= splitmix64(capture_additional_rosc_samples(8 * sizeof(rosc_samples))); |
| 546 | ++ which ^= 1; |
| 547 | ++#endif |
| 548 | ++ |
| 549 | ++#if PICO_RAND_SEED_ENTROPY_SRC_TIME |
| 550 | ++ // Mix in hashed time. This is [possibly] predictable boot-to-boot |
| 551 | ++ // but will vary application-to-application. |
| 552 | ++ local_rng_state.r[which] ^= splitmix64(time_us_64()); |
| 553 | ++ which ^= 1; |
| 554 | ++#endif |
| 555 | ++ |
| 556 | ++ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_RAND); |
| 557 | ++ uint32_t save = spin_lock_blocking(lock); |
| 558 | ++ if (!rng_initialised) { |
| 559 | ++#if PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER |
| 560 | ++#if !PICO_RAND_BUSCTRL_COUNTER_INDEX |
| 561 | ++ int idx = -1; |
| 562 | ++ for(uint i = 0; i < count_of(bus_ctrl_hw->counter); i++) { |
| 563 | ++ if (bus_ctrl_hw->counter[i].sel == BUSCTRL_PERFSEL0_RESET) { |
| 564 | ++ idx = (int)i; |
| 565 | ++ break; |
| 566 | ++ } |
| 567 | ++ } |
| 568 | ++ hard_assert(idx != -1); |
| 569 | ++ bus_counter_idx = (uint8_t)idx; |
| 570 | ++#else |
| 571 | ++ bus_counter_idx = (uint8_t)PICO_RAND_BUSCTRL_COUNTER_INDEX; |
| 572 | ++#endif |
| 573 | ++ bus_ctrl_hw->counter[bus_counter_idx].sel = PICO_RAND_BUS_PERF_COUNTER_EVENT; |
| 574 | ++#endif |
| 575 | ++ (void) xoroshiro128ss(&local_rng_state); |
| 576 | ++ rng_state = local_rng_state; |
| 577 | ++ rng_initialised = true; |
| 578 | ++ } |
| 579 | ++ spin_unlock(lock, save); |
| 580 | ++} |
| 581 | ++ |
| 582 | ++uint64_t get_rand_64(void) { |
| 583 | ++ if (!rng_initialised) { |
| 584 | ++ // Do not provide 'RNs' until the system has been initialised. Note: |
| 585 | ++ // The first initialisation can be quite time-consuming depending on |
| 586 | ++ // the amount of RAM hashed, see RAM_HASH_START and RAM_HASH_END |
| 587 | ++ initialise_rand(); |
| 588 | ++ } |
| 589 | ++ |
| 590 | ++ static volatile uint8_t check_byte; |
| 591 | ++ rng_128_t local_rng_state = rng_state; |
| 592 | ++ uint8_t local_check_byte = check_byte; |
| 593 | ++ // Modify PRNG state with the run-time entropy sources, |
| 594 | ++ // hashed to reduce correlation with previous modifications. |
| 595 | ++ uint which = 0; |
| 596 | ++#if PICO_RAND_ENTROPY_SRC_TIME |
| 597 | ++ local_rng_state.r[which] ^= splitmix64(time_us_64()); |
| 598 | ++ which ^= 1; |
| 599 | ++#endif |
| 600 | ++#if PICO_RAND_ENTROPY_SRC_ROSC |
| 601 | ++ local_rng_state.r[which] ^= splitmix64(capture_additional_rosc_samples(PICO_RAND_ROSC_BIT_SAMPLE_COUNT)); |
| 602 | ++ which ^= 1; |
| 603 | ++#endif |
| 604 | ++#if PICO_RAND_ENTROPY_SRC_BUS_PERF_COUNTER |
| 605 | ++ uint32_t bus_counter_value = bus_ctrl_hw->counter[bus_counter_idx].value; |
| 606 | ++ // counter is saturating, so clear it if it has reached saturation |
| 607 | ++ if (bus_counter_value == BUSCTRL_PERFCTR0_BITS) { |
| 608 | ++ bus_ctrl_hw->counter[bus_counter_idx].value = 0; |
| 609 | ++ } |
| 610 | ++ local_rng_state.r[which] ^= splitmix64(bus_counter_value); |
| 611 | ++ which ^= 1; |
| 612 | ++#endif |
| 613 | ++ |
| 614 | ++ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_RAND); |
| 615 | ++ uint32_t save = spin_lock_blocking(lock); |
| 616 | ++ if (local_check_byte != check_byte) { |
| 617 | ++ // someone got a random number in the interim, so mix it in |
| 618 | ++ local_rng_state.r[0] ^= rng_state.r[0]; |
| 619 | ++ local_rng_state.r[1] ^= rng_state.r[1]; |
| 620 | ++ } |
| 621 | ++ // Generate a 64-bit RN from the modified PRNG state. |
| 622 | ++ // Note: This also "churns" the 128-bit state for next time. |
| 623 | ++ uint64_t rand64 = xoroshiro128ss(&local_rng_state); |
| 624 | ++ rng_state = local_rng_state; |
| 625 | ++ check_byte++; |
| 626 | ++ spin_unlock(lock, save); |
| 627 | ++ |
| 628 | ++ return rand64; |
| 629 | ++} |
| 630 | ++ |
| 631 | ++void get_rand_128(rng_128_t *ptr128) { |
| 632 | ++ ptr128->r[0] = get_rand_64(); |
| 633 | ++ ptr128->r[1] = get_rand_64(); |
| 634 | ++} |
| 635 | ++ |
| 636 | ++uint32_t get_rand_32(void) { |
| 637 | ++ return (uint32_t) get_rand_64(); |
| 638 | ++} |
| 639 | +diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/trng_api.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/trng_api.c |
| 640 | +new file mode 100644 |
| 641 | +index 0000000000..b0886badcc |
| 642 | +--- /dev/null |
| 643 | ++++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/trng_api.c |
| 644 | +@@ -0,0 +1,64 @@ |
| 645 | ++/* mbed Microcontroller Library |
| 646 | ++ * Copyright (c) 2018 GigaDevice Semiconductor Inc. |
| 647 | ++ * |
| 648 | ++ * SPDX-License-Identifier: Apache-2.0 |
| 649 | ++ * |
| 650 | ++ * Licensed under the Apache License, Version 2.0 (the "License"); |
| 651 | ++ * you may not use this file except in compliance with the License. |
| 652 | ++ * You may obtain a copy of the License at |
| 653 | ++ * |
| 654 | ++ * http://www.apache.org/licenses/LICENSE-2.0 |
| 655 | ++ * |
| 656 | ++ * Unless required by applicable law or agreed to in writing, software |
| 657 | ++ * distributed under the License is distributed on an "AS IS" BASIS, |
| 658 | ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 659 | ++ * See the License for the specific language governing permissions and |
| 660 | ++ * limitations under the License. |
| 661 | ++ */ |
| 662 | ++#if DEVICE_TRNG |
| 663 | ++ |
| 664 | ++#include "trng_api.h" |
| 665 | ++ |
| 666 | ++/** Initialize the TRNG peripheral |
| 667 | ++ * |
| 668 | ++ * @param obj The TRNG object |
| 669 | ++ */ |
| 670 | ++void trng_init(trng_t *obj) |
| 671 | ++{ |
| 672 | ++ (void)obj; |
| 673 | ++} |
| 674 | ++ |
| 675 | ++/** Deinitialize the TRNG peripheral |
| 676 | ++ * |
| 677 | ++ * @param obj The TRNG object |
| 678 | ++ */ |
| 679 | ++void trng_free(trng_t *obj) |
| 680 | ++{ |
| 681 | ++ (void)obj; |
| 682 | ++} |
| 683 | ++ |
| 684 | ++/** Get random data from TRNG peripheral |
| 685 | ++ * |
| 686 | ++ * @param obj The TRNG object |
| 687 | ++ * @param output The pointer to an output array |
| 688 | ++ * @param length The size of output data, to avoid buffer overwrite |
| 689 | ++ * @param output_length The length of generated data |
| 690 | ++ * @return 0 success, -1 fail |
| 691 | ++ */ |
| 692 | ++int trng_get_bytes(trng_t *obj, uint8_t *output, size_t length, size_t *output_length) |
| 693 | ++{ |
| 694 | ++ (void)obj; |
| 695 | ++ *output_length = 0; |
| 696 | ++ uint32_t random[16]; |
| 697 | ++ |
| 698 | ++ while (*output_length < length) { |
| 699 | ++ get_rand_128((rng_128_t*)random); |
| 700 | ++ for (uint8_t i = 0; (i < 16) && (*output_length < length) ; i++) { |
| 701 | ++ *output++ = random[i]; |
| 702 | ++ *output_length += 1; |
| 703 | ++ random[i] = 0; |
| 704 | ++ } |
| 705 | ++ } |
| 706 | ++ return 0; |
| 707 | ++} |
| 708 | ++#endif /* DEVICE_TRNG */ |
| 709 | +diff --git a/targets/targets.json b/targets/targets.json |
| 710 | +index 9a12422336..83fa8c930a 100644 |
| 711 | +--- a/targets/targets.json |
| 712 | ++++ b/targets/targets.json |
| 713 | +@@ -9700,7 +9700,8 @@ |
| 714 | + "USTICKER", |
| 715 | + "WATCHDOG", |
| 716 | + "USBDEVICE", |
| 717 | +- "RESET_REASON" |
| 718 | ++ "RESET_REASON", |
| 719 | ++ "TRNG" |
| 720 | + ] |
| 721 | + }, |
| 722 | + "NANO_RP2040_CONNECT": { |
| 723 | +-- |
| 724 | +2.43.0 |
| 725 | + |
0 commit comments