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 "fsm_error" state. This is a terminal state indicating the FSM
137  * has been glitched.
138  */
140  /**
141  * The terminal state. Most configurations will never reach this state, since
142  * one of the previous phases will use an escalation signal to reset the
143  * device.
144  */
146 
147  /**
148  * The zeroth escalation phase.
149  */
151  /**
152  * The first escalation phase.
153  */
155  /**
156  * The second escalation phase.
157  */
159  /**
160  * The third escalation phase.
161  */
164 
165 /**
166  * An escalation signal, identified by a numeric ID.
167  *
168  * An escalation signal is a generic "response" to failing to handle alert(s).
169  * The meaning of each escalation signal is determined by the chip.
170  *
171  * An alert class can be configured to raise various escalation signal(s) during
172  * various escalation phases as part of its escalation policy.
173  */
175 
176 /**
177  * Runtime configuration for an escalation phase.
178  */
180  /**
181  * The phase this configuration describes.
182  *
183  * It is an error for this to not be one of the `Phase` constants in
184  * `dif_alert_handler_class_state_t`.
185  */
187  /**
188  * The escalation signal that should be triggered when this phase begins.
189  */
191  /**
192  * The duration of this phase, in cycles.
193  */
194  uint32_t duration_cycles;
196 
197 /**
198  * Runtime configuration for a particular alert class.
199  *
200  * This struct describes the escalation protocol for an alert class.
201  */
203  /**
204  * Whether to automatically lock the accumulation counter.
205  *
206  * There are two ways to lock the accumulation counter (prevent it from being
207  * cleared once the class's escalation protocol has been triggered):
208  * 1. clear the write enable for the accumulation counter clear register, or
209  * 2. to set this configuration flag which will automatically clear the
210  * write enable for the accumulation counter clear register once the
211  * class's escalation protocol has been triggered.
212  */
214  /**
215  * The threshold for the class accmulator which indicates the number of alerts
216  * that must fire because the class's escalation protocol will trigger.
217  */
219  /**
220  * The number of cycles this class's associated IRQ handler has to acknowledge
221  * the IRQ before escalation is triggered.
222  *
223  * A value of zero disables the timeout.
224  */
226  /**
227  * Escalation phases to be configured for this class.
228  *
229  * Each escalation phase in this list will additionally be set as enabled for
230  * this class; phases not listed will have their escalation signals disabled.
231  */
233  /**
234  * The length of the array `escalation_phases`.
235  */
237  /**
238  * The escalation phase to capture the crashdump information in.
239  *
240  * It is an error for this to not be one of the `Phase` constants in
241  * `dif_alert_handler_class_state_t`.
242  *
243  * Note, it is recommended to capture the crashdump upon entering the first
244  * escalation phase that activates a countermeasure with many side-effects
245  * (e.g. life cycle state scrapping) in order to prevent spurious alert events
246  * from masking the original alert causes.
247  */
250 
251 /**
252  * Runtime configuration for the alert handler.
253  *
254  * This struct describes runtime information for a single-shot configuration of
255  * the alert handler hardware.
256  *
257  * Note, any of the array pointers may be NULL, in which case the associated
258  * length should be 0.
259  */
260 typedef struct dif_alert_handler_config {
261  /**
262  * A list of alerts to configure.
263  */
265  /**
266  * A list of classes to assign each alert to.
267  */
269  /**
270  * The lengths of the arrays `alerts` and `alert_classes`.
271  */
272  size_t alerts_len;
273 
274  /**
275  * A list of local alerts to configure.
276  */
278  /**
279  * A list of classes to assign each local alert to.
280  */
282  /**
283  * The lengths of the arrays `local_alerts` and `local_alert_classes`.
284  */
286 
287  /**
288  * A list of alert classes to configure.
289  */
291  /**
292  * A list of alert class (escalation protocol) configurations.
293  */
295  /**
296  * The length of the arrays `classes` and `class_configs`.
297  */
298  size_t classes_len;
299 
300  /**
301  * The alert ping timeout, in cycles.
302  *
303  * The alert handler will regularly, at random intervals, ping alert
304  * sources. If a source fails to respond, a local alert will be raised.
305  *
306  * The appropriate value will be dependent on all of the clocks involved on
307  * a chip.
308  *
309  * Note that the ping timer won't start until `dif_alert_handler_lock()` is
310  * successfully called.
311  *
312  * Note while this value must fit into the timeout register which is smaller
313  * than the native word length.
314  */
315  uint32_t ping_timeout;
316 
318 
319 /**
320  * Configures an alert in the alert handler.
321  *
322  * This operation is lock-protected, meaning once the configuration is locked,
323  * it cannot be reconfigured until after a system reset.
324  *
325  * @param alert_handler An alert handler handle.
326  * @param alert The alert to be configured.
327  * @param alert_class The class to assign the alert to.
328  * @param enabled The enablement state to configure the alert in.
329  * @param locked The locked state to configure the alert in.
330  * @return The result of the operation.
331  */
334  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert,
335  dif_alert_handler_class_t alert_class, dif_toggle_t enabled,
336  dif_toggle_t locked);
337 
338 /**
339  * Configures a local alert in the alert handler.
340  *
341  * This operation is lock-protected, meaning once the configuration is locked,
342  * it cannot be reconfigured until after a system reset.
343  *
344  * @param alert_handler An alert handler handle.
345  * @param local_alert The local alert to be configured.
346  * @param alert_class The class to assign the alert to.
347  * @param enabled The enablement state to configure the alert in.
348  * @param locked The locked state to configure the alert in.
349  * @return The result of the operation.
350  */
353  const dif_alert_handler_t *alert_handler,
355  dif_alert_handler_class_t alert_class, dif_toggle_t enabled,
356  dif_toggle_t locked);
357 
358 /**
359  * Configures the escalation protocol of an alert class in the alert handler.
360  *
361  * This operation is lock-protected, meaning once the configuration is locked,
362  * it cannot be reconfigured until after a system reset.
363  *
364  * Note, regardless if the class is enabled or, IRQs will still fire based on
365  * the accumulation counter threshold configuration for the class, however, the
366  * escalation protocol will not trigger.
367  *
368  * @param alert_handler An alert handler handle.
369  * @param alert_class The class to be configured.
370  * @param config The escalation protocol configuration.
371  * @param enabled The enablement state of the class escalation protocol.
372  * @param locked The locked state to configure the class in.
373  * @return The result of the operation.
374  */
377  const dif_alert_handler_t *alert_handler,
378  dif_alert_handler_class_t alert_class,
380  dif_toggle_t locked);
381 
382 /**
383  * Configures the ping timer in the alert handler.
384  *
385  * This operation is lock-protected, meaning once the configuration is locked,
386  * it cannot be reconfigured until after a system reset.
387  *
388  * Note, the ping timer will only ping alerts that have been enabled AND locked.
389  * Therefore, this DIF should be invoked after configuring and enabling each
390  * (local) alert.
391  *
392  * @param alert_handler An alert handler handle.
393  * @param ping_timeout The alert ping timeout, in cycles.
394  * @param enabled The enablement state to configure the ping timer in.
395  * @param locked The locked state to configure ping timer in.
396  * @return The result of the operation.
397  */
400  const dif_alert_handler_t *alert_handler, uint32_t ping_timeout,
401  dif_toggle_t enabled, dif_toggle_t locked);
402 
403 /**
404  * Enables the ping timer in the alert handler.
405  *
406  * This operation is lock-protected, meaning once the configuration is locked,
407  * it cannot be reconfigured until after a system reset.
408  *
409  * Note, the ping timer will only ping alerts that have been enabled AND locked.
410  * Therefore, this DIF should be invoked after configuring and enabling each
411  * (local) alert.
412  *
413  * @param alert_handler An alert handler handle.
414  * @param locked The locked state to configure ping timer in after enabling it.
415  * @return The result of the operation.
416  */
419  const dif_alert_handler_t *alert_handler, dif_toggle_t locked);
420 
421 /**
422  * Locks out an alert handler alert configuration.
423  *
424  * This operation cannot be undone, and should be performed at the end of
425  * configuring the alert handler in early boot.
426  *
427  * This function is reentrant: calling it while functionality is locked will
428  * have no effect and return `kDifOk`.
429  *
430  * @param alert_handler An alert handler handle.
431  * @param alert The alert to lock.
432  * @return The result of the operation.
433  */
436  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert);
437 
438 /**
439  * Checks whether an alert handler's alert is locked.
440  *
441  * @param alert_handler An alert handler handle.
442  * @param alert The alert to check is locked.
443  * @param[out] is_locked Out-param for the locked state.
444  * @return The result of the operation.
445  */
448  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert,
449  bool *is_locked);
450 
451 /**
452  * Locks out an alert handler local alert configuration.
453  *
454  * This operation cannot be undone, and should be performed at the end of
455  * configuring the alert handler in early boot.
456  *
457  * This function is reentrant: calling it while functionality is locked will
458  * have no effect and return `kDifOk`.
459  *
460  * @param alert_handler An alert handler handle.
461  * @param local_alert The local alert to lock.
462  * @return The result of the operation.
463  */
466  const dif_alert_handler_t *alert_handler,
467  dif_alert_handler_local_alert_t local_alert);
468 
469 /**
470  * Checks whether an alert handler's local alert is locked.
471  *
472  * @param alert_handler An alert handler handle.
473  * @param local_alert The local alert to check is locked.
474  * @param[out] is_locked Out-param for the locked state.
475  * @return The result of the operation.
476  */
479  const dif_alert_handler_t *alert_handler,
480  dif_alert_handler_local_alert_t local_alert, bool *is_locked);
481 
482 /**
483  * Locks out an alert handler class configuration.
484  *
485  * This operation cannot be undone, and should be performed at the end of
486  * configuring the alert handler in early boot.
487  *
488  * This function is reentrant: calling it while functionality is locked will
489  * have no effect and return `kDifOk`.
490  *
491  * @param alert_handler An alert handler handle.
492  * @param alert_class The alert class to lock.
493  * @return The result of the operation.
494  */
497  const dif_alert_handler_t *alert_handler,
498  dif_alert_handler_class_t alert_class);
499 
500 /**
501  * Checks whether an alert handler's class is locked.
502  *
503  * @param alert_handler An alert handler handle.
504  * @param alert_class The alert class to check is locked.
505  * @param[out] is_locked Out-param for the locked state.
506  * @return The result of the operation.
507  */
510  const dif_alert_handler_t *alert_handler,
511  dif_alert_handler_class_t alert_class, bool *is_locked);
512 
513 /**
514  * Locks out alert handler ping timer configuration.
515  *
516  * This operation cannot be undone, and should be performed at the end of
517  * configuring the alert handler in early boot.
518  *
519  * This function is reentrant: calling it while functionality is locked will
520  * have no effect and return `kDifOk`.
521  *
522  * @param alert_handler An alert handler handle.
523  * @return The result of the operation.
524  */
527  const dif_alert_handler_t *alert_handler);
528 
529 /**
530  * Checks whether alert handler's ping timer is locked.
531  *
532  * @param alert_handler An alert handler handle.
533  * @param[out] is_locked Out-param for the locked state.
534  * @return The result of the operation.
535  */
538  const dif_alert_handler_t *alert_handler, bool *is_locked);
539 
540 /**
541  * Checks whether an alert is one of the causes for an alert IRQ.
542  *
543  * Note that multiple alerts may be causes at the same time.
544  *
545  * @param alert_handler An alert handler handle.
546  * @param alert The alert to check.
547  * @param[out] is_cause Out-param for whether this alert is a cause.
548  * @return The result of the operation.
549  */
552  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert,
553  bool *is_cause);
554 
555 /**
556  * Clears an alert from the cause vector, similar to an IRQ acknowledgement.
557  *
558  * @param alert_handler An alert handler handle.
559  * @param alert The alert to acknowledge.
560  * @return The result of the operation.
561  */
564  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert);
565 
566 /**
567  * Checks whether a local alert is one of the causes for an alert IRQ.
568  *
569  * Note that multiple alerts may be causes at the same time.
570  *
571  * @param alert_handler An alert handler handle.
572  * @param local_alert The local alert to check.
573  * @param[out] is_cause Out-param for whether this alert is a cause.
574  * @return The result of the operation.
575  */
578  const dif_alert_handler_t *alert_handler,
579  dif_alert_handler_local_alert_t local_alert, bool *is_cause);
580 
581 /**
582  * Clears a local alert from the cause vector, similar to an IRQ
583  * acknowledgement.
584  *
585  * @param alert_handler An alert handler handle.
586  * @param local_alert The local alert to acknowledge.
587  * @return The result of the operation.
588  */
591  const dif_alert_handler_t *alert_handler,
592  dif_alert_handler_local_alert_t local_alert);
593 
594 /**
595  * Checks whether software can clear escalations for this class.
596  *
597  * If `automatic_locking` has been set in a class's configuration, this
598  * function may suddenly begin returning `false` instead of `true` without
599  * software invervention, if escalation has been triggered.
600  *
601  * @param alert_handler An alert handler handle.
602  * @param alert_class The class to check.
603  * @param[out] can_clear Out-param for the clear enablement state.
604  * @return The result of the operation.
605  */
608  const dif_alert_handler_t *alert_handler,
609  dif_alert_handler_class_t alert_class, bool *can_clear);
610 
611 /**
612  * Disables escalation clearing for this class.
613  *
614  * This operation is similar to locking in that it cannot be undone.
615  *
616  * @param alert_handler An alert handler handle.
617  * @param alert_class The class to disable clearing for.
618  * @return The result of the operation.
619  */
622  const dif_alert_handler_t *alert_handler,
623  dif_alert_handler_class_t alert_class);
624 
625 /**
626  * Clears an on-going escalation, as well as the class accumulator.
627  *
628  * This operation can be disabled with
629  * `dif_alert_handler_escalation_disable_clearing()`.
630  *
631  * @param alert_handler An alert handler handle.
632  * @param alert_class The class to clear an escalation for.
633  * @return The result of the operation.
634  */
637  const dif_alert_handler_t *alert_handler,
638  dif_alert_handler_class_t alert_class);
639 
640 /**
641  * Gets the accumulator value for this class.
642  *
643  * This value is the number of alerts of this class that have been logged so
644  * far (more or less, since multiple alerts on the same cycle will be merged
645  * into one). Once this value equals the configured threshold, any followup
646  * alerts will immediately trigger the escalation protocol.
647  *
648  * This value is cleared as a side-effect of
649  * `dif_alert_handler_escalation_clear()`.
650  *
651  * @param alert_handler An alert handler handle.
652  * @param alert_class The class to get the accumulator for.
653  * @param[out] num_alerts Out-param for the number of alerts that have
654  * accumulated.
655  * @return The result of the operation.
656  */
659  const dif_alert_handler_t *alert_handler,
660  dif_alert_handler_class_t alert_class, uint16_t *num_alerts);
661 
662 /**
663  * Gets the current value of the "escalation counter".
664  *
665  * The interpretation of this value depends on the value returned by
666  * `dif_alert_handler_class_state_get()`. If it is in the timeout state,
667  * it returns the number of cycles counted towards that cycle so far.
668  * If in an escalation phase, it returns the number of cycles that phase
669  * has been active for.
670  *
671  * @param alert_handler An alert handler handle.
672  * @param alert_class The class to set the counter for.
673  * @param[out] cycles Out-param for the counter.
674  * @return The result of the operation.
675  */
678  const dif_alert_handler_t *alert_handler,
679  dif_alert_handler_class_t alert_class, uint32_t *cycles);
680 
681 /**
682  * Gets the current state of this class.
683  *
684  * See `dif_alert_handler_class_state_t` for potential states.
685  *
686  * @param alert_handler An alert handler handle.
687  * @param alert_class The class to get the state of
688  * @param[out] state Out-param for the class state.
689  * @return The result of the operation.
690  */
693  const dif_alert_handler_t *alert_handler,
694  dif_alert_handler_class_t alert_class,
696 
697 #ifdef __cplusplus
698 } // extern "C"
699 #endif // __cplusplus
700 
701 #endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_ALERT_HANDLER_H_