Software APIs
alert_handler_escalation_test.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 
11 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
13 #include "sw/device/lib/runtime/irq.h"
15 #include "sw/device/lib/testing/alert_handler_testutils.h"
16 #include "sw/device/lib/testing/keymgr_testutils.h"
17 #include "sw/device/lib/testing/rstmgr_testutils.h"
18 #include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h"
19 #include "sw/device/lib/testing/test_framework/check.h"
21 
22 #include "alert_handler_regs.h" // Generated.
24 #include "rv_core_ibex_regs.h" // Generated.
25 
26 OTTF_DEFINE_TEST_CONFIG();
27 
28 static dif_clkmgr_t clkmgr;
29 static dif_keymgr_t keymgr;
30 static dif_rstmgr_t rstmgr;
31 static dif_alert_handler_t alert_handler;
32 static dif_rv_core_ibex_t rv_core_ibex;
33 static dif_uart_t uart;
34 
35 /**
36  * External ISR.
37  *
38  * Handles all peripheral interrupts on Ibex. PLIC asserts an external interrupt
39  * line to the CPU, which results in a call to this OTTF ISR. This ISR
40  * overrides the default OTTF implementation.
41  *
42  * @param exc_info Execution info.
43  */
44 void ottf_external_nmi_handler(uint32_t *exc_info) {
45  // DO NOT REMOVE, DV sync message
46  LOG_INFO("You are experiencing an NMI");
47 
49 
50  CHECK_DIF_OK(dif_rv_core_ibex_get_nmi_state(
51  &rv_core_ibex, (dif_rv_core_ibex_nmi_state_t *)&nmi_state));
52 
53  CHECK(nmi_state.alert_enabled && nmi_state.alert_raised,
54  "Alert handler NMI state not expected:\n\t"
55  "alert_enable:%x\n\talert_raised:%x\n",
56  nmi_state.alert_enabled, nmi_state.alert_raised);
57 
60  &alert_handler, kDifAlertHandlerClassA, &state));
61 
62  // Now intentionally hang the device
65 
66  // access uart after clocks have been disabled
67  CHECK_DIF_OK(dif_uart_disable_rx_timeout(&uart));
68  LOG_FATAL("This message should never be seen");
69 }
70 
71 /**
72  * Initialize the dif handles required for this test.
73  */
74 static void init_peripheral_handles(void) {
75  CHECK_DIF_OK(dif_clkmgr_init(
77 
78  CHECK_DIF_OK(dif_rstmgr_init(
80 
81  CHECK_DIF_OK(dif_alert_handler_init(
83  &alert_handler));
84 
85  CHECK_DIF_OK(dif_rv_core_ibex_init(
87  &rv_core_ibex));
88 
89  CHECK_DIF_OK(dif_uart_init(
91 
92  CHECK_DIF_OK(dif_keymgr_init(
94 }
95 
96 /**
97  * Configure the alert handler. The escalation phases (NMI interrupt, LC scrap
98  * state, chip reset) are assigned to alert class A.
99  */
100 static void config_alert_handler(void) {
101  // Escalation phase 0 is the NMI interrupt whose timeout value before
102  // progressing to phase 1 differs depending on the simulation device. For
103  // example, on the ChipWhisperer 1000000 cycles are enough to prevent a
104  // premature cancellation of the NMI interrupt handler (see
105  // `ottf_external_nmi_handler`).
106  uint32_t phase0DurationCycles = 1000000;
108  phase0DurationCycles /= 10;
109  } else if (kDeviceType == kDeviceSimDV) {
110  phase0DurationCycles /= 100;
111  }
112 
113  dif_alert_handler_escalation_phase_t escalationProfiles[] = {
115  .signal = 0,
116  .duration_cycles = phase0DurationCycles},
118  .signal = 1,
119  .duration_cycles = 10000},
121  .signal = 3,
122  .duration_cycles = 10000},
123  };
124  dif_alert_handler_class_config_t configProfiles[] = {{
126  .accumulator_threshold = 0,
127  .irq_deadline_cycles = 0,
128  .escalation_phases = escalationProfiles,
129  .escalation_phases_len = 3,
130  .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase1,
131  }};
132 
133  // set the alert we care about to class A
136  kDifAlertHandlerClassA, /*enabled=*/kDifToggleEnabled,
137  /*locked=*/kDifToggleEnabled));
138 
139  // configure class A
141  &alert_handler, kDifAlertHandlerClassA, configProfiles[0],
142  /*enabled=*/kDifToggleEnabled,
143  /*locked=*/kDifToggleEnabled));
144 }
145 
146 /**
147  * - Verify the first escalation results in NMI interrupt serviced by the CPU.
148  * - Verify the second results in device being put in escalate state, via the LC
149  * JTAG TAP.
150  * - Verify the third results in chip reset.
151  * - Ensure that all escalation handshakes complete without errors.
152  *
153  * The first escalation is checked via the entry of the NMI handler and polling
154  * by dv. The second escalation is directly checked by dv. The third escalation
155  * is checked via reset reason.
156  */
157 bool test_main(void) {
158  init_peripheral_handles();
159 
160  // Check if there was a HW reset caused by the escalation.
162  rst_info = rstmgr_testutils_reason_get();
163  rstmgr_testutils_reason_clear();
164 
165  if (rst_info & kDifRstmgrResetInfoPor) {
166  config_alert_handler();
167 
168  // Initialize keymgr with otp contents
169  CHECK_STATUS_OK(keymgr_testutils_advance_state(&keymgr, NULL));
170 
171  // DO NOT REMOVE, DV sync message
172  LOG_INFO("Keymgr entered Init State");
173 
174  // Enable NMI
175  CHECK_DIF_OK(dif_rv_core_ibex_enable_nmi(&rv_core_ibex,
176  kDifRvCoreIbexNmiSourceAlert));
177 
178  // force trigger the alert
179  CHECK_DIF_OK(dif_rv_core_ibex_alert_force(&rv_core_ibex,
180  kDifRvCoreIbexAlertRecovSwErr));
181 
182  // Stop execution here and just wait for something to happen
184  LOG_ERROR("Should have reset before this line");
185  return false;
186  } else if (rst_info & kDifRstmgrResetInfoEscalation) {
187  // DO NOT REMOVE, DV sync message
188  LOG_INFO("Reset due to alert escalation");
189  return true;
190  } else {
191  LOG_ERROR("Unexpected reset info %d", rst_info);
192  }
193 
194  return false;
195 }