Software APIs
csrng_edn_concurrency_test.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
9 #include "sw/device/lib/dif/dif_csrng_shared.h"
12 #include "sw/device/lib/runtime/irq.h"
14 #include "sw/device/lib/testing/csrng_testutils.h"
15 #include "sw/device/lib/testing/edn_testutils.h"
16 #include "sw/device/lib/testing/entropy_testutils.h"
18 #include "sw/device/lib/testing/rand_testutils.h"
19 #include "sw/device/lib/testing/rv_plic_testutils.h"
20 #include "sw/device/lib/testing/test_framework/check.h"
21 #include "sw/device/lib/testing/test_framework/ottf_macros.h"
23 #include "sw/device/tests/otbn_randomness_impl.h"
24 
26 #include "sw/device/lib/testing/autogen/isr_testutils.h"
27 
28 static dif_csrng_t csrng;
29 static dif_edn_t edn0;
30 static dif_edn_t edn1;
31 static dif_entropy_src_t entropy_src;
32 static dif_otbn_t otbn;
33 static dif_rv_plic_t plic;
34 static dif_rv_core_ibex_t rv_core_ibex;
35 static dif_aes_t aes;
36 static csrng_app_cmd_t sw_ins;
37 static csrng_app_cmd_t sw_gen;
38 static csrng_app_cmd_t sw_res;
39 dif_csrng_seed_material_t sw_ins_seed;
40 dif_csrng_seed_material_t sw_gen_seed;
41 dif_csrng_seed_material_t sw_res_seed;
42 static uint32_t sw_num_reqs_between_reseeds;
43 
44 enum {
45  /**
46  * The number of test iterations per target.
47  */
48  kTestParamNumIterationsSim = 2,
49  kTestParamNumIterationsOther = 20,
50  /**
51  * The number of test iterations per entropy consumer.
52  */
53  kTestParamNumOtbnIterationsMax = 4,
54  kTestParamNumIbexIterationsMax = 16,
55  kTestParamNumAesIterationsMax = 32,
56  kTestParamNumCsrngIterationsMax = 8,
57  /*
58  * The number of entries of the esfinal FIFO of ENTROPY_SRC.
59  */
60  kEntropySrcEsFinalFifoDepth = 3,
61  /*
62  * Parameters for controlling the waiting until the esfinal FIFO fills up.
63  * Under normal operating conditions, producing one seed takes roughly 4 ms.
64  * We wait for at most 32 ms for 6 seeds (2 for the EDNs, 1 for CSRNG, 3 to
65  * fill the esfinal FIFO).
66  */
67  kEsFinalFifoIterationTimeUs = 100,
68  kEsFinalFifoNumIterationsMax = 320
69 };
70 
71 /**
72  * Test execution states. These are use to control the execution state of all
73  * test tasks.
74  */
75 typedef enum test_state {
76  /**
77  * Configure entropy complex for next test iteration.
78  */
79  kTestStateSetup,
80  /**
81  * Request entropy from various endpoints.
82  */
83  kTestStateRun,
84  /**
85  * Tear down tasks.
86  */
87  kTestStateTearDown,
88  /**
89  * Number of test states.
90  */
91  kTestStateCount,
92 } test_state_t;
93 static volatile test_state_t execution_state;
94 
95 static const char *kStatusNames[kTestStateCount] = {"Setup", "Run", "TearDown"};
96 static_assert(ARRAYSIZE(kStatusNames) == kTestStateCount,
97  "Unexpected kStatusNames array size.");
98 
99 /**
100  * Each task uses the task ID to update flag and counter arrays.
101  */
102 typedef enum task_id {
103  /**
104  * Assigned to `main_task()`.
105  */
106  kTestTaskIdMain,
107  /**
108  * Assigned to `otbn_task()`.
109  */
110  kTestTaskIdOtbn,
111  /**
112  * Assigned to `ibex_task()`.
113  */
114  kTestTaskIdIbex,
115  /**
116  * Assigned to `aes_task()`.
117  */
118  kTestTaskIdAes,
119  /**
120  * Assigned to `csrng_task()`.
121  */
122  kTestTaskIdCsrng,
123  /**
124  * Number of tasks. Used to define task flag and counter arrays.
125  */
126  kTestTaskIdCount
127 } task_id_t;
128 /**
129  * Flags used to track when a task is done executing a test iteration.
130  */
131 static volatile bool task_done[kTestTaskIdCount];
132 /**
133  * Flags used to track the number of test iterations per task.
134  */
135 static volatile uint32_t task_iter_count_max[kTestTaskIdCount];
136 
137 OTTF_DEFINE_TEST_CONFIG(.enable_concurrency = true);
138 
139 /**
140  * Initializes the peripherals used in this test.
141  */
142 static void init_peripherals(void) {
143  CHECK_DIF_OK(dif_csrng_init(
145  CHECK_DIF_OK(
146  dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN0_BASE_ADDR), &edn0));
147  CHECK_DIF_OK(
148  dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN1_BASE_ADDR), &edn1));
149  CHECK_DIF_OK(dif_entropy_src_init(
151  CHECK_DIF_OK(dif_rv_plic_init(
153  CHECK_DIF_OK(dif_rv_core_ibex_init(
155  &rv_core_ibex));
156  CHECK_DIF_OK(
157  dif_otbn_init(mmio_region_from_addr(TOP_EARLGREY_OTBN_BASE_ADDR), &otbn));
158  CHECK_DIF_OK(
160 }
161 
162 /**
163  * Helper function used to set the task done flag.
164  *
165  * Issues a `ottf_task_yield()` to ensure control is handed over to pending
166  * tasks.
167  *
168  * @param task_id The task ID.
169  */
170 static void task_done_set_and_yield(task_id_t task_id) {
171  task_done[task_id] = true;
172  ottf_task_yield();
173 }
174 
175 /**
176  * OTBN task.
177  *
178  * Executes OTBN randomness test, the test state is set to `kTestStateRun`.
179  *
180  * @param task_parameters Unused. Set to NULL by ottf.
181  */
182 static void otbn_task(void *task_parameters) {
183  while (true) {
184  if (execution_state == kTestStateTearDown) {
185  break;
186  }
187  if (execution_state == kTestStateSetup || task_done[kTestTaskIdOtbn]) {
188  ottf_task_yield();
189  continue;
190  }
191  LOG_INFO("OTBN:START");
192  for (size_t i = 0; i < task_iter_count_max[kTestTaskIdOtbn]; ++i) {
193  otbn_randomness_test_start(&otbn, /*iters=*/0);
195  do {
196  CHECK_DIF_OK(dif_otbn_get_status(&otbn, &status));
197  ottf_task_yield();
198  } while (status != kDifOtbnStatusIdle && status != kDifOtbnStatusLocked);
199  CHECK(otbn_randomness_test_end(&otbn, /*skip_otbn_done_check=*/false));
200  }
201  LOG_INFO("OTBN:DONE");
202  task_done_set_and_yield(kTestTaskIdOtbn);
203  }
204  OTTF_TASK_DELETE_SELF_OR_DIE;
205 }
206 
207 /**
208  * Ibex task.
209  *
210  * Executes Ibex randomness test, the test state is set to `kTestStateRun`.
211  *
212  * @param task_parameters Unused. Set to NULL by ottf.
213  */
214 static void ibex_task(void *task_parameters) {
215  while (true) {
216  if (execution_state == kTestStateTearDown) {
217  break;
218  }
219  if (execution_state == kTestStateSetup || task_done[kTestTaskIdIbex]) {
220  ottf_task_yield();
221  continue;
222  }
223  LOG_INFO("Ibex:START");
224  uint32_t prev_data = 0;
225  for (size_t i = 0; i < task_iter_count_max[kTestTaskIdIbex];) {
226  dif_rv_core_ibex_rnd_status_t status;
227  CHECK_DIF_OK(dif_rv_core_ibex_get_rnd_status(&rv_core_ibex, &status));
228  if ((status & kDifRvCoreIbexRndStatusValid) == 0) {
229  ottf_task_yield();
230  continue;
231  }
232  i++;
233  uint32_t new_data;
234  CHECK_DIF_OK(dif_rv_core_ibex_read_rnd_data(&rv_core_ibex, &new_data));
235 
236  // The following checks have a probability of returning false negatives.
237  // Flakiness issues can potentially be addressed by switching to error
238  // counters.
239  CHECK(new_data != prev_data, "Unexpected duplicate data");
240  CHECK(new_data != 0);
241  CHECK(new_data != UINT32_MAX);
242  prev_data = new_data;
243  }
244  LOG_INFO("Ibex:DONE");
245  task_done_set_and_yield(kTestTaskIdIbex);
246  }
247  OTTF_TASK_DELETE_SELF_OR_DIE;
248 }
249 
250 /**
251  * AES task.
252  *
253  * Reseeds the AES masking and clearing PRNGs, test state is set to
254  * `kTestStateRun`.
255  *
256  * @param task_parameters Unused. Set to NULL by ottf.
257  */
258 static void aes_task(void *task_parameters) {
259  while (true) {
260  if (execution_state == kTestStateTearDown) {
261  break;
262  }
263  if (execution_state == kTestStateSetup || task_done[kTestTaskIdAes]) {
264  ottf_task_yield();
265  continue;
266  }
267  LOG_INFO("AES:START");
268  for (size_t i = 0; i < task_iter_count_max[kTestTaskIdAes]; ++i) {
271  bool set;
272  CHECK_DIF_OK(dif_aes_trigger(&aes, trigger));
273  do {
274  CHECK_DIF_OK(dif_aes_get_status(&aes, status, &set));
275  ottf_task_yield();
276  } while (!set);
277  }
278  LOG_INFO("AES:DONE");
279  task_done_set_and_yield(kTestTaskIdAes);
280  }
281  OTTF_TASK_DELETE_SELF_OR_DIE;
282 }
283 
284 /**
285  * CSRNG task.
286  *
287  * Uses the CSRNG SW instance, test state is set to
288  * `kTestStateRun`.
289  *
290  * @param task_parameters Unused. Set to NULL by ottf.
291  */
292 static void csrng_task(void *task_parameters) {
293  while (true) {
294  if (execution_state == kTestStateTearDown) {
295  break;
296  }
297  if (execution_state == kTestStateSetup || task_done[kTestTaskIdCsrng]) {
298  ottf_task_yield();
299  continue;
300  }
301  LOG_INFO("CSRNG:START");
302  // Per test iteration, we do:
303  // - 1 instantiate, see entropy_config()
304  // - task_iter_count_max[kTestTaskIdCsrng] iterations of
305  // - sw_num_reqs_between_reseeds Generate commands
306  // - Each Generate command produces generate_len 128-bit genbits blocks
307  // - 1 Reseed command
308  for (size_t i = 0; i < task_iter_count_max[kTestTaskIdCsrng]; ++i) {
309  dif_csrng_cmd_status_t cmd_status;
310  for (uint32_t i_gen = 0; i_gen < sw_num_reqs_between_reseeds; ++i_gen) {
311  // Run Generate command.
312  do {
313  CHECK_DIF_OK(dif_csrng_get_cmd_interface_status(&csrng, &cmd_status));
314  CHECK(cmd_status.kind != kDifCsrngCmdStatusError);
315  ottf_task_yield();
316  } while (cmd_status.kind != kDifCsrngCmdStatusReady);
317  CHECK_DIF_OK(
318  csrng_send_app_cmd(csrng.base_addr, kCsrngAppCmdTypeCsrng, sw_gen));
319  // Read genbits blocks.
320  for (uint32_t i_block = 0; i_block < sw_gen.generate_len; ++i_block) {
321  dif_csrng_output_status_t output_status;
322  uint32_t output[kCsrngGenBitsBufferSize];
323  do {
324  CHECK_DIF_OK(dif_csrng_get_output_status(&csrng, &output_status));
325  ottf_task_yield();
326  } while (!output_status.valid_data);
327  CHECK_DIF_OK(dif_csrng_generate_read(
328  &csrng, output, (size_t)kCsrngGenBitsBufferSize));
329  }
330  }
331  // Run Reseed command.
332  do {
333  CHECK_DIF_OK(dif_csrng_get_cmd_interface_status(&csrng, &cmd_status));
334  CHECK(cmd_status.kind != kDifCsrngCmdStatusError);
335  ottf_task_yield();
336  } while (cmd_status.kind != kDifCsrngCmdStatusReady);
337  CHECK_DIF_OK(
338  csrng_send_app_cmd(csrng.base_addr, kCsrngAppCmdTypeCsrng, sw_res));
339  }
340  LOG_INFO("CSRNG:DONE");
341  task_done_set_and_yield(kTestTaskIdCsrng);
342  }
343  OTTF_TASK_DELETE_SELF_OR_DIE;
344 }
345 
346 /**
347  * Generates a randomized entropy complex configuration and applies it to both
348  * EDNs and the CSRNG SW instance. The configuration of ENTROPY_SRC is left
349  * untouched to optimize test performance.
350  *
351  * Note that to generate the randomized configuration, the entropy complex needs
352  * to be configured in auto mode before calling this function.
353  */
354 static void entropy_config(void) {
355  LOG_INFO("Generating EDN and CSRNG params");
356  dif_edn_auto_params_t edn_params0 =
357  edn_testutils_auto_params_build(false,
358  /*res_itval=*/0,
359  /*glen_val=*/0);
360  dif_edn_auto_params_t edn_params1 =
361  edn_testutils_auto_params_build(false,
362  /*res_itval=*/0,
363  /*glen_val=*/0);
364  sw_ins = csrng_testutils_app_cmd_build(
365  false,
366  /*id=*/kCsrngAppCmdInstantiate,
367  /*entropy_src_en=*/kDifCsrngEntropySrcToggleEnable,
368  /*glen_val=*/0, &sw_ins_seed);
369  sw_gen = csrng_testutils_app_cmd_build(
370  false,
371  /*id=*/kCsrngAppCmdGenerate,
372  /*entropy_src_en=*/kDifCsrngEntropySrcToggleEnable,
373  /*glen_val=*/0, &sw_gen_seed);
374  sw_res = csrng_testutils_app_cmd_build(
375  false,
376  /*id=*/kCsrngAppCmdReseed,
377  /*entropy_src_en=*/kDifCsrngEntropySrcToggleEnable,
378  /*glen_val=*/0, &sw_res_seed);
379  sw_num_reqs_between_reseeds = rand_testutils_gen32_range(1, 10);
380 
381  task_iter_count_max[kTestTaskIdOtbn] =
382  rand_testutils_gen32_range(/*min=*/1, kTestParamNumOtbnIterationsMax);
383  task_iter_count_max[kTestTaskIdIbex] =
384  rand_testutils_gen32_range(/*min=*/1, kTestParamNumIbexIterationsMax);
385  task_iter_count_max[kTestTaskIdAes] =
386  rand_testutils_gen32_range(/*min=*/1, kTestParamNumAesIterationsMax);
387  task_iter_count_max[kTestTaskIdCsrng] =
388  rand_testutils_gen32_range(/*min=*/1, kTestParamNumCsrngIterationsMax);
389 
390  CHECK_STATUS_OK(entropy_testutils_stop_csrng_edn());
391  CHECK_DIF_OK(dif_csrng_configure(&csrng));
392  CHECK_DIF_OK(dif_edn_set_auto_mode(&edn0, edn_params0));
393  CHECK_DIF_OK(dif_edn_set_auto_mode(&edn1, edn_params1));
394 
395  CHECK_STATUS_OK(csrng_testutils_cmd_ready_wait(&csrng));
396  CHECK_DIF_OK(dif_csrng_uninstantiate(&csrng));
397  CHECK_STATUS_OK(csrng_testutils_cmd_ready_wait(&csrng));
398  CHECK_DIF_OK(dif_csrng_instantiate(&csrng, sw_ins.entropy_src_enable,
399  sw_ins.seed_material));
400  CHECK_STATUS_OK(csrng_testutils_cmd_ready_wait(&csrng));
401 
402  // Wait for the esfinal FIFO inside ENTROPY_SRC to fill up. This will reduce
403  // the wait time for ENTROPY_SRC seeds and instead increase contention on the
404  // CSRNG and EDN hardware pipelines which are in focus for this test.
405  //
406  // Under normal operating conditions, producing one seed takes roughly 4 ms.
407  // We wait for at most 32 ms for 6 seeds (2 for the EDNs, 1 for CSRNG, 3 to
408  // fill the esfinal FIFO). In the reduced_freq varaint of the test, raw
409  // entropy may be generated at a lower rate. Depending on the configuration of
410  // the EDNs, the constant entropy consumption of AST may prevent the esfinal
411  // FIFO from filling up.
412  dif_entropy_src_debug_state_t debug_state;
413  uint32_t iter_count = 0;
414  do {
415  busy_spin_micros(kEsFinalFifoIterationTimeUs);
416  if (++iter_count >= kEsFinalFifoNumIterationsMax) {
417  LOG_INFO("Continuing without esfinal FIFO being full");
418  break;
419  }
420  CHECK_DIF_OK(dif_entropy_src_get_debug_state(&entropy_src, &debug_state));
421  } while (debug_state.entropy_fifo_depth < kEntropySrcEsFinalFifoDepth);
422 }
423 
424 /**
425  * Updates and logs the execution state.
426  *
427  * @param next_state The next state.
428  */
429 static void execution_state_update(test_state_t next_state) {
430  CHECK(next_state < kTestStateCount);
431  LOG_INFO("Test state: %s", kStatusNames[next_state]);
432  execution_state = next_state;
433 }
434 
435 /**
436  * Main test task.
437  *
438  * Configures entropy complex and signals test tasks to run an iteration loop.
439  *
440  * @param task_parameters Unused. Set to NULL by ottf.
441  */
442 static void main_task(void *task_parameters) {
443  task_iter_count_max[kTestTaskIdMain] = kTestParamNumIterationsSim;
445  task_iter_count_max[kTestTaskIdMain] = kTestParamNumIterationsOther;
446  }
447 
448  uint32_t iter_count = 0;
449  while (true) {
450  if (execution_state == kTestStateRun) {
451  uint32_t count = 0;
452  for (size_t i = 0; i < kTestTaskIdCount; ++i) {
453  count += task_done[i] ? 1 : 0;
454  }
455  if (count < kTestTaskIdCount) {
456  ottf_task_yield();
457  continue;
458  }
459  // Consider this test iteration done if all tasks are done. Update the
460  // iteration counter and set the execution state to `kTestStateSetup`
461  // to continue with configuring the entropy blocks for the next test
462  // run iteration.
463  if (++iter_count >= task_iter_count_max[kTestTaskIdMain]) {
464  execution_state_update(kTestStateTearDown);
465  break;
466  }
467  CHECK_STATUS_OK((csrng_testutils_recoverable_alerts_check(&csrng)));
468  CHECK_STATUS_OK(entropy_testutils_error_check(&csrng, &edn0, &edn1));
469  execution_state_update(kTestStateSetup);
470  }
471  // The rest of this code block is executed when
472  // `execute_state == kTestStateSetup`.
473  entropy_config();
474  for (size_t i = 0; i < kTestTaskIdCount; ++i) {
475  task_done[i] = false;
476  }
477  // Signal the other tasks to start test execution.
478  execution_state_update(kTestStateRun);
479  // This is required to ensure the aggregation of task_done entries is equal
480  // to `kTestTaskIdCount`.
481  task_done_set_and_yield(kTestTaskIdMain);
482  }
483  OTTF_TASK_DELETE_SELF_OR_DIE;
484 }
485 
486 bool test_main(void) {
487  init_peripherals();
488  CHECK_STATUS_OK(entropy_testutils_auto_mode_init());
489 
490  // Initialize the test `execution_state` before launching the tasks.
491  execution_state_update(kTestStateSetup);
492 
493  CHECK(ottf_task_create(main_task, "main", kOttfFreeRtosMinStackSize, 1));
494  CHECK(ottf_task_create(otbn_task, "otbn", kOttfFreeRtosMinStackSize, 1));
495  CHECK(ottf_task_create(ibex_task, "ibex", kOttfFreeRtosMinStackSize, 1));
496  CHECK(ottf_task_create(aes_task, "aes", kOttfFreeRtosMinStackSize, 1));
497  CHECK(ottf_task_create(csrng_task, "csrng", kOttfFreeRtosMinStackSize, 1));
498 
499  // There is no need to poll for completion as the tasks above will execute
500  // with higher priority and control will not be returned to this task until
501  // all tasks are done executing.
502  ottf_task_yield();
503  return true;
504 }