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