Software APIs
pwrmgr_random_sleep_power_glitch_reset_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 
5 #include <assert.h>
6 #include <limits.h>
7 #include <stdbool.h>
8 #include <stdint.h>
9 
22 #include "sw/device/lib/runtime/irq.h"
24 #include "sw/device/lib/testing/alert_handler_testutils.h"
25 #include "sw/device/lib/testing/aon_timer_testutils.h"
26 #include "sw/device/lib/testing/flash_ctrl_testutils.h"
27 #include "sw/device/lib/testing/nv_counter_testutils.h"
28 #include "sw/device/lib/testing/pwrmgr_testutils.h"
29 #include "sw/device/lib/testing/rstmgr_testutils.h"
30 #include "sw/device/lib/testing/rv_plic_testutils.h"
31 #include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h"
32 #include "sw/device/lib/testing/test_framework/check.h"
34 
36 
37 OTTF_DEFINE_TEST_CONFIG();
38 static volatile const uint8_t RST_IDX[12] = {0, 1, 2, 3, 4, 5,
39  6, 7, 8, 9, 10, 11};
40 static const uint32_t kPlicTarget = kTopEarlgreyPlicTargetIbex0;
41 
42 /**
43  * Objects to access the peripherals used in this test via dif API.
44  */
45 static dif_flash_ctrl_state_t flash_ctrl;
46 static dif_rv_plic_t plic;
47 static dif_alert_handler_t alert_handler;
48 static dif_aon_timer_t aon_timer;
49 static dif_pwrmgr_t pwrmgr;
50 static dif_rstmgr_t rstmgr;
51 
52 /**
53  * Program the alert handler to escalate on alerts upto phase 2 (i.e. reset) but
54  * the phase 1 (i.e. wipe secrets) should occur and last during the time the
55  * wdog is programed to bark.
56  */
57 enum {
58  kWdogBarkMicros = 3 * 100, // 300 us
59  kWdogBiteMicros = 4 * 100, // 400 us
60  kEscalationPhase0Micros = 1 * 100, // 100 us
61  // The cpu value is slightly larger as the busy_spin_micros
62  // routine cycle count comes out slightly smaller due to the
63  // fact that it does not divide by exactly 1M
64  // see sw/device/lib/runtime/hart.c
65  kEscalationPhase0MicrosCpu = kEscalationPhase0Micros + 20, // 120 us
66  kEscalationPhase1Micros = 5 * 100, // 500 us
67  kEscalationPhase2Micros = 50, // 50 us
68 };
69 
70 static_assert(
71  kWdogBarkMicros < kWdogBiteMicros &&
72  kWdogBarkMicros > kEscalationPhase0Micros &&
73  kWdogBarkMicros < (kEscalationPhase0Micros + kEscalationPhase1Micros) &&
74  kWdogBiteMicros < (kEscalationPhase0Micros + kEscalationPhase1Micros),
75  "The wdog bark and bite shall happens during the escalation phase 1");
76 
77 /**
78  * External ISR.
79  *
80  * Handles all peripheral interrupts on Ibex. PLIC asserts an external interrupt
81  * line to the CPU, which results in a call to this OTTF ISR. This ISR
82  * overrides the default OTTF implementation.
83  */
84 void ottf_external_isr(uint32_t *exc_info) {
86  dif_rv_plic_irq_id_t irq_id;
87  uint32_t irq = 0;
88  uint32_t alert = 0;
89 
90  CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic, kPlicTarget, &irq_id));
91 
92  peripheral = (top_earlgrey_plic_peripheral_t)
94 
95  if (peripheral == kTopEarlgreyPlicPeripheralAonTimerAon) {
96  irq =
97  (dif_aon_timer_irq_t)(irq_id -
100 
101  // Stops escalation process.
102  CHECK_DIF_OK(dif_alert_handler_escalation_clear(&alert_handler,
103  kDifAlertHandlerClassA));
104  CHECK_DIF_OK(dif_aon_timer_irq_acknowledge(&aon_timer, irq));
105 
107  "AON Timer Wdog should not bark");
108 
109  } else if (peripheral == kTopEarlgreyPlicPeripheralAlertHandler) {
110  irq = (dif_rv_plic_irq_id_t)(irq_id -
113 
114  CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(&alert_handler, alert));
115 
118  &alert_handler, kDifAlertHandlerClassA, &state));
119 
120  CHECK(state == kDifAlertHandlerClassStatePhase0, "Wrong phase %d", state);
121 
122  CHECK_DIF_OK(dif_alert_handler_irq_acknowledge(&alert_handler, irq));
123  }
124 
125  // Complete the IRQ by writing the IRQ source to the Ibex specific CC
126  // register.
127  CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic, kPlicTarget, irq_id));
128 }
129 
130 /**
131  * Initialize the peripherals used in this test.
132  */
133 void init_peripherals(void) {
134  // Initialize pwrmgr.
135  CHECK_DIF_OK(dif_pwrmgr_init(
137 
138  // Initialize rstmgr to check the reset reason.
139  CHECK_DIF_OK(dif_rstmgr_init(
141 
142  // Initialize aon timer to use the wdog.
143  CHECK_DIF_OK(dif_aon_timer_init(
145 
146  // Initialize flash_ctrl
147  CHECK_DIF_OK(dif_flash_ctrl_init_state(
148  &flash_ctrl,
150 
151  // Initialize plic.
152  CHECK_DIF_OK(dif_rv_plic_init(
154 
155  rv_plic_testutils_irq_range_enable(
158 
159  // Initialize alert handler.
160  CHECK_DIF_OK(dif_alert_handler_init(
162  &alert_handler));
163 }
164 
165 /**
166  * Program the alert handler to escalate on alerts upto phase 2 (i.e. reset) but
167  * the phase 1 (i.e. wipe secrets) should occur and last during the time the
168  * wdog is programed to bark.
169  */
170 static void alert_handler_config(void) {
172  dif_alert_handler_class_t alert_classes[] = {kDifAlertHandlerClassA};
173 
174  uint32_t cycles[3] = {0};
175  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(
176  kEscalationPhase0Micros, &cycles[0]));
177  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(
178  kEscalationPhase1Micros, &cycles[1]));
179  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(
180  kEscalationPhase2Micros, &cycles[2]));
181 
182  dif_alert_handler_escalation_phase_t esc_phases[] = {
184  .signal = 0,
185  .duration_cycles =
186  cycles[0] * alert_handler_testutils_cycle_rescaling_factor()},
188  .signal = 1,
189  .duration_cycles =
190  cycles[1] * alert_handler_testutils_cycle_rescaling_factor()},
192  .signal = 3,
193  .duration_cycles =
194  cycles[2] * alert_handler_testutils_cycle_rescaling_factor()}};
195 
196  dif_alert_handler_class_config_t class_config[] = {{
198  .accumulator_threshold = 0,
199  .irq_deadline_cycles =
200  cycles[0] * alert_handler_testutils_cycle_rescaling_factor(),
201  .escalation_phases = esc_phases,
202  .escalation_phases_len = ARRAYSIZE(esc_phases),
203  .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase3,
204  }};
205 
206  dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA};
207  dif_alert_handler_config_t config = {
208  .alerts = alerts,
209  .alert_classes = alert_classes,
210  .alerts_len = ARRAYSIZE(alerts),
211  .classes = classes,
212  .class_configs = class_config,
213  .classes_len = ARRAYSIZE(class_config),
214  .ping_timeout = kAlertHandlerTestutilsDefaultPingTimeout,
215  };
216 
217  CHECK_STATUS_OK(alert_handler_testutils_configure_all(&alert_handler, config,
219  // Enables alert handler irq.
220  CHECK_DIF_OK(dif_alert_handler_irq_set_enabled(
221  &alert_handler, kDifAlertHandlerIrqClassa, kDifToggleEnabled));
222 }
223 
224 /**
225  * Execute the aon timer interrupt test.
226  */
227 static void config_escalate(dif_aon_timer_t *aon_timer,
228  const dif_pwrmgr_t *pwrmgr) {
229  uint32_t bark_cycles = 0;
230  CHECK_STATUS_OK(aon_timer_testutils_get_aon_cycles_32_from_us(kWdogBarkMicros,
231  &bark_cycles));
232  bark_cycles *= alert_handler_testutils_cycle_rescaling_factor();
233  uint32_t bite_cycles = 0;
234  CHECK_STATUS_OK(aon_timer_testutils_get_aon_cycles_32_from_us(kWdogBiteMicros,
235  &bite_cycles));
236  bite_cycles *= alert_handler_testutils_cycle_rescaling_factor();
237 
238  LOG_INFO(
239  "Wdog will bark after %u/%u us/cycles and bite after %u/%u us/cycles",
240  (uint32_t)kWdogBarkMicros, (uint32_t)bark_cycles,
241  (uint32_t)kWdogBiteMicros, (uint32_t)bite_cycles);
242 
243  // Setup the wdog bark and bite timeouts.
244  CHECK_STATUS_OK(aon_timer_testutils_watchdog_config(aon_timer, bark_cycles,
245  bite_cycles, false));
246 
247  // Trigger the alert handler to escalate.
248  dif_pwrmgr_alert_t alert = kDifPwrmgrAlertFatalFault;
249  CHECK_DIF_OK(dif_pwrmgr_alert_force(pwrmgr, alert));
250 }
251 
252 static void low_power_glitch_reset(const dif_pwrmgr_t *pwrmgr) {
253  // Program the pwrmgr to go to deep sleep state (clocks off).
254  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
255  pwrmgr, kDifPwrmgrWakeupRequestSourceFive, 0));
256  // Enter in low power mode.
258 }
259 
260 static void normal_sleep_glitch_reset(const dif_pwrmgr_t *pwrmgr) {
261  // Place device into normal (shallow) power
263  config = kDifPwrmgrDomainOptionUsbClockInLowPower |
266  kDifPwrmgrDomainOptionMainPowerInLowPower;
267  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
268  pwrmgr, kDifPwrmgrWakeupRequestSourceFive, config));
269  // Enter in low power mode.
271 }
272 
273 static void timer_on(uint32_t usec) {
274  busy_spin_micros(usec);
275  // If we arrive here the test must fail.
276  CHECK(false, "Timeout waiting for reset!");
277 }
278 
279 /**
280  * Configure the wdog.
281  */
282 static void config_wdog(const dif_aon_timer_t *aon_timer,
283  const dif_pwrmgr_t *pwrmgr, uint64_t bark_time_us,
284  uint64_t bite_time_us) {
285  uint32_t bark_cycles = 0;
286  CHECK_STATUS_OK(aon_timer_testutils_get_aon_cycles_32_from_us(bark_time_us,
287  &bark_cycles));
288  uint32_t bite_cycles = 0;
289  CHECK_STATUS_OK(aon_timer_testutils_get_aon_cycles_32_from_us(bite_time_us,
290  &bite_cycles));
291 
292  LOG_INFO("Wdog will bark after %u us and bite after %u us",
293  (uint32_t)bark_time_us, (uint32_t)bite_time_us);
294  // Setup the wdog bark and bite timeouts.
295 
296  CHECK_STATUS_OK(aon_timer_testutils_watchdog_config(aon_timer, bark_cycles,
297  bite_cycles, false));
298  // Set wdog as a reset source.
300  kDifPwrmgrResetRequestSourceTwo,
302 }
303 
304 /**
305  * Execute the aon timer wdog bite reset during sleep test.
306  */
307 static void sleep_wdog_bite_test(const dif_aon_timer_t *aon_timer,
308  const dif_pwrmgr_t *pwrmgr,
309  uint64_t bark_time_us) {
310  uint64_t bite_time_us = bark_time_us * 2;
311  config_wdog(aon_timer, pwrmgr, bark_time_us, bite_time_us);
312 }
313 
314 static void low_power_wdog(const dif_pwrmgr_t *pwrmgr) {
315  // Program the pwrmgr to go to deep sleep state (clocks off).
316  // Enter in low power mode.
317  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
318  pwrmgr, kDifPwrmgrWakeupRequestSourceTwo, 0));
319  LOG_INFO("Low power set for watch dog");
321  // If we arrive here the test must fail.
322  CHECK(false, "Fail to enter in low power mode!");
323 }
324 
325 static void normal_sleep_wdog(const dif_pwrmgr_t *pwrmgr) {
326  // Place device into low power and immediately wake.
328  config = kDifPwrmgrDomainOptionUsbClockInLowPower |
331  kDifPwrmgrDomainOptionMainPowerInLowPower;
332 
333  // Enter in low power mode.
334  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
335  pwrmgr, kDifPwrmgrWakeupRequestSourceTwo, config));
336  LOG_INFO("Normal sleep set for watchdog");
338 }
339 
340 static void low_power_por(const dif_pwrmgr_t *pwrmgr) {
341  // Set por as a reset source.
343  kDifPwrmgrResetRequestSourceTwo,
345 
346  // Program the pwrmgr to go to deep sleep state (clocks off).
347  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
348  pwrmgr,
349  (kDifPwrmgrWakeupRequestSourceOne | kDifPwrmgrWakeupRequestSourceTwo |
350  kDifPwrmgrWakeupRequestSourceThree | kDifPwrmgrWakeupRequestSourceFour |
351  kDifPwrmgrWakeupRequestSourceFive | kDifPwrmgrWakeupRequestSourceSix),
352  0));
353  // Enter in low power mode.
355  // If we arrive here the test must fail.
356  CHECK(false, "Fail to enter in low power mode!");
357 }
358 
359 static void normal_sleep_por(const dif_pwrmgr_t *pwrmgr) {
360  // Set por as a reset source.
362  kDifPwrmgrResetRequestSourceTwo,
364 
365  // Place device into low power and immediately wake.
367  config = kDifPwrmgrDomainOptionUsbClockInLowPower |
370  kDifPwrmgrDomainOptionMainPowerInLowPower;
371 
372  // Program the pwrmgr to go to swallow sleep state (clocks on).
373  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
374  pwrmgr,
375  (kDifPwrmgrWakeupRequestSourceOne | kDifPwrmgrWakeupRequestSourceTwo |
376  kDifPwrmgrWakeupRequestSourceThree | kDifPwrmgrWakeupRequestSourceFour |
377  kDifPwrmgrWakeupRequestSourceFive | kDifPwrmgrWakeupRequestSourceSix),
378  config));
379  // Enter in low power mode.
381 }
382 
383 bool test_main(void) {
384  // Enable global and external IRQ at Ibex.
385  irq_global_ctrl(true);
386  irq_external_ctrl(true);
387 
388  init_peripherals();
389 
390  // Enable all the AON interrupts used in this test.
391  rv_plic_testutils_irq_range_enable(&plic, kPlicTarget,
394 
395  alert_handler_config();
396 
397  // First check the flash stored value
398  uint32_t event_idx = 0;
399  CHECK_STATUS_OK(flash_ctrl_testutils_counter_get(0, &event_idx));
400 
401  // Enable flash access
402  CHECK_STATUS_OK(
403  flash_ctrl_testutils_default_region_access(&flash_ctrl,
404  /*rd_en*/ true,
405  /*prog_en*/ true,
406  /*erase_en*/ true,
407  /*scramble_en*/ false,
408  /*ecc_en*/ false,
409  /*he_en*/ false));
410 
411  // Increment flash counter to know where we are
412  CHECK_STATUS_OK(flash_ctrl_testutils_counter_increment(&flash_ctrl, 0));
413 
414  LOG_INFO("Test round %d", event_idx);
415  LOG_INFO("RST_IDX[%d] = %d", event_idx, RST_IDX[event_idx]);
416 
417  // Check if there was a HW reset caused by expected cases
419  rst_info = rstmgr_testutils_reason_get();
420  rstmgr_testutils_reason_clear();
421  LOG_INFO("reset info = %02X", rst_info);
422 
423  CHECK(rst_info == kDifRstmgrResetInfoPor ||
424  rst_info == kDifRstmgrResetInfoSysRstCtrl ||
425  rst_info == kDifRstmgrResetInfoWatchdog ||
426  rst_info == kDifRstmgrResetInfoEscalation ||
427  rst_info == kDifRstmgrResetInfoLowPowerExit ||
428  rst_info == (kDifRstmgrResetInfoSysRstCtrl |
430  rst_info == (kDifRstmgrResetInfoPowerUnstable |
432  rst_info == (kDifRstmgrResetInfoPowerUnstable |
433  kDifRstmgrResetInfoWatchdog |
435  rst_info == (kDifRstmgrResetInfoPowerUnstable |
436  kDifRstmgrResetInfoWatchdog) ||
437  rst_info == kDifRstmgrResetInfoPowerUnstable ||
438  rst_info ==
440  rst_info == (kDifRstmgrResetInfoWatchdog |
442  rst_info == (kDifRstmgrResetInfoEscalation |
444  rst_info == kDifRstmgrResetInfoSw,
445  "Wrong reset reason %02X", rst_info);
446 
447  switch (RST_IDX[event_idx] / 2) {
448  case 0:
449  if (RST_IDX[event_idx] % 2) {
450  LOG_INFO("Booting and setting normal sleep followed by glitch reset");
451  LOG_INFO("Let SV wait timer reset");
452  normal_sleep_glitch_reset(&pwrmgr);
453  timer_on(kWdogBiteMicros);
454  } else {
455  LOG_INFO("Booting and setting deep sleep followed by glitch reset");
456  LOG_INFO("Let SV wait timer reset");
457  low_power_glitch_reset(&pwrmgr);
458  }
459  break;
460  case 1:
461  if (RST_IDX[event_idx] % 2) {
462  LOG_INFO("Booting and setting normal sleep followed by hw por");
463  LOG_INFO("Let SV wait timer reset");
464  normal_sleep_por(&pwrmgr);
465  timer_on(kWdogBiteMicros);
466  } else {
467  LOG_INFO("Booting and setting deep sleep followed by hw por");
468  LOG_INFO("Let SV wait timer reset");
469  low_power_por(&pwrmgr);
470  }
471  break;
472  case 2:
473  if (RST_IDX[event_idx] % 2) {
474  LOG_INFO(
475  "Booting and setting normal sleep mode followed for low_power "
476  "entry reset");
477  LOG_INFO("Let SV wait timer reset");
478  // actually the same test as normal sleep + watchdog
479  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
480  sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200);
481  normal_sleep_wdog(&pwrmgr);
482  timer_on(kEscalationPhase0MicrosCpu);
483  } else {
484  LOG_INFO(
485  "Booting and setting deep sleep mode followed for low_power entry "
486  "reset");
487  LOG_INFO("Let SV wait timer reset");
488  // Executing the wdog bite reset during sleep test.
489  // actually the same test as deep sleep + watchdog
490  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
491  sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200);
492  low_power_wdog(&pwrmgr);
493  }
494  break;
495 
496  case 3:
497  if (RST_IDX[event_idx] % 2) {
498  LOG_INFO(
499  "Booting and setting normal sleep followed by watchdog reset "
500  "combined "
501  "with sw_req");
502  LOG_INFO("Let SV wait timer reset");
503  // Executing the wdog bite reset during sleep test.
504  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
505  CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr));
506  LOG_INFO("Device reset from sw");
507  sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200);
508  normal_sleep_wdog(&pwrmgr);
509  timer_on(kEscalationPhase0MicrosCpu);
510  } else {
511  LOG_INFO(
512  "Booting and setting deep sleep followed by watchdog reset "
513  "combined "
514  "with sw_req");
515  LOG_INFO("Let SV wait timer reset");
516  // Executing the wdog bite reset during sleep test.
517  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
518  CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr));
519  LOG_INFO("Device reset from sw");
520  sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200);
521  low_power_wdog(&pwrmgr);
522  }
523  break;
524  case 4:
525  if (RST_IDX[event_idx] % 2) {
526  LOG_INFO("Booting and setting normal sleep followed by watchdog reset");
527  LOG_INFO("Let SV wait timer reset");
528  // Executing the wdog bite reset during sleep test.
529  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
530  sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200);
531  normal_sleep_wdog(&pwrmgr);
532  timer_on(kEscalationPhase0MicrosCpu);
533  } else {
534  LOG_INFO("Booting and setting deep sleep followed by watchdog reset");
535  LOG_INFO("Let SV wait timer reset");
536  // Executing the wdog bite reset during sleep test.
537  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
538  sleep_wdog_bite_test(&aon_timer, &pwrmgr, 200);
539  low_power_wdog(&pwrmgr);
540  }
541  break;
542  case 5:
543  if (RST_IDX[event_idx] % 2) {
544  LOG_INFO("Last Booting");
545 
546  return true;
547  } else {
548  LOG_INFO(
549  "Booting and running normal sleep followed by escalation reset");
550  config_escalate(&aon_timer, &pwrmgr);
551  timer_on(kEscalationPhase0MicrosCpu);
552  }
553  break;
554  default:
555  LOG_INFO("Booting for undefined case");
556  }
557 
558  return false;
559 }