exception-handling.rst 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. Exception Handling Framework
  2. ============================
  3. This document describes various aspects of handling exceptions by Runtime
  4. Firmware (BL31) that are targeted at EL3, other than SMCs. The |EHF| takes care
  5. of the following exceptions when targeted at EL3:
  6. - Interrupts
  7. - Synchronous External Aborts
  8. - Asynchronous External Aborts
  9. |TF-A|'s handling of synchronous ``SMC`` exceptions raised from lower ELs is
  10. described in the :ref:`Firmware Design document <handling-an-smc>`. However, the
  11. |EHF| changes the semantics of `Interrupt handling`_ and :ref:`synchronous
  12. exceptions <Effect on SMC calls>` other than SMCs.
  13. The |EHF| is selected by setting the build option ``EL3_EXCEPTION_HANDLING`` to
  14. ``1``, and is only available for AArch64 systems.
  15. Introduction
  16. ------------
  17. Through various control bits in the ``SCR_EL3`` register, the Arm architecture
  18. allows for asynchronous exceptions to be routed to EL3. As described in the
  19. :ref:`Interrupt Management Framework` document, depending on the chosen
  20. interrupt routing model, TF-A appropriately sets the ``FIQ`` and ``IRQ`` bits of
  21. ``SCR_EL3`` register to effect this routing. For most use cases, other than for
  22. the purpose of facilitating context switch between Normal and Secure worlds,
  23. FIQs and IRQs routed to EL3 are not required to be handled in EL3.
  24. However, the evolving system and standards landscape demands that various
  25. exceptions are targeted at and handled in EL3. For instance:
  26. - Starting with ARMv8.2 architecture extension, many RAS features have been
  27. introduced to the Arm architecture. With RAS features implemented, various
  28. components of the system may use one of the asynchronous exceptions to signal
  29. error conditions to PEs. These error conditions are of critical nature, and
  30. it's imperative that corrective or remedial actions are taken at the earliest
  31. opportunity. Therefore, a *Firmware-first Handling* approach is generally
  32. followed in response to RAS events in the system.
  33. - The Arm `SDEI specification`_ defines interfaces through which Normal world
  34. interacts with the Runtime Firmware in order to request notification of
  35. system events. The |SDEI| specification requires that these events are
  36. notified even when the Normal world executes with the exceptions masked. This
  37. too implies that firmware-first handling is required, where the events are
  38. first received by the EL3 firmware, and then dispatched to Normal world
  39. through purely software mechanism.
  40. For |TF-A|, firmware-first handling means that asynchronous exceptions are
  41. suitably routed to EL3, and the Runtime Firmware (BL31) is extended to include
  42. software components that are capable of handling those exceptions that target
  43. EL3. These components—referred to as *dispatchers* [#spd]_ in general—may
  44. choose to:
  45. .. _delegation-use-cases:
  46. - Receive and handle exceptions entirely in EL3, meaning the exceptions
  47. handling terminates in EL3.
  48. - Receive exceptions, but handle part of the exception in EL3, and delegate the
  49. rest of the handling to a dedicated software stack running at lower Secure
  50. ELs. In this scheme, the handling spans various secure ELs.
  51. - Receive exceptions, but handle part of the exception in EL3, and delegate
  52. processing of the error to dedicated software stack running at lower secure
  53. ELs (as above); additionally, the Normal world may also be required to
  54. participate in the handling, or be notified of such events (for example, as
  55. an |SDEI| event). In this scheme, exception handling potentially and
  56. maximally spans all ELs in both Secure and Normal worlds.
  57. On any given system, all of the above handling models may be employed
  58. independently depending on platform choice and the nature of the exception
  59. received.
  60. .. [#spd] Not to be confused with :ref:`Secure Payload Dispatcher
  61. <firmware_design_sel1_spd>`, which is an EL3 component that operates in EL3
  62. on behalf of Secure OS.
  63. The role of Exception Handling Framework
  64. ----------------------------------------
  65. Corollary to the use cases cited above, the primary role of the |EHF| is to
  66. facilitate firmware-first handling of exceptions on Arm systems. The |EHF| thus
  67. enables multiple exception dispatchers in runtime firmware to co-exist, register
  68. for, and handle exceptions targeted at EL3. This section outlines the basics,
  69. and the rest of this document expands the various aspects of the |EHF|.
  70. In order to arbitrate exception handling among dispatchers, the |EHF| operation
  71. is based on a priority scheme. This priority scheme is closely tied to how the
  72. Arm GIC architecture defines it, although it's applied to non-interrupt
  73. exceptions too (SErrors, for example).
  74. The platform is required to `partition`__ the Secure priority space into
  75. priority levels as applicable for the Secure software stack. It then assigns the
  76. dispatchers to one or more priority levels. The dispatchers then register
  77. handlers for the priority levels at runtime. A dispatcher can register handlers
  78. for more than one priority level.
  79. .. __: `Partitioning priority levels`_
  80. .. _ehf-figure:
  81. .. image:: ../resources/diagrams/draw.io/ehf.svg
  82. A priority level is *active* when a handler at that priority level is currently
  83. executing in EL3, or has delegated the execution to a lower EL. For interrupts,
  84. this is implicit when an interrupt is targeted and acknowledged at EL3, and the
  85. priority of the acknowledged interrupt is used to match its registered handler.
  86. The priority level is likewise implicitly deactivated when the interrupt
  87. handling concludes by EOIing the interrupt.
  88. Non-interrupt exceptions (SErrors, for example) don't have a notion of priority.
  89. In order for the priority arbitration to work, the |EHF| provides APIs in order
  90. for these non-interrupt exceptions to assume a priority, and to interwork with
  91. interrupts. Dispatchers handling such exceptions must therefore explicitly
  92. activate and deactivate the respective priority level as and when they're
  93. handled or delegated.
  94. Because priority activation and deactivation for interrupt handling is implicit
  95. and involves GIC priority masking, it's impossible for a lower priority
  96. interrupt to preempt a higher priority one. By extension, this means that a
  97. lower priority dispatcher cannot preempt a higher-priority one. Priority
  98. activation and deactivation for non-interrupt exceptions, however, has to be
  99. explicit. The |EHF| therefore disallows for lower priority level to be activated
  100. whilst a higher priority level is active, and would result in a panic.
  101. Likewise, a panic would result if it's attempted to deactivate a lower priority
  102. level when a higher priority level is active.
  103. In essence, priority level activation and deactivation conceptually works like a
  104. stack—priority levels stack up in strictly increasing fashion, and need to be
  105. unstacked in strictly the reverse order. For interrupts, the GIC ensures this is
  106. the case; for non-interrupts, the |EHF| monitors and asserts this. See
  107. `Transition of priority levels`_.
  108. .. _interrupt-handling:
  109. Interrupt handling
  110. ------------------
  111. The |EHF| is a client of *Interrupt Management Framework*, and registers the
  112. top-level handler for interrupts that target EL3, as described in the
  113. :ref:`Interrupt Management Framework` document. This has the following
  114. implications:
  115. - On GICv3 systems, when executing in S-EL1, pending Non-secure interrupts of
  116. sufficient priority are signalled as FIQs, and therefore will be routed to
  117. EL3. As a result, S-EL1 software cannot expect to handle Non-secure
  118. interrupts at S-EL1. Essentially, this deprecates the routing mode described
  119. as :ref:`CSS=0, TEL3=0 <EL3 interrupts>`.
  120. In order for S-EL1 software to handle Non-secure interrupts while having
  121. |EHF| enabled, the dispatcher must adopt a model where Non-secure interrupts
  122. are received at EL3, but are then :ref:`synchronously <sp-synchronous-int>`
  123. handled over to S-EL1.
  124. - On GICv2 systems, it's required that the build option ``GICV2_G0_FOR_EL3`` is
  125. set to ``1`` so that *Group 0* interrupts target EL3.
  126. - While executing in Secure world, |EHF| sets GIC Priority Mask Register to the
  127. lowest Secure priority. This means that no Non-secure interrupts can preempt
  128. Secure execution. See `Effect on SMC calls`_ for more details.
  129. As mentioned above, with |EHF|, the platform is required to partition *Group 0*
  130. interrupts into distinct priority levels. A dispatcher that chooses to receive
  131. interrupts can then *own* one or more priority levels, and register interrupt
  132. handlers for them. A given priority level can be assigned to only one handler. A
  133. dispatcher may register more than one priority level.
  134. Dispatchers are assigned interrupt priority levels in two steps:
  135. .. _Partitioning priority levels:
  136. Partitioning priority levels
  137. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  138. Interrupts are associated to dispatchers by way of grouping and assigning
  139. interrupts to a priority level. In other words, all interrupts that are to
  140. target a particular dispatcher should fall in a particular priority level. For
  141. priority assignment:
  142. - Of the 8 bits of priority that Arm GIC architecture permits, bit 7 must be 0
  143. (secure space).
  144. - Depending on the number of dispatchers to support, the platform must choose
  145. to use the top *n* of the 7 remaining bits to identify and assign interrupts
  146. to individual dispatchers. Choosing *n* bits supports up to 2\ :sup:`n`
  147. distinct dispatchers. For example, by choosing 2 additional bits (i.e., bits
  148. 6 and 5), the platform can partition into 4 secure priority ranges: ``0x0``,
  149. ``0x20``, ``0x40``, and ``0x60``. See `Interrupt handling example`_.
  150. .. note::
  151. The Arm GIC architecture requires that a GIC implementation that supports two
  152. security states must implement at least 32 priority levels; i.e., at least 5
  153. upper bits of the 8 bits are writeable. In the scheme described above, when
  154. choosing *n* bits for priority range assignment, the platform must ensure
  155. that at least ``n+1`` top bits of GIC priority are writeable.
  156. The priority thus assigned to an interrupt is also used to determine the
  157. priority of delegated execution in lower ELs. Delegated execution in lower EL is
  158. associated with a priority level chosen with ``ehf_activate_priority()`` API
  159. (described `later`__). The chosen priority level also determines the interrupts
  160. masked while executing in a lower EL, therefore controls preemption of delegated
  161. execution.
  162. .. __: `ehf-apis`_
  163. The platform expresses the chosen priority levels by declaring an array of
  164. priority level descriptors. Each entry in the array is of type
  165. ``ehf_pri_desc_t``, and declares a priority level, and shall be populated by the
  166. ``EHF_PRI_DESC()`` macro.
  167. .. warning::
  168. The macro ``EHF_PRI_DESC()`` installs the descriptors in the array at a
  169. computed index, and not necessarily where the macro is placed in the array.
  170. The size of the array might therefore be larger than what it appears to be.
  171. The ``ARRAY_SIZE()`` macro therefore should be used to determine the size of
  172. array.
  173. Finally, this array of descriptors is exposed to |EHF| via the
  174. ``EHF_REGISTER_PRIORITIES()`` macro.
  175. Refer to the `Interrupt handling example`_ for usage. See also: `Interrupt
  176. Prioritisation Considerations`_.
  177. Programming priority
  178. ~~~~~~~~~~~~~~~~~~~~
  179. The text in `Partitioning priority levels`_ only describes how the platform
  180. expresses the required levels of priority. It however doesn't choose interrupts
  181. nor program the required priority in GIC.
  182. The :ref:`Firmware Design guide<configuring-secure-interrupts>` explains methods
  183. for configuring secure interrupts. |EHF| requires the platform to enumerate
  184. interrupt properties (as opposed to just numbers) of Secure interrupts. The
  185. priority of secure interrupts must match that as determined in the
  186. `Partitioning priority levels`_ section above.
  187. See `Limitations`_, and also refer to `Interrupt handling example`_ for
  188. illustration.
  189. Registering handler
  190. -------------------
  191. Dispatchers register handlers for their priority levels through the following
  192. API:
  193. .. code:: c
  194. int ehf_register_priority_handler(int pri, ehf_handler_t handler)
  195. The API takes two arguments:
  196. - The priority level for which the handler is being registered;
  197. - The handler to be registered. The handler must be aligned to 4 bytes.
  198. If a dispatcher owns more than one priority levels, it has to call the API for
  199. each of them.
  200. The API will succeed, and return ``0``, only if:
  201. - There exists a descriptor with the priority level requested.
  202. - There are no handlers already registered by a previous call to the API.
  203. Otherwise, the API returns ``-1``.
  204. The interrupt handler should have the following signature:
  205. .. code:: c
  206. typedef int (*ehf_handler_t)(uint32_t intr_raw, uint32_t flags, void *handle,
  207. void *cookie);
  208. The parameters are as obtained from the top-level :ref:`EL3 interrupt handler
  209. <el3-runtime-firmware>`.
  210. The :ref:`SDEI dispatcher<SDEI: Software Delegated Exception Interface>`, for
  211. example, expects the platform to allocate two different priority levels—
  212. ``PLAT_SDEI_CRITICAL_PRI``, and ``PLAT_SDEI_NORMAL_PRI`` —and registers the
  213. same handler to handle both levels.
  214. Interrupt handling example
  215. --------------------------
  216. The following annotated snippet demonstrates how a platform might choose to
  217. assign interrupts to fictitious dispatchers:
  218. .. code:: c
  219. #include <common/interrupt_props.h>
  220. #include <drivers/arm/gic_common.h>
  221. #include <exception_mgmt.h>
  222. ...
  223. /*
  224. * This platform uses 2 bits for interrupt association. In total, 3 upper
  225. * bits are in use.
  226. *
  227. * 7 6 5 3 0
  228. * .-.-.-.----------.
  229. * |0|b|b| ..0.. |
  230. * '-'-'-'----------'
  231. */
  232. #define PLAT_PRI_BITS 2
  233. /* Priorities for individual dispatchers */
  234. #define DISP0_PRIO 0x00 /* Not used */
  235. #define DISP1_PRIO 0x20
  236. #define DISP2_PRIO 0x40
  237. #define DISP3_PRIO 0x60
  238. /* Install priority level descriptors for each dispatcher */
  239. ehf_pri_desc_t plat_exceptions[] = {
  240. EHF_PRI_DESC(PLAT_PRI_BITS, DISP1_PRIO),
  241. EHF_PRI_DESC(PLAT_PRI_BITS, DISP2_PRIO),
  242. EHF_PRI_DESC(PLAT_PRI_BITS, DISP3_PRIO),
  243. };
  244. /* Expose priority descriptors to Exception Handling Framework */
  245. EHF_REGISTER_PRIORITIES(plat_exceptions, ARRAY_SIZE(plat_exceptions),
  246. PLAT_PRI_BITS);
  247. ...
  248. /* List interrupt properties for GIC driver. All interrupts target EL3 */
  249. const interrupt_prop_t plat_interrupts[] = {
  250. /* Dispatcher 1 owns interrupts d1_0 and d1_1, so assigns priority DISP1_PRIO */
  251. INTR_PROP_DESC(d1_0, DISP1_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL),
  252. INTR_PROP_DESC(d1_1, DISP1_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL),
  253. /* Dispatcher 2 owns interrupts d2_0 and d2_1, so assigns priority DISP2_PRIO */
  254. INTR_PROP_DESC(d2_0, DISP2_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL),
  255. INTR_PROP_DESC(d2_1, DISP2_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL),
  256. /* Dispatcher 3 owns interrupts d3_0 and d3_1, so assigns priority DISP3_PRIO */
  257. INTR_PROP_DESC(d3_0, DISP3_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL),
  258. INTR_PROP_DESC(d3_1, DISP3_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL),
  259. };
  260. ...
  261. /* Dispatcher 1 registers its handler */
  262. ehf_register_priority_handler(DISP1_PRIO, disp1_handler);
  263. /* Dispatcher 2 registers its handler */
  264. ehf_register_priority_handler(DISP2_PRIO, disp2_handler);
  265. /* Dispatcher 3 registers its handler */
  266. ehf_register_priority_handler(DISP3_PRIO, disp3_handler);
  267. ...
  268. See also the `Build-time flow`_ and the `Run-time flow`_.
  269. .. _Activating and Deactivating priorities:
  270. Activating and Deactivating priorities
  271. --------------------------------------
  272. A priority level is said to be *active* when an exception of that priority is
  273. being handled: for interrupts, this is implied when the interrupt is
  274. acknowledged; for non-interrupt exceptions, such as SErrors or :ref:`SDEI
  275. explicit dispatches <explicit-dispatch-of-events>`, this has to be done via
  276. calling ``ehf_activate_priority()``. See `Run-time flow`_.
  277. Conversely, when the dispatcher has reached a logical resolution for the cause
  278. of the exception, the corresponding priority level ought to be deactivated. As
  279. above, for interrupts, this is implied when the interrupt is EOId in the GIC;
  280. for other exceptions, this has to be done via calling
  281. ``ehf_deactivate_priority()``.
  282. Thanks to `different provisions`__ for exception delegation, there are
  283. potentially more than one work flow for deactivation:
  284. .. __: `delegation-use-cases`_
  285. .. _deactivation workflows:
  286. - The dispatcher has addressed the cause of the exception, and decided to take
  287. no further action. In this case, the dispatcher's handler deactivates the
  288. priority level before returning to the |EHF|. Runtime firmware, upon exit
  289. through an ``ERET``, resumes execution before the interrupt occurred.
  290. - The dispatcher has to delegate the execution to lower ELs, and the cause of
  291. the exception can be considered resolved only when the lower EL returns
  292. signals complete (via an ``SMC``) at a future point in time. The following
  293. sequence ensues:
  294. #. The dispatcher calls ``setjmp()`` to setup a jump point, and arranges to
  295. enter a lower EL upon the next ``ERET``.
  296. #. Through the ensuing ``ERET`` from runtime firmware, execution is delegated
  297. to a lower EL.
  298. #. The lower EL completes its execution, and signals completion via an
  299. ``SMC``.
  300. #. The ``SMC`` is handled by the same dispatcher that handled the exception
  301. previously. Noticing the conclusion of exception handling, the dispatcher
  302. does ``longjmp()`` to resume beyond the previous jump point.
  303. As mentioned above, the |EHF| provides the following APIs for activating and
  304. deactivating interrupt:
  305. .. _ehf-apis:
  306. - ``ehf_activate_priority()`` activates the supplied priority level, but only
  307. if the current active priority is higher than the given one; otherwise
  308. panics. Also, to prevent interruption by physical interrupts of lower
  309. priority, the |EHF| programs the *Priority Mask Register* corresponding to
  310. the PE to the priority being activated. Dispatchers typically only need to
  311. call this when handling exceptions other than interrupts, and it needs to
  312. delegate execution to a lower EL at a desired priority level.
  313. - ``ehf_deactivate_priority()`` deactivates a given priority, but only if the
  314. current active priority is equal to the given one; otherwise panics. |EHF|
  315. also restores the *Priority Mask Register* corresponding to the PE to the
  316. priority before the call to ``ehf_activate_priority()``. Dispatchers
  317. typically only need to call this after handling exceptions other than
  318. interrupts.
  319. The calling of APIs are subject to allowed `transitions`__. See also the
  320. `Run-time flow`_.
  321. .. __: `Transition of priority levels`_
  322. Transition of priority levels
  323. -----------------------------
  324. The |EHF| APIs ``ehf_activate_priority()`` and ``ehf_deactivate_priority()`` can
  325. be called to transition the current priority level on a PE. A given sequence of
  326. calls to these APIs are subject to the following conditions:
  327. - For activation, the |EHF| only allows for the priority to increase (i.e.
  328. numeric value decreases);
  329. - For deactivation, the |EHF| only allows for the priority to decrease (i.e.
  330. numeric value increases). Additionally, the priority being deactivated is
  331. required to be the current priority.
  332. If these are violated, a panic will result.
  333. .. _Effect on SMC calls:
  334. Effect on SMC calls
  335. -------------------
  336. In general, Secure execution is regarded as more important than Non-secure
  337. execution. As discussed elsewhere in this document, EL3 execution, and any
  338. delegated execution thereafter, has the effect of raising GIC's priority
  339. mask—either implicitly by acknowledging Secure interrupts, or when dispatchers
  340. call ``ehf_activate_priority()``. As a result, Non-secure interrupts cannot
  341. preempt any Secure execution.
  342. SMCs from Non-secure world are synchronous exceptions, and are mechanisms for
  343. Non-secure world to request Secure services. They're broadly classified as
  344. *Fast* or *Yielding* (see `SMCCC`__).
  345. .. __: https://developer.arm.com/docs/den0028/latest
  346. - *Fast* SMCs are atomic from the caller's point of view. I.e., they return
  347. to the caller only when the Secure world has finished serving the request.
  348. Any Non-secure interrupts that become pending meanwhile cannot preempt Secure
  349. execution.
  350. - *Yielding* SMCs carry the semantics of a preemptible, lower-priority request.
  351. A pending Non-secure interrupt can preempt Secure execution handling a
  352. Yielding SMC. I.e., the caller might observe a Yielding SMC returning when
  353. either:
  354. #. Secure world completes the request, and the caller would find ``SMC_OK``
  355. as the return code.
  356. #. A Non-secure interrupt preempts Secure execution. Non-secure interrupt is
  357. handled, and Non-secure execution resumes after ``SMC`` instruction.
  358. The dispatcher handling a Yielding SMC must provide a different return code
  359. to the Non-secure caller to distinguish the latter case. This return code,
  360. however, is not standardised (unlike ``SMC_UNKNOWN`` or ``SMC_OK``, for
  361. example), so will vary across dispatchers that handle the request.
  362. For the latter case above, dispatchers before |EHF| expect Non-secure interrupts
  363. to be taken to S-EL1 [#irq]_, so would get a chance to populate the designated
  364. preempted error code before yielding to Non-secure world.
  365. The introduction of |EHF| changes the behaviour as described in `Interrupt
  366. handling`_.
  367. When |EHF| is enabled, in order to allow Non-secure interrupts to preempt
  368. Yielding SMC handling, the dispatcher must call ``ehf_allow_ns_preemption()``
  369. API. The API takes one argument, the error code to be returned to the Non-secure
  370. world upon getting preempted.
  371. .. [#irq] In case of GICv2, Non-secure interrupts while in S-EL1 were signalled
  372. as IRQs, and in case of GICv3, FIQs.
  373. Build-time flow
  374. ---------------
  375. Please refer to the `figure`__ above.
  376. .. __: `ehf-figure`_
  377. The build-time flow involves the following steps:
  378. #. Platform assigns priorities by installing priority level descriptors for
  379. individual dispatchers, as described in `Partitioning priority levels`_.
  380. #. Platform provides interrupt properties to GIC driver, as described in
  381. `Programming priority`_.
  382. #. Dispatcher calling ``ehf_register_priority_handler()`` to register an
  383. interrupt handler.
  384. Also refer to the `Interrupt handling example`_.
  385. Run-time flow
  386. -------------
  387. .. _interrupt-flow:
  388. The following is an example flow for interrupts:
  389. #. The GIC driver, during initialization, iterates through the platform-supplied
  390. interrupt properties (see `Programming priority`_), and configures the
  391. interrupts. This programs the appropriate priority and group (Group 0) on
  392. interrupts belonging to different dispatchers.
  393. #. The |EHF|, during its initialisation, registers a top-level interrupt handler
  394. with the :ref:`Interrupt Management Framework<el3-runtime-firmware>` for EL3
  395. interrupts. This also results in setting the routing bits in ``SCR_EL3``.
  396. #. When an interrupt belonging to a dispatcher fires, GIC raises an EL3/Group 0
  397. interrupt, and is taken to EL3.
  398. #. The top-level EL3 interrupt handler executes. The handler acknowledges the
  399. interrupt, reads its *Running Priority*, and from that, determines the
  400. dispatcher handler.
  401. #. The |EHF| programs the *Priority Mask Register* of the PE to the priority of
  402. the interrupt received.
  403. #. The |EHF| marks that priority level *active*, and jumps to the dispatcher
  404. handler.
  405. #. Once the dispatcher handler finishes its job, it has to immediately
  406. *deactivate* the priority level before returning to the |EHF|. See
  407. `deactivation workflows`_.
  408. .. _non-interrupt-flow:
  409. The following is an example flow for exceptions that targets EL3 other than
  410. interrupt:
  411. #. The platform provides handlers for the specific kind of exception.
  412. #. The exception arrives, and the corresponding handler is executed.
  413. #. The handler calls ``ehf_activate_priority()`` to activate the required
  414. priority level. This also has the effect of raising GIC priority mask, thus
  415. preventing interrupts of lower priority from preempting the handling. The
  416. handler may choose to do the handling entirely in EL3 or delegate to a lower
  417. EL.
  418. #. Once exception handling concludes, the handler calls
  419. ``ehf_deactivate_priority()`` to deactivate the priority level activated
  420. earlier. This also has the effect of lowering GIC priority mask to what it
  421. was before.
  422. Interrupt Prioritisation Considerations
  423. ---------------------------------------
  424. The GIC priority scheme, by design, prioritises Secure interrupts over Normal
  425. world ones. The platform further assigns relative priorities amongst Secure
  426. dispatchers through |EHF|.
  427. As mentioned in `Partitioning priority levels`_, interrupts targeting distinct
  428. dispatchers fall in distinct priority levels. Because they're routed via the
  429. GIC, interrupt delivery to the PE is subject to GIC prioritisation rules. In
  430. particular, when an interrupt is being handled by the PE (i.e., the interrupt is
  431. in *Active* state), only interrupts of higher priority are signalled to the PE,
  432. even if interrupts of same or lower priority are pending. This has the side
  433. effect of one dispatcher being starved of interrupts by virtue of another
  434. dispatcher handling its (higher priority) interrupts.
  435. The |EHF| doesn't enforce a particular prioritisation policy, but the platform
  436. should carefully consider the assignment of priorities to dispatchers integrated
  437. into runtime firmware. The platform should sensibly delineate priority to
  438. various dispatchers according to their nature. In particular, dispatchers of
  439. critical nature (RAS, for example) should be assigned higher priority than
  440. others (|SDEI|, for example); and within |SDEI|, Critical priority
  441. |SDEI| should be assigned higher priority than Normal ones.
  442. Limitations
  443. -----------
  444. The |EHF| has the following limitations:
  445. - Although there could be up to 128 Secure dispatchers supported by the GIC
  446. priority scheme, the size of descriptor array exposed with
  447. ``EHF_REGISTER_PRIORITIES()`` macro is currently limited to 32. This serves most
  448. expected use cases. This may be expanded in the future, should use cases
  449. demand so.
  450. - The platform must ensure that the priority assigned to the dispatcher in the
  451. exception descriptor and the programmed priority of interrupts handled by the
  452. dispatcher match. The |EHF| cannot verify that this has been followed.
  453. --------------
  454. *Copyright (c) 2018-2020, Arm Limited and Contributors. All rights reserved.*
  455. .. _SDEI specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf