| /* |
| * Copyright (c) 2021, Commonwealth Scientific and Industrial Research |
| * Organisation (CSIRO) ABN 41 687 119 230. |
| * |
| * SPDX-License-Identifier: CC0-1.0 |
| * |
| * Based on code written in 2019 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 <http://creativecommons.org/publicdomain/zero/1.0/>. |
| * |
| * From: https://prng.di.unimi.it/xoshiro128plusplus.c |
| * |
| * This is xoshiro128++ 1.0, one of our 32-bit all-purpose, rock-solid |
| * generators. It has excellent speed, a state size (128 bits) that is |
| * large enough for mild parallelism, and it passes all tests we are aware |
| * of. |
| * |
| * For generating just single-precision (i.e., 32-bit) floating-point |
| * numbers, xoshiro128+ is even faster. |
| * |
| * The state must be seeded so that it is not everywhere zero. |
| */ |
| |
| #include <init.h> |
| #include <device.h> |
| #include <drivers/entropy.h> |
| #include <kernel.h> |
| #include <string.h> |
| |
| static uint32_t state[4]; |
| |
| static inline uint32_t rotl(const uint32_t x, int k) |
| { |
| return (x << k) | (x >> (32 - k)); |
| } |
| |
| static int xoshiro128_initialize(const struct device *dev) |
| { |
| dev = device_get_binding(DT_CHOSEN_ZEPHYR_ENTROPY_LABEL); |
| if (!dev) { |
| return -EINVAL; |
| } |
| |
| int32_t rc = entropy_get_entropy_isr(dev, (uint8_t *)&state, |
| sizeof(state), ENTROPY_BUSYWAIT); |
| |
| if (rc == -ENOTSUP) { |
| /* Driver does not provide an ISR-specific API, assume it can |
| * be called from ISR context |
| */ |
| rc = entropy_get_entropy(dev, (uint8_t *)&state, sizeof(state)); |
| } |
| |
| if (rc < 0) { |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| static uint32_t xoshiro128_next(void) |
| { |
| const uint32_t result = rotl(state[0] + state[3], 7) + state[0]; |
| |
| const uint32_t t = state[1] << 9; |
| |
| state[2] ^= state[0]; |
| state[3] ^= state[1]; |
| state[1] ^= state[2]; |
| state[0] ^= state[3]; |
| |
| state[2] ^= t; |
| |
| state[3] = rotl(state[3], 11); |
| |
| return result; |
| } |
| |
| uint32_t z_impl_sys_rand32_get(void) |
| { |
| uint32_t ret; |
| |
| ret = xoshiro128_next(); |
| |
| return ret; |
| } |
| |
| void z_impl_sys_rand_get(void *dst, size_t outlen) |
| { |
| size_t blocks = outlen / sizeof(uint32_t); |
| size_t rem = (outlen - (blocks * sizeof(uint32_t))); |
| uint32_t *unaligned = dst; |
| uint32_t ret; |
| |
| /* Write all full 32bit chunks */ |
| while (blocks--) { |
| UNALIGNED_PUT(xoshiro128_next(), unaligned++); |
| } |
| /* Write trailing bytes */ |
| if (rem) { |
| ret = xoshiro128_next(); |
| memcpy(unaligned, &ret, rem); |
| } |
| } |
| |
| /* In-tree entropy drivers will initialize in PRE_KERNEL_1; ensure that they're |
| * initialized properly before initializing ourselves. |
| */ |
| SYS_INIT(xoshiro128_initialize, PRE_KERNEL_2, |
| CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); |