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