1##################################
2Secure Interrupt Integration Guide
3##################################
4
5************
6Introduction
7************
8
9This document describes how to enable an interrupt in TF-M. The target audiences
10are mainly platform integrators and Secure Partition developers.
11
12This document assumes that you have read the PSA Firmware Framework (FF-M) v1.0
13[1]_ and the FF-M v1.1 extensions [2]_ thus have knowlege on the terminologies
14such as Secure Partitions and manifests.
15
16************************
17Interrupt Handling Model
18************************
19
20TF-M supports the two interrupt handling model defined by FF-M:
21
22- First-Level Interrupt Handling (FLIH)
23
24  In this model, the interrupt handling is carried out immediately when the
25  interrupt exception happens.
26
27  The interrupt handling can optionally set an interrupt signal for the Secure
28  Partition Thread to have further data processing.
29
30- Second-Level Interrupt Handling (SLIH)
31
32  In this model, the interrupt handling is deferred after the interrupt
33  exception. The handling occurs in the Secure Partition Thread thus is subject
34  to scheduling.
35
36The FLIH supports handling an interrupt in a bounded time, but very limited APIs
37are allowed in the FLIH handling because the handling occurs in an special
38exception context.
39
40The SLIH is deferred and subject to scheduling but all Secure Partition APIs are
41allowed as the SLIH handling is in the Secure Partition Thread.
42
43Both the FLIH and the SLIH can be used by Secure Partitions which conform to
44Firmware Framework v1.1.
45
46While the SLIH is the only supported model for Secure Partitions which conform
47to Firmware Framework v1.0.
48
49Please refer to chapter 6.2 of FF-M v1.1 [1]_ for more details on the interrupt
50handling models.
51
52*********************
53Enabling an Interrupt
54*********************
55
56To enable an interrupt, you need to do the following:
57
58- Binding the interrupt to a Secure Partition.
59- Granting the Secure Partition access permissions to the device of the
60  interrupt.
61- Initializing the interrupt.
62- Integrating the interrupt handling function
63
64TF-M has two Test Partitions as good examples for both FLIH [3]_ and SLIH [4]_.
65See also `Enabling the Interrupt Tests`_ on how to integrate them to platforms.
66
67Binding an Interrupt to a Secure Partition
68==========================================
69
70To bind an interrupt to a Secure Partition, you need to add an item to the
71``irqs`` attribute of the Secure Partition manifest.
72``irqs`` is a list of Interrupt Request (IRQ) assigned to the Secure Partition.
73
74Secure Partitions are not allowed to share IRQs with other Secure Partitions.
75
76Different Firmware Framework versions have different definitions of manifest.
77
78FF-M v1.0
79---------
80
81Here is an example manifest of Secure Partitions conform to Firmware Framework
82version 1.0:
83
84.. code-block:: yaml
85
86  {
87    "irqs": [
88      {
89        "source": 5,
90        "signal": "DUAL_TIMER_SIGNAL"
91      },
92      {
93        "source": "TIMER_1_SOURCE",
94        "signal": "TIMER_1_SIGNAL"
95      }
96    ]
97  }
98
99- source
100
101  Required, Unique.
102
103  The ``source`` is a string that identifies the interrupt source.
104  It can be a valid exception number or a symbolic name defined in platform codes.
105
106- signal
107
108  Required, Unique.
109
110  The ``signal`` attribute is a symbolic name used by TF-M to identify which
111  interrupt is asserted.
112  It is also used by the Secure Partition to receive the interrupt signal by
113  calling ``psa_wait`` for interrupt handling.
114
115  It is defined in the Secure Partition header file
116  ``<psa_manifest/manifestfilename.h>`` generated by TF-M:
117
118  .. code-block:: c
119
120    #define signal VALUE
121
122The interrupt handling model is SLIH by default as it is the only supported one
123for FF-M v1.0.
124
125FF-M v1.1
126---------
127
128Here is an example manifest of Secure Partitions conform to Firmware Framework
129version 1.1:
130
131.. code-block:: yaml
132
133  {
134    "irqs": [
135      {
136        "source"  : "TIMER_1_SOURCE",
137        "name"    : "TIMER_1",
138        "handling": "FLIH"
139      },
140      {
141        "source"  : 5,
142        "name"    : "DUAL_TIMER",
143        "handling": "SLIH"
144      }
145    ]
146  }
147
148- source
149
150  The ``source`` is the same as the one in Firmware Framework Version 1.0.
151
152- name
153
154  Required, Unique.
155
156  The ``name`` is used to construct the following two elements:
157
158  - the interrupt signal symbol: ``{{name}}_SIGNAL``, the equivalent of
159    ``signal`` in FF-M v1.0
160  - the FLIH Function for handling ``FLIH`` IRQs provided by Secure Partition:
161
162    ``psa_flih_result_t {{name}}_flih(void);``
163
164    It is also declared in ``<psa_manifest/manifestfilename.h>``.
165
166- handling
167
168  Required.
169
170  The ``handling`` attribute specifies the interrupt handling model and must
171  have one of the following values:
172
173  - ``FLIH`` - First-Level Interrupt Handling
174  - ``SLIH`` - Second-Level Interrupt Handling
175
176Granting Permissions to Devices for Secure Partitions
177=====================================================
178
179A secure partition shall be granted two parts of permissions to access a device.
180One is the Memory Maped I/O (MMIO) region of the device. The other is the driver
181codes to access the device.
182
183The MMIO Regions
184----------------
185
186You need to declare the MMIO region in the ``mmio_regions`` attributes in the
187Secure Partition manifest, to enable the Secure Partition to access it.
188
189An MMIO region can be described as either ``numbered_region`` or
190``named_region``.
191A numbered region consists of a ``base`` address and a ``size``.
192A named region consists of a string ``name`` to describe the region.
193
194Here is an example of named region:
195
196.. code-block:: yaml
197
198  {
199    "mmio_regions": [
200      {
201        "name": "TFM_PERIPHERAL_TIMER0",
202        "permission": "READ-WRITE"
203      }
204    ]
205  }
206
207- name
208
209  Required.
210
211  The ``name`` attribute is a symbolic name defined by platforms.
212  It is a pointer to structure instance that usually includes the base address
213  and size of the region and some other platform specific attributes that are
214  required to set up permissions to the MMIO region.
215
216  The structure is defined by platforms and the name must be
217  ``struct platform_data_t``.
218
219- permission
220
221  Required.
222
223  The ``permission`` attribute must have one of the following values:
224
225  - ``READ-ONLY``
226  - ``READ-WRITE``
227
228The Device Drivers
229------------------
230
231To give permissions of devices drivers to Secure Partitions, it is recommended
232to put the driver codes to the Partition's CMake library:
233
234.. code-block:: bash
235
236  target_sources(some_partition_lib
237      PRIVATE
238          some_driver_code.c
239  )
240
241Initializing the Interrupts
242===========================
243
244Platforms must define an interrupt initialization function for each Secure
245interrupt.
246
247The prototype of the function is:
248
249.. code-block:: c
250
251  enum tfm_hal_status_t {source_symbol}_init(void *p_pt,
252                                             const struct irq_load_info_t *p_ildi)
253
254The ``{source_symbol}`` is:
255
256- ``irq_{source}``, if the ``source`` attribute of the IRQ in Partition manifest
257  is a number
258- Lowercase of ``source`` attribute, if ``source`` is a symbolic name
259
260For example if the manifest declares ``"source": 5``, then the function name
261is ``irq_5_init``.
262If the mannifest declares ``"source"  : "TIMER_1_IRQ"`` then the function
263name is ``timer_1_irq_init``.
264
265The function will be called by the Framework automatically during
266initialization. The function can be put in any source file that belongs to SPM,
267for example a ``tfm_interrupts.c`` added to the ``tfm_spm`` CMake target.
268
269The initialization of an interrupt must include:
270
271- setting the priority
272- ensuring that the interrupt targets the Secure State.
273- saving the interrupt information
274
275Setting Priority
276----------------
277
278The priority of external interrupts must be in the following range:
279``(0, N / 2)``, where ``N`` is the number of configurable priorities.
280Smaller values have higher priorities.
281
282For example if the number of configurable priority of your interrupt controller
283is 16, you must use the priorities in range ``(0, 8)`` only, boundaries
284excluded.
285
286Note that these are not the values set into the interrupt controllers.
287Different platforms may have different values for those priorities.
288But if you use the ``NVIC_SetPriority`` function provided by CMSIS to set
289priorities, you can pass the values directly.
290
291Platforms have the flexibilities on the assignment of priorities.
292
293Targeting Interrupts to Secure
294------------------------------
295
296In single core systems, platform integrators must ensure that the Secure
297interrupts target to Secure State by setting the Interrupt Controller.
298
299In multi-core systems, this might be optional.
300
301Saving the Interrupt Information
302--------------------------------
303
304The initialization function is called during Partition loading with the
305following information:
306
307- ``p_pt`` - pointer to Partition runtime struct of the owner Partition
308- ``p_ildi`` - pointer to ``irq_load_info_t`` struct of the interrupt
309
310Platforms must save the information for the future use.
311See `Integrating the Interrupt Handling Function`_ for the usage.
312
313The easiest way is to save them in global variables for each interrupt.
314TF-M provides a struct for saving the information:
315
316.. code-block:: c
317
318  struct irq_t {
319      void                         *p_pt;
320      const struct irq_load_info_t *p_ildi;
321  };
322
323Integrating the Interrupt Handling Function
324===========================================
325
326TF-M provides an interrupt handling entry for Secure interrupts:
327
328.. code-block:: c
329
330  void spm_handle_interrupt(void *p_pt, const struct irq_load_info_t *p_ildi)
331
332The ``p_pt`` and ``p_ildi`` are the information passed to interrupt
333initialization functions and saved by platforms.
334
335Platforms should call this entry function in the interrupt handlers held in
336Vector Table with the information saved by the interrupt initialization
337functions.
338If the information is saved as global variables, then the interrupt handlers can
339be put in the same source file that contains the initialization functions.
340
341Here is an example:
342
343.. code-block:: c
344
345  void TFM_TIMER0_IRQ_Handler(void) /* The handler in Vector Table */
346  {
347      spm_handle_interrupt(p_timer0_pt, p_tfm_timer0_irq_ldinf);
348  }
349
350****************************
351Enabling the Interrupt Tests
352****************************
353
354TF-M provides test suites for FLIH and SLIH interrupts respectively.
355They are disabled by default.
356
357.. note::
358
359  FLIH interrupt test and SLIH interrupt test share the same timer
360  ``TFM_TIMER0_IRQ`` thus cannot be enabled at the same time.
361
362To enable the tests, please follow steps in the previous sections.
363In addition, you need to implement the following APIs of timer control:
364
365- ``void tfm_plat_test_secure_timer_start(void)``
366- ``void tfm_plat_test_secure_timer_clear_intr(void)``
367- ``void tfm_plat_test_secure_timer_stop(void)``
368
369You shall also select the following flags in platform specific ``config.cmake``
370to indicate that FLIH and SLIH interrupt tests are supported respectively.
371
372- ``PLATFORM_FLIH_IRQ_TEST_SUPPORT``: platform implements support of FLIH
373  interrupt tests
374- ``PLATFORM_SLIH_IRQ_TEST_SUPPORT``: platform implements support of SLIH
375  interrupt tests
376
377The following configurations control SLIH and FLIH interrupt tests:
378
379- ``TEST_NS_FLIH_IRQ``
380- ``TEST_NS_SLIH_IRQ``
381
382They can be enabled via build command line or via ``TEST_NS``.
383
384************************************
385Migrating to Firmware Framework v1.1
386************************************
387
388Please refer to ``Migrating Secure Partitions to version 1.1`` of FF-M v1.1 [1]_
389.
390
391**********
392References
393**********
394
395.. [1] `FF-M v1.0 Specification <https://developer.arm.com/-/media/Files/pdf/PlatformSecurityArchitecture/Architect/DEN0063-PSA_Firmware_Framework-1.0.0-2.pdf?revision=2d1429fa-4b5b-461a-a60e-4ef3d8f7f4b4>`__
396
397.. [2] `FF-M v1.1 Extention <https://documentation-service.arm.com/static/600067c09b9c2d1bb22cd1c5?token=>`__
398
399.. [3] https://git.trustedfirmware.org/TF-M/tf-m-tests.git/tree/test/secure_fw/suites/spm/irq/service/tfm_flih_test_service
400
401.. [4] https://git.trustedfirmware.org/TF-M/tf-m-tests.git/tree/test/secure_fw/suites/spm/irq/service/tfm_slih_test_service
402
403--------------
404
405*Copyright (c) 2021-2022, Arm Limited. All rights reserved.*
406*Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company)
407or an affiliate of Cypress Semiconductor Corporation. All rights reserved.*
408