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