Software APIs
rng_fi.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 
6 #include "sw/device/lib/base/status.h"
8 #include "sw/device/lib/dif/dif_csrng_shared.h"
11 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
13 #include "sw/device/lib/testing/csrng_testutils.h"
14 #include "sw/device/lib/testing/edn_testutils.h"
15 #include "sw/device/lib/testing/entropy_src_testutils.h"
16 #include "sw/device/lib/testing/entropy_testutils.h"
17 #include "sw/device/lib/testing/rv_core_ibex_testutils.h"
18 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
19 #include "sw/device/lib/ujson/ujson.h"
20 #include "sw/device/tests/penetrationtests/firmware/lib/pentest_lib.h"
21 #include "sw/device/tests/penetrationtests/json/rng_fi_commands.h"
22 
23 #include "edn_regs.h" // Generated
25 
26 enum {
27  kEdnKatTimeout = (10 * 1000 * 1000),
28  kCsrngExpectedOutputLen = 16,
29  kEdnBusAckMaxData = 64,
30  kEdnBiasMaxData = 16,
31  kEdnKatMaxClen = 12,
32  kEdnKatOutputLen = 16,
33  kEdnKatWordsPerBlock = 4,
34  kEntropyFifoBufferSize = 32,
35  kCsrngBiasFWFifoBufferSize = 12,
36  kMaxReadCountNotBlocking = 32,
37  kTestParamEntropySrcMaxAttempts = 256,
38 };
39 
40 static dif_rv_core_ibex_t rv_core_ibex;
41 static dif_entropy_src_t entropy_src;
42 static dif_csrng_t csrng;
43 static dif_edn_t edn0;
44 static dif_edn_t edn1;
45 static bool disable_health_check;
46 
47 static bool firmware_override_init;
48 
49 static const uint32_t kInputMsg[kCsrngBiasFWFifoBufferSize] = {
50  0xa52a0da9, 0xcae141b2, 0x6d5bab9d, 0x2c3e5cc0, 0x225afc93, 0x5d31a610,
51  0x91b7f960, 0x0d566bb3, 0xef35e170, 0x94ba7d8e, 0x534eb741, 0x6b60b0da,
52 };
53 
54 // Seed material for the EDN KAT instantiate command.
55 static const dif_edn_seed_material_t kEdnKatSeedMaterialInstantiate = {
56  .len = kEdnKatMaxClen,
57  .data = {0x73bec010, 0x9262474c, 0x16a30f76, 0x531b51de, 0x2ee494e5,
58  0xdfec9db3, 0xcb7a879d, 0x5600419c, 0xca79b0b0, 0xdda33b5c,
59  0xa468649e, 0xdf5d73fa},
60 };
61 // Seed material for the EDN KAT reseed command.
62 static const dif_edn_seed_material_t kEdnKatSeedMaterialReseed = {
63  .len = kEdnKatMaxClen,
64  .data = {0x73bec010, 0x9262474c, 0x16a30f76, 0x531b51de, 0x2ee494e5,
65  0xdfec9db3, 0xcb7a879d, 0x5600419c, 0xca79b0b0, 0xdda33b5c,
66  0xa468649e, 0xdf5d73fa},
67 };
68 // Seed material for the EDN KAT generate command.
69 static const dif_edn_seed_material_t kEdnKatSeedMaterialGenerate = {
70  .len = 0,
71 };
72 
73 static dif_edn_auto_params_t kat_auto_params_build(void) {
74  return (dif_edn_auto_params_t){
76  {
77  .cmd = csrng_cmd_header_build(kCsrngAppCmdInstantiate,
79  kEdnKatSeedMaterialInstantiate.len,
80  /*generate_len=*/0),
81  .seed_material = kEdnKatSeedMaterialInstantiate,
82  },
83  .reseed_cmd =
84  {
85  .cmd = csrng_cmd_header_build(kCsrngAppCmdReseed,
87  kEdnKatSeedMaterialReseed.len,
88  /*generate_len=*/0),
89  .seed_material = kEdnKatSeedMaterialReseed,
90  },
91  .generate_cmd =
92  {
93  .cmd = csrng_cmd_header_build(
94  kCsrngAppCmdGenerate, kDifCsrngEntropySrcToggleDisable,
95  kEdnKatSeedMaterialGenerate.len,
96  /*generate_len=*/
97  kEdnKatOutputLen / kEdnKatWordsPerBlock),
98  .seed_material = kEdnKatSeedMaterialGenerate,
99  },
100  .reseed_interval = 32,
101  };
102 }
103 
104 static const uint32_t kExpectedOutput[kEdnKatOutputLen] = {
105  0xe48bb8cb, 0x1012c84c, 0x5af8a7f1, 0xd1c07cd9, 0xdf82ab22, 0x771c619b,
106  0xd40fccb1, 0x87189e99, 0x510494b3, 0x64f7ac0c, 0x2581f391, 0x80b1dc2f,
107  0x793e01c5, 0x87b107ae, 0xdb17514c, 0xa43c41b7,
108 };
109 
110 /**
111  * Flushes the data entropy buffer until there is no data available to read.
112  *
113  * Asserts test error if any of the returned words is equal to zero. Logs the
114  * number of entropy words flushed in a single call.
115  *
116  * @param entropy An entropy source instance.
117  */
118 static void entropy_data_flush(dif_entropy_src_t *entropy_src) {
119  uint32_t entropy_bits;
120  uint32_t read_count = 0;
121 
122  // TODO: Remove this limit. Entropy source should block if there is no entropy
123  // available in FW override mode.
124  const uint32_t kMaxReadCount = 128;
125 
126  while (dif_entropy_src_is_entropy_available(entropy_src) == kDifOk) {
127  CHECK_DIF_OK(dif_entropy_src_non_blocking_read(entropy_src, &entropy_bits));
128  CHECK(entropy_bits != 0);
129  read_count++;
130  if (read_count >= kMaxReadCount) {
131  break;
132  }
133  }
134 }
135 
136 /**
137  * Stops the entropy_src conditioner.
138  *
139  * @param entropy_src A entropy source handle.
140  */
141 static void entropy_conditioner_stop(const dif_entropy_src_t *entropy_src) {
142  uint32_t fail_count = 0;
143  dif_result_t op_result;
144  do {
145  op_result = dif_entropy_src_conditioner_stop(entropy_src);
146  if (op_result == kDifIpFifoFull) {
147  CHECK(fail_count++ < kTestParamEntropySrcMaxAttempts);
148  } else {
149  CHECK_DIF_OK(op_result);
150  }
151  } while (op_result == kDifIpFifoFull);
152 }
153 
154 status_t handle_rng_fi_entropy_src_bias(ujson_t *uj) {
155  // Clear registered alerts in alert handler.
156  pentest_registered_alerts_t reg_alerts = pentest_get_triggered_alerts();
157  // Clear the AST recoverable alerts.
158  pentest_clear_sensor_recov_alerts();
159 
161 
162  // Setup fips grade entropy that can be read by firmware.
163  const dif_entropy_src_config_t config = {
164  .fips_enable = true,
165  .route_to_firmware = true,
166  .single_bit_mode = kDifEntropySrcSingleBitModeDisabled,
167  .health_test_threshold_scope = false, /*default*/
168  .health_test_window_size = 0x0200, /*default*/
169  .alert_threshold = 2, /*default*/
170  };
171 
172  // Re-enable entropy src.
173  TRY(dif_entropy_src_configure(&entropy_src, config, kDifToggleEnabled));
174  // ensure health tests are actually running
175  TRY(entropy_src_testutils_wait_for_state(
176  &entropy_src, kDifEntropySrcMainFsmStateContHTRunning));
177 
178  entropy_data_flush(&entropy_src);
179 
180  uint32_t entropy_bits[kMaxReadCountNotBlocking] = {0};
181 
182  pentest_set_trigger_high();
183  asm volatile(NOP30);
184  for (size_t it = 0; it < kMaxReadCountNotBlocking; it++) {
185  while (dif_entropy_src_non_blocking_read(&entropy_src, &entropy_bits[it]) !=
186  kDifOk)
187  ;
188  }
189  asm volatile(NOP30);
190  pentest_set_trigger_low();
191 
192  // Get registered alerts from alert handler.
193  reg_alerts = pentest_get_triggered_alerts();
194  // Get fatal and recoverable AST alerts from sensor controller.
195  pentest_sensor_alerts_t sensor_alerts = pentest_get_sensor_alerts();
196 
197  // Read ERR_STATUS register from Ibex.
198  dif_rv_core_ibex_error_status_t err_ibx;
199  TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &err_ibx));
200 
201  // Send result & ERR_STATUS to host.
202  rng_fi_entropy_src_bias_t uj_output;
203  // Send result & ERR_STATUS to host.
204  memcpy(uj_output.rand, entropy_bits, sizeof(entropy_bits));
205  uj_output.err_status = err_ibx;
206  memcpy(uj_output.alerts, reg_alerts.alerts, sizeof(reg_alerts.alerts));
207  memcpy(uj_output.ast_alerts, sensor_alerts.alerts,
208  sizeof(sensor_alerts.alerts));
209  RESP_OK(ujson_serialize_rng_fi_entropy_src_bias_t, uj, &uj_output);
210 
211  return OK_STATUS();
212 }
213 
214 status_t handle_rng_fi_firmware_override(ujson_t *uj) {
215  // Clear registered alerts in alert handler.
216  pentest_registered_alerts_t reg_alerts = pentest_get_triggered_alerts();
217  // Clear the AST recoverable alerts.
218  pentest_clear_sensor_recov_alerts();
219 
220  if (!firmware_override_init) {
221  // Check if we keep heal tests enabled.
222  rng_fi_fw_overwrite_health_t uj_data;
223  TRY(ujson_deserialize_rng_fi_fw_overwrite_health_t(uj, &uj_data));
224  disable_health_check = uj_data.disable_health_check;
225 
226  firmware_override_init = true;
227  }
228 
229  TRY(entropy_testutils_stop_all());
230 
231  if (disable_health_check) {
232  // Disable all health tests.
233  TRY(entropy_src_testutils_disable_health_tests(&entropy_src));
234  }
235 
236  TRY(entropy_src_testutils_fw_override_enable(&entropy_src,
237  kEntropyFifoBufferSize,
238  /*route_to_firmware=*/true,
239  /*bypass_conditioner=*/true));
240 
241  entropy_data_flush(&entropy_src);
242 
243  uint32_t buf[kEntropyFifoBufferSize] = {0};
244 
245  pentest_set_trigger_high();
246  asm volatile(NOP30);
247  for (size_t it = 0; it < kEntropyFifoBufferSize; it++) {
248  while (buf[it] == 0) {
249  TRY(dif_entropy_src_observe_fifo_blocking_read(&entropy_src, &buf[it],
250  kEntropyFifoBufferSize));
251  }
252  }
253 
254  asm volatile(NOP30);
255  pentest_set_trigger_low();
256 
257  // Get registered alerts from alert handler.
258  reg_alerts = pentest_get_triggered_alerts();
259  // Get fatal and recoverable AST alerts from sensor controller.
260  pentest_sensor_alerts_t sensor_alerts = pentest_get_sensor_alerts();
261 
262  // Read ERR_STATUS register from Ibex.
263  dif_rv_core_ibex_error_status_t err_ibx;
264  TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &err_ibx));
265 
266  // Send result & ERR_STATUS to host.
267  rng_fi_fw_overwrite_t uj_output;
268  // Send result & ERR_STATUS to host.
269  memcpy(uj_output.rand, buf, sizeof(buf));
270  uj_output.err_status = err_ibx;
271  memcpy(uj_output.alerts, reg_alerts.alerts, sizeof(reg_alerts.alerts));
272  memcpy(uj_output.ast_alerts, sensor_alerts.alerts,
273  sizeof(sensor_alerts.alerts));
274  RESP_OK(ujson_serialize_rng_fi_fw_overwrite_t, uj, &uj_output);
275 
276  return OK_STATUS();
277 }
278 
279 status_t handle_rng_fi_edn_bias(ujson_t *uj) {
280  // Clear registered alerts in alert handler.
281  pentest_registered_alerts_t reg_alerts = pentest_get_triggered_alerts();
282  // Clear the AST recoverable alerts.
283  pentest_clear_sensor_recov_alerts();
284 
285  TRY(dif_entropy_src_init(
288  &csrng));
289  TRY(dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN0_BASE_ADDR), &edn0));
290  TRY(dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN1_BASE_ADDR), &edn1));
291  TRY(dif_rv_core_ibex_init(
293  &rv_core_ibex));
294 
295  dif_edn_auto_params_t edn_params =
296  edn_testutils_auto_params_build(true, /*res_itval=*/0, /*glen_val=*/0);
297  // Disable the entropy complex.
298  TRY(entropy_testutils_stop_all());
299  // Enable ENTROPY_SRC in FIPS mode.
300  TRY(entropy_testutils_entropy_src_init());
301  // Enable CSRNG.
302  TRY(dif_csrng_configure(&csrng));
303  // Enable EDN1 in auto request mode.
304  TRY(dif_edn_set_auto_mode(&edn1, edn_params));
305  // Enable EDN0 in auto request mode.
306  TRY(dif_edn_set_auto_mode(&edn0, kat_auto_params_build()));
307 
308  uint32_t ibex_rnd_data_got[kEdnBiasMaxData];
309 
310  pentest_set_trigger_high();
311  asm volatile(NOP30);
312  for (size_t it = 0; it < kEdnBiasMaxData; it++) {
313  CHECK_STATUS_OK(rv_core_ibex_testutils_get_rnd_data(
314  &rv_core_ibex, kEdnKatTimeout, &ibex_rnd_data_got[it]));
315  }
316  asm volatile(NOP30);
317  pentest_set_trigger_low();
318 
319  rng_fi_edn_t uj_output;
320  memset(uj_output.rand, 0, sizeof(uj_output.rand));
321  size_t collisions = 0;
322  for (size_t got = 0; got < kEdnBiasMaxData; got++) {
323  for (size_t ref = 0; ref < kEdnBiasMaxData; ref++) {
324  if (ibex_rnd_data_got[got] == kExpectedOutput[ref]) {
325  uj_output.rand[collisions] = ibex_rnd_data_got[got];
326  collisions++;
327  }
328  }
329  }
330 
331  // Get registered alerts from alert handler.
332  reg_alerts = pentest_get_triggered_alerts();
333  // Get fatal and recoverable AST alerts from sensor controller.
334  pentest_sensor_alerts_t sensor_alerts = pentest_get_sensor_alerts();
335 
336  // Read ERR_STATUS register from Ibex.
337  dif_rv_core_ibex_error_status_t err_ibx;
338  TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &err_ibx));
339 
340  // Send result & ERR_STATUS to host.
341  uj_output.collisions = collisions;
342  memcpy(uj_output.alerts, reg_alerts.alerts, sizeof(reg_alerts.alerts));
343  memcpy(uj_output.ast_alerts, sensor_alerts.alerts,
344  sizeof(sensor_alerts.alerts));
345  uj_output.err_status = err_ibx;
346  RESP_OK(ujson_serialize_rng_fi_edn_t, uj, &uj_output);
347  return OK_STATUS();
348 }
349 
350 status_t handle_rng_fi_edn_resp_ack(ujson_t *uj) {
351  // Clear registered alerts in alert handler.
352  pentest_registered_alerts_t reg_alerts = pentest_get_triggered_alerts();
353  // Clear the AST recoverable alerts.
354  pentest_clear_sensor_recov_alerts();
355  // Enable entropy complex, CSRNG and EDN so Ibex can get entropy.
356  // Configure entropy in auto_mode to avoid starving the system from entropy,
357  // given that boot mode entropy has a limited number of generated bits.
358  TRY(entropy_testutils_auto_mode_init());
359 
360  uint32_t ibex_rnd_data[kEdnBusAckMaxData];
361 
362  // Inject faults during generating and receiving random data.
363  // Goal is to manipulate ACK on bus to trigger that the same
364  // data chunk is transmitted multiple times.
365  pentest_set_trigger_high();
366  asm volatile(NOP30);
367  for (size_t it = 0; it < kEdnBusAckMaxData; it++) {
368  TRY(rv_core_ibex_testutils_get_rnd_data(&rv_core_ibex, kEdnKatTimeout,
369  &ibex_rnd_data[it]));
370  }
371  pentest_set_trigger_low();
372 
373  // Check if there are any collisions.
374  rng_fi_edn_t uj_output;
375  memset(uj_output.rand, 0, sizeof(uj_output.rand));
376  size_t collisions = 0;
377  for (size_t outer = 0; outer < kEdnBusAckMaxData; outer++) {
378  for (size_t inner = 0; inner < kEdnBusAckMaxData; inner++) {
379  if (outer != inner && ibex_rnd_data[outer] == ibex_rnd_data[inner]) {
380  if (collisions < 16) {
381  uj_output.rand[collisions] = ibex_rnd_data[outer];
382  }
383  collisions++;
384  }
385  }
386  }
387 
388  // Get registered alerts from alert handler.
389  reg_alerts = pentest_get_triggered_alerts();
390  // Get fatal and recoverable AST alerts from sensor controller.
391  pentest_sensor_alerts_t sensor_alerts = pentest_get_sensor_alerts();
392 
393  // Read ERR_STATUS register from Ibex.
394  dif_rv_core_ibex_error_status_t err_ibx;
395  TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &err_ibx));
396 
397  // Send result & ERR_STATUS to host.
398  uj_output.collisions = collisions;
399  memcpy(uj_output.alerts, reg_alerts.alerts, sizeof(reg_alerts.alerts));
400  memcpy(uj_output.ast_alerts, sensor_alerts.alerts,
401  sizeof(sensor_alerts.alerts));
402  uj_output.err_status = err_ibx;
403  RESP_OK(ujson_serialize_rng_fi_edn_t, uj, &uj_output);
404  return OK_STATUS();
405 }
406 
407 status_t handle_rng_fi_edn_init(ujson_t *uj) {
408  penetrationtest_cpuctrl_t uj_data;
409  TRY(ujson_deserialize_penetrationtest_cpuctrl_t(uj, &uj_data));
410 
411  pentest_select_trigger_type(kPentestTriggerTypeSw);
412  // As we are using the software defined trigger, the first argument of
413  // pentest_init is not needed. kPentestTriggerSourceAes is selected as a
414  // placeholder.
415  pentest_init(kPentestTriggerSourceAes,
416  kPentestPeripheralIoDiv4 | kPentestPeripheralEntropy |
417  kPentestPeripheralCsrng | kPentestPeripheralEdn);
418 
419  // Configure the CPU for the pentest.
420  penetrationtest_device_info_t uj_output;
421  TRY(pentest_configure_cpu(
422  uj_data.icache_disable, uj_data.dummy_instr_disable,
423  uj_data.enable_jittery_clock, uj_data.enable_sram_readback,
424  &uj_output.clock_jitter_locked, &uj_output.clock_jitter_en,
425  &uj_output.sram_main_readback_locked, &uj_output.sram_ret_readback_locked,
426  &uj_output.sram_main_readback_en, &uj_output.sram_ret_readback_en));
427 
428  // Configure Ibex to allow reading ERR_STATUS register.
429  TRY(dif_rv_core_ibex_init(
431  &rv_core_ibex));
432 
433  // Configure the alert handler. Alerts triggered by IP blocks are captured
434  // and reported to the test.
435  pentest_configure_alert_handler();
436 
437  // Initialize peripherals used in this FI test.
438  TRY(dif_entropy_src_init(
441  &csrng));
442  TRY(dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN0_BASE_ADDR), &edn0));
443  TRY(dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN1_BASE_ADDR), &edn1));
444 
445  // Read device ID and return to host.
446  TRY(pentest_read_device_id(uj_output.device_id));
447  RESP_OK(ujson_serialize_penetrationtest_device_info_t, uj, &uj_output);
448 
449  firmware_override_init = false;
450 
451  return OK_STATUS();
452 }
453 
454 status_t handle_rng_fi_csrng_bias(ujson_t *uj) {
455  // Get the test mode.
456  crypto_fi_csrng_mode_t uj_data;
457  TRY(ujson_deserialize_crypto_fi_csrng_mode_t(uj, &uj_data));
458  // Clear registered alerts in alert handler.
459  pentest_registered_alerts_t reg_alerts = pentest_get_triggered_alerts();
460  // Clear the AST recoverable alerts.
461  pentest_clear_sensor_recov_alerts();
462 
463  TRY(csrng_testutils_cmd_ready_wait(&csrng));
464  TRY(dif_csrng_uninstantiate(&csrng));
465 
466  const dif_csrng_seed_material_t kEntropyInput = {
467  .seed_material = {0x73bec010, 0x9262474c, 0x16a30f76, 0x531b51de,
468  0x2ee494e5, 0xdfec9db3, 0xcb7a879d, 0x5600419c,
469  0xca79b0b0, 0xdda33b5c, 0xa468649e, 0xdf5d73fa},
470  .seed_material_len = 12,
471  };
472 
474  &kEntropyInput));
475 
476  // FI code target.
477  uint32_t rand_data_got[kCsrngExpectedOutputLen];
478  TRY(csrng_testutils_cmd_ready_wait(&csrng));
479 
480  if (uj_data.all_trigger || uj_data.start_trigger) {
481  pentest_set_trigger_high();
482  }
483  TRY(dif_csrng_generate_start(&csrng, kCsrngExpectedOutputLen));
484  if (uj_data.start_trigger) {
485  pentest_set_trigger_low();
486  }
487 
488  if (uj_data.valid_trigger) {
489  pentest_set_trigger_high();
490  }
491  dif_csrng_output_status_t output_status;
492  do {
493  TRY(dif_csrng_get_output_status(&csrng, &output_status));
494  } while (!output_status.valid_data);
495  if (uj_data.valid_trigger) {
496  pentest_set_trigger_low();
497  }
498 
499  if (uj_data.read_trigger) {
500  pentest_set_trigger_high();
501  }
502  TRY(dif_csrng_generate_read(&csrng, rand_data_got, kCsrngExpectedOutputLen));
503  if (uj_data.all_trigger || uj_data.read_trigger) {
504  pentest_set_trigger_low();
505  }
506 
507  // Get registered alerts from alert handler.
508  reg_alerts = pentest_get_triggered_alerts();
509  // Get fatal and recoverable AST alerts from sensor controller.
510  pentest_sensor_alerts_t sensor_alerts = pentest_get_sensor_alerts();
511 
512  // Read ERR_STATUS register from Ibex.
513  dif_rv_core_ibex_error_status_t err_ibx;
514  TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &err_ibx));
515 
516  // Compare with expected data.
517  const uint32_t kExpectedOutput[kCsrngExpectedOutputLen] = {
518  932170270, 3480632584, 387346064, 186012424, 899661374, 2795183089,
519  336687633, 3222931513, 1490543709, 3319795384, 3464147855, 1850271046,
520  1239323641, 2292604615, 3314177342, 1567494162,
521  };
522  rng_fi_csrng_output_t uj_output;
523  uj_output.res = 0;
524  for (size_t it = 0; it < kCsrngExpectedOutputLen; it++) {
525  if (rand_data_got[it] != kExpectedOutput[it]) {
526  uj_output.res = 1;
527  }
528  }
529 
530  // Send result & ERR_STATUS to host.
531  memcpy(uj_output.rand, rand_data_got, sizeof(rand_data_got));
532  uj_output.err_status = err_ibx;
533  memcpy(uj_output.alerts, reg_alerts.alerts, sizeof(reg_alerts.alerts));
534  memcpy(uj_output.ast_alerts, sensor_alerts.alerts,
535  sizeof(sensor_alerts.alerts));
536  RESP_OK(ujson_serialize_rng_fi_csrng_output_t, uj, &uj_output);
537 
538  return OK_STATUS();
539 }
540 
541 status_t handle_rng_fi_csrng_bias_fw_override(ujson_t *uj, bool static_seed) {
542  // Clear registered alerts in alert handler.
543  pentest_registered_alerts_t reg_alerts = pentest_get_triggered_alerts();
544  // Clear the AST recoverable alerts.
545  pentest_clear_sensor_recov_alerts();
546 
547  uint32_t received_data[kCsrngBiasFWFifoBufferSize];
548  const dif_csrng_seed_material_t kEmptySeedMaterial = {0};
549 
550  uint32_t seed[kCsrngBiasFWFifoBufferSize];
551 
552  if (static_seed) {
553  memcpy(seed, kInputMsg, sizeof(kInputMsg));
554  } else {
555  rng_fi_seed_t uj_data;
556  TRY(ujson_deserialize_rng_fi_seed_t(uj, &uj_data));
557  memcpy(seed, uj_data.seed, sizeof(uj_data.seed));
558  }
559 
560  CHECK_STATUS_OK(entropy_testutils_stop_all());
561  CHECK_STATUS_OK(entropy_src_testutils_fw_override_enable(
562  &entropy_src, kCsrngBiasFWFifoBufferSize,
563  /*route_to_firmware=*/false,
564  /*bypass_conditioner=*/false));
565 
566  entropy_data_flush(&entropy_src);
567 
568  CHECK_DIF_OK(dif_csrng_configure(&csrng));
569 
570  CHECK_DIF_OK(dif_entropy_src_conditioner_start(&entropy_src));
571 
572  uint32_t fail_count = 0;
573  uint32_t total = 0;
574  do {
575  uint32_t count;
577  &entropy_src, seed + total, ARRAYSIZE(seed) - total, &count);
578  total += count;
579  if (op_result == kDifIpFifoFull) {
580  CHECK(fail_count++ < kTestParamEntropySrcMaxAttempts);
581  } else {
582  fail_count = 0;
583  CHECK_DIF_OK(op_result);
584  }
585  } while (total < ARRAYSIZE(seed));
586 
587  pentest_set_trigger_high();
588  entropy_conditioner_stop(&entropy_src);
589 
590  TRY(csrng_testutils_cmd_ready_wait(&csrng));
592  &kEmptySeedMaterial));
593 
594  CHECK_STATUS_OK(csrng_testutils_cmd_generate_run(&csrng, received_data,
595  ARRAYSIZE(received_data)));
596 
597  asm volatile(NOP30);
598  pentest_set_trigger_low();
599 
600  // Get registered alerts from alert handler.
601  reg_alerts = pentest_get_triggered_alerts();
602  // Get fatal and recoverable AST alerts from sensor controller.
603  pentest_sensor_alerts_t sensor_alerts = pentest_get_sensor_alerts();
604 
605  // Read ERR_STATUS register from Ibex.
606  dif_rv_core_ibex_error_status_t err_ibx;
607  TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &err_ibx));
608 
609  rng_fi_csrng_ov_output_t uj_output;
610 
611  // Send result & ERR_STATUS to host.
612  uj_output.res = 0; // No result is returned.
613  memcpy(uj_output.rand, received_data, sizeof(received_data));
614  uj_output.err_status = err_ibx;
615  memcpy(uj_output.alerts, reg_alerts.alerts, sizeof(reg_alerts.alerts));
616  memcpy(uj_output.ast_alerts, sensor_alerts.alerts,
617  sizeof(sensor_alerts.alerts));
618  RESP_OK(ujson_serialize_rng_fi_csrng_ov_output_t, uj, &uj_output);
619 
620  return OK_STATUS();
621 }
622 
623 status_t handle_rng_fi_csrng_init(ujson_t *uj) {
624  penetrationtest_cpuctrl_t uj_data;
625  TRY(ujson_deserialize_penetrationtest_cpuctrl_t(uj, &uj_data));
626 
627  pentest_select_trigger_type(kPentestTriggerTypeSw);
628  // As we are using the software defined trigger, the first argument of
629  // pentest_init is not needed. kPentestTriggerSourceAes is selected as a
630  // placeholder.
631  pentest_init(kPentestTriggerSourceAes,
632  kPentestPeripheralIoDiv4 | kPentestPeripheralCsrng);
633 
634  // Configure the CPU for the pentest.
635  penetrationtest_device_info_t uj_output;
636  TRY(pentest_configure_cpu(
637  uj_data.icache_disable, uj_data.dummy_instr_disable,
638  uj_data.enable_jittery_clock, uj_data.enable_sram_readback,
639  &uj_output.clock_jitter_locked, &uj_output.clock_jitter_en,
640  &uj_output.sram_main_readback_locked, &uj_output.sram_ret_readback_locked,
641  &uj_output.sram_main_readback_en, &uj_output.sram_ret_readback_en));
642 
643  // Configure Ibex to allow reading ERR_STATUS register.
644  TRY(dif_rv_core_ibex_init(
646  &rv_core_ibex));
647 
648  // Configure the alert handler. Alerts triggered by IP blocks are captured
649  // and reported to the test.
650  pentest_configure_alert_handler();
651 
652  // Initialize CSRNG.
654  CHECK_DIF_OK(dif_csrng_init(base_addr, &csrng));
655  CHECK_DIF_OK(dif_csrng_configure(&csrng));
656 
657  // Read device ID and return to host.
658  TRY(pentest_read_device_id(uj_output.device_id));
659  RESP_OK(ujson_serialize_penetrationtest_device_info_t, uj, &uj_output);
660 
661  return OK_STATUS();
662 }
663 
664 status_t handle_rng_fi(ujson_t *uj) {
665  rng_fi_subcommand_t cmd;
666  TRY(ujson_deserialize_rng_fi_subcommand_t(uj, &cmd));
667  switch (cmd) {
668  case kRngFiSubcommandCsrngInit:
669  return handle_rng_fi_csrng_init(uj);
670  case kRngFiSubcommandCsrngBias:
671  return handle_rng_fi_csrng_bias(uj);
672  case kRngFiSubcommandCsrngBiasFWOverride:
673  return handle_rng_fi_csrng_bias_fw_override(uj, false);
674  case kRngFiSubcommandCsrngBiasFWOverrideStatic:
675  return handle_rng_fi_csrng_bias_fw_override(uj, true);
676  case kRngFiSubcommandEdnInit:
677  return handle_rng_fi_edn_init(uj);
678  case kRngFiSubcommandEdnRespAck:
679  return handle_rng_fi_edn_resp_ack(uj);
680  case kRngFiSubcommandEdnBias:
681  return handle_rng_fi_edn_bias(uj);
682  case kRngFiSubcommandFWOverride:
683  return handle_rng_fi_firmware_override(uj);
684  case kRngFiSubcommandEntropySrcBias:
685  return handle_rng_fi_entropy_src_bias(uj);
686  default:
687  LOG_ERROR("Unrecognized RNG FI subcommand: %d", cmd);
688  return INVALID_ARGUMENT();
689  }
690  return OK_STATUS();
691 }