1 /*
2  * Copyright (c) 2013-2015 Wind River Systems, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Non-random number generator based on system timer
10  *
11  * This module provides a non-random implementation of sys_rand32_get(), which
12  * is not meant to be used in a final product as a truly random number
13  * generator. It was provided to allow testing on a platform that does not (yet)
14  * provide a random number generator.
15  */
16 
17 #include <zephyr/random/random.h>
18 #include <zephyr/drivers/timer/system_timer.h>
19 #include <zephyr/kernel.h>
20 #include <zephyr/spinlock.h>
21 #include <string.h>
22 
23 static struct k_spinlock rand32_lock;
24 
25 /**
26  * @brief Get a 32 bit random number
27  *
28  * This pseudo-random number generator returns values that are based off the
29  * target's clock counter, which means that successive calls will return
30  * different values.
31  *
32  * @return a 32-bit number
33  */
rand32_get(void)34 static inline uint32_t rand32_get(void)
35 {
36 	/* initial seed value */
37 	static uint64_t state = (uint64_t)CONFIG_TIMER_RANDOM_INITIAL_STATE;
38 	k_spinlock_key_t key = k_spin_lock(&rand32_lock);
39 
40 	state = state + k_cycle_get_32();
41 	state = state * 2862933555777941757ULL + 3037000493ULL;
42 	uint32_t val = (uint32_t)(state >> 32);
43 
44 	k_spin_unlock(&rand32_lock, key);
45 	return val;
46 }
47 
48 /**
49  * @brief Fill destination buffer with random numbers
50  *
51  * The pseudo-random number generator returns values that are based off the
52  * target's clock counter, which means that successive calls will return
53  * different values.
54  *
55  * @param dst destination buffer to fill
56  * @param outlen size of destination buffer to fill
57  */
z_impl_sys_rand_get(void * dst,size_t outlen)58 void z_impl_sys_rand_get(void *dst, size_t outlen)
59 {
60 	uint8_t *udst = dst;
61 	uint32_t blocksize;
62 	uint32_t ret;
63 
64 	while (outlen > 0) {
65 		ret = rand32_get();
66 		blocksize = MIN(outlen, sizeof(ret));
67 		(void)memcpy((void *)udst, &ret, blocksize);
68 		udst += blocksize;
69 		outlen -= blocksize;
70 	}
71 }
72