| /* | 
 |  * 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 <zephyr/init.h> | 
 | #include <zephyr/device.h> | 
 | #include <zephyr/drivers/entropy.h> | 
 | #include <zephyr/kernel.h> | 
 | #include <string.h> | 
 |  | 
 | static const struct device *const entropy_driver = | 
 | 	DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy)); | 
 | static uint32_t state[4]; | 
 | static bool initialized; | 
 |  | 
 | static inline uint32_t rotl(const uint32_t x, int k) | 
 | { | 
 | 	return (x << k) | (x >> (32 - k)); | 
 | } | 
 |  | 
 | static int xoshiro128_initialize(void) | 
 | { | 
 | 	if (!device_is_ready(entropy_driver)) { | 
 | 		return -ENODEV; | 
 | 	} | 
 | 	return 0; | 
 | } | 
 |  | 
 | static void xoshiro128_init_state(void) | 
 | { | 
 | 	int rc; | 
 |  | 
 | 	/* This is not thread safe but it doesn't matter as we will just end | 
 | 	 * up with a mix of random bytes from both threads. | 
 | 	 */ | 
 | 	rc = entropy_get_entropy(entropy_driver, (uint8_t *)&state, sizeof(state)); | 
 | 	if (rc == 0) { | 
 | 		initialized = true; | 
 | 	} else { | 
 | 		/* Entropy device failed or is not yet ready. | 
 | 		 * Reseed the PRNG state with pseudo-random data until it can | 
 | 		 * be properly seeded. This may be needed if random numbers are | 
 | 		 * requested before the backing entropy device has been enabled. | 
 | 		 */ | 
 | 		state[0] = k_cycle_get_32(); | 
 | 		state[1] = k_cycle_get_32() ^ 0x9b64c2b0; | 
 | 		state[2] = k_cycle_get_32() ^ 0x86d3d2d4; | 
 | 		state[3] = k_cycle_get_32() ^ 0xa00ae278; | 
 | 	} | 
 | } | 
 |  | 
 | 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; | 
 | } | 
 |  | 
 | 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; | 
 |  | 
 | 	if (unlikely(!initialized)) { | 
 | 		xoshiro128_init_state(); | 
 | 	} | 
 |  | 
 | 	/* 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); |