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