Software APIs
dif_alert_handler.h
Go to the documentation of this file.
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 #ifndef OPENTITAN_SW_DEVICE_LIB_DIF_DIF_ALERT_HANDLER_H_
6 #define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_ALERT_HANDLER_H_
7 
8 /**
9  * @file
10  * @brief <a href="/hw/ip/alert_handler/doc/">Alert handler</a> Device Interface
11  * Functions
12  */
13 
14 #include <stdint.h>
15 
19 
21 
22 #ifdef __cplusplus
23 extern "C" {
24 #endif // __cplusplus
25 
26 /**
27  * Helper X macro for defining enums and case statements related to alert
28  * classes. If an additional class is ever added to the hardware, this list can
29  * be updated.
30  */
31 #define LIST_OF_CLASSES(X) \
32  X(A, 0) \
33  X(B, 1) \
34  X(C, 2) \
35  X(D, 3)
36 
37 /**
38  * Helper macro for defining a `dif_alert_handler_class_t` enumeration constant.
39  * @class_ Alert class of the enumeration constant.
40  * @value_ Value of the enumeration constant.
41  */
42 #define ALERT_CLASS_ENUM_INIT_(class_, value_) \
43  kDifAlertHandlerClass##class_ = value_,
44 
45 /**
46  * An alert class.
47  *
48  * An alert class roughly specifies how to deal with an alert. The class
49  * determines which interrupt handler is fired for an alert, as well as the
50  * fine-grained details of the escalation policy, for when the processor
51  * fails to respond to an alert quickly enough.
52  *
53  * Alert classes serve as the alert handler's IRQ types. There is one IRQ for
54  * each class. Whenever an alert fires, the corresponding class's IRQ is
55  * serviced by the processor (if enabled).
56  */
60 
61 /**
62  * An alert, identified by a numeric id.
63  *
64  * Alerts are hardware-level events indicating that something catastrophic
65  * has happened. The alert handler consumes alerts, classifies them into a
66  * particular `dif_alert_handler_class_t`, and uses policy information attached
67  * to that class to handle it.
68  *
69  * The number of alerts is configurable at hardware-synthesis time.
70  */
71 typedef uint32_t dif_alert_handler_alert_t;
72 
73 /**
74  * Helper X macro for defining enums and case statements related to local
75  * alerts. If an additional class is ever added to the hardware, this list can
76  * be updated.
77  */
78 #define LIST_OF_LOC_ALERTS(X) \
79  X(kDifAlertHandlerLocalAlertAlertPingFail, 0) \
80  X(kDifAlertHandlerLocalAlertEscalationPingFail, 1) \
81  X(kDifAlertHandlerLocalAlertAlertIntegrityFail, 2) \
82  X(kDifAlertHandlerLocalAlertEscalationIntegrityFail, 3) \
83  X(kDifAlertHandlerLocalAlertBusIntegrityFail, 4) \
84  X(kDifAlertHandlerLocalAlertShadowedUpdateError, 5) \
85  X(kDifAlertHandlerLocalAlertShadowedStorageError, 6)
86 
87 /**
88  * Helper macro for defining a `dif_alert_handler_local_alert_t` enumeration
89  * constant.
90  * @name_ Name of the enumeration constant.
91  */
92 #define LOC_ALERT_ENUM_INIT_(name_, value_) name_ = value_,
93 
94 /**
95  * A local alert originating from within the alert handler itself.
96  *
97  * A local alert is exactly the same as a normal `dif_alert_handler_alert_t`,
98  * except that they use different functions for setting up classification and
99  * for getting causes.
100  */
104 
105 /**
106  * An alert class state.
107  *
108  * This enum describes the sequence of states in the *escalation protocol*,
109  * which triggers under two different conditions:
110  * - If too many alerts of a particular class accumulate.
111  * - If the software IRQ handler for that class times out.
112  *
113  * When either of these conditions is reached, phase 0 begins. This may trigger
114  * an escalation signal, and after a configured duration, proceed to phase 1.
115  * This process repeats until phase 3 ends, at which point the class enters a
116  * "bricked" terminal state, which cannot be exited except by reset.
117  *
118  * At any point, software may end the escalation protocol by calling
119  * `dif_alert_handler_escalation_clear()` (unless clearing is disabled).
120  * Successfully calling this function, or clearing the IRQ on time, will reset
121  * the state back to idle. Note that this function cannot clear the terminal
122  * state; that state can only be cleared by resetting the chip.
123  */
125  /**
126  * The initial, idle state.
127  */
129  /**
130  * The "timeout" state, that is, the IRQ has been fired and the clock is
131  * ticking for the processor to handle the alert.
132  */
134 
135  /**
136  * The zeroth escalation phase.
137  */
139  /**
140  * The first escalation phase.
141  */
143  /**
144  * The second escalation phase.
145  */
147  /**
148  * The third escalation phase.
149  */
151 
152  /**
153  * The terminal state. Most configurations will never reach this state, since
154  * one of the previous phases will use an escalation signal to reset the
155  * device.
156  */
159 
160 /**
161  * An escalation signal, identified by a numeric ID.
162  *
163  * An escalation signal is a generic "response" to failing to handle alert(s).
164  * The meaning of each escalation signal is determined by the chip.
165  *
166  * An alert class can be configured to raise various escalation signal(s) during
167  * various escalation phases as part of its escalation policy.
168  */
170 
171 /**
172  * Runtime configuration for an escalation phase.
173  */
175  /**
176  * The phase this configuration describes.
177  *
178  * It is an error for this to not be one of the `Phase` constants in
179  * `dif_alert_handler_class_state_t`.
180  */
182  /**
183  * The escalation signal that should be triggered when this phase begins.
184  */
186  /**
187  * The duration of this phase, in cycles.
188  */
189  uint32_t duration_cycles;
191 
192 /**
193  * Runtime configuration for a particular alert class.
194  *
195  * This struct describes the escalation protocol for an alert class.
196  */
198  /**
199  * Whether to automatically lock the accumulation counter.
200  *
201  * There are two ways to lock the accumulation counter (prevent it from being
202  * cleared once the class's escalation protocol has been triggered):
203  * 1. clear the write enable for the accumulation counter clear register, or
204  * 2. to set this configuration flag which will automatically clear the
205  * write enable for the accumulation counter clear register once the
206  * class's escalation protocol has been triggered.
207  */
209  /**
210  * The threshold for the class accmulator which indicates the number of alerts
211  * that must fire because the class's escalation protocol will trigger.
212  */
214  /**
215  * The number of cycles this class's associated IRQ handler has to acknowledge
216  * the IRQ before escalation is triggered.
217  *
218  * A value of zero disables the timeout.
219  */
221  /**
222  * Escalation phases to be configured for this class.
223  *
224  * Each escalation phase in this list will additionally be set as enabled for
225  * this class; phases not listed will have their escalation signals disabled.
226  */
228  /**
229  * The length of the array `escalation_phases`.
230  */
232  /**
233  * The escalation phase to capture the crashdump information in.
234  *
235  * It is an error for this to not be one of the `Phase` constants in
236  * `dif_alert_handler_class_state_t`.
237  *
238  * Note, it is recommended to capture the crashdump upon entering the first
239  * escalation phase that activates a countermeasure with many side-effects
240  * (e.g. life cycle state scrapping) in order to prevent spurious alert events
241  * from masking the original alert causes.
242  */
245 
246 /**
247  * Runtime configuration for the alert handler.
248  *
249  * This struct describes runtime information for a single-shot configuration of
250  * the alert handler hardware.
251  *
252  * Note, any of the array pointers may be NULL, in which case the associated
253  * length should be 0.
254  */
255 typedef struct dif_alert_handler_config {
256  /**
257  * A list of alerts to configure.
258  */
260  /**
261  * A list of classes to assign each alert to.
262  */
264  /**
265  * The lengths of the arrays `alerts` and `alert_classes`.
266  */
267  size_t alerts_len;
268 
269  /**
270  * A list of local alerts to configure.
271  */
273  /**
274  * A list of classes to assign each local alert to.
275  */
277  /**
278  * The lengths of the arrays `local_alerts` and `local_alert_classes`.
279  */
281 
282  /**
283  * A list of alert classes to configure.
284  */
286  /**
287  * A list of alert class (escalation protocol) configurations.
288  */
290  /**
291  * The length of the arrays `classes` and `class_configs`.
292  */
293  size_t classes_len;
294 
295  /**
296  * The alert ping timeout, in cycles.
297  *
298  * The alert handler will regularly, at random intervals, ping alert
299  * sources. If a source fails to respond, a local alert will be raised.
300  *
301  * The appropriate value will be dependent on all of the clocks involved on
302  * a chip.
303  *
304  * Note that the ping timer won't start until `dif_alert_handler_lock()` is
305  * successfully called.
306  *
307  * Note while this value must fit into the timeout register which is smaller
308  * than the native word length.
309  */
310  uint32_t ping_timeout;
311 
313 
314 /**
315  * Configures an alert in the alert handler.
316  *
317  * This operation is lock-protected, meaning once the configuration is locked,
318  * it cannot be reconfigured until after a system reset.
319  *
320  * @param alert_handler An alert handler handle.
321  * @param alert The alert to be configured.
322  * @param alert_class The class to assign the alert to.
323  * @param enabled The enablement state to configure the alert in.
324  * @param locked The locked state to configure the alert in.
325  * @return The result of the operation.
326  */
329  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert,
330  dif_alert_handler_class_t alert_class, dif_toggle_t enabled,
331  dif_toggle_t locked);
332 
333 /**
334  * Configures a local alert in the alert handler.
335  *
336  * This operation is lock-protected, meaning once the configuration is locked,
337  * it cannot be reconfigured until after a system reset.
338  *
339  * @param alert_handler An alert handler handle.
340  * @param local_alert The local alert to be configured.
341  * @param alert_class The class to assign the alert to.
342  * @param enabled The enablement state to configure the alert in.
343  * @param locked The locked state to configure the alert in.
344  * @return The result of the operation.
345  */
348  const dif_alert_handler_t *alert_handler,
350  dif_alert_handler_class_t alert_class, dif_toggle_t enabled,
351  dif_toggle_t locked);
352 
353 /**
354  * Configures the escalation protocol of an alert class in the alert handler.
355  *
356  * This operation is lock-protected, meaning once the configuration is locked,
357  * it cannot be reconfigured until after a system reset.
358  *
359  * Note, regardless if the class is enabled or, IRQs will still fire based on
360  * the accumulation counter threshold configuration for the class, however, the
361  * escalation protocol will not trigger.
362  *
363  * @param alert_handler An alert handler handle.
364  * @param alert_class The class to be configured.
365  * @param config The escalation protocol configuration.
366  * @param enabled The enablement state of the class escalation protocol.
367  * @param locked The locked state to configure the class in.
368  * @return The result of the operation.
369  */
372  const dif_alert_handler_t *alert_handler,
373  dif_alert_handler_class_t alert_class,
375  dif_toggle_t locked);
376 
377 /**
378  * Configures the ping timer in the alert handler.
379  *
380  * This operation is lock-protected, meaning once the configuration is locked,
381  * it cannot be reconfigured until after a system reset.
382  *
383  * Note, the ping timer will only ping alerts that have been enabled AND locked.
384  * Therefore, this DIF should be invoked after configuring and enabling each
385  * (local) alert.
386  *
387  * @param alert_handler An alert handler handle.
388  * @param ping_timeout The alert ping timeout, in cycles.
389  * @param enabled The enablement state to configure the ping timer in.
390  * @param locked The locked state to configure ping timer in.
391  * @return The result of the operation.
392  */
395  const dif_alert_handler_t *alert_handler, uint32_t ping_timeout,
396  dif_toggle_t enabled, dif_toggle_t locked);
397 
398 /**
399  * Enables the ping timer in the alert handler.
400  *
401  * This operation is lock-protected, meaning once the configuration is locked,
402  * it cannot be reconfigured until after a system reset.
403  *
404  * Note, the ping timer will only ping alerts that have been enabled AND locked.
405  * Therefore, this DIF should be invoked after configuring and enabling each
406  * (local) alert.
407  *
408  * @param alert_handler An alert handler handle.
409  * @param locked The locked state to configure ping timer in after enabling it.
410  * @return The result of the operation.
411  */
414  const dif_alert_handler_t *alert_handler, dif_toggle_t locked);
415 
416 /**
417  * Locks out an alert handler alert configuration.
418  *
419  * This operation cannot be undone, and should be performed at the end of
420  * configuring the alert handler in early boot.
421  *
422  * This function is reentrant: calling it while functionality is locked will
423  * have no effect and return `kDifOk`.
424  *
425  * @param alert_handler An alert handler handle.
426  * @param alert The alert to lock.
427  * @return The result of the operation.
428  */
431  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert);
432 
433 /**
434  * Checks whether an alert handler's alert is locked.
435  *
436  * @param alert_handler An alert handler handle.
437  * @param alert The alert to check is locked.
438  * @param[out] is_locked Out-param for the locked state.
439  * @return The result of the operation.
440  */
443  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert,
444  bool *is_locked);
445 
446 /**
447  * Locks out an alert handler local alert configuration.
448  *
449  * This operation cannot be undone, and should be performed at the end of
450  * configuring the alert handler in early boot.
451  *
452  * This function is reentrant: calling it while functionality is locked will
453  * have no effect and return `kDifOk`.
454  *
455  * @param alert_handler An alert handler handle.
456  * @param local_alert The local alert to lock.
457  * @return The result of the operation.
458  */
461  const dif_alert_handler_t *alert_handler,
462  dif_alert_handler_local_alert_t local_alert);
463 
464 /**
465  * Checks whether an alert handler's local alert is locked.
466  *
467  * @param alert_handler An alert handler handle.
468  * @param local_alert The local alert to check is locked.
469  * @param[out] is_locked Out-param for the locked state.
470  * @return The result of the operation.
471  */
474  const dif_alert_handler_t *alert_handler,
475  dif_alert_handler_local_alert_t local_alert, bool *is_locked);
476 
477 /**
478  * Locks out an alert handler class configuration.
479  *
480  * This operation cannot be undone, and should be performed at the end of
481  * configuring the alert handler in early boot.
482  *
483  * This function is reentrant: calling it while functionality is locked will
484  * have no effect and return `kDifOk`.
485  *
486  * @param alert_handler An alert handler handle.
487  * @param alert_class The alert class to lock.
488  * @return The result of the operation.
489  */
492  const dif_alert_handler_t *alert_handler,
493  dif_alert_handler_class_t alert_class);
494 
495 /**
496  * Checks whether an alert handler's class is locked.
497  *
498  * @param alert_handler An alert handler handle.
499  * @param alert_class The alert class to check is locked.
500  * @param[out] is_locked Out-param for the locked state.
501  * @return The result of the operation.
502  */
505  const dif_alert_handler_t *alert_handler,
506  dif_alert_handler_class_t alert_class, bool *is_locked);
507 
508 /**
509  * Locks out alert handler ping timer configuration.
510  *
511  * This operation cannot be undone, and should be performed at the end of
512  * configuring the alert handler in early boot.
513  *
514  * This function is reentrant: calling it while functionality is locked will
515  * have no effect and return `kDifOk`.
516  *
517  * @param alert_handler An alert handler handle.
518  * @return The result of the operation.
519  */
522  const dif_alert_handler_t *alert_handler);
523 
524 /**
525  * Checks whether alert handler's ping timer is locked.
526  *
527  * @param alert_handler An alert handler handle.
528  * @param[out] is_locked Out-param for the locked state.
529  * @return The result of the operation.
530  */
533  const dif_alert_handler_t *alert_handler, bool *is_locked);
534 
535 /**
536  * Checks whether an alert is one of the causes for an alert IRQ.
537  *
538  * Note that multiple alerts may be causes at the same time.
539  *
540  * @param alert_handler An alert handler handle.
541  * @param alert The alert to check.
542  * @param[out] is_cause Out-param for whether this alert is a cause.
543  * @return The result of the operation.
544  */
547  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert,
548  bool *is_cause);
549 
550 /**
551  * Clears an alert from the cause vector, similar to an IRQ acknowledgement.
552  *
553  * @param alert_handler An alert handler handle.
554  * @param alert The alert to acknowledge.
555  * @return The result of the operation.
556  */
559  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert);
560 
561 /**
562  * Checks whether a local alert is one of the causes for an alert IRQ.
563  *
564  * Note that multiple alerts may be causes at the same time.
565  *
566  * @param alert_handler An alert handler handle.
567  * @param local_alert The local alert to check.
568  * @param[out] is_cause Out-param for whether this alert is a cause.
569  * @return The result of the operation.
570  */
573  const dif_alert_handler_t *alert_handler,
574  dif_alert_handler_local_alert_t local_alert, bool *is_cause);
575 
576 /**
577  * Clears a local alert from the cause vector, similar to an IRQ
578  * acknowledgement.
579  *
580  * @param alert_handler An alert handler handle.
581  * @param local_alert The local alert to acknowledge.
582  * @return The result of the operation.
583  */
586  const dif_alert_handler_t *alert_handler,
587  dif_alert_handler_local_alert_t local_alert);
588 
589 /**
590  * Checks whether software can clear escalations for this class.
591  *
592  * If `automatic_locking` has been set in a class's configuration, this
593  * function may suddenly begin returning `false` instead of `true` without
594  * software invervention, if escalation has been triggered.
595  *
596  * @param alert_handler An alert handler handle.
597  * @param alert_class The class to check.
598  * @param[out] can_clear Out-param for the clear enablement state.
599  * @return The result of the operation.
600  */
603  const dif_alert_handler_t *alert_handler,
604  dif_alert_handler_class_t alert_class, bool *can_clear);
605 
606 /**
607  * Disables escalation clearing for this class.
608  *
609  * This operation is similar to locking in that it cannot be undone.
610  *
611  * @param alert_handler An alert handler handle.
612  * @param alert_class The class to disable clearing for.
613  * @return The result of the operation.
614  */
617  const dif_alert_handler_t *alert_handler,
618  dif_alert_handler_class_t alert_class);
619 
620 /**
621  * Clears an on-going escalation, as well as the class accumulator.
622  *
623  * This operation can be disabled with
624  * `dif_alert_handler_escalation_disable_clearing()`.
625  *
626  * @param alert_handler An alert handler handle.
627  * @param alert_class The class to clear an escalation for.
628  * @return The result of the operation.
629  */
632  const dif_alert_handler_t *alert_handler,
633  dif_alert_handler_class_t alert_class);
634 
635 /**
636  * Gets the accumulator value for this class.
637  *
638  * This value is the number of alerts of this class that have been logged so
639  * far (more or less, since multiple alerts on the same cycle will be merged
640  * into one). Once this value equals the configured threshold, any followup
641  * alerts will immediately trigger the escalation protocol.
642  *
643  * This value is cleared as a side-effect of
644  * `dif_alert_handler_escalation_clear()`.
645  *
646  * @param alert_handler An alert handler handle.
647  * @param alert_class The class to get the accumulator for.
648  * @param[out] num_alerts Out-param for the number of alerts that have
649  * accumulated.
650  * @return The result of the operation.
651  */
654  const dif_alert_handler_t *alert_handler,
655  dif_alert_handler_class_t alert_class, uint16_t *num_alerts);
656 
657 /**
658  * Gets the current value of the "escalation counter".
659  *
660  * The interpretation of this value depends on the value returned by
661  * `dif_alert_handler_class_state_get()`. If it is in the timeout state,
662  * it returns the number of cycles counted towards that cycle so far.
663  * If in an escalation phase, it returns the number of cycles that phase
664  * has been active for.
665  *
666  * @param alert_handler An alert handler handle.
667  * @param alert_class The class to set the counter for.
668  * @param[out] cycles Out-param for the counter.
669  * @return The result of the operation.
670  */
673  const dif_alert_handler_t *alert_handler,
674  dif_alert_handler_class_t alert_class, uint32_t *cycles);
675 
676 /**
677  * Gets the current state of this class.
678  *
679  * See `dif_alert_handler_class_state_t` for potential states.
680  *
681  * @param alert_handler An alert handler handle.
682  * @param alert_class The class to get the state of
683  * @param[out] state Out-param for the class state.
684  * @return The result of the operation.
685  */
688  const dif_alert_handler_t *alert_handler,
689  dif_alert_handler_class_t alert_class,
691 
692 #ifdef __cplusplus
693 } // extern "C"
694 #endif // __cplusplus
695 
696 #endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_ALERT_HANDLER_H_