1.. _interrupts_v2:
2
3Interrupts
4##########
5
6An :dfn:`interrupt service routine` (ISR) is a function that executes
7asynchronously in response to a hardware or software interrupt.
8An ISR normally preempts the execution of the current thread,
9allowing the response to occur with very low overhead.
10Thread execution resumes only once all ISR work has been completed.
11
12.. contents::
13    :local:
14    :depth: 2
15
16Concepts
17********
18
19Any number of ISRs can be defined (limited only by available RAM), subject to
20the constraints imposed by underlying hardware.
21
22An ISR has the following key properties:
23
24* An **interrupt request (IRQ) signal** that triggers the ISR.
25* A **priority level** associated with the IRQ.
26* An **interrupt service routine** that is invoked to handle the interrupt.
27* An **argument value** that is passed to that function.
28
29An :abbr:`IDT (Interrupt Descriptor Table)` or a vector table is used
30to associate a given interrupt source with a given ISR.
31Only a single ISR can be associated with a specific IRQ at any given time.
32
33Multiple ISRs can utilize the same function to process interrupts,
34allowing a single function to service a device that generates
35multiple types of interrupts or to service multiple devices
36(usually of the same type). The argument value passed to an ISR's function
37allows the function to determine which interrupt has been signaled.
38
39The kernel provides a default ISR for all unused IDT entries. This ISR
40generates a fatal system error if an unexpected interrupt is signaled.
41
42The kernel supports **interrupt nesting**. This allows an ISR to be preempted
43in mid-execution if a higher priority interrupt is signaled. The lower
44priority ISR resumes execution once the higher priority ISR has completed
45its processing.
46
47An ISR executes in the kernel's **interrupt context**. This context has its
48own dedicated stack area (or, on some architectures, stack areas). The size
49of the interrupt context stack must be capable of handling the execution of
50multiple concurrent ISRs if interrupt
51nesting support is enabled.
52
53.. important::
54    Many kernel APIs can be used only by threads, and not by ISRs. In cases
55    where a routine may be invoked by both threads and ISRs the kernel
56    provides the :c:func:`k_is_in_isr` API to allow the routine to
57    alter its behavior depending on whether it is executing as part of
58    a thread or as part of an ISR.
59
60.. _multi_level_interrupts:
61
62Multi-level Interrupt Handling
63==============================
64
65A hardware platform can support more interrupt lines than natively-provided
66through the use of one or more nested interrupt controllers.  Sources of
67hardware interrupts are combined into one line that is then routed to
68the parent controller.
69
70If nested interrupt controllers are supported, :kconfig:option:`CONFIG_MULTI_LEVEL_INTERRUPTS`
71should be enabled, and :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPTS` and
72:kconfig:option:`CONFIG_3RD_LEVEL_INTERRUPTS` configured as well, based on the
73hardware architecture.
74
75A unique 32-bit interrupt number is assigned with information
76embedded in it to select and invoke the correct Interrupt
77Service Routine (ISR). Each interrupt level is given a byte within this 32-bit
78number, providing support for up to four interrupt levels using this arch, as
79illustrated and explained below:
80
81.. code-block:: none
82
83                 9             2   0
84           _ _ _ _ _ _ _ _ _ _ _ _ _         (LEVEL 1)
85         5       |         A   |
86       _ _ _ _ _ _ _         _ _ _ _ _ _ _   (LEVEL 2)
87         |   C                       B
88       _ _ _ _ _ _ _                         (LEVEL 3)
89               D
90
91There are three interrupt levels shown here.
92
93* '-' means interrupt line and is numbered from 0 (right most).
94* LEVEL 1 has 12 interrupt lines, with two lines (2 and 9) connected
95  to nested controllers and one device 'A' on line 4.
96* One of the LEVEL 2 controllers has interrupt line 5 connected to
97  a LEVEL 3 nested controller and one device 'C' on line 3.
98* The other LEVEL 2 controller has no nested controllers but has one
99  device 'B' on line 2.
100* The LEVEL 3 controller has one device 'D' on line 2.
101
102Here's how unique interrupt numbers are generated for each
103hardware interrupt.  Let's consider four interrupts shown above
104as A, B, C, and D:
105
106.. code-block:: none
107
108   A -> 0x00000004
109   B -> 0x00000302
110   C -> 0x00000409
111   D -> 0x00030609
112
113.. note::
114   The bit positions for LEVEL 2 and onward are offset by 1, as 0 means that
115   interrupt number is not present for that level. For our example, the LEVEL 3
116   controller has device D on line 2, connected to the LEVEL 2 controller's line
117   5, that is connected to the LEVEL 1 controller's line 9 (2 -> 5 -> 9).
118   Because of the encoding offset for LEVEL 2 and onward, device D is given the
119   number 0x00030609.
120
121Preventing Interruptions
122========================
123
124In certain situations it may be necessary for the current thread to
125prevent ISRs from executing while it is performing time-sensitive
126or critical section operations.
127
128A thread may temporarily prevent all IRQ handling in the system using
129an **IRQ lock**. This lock can be applied even when it is already in effect,
130so routines can use it without having to know if it is already in effect.
131The thread must unlock its IRQ lock the same number of times it was locked
132before interrupts can be once again processed by the kernel while the thread
133is running.
134
135.. important::
136    The IRQ lock is thread-specific. If thread A locks out interrupts
137    then performs an operation that puts itself to sleep (e.g. sleeping
138    for N milliseconds), the thread's IRQ lock no longer applies once
139    thread A is swapped out and the next ready thread B starts to
140    run.
141
142    This means that interrupts can be processed while thread B is
143    running unless thread B has also locked out interrupts using its own
144    IRQ lock.  (Whether interrupts can be processed while the kernel is
145    switching between two threads that are using the IRQ lock is
146    architecture-specific.)
147
148    When thread A eventually becomes the current thread once again, the kernel
149    re-establishes thread A's IRQ lock. This ensures thread A won't be
150    interrupted until it has explicitly unlocked its IRQ lock.
151
152    If thread A does not sleep but does make a higher-priority thread B
153    ready, the IRQ lock will inhibit any preemption that would otherwise
154    occur.  Thread B will not run until the next :ref:`reschedule point
155    <scheduling_v2>` reached after releasing the IRQ lock.
156
157Alternatively, a thread may temporarily **disable** a specified IRQ
158so its associated ISR does not execute when the IRQ is signaled.
159The IRQ must be subsequently **enabled** to permit the ISR to execute.
160
161.. important::
162    Disabling an IRQ prevents *all* threads in the system from being preempted
163    by the associated ISR, not just the thread that disabled the IRQ.
164
165.. _zlis:
166
167Zero Latency Interrupts
168-----------------------
169
170Preventing interruptions by applying an IRQ lock may increase the observed
171interrupt latency. A high interrupt latency, however, may not be acceptable
172for certain low-latency use-cases.
173
174The kernel addresses such use-cases by allowing interrupts with critical
175latency constraints to execute at a priority level that cannot be blocked
176by interrupt locking. These interrupts are defined as
177*zero-latency interrupts*. The support for zero-latency interrupts requires
178:kconfig:option:`CONFIG_ZERO_LATENCY_IRQS` to be enabled. Any interrupts
179configured as zero-latency must also be declared as :ref:`direct ISRs
180<direct_isrs>` (and must not use the :c:macro:`ISR_DIRECT_PM` in them), since
181regular ISRs interact with the kernel. In addition to that, the flag
182:c:macro:`IRQ_ZERO_LATENCY` must be passed to the :c:macro:`IRQ_DIRECT_CONNECT`
183macro to configure the particular interrupt with
184zero latency. Declaring a zero-latency interrupt ISR to be both direct and
185dynamic is possible on some architectures, see :ref:`direct_isrs`.
186
187Zero-latency interrupts are expected to be used to manage hardware events
188directly, and not to interoperate with the kernel code at all. They should
189treat all kernel APIs as undefined behavior (i.e. an application that uses the
190APIs inside a zero-latency interrupt context is responsible for directly
191verifying correct behavior). Zero-latency interrupts may not modify any data
192inspected by kernel APIs invoked from normal Zephyr contexts and shall not
193generate exceptions that need to be handled synchronously (e.g. kernel panic).
194
195.. important::
196    Zero-latency interrupts are supported on an architecture-specific basis.
197    The feature is currently implemented in the ARM Cortex-M architecture
198    variant.
199
200.. tip::
201    To mitigate flash access latency, consider relocating ISRs and all related
202    symbols to RAM.
203
204Offloading ISR Work
205===================
206
207An ISR should execute quickly to ensure predictable system operation.
208If time consuming processing is required the ISR should offload some or all
209processing to a thread, thereby restoring the kernel's ability to respond
210to other interrupts.
211
212The kernel supports several mechanisms for offloading interrupt-related
213processing to a thread.
214
215* An ISR can signal a helper thread to do interrupt-related processing
216  using a kernel object, such as a FIFO, LIFO, or semaphore.
217
218* An ISR can instruct the system workqueue thread to execute a work item.
219  (See :ref:`workqueues_v2`.)
220
221When an ISR offloads work to a thread, there is typically a single context
222switch to that thread when the ISR completes, allowing interrupt-related
223processing to continue almost immediately. However, depending on the
224priority of the thread handling the offload, it is possible that
225the currently executing cooperative thread or other higher-priority threads
226may execute before the thread handling the offload is scheduled.
227
228Sharing interrupt lines
229=======================
230
231In the case of some hardware platforms, the same interrupt lines may be used
232by different IPs. For example, interrupt 17 may be used by a DMA controller to
233signal that a data transfer has been completed or by a DAI controller to signal
234that the transfer FIFO has reached its watermark. To make this work, one would
235have to either employ some special logic or find a workaround (for example, using
236the shared_irq interrupt controller), which doesn't scale very well.
237
238To solve this problem, one may use shared interrupts, which can be enabled using
239:kconfig:option:`CONFIG_SHARED_INTERRUPTS`. Whenever an attempt to register
240a second ISR/argument pair on the same interrupt line is made (using
241:c:macro:`IRQ_CONNECT` or :c:func:`irq_connect_dynamic`), the interrupt line will
242become shared, meaning the two ISR/argument pairs (previous one and the one that
243has just been registered) will be invoked each time the interrupt is triggered.
244The entities that make use of an interrupt line in the shared interrupt context
245are known as clients. The maximum number of allowed clients for an interrupt is
246controlled by :kconfig:option:`CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS`.
247
248Interrupt sharing is transparent to the user. As such, the user may register
249interrupts using :c:macro:`IRQ_CONNECT` and :c:func:`irq_connect_dynamic` as
250they normally would. The interrupt sharing is taken care of behind the scenes.
251
252Enabling the shared interrupt support and dynamic interrupt support will
253allow users to dynamically disconnect ISRs using :c:func:`irq_disconnect_dynamic`.
254After an ISR is disconnected, whenever the interrupt line for which it was
255register gets triggered, the ISR will no longer get invoked.
256
257Please note that enabling :kconfig:option:`CONFIG_SHARED_INTERRUPTS` will
258result in a non-negligible increase in the binary size. Use with caution.
259
260Implementation
261**************
262
263Defining a regular ISR
264======================
265
266An ISR is defined at runtime by calling :c:macro:`IRQ_CONNECT`. It must
267then be enabled by calling :c:func:`irq_enable`.
268
269.. important::
270    IRQ_CONNECT() is not a C function and does some inline assembly magic
271    behind the scenes. All its arguments must be known at build time.
272    Drivers that have multiple instances may need to define per-instance
273    config functions to configure each instance of the interrupt.
274
275The following code defines and enables an ISR.
276
277.. code-block:: c
278
279    #define MY_DEV_IRQ  24       /* device uses IRQ 24 */
280    #define MY_DEV_PRIO  2       /* device uses interrupt priority 2 */
281    /* argument passed to my_isr(), in this case a pointer to the device */
282    #define MY_ISR_ARG  DEVICE_GET(my_device)
283    #define MY_IRQ_FLAGS 0       /* IRQ flags */
284
285    void my_isr(void *arg)
286    {
287       ... /* ISR code */
288    }
289
290    void my_isr_installer(void)
291    {
292       ...
293       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_PRIO, my_isr, MY_ISR_ARG, MY_IRQ_FLAGS);
294       irq_enable(MY_DEV_IRQ);
295       ...
296    }
297
298Since the :c:macro:`IRQ_CONNECT` macro requires that all its parameters be
299known at build time, in some cases this may not be acceptable. It is also
300possible to install interrupts at runtime with
301:c:func:`irq_connect_dynamic`. It is used in exactly the same way as
302:c:macro:`IRQ_CONNECT`:
303
304.. code-block:: c
305
306    void my_isr_installer(void)
307    {
308       ...
309       irq_connect_dynamic(MY_DEV_IRQ, MY_DEV_PRIO, my_isr, MY_ISR_ARG,
310                           MY_IRQ_FLAGS);
311       irq_enable(MY_DEV_IRQ);
312       ...
313    }
314
315Dynamic interrupts require the :kconfig:option:`CONFIG_DYNAMIC_INTERRUPTS` option to
316be enabled. Removing or re-configuring a dynamic interrupt is currently
317unsupported.
318
319.. _direct_isrs:
320
321Defining a 'direct' ISR
322=======================
323
324Regular Zephyr interrupts introduce some overhead which may be unacceptable
325for some low-latency use-cases. Specifically:
326
327* The argument to the ISR is retrieved and passed to the ISR
328
329* If power management is enabled and the system was idle, all the hardware
330  will be resumed from low-power state before the ISR is executed, which can be
331  very time-consuming
332
333* Although some architectures will do this in hardware, other architectures
334  need to switch to the interrupt stack in code
335
336* After the interrupt is serviced, the OS then performs some logic to
337  potentially make a scheduling decision
338
339* :ref:`zlis` must always be declared as direct ISRs, since regular
340  ISRs interact with the kernel
341
342Zephyr supports so-called 'direct' interrupts, which are installed via
343:c:macro:`IRQ_DIRECT_CONNECT` and whose handlers are declared using
344:c:macro:`ISR_DIRECT_DECLARE`. These direct interrupts have some special
345implementation requirements and a reduced feature set; see the definitions
346of :c:macro:`IRQ_DIRECT_CONNECT` and :c:macro:`ISR_DIRECT_DECLARE` for details.
347
348The following code demonstrates a direct ISR:
349
350.. code-block:: c
351
352    #define MY_DEV_IRQ  24       /* device uses IRQ 24 */
353    #define MY_DEV_PRIO  2       /* device uses interrupt priority 2 */
354    #define MY_IRQ_FLAGS 0       /* IRQ flags */
355
356    ISR_DIRECT_DECLARE(my_isr)
357    {
358       do_stuff();
359       /* PM done after servicing interrupt for best latency. This cannot be
360       used for zero-latency IRQs because it accesses kernel data. */
361       ISR_DIRECT_PM();
362       /* Ask the kernel to check if scheduling decision should be made. If the
363       ISR is for a zero-latency IRQ then the return value must always be 0. */
364       return 1;
365    }
366
367    void my_isr_installer(void)
368    {
369       ...
370       IRQ_DIRECT_CONNECT(MY_DEV_IRQ, MY_DEV_PRIO, my_isr, MY_IRQ_FLAGS);
371       irq_enable(MY_DEV_IRQ);
372       ...
373    }
374
375Installation of dynamic direct interrupts is supported on an
376architecture-specific basis. The feature is currently implemented in the Arm
377Cortex-M architecture variant via the macro
378:c:macro:`ARM_IRQ_DIRECT_DYNAMIC_CONNECT`, which can be used to declare a direct
379and dynamic interrupt.
380
381RAM-based ISR Execution
382=======================
383
384For ultra-low latency, ISRs and vector tables can be relocated to RAM to
385eliminate flash access delays. That can be achieved by enabling the
386:kconfig:option:`CONFIG_SRAM_VECTOR_TABLE` and
387:kconfig:option:`CONFIG_SRAM_SW_ISR_TABLE` options which will result in vector
388tables being placed in RAM.
389Then, Zephyr :ref:`Code and Data Relocation <code_data_relocation>` can be
390used to relocate the ISR code and all the related symbols to RAM as well.
391
392Sharing an interrupt line
393=========================
394
395The following code defines two ISRs using the same interrupt number.
396
397.. code-block:: c
398
399    #define MY_DEV_IRQ 24		/* device uses INTID 24 */
400    #define MY_DEV_IRQ_PRIO 2		/* device uses interrupt priority 2 */
401    /*  this argument may be anything */
402    #define MY_FST_ISR_ARG INT_TO_POINTER(1)
403    /*  this argument may be anything */
404    #define MY_SND_ISR_ARG INT_TO_POINTER(2)
405    #define MY_IRQ_FLAGS 0		/* IRQ flags */
406
407    void my_first_isr(void *arg)
408    {
409       ... /* some magic happens here */
410    }
411
412    void my_second_isr(void *arg)
413    {
414       ... /* even more magic happens here */
415    }
416
417    void my_isr_installer(void)
418    {
419       ...
420       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_first_isr, MY_FST_ISR_ARG, MY_IRQ_FLAGS);
421       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_second_isr, MY_SND_ISR_ARG, MY_IRQ_FLAGS);
422       ...
423    }
424
425The same restrictions regarding :c:macro:`IRQ_CONNECT` described in `Defining a regular ISR`_
426are applicable here. If :kconfig:option:`CONFIG_SHARED_INTERRUPTS` is disabled, the above
427code will generate a build error. Otherwise, the above code will result in the two ISRs
428being invoked each time interrupt 24 is triggered.
429
430If :kconfig:option:`CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS` is set to a value lower than 2
431(current number of clients), a build error will be generated.
432
433If dynamic interrupts are enabled, :c:func:`irq_connect_dynamic` will allow sharing interrupts
434during runtime. Exceeding the configured maximum number of allowed clients will result in
435a failed assertion.
436
437Dynamically disconnecting an ISR
438================================
439
440The following code defines two ISRs using the same interrupt number. The second
441ISR is disconnected during runtime.
442
443.. code-block:: c
444
445    #define MY_DEV_IRQ 24		/* device uses INTID 24 */
446    #define MY_DEV_IRQ_PRIO 2		/* device uses interrupt priority 2 */
447    /*  this argument may be anything */
448    #define MY_FST_ISR_ARG INT_TO_POINTER(1)
449    /*  this argument may be anything */
450    #define MY_SND_ISR_ARG INT_TO_POINTER(2)
451    #define MY_IRQ_FLAGS 0		/* IRQ flags */
452
453    void my_first_isr(void *arg)
454    {
455       ... /* some magic happens here */
456    }
457
458    void my_second_isr(void *arg)
459    {
460       ... /* even more magic happens here */
461    }
462
463    void my_isr_installer(void)
464    {
465       ...
466       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_first_isr, MY_FST_ISR_ARG, MY_IRQ_FLAGS);
467       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_second_isr, MY_SND_ISR_ARG, MY_IRQ_FLAGS);
468       ...
469    }
470
471    void my_isr_uninstaller(void)
472    {
473       ...
474       irq_disconnect_dynamic(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_first_isr, MY_FST_ISR_ARG, MY_IRQ_FLAGS);
475       ...
476    }
477
478The :c:func:`irq_disconnect_dynamic` call will result in interrupt 24 becoming
479unshared, meaning the system will act as if the first :c:macro:`IRQ_CONNECT`
480call never happened. This behaviour is only allowed if
481:kconfig:option:`CONFIG_DYNAMIC_INTERRUPTS` is enabled, otherwise a linker
482error will be generated.
483
484Implementation Details
485======================
486
487Interrupt tables are set up at build time using some special build tools.  The
488details laid out here apply to all architectures except x86, which are
489covered in the `x86 Details`_ section below.
490
491The invocation of :c:macro:`IRQ_CONNECT` will declare an instance of
492struct _isr_list which is placed in a special .intList section.
493This section is placed in compiled code on precompilation stages only.
494It is meant to be used by Zephyr script to generate interrupt tables
495and is removed from the final build.
496The script implements different parsers to process the data from .intList section
497and produce the required output.
498
499The default parser generates C arrays filled with arguments and interrupt
500handlers in a form of addresses directly taken from .intList section entries.
501It works with all the architectures and compilers (with the exception mentioned above).
502The limitation of this parser is the fact that after the arrays are generated
503it is expected for the code not to relocate.
504Any relocation on this stage may lead to the situation where the entry in the interrupt array
505is no longer pointing to the function that was expected.
506It means that this parser, being more compatible is limiting us from using Link Time Optimization.
507
508The local isr declaration parser uses different approach to construct
509the same arrays at binnary level.
510All the entries to the arrays are declared and defined locally,
511directly in the file where :c:macro:`IRQ_CONNECT` is used.
512They are placed in a section with the unique, synthesized name.
513The name of the section is then placed in .intList section and it is used to create linker script
514to properly place the created entry in the right place in the memory.
515This parser is now limited to the supported architectures and toolchains but in reward it keeps
516the information about object relations for linker thus allowing the Link Time Optimization.
517
518Implementation using C arrays
519-----------------------------
520
521This is the default configuration available for all Zephyr supported architectures.
522
523Any invocation of :c:macro:`IRQ_CONNECT` will declare an instance of
524struct _isr_list which is placed in a special .intList section:
525
526.. code-block:: c
527
528    struct _isr_list {
529        /** IRQ line number */
530        int32_t irq;
531        /** Flags for this IRQ, see ISR_FLAG_* definitions */
532        int32_t flags;
533        /** ISR to call */
534        void *func;
535        /** Parameter for non-direct IRQs */
536        void *param;
537    };
538
539Zephyr is built in two phases; the first phase of the build produces
540``${ZEPHYR_PREBUILT_EXECUTABLE}``.elf which contains all the entries in
541the .intList section preceded by a header:
542
543.. code-block:: c
544
545    struct {
546        void *spurious_irq_handler;
547        void *sw_irq_handler;
548        uint32_t num_isrs;
549        uint32_t num_vectors;
550        struct _isr_list isrs[];  <- of size num_isrs
551    };
552
553This data consisting of the header and instances of struct _isr_list inside
554``${ZEPHYR_PREBUILT_EXECUTABLE}``.elf is then used by the
555gen_isr_tables.py script to generate a C file defining a vector table and
556software ISR table that are then compiled and linked into the final
557application.
558
559The priority level of any interrupt is not encoded in these tables, instead
560:c:macro:`IRQ_CONNECT` also has a runtime component which programs the desired
561priority level of the interrupt to the interrupt controller. Some architectures
562do not support the notion of interrupt priority, in which case the priority
563argument is ignored.
564
565Vector Table
566~~~~~~~~~~~~
567A vector table is generated when :kconfig:option:`CONFIG_GEN_IRQ_VECTOR_TABLE` is
568enabled.  This data structure is used natively by the CPU and is simply an
569array of function pointers, where each element n corresponds to the IRQ handler
570for IRQ line n, and the function pointers are:
571
572#. For 'direct' interrupts declared with :c:macro:`IRQ_DIRECT_CONNECT`, the
573   handler function will be placed here.
574#. For regular interrupts declared with :c:macro:`IRQ_CONNECT`, the address
575   of the common software IRQ handler is placed here. This code does common
576   kernel interrupt bookkeeping and looks up the ISR and parameter from the
577   software ISR table.
578#. For interrupt lines that are not configured at all, the address of the
579   spurious IRQ handler will be placed here. The spurious IRQ handler
580   causes a system fatal error if encountered.
581
582Some architectures have a common entry point for all interrupts and do not
583support a vector table, in which case the
584:kconfig:option:`CONFIG_GEN_IRQ_VECTOR_TABLE` option should be disabled.
585
586Some architectures may reserve some initial vectors for system exceptions
587and declare this in a table elsewhere, in which case
588CONFIG_GEN_IRQ_START_VECTOR needs to be set to properly offset the indices
589in the table.
590
591SW ISR Table
592~~~~~~~~~~~~
593This is an array of struct _isr_table_entry:
594
595.. code-block:: c
596
597    struct _isr_table_entry {
598        void *arg;
599        void (*isr)(void *);
600    };
601
602This is used by the common software IRQ handler to look up the ISR and its
603argument and execute it. The active IRQ line is looked up in an interrupt
604controller register and used to index this table.
605
606Shared SW ISR Table
607~~~~~~~~~~~~~~~~~~~
608
609This is an array of struct z_shared_isr_table_entry:
610
611.. code-block:: c
612
613    struct z_shared_isr_table_entry {
614        struct _isr_table_entry clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS];
615        size_t client_num;
616    };
617
618This table keeps track of the registered clients for each of the interrupt
619lines. Whenever an interrupt line becomes shared, :c:func:`z_shared_isr` will
620replace the currently registered ISR in _sw_isr_table. This special ISR will
621iterate through the list of registered clients and invoke the ISRs.
622
623Implementation using linker script
624----------------------------------
625
626This way of prepare and parse .isrList section to implement interrupt vectors arrays
627is called local isr declaration.
628The name comes from the fact that all the entries to the arrays that would create
629interrupt vectors are created locally in place of invocation of :c:macro:`IRQ_CONNECT` macro.
630Then automatically generated linker scripts are used to place it in the right place in the memory.
631
632This option requires enabling by the choose of :kconfig:option:`CONFIG_ISR_TABLES_LOCAL_DECLARATION`.
633If this configuration is supported by the used architecture and toolchaing the
634:kconfig:option:`CONFIG_ISR_TABLES_LOCAL_DECLARATION_SUPPORTED` is set.
635See details of this option for the information about currently supported configurations.
636
637Any invocation of :c:macro:`IRQ_CONNECT` or :c:macro:`IRQ_DIRECT_CONNECT` will declare an instance
638of ``struct _isr_list_sname`` which is placed in a special .intList section:
639
640.. code-block:: c
641
642    struct _isr_list_sname {
643        /** IRQ line number */
644        int32_t irq;
645        /** Flags for this IRQ, see ISR_FLAG_* definitions */
646        int32_t flags;
647        /** The section name */
648        const char sname[];
649    };
650
651Note that the section name is placed in flexible array member.
652It means that the size of the initialized structure will vary depending on the
653structure name length.
654The whole entry is used by the script during the build of the application
655and has all the information needed for proper interrupt placement.
656
657Beside of the _isr_list_sname the :c:macro:`IRQ_CONNECT` macro generates an entry
658that would be the part of the interrupt array:
659
660.. code-block:: c
661
662    struct _isr_table_entry {
663        const void *arg;
664        void (*isr)(const void *);
665    };
666
667This array is placed in a section with the name saved in _isr_list_sname structure.
668
669The values created by :c:macro:`IRQ_DIRECT_CONNECT` macro depends on the architecture.
670It can be changed to variable that points to a interrupt handler:
671
672.. code-block:: c
673
674    static uintptr_t <unique name> = ((uintptr_t)func);
675
676Or to actually naked function that implements a jump to the interrupt handler:
677
678.. code-block:: c
679
680    static void <unique name>(void)
681    {
682        __asm(ARCH_IRQ_VECTOR_JUMP_CODE(func));
683    }
684
685Similar like for :c:macro:`IRQ_CONNECT`, the created variable or function is placed
686in a section, saved in _isr_list_sname section.
687
688Files generated by the script
689~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
690
691The interrupt tables generator script creates 3 files:
692isr_tables.c, isr_tables_swi.ld, and isr_tables_vt.ld.
693
694The isr_tables.c will contain all the structures for interrupts, direct interrupts and
695shared interrupts (if enabled). This file implements only all the structures that
696are not implemented by the application, leaving a comment where the interrupt
697not implemented here can be found.
698
699Then two linker files are used. The isr_tables_vt.ld file is included in place
700where the interrupt vectors are required to be placed in the selected architecture.
701The isr_tables_swi.ld file describes the placement of the software interrupt table
702elements. The separated file is required as it might be placed in writable on nonwritable
703section, depending on the current configuration.
704
705x86 Details
706-----------
707
708The x86 architecture has a special type of vector table called the Interrupt
709Descriptor Table (IDT) which must be laid out in a certain way per the x86
710processor documentation.  It is still fundamentally a vector table, and the
711:ref:`gen_idt.py` tool uses the .intList section to create it. However, on APIC-based
712systems the indexes in the vector table do not correspond to the IRQ line. The
713first 32 vectors are reserved for CPU exceptions, and all remaining vectors (up
714to index 255) correspond to the priority level, in groups of 16. In this
715scheme, interrupts of priority level 0 will be placed in vectors 32-47, level 1
71648-63, and so forth. When the :ref:`gen_idt.py` tool is constructing the IDT, when it
717configures an interrupt it will look for a free vector in the appropriate range
718for the requested priority level and set the handler there.
719
720On x86 when an interrupt or exception vector is executed by the CPU, there is
721no foolproof way to determine which vector was fired, so a software ISR table
722indexed by IRQ line is not used. Instead, the :c:macro:`IRQ_CONNECT` call
723creates a small assembly language function which calls the common interrupt
724code in :c:func:`_interrupt_enter` with the ISR and parameter as arguments.
725It is the address of this assembly interrupt stub which gets placed in the IDT.
726For interrupts declared with :c:macro:`IRQ_DIRECT_CONNECT` the parameterless
727ISR is placed directly in the IDT.
728
729On systems where the position in the vector table corresponds to the
730interrupt's priority level, the interrupt controller needs to know at
731runtime what vector is associated with an IRQ line. :ref:`gen_idt.py` additionally
732creates an _irq_to_interrupt_vector array which maps an IRQ line to its
733configured vector in the IDT. This is used at runtime by :c:macro:`IRQ_CONNECT`
734to program the IRQ-to-vector association in the interrupt controller.
735
736For dynamic interrupts, the build must generate some 4-byte dynamic interrupt
737stubs, one stub per dynamic interrupt in use. The number of stubs is controlled
738by the :kconfig:option:`CONFIG_X86_DYNAMIC_IRQ_STUBS` option. Each stub pushes an
739unique identifier which is then used to fetch the appropriate handler function
740and parameter out of a table populated when the dynamic interrupt was
741connected.
742
743Going Beyond the Default Supported Number of Interrupts
744-------------------------------------------------------
745
746When generating interrupts in the multi-level configuration, 8-bits per level is the default
747mask used when determining which level a given interrupt code belongs to. This can become
748a problem when dealing with CPUs that support more than 255 interrupts per single
749aggregator. In this case it may be desirable to override these defaults and use a custom
750number of bits per level. Regardless of how many bits used for each level, the sum of
751the total bits used between all levels must sum to be less than or equal to 32-bits,
752fitting into a single 32-bit integer. To modify the bit total per level, override the
753default 8 in :file:`Kconfig.multilevel` by setting :kconfig:option:`CONFIG_1ST_LEVEL_INTERRUPT_BITS`
754for the  first level, :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPT_BITS` for the second level and
755:kconfig:option:`CONFIG_3RD_LEVEL_INTERRUPT_BITS` for the third level. These masks control the
756length of the bit masks and shift to apply when generating interrupt values, when checking the
757interrupts level and converting interrupts to a different level. The logic controlling
758this can be found in :file:`irq_multilevel.h`
759
760Suggested Uses
761**************
762
763Use a regular or direct ISR to perform interrupt processing that requires a
764very rapid response, and can be done quickly without blocking.
765
766.. note::
767    Interrupt processing that is time consuming, or involves blocking,
768    should be handed off to a thread. See `Offloading ISR Work`_ for
769    a description of various techniques that can be used in an application.
770
771Configuration Options
772*********************
773
774Related configuration options:
775
776* :kconfig:option:`CONFIG_ISR_STACK_SIZE`
777
778Additional architecture-specific and device-specific configuration options
779also exist.
780
781API Reference
782*************
783
784.. doxygengroup:: isr_apis
785