Software APIs
entropy_src_fw_override_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 
5 #include <string.h>
6 
13 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
15 #include "sw/device/lib/runtime/irq.h"
17 #include "sw/device/lib/testing/aes_testutils.h"
18 #include "sw/device/lib/testing/edn_testutils.h"
19 #include "sw/device/lib/testing/entropy_src_testutils.h"
20 #include "sw/device/lib/testing/entropy_testutils.h"
21 #include "sw/device/lib/testing/kmac_testutils.h"
22 #include "sw/device/lib/testing/rand_testutils.h"
23 #include "sw/device/lib/testing/rv_core_ibex_testutils.h"
24 #include "sw/device/lib/testing/test_framework/check.h"
26 #include "sw/device/tests/otbn_randomness_impl.h"
27 
28 #include "entropy_src_regs.h" // Generated.
29 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" // Generated.
30 
31 OTTF_DEFINE_TEST_CONFIG();
32 
33 enum {
34  kEntropySrcHealthTestWindowSize = 0x200,
35  /**
36  * Observe FIFO threshold: half of the FIFO size.
37  */
38  kEntropySrcFifoThreshold = 16,
39  /**
40  * The number of contiguous samples we want to capture.
41  */
42  kContiguousSamplesCount = 1024,
43  /**
44  * Number of bits per sample.
45  */
46  kBitsPerSample = 4,
47  /**
48  * Size of buffer in words to hold all the samples, assuming
49  * 4-bit samples at the most.
50  */
51  kFifoBufferSizeWords =
52  kContiguousSamplesCount * kBitsPerSample / sizeof(uint32_t),
53  /**
54  * Maximum number of words to move from the output buffer in one ISR.
55  *
56  * This number has to be small otherwise the conditioner runs for too long
57  * and blocks the ISR.
58  */
59  kMaxOutputWords = 16,
60  /**
61  * Number of micro seconds we wait between having extracted words from the
62  * observe FIFO and inserting words back into the entropy source.
63  */
64  kOutputDelayUs = 128,
65  /**
66  * The size of the buffer used in firmware to process the entropy bits in
67  * firmware override mode.
68  */
69  kEntropyFifoBufferSize = 12,
70  /**
71  * The amount of random numbers to generate as entropy consumers in each test.
72  */
73  kRandomNumberCount = 16,
74  /*
75  * Timeout to generate a random number in micro seconds.
76  */
77  kRandomNumberTimeoutUsec = 100 * 1000,
78  /**
79  * Timeout to generate a random number in micro seconds when running in a
80  * Verilator simulation environment. Verilator observes entropy more slowly
81  * than other environments, and so is given a longer timeout.
82  */
83  kVerilatorRandomNumberTimeoutUsec = 48 * 100 * 1000,
84  /**
85  * Timeout to run AES testutils in micro seconds.
86  */
87  kAesTestutilsTimeoutUsec = 1 * 1000 * 1000,
88  /**
89  * Timeout to run AES testutils in micro seconds when running in a
90  * Verilator simulation environment. Verilator observes entropy more slowly
91  * than other environments, and so is given a longer timeout.
92  */
93  kVerilatorAesTestutilsTimeoutUsec = 48 * 1000 * 1000,
94 };
95 
96 static dif_aes_t aes;
97 static dif_csrng_t csrng;
98 static dif_edn_t edn0;
99 static dif_edn_t edn1;
100 static dif_entropy_src_t entropy_src;
101 static dif_kmac_t kmac;
102 static dif_otbn_t otbn;
103 static dif_rv_core_ibex_t rv_core_ibex;
104 static dif_rv_plic_t rv_plic;
105 
106 // Buffers to collect samples into.
107 //
108 // We use a double-buffering approach, where one buffer is for the "input"
109 // samples that we read from the observe FIFO, and the other is for "output"
110 // samples that we need to write to the conditioner.
111 //
112 // When the input buffer is filled and the output buffer is empty, we swap them
113 // and the bytes we collected are written out to the conditioner. The input
114 // buffer is now empty, and we can start writing new samples to it.
115 static uint32_t sample_buf_0[kFifoBufferSizeWords];
116 static uint32_t sample_buf_1[kFifoBufferSizeWords];
117 
118 // These pointers track which buffer is the input or the output and are cursors
119 // into where we have written to / read from them so far.
120 static uint32_t *input_buf = sample_buf_0;
121 static uint32_t *output_buf = sample_buf_1 + kFifoBufferSizeWords;
122 
123 // These counters track how many words are remaining to be written to the input
124 // buffer or read out of the output buffer.
125 static size_t words_to_input = kFifoBufferSizeWords;
126 static size_t words_to_output = 0;
127 
128 static dif_edn_auto_params_t edn_params0;
129 static dif_edn_auto_params_t edn_params1;
130 
131 static bool fw_ov_insert_wait_enabled = false;
132 
133 /**
134  * Determine whether the observe FIFO has overflowed.
135  *
136  * TODO(#21279) Normally, one would rely on the FW_OV_RD_FIFO_OVERFLOW
137  * register but due to an RTL bug, the overflow bit is pulsed
138  * instead of latched so we cannot rely on it. Instead, rely
139  * on OBSERVE_FIFO_DEPTH and assume that if the FIFO is full
140  * then it has overflowed.
141  */
142 bool entropy_src_fifo_has_overflowed(void) {
143  uint32_t fifo_depth;
144  CHECK_DIF_OK(dif_entropy_src_get_fifo_depth(&entropy_src, &fifo_depth));
145  return fifo_depth == ENTROPY_SRC_PARAM_OBSERVE_FIFO_DEPTH;
146 }
147 
148 void ottf_external_isr(uint32_t *exc_info) {
149  dif_rv_plic_irq_id_t plic_irq_id;
150  CHECK_DIF_OK(dif_rv_plic_irq_claim(&rv_plic, kTopEarlgreyPlicTargetIbex0,
151  &plic_irq_id));
152 
153  top_earlgrey_plic_peripheral_t peripheral =
155  CHECK(peripheral == kTopEarlgreyPlicPeripheralEntropySrc);
156 
157  // If the observe buffer overflows while we're still collecting samples
158  // then we need to drain it and start again or our samples won't be
159  // contiguous.
160  if (words_to_input > 0 && entropy_src_fifo_has_overflowed()) {
161  CHECK_STATUS_OK(entropy_src_testutils_drain_observe_fifo(&entropy_src));
162  // Reset the input buffer.
163  input_buf -= (kFifoBufferSizeWords - words_to_input);
164  words_to_input = kFifoBufferSizeWords;
165  }
166 
167  if (words_to_input > 0) {
168  // Move at most `kEntropySrcFifoThreshold` into the input buffer.
169  // We don't want to slow down this ISR by copying too many words or waiting
170  // for more entropy to arrive.
171  size_t len = words_to_input;
172  if (len > kEntropySrcFifoThreshold) {
173  len = kEntropySrcFifoThreshold;
174  }
175 
177  &entropy_src, input_buf, &len));
178 
179  input_buf += len;
180  words_to_input -= len;
181  }
182 
183  // If we've filled the input buffer and drained the output buffer, swap
184  // them.
185  if (words_to_input == 0 && words_to_output == 0) {
186  // Swap the buffers.
187  uint32_t *output_tmp = output_buf;
188  output_buf = input_buf - kFifoBufferSizeWords;
189  input_buf = output_tmp - kFifoBufferSizeWords;
190 
191  words_to_input = kFifoBufferSizeWords;
192  words_to_output = kFifoBufferSizeWords;
193  }
194 
195  if (fw_ov_insert_wait_enabled) {
196  busy_spin_micros(kOutputDelayUs);
197  }
198 
199  if (words_to_output > 0) {
200  // Move out at most `kMaxOutputWords` into the override FIFO.
201  size_t len = words_to_output;
202  if (len > kMaxOutputWords) {
203  len = kMaxOutputWords;
204  }
205 
206  // Start the SHA3 process so that it is ready to accept entropy data.
208  &entropy_src, kDifToggleEnabled));
209 
210  size_t words_written = 0;
211  CHECK_DIF_OK(dif_entropy_src_fw_ov_data_write(&entropy_src, output_buf, len,
212  &words_written));
213 
214  output_buf += words_written;
215  words_to_output -= words_written;
216 
217  // Stop the SHA3 process causing it to finish up and push the results
218  // through the rest of the entropy source.
220  &entropy_src, kDifToggleDisabled));
221  }
222 
223  CHECK_DIF_OK(dif_entropy_src_irq_acknowledge(
224  &entropy_src, kDifEntropySrcIrqEsObserveFifoReady));
225 
227  plic_irq_id));
228 }
229 
230 static status_t configure_interrupts(void) {
233 
235  0x0));
236 
240 
241  TRY(dif_entropy_src_irq_set_enabled(
242  &entropy_src, kDifEntropySrcIrqEsObserveFifoReady, kDifToggleEnabled));
243 
244  return OK_STATUS();
245 }
246 
247 // Configure the entropy complex.
248 static status_t entropy_config(
249  dif_entropy_src_single_bit_mode_t single_bit_mode,
250  bool bypass_conditioner) {
251  // Don't let the extract and insert interrupt handler run until we've enabled
252  // the entropy source.
253  irq_external_ctrl(false);
254 
255  LOG_INFO("Disabling entropy complex");
256  // Disable the entropy complex.
257  TRY(entropy_testutils_stop_all());
258  // Disable all health tests.
259  TRY(entropy_src_testutils_disable_health_tests(&entropy_src));
260 
261  // Enable FW override.
263  &entropy_src,
265  .entropy_insert_enable = true,
266  .buffer_threshold = kEntropySrcFifoThreshold,
267  },
269 
270  // Enable entropy_src.
271  LOG_INFO("Enabling entropy source");
273  &entropy_src,
275  .fips_enable = true,
276  .fips_flag = true,
277  .rng_fips = true,
278  .route_to_firmware = false,
279  .bypass_conditioner = bypass_conditioner,
280  .single_bit_mode = single_bit_mode,
281  .health_test_threshold_scope = false,
282  .health_test_window_size = kEntropySrcHealthTestWindowSize,
283  .alert_threshold = UINT16_MAX},
285 
286  // Enable the interrupt handler to provide CSRNG with entropy.
287  irq_external_ctrl(true);
288 
289  // Enable CSRNG
290  LOG_INFO("Enabling CSRNG");
291  TRY(dif_csrng_configure(&csrng));
292 
293  // Enable EDNs in auto request mode
294  LOG_INFO("Enabling EDNs");
295  TRY(dif_edn_set_auto_mode(&edn0, edn_params0));
296  TRY(dif_edn_set_auto_mode(&edn1, edn_params1));
297 
298  LOG_INFO("Entropy complex configured");
299 
300  return OK_STATUS();
301 }
302 
303 // Configure the entropy complex.
304 static status_t reenable_entropy_src(
305  dif_entropy_src_single_bit_mode_t single_bit_mode,
306  bool bypass_conditioner) {
307  uint32_t data;
308  bool entropy_req_intr = false;
309  size_t words_written = 0;
310  uint32_t kInputMsg[kEntropyFifoBufferSize];
311  uint32_t cnt = 0;
312 
313  // Don't let the extract and insert interrupt handler run until we've
314  // re-enabled the entropy source.
315  irq_external_ctrl(false);
316 
317  // Make ENTROPY_SRC produce new seeds until CSRNG has no outstanding
318  // entropy requests.
319  do {
320  // If the FW_OV_WR_DATA register is not ready yet,
321  // we wait for a bit and try again.
322  data = mmio_region_read32(entropy_src.base_addr,
323  ENTROPY_SRC_FW_OV_WR_FIFO_FULL_REG_OFFSET);
324  if (data) {
325  busy_spin_micros(10);
326  continue;
327  }
328  // Make SHA3 absorb new data and produce a new seed right away.
329  // We use a counter for the input message to avoid triggering
330  // ES_BUS_CMP_ALERT.
332  &entropy_src, kDifToggleEnabled));
333  for (int i = 0; i < kEntropyFifoBufferSize; i++) {
334  kInputMsg[i] = cnt++;
335  }
337  &entropy_src, (const uint32_t *)kInputMsg, kEntropyFifoBufferSize,
338  &words_written));
340  &entropy_src, kDifToggleDisabled));
341  // Clear CS_ENTROPY_REQ and check if it is reasserted.
342  // If not, we can disable ENTROPY_SRC and check if the entropy
343  // complex still produces entropy after reenabling ENTROPY_SRC.
344  CHECK_DIF_OK(dif_csrng_irq_acknowledge_state(
345  &csrng, 1 << CSRNG_INTR_STATE_CS_ENTROPY_REQ_BIT));
346  CHECK_DIF_OK(dif_csrng_irq_is_pending(
347  &csrng, CSRNG_INTR_STATE_CS_ENTROPY_REQ_BIT, &entropy_req_intr));
348  } while (entropy_req_intr);
349 
350  // Disable the entropy source.
351  LOG_INFO("Disabling entropy_src");
353 
354  // Wait for CSRNG to request a seed while ENTROPY_SRC is diabled.
355  do {
356  if (rv_core_ibex_testutils_is_rnd_data_valid(&rv_core_ibex)) {
357  TRY(dif_rv_core_ibex_read_rnd_data(&rv_core_ibex, &data));
358  }
359  CHECK_DIF_OK(dif_csrng_irq_is_pending(
360  &csrng, CSRNG_INTR_STATE_CS_ENTROPY_REQ_BIT, &entropy_req_intr));
361  } while (!entropy_req_intr);
362 
363  // Reenable ENTROPY_SRC now that CSRNG has an outstanding entropy request.
365  LOG_INFO("ENTROPY_SRC re-enabled");
366 
367  // Enable the interrupt handler to provide CSRNG with entropy.
368  irq_external_ctrl(true);
369 
370  return OK_STATUS();
371 }
372 
373 /**
374  * Configure the entropy source in extract and insert mode and run some entropy
375  * consumers.
376  */
377 status_t firmware_override_extract_insert(
378  dif_entropy_src_single_bit_mode_t single_bit_mode, bool bypass_conditioner,
379  bool reenable_es) {
380  LOG_INFO("==================");
381  LOG_INFO("Configuring single_bit_mode=%u, bypass_conditioner=%d",
382  single_bit_mode, bypass_conditioner);
383 
384  entropy_config(single_bit_mode, bypass_conditioner);
385 
386  // Generate some random numbers.
387  LOG_INFO("Generating random numbers...");
388  uint32_t rnd_timeout_usec = kRandomNumberTimeoutUsec;
390  // Simulation on Verilator generates entropy much more slowly than other
391  // execution environments. As a result, the timeout to generate random
392  // numbers is increased only when running on Verilator.
393  rnd_timeout_usec = kVerilatorRandomNumberTimeoutUsec;
394  }
395  uint32_t data;
396  for (size_t i = 0; i < kRandomNumberCount; i++) {
397  TRY(rv_core_ibex_testutils_get_rnd_data(&rv_core_ibex,
398  /*timeout_usec=*/rnd_timeout_usec,
399  &data));
400  }
401 
402  if (reenable_es) {
403  // Now that we know that a seed was produced we reenable the entropy_src
404  // and see whether the entropy complex still works as expected.
405  reenable_entropy_src(single_bit_mode, bypass_conditioner);
406  }
407 
408  // Run an AES encryption and decryption process.
409  dif_aes_transaction_t transaction = {
410  .operation = kDifAesOperationEncrypt,
411  .mode = kDifAesModeEcb,
412  .key_len = kDifAesKey256,
413  .key_provider = kDifAesKeySoftwareProvided,
414  .mask_reseeding = kDifAesReseedPerBlock,
415  .manual_operation = kDifAesManualOperationAuto,
416  .reseed_on_key_change = true,
417  .ctrl_aux_lock = false,
418  };
419 
420  LOG_INFO("Running AES...");
421  uint32_t aes_timeout_usec = kAesTestutilsTimeoutUsec;
423  // Simulation on Verilator generates entropy much more slowly than other
424  // execution environments. As a result, the timeout for AES testuils is
425  // increased only when running on Verilator.
426  aes_timeout_usec = kVerilatorAesTestutilsTimeoutUsec;
427  }
428  TRY(aes_testutils_setup_encryption(transaction, &aes));
429  AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusOutputValid, true,
430  /*timeout_usec=*/aes_timeout_usec);
431  TRY(aes_testutils_decrypt_ciphertext(transaction, &aes));
432 
433  // Run KMAC
434  dif_kmac_config_t config = {
435  .entropy_mode = kDifKmacEntropyModeEdn,
436  .entropy_fast_process = false,
437  .entropy_seed = {0},
438  .entropy_hash_threshold = 1,
439  .entropy_wait_timer = 0,
440  .entropy_prescaler = 0,
441  .message_big_endian = false,
442  .output_big_endian = false,
443  .sideload = false,
444  .msg_mask = true,
445  };
446  TRY(dif_kmac_configure(&kmac, config));
447 
448  dif_kmac_key_t software_key = {
449  .share0 = {0x43424140, 0x47464544, 0x4B4A4948, 0x4F4E4D4C, 0x53525150,
450  0x57565554, 0x5B5A5958, 0x5F5E5D5C},
451  .share1 = {0},
452  .length = kDifKmacKeyLen256,
453  };
454  uint32_t output[8];
455  LOG_INFO("Running KMAC...");
456  TRY(kmac_testutils_kmac(&kmac, kDifKmacModeKmacLen128, &software_key,
457  /*custom_string=*/NULL, /*custom_string_len=*/0,
458  /*message=*/"hello", /*message_len=*/6,
459  ARRAYSIZE(output), output, /*capacity=*/NULL));
460 
461  LOG_INFO("Running OTBN...");
462  otbn_randomness_test_start(&otbn, /*iters=*/10);
463  TRY_CHECK(otbn_randomness_test_end(&otbn, /*skip_otbn_done_check=*/false));
464 
465  return OK_STATUS();
466 }
467 
468 bool test_main(void) {
469  mmio_region_t base_addr;
470 
472  CHECK_DIF_OK(dif_aes_init(base_addr, &aes));
474  CHECK_DIF_OK(dif_csrng_init(base_addr, &csrng));
476  CHECK_DIF_OK(dif_edn_init(base_addr, &edn0));
478  CHECK_DIF_OK(dif_edn_init(base_addr, &edn1));
480  CHECK_DIF_OK(dif_entropy_src_init(base_addr, &entropy_src));
482  CHECK_DIF_OK(dif_kmac_init(base_addr, &kmac));
484  CHECK_DIF_OK(dif_otbn_init(base_addr, &otbn));
486  CHECK_DIF_OK(dif_rv_core_ibex_init(base_addr, &rv_core_ibex));
488  CHECK_DIF_OK(dif_rv_plic_init(base_addr, &rv_plic));
489 
490  LOG_INFO("Configuring interrupts...");
491  configure_interrupts();
492  irq_global_ctrl(true);
493  irq_external_ctrl(false);
494 
495  LOG_INFO("Computing EDN parameters");
496  edn_params0 = edn_testutils_auto_params_build(
497  /*disable_rand=*/true, /*res_itval=*/1, /*glen_val=*/1);
498  edn_params1 = edn_testutils_auto_params_build(
499  /*disable_rand=*/true, /*res_itval=*/1, /*glen_val=*/1);
500 
501  // Test all modes.
502  static dif_entropy_src_single_bit_mode_t kModes[] = {
506  };
507 
508  size_t entropy_src_mode_count = ARRAYSIZE(kModes);
509 
510  // If running on Verilator, then we only test ModeDisabled and Mode0, since
511  // the subsequent 3 modes are very similar and are much slower, causing
512  // Verilator simulation to take an impractical amount of time.
514  entropy_src_mode_count = 2;
515  }
516 
517  status_t test_result = OK_STATUS();
518 
519  for (size_t i = 0; i < entropy_src_mode_count; i++) {
520  EXECUTE_TEST(test_result, firmware_override_extract_insert, kModes[i],
521  false, false);
522  EXECUTE_TEST(test_result, firmware_override_extract_insert, kModes[i], true,
523  false);
524  }
525 
526  // Rerun the test with single bit mode disabled, this time we reenable the
527  // entropy_src without reenabling the rest of the entropy complex.
528  EXECUTE_TEST(test_result, firmware_override_extract_insert,
530  EXECUTE_TEST(test_result, firmware_override_extract_insert,
532 
534  // If running on Verilator, then we skip the final phase of testing,
535  // since entropy is generated much more slowly on Verilator and we do not
536  // learn a lot of useful information from running these tests. This stops
537  // simulaton on Verilator taking an impractical amount of time.
538  return status_ok(test_result);
539  }
540 
541  // Rerun the test with single bit mode disabled,
542  // this time with an output delay.
543  fw_ov_insert_wait_enabled = true;
544  EXECUTE_TEST(test_result, firmware_override_extract_insert,
546  EXECUTE_TEST(test_result, firmware_override_extract_insert,
548 
549  return status_ok(test_result);
550 }