Software APIs
entropy_src_fw_observe_many_contiguous.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 
10 #include "sw/device/lib/testing/edn_testutils.h"
11 #include "sw/device/lib/testing/entropy_src_testutils.h"
12 #include "sw/device/lib/testing/entropy_testutils.h"
13 #include "sw/device/lib/testing/test_framework/check.h"
15 
16 #include "entropy_src_regs.h" // Generated.
17 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" // Generated.
18 
19 OTTF_DEFINE_TEST_CONFIG();
20 
21 enum {
22  kEntropySrcHealthTestWindowSize = 0x200,
23  /**
24  * Observe FIFO threshold: half of the FIFO size.
25  */
26  kEntropySrcFifoThreshold = 16,
27  /**
28  * The number of contiguous samples we want to capture.
29  */
30  kContiguousSamplesCount = 1024,
31  /**
32  * The number of contiguous samples we want to capture when running on
33  * Verilator.
34  */
35  kVerilatorContiguousSamplesCount = 8,
36  /*
37  * Timeout to read kContiguousSamplesCount.
38  */
39  kTimeoutUsec = 1000 * 1000,
40  /**
41  * Number of time to repeat each test, letting the observe FIFO
42  * overflow in-between tests.
43  */
44  kRepeatCount = 4,
45  /**
46  * Number of bits per sample.
47  */
48  kBitsPerSample = 4,
49  /**
50  * Size of buffer in words to hold all the samples, assuming
51  * 4-bit samples at the most.
52  */
53  kFifoBufferSizeWords =
54  kContiguousSamplesCount * kBitsPerSample / sizeof(uint32_t),
55 };
56 
57 static uint32_t sample_buffer[kFifoBufferSizeWords];
58 static dif_entropy_src_t entropy_src;
59 static dif_csrng_t csrng;
60 static dif_edn_t edn0;
61 static dif_edn_t edn1;
62 
63 /**
64  * Determine whether the observe FIFO has overflowed.
65  */
66 bool entropy_src_fifo_has_overflowed(void) {
67  bool has_overflowed;
68  CHECK_DIF_OK(
69  dif_entropy_src_has_fifo_overflowed(&entropy_src, &has_overflowed));
70  return has_overflowed;
71 }
72 
73 /**
74  * Let observe FIFO overflow.
75  */
76 static status_t let_observe_fifo_overflow(uint32_t timeout_usec) {
77  LOG_INFO("let observe FIFO overflow...");
78  IBEX_TRY_SPIN_FOR(entropy_src_fifo_has_overflowed(), timeout_usec);
79  return OK_STATUS();
80 }
81 
82 /**
83  * Determine whether health tested entropy bits have been dropped before the
84  * postht FIFO due to conditioner back pressure.
85  */
86 bool postht_entropy_dropped(void) {
87  uint32_t recov_alert_sts;
88  CHECK_DIF_OK(
89  dif_entropy_src_get_recoverable_alerts(&entropy_src, &recov_alert_sts));
90  bool dropped = bitfield_bit32_read(
91  recov_alert_sts,
92  ENTROPY_SRC_RECOV_ALERT_STS_POSTHT_ENTROPY_DROP_ALERT_BIT);
93  return dropped;
94 }
95 
96 // Configure the entropy complex.
97 static status_t entropy_config(
98  dif_entropy_src_single_bit_mode_t single_bit_mode) {
99  dif_edn_auto_params_t edn_params0 =
100  edn_testutils_auto_params_build(false, /*res_itval=*/0, /*glen_val=*/0);
101  dif_edn_auto_params_t edn_params1 =
102  edn_testutils_auto_params_build(false, /*res_itval=*/0, /*glen_val=*/0);
103  // Disable the entropy complex.
104  TRY(entropy_testutils_stop_all());
105  // Disable all health tests.
106  TRY(entropy_src_testutils_disable_health_tests(&entropy_src));
107 
108  // Enable FW override.
110  &entropy_src,
112  .entropy_insert_enable = false,
113  .buffer_threshold = kEntropySrcFifoThreshold,
114  },
116  // Enable entropy_src.
118  &entropy_src,
120  .fips_enable = true,
121  .route_to_firmware = false,
122  .bypass_conditioner = false,
123  .single_bit_mode = single_bit_mode,
124  .health_test_threshold_scope = false,
125  .health_test_window_size = kEntropySrcHealthTestWindowSize,
126  .alert_threshold = UINT16_MAX},
128 
129  // Enable CSRNG
130  TRY(dif_csrng_configure(&csrng));
131  // Enable EDNs in auto request mode
132  TRY(dif_edn_set_auto_mode(&edn0, edn_params0));
133  TRY(dif_edn_set_auto_mode(&edn1, edn_params1));
134  return OK_STATUS();
135 }
136 
137 /**
138  * Test the firmware override observe path.
139  *
140  * @param entropy An Entropy handle.
141  */
142 status_t firmware_override_observe(
143  uint32_t nr_samples, dif_entropy_src_single_bit_mode_t single_bit_mode,
144  uint32_t timeout_usec, uint32_t repeat_count) {
145  // Slow computation: do it once.
146  uint32_t nr_sample_words =
147  ceil_div(nr_samples * kBitsPerSample, sizeof(uint32_t));
148  // Configure the entropy complex.
149  entropy_config(single_bit_mode);
150 
151  LOG_INFO("==================");
152  LOG_INFO("Running test in mode %u, will run test %u times", single_bit_mode,
153  repeat_count);
154  while (repeat_count-- > 0) {
155  LOG_INFO("collecting %u samples...", nr_samples);
156  // Collect samples from the the observe FIFO.
157  uint32_t words_to_read = nr_sample_words;
158  uint32_t *sample_buffer_ptr = sample_buffer;
159  // Clear POSTHT_ENTROPY_DROP_ALERT bit.
161  &entropy_src,
162  ENTROPY_SRC_RECOV_ALERT_STS_POSTHT_ENTROPY_DROP_ALERT_BIT));
163  // Drain FIFO to make sure we get contiguous samples.
164  LOG_INFO("drain observe FIFO overflow...");
165  TRY(entropy_src_testutils_drain_observe_fifo(&entropy_src));
166  // Collect.
167  ibex_timeout_t tmo = ibex_timeout_init(timeout_usec);
168  while (words_to_read > 0 && !ibex_timeout_check(&tmo)) {
169  size_t len = words_to_read;
170  // Make sure no health tested entropy bits were dropped before the
171  // postht FIFO.
172  TRY_CHECK(!postht_entropy_dropped(),
173  "entropy bits dropped before postht FIFO");
174  // Check FIFO did not overflow during collection.
175  TRY_CHECK(!entropy_src_fifo_has_overflowed(),
176  "observe FIFO overflowed during collection");
178  &entropy_src, sample_buffer_ptr, &len));
179  sample_buffer_ptr += len;
180  words_to_read -= len;
181  }
182  TRY_CHECK(!ibex_timeout_check(&tmo), "did not collect samples in time");
183  uint64_t elapsed = ibex_timeout_elapsed(&tmo);
184  uint64_t freq =
185  udiv64_slow((uint64_t)nr_samples * (uint64_t)1000000, elapsed, NULL);
186  LOG_INFO("done in %ums (~ %usamples/s)",
187  (uint32_t)udiv64_slow(elapsed, 1000, NULL), (uint32_t)freq);
188 
189  // Let observe FIFO overflow
190  if (repeat_count > 0) {
191  TRY(let_observe_fifo_overflow(timeout_usec));
192  }
193  }
194  return OK_STATUS();
195 }
196 
197 bool test_main(void) {
198  CHECK_DIF_OK(dif_entropy_src_init(
200  CHECK_DIF_OK(dif_csrng_init(
202  CHECK_DIF_OK(
203  dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN0_BASE_ADDR), &edn0));
204  CHECK_DIF_OK(
205  dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN1_BASE_ADDR), &edn1));
206  // Test all modes.
207  static dif_entropy_src_single_bit_mode_t kModes[] = {
211  };
212  uint32_t contiguous_sample_count = kContiguousSamplesCount;
214  // If running on Verilator, then entropy is observed much more slowly,
215  // in addition to the standard simulator overhead. Observing 1024 words
216  // would take around 30+ seconds each, which would take dozens of hours
217  // to simulate. We only care that entropy observation works on Verilator
218  // and not that it works at a given rate, so we just observe 8 samples.
219  contiguous_sample_count = kVerilatorContiguousSamplesCount;
220  }
221  status_t test_result = OK_STATUS();
222  for (size_t i = 0; i < ARRAYSIZE(kModes); i++) {
223  EXECUTE_TEST(test_result, firmware_override_observe,
224  contiguous_sample_count, kModes[i], kTimeoutUsec,
225  kRepeatCount);
226  }
227 
228  return status_ok(test_result);
229 }