Software APIs
otp_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/otp_fi.h"
6 
8 #include "sw/device/lib/base/status.h"
11 #include "sw/device/lib/testing/otp_ctrl_testutils.h"
12 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
13 #include "sw/device/lib/ujson/ujson.h"
14 #include "sw/device/tests/penetrationtests/firmware/lib/pentest_lib.h"
15 #include "sw/device/tests/penetrationtests/json/otp_fi_commands.h"
16 
18 #include "otp_ctrl_regs.h" // Generated.
19 
20 static dif_otp_ctrl_t otp;
21 
22 uint32_t
23  otp_read32_result_vendor_test_comp[OTP_CTRL_PARAM_VENDOR_TEST_SIZE / 4];
24 uint32_t otp_read32_result_vendor_test_fi[OTP_CTRL_PARAM_VENDOR_TEST_SIZE / 4];
25 uint32_t
26  otp_read32_result_owner_sw_cfg_comp[OTP_CTRL_PARAM_OWNER_SW_CFG_SIZE / 4];
27 uint32_t
28  otp_read32_result_owner_sw_cfg_fi[OTP_CTRL_PARAM_OWNER_SW_CFG_SIZE / 4];
29 uint32_t otp_read32_result_hw_cfg_comp[OTP_CTRL_PARAM_HW_CFG0_SIZE / 4];
30 uint32_t otp_read32_result_hw_cfg_fi[OTP_CTRL_PARAM_HW_CFG0_SIZE / 4];
31 uint32_t otp_read32_result_life_cycle_comp[OTP_CTRL_PARAM_LIFE_CYCLE_SIZE / 4];
32 uint32_t otp_read32_result_life_cycle_fi[OTP_CTRL_PARAM_LIFE_CYCLE_SIZE / 4];
33 
34 void init_otp_mem_dump_buffers(void) {
35  for (uint32_t i = 0; i < OTP_CTRL_PARAM_VENDOR_TEST_SIZE / 4; i++) {
36  otp_read32_result_vendor_test_comp[i] = 0x00000001;
37  otp_read32_result_vendor_test_fi[i] = 0x00000001;
38  }
39  for (uint32_t i = 0; i < OTP_CTRL_PARAM_OWNER_SW_CFG_SIZE / 4; i++) {
40  otp_read32_result_owner_sw_cfg_comp[i] = 0x00000001;
41  otp_read32_result_owner_sw_cfg_fi[i] = 0x00000001;
42  }
43  for (uint32_t i = 0; i < OTP_CTRL_PARAM_HW_CFG0_SIZE / 4; i++) {
44  otp_read32_result_hw_cfg_comp[i] = 0x00000001;
45  otp_read32_result_hw_cfg_fi[i] = 0x00000001;
46  }
47  for (uint32_t i = 0; i < OTP_CTRL_PARAM_LIFE_CYCLE_SIZE / 4; i++) {
48  otp_read32_result_life_cycle_comp[i] = 0x00000001;
49  otp_read32_result_life_cycle_fi[i] = 0x00000001;
50  }
51 }
52 
53 status_t otp_vendor_test_dump(uint32_t *buffer) {
54  // Read VENDOR_TEST partition
55  TRY(otp_ctrl_testutils_dai_read32_array(&otp, kDifOtpCtrlPartitionVendorTest,
56  0, buffer,
57  OTP_CTRL_PARAM_VENDOR_TEST_SIZE / 4));
58 
59  return OK_STATUS();
60 }
61 
62 status_t otp_owner_sw_cfg_dump(uint32_t *buffer) {
63  // Read OWNER_SW_CFG partition
64  TRY(otp_ctrl_testutils_dai_read32_array(
65  &otp, kDifOtpCtrlPartitionOwnerSwCfg, 0, buffer,
66  OTP_CTRL_PARAM_OWNER_SW_CFG_SIZE / 4));
67 
68  return OK_STATUS();
69 }
70 
71 status_t otp_hw_cfg_dump(uint32_t *buffer) {
72  // Read HW_CFG partition
73  TRY(otp_ctrl_testutils_dai_read32_array(&otp, kDifOtpCtrlPartitionHwCfg0, 0,
74  buffer,
75  OTP_CTRL_PARAM_HW_CFG0_SIZE / 4));
76 
77  return OK_STATUS();
78 }
79 
80 status_t otp_life_cycle_dump(uint32_t *buffer) {
81  // Read LIFE_CYCLE partition
82  TRY(otp_ctrl_testutils_dai_read32_array(&otp, kDifOtpCtrlPartitionLifeCycle,
83  0, buffer,
84  OTP_CTRL_PARAM_LIFE_CYCLE_SIZE / 4));
85 
86  return OK_STATUS();
87 }
88 
89 status_t handle_otp_fi_hw_cfg(ujson_t *uj) {
90  // Clear registered alerts in alert handler.
91  pentest_registered_alerts_t reg_alerts = pentest_get_triggered_alerts();
92  // Clear the AST recoverable alerts.
93  pentest_clear_sensor_recov_alerts();
94 
95  // Read OTP partition for comparison values
96  TRY(otp_hw_cfg_dump(otp_read32_result_hw_cfg_comp));
97 
98  // FI code target.
99  pentest_set_trigger_high();
100 
101  // Point for FI
102  asm volatile(NOP1000);
103  asm volatile(NOP1000);
104  asm volatile(NOP1000);
105  asm volatile(NOP1000);
106 
107  pentest_set_trigger_low();
108 
109  // Read OTP partition again to see if values changed
110  TRY(otp_hw_cfg_dump(otp_read32_result_hw_cfg_fi));
111 
112  // Get registered alerts from alert handler.
113  reg_alerts = pentest_get_triggered_alerts();
114  // Get fatal and recoverable AST alerts from sensor controller.
115  pentest_sensor_alerts_t sensor_alerts = pentest_get_sensor_alerts();
116 
117  // Get OTP CTRL status
119  TRY(dif_otp_ctrl_get_status(&otp, &status));
120 
121  // Send result & status codes to host.
122  otp_fi_hwcfg_partition_t uj_output;
123  for (uint32_t i = 0; i < OTP_CTRL_PARAM_HW_CFG0_SIZE / 4; i++) {
124  uj_output.hw_cfg_comp[i] = otp_read32_result_hw_cfg_comp[i];
125  uj_output.hw_cfg_fi[i] = otp_read32_result_hw_cfg_fi[i];
126  }
127  uj_output.otp_status_codes = status.codes;
128  memcpy(uj_output.otp_error_causes, (uint8_t *)status.causes,
130  uj_output.alerts[0] = reg_alerts.alerts[0];
131  uj_output.alerts[1] = reg_alerts.alerts[1];
132  uj_output.alerts[2] = reg_alerts.alerts[2];
133  memcpy(uj_output.ast_alerts, sensor_alerts.alerts,
134  sizeof(sensor_alerts.alerts));
135  RESP_OK(ujson_serialize_otp_fi_hwcfg_partition_t, uj, &uj_output);
136 
137  return OK_STATUS();
138 }
139 
140 status_t handle_otp_fi_init(ujson_t *uj) {
141  penetrationtest_cpuctrl_t uj_data;
142  TRY(ujson_deserialize_penetrationtest_cpuctrl_t(uj, &uj_data));
143 
144  pentest_select_trigger_type(kPentestTriggerTypeSw);
145  // As we are using the software defined trigger, the first argument of
146  // pentest_init is not needed. kPentestTriggerSourceAes is selected as a
147  // placeholder.
148  pentest_init(kPentestTriggerSourceAes,
149  kPentestPeripheralIoDiv4 | kPentestPeripheralEdn |
150  kPentestPeripheralCsrng | kPentestPeripheralEntropy |
151  kPentestPeripheralAes | kPentestPeripheralHmac |
152  kPentestPeripheralKmac | kPentestPeripheralOtbn);
153 
154  // Configure the alert handler. Alerts triggered by IP blocks are captured
155  // and reported to the test.
156  pentest_configure_alert_handler();
157 
158  // Configure the CPU for the pentest.
159  penetrationtest_device_info_t uj_output;
160  TRY(pentest_configure_cpu(
161  uj_data.icache_disable, uj_data.dummy_instr_disable,
162  uj_data.enable_jittery_clock, uj_data.enable_sram_readback,
163  &uj_output.clock_jitter_locked, &uj_output.clock_jitter_en,
164  &uj_output.sram_main_readback_locked, &uj_output.sram_ret_readback_locked,
165  &uj_output.sram_main_readback_en, &uj_output.sram_ret_readback_en));
166 
167  TRY(dif_otp_ctrl_init(
169 
170  init_otp_mem_dump_buffers();
171 
172  // Read device ID and return to host.
173  TRY(pentest_read_device_id(uj_output.device_id));
174  RESP_OK(ujson_serialize_penetrationtest_device_info_t, uj, &uj_output);
175 
176  return OK_STATUS();
177 }
178 
179 status_t handle_otp_fi_life_cycle(ujson_t *uj) {
180  // Clear registered alerts in alert handler.
181  pentest_registered_alerts_t reg_alerts = pentest_get_triggered_alerts();
182  // Clear the AST recoverable alerts.
183  pentest_clear_sensor_recov_alerts();
184 
185  // Read OTP partition for comparison values
186  TRY(otp_life_cycle_dump(otp_read32_result_life_cycle_comp));
187 
188  // FI code target.
189  pentest_set_trigger_high();
190 
191  // Point for FI
192  asm volatile(NOP1000);
193  asm volatile(NOP1000);
194  asm volatile(NOP1000);
195  asm volatile(NOP1000);
196 
197  pentest_set_trigger_low();
198 
199  // Read OTP partition again to see if values changed
200  TRY(otp_life_cycle_dump(otp_read32_result_life_cycle_fi));
201 
202  // Get registered alerts from alert handler.
203  reg_alerts = pentest_get_triggered_alerts();
204  // Get fatal and recoverable AST alerts from sensor controller.
205  pentest_sensor_alerts_t sensor_alerts = pentest_get_sensor_alerts();
206 
207  // Get OTP CTRL status
209  TRY(dif_otp_ctrl_get_status(&otp, &status));
210 
211  // Send result & status codes to host.
212  otp_fi_lifecycle_partition_t uj_output;
213  for (uint32_t i = 0; i < OTP_CTRL_PARAM_LIFE_CYCLE_SIZE / 4; i++) {
214  uj_output.life_cycle_comp[i] = otp_read32_result_life_cycle_comp[i];
215  uj_output.life_cycle_fi[i] = otp_read32_result_life_cycle_fi[i];
216  }
217  uj_output.otp_status_codes = status.codes;
218  memcpy(uj_output.otp_error_causes, (uint8_t *)status.causes,
220  uj_output.alerts[0] = reg_alerts.alerts[0];
221  uj_output.alerts[1] = reg_alerts.alerts[1];
222  uj_output.alerts[2] = reg_alerts.alerts[2];
223  memcpy(uj_output.ast_alerts, sensor_alerts.alerts,
224  sizeof(sensor_alerts.alerts));
225  RESP_OK(ujson_serialize_otp_fi_lifecycle_partition_t, uj, &uj_output);
226 
227  return OK_STATUS();
228 }
229 
230 status_t handle_otp_fi_owner_sw_cfg(ujson_t *uj) {
231  // Clear registered alerts in alert handler.
232  pentest_registered_alerts_t reg_alerts = pentest_get_triggered_alerts();
233  // Clear the AST recoverable alerts.
234  pentest_clear_sensor_recov_alerts();
235 
236  // Read OTP partition for comparison values
237  TRY(otp_owner_sw_cfg_dump(otp_read32_result_owner_sw_cfg_comp));
238 
239  // FI code target.
240  pentest_set_trigger_high();
241 
242  // Point for FI
243  asm volatile(NOP1000);
244  asm volatile(NOP1000);
245  asm volatile(NOP1000);
246  asm volatile(NOP1000);
247 
248  pentest_set_trigger_low();
249 
250  // Read OTP partition again to see if values changed
251  TRY(otp_owner_sw_cfg_dump(otp_read32_result_owner_sw_cfg_fi));
252 
253  // Get registered alerts from alert handler.
254  reg_alerts = pentest_get_triggered_alerts();
255  // Get fatal and recoverable AST alerts from sensor controller.
256  pentest_sensor_alerts_t sensor_alerts = pentest_get_sensor_alerts();
257 
258  // Get OTP CTRL status
260  TRY(dif_otp_ctrl_get_status(&otp, &status));
261 
262  // Send result & status codes to host.
263  otp_fi_ownerswcfg_partition_t uj_output;
264  for (uint32_t i = 0; i < OTP_CTRL_PARAM_OWNER_SW_CFG_SIZE / 4; i++) {
265  uj_output.owner_sw_cfg_comp[i] = otp_read32_result_owner_sw_cfg_comp[i];
266  uj_output.owner_sw_cfg_fi[i] = otp_read32_result_owner_sw_cfg_fi[i];
267  }
268  uj_output.otp_status_codes = status.codes;
269  memcpy(uj_output.otp_error_causes, (uint8_t *)status.causes,
271  uj_output.alerts[0] = reg_alerts.alerts[0];
272  uj_output.alerts[1] = reg_alerts.alerts[1];
273  uj_output.alerts[2] = reg_alerts.alerts[2];
274  memcpy(uj_output.ast_alerts, sensor_alerts.alerts,
275  sizeof(sensor_alerts.alerts));
276  RESP_OK(ujson_serialize_otp_fi_ownerswcfg_partition_t, uj, &uj_output);
277 
278  return OK_STATUS();
279 }
280 
281 status_t handle_otp_fi_vendor_test(ujson_t *uj) {
282  // Clear registered alerts in alert handler.
283  pentest_registered_alerts_t reg_alerts = pentest_get_triggered_alerts();
284  // Clear the AST recoverable alerts.
285  pentest_clear_sensor_recov_alerts();
286 
287  // Read OTP partition for comparison values
288  TRY(otp_vendor_test_dump(otp_read32_result_vendor_test_comp));
289 
290  // FI code target.
291  pentest_set_trigger_high();
292 
293  // Point for FI
294  asm volatile(NOP1000);
295  asm volatile(NOP1000);
296  asm volatile(NOP1000);
297  asm volatile(NOP1000);
298 
299  pentest_set_trigger_low();
300 
301  // Read OTP partition again to see if values changed
302  TRY(otp_vendor_test_dump(otp_read32_result_vendor_test_fi));
303 
304  // Get registered alerts from alert handler.
305  reg_alerts = pentest_get_triggered_alerts();
306  // Get fatal and recoverable AST alerts from sensor controller.
307  pentest_sensor_alerts_t sensor_alerts = pentest_get_sensor_alerts();
308 
309  // Get OTP CTRL status
311  TRY(dif_otp_ctrl_get_status(&otp, &status));
312 
313  // Send result & status codes to host.
314  otp_fi_vendortest_partition_t uj_output;
315  for (uint32_t i = 0; i < OTP_CTRL_PARAM_VENDOR_TEST_SIZE / 4; i++) {
316  uj_output.vendor_test_comp[i] = otp_read32_result_vendor_test_comp[i];
317  uj_output.vendor_test_fi[i] = otp_read32_result_vendor_test_fi[i];
318  }
319  uj_output.otp_status_codes = status.codes;
320  memcpy(uj_output.otp_error_causes, (uint8_t *)status.causes,
322  uj_output.alerts[0] = reg_alerts.alerts[0];
323  uj_output.alerts[1] = reg_alerts.alerts[1];
324  uj_output.alerts[2] = reg_alerts.alerts[2];
325  memcpy(uj_output.ast_alerts, sensor_alerts.alerts,
326  sizeof(sensor_alerts.alerts));
327  RESP_OK(ujson_serialize_otp_fi_vendortest_partition_t, uj, &uj_output);
328 
329  return OK_STATUS();
330 }
331 
332 status_t handle_otp_fi(ujson_t *uj) {
333  otp_fi_subcommand_t cmd;
334  TRY(ujson_deserialize_otp_fi_subcommand_t(uj, &cmd));
335  switch (cmd) {
336  case kOtpFiSubcommandInit:
337  return handle_otp_fi_init(uj);
338  case kOtpFiSubcommandVendorTest:
339  return handle_otp_fi_vendor_test(uj);
340  case kOtpFiSubcommandOwnerSwCfg:
341  return handle_otp_fi_owner_sw_cfg(uj);
342  case kOtpFiSubcommandHwCfg:
343  return handle_otp_fi_hw_cfg(uj);
344  case kOtpFiSubcommandLifeCycle:
345  return handle_otp_fi_life_cycle(uj);
346  default:
347  LOG_ERROR("Unrecognized OTP FI subcommand: %d", cmd);
348  return INVALID_ARGUMENT();
349  }
350  return OK_STATUS();
351 }