Software APIs
alert_handler_lpg_sleep_mode_alerts.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 <assert.h>
6 #include <limits.h>
7 #include <stdbool.h>
8 #include <stdint.h>
9 
14 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
16 #include "sw/device/lib/runtime/irq.h"
18 #include "sw/device/lib/testing/alert_handler_testutils.h"
19 #include "sw/device/lib/testing/aon_timer_testutils.h"
20 #include "sw/device/lib/testing/pwrmgr_testutils.h"
21 #include "sw/device/lib/testing/rand_testutils.h"
22 #include "sw/device/lib/testing/ret_sram_testutils.h"
23 #include "sw/device/lib/testing/rstmgr_testutils.h"
24 #include "sw/device/lib/testing/rv_plic_testutils.h"
25 #include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h"
26 #include "sw/device/lib/testing/test_framework/check.h"
28 
29 #include "alert_handler_regs.h"
31 #include "pwrmgr_regs.h"
32 #include "sw/device/lib/testing/autogen/isr_testutils.h"
33 
34 OTTF_DEFINE_TEST_CONFIG();
35 
36 static const dt_rstmgr_t kRstmgrDt = 0;
37 static_assert(kDtRstmgrCount == 1, "this test expects a rstmgr");
38 static const dt_pwrmgr_t kPwrmgrDt = 0;
39 static_assert(kDtPwrmgrCount == 1, "this test expects a pwrmgr");
40 static const dt_aon_timer_t kAonTimerDt = 0;
41 static_assert(kDtAonTimerCount == 1, "this test expects an aon_timer");
42 static const dt_rv_plic_t kRvPlicDt = 0;
43 static_assert(kDtRvPlicCount == 1, "this test expects exactly one rv_plic");
44 static const dt_rv_core_ibex_t kRvCoreIbexDt = 0;
45 static_assert(kDtRvCoreIbexCount == 1,
46  "this test expects exactly one rv_core_ibex");
47 static const dt_alert_handler_t kAlertHandlerDt = 0;
48 static_assert(kDtAlertHandlerCount == 1,
49  "this library expects exactly one alert_handler");
50 
51 static dif_rv_plic_t plic;
52 static dif_alert_handler_t alert_handler;
53 static dif_aon_timer_t aon_timer;
54 static dif_pwrmgr_t pwrmgr;
55 static dif_rstmgr_t rstmgr;
56 static dif_rv_core_ibex_t ibex;
57 
58 // This location will be update from SV to contain the expected alert.
59 static volatile const uint8_t kExpectedAlertNumber = 0;
60 
61 static dif_pwrmgr_request_sources_t pwrmgr_aon_timer_wakeups;
62 
63 /**
64  * Initialize the peripherals used in this test.
65  */
66 static void init_peripherals(void) {
67  CHECK_DIF_OK(dif_rv_plic_init_from_dt(kRvPlicDt, &plic));
68 
69  CHECK_DIF_OK(dif_alert_handler_init_from_dt(kAlertHandlerDt, &alert_handler));
70 
71  // Initialize pwrmgr
72  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
73 
74  // Initialize aon_timer
75  CHECK_DIF_OK(dif_aon_timer_init_from_dt(kAonTimerDt, &aon_timer));
76  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
77  &pwrmgr, kDifPwrmgrReqTypeWakeup, dt_aon_timer_instance_id(kAonTimerDt),
78  kDtAonTimerWakeupWkupReq, &pwrmgr_aon_timer_wakeups));
79 
80  CHECK_DIF_OK(dif_rstmgr_init_from_dt(kRstmgrDt, &rstmgr));
81 
82  CHECK_DIF_OK(dif_rv_core_ibex_init_from_dt(kRvCoreIbexDt, &ibex));
83 }
84 
85 // NVM counters/fields to keep test steps between deep sleep modes
86 enum {
87  // The counter ID for the non-volatile counter keeping the test steps.
88  kCounterTestSteps = 0,
89  // The counter ID for the non-volatile counter keeping the number of max
90  // wakeup events
91  kCounterMaxWakeups = 1,
92 };
93 
94 /**
95  * Program the alert handler to escalate on alerts upto phase 1 (i.e. wipe
96  * secret) but not trigger reset. Then CPU can check if the correct interrupt
97  * fires and check the local alert cause register.
98  */
99 static void alert_handler_config(uint32_t ping_timeout) {
100  dif_alert_handler_alert_t alerts[ALERT_HANDLER_PARAM_N_ALERTS];
101  dif_alert_handler_class_t alert_classes[ALERT_HANDLER_PARAM_N_ALERTS];
102 
103  // Enable all incoming alerts and configure them to classa.
104  // This alert should never fire because we do not expect any incoming alerts.
105  for (dif_alert_handler_alert_t i = 0; i < ALERT_HANDLER_PARAM_N_ALERTS; ++i) {
106  alerts[i] = i;
107  alert_classes[i] = kDifAlertHandlerClassA;
108  }
109 
110  // Enable alert ping fail local alert and configure that to classb.
111  // Enable other local alerts and configure them to classa.
112  dif_alert_handler_local_alert_t loc_alerts[] = {
113  kDifAlertHandlerLocalAlertAlertPingFail,
114  kDifAlertHandlerLocalAlertAlertIntegrityFail,
115  kDifAlertHandlerLocalAlertBusIntegrityFail,
116  kDifAlertHandlerLocalAlertEscalationIntegrityFail,
117  kDifAlertHandlerLocalAlertEscalationPingFail,
118  kDifAlertHandlerLocalAlertShadowedStorageError,
119  kDifAlertHandlerLocalAlertShadowedUpdateError};
120  dif_alert_handler_class_t loc_alert_classes[] = {
121  kDifAlertHandlerClassB, kDifAlertHandlerClassA, kDifAlertHandlerClassA,
122  kDifAlertHandlerClassA, kDifAlertHandlerClassA, kDifAlertHandlerClassA,
123  kDifAlertHandlerClassA};
124 
125  uint32_t cycles = 0;
126  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(200, &cycles));
127  dif_alert_handler_escalation_phase_t esc_phases[] = {{
129  .signal = 0,
130  .duration_cycles = cycles,
131  }};
132 
133  dif_alert_handler_class_config_t class_config = {
135  .accumulator_threshold = 0,
136  .irq_deadline_cycles = cycles,
137  .escalation_phases = esc_phases,
138  .escalation_phases_len = ARRAYSIZE(esc_phases),
139  .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase1,
140  };
141 
142  dif_alert_handler_class_config_t class_configs[] = {class_config,
143  class_config};
144 
145  dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA,
146  kDifAlertHandlerClassB};
147  dif_alert_handler_config_t config = {
148  .alerts = alerts,
149  .alert_classes = alert_classes,
150  .alerts_len = ARRAYSIZE(alerts),
151  .local_alerts = loc_alerts,
152  .local_alert_classes = loc_alert_classes,
153  .local_alerts_len = ARRAYSIZE(loc_alerts),
154  .classes = classes,
155  .class_configs = class_configs,
156  .classes_len = ARRAYSIZE(class_configs),
157  .ping_timeout = ping_timeout,
158  };
159 
160  CHECK_STATUS_OK(alert_handler_testutils_configure_all(&alert_handler, config,
162  // Enables alert handler irq.
163  CHECK_DIF_OK(dif_alert_handler_irq_set_enabled(
164  &alert_handler, kDifAlertHandlerIrqClassa, kDifToggleEnabled));
165 
166  CHECK_DIF_OK(dif_alert_handler_irq_set_enabled(
167  &alert_handler, kDifAlertHandlerIrqClassb, kDifToggleEnabled));
168 }
169 
170 /**
171  * Clear all alert_cause and local_alert_cause registers
172  */
173 static void alert_handler_clear_cause_regs(void) {
174  // Loop over all alert_cause regs
175  for (dif_alert_handler_alert_t i = 0; i < ALERT_HANDLER_PARAM_N_ALERTS; i++) {
176  CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(&alert_handler, i));
177  }
178 
179  // Loop over all loc_alert_cause regs
181  i < ALERT_HANDLER_PARAM_N_LOC_ALERT; i++) {
182  CHECK_DIF_OK(dif_alert_handler_local_alert_acknowledge(&alert_handler, i));
183  }
184 }
185 
186 /**
187  * Checks if any of the alert_cause or local_alert_cause register is set
188  * @param expected_alert_value: Expected value for the accumulator.
189  */
190 static uint16_t alert_handler_num_fired_alerts(void) {
191  bool is_cause;
192  // Indicates if any of the alerts or local alerts is fired.
193  uint16_t accumulator = 0;
194  // Loop over all alert_cause regs
195  for (dif_alert_handler_alert_t i = 0; i < ALERT_HANDLER_PARAM_N_ALERTS; i++) {
196  CHECK_DIF_OK(
197  dif_alert_handler_alert_is_cause(&alert_handler, i, &is_cause));
198  if (is_cause) {
199  LOG_INFO("Alert %d fired", i);
200  }
201  accumulator += is_cause;
202  }
203  return accumulator;
204 }
205 
206 /**
207  * Checks if any of the alert_cause or local_alert_cause register is set
208  * @param expected_alert_value: Expected value for the accumulator.
209  */
210 static uint16_t alert_handler_num_fired_loc_alerts(void) {
211  bool is_cause;
212  // Indicates if any of the alerts or local alerts is fired.
213  uint16_t accumulator = 0;
214  // Loop over all loc_alert_cause regs
216  i < ALERT_HANDLER_PARAM_N_LOC_ALERT; i++) {
217  CHECK_DIF_OK(
218  dif_alert_handler_local_alert_is_cause(&alert_handler, i, &is_cause));
219  accumulator += is_cause;
220  }
221  return accumulator;
222 }
223 
224 /**
225  * Configures the power manager and enter a sleep mode
226  * @param deep_sleep: true => deep sleep, false => normal sleep
227  */
228 static void enter_low_power(bool deep_sleep) {
230  CHECK_DIF_OK(dif_pwrmgr_get_domain_config(&pwrmgr, &cfg));
232  kDifPwrmgrDomainOptionUsbClockInLowPower |
233  kDifPwrmgrDomainOptionUsbClockInActivePower)) |
234  (!deep_sleep ? kDifPwrmgrDomainOptionMainPowerInLowPower : 0);
235 
236  // Set the wake_up trigger as AON timer module.
237  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
238  &pwrmgr, /*wake_up_request_source*/ pwrmgr_aon_timer_wakeups, cfg));
240 }
241 
242 /**
243  * Clean up wakeup sources.
244  */
245 void cleanup_wakeup_src(void) {
246  CHECK_DIF_OK(dif_aon_timer_wakeup_stop(&aon_timer));
247  CHECK_DIF_OK(dif_aon_timer_clear_wakeup_cause(&aon_timer));
248  // Ensure the de-asserted events have cleared from the wakeup pipeline
249  // within 30us.
250  busy_spin_micros(30);
251  CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_clear(&pwrmgr));
252 }
253 
254 static plic_isr_ctx_t plic_ctx = {.rv_plic = &plic,
255  .hart_id = kTopEarlgreyPlicTargetIbex0};
256 
257 static pwrmgr_isr_ctx_t pwrmgr_isr_ctx = {
258  .pwrmgr = &pwrmgr,
259  .plic_pwrmgr_start_irq_id = kTopEarlgreyPlicIrqIdPwrmgrAonWakeup,
260  .expected_irq = kDifPwrmgrIrqWakeup,
261  .is_only_irq = true};
262 
263 // To keep the random number of iterations
264 static uint32_t num_total_wakeups;
265 // To keep track of the test steps
266 static size_t test_step_cnt;
267 
268 /**
269  * Helper function to keep the test body clean
270  * Initializes the test counters.
271  */
272 void init_test_components(void) {
273  // Enable global and external IRQ at Ibex.
274  irq_global_ctrl(true);
275  irq_external_ctrl(true);
276 
277  init_peripherals();
278 
279  ret_sram_testutils_init();
280 
281  // Enable all the AON interrupts used in this test.
282  rv_plic_testutils_irq_range_enable(&plic, kTopEarlgreyPlicTargetIbex0,
285 
286  // Enable pwrmgr interrupt
287  CHECK_DIF_OK(dif_pwrmgr_irq_set_enabled(&pwrmgr, 0, kDifToggleEnabled));
288 
289  CHECK_STATUS_OK(
290  ret_sram_testutils_counter_get(kCounterTestSteps, &test_step_cnt));
291  // Total number of iterations for each test phase
292  CHECK_STATUS_OK(
293  ret_sram_testutils_counter_get(kCounterMaxWakeups, &num_total_wakeups));
294 
295  CHECK(test_step_cnt < INT_MAX, "test_step_cnt too large");
296 
297  // If this is the first iteration,
298  // set num_iterations to a random value between 8 and 32
299  if (num_total_wakeups == 0) {
300  // number of total wakeups
301  num_total_wakeups = 2;
302  CHECK_STATUS_OK(
303  ret_sram_testutils_counter_set(kCounterMaxWakeups, num_total_wakeups));
304  }
305 }
306 
307 /**
308  * Execute the test phases:
309  */
310 static void execute_test_phases(uint8_t test_phase, uint32_t ping_timeout_cyc) {
311  // To keep the test results
312  bool is_cause;
313  bool is_locked;
314  uint16_t num_fired_alerts;
315  uint16_t num_fired_loc_alerts;
316 
317  // Need to configure the alert handler again after deep sleep
318  CHECK_DIF_OK(
319  dif_alert_handler_is_ping_timer_locked(&alert_handler, &is_locked));
320  // Configure the alert handler after wakeup if necessary
321  if (!is_locked) {
322  alert_handler_config(/*ping_timeout=*/ping_timeout_cyc);
323  }
324 
325  // Power-on reset
326  if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) == true) {
327  LOG_INFO("POR reset");
328 
329  // Increment the test_step counter for the next test step
330  CHECK_STATUS_OK(ret_sram_testutils_counter_increment(kCounterTestSteps));
331  CHECK_STATUS_OK(
332  ret_sram_testutils_counter_get(kCounterTestSteps, &test_step_cnt));
333 
334  // Set the AON timer to send a wakeup signal in ~10-50us.
335  CHECK_STATUS_OK(aon_timer_testutils_wakeup_config(
336  &aon_timer, (uint32_t)rand_testutils_gen32_range(2, 10)));
337 
338  // Trigger the SV side to inject fault.
339  // DO NOT CHANGE THIS: it is used to notify the SV side.
340  LOG_INFO("Ready for fault injection");
341 
342  // Enter normal sleep mode.
343  enter_low_power(/*deep_sleep=*/false);
344  } else if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(
345  &pwrmgr, pwrmgr_aon_timer_wakeups))) {
346  // Cleanup after wakeup
347  cleanup_wakeup_src();
348 
349  // Check if handler is locked after waking up from normal sleep.
350  CHECK_DIF_OK(
351  dif_alert_handler_is_ping_timer_locked(&alert_handler, &is_locked));
352  CHECK(
353  is_locked,
354  "The alert handler should be locked after waking up from normal sleep");
355 
356  // Clear all cause regs after the wakeup
357  alert_handler_clear_cause_regs();
358 
359  // Wait for the fatal alert to trigger again
360  busy_spin_micros(100);
361 
362  // The fatal alert fired by the SV
363  LOG_INFO("Phase #1 step %d", test_step_cnt);
364  LOG_INFO("Expected alert number = %d", kExpectedAlertNumber);
365 
366  num_fired_alerts = alert_handler_num_fired_alerts();
367  num_fired_loc_alerts = alert_handler_num_fired_loc_alerts();
368  LOG_INFO("num_fired alerts = %d, num_fired_loc_alerts = %d",
369  num_fired_alerts, num_fired_loc_alerts);
370 
371  // Check if the number of the fired alerts/local-alerts are correct
372  CHECK(num_fired_alerts == 1,
373  "Phase #1: Only a single alert must be fired after wakeup!");
374  CHECK(num_fired_loc_alerts == 0,
375  "Phase #1: No local alerts must be fired!");
376 
377  // Check if the expected fatal alert has been fired.
379  &alert_handler, kExpectedAlertNumber, &is_cause));
380  CHECK(is_cause, "Phase #1: Expected alert has NOT been fired!!");
381 
382  // Increment the test_step counter for the next test step
383  CHECK_STATUS_OK(ret_sram_testutils_counter_increment(kCounterTestSteps));
384  CHECK_STATUS_OK(
385  ret_sram_testutils_counter_get(kCounterTestSteps, &test_step_cnt));
386 
387  // Set the AON timer to send a wakeup signal in ~10-50us.
388  CHECK_STATUS_OK(aon_timer_testutils_wakeup_config(
389  &aon_timer, (uint32_t)rand_testutils_gen32_range(2, 10)));
390  // Enter the normal sleep mode
391  enter_low_power(/*deep_sleep=*/false);
392  } else {
393  dif_pwrmgr_wakeup_reason_t wakeup_reason;
394  CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason));
395  LOG_ERROR("Unexpected wakeup_reason=%x", wakeup_reason);
396  CHECK(false, "Unexpected wakeup reason");
397  }
398 }
399 
400 /**
401  * External interrupt handler.
402  */
403 void ottf_external_isr(uint32_t *exc_info) {
404  dif_pwrmgr_irq_t irq_id;
406 
407  isr_testutils_pwrmgr_isr(plic_ctx, pwrmgr_isr_ctx, &peripheral, &irq_id);
408 
409  // Check that both the peripheral and the irq id is correct
410  CHECK(peripheral == kTopEarlgreyPlicPeripheralPwrmgrAon,
411  "IRQ peripheral: %d is incorrect", peripheral);
412  CHECK(irq_id == kDifPwrmgrIrqWakeup, "IRQ ID: %d is incorrect", irq_id);
413 }
414 
415 bool test_main(void) {
416  // Check if there was a HW reset caused by the escalation.
418  rst_info = rstmgr_testutils_reason_get();
419  rstmgr_testutils_reason_clear();
420 
421  CHECK(rst_info == kDifRstmgrResetInfoPor ||
422  rst_info == kDifRstmgrResetInfoEscalation,
423  "Wrong reset reason %02X", rst_info);
424 
425  if (rst_info == kDifRstmgrResetInfoPor) {
426  CHECK_STATUS_OK(ret_sram_testutils_counter_clear(kCounterTestSteps));
427  CHECK_STATUS_OK(ret_sram_testutils_counter_clear(kCounterMaxWakeups));
428  }
429  init_test_components();
430 
431  // TEST PHASE #1 (ping-timeout = 256)
432  // To ensure that fatal alerts keep firing after sleep/wakeup.
433  // Only a single fatal alert is expected to be fired.
434  // No local alerts is expected to be fired.
435  while (test_step_cnt < num_total_wakeups) {
436  // TODO: It seems to be that the only way to continue the SW execution
437  // after a kTopEarlgreyAlertIdFlashCtrlFatalStdErr or
438  // kTopEarlgreyAlertIdSramCtrlMainFatalError a reset. In this test, we are
439  // only interested in the shallow sleep mode. Figure out a method to handle
440  // those alerts in C code. Currently, they are bypassed by the SV through
441  // aplusarg (avoid_inject_fatal_error_for_ips).
442  execute_test_phases(/*test_phase=*/1, /*ping_timeout_cyc=*/256);
443  }
444 
445  // Do the cleanup
446  cleanup_wakeup_src();
447 
448  return true;
449 }