1 /*
2  * Copyright (c) 2018 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Pseudo-random entropy generator for native simulator based target boards:
7  * Following the principle of reproducibility of the native_sim board
8  * this entropy device will always generate the same random sequence when
9  * initialized with the same seed
10  *
11  * This entropy source should only be used for testing.
12  */
13 
14 #include <zephyr/devicetree.h>
15 #if DT_HAS_COMPAT_STATUS_OKAY(zephyr_native_posix_rng)
16 #define DT_DRV_COMPAT zephyr_native_posix_rng
17 #warning "zephyr,native-posix-rng is deprecated in favor of zephyr,native-sim-rng"
18 #else
19 #define DT_DRV_COMPAT zephyr_native_sim_rng
20 #endif
21 
22 #include <zephyr/device.h>
23 #include <zephyr/drivers/entropy.h>
24 #include <zephyr/init.h>
25 #include <zephyr/sys/util.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <zephyr/arch/posix/posix_trace.h>
29 #include "soc.h"
30 #include "cmdline.h" /* native_sim command line options header */
31 #include "nsi_host_trampolines.h"
32 #include "fake_entropy_native_bottom.h"
33 
34 static unsigned int seed = 0x5678;
35 static bool seed_random;
36 static bool seed_set;
37 
entropy_native_sim_get_entropy(const struct device * dev,uint8_t * buffer,uint16_t length)38 static int entropy_native_sim_get_entropy(const struct device *dev,
39 					    uint8_t *buffer,
40 					    uint16_t length)
41 {
42 	ARG_UNUSED(dev);
43 
44 	while (length) {
45 		/*
46 		 * Note that only 1 thread (Zephyr thread or HW models), runs at
47 		 * a time, therefore there is no need to use random_r()
48 		 */
49 		long value = nsi_host_random();
50 
51 		/* The host random() provides a number between 0 and 2**31-1. Bit 32 is always 0.
52 		 * So let's just use the lower 3 bytes discarding the upper 7 bits
53 		 */
54 		size_t to_copy = MIN(length, 3);
55 
56 		memcpy(buffer, &value, to_copy);
57 		buffer += to_copy;
58 		length -= to_copy;
59 	}
60 
61 	return 0;
62 }
63 
entropy_native_sim_get_entropy_isr(const struct device * dev,uint8_t * buf,uint16_t len,uint32_t flags)64 static int entropy_native_sim_get_entropy_isr(const struct device *dev,
65 						uint8_t *buf,
66 						uint16_t len, uint32_t flags)
67 {
68 	ARG_UNUSED(flags);
69 
70 	/*
71 	 * entropy_native_sim_get_entropy() is also safe for ISRs
72 	 * and always produces data.
73 	 */
74 	entropy_native_sim_get_entropy(dev, buf, len);
75 
76 	return len;
77 }
78 
entropy_native_sim_init(const struct device * dev)79 static int entropy_native_sim_init(const struct device *dev)
80 {
81 	ARG_UNUSED(dev);
82 	if (seed_set || seed_random ||
83 	    IS_ENABLED(CONFIG_FAKE_ENTROPY_NATIVE_SIM_SEED_BY_DEFAULT)) {
84 		entropy_native_seed(seed, seed_random);
85 	}
86 	posix_print_warning("WARNING: "
87 			    "Using a test - not safe - entropy source\n");
88 	return 0;
89 }
90 
91 static DEVICE_API(entropy, entropy_native_sim_api_funcs) = {
92 	.get_entropy     = entropy_native_sim_get_entropy,
93 	.get_entropy_isr = entropy_native_sim_get_entropy_isr
94 };
95 
96 DEVICE_DT_INST_DEFINE(0,
97 		    entropy_native_sim_init, NULL,
98 		    NULL, NULL,
99 		    PRE_KERNEL_1, CONFIG_ENTROPY_INIT_PRIORITY,
100 		    &entropy_native_sim_api_funcs);
101 
seed_was_set(char * argv,int offset)102 static void seed_was_set(char *argv, int offset)
103 {
104 	ARG_UNUSED(argv);
105 	ARG_UNUSED(offset);
106 	seed_set = true;
107 }
108 
add_fake_entropy_option(void)109 static void add_fake_entropy_option(void)
110 {
111 	static struct args_struct_t entropy_options[] = {
112 		{
113 			.option = "seed",
114 			.name = "r_seed",
115 			.type = 'u',
116 			.dest = (void *)&seed,
117 			.call_when_found = seed_was_set,
118 			.descript = "A 32-bit integer seed value for the entropy device, such as "
119 				    "97229 (decimal), 0x17BCD (hex), or 0275715 (octal)"
120 		},
121 		{
122 			.is_switch = true,
123 			.option = "seed-random",
124 			.type = 'b',
125 			.dest = (void *)&seed_random,
126 			.descript = "Seed the random generator from /dev/urandom. "
127 				    "Note your test may not be reproducible if you set this option"
128 		},
129 		ARG_TABLE_ENDMARKER
130 	};
131 
132 	native_add_command_line_opts(entropy_options);
133 }
134 
135 NATIVE_TASK(add_fake_entropy_option, PRE_BOOT_1, 10);
136