Contiki-NG
soc-trng.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, University of Bristol - http://www.bristol.ac.uk
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 /*---------------------------------------------------------------------------*/
31 /**
32  * \addtogroup cc26xx-trng
33  * @{
34  *
35  * \file
36  *
37  * Implementation of the CC13xx/CC26xx RNG driver
38  */
39 /*---------------------------------------------------------------------------*/
40 #include "contiki.h"
41 #include "lpm.h"
42 #include "sys/process.h"
43 #include "dev/soc-trng.h"
44 #include "ti-lib.h"
45 
46 #include <stdbool.h>
47 #include <stdint.h>
48 #include <stddef.h>
49 /*---------------------------------------------------------------------------*/
50 #ifdef SOC_TRNG_CONF_CACHE_LEN
51 #define SOC_TRNG_CACHE_LEN SOC_TRNG_CONF_CACHE_LEN
52 #else
53 /** Size of the random number cache. Each slot holds 4 16-bit numbers */
54 #define SOC_TRNG_CACHE_LEN 4
55 #endif
56 /*---------------------------------------------------------------------------*/
57 #define MIN_REFILL_CYCLES_MAX 0x00000000
58 /*---------------------------------------------------------------------------*/
59 PROCESS(soc_trng_process, "CC13xx/CC26xx TRNG process");
60 /*---------------------------------------------------------------------------*/
61 static process_event_t rng_ready_event = PROCESS_EVENT_NONE;
62 /*---------------------------------------------------------------------------*/
63 static soc_trng_callback_t notify_cb = NULL;
64 /*---------------------------------------------------------------------------*/
65 #define soc_trng_isr TRNGIntHandler
66 /*---------------------------------------------------------------------------*/
67 static uint64_t rands_cache[SOC_TRNG_CACHE_LEN];
68 static bool rands_mask[SOC_TRNG_CACHE_LEN];
69 /*---------------------------------------------------------------------------*/
70 static void
71 disable_number_ready_interrupt(void)
72 {
73  ti_lib_trng_int_disable(TRNG_NUMBER_READY);
74  ti_lib_int_disable(INT_TRNG_IRQ);
75 }
76 /*---------------------------------------------------------------------------*/
77 static void
78 enable_number_ready_interrupt(void)
79 {
80  ti_lib_trng_int_clear(TRNG_NUMBER_READY);
81  ti_lib_trng_int_enable(TRNG_NUMBER_READY);
82  ti_lib_int_enable(INT_TRNG_IRQ);
83 }
84 /*---------------------------------------------------------------------------*/
85 static bool
86 accessible(void)
87 {
88  /* First, check the PD */
89  if(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH)
90  != PRCM_DOMAIN_POWER_ON) {
91  return false;
92  }
93 
94  /* Then check the 'run mode' clock gate */
95  if(!(HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) &
96  PRCM_SECDMACLKGDS_TRNG_CLK_EN_M)) {
97  return false;
98  }
99 
100  return true;
101 }
102 /*---------------------------------------------------------------------------*/
103 static void
104 power_up(void)
105 {
106  /* First, make sure the PERIPH PD is on */
107  ti_lib_prcm_power_domain_on(PRCM_DOMAIN_PERIPH);
108  while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH)
109  != PRCM_DOMAIN_POWER_ON));
110 
111  /* Enable clock in active mode */
112  ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_TRNG);
113  ti_lib_prcm_load_set();
114  while(!ti_lib_prcm_load_get());
115 }
116 /*---------------------------------------------------------------------------*/
117 static void
118 reset_synchronous(void)
119 {
120  ti_lib_trng_reset();
121  while(HWREG(TRNG_BASE + TRNG_O_SWRESET));
122 }
123 /*---------------------------------------------------------------------------*/
124 static uint8_t
125 request(void)
126 {
127  if(notify_cb) {
128  return LPM_MODE_SLEEP;
129  }
130  return LPM_MODE_MAX_SUPPORTED;
131 }
132 /*---------------------------------------------------------------------------*/
133 LPM_MODULE(rng_module, request, NULL, NULL, LPM_DOMAIN_NONE);
134 /*---------------------------------------------------------------------------*/
135 static uint64_t
136 read_number(void)
137 {
138  uint64_t ran = (uint64_t)HWREG(TRNG_BASE + TRNG_O_OUT1) << 32;
139  ran += ti_lib_trng_number_get(TRNG_LOW_WORD);
140 
141  return ran;
142 }
143 /*---------------------------------------------------------------------------*/
144 uint64_t
146 {
147  uint64_t ran;
148  bool interrupts_disabled;
149  int i;
150 
151  /* If the TRNG is gathering entropy, return a cached value */
152  if(notify_cb) {
153  for(i = 0; i < SOC_TRNG_CACHE_LEN; i++) {
154  if(rands_mask[i]) {
155  rands_mask[i] = false;
156  return rands_cache[i];
157  }
158  }
159  return 0;
160  }
161 
162  if(!accessible()) {
163  power_up();
164  }
165 
166  /*
167  * If we were previously enabled, we either have a number already available,
168  * or we need clock, which means we are calculating. If neither is true then
169  * we need setup from scratch.
170  */
171  if((ti_lib_trng_status_get() & (TRNG_NEED_CLOCK | TRNG_NUMBER_READY)) == 0) {
172  reset_synchronous();
173  ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, SOC_TRNG_REFILL_CYCLES_MIN, 0);
174  ti_lib_trng_enable();
175  }
176 
177  interrupts_disabled = ti_lib_int_master_disable();
178 
179  while((ti_lib_trng_status_get() & TRNG_NUMBER_READY) == 0);
180 
181  ran = read_number();
182 
183  if(!interrupts_disabled) {
184  ti_lib_int_master_enable();
185  }
186 
187  return ran;
188 }
189 /*---------------------------------------------------------------------------*/
190 uint8_t
192 {
193  int i;
194  bool interrupts_disabled;
195 
196  if(notify_cb != NULL) {
198  }
199 
200  if(!accessible()) {
201  power_up();
202  }
203 
204  /*
205  * First we need to cache some random numbers for general use in case the
206  * application requests them while we are calculating.
207  *
208  * If we were previously enabled, we either have a number already available,
209  * or we need clock, which means we are calculating. If neither is true then
210  * we need setup from scratch.
211  */
212  if((ti_lib_trng_status_get() & (TRNG_NEED_CLOCK | TRNG_NUMBER_READY)) == 0) {
213  reset_synchronous();
214  }
215 
216  interrupts_disabled = ti_lib_int_master_disable();
217 
218  ti_lib_trng_disable();
219  ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, SOC_TRNG_REFILL_CYCLES_MIN, 0);
220  ti_lib_trng_enable();
221 
222  /* Cache SOC_TRNG_CACHE_LEN min-entropy rands */
223  for(i = 0; i < SOC_TRNG_CACHE_LEN; i++) {
224  while((ti_lib_trng_status_get() & TRNG_NUMBER_READY) == 0);
225  rands_mask[i] = true;
226  rands_cache[i] = read_number();
227  }
228 
229  /* Configure the RNG to the required entropy */
230  ti_lib_trng_disable();
231  ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, samples, 0);
232 
233  /*
234  * Clear the TRNG_NUMBER_READY flag. This will trigger a new calculation
235  * as soon as the module gets enabled.
236  */
237  ti_lib_trng_int_clear(TRNG_NUMBER_READY);
238 
239  /* Enable clock in sleep mode and register with LPM */
240  ti_lib_prcm_peripheral_sleep_enable(PRCM_PERIPH_TRNG);
241  ti_lib_prcm_load_set();
242  while(!ti_lib_prcm_load_get());
243 
244  lpm_register_module(&rng_module);
245 
246  notify_cb = cb;
247 
248  /* Enable the number ready interrupt and fire-up the module */
249  enable_number_ready_interrupt();
250  ti_lib_trng_enable();
251 
252  if(!interrupts_disabled) {
253  ti_lib_int_master_enable();
254  }
255 
257 }
258 /*---------------------------------------------------------------------------*/
259 PROCESS_THREAD(soc_trng_process, ev, data)
260 {
261  PROCESS_BEGIN();
262 
263  while(1) {
264  PROCESS_YIELD_UNTIL(ev == rng_ready_event);
265 
266  if(notify_cb) {
267  uint64_t ran = read_number();
268 
269  notify_cb(ran);
270  notify_cb = NULL;
271  }
272 
273  /* Disable clock in sleep mode */
274  ti_lib_prcm_peripheral_sleep_disable(PRCM_PERIPH_TRNG);
275  ti_lib_prcm_load_set();
276  while(!ti_lib_prcm_load_get());
277 
278  lpm_unregister_module(&rng_module);
279  }
280 
281  PROCESS_END();
282 }
283 /*---------------------------------------------------------------------------*/
284 void
285 soc_trng_isr(void)
286 {
287  ti_lib_trng_disable();
288 
289  disable_number_ready_interrupt();
290 
291  ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, SOC_TRNG_REFILL_CYCLES_MIN, 0);
292  ti_lib_trng_enable();
293 
294  process_post(&soc_trng_process, rng_ready_event, NULL);
295 }
296 /*---------------------------------------------------------------------------*/
297 void
299 {
300  if(rng_ready_event != PROCESS_EVENT_NONE) {
301  return;
302  }
303 
304  /* Register the RNG ready event */
305  rng_ready_event = process_alloc_event();
306  process_start(&soc_trng_process, NULL);
307 }
308 /*---------------------------------------------------------------------------*/
309 /**
310  * @}
311  */
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
void soc_trng_init()
Initialise the CC13xx/CC26xx TRNG driver.
Definition: soc-trng.c:298
Header file with macros which rename TI CC26xxware functions.
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
Header file for the CC13xx/CC26xx TRNG driver.
Header file for the Contiki process interface.
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition: process.c:93
#define SOC_TRNG_RAND_ASYNC_REQUEST_ERROR
Async request rejected.
Definition: soc-trng.h:51
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
uint64_t soc_trng_rand_synchronous()
Returns a minimum entropy random number.
Definition: soc-trng.c:145
#define LPM_MODULE(n, m, s, w, l)
Declare a variable to be used in order to get notifications from LPM.
Definition: lpm.h:96
#define SOC_TRNG_CACHE_LEN
Size of the random number cache.
Definition: soc-trng.c:54
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1110
uint8_t soc_trng_rand_asynchronous(uint32_t samples, soc_trng_callback_t cb)
Request a 64-bit, configurable-entropy random number.
Definition: soc-trng.c:191
#define SOC_TRNG_RAND_ASYNC_REQUEST_OK
Async request accepted.
Definition: soc-trng.h:52
void lpm_unregister_module(lpm_registered_module_t *module)
Unregister a module from LPM notifications.
Definition: lpm.c:551
void(* soc_trng_callback_t)(uint64_t rand)
Pointer to a callback to be provided as an argument to soc_trng_rand_asynchronous() ...
Definition: soc-trng.h:61
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
void lpm_register_module(lpm_registered_module_t *module)
Register a module for LPM notifications.
Definition: lpm.c:545