Software APIs
rom_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 
5 #include "sw/device/tests/penetrationtests/firmware/fi/rom_fi.h"
6 
9 #include "sw/device/lib/base/status.h"
11 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
13 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
14 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
15 #include "sw/device/lib/ujson/ujson.h"
16 #include "sw/device/tests/penetrationtests/firmware/lib/pentest_lib.h"
17 #include "sw/device/tests/penetrationtests/json/rom_fi_commands.h"
18 
20 #include "rom_ctrl_regs.h"
21 
22 // Interface to Ibex.
23 static dif_rv_core_ibex_t rv_core_ibex;
24 
25 static dif_rom_ctrl_t rom_ctrl;
26 
27 status_t handle_rom_read(ujson_t *uj) {
28  pentest_registered_alerts_t reg_alerts = pentest_get_triggered_alerts();
29 
30  dif_rom_ctrl_digest_t expected_digest;
31  dif_rom_ctrl_digest_t fi_digest[8];
32  TRY(dif_rom_ctrl_get_digest(&rom_ctrl, &expected_digest));
33 
34  pentest_set_trigger_high();
35  asm volatile(NOP30);
36  TRY(dif_rom_ctrl_get_digest(&rom_ctrl, &fi_digest[0]));
37  TRY(dif_rom_ctrl_get_digest(&rom_ctrl, &fi_digest[1]));
38  TRY(dif_rom_ctrl_get_digest(&rom_ctrl, &fi_digest[2]));
39  TRY(dif_rom_ctrl_get_digest(&rom_ctrl, &fi_digest[3]));
40  TRY(dif_rom_ctrl_get_digest(&rom_ctrl, &fi_digest[4]));
41  TRY(dif_rom_ctrl_get_digest(&rom_ctrl, &fi_digest[5]));
42  TRY(dif_rom_ctrl_get_digest(&rom_ctrl, &fi_digest[6]));
43  TRY(dif_rom_ctrl_get_digest(&rom_ctrl, &fi_digest[7]));
44  asm volatile(NOP30);
45  pentest_set_trigger_low();
46 
47  // Get registered alerts from alert handler.
48  reg_alerts = pentest_get_triggered_alerts();
49  // Get fatal and recoverable AST alerts from sensor controller.
50  pentest_sensor_alerts_t sensor_alerts = pentest_get_sensor_alerts();
51 
52  // Read ERR_STATUS register.
53  dif_rv_core_ibex_error_status_t codes;
54  TRY(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes));
55 
56  rom_fi_digest_t uj_output;
57  memset(uj_output.digest, 0, sizeof(uj_output.digest));
58  for (size_t i = 0; i < 8; i++) {
59  if (memcmp(&expected_digest, &fi_digest[i],
60  ROM_CTRL_DIGEST_MULTIREG_COUNT)) {
61  uj_output.digest[i] =
62  fi_digest[i]
63  .digest[0]; // Just return the first 32-bit of the digest.
64  }
65  }
66 
67  // Send the first 8 bytes of the digest and the alerts back to the host.
68  uj_output.err_status = codes;
69  memcpy(uj_output.alerts, reg_alerts.alerts, sizeof(reg_alerts.alerts));
70  memcpy(uj_output.ast_alerts, sensor_alerts.alerts,
71  sizeof(sensor_alerts.alerts));
72  RESP_OK(ujson_serialize_rom_fi_digest_t, uj, &uj_output);
73  return OK_STATUS();
74 }
75 
76 status_t handle_rom_fi_init(ujson_t *uj) {
77  penetrationtest_cpuctrl_t uj_data;
78  TRY(ujson_deserialize_penetrationtest_cpuctrl_t(uj, &uj_data));
79 
80  pentest_select_trigger_type(kPentestTriggerTypeSw);
81  pentest_init(kPentestTriggerSourceAes,
82  kPentestPeripheralIoDiv4 | kPentestPeripheralEdn |
83  kPentestPeripheralCsrng | kPentestPeripheralEntropy |
84  kPentestPeripheralKmac);
85 
86  // Configure the alert handler. Alerts triggered by IP blocks are captured
87  // and reported to the test.
88  pentest_configure_alert_handler();
89 
90  // Configure the CPU for the pentest.
91  penetrationtest_device_info_t uj_output;
92  TRY(pentest_configure_cpu(
93  uj_data.icache_disable, uj_data.dummy_instr_disable,
94  uj_data.enable_jittery_clock, uj_data.enable_sram_readback,
95  &uj_output.clock_jitter_locked, &uj_output.clock_jitter_en,
96  &uj_output.sram_main_readback_locked, &uj_output.sram_ret_readback_locked,
97  &uj_output.sram_main_readback_en, &uj_output.sram_ret_readback_en));
98 
99  // Initialize rom_ctrl.
100  mmio_region_t rom_ctrl_reg =
102  TRY(dif_rom_ctrl_init(rom_ctrl_reg, &rom_ctrl));
103 
104  // Configure Ibex to allow reading ERR_STATUS register.
105  TRY(dif_rv_core_ibex_init(
107  &rv_core_ibex));
108 
109  // Read device ID and return to host.
110  TRY(pentest_read_device_id(uj_output.device_id));
111  RESP_OK(ujson_serialize_penetrationtest_device_info_t, uj, &uj_output);
112 
113  return OK_STATUS();
114 }
115 
116 status_t handle_rom_fi(ujson_t *uj) {
117  rom_fi_subcommand_t cmd;
118  TRY(ujson_deserialize_rom_fi_subcommand_t(uj, &cmd));
119  switch (cmd) {
120  case kRomFiSubcommandInit:
121  return handle_rom_fi_init(uj);
122  case kRomFiSubcommandRead:
123  return handle_rom_read(uj);
124  default:
125  LOG_ERROR("Unrecognized Rom FI subcommand: %d", cmd);
126  return INVALID_ARGUMENT();
127  }
128  return OK_STATUS();
129 }