Software APIs
lc_ctrl_program_error.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 <stdbool.h>
6 #include <stdint.h>
7 
15 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
19 #include "sw/device/lib/runtime/irq.h"
21 #include "sw/device/lib/testing/alert_handler_testutils.h"
22 #include "sw/device/lib/testing/lc_ctrl_testutils.h"
23 #include "sw/device/lib/testing/ret_sram_testutils.h"
24 #include "sw/device/lib/testing/rstmgr_testutils.h"
25 #include "sw/device/lib/testing/rv_plic_testutils.h"
26 #include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h"
27 #include "sw/device/lib/testing/test_framework/check.h"
29 
30 #include "alert_handler_regs.h"
32 
33 /*
34  * Checks the result of getting an otp programming error, as when attempting
35  * to flip a bit to zero. The SV side injects an error on an otherwise okay
36  * transition request.
37  *
38  * There should be a reset caused by an lc_ctrl fatal alert, but the only
39  * trace of that is found in the rstmgr's alert dump. The lc state should
40  * not change.
41  */
42 OTTF_DEFINE_TEST_CONFIG();
43 
44 /**
45  * Constants used for data stored in retention sram.
46  */
47 enum {
48  // Counter for resets.
49  kCounterReset,
50  // Counter for regular interrupts.
51  kCounterInterrupt,
52  // Counter for NMIs.
53  kCounterNmi,
54  // Scratch area used for fault_checker function.
55  kScratchFunction = 0,
56  // Scratch area used for fault_checker ip_inst.
57  kScratchIpInst = 1,
58  // Scratch area used for the current lc state, to check it doesn't change.
59  kScratchLcState = 2,
60 };
61 
62 static dif_alert_handler_t alert_handler;
63 static dif_lc_ctrl_t lc_ctrl;
64 static dif_rstmgr_t rstmgr;
65 
66 static const uint32_t kPlicTarget = kTopEarlgreyPlicTargetIbex0;
67 static dif_rv_plic_t plic;
68 static dif_rv_core_ibex_t rv_core_ibex;
69 
70 // Used for checking whether a regular alert interrupt has been seen.
71 static volatile bool alert_irq_seen = false;
72 
73 static const dif_alert_handler_escalation_phase_t kEscProfiles[] = {
74  // TODO:
75  // this duration must be long enough to
76  // accommodate a few jtag transactions
77  // how can this be done in a non-hardcoded way?
79  .signal = 1,
80  .duration_cycles = 10000},
82  .signal = 3,
83  .duration_cycles = 10000}};
84 
85 static const dif_alert_handler_class_config_t kConfigProfiles[] = {{
87  .accumulator_threshold = 0,
88  .irq_deadline_cycles = 0,
89  .escalation_phases = kEscProfiles,
90  .escalation_phases_len = 2,
91  .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase0,
92 }};
93 
94 // The function to check the fault status.
95 typedef void (*FaultCheckerFunction)(bool, const char *inst);
96 
97 typedef struct fault_checker {
98  FaultCheckerFunction function;
99  const char *ip_inst;
101 
102 // This is the fault checker to be used. It is saved and retrieved from
103 // retention ram to preserve it across resets.
105 
106 static void save_fault_checker(fault_checker_t *fault_checker) {
107  uint32_t function_addr = (uint32_t)(fault_checker->function);
108  uint32_t ip_inst_addr = (uint32_t)(fault_checker->ip_inst);
109  CHECK_STATUS_OK(
110  ret_sram_testutils_scratch_write(kScratchFunction, 1, &function_addr));
111  CHECK_STATUS_OK(
112  ret_sram_testutils_scratch_write(kScratchIpInst, 1, &ip_inst_addr));
113 }
114 
115 static void restore_fault_checker(fault_checker_t *fault_checker) {
116  CHECK_STATUS_OK(ret_sram_testutils_scratch_read(
117  kScratchFunction, 1, (uint32_t *)&(fault_checker->function)));
118  CHECK_STATUS_OK(ret_sram_testutils_scratch_read(
119  kScratchIpInst, 1, (uint32_t *)&(fault_checker->ip_inst)));
120 }
121 
122 static const char *lc_ctrl_inst_name = "lc_ctrl";
123 
124 // This checks the lc_ctrl integrity fatal error code against expected.
125 static void lc_ctrl_fault_checker(bool enable, const char *ip_inst) {
127  CHECK_DIF_OK(dif_lc_ctrl_get_status(&lc_ctrl, &status));
128  bitfield_field32_t relevant_field = {
129  .mask = UINT32_MAX, .index = kDifLcCtrlStatusCodeTooManyTransitions};
130  uint32_t mask = bitfield_field32_write(0, relevant_field, UINT32_MAX);
131  uint32_t relevant_status = status & mask;
132  uint32_t fatal_prog_error =
134  uint32_t expected_status = enable ? fatal_prog_error : 0;
135  CHECK(relevant_status == expected_status,
136  "For %s got codes 0x%x, expected 0x%x", ip_inst, relevant_status,
137  expected_status);
138 }
139 
140 /**
141  * External ISR.
142  *
143  * Handles all peripheral interrupts on Ibex. PLIC asserts an external interrupt
144  * line to the CPU, which results in a call to this OTTF ISR. This ISR
145  * overrides the default OTTF implementation.
146  */
147 void ottf_external_isr(uint32_t *exc_info) {
148  dif_rv_plic_irq_id_t irq_id;
149 
150  LOG_INFO("At regular external ISR");
151 
152  // There may be multiple interrupts due to the alert firing, so this keeps an
153  // interrupt counter and errors-out if there are too many interrupts.
154  CHECK_STATUS_OK(ret_sram_testutils_counter_increment(kCounterInterrupt));
155 
156  CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic, kPlicTarget, &irq_id));
157 
160 
161  if (peripheral == kTopEarlgreyPlicPeripheralAonTimerAon) {
162  uint32_t irq =
163  (irq_id - (dif_rv_plic_irq_id_t)
165 
166  // We should not get aon timer interrupts since escalation suppresses them.
167  CHECK(false, "Unexpected aon timer interrupt %d", irq);
168  } else if (peripheral == kTopEarlgreyPlicPeripheralAlertHandler) {
169  // Don't acknowledge the interrupt to alert_handler so it escalates.
170  CHECK(fault_checker.function);
171  CHECK(fault_checker.ip_inst);
172 
173  // Fatal alerts are only cleared by reset.
174  fault_checker.function(/*enable=*/true, fault_checker.ip_inst);
175  }
176 
177  // Disable these interrupts from alert_handler so they don't keep happening
178  // until NMI.
179  uint32_t irq =
181  CHECK_DIF_OK(dif_alert_handler_irq_set_enabled(&alert_handler, irq,
183 
184  // Disable this interrupt to prevent it from continuously firing. This
185  // should not prevent escalation from continuing.
186  CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(&plic, irq_id, kPlicTarget,
188 
189  // Complete the IRQ by writing the IRQ source to the Ibex specific CC
190  // register.
191  CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic, kPlicTarget, irq_id));
192 
193  // Notify test function that the alert IRQ has been seen
194  alert_irq_seen = true;
195 
196  LOG_INFO("Regular external ISR exiting");
197 }
198 
199 /**
200  * External NMI ISR.
201  *
202  * Handles NMI interrupts on Ibex for either escalation or watchdog.
203  */
204 void ottf_external_nmi_handler(uint32_t *exc_info) {
206  LOG_INFO("At NMI handler");
207 
208  // Read the NV NMI counter from flash and increment it.
209  CHECK_STATUS_OK(ret_sram_testutils_counter_increment(kCounterNmi));
210 
211  // Check that this NMI was due to an alert handler escalation, and not due
212  // to a watchdog bark, since escalation suppresses the watchdog.
213  CHECK_DIF_OK(dif_rv_core_ibex_get_nmi_state(
214  &rv_core_ibex, (dif_rv_core_ibex_nmi_state_t *)&nmi_state));
215  CHECK(nmi_state.alert_enabled && nmi_state.alert_raised,
216  "Alert handler NMI state not expected:\n\t"
217  "alert_enable:%x\n\talert_raised:%x\n",
218  nmi_state.alert_enabled, nmi_state.alert_raised);
219  CHECK(nmi_state.wdog_enabled && !nmi_state.wdog_barked,
220  "Watchdog NMI state not expected:\n\t"
221  "wdog_enabled:%x\n\twdog_barked:%x\n",
222  nmi_state.wdog_enabled, nmi_state.wdog_barked);
223 
224  // Check the class.
227  &alert_handler, kDifAlertHandlerClassA, &state));
228  CHECK(state == kDifAlertHandlerClassStatePhase1, "Wrong phase %d", state);
229 
230  // Check this gets the expected alert.
231  bool is_cause = false;
233  &alert_handler, kTopEarlgreyAlertIdLcCtrlFatalProgError, &is_cause));
234  CHECK(is_cause);
235 
236  // Acknowledge the cause, which doesn't affect escalation.
238  &alert_handler, kTopEarlgreyAlertIdLcCtrlFatalProgError));
239  LOG_INFO("NMI handler exiting");
240 }
241 
242 void check_alert_dump(void) {
244  size_t seg_size;
245  alert_handler_testutils_info_t actual_info;
246 
247  // Reads the alert crash dump retained after reset (except POR)
248  CHECK_DIF_OK(dif_rstmgr_alert_info_dump_read(
249  &rstmgr, dump, DIF_RSTMGR_ALERT_INFO_MAX_SIZE, &seg_size));
250 
251  LOG_INFO("DUMP SIZE %d", seg_size);
252  for (int i = 0; i < seg_size; i++) {
253  LOG_INFO("DUMP:%d: 0x%x", i, dump[i]);
254  }
255 
256  CHECK(seg_size <= INT_MAX, "seg_size must fit in int");
257  CHECK_STATUS_OK(
258  alert_handler_testutils_info_parse(dump, (int)seg_size, &actual_info));
259  LOG_INFO("The alert info crash dump:");
260  alert_handler_testutils_info_dump(&actual_info);
261  // Check alert cause.
262  for (int i = 0; i < ALERT_HANDLER_PARAM_N_ALERTS; ++i) {
264  CHECK(actual_info.alert_cause[i], "Expected alert cause %d to be set", i);
265  } else {
266  // It is possible some alerts can trigger others; for example, some
267  // lc_ctrl faults lead to otp_ctrl faults.
268  if (actual_info.alert_cause[i]) {
269  LOG_INFO("Unexpected alert cause %d, may be triggered by %d", i,
271  }
272  }
273  }
274 }
275 
276 bool test_main(void) {
277  // Enable global and external IRQ at Ibex.
278  irq_global_ctrl(true);
279  irq_external_ctrl(true);
280 
281  // Initialize core and peripherals.
282  CHECK_DIF_OK(dif_rv_core_ibex_init(
284  &rv_core_ibex));
285 
286  CHECK_DIF_OK(dif_lc_ctrl_init(
288 
289  CHECK_DIF_OK(dif_rstmgr_init(
291 
292  CHECK_DIF_OK(dif_alert_handler_init(
294  &alert_handler));
295 
296  // Check if there was a HW reset caused by the escalation.
297  dif_rstmgr_reset_info_bitfield_t rst_info = rstmgr_testutils_reason_get();
298  rstmgr_testutils_reason_clear();
299 
300  ret_sram_testutils_init();
301 
302  CHECK(rst_info == kDifRstmgrResetInfoPor ||
303  rst_info == kDifRstmgrResetInfoEscalation,
304  "Wrong reset reason %02X", rst_info);
305 
306  if (rst_info & kDifRstmgrResetInfoPor) {
307  LOG_INFO("Booting for the first time: starting test");
308 
309  CHECK_STATUS_OK(ret_sram_testutils_counter_clear(kCounterReset));
310  CHECK_STATUS_OK(ret_sram_testutils_counter_clear(kCounterInterrupt));
311  CHECK_STATUS_OK(ret_sram_testutils_counter_clear(kCounterNmi));
312 
313  LOG_INFO("Enabling rstmgr alert info capture");
314  // Enable rstmgr alert crash dump capture.
316 
317  LOG_INFO("Configuring alert handlers");
318  // Configure the alert handler, LC controller fault checker and start
319  // executing the test. Set the alert we care about to class A.
322  kDifAlertHandlerClassA, /*enabled=*/kDifToggleEnabled,
323  /*locked=*/kDifToggleEnabled));
324 
325  // Configure class A alerts.
327  &alert_handler, kDifAlertHandlerClassA, kConfigProfiles[0],
328  /*enabled=*/kDifToggleEnabled,
329  /*locked=*/kDifToggleEnabled));
330 
331  LOG_INFO("Configuring fault checker");
332  // Configure the LC fault_checker function.
333  fault_checker_t fc = {lc_ctrl_fault_checker, lc_ctrl_inst_name};
334  fault_checker = fc;
335 
336  LOG_INFO("Saving fault checker to Flash");
337  // Save the fault_checker to flash.
338  save_fault_checker(&fault_checker);
339 
340  LOG_INFO("Enabling watchdog and alert NMIs");
341  // Enable both the watchdog and alert NMIs.
342  CHECK_DIF_OK(dif_rv_core_ibex_enable_nmi(&rv_core_ibex,
343  kDifRvCoreIbexNmiSourceAlert));
344  CHECK_DIF_OK(dif_rv_core_ibex_enable_nmi(&rv_core_ibex,
345  kDifRvCoreIbexNmiSourceWdog));
346 
347  // Initiate transition into scrap
348 
349  // Get current lc state and save it to retention sram.
350  dif_lc_ctrl_state_t state;
351  CHECK_DIF_OK(dif_lc_ctrl_get_state(&lc_ctrl, &state));
352  CHECK_STATUS_OK(
353  ret_sram_testutils_scratch_write(kScratchLcState, 1, &state));
354 
355  // DV sync message
356  LOG_INFO("Begin life cycle transition");
357 
358  // Mutex acquire should always succeed, there are no competing agents
359  CHECK_DIF_OK(dif_lc_ctrl_mutex_try_acquire(&lc_ctrl));
360 
361  // Attempt a transition to scrap.
362  CHECK_DIF_OK(
363  dif_lc_ctrl_configure(&lc_ctrl, kDifLcCtrlStateScrap, false, NULL));
364  LOG_INFO("Configuring lc transition to scrap state");
365  CHECK_DIF_OK(dif_lc_ctrl_transition(&lc_ctrl));
366 
367  dif_lc_ctrl_status_t lc_status;
368  CHECK_DIF_OK(dif_lc_ctrl_get_status(&lc_ctrl, &lc_status));
369  CHECK((lc_status & ((1 << kDifLcCtrlStatusCodeTooManyTransitions) |
372  (1 << kDifLcCtrlStatusCodeFlashRmaError))) == 0,
373  "Got unexpected lc-side error");
374  LOG_INFO("lc STATUS:0x%x", lc_status);
375 
376  // halt execution
378 
379  } else if (rst_info & kDifRstmgrResetInfoEscalation) {
380  LOG_INFO("Booting for the second time due to escalation reset");
381  restore_fault_checker(&fault_checker);
382 
383  uint32_t interrupt_count = 0;
384  CHECK_STATUS_OK(
385  ret_sram_testutils_counter_get(kCounterInterrupt, &interrupt_count));
386  uint32_t nmi_count = 0;
387  CHECK_STATUS_OK(ret_sram_testutils_counter_get(kCounterNmi, &nmi_count));
388 
389  LOG_INFO("Interrupt count %d", interrupt_count);
390  LOG_INFO("NMI count %d", nmi_count);
391 
392  CHECK(interrupt_count == 0,
393  "Regular ISR should not run for "
394  "kTopEarlgreyAlertIdLcCtrlFatalProgError");
395  CHECK(nmi_count == 0,
396  "NMI should not run for kTopEarlgreyAlertIdLcCtrlFatalProgError");
397 
398  // Get the retention sram maintained reset counter.
399  uint32_t reset_count;
400  CHECK_STATUS_OK(ret_sram_testutils_counter_get(kCounterReset,
401  (uint32_t *)&reset_count));
402  LOG_INFO("Reset counter value: %u", reset_count);
403  CHECK(reset_count <= 1, "Too many resets, expected only one non-POR");
404 
405  // Increment reset counter.
406  CHECK_STATUS_OK(ret_sram_testutils_counter_increment(kCounterReset));
407 
408  // Check that the alert handler cause is cleared after reset.
409  bool is_cause = true;
411  &alert_handler, kTopEarlgreyAlertIdLcCtrlFatalProgError, &is_cause));
412  CHECK(!is_cause);
413 
414  // Check that the fault register is cleared after reset.
415  fault_checker.function(/*enable=*/false, fault_checker.ip_inst);
416 
417  // Check the escalation alert cause from alert dump is as expected.
418  check_alert_dump();
419 
420  // Check that the lc state didn't change.
421  dif_lc_ctrl_state_t state;
422  dif_lc_ctrl_state_t prior_state;
423  CHECK_DIF_OK(dif_lc_ctrl_get_state(&lc_ctrl, &state));
424  CHECK_STATUS_OK(ret_sram_testutils_scratch_read(kScratchLcState, 1,
425  (uint32_t *)&prior_state));
426  CHECK(state == prior_state, "Unexpected lc state change");
427 
428  return true;
429  } else {
430  LOG_FATAL("unexpected reset info %d", rst_info);
431  }
432 
433  return false;
434 }