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 #if defined(__GNUC__)
24
25 static struct k_spinlock rand32_lock;
26
27 /**
28 * @brief Get a 32 bit random number
29 *
30 * This pseudo-random number generator returns values that are based off the
31 * target's clock counter, which means that successive calls will return
32 * different values.
33 *
34 * @return a 32-bit number
35 */
z_impl_sys_rand32_get(void)36 uint32_t z_impl_sys_rand32_get(void)
37 {
38 /* initial seed value */
39 static uint64_t state = (uint64_t)CONFIG_TIMER_RANDOM_INITIAL_STATE;
40 k_spinlock_key_t key = k_spin_lock(&rand32_lock);
41
42 state = state + k_cycle_get_32();
43 state = state * 2862933555777941757ULL + 3037000493ULL;
44 uint32_t val = (uint32_t)(state >> 32);
45
46 k_spin_unlock(&rand32_lock, key);
47 return val;
48 }
49
50 /**
51 * @brief Fill destination buffer with random numbers
52 *
53 * The pseudo-random number generator returns values that are based off the
54 * target's clock counter, which means that successive calls will return
55 * different values.
56 *
57 * @param dst destination buffer to fill
58 * @param outlen size of destination buffer to fill
59 */
z_impl_sys_rand_get(void * dst,size_t outlen)60 void z_impl_sys_rand_get(void *dst, size_t outlen)
61 {
62 uint8_t *udst = dst;
63 uint32_t blocksize;
64 uint32_t ret;
65
66 while (outlen) {
67 ret = sys_rand32_get();
68 blocksize = MIN(outlen, sizeof(ret));
69 (void)memcpy((void *)udst, &ret, blocksize);
70 udst += blocksize;
71 outlen -= blocksize;
72 }
73 }
74 #endif /* __GNUC__ */
75