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
165Zero Latency Interrupts
166-----------------------
167
168Preventing interruptions by applying an IRQ lock may increase the observed
169interrupt latency. A high interrupt latency, however, may not be acceptable
170for certain low-latency use-cases.
171
172The kernel addresses such use-cases by allowing interrupts with critical
173latency constraints to execute at a priority level that cannot be blocked
174by interrupt locking. These interrupts are defined as
175*zero-latency interrupts*. The support for zero-latency interrupts requires
176:kconfig:option:`CONFIG_ZERO_LATENCY_IRQS` to be enabled. In addition to that, the
177flag :c:macro:`IRQ_ZERO_LATENCY` must be passed to :c:macro:`IRQ_CONNECT` or
178:c:macro:`IRQ_DIRECT_CONNECT` macros to configure the particular interrupt
179with zero latency.
180
181Zero-latency interrupts are expected to be used to manage hardware events
182directly, and not to interoperate with the kernel code at all. They should
183treat all kernel APIs as undefined behavior (i.e. an application that uses the
184APIs inside a zero-latency interrupt context is responsible for directly
185verifying correct behavior). Zero-latency interrupts may not modify any data
186inspected by kernel APIs invoked from normal Zephyr contexts and shall not
187generate exceptions that need to be handled synchronously (e.g. kernel panic).
188
189.. important::
190    Zero-latency interrupts are supported on an architecture-specific basis.
191    The feature is currently implemented in the ARM Cortex-M architecture
192    variant.
193
194Offloading ISR Work
195===================
196
197An ISR should execute quickly to ensure predictable system operation.
198If time consuming processing is required the ISR should offload some or all
199processing to a thread, thereby restoring the kernel's ability to respond
200to other interrupts.
201
202The kernel supports several mechanisms for offloading interrupt-related
203processing to a thread.
204
205* An ISR can signal a helper thread to do interrupt-related processing
206  using a kernel object, such as a FIFO, LIFO, or semaphore.
207
208* An ISR can instruct the system workqueue thread to execute a work item.
209  (See :ref:`workqueues_v2`.)
210
211When an ISR offloads work to a thread, there is typically a single context
212switch to that thread when the ISR completes, allowing interrupt-related
213processing to continue almost immediately. However, depending on the
214priority of the thread handling the offload, it is possible that
215the currently executing cooperative thread or other higher-priority threads
216may execute before the thread handling the offload is scheduled.
217
218Sharing interrupt lines
219=======================
220
221In the case of some hardware platforms, the same interrupt lines may be used
222by different IPs. For example, interrupt 17 may be used by a DMA controller to
223signal that a data transfer has been completed or by a DAI controller to signal
224that the transfer FIFO has reached its watermark. To make this work, one would
225have to either employ some special logic or find a workaround (for example, using
226the shared_irq interrupt controller), which doesn't scale very well.
227
228To solve this problem, one may use shared interrupts, which can be enabled using
229:kconfig:option:`CONFIG_SHARED_INTERRUPTS`. Whenever an attempt to register
230a second ISR/argument pair on the same interrupt line is made (using
231:c:macro:`IRQ_CONNECT` or :c:func:`irq_connect_dynamic`), the interrupt line will
232become shared, meaning the two ISR/argument pairs (previous one and the one that
233has just been registered) will be invoked each time the interrupt is triggered.
234The entities that make use of an interrupt line in the shared interrupt context
235are known as clients. The maximum number of allowed clients for an interrupt is
236controlled by :kconfig:option:`CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS`.
237
238Interrupt sharing is transparent to the user. As such, the user may register
239interrupts using :c:macro:`IRQ_CONNECT` and :c:func:`irq_connect_dynamic` as
240they normally would. The interrupt sharing is taken care of behind the scenes.
241
242Enabling the shared interrupt support and dynamic interrupt support will
243allow users to dynamically disconnect ISRs using :c:func:`irq_disconnect_dynamic`.
244After an ISR is disconnected, whenever the interrupt line for which it was
245register gets triggered, the ISR will no longer get invoked.
246
247Please note that enabling :kconfig:option:`CONFIG_SHARED_INTERRUPTS` will
248result in a non-negligible increase in the binary size. Use with caution.
249
250Implementation
251**************
252
253Defining a regular ISR
254======================
255
256An ISR is defined at runtime by calling :c:macro:`IRQ_CONNECT`. It must
257then be enabled by calling :c:func:`irq_enable`.
258
259.. important::
260    IRQ_CONNECT() is not a C function and does some inline assembly magic
261    behind the scenes. All its arguments must be known at build time.
262    Drivers that have multiple instances may need to define per-instance
263    config functions to configure each instance of the interrupt.
264
265The following code defines and enables an ISR.
266
267.. code-block:: c
268
269    #define MY_DEV_IRQ  24       /* device uses IRQ 24 */
270    #define MY_DEV_PRIO  2       /* device uses interrupt priority 2 */
271    /* argument passed to my_isr(), in this case a pointer to the device */
272    #define MY_ISR_ARG  DEVICE_GET(my_device)
273    #define MY_IRQ_FLAGS 0       /* IRQ flags */
274
275    void my_isr(void *arg)
276    {
277       ... /* ISR code */
278    }
279
280    void my_isr_installer(void)
281    {
282       ...
283       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_PRIO, my_isr, MY_ISR_ARG, MY_IRQ_FLAGS);
284       irq_enable(MY_DEV_IRQ);
285       ...
286    }
287
288Since the :c:macro:`IRQ_CONNECT` macro requires that all its parameters be
289known at build time, in some cases this may not be acceptable. It is also
290possible to install interrupts at runtime with
291:c:func:`irq_connect_dynamic`. It is used in exactly the same way as
292:c:macro:`IRQ_CONNECT`:
293
294.. code-block:: c
295
296    void my_isr_installer(void)
297    {
298       ...
299       irq_connect_dynamic(MY_DEV_IRQ, MY_DEV_PRIO, my_isr, MY_ISR_ARG,
300                           MY_IRQ_FLAGS);
301       irq_enable(MY_DEV_IRQ);
302       ...
303    }
304
305Dynamic interrupts require the :kconfig:option:`CONFIG_DYNAMIC_INTERRUPTS` option to
306be enabled. Removing or re-configuring a dynamic interrupt is currently
307unsupported.
308
309Defining a 'direct' ISR
310=======================
311
312Regular Zephyr interrupts introduce some overhead which may be unacceptable
313for some low-latency use-cases. Specifically:
314
315* The argument to the ISR is retrieved and passed to the ISR
316
317* If power management is enabled and the system was idle, all the hardware
318  will be resumed from low-power state before the ISR is executed, which can be
319  very time-consuming
320
321* Although some architectures will do this in hardware, other architectures
322  need to switch to the interrupt stack in code
323
324* After the interrupt is serviced, the OS then performs some logic to
325  potentially make a scheduling decision.
326
327Zephyr supports so-called 'direct' interrupts, which are installed via
328:c:macro:`IRQ_DIRECT_CONNECT`. These direct interrupts have some special
329implementation requirements and a reduced feature set; see the definition
330of :c:macro:`IRQ_DIRECT_CONNECT` for details.
331
332The following code demonstrates a direct ISR:
333
334.. code-block:: c
335
336    #define MY_DEV_IRQ  24       /* device uses IRQ 24 */
337    #define MY_DEV_PRIO  2       /* device uses interrupt priority 2 */
338    /* argument passed to my_isr(), in this case a pointer to the device */
339    #define MY_IRQ_FLAGS 0       /* IRQ flags */
340
341    ISR_DIRECT_DECLARE(my_isr)
342    {
343       do_stuff();
344       ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency */
345       return 1; /* We should check if scheduling decision should be made */
346    }
347
348    void my_isr_installer(void)
349    {
350       ...
351       IRQ_DIRECT_CONNECT(MY_DEV_IRQ, MY_DEV_PRIO, my_isr, MY_IRQ_FLAGS);
352       irq_enable(MY_DEV_IRQ);
353       ...
354    }
355
356Installation of dynamic direct interrupts is supported on an
357architecture-specific basis. (The feature is currently implemented in
358ARM Cortex-M architecture variant. Dynamic direct interrupts feature is
359exposed to the user via an ARM-only API.)
360
361Sharing an interrupt line
362=========================
363
364The following code defines two ISRs using the same interrupt number.
365
366.. code-block:: c
367
368    #define MY_DEV_IRQ 24		/* device uses INTID 24 */
369    #define MY_DEV_IRQ_PRIO 2		/* device uses interrupt priority 2 */
370    /*  this argument may be anything */
371    #define MY_FST_ISR_ARG INT_TO_POINTER(1)
372    /*  this argument may be anything */
373    #define MY_SND_ISR_ARG INT_TO_POINTER(2)
374    #define MY_IRQ_FLAGS 0		/* IRQ flags */
375
376    void my_first_isr(void *arg)
377    {
378       ... /* some magic happens here */
379    }
380
381    void my_second_isr(void *arg)
382    {
383       ... /* even more magic happens here */
384    }
385
386    void my_isr_installer(void)
387    {
388       ...
389       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_first_isr, MY_FST_ISR_ARG, MY_IRQ_FLAGS);
390       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_second_isr, MY_SND_ISR_ARG, MY_IRQ_FLAGS);
391       ...
392    }
393
394The same restrictions regarding :c:macro:`IRQ_CONNECT` described in `Defining a regular ISR`_
395are applicable here. If :kconfig:option:`CONFIG_SHARED_INTERRUPTS` is disabled, the above
396code will generate a build error. Otherwise, the above code will result in the two ISRs
397being invoked each time interrupt 24 is triggered.
398
399If :kconfig:option:`CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS` is set to a value lower than 2
400(current number of clients), a build error will be generated.
401
402If dynamic interrupts are enabled, :c:func:`irq_connect_dynamic` will allow sharing interrupts
403during runtime. Exceeding the configured maximum number of allowed clients will result in
404a failed assertion.
405
406Dynamically disconnecting an ISR
407================================
408
409The following code defines two ISRs using the same interrupt number. The second
410ISR is disconnected during runtime.
411
412.. code-block:: c
413
414    #define MY_DEV_IRQ 24		/* device uses INTID 24 */
415    #define MY_DEV_IRQ_PRIO 2		/* device uses interrupt priority 2 */
416    /*  this argument may be anything */
417    #define MY_FST_ISR_ARG INT_TO_POINTER(1)
418    /*  this argument may be anything */
419    #define MY_SND_ISR_ARG INT_TO_POINTER(2)
420    #define MY_IRQ_FLAGS 0		/* IRQ flags */
421
422    void my_first_isr(void *arg)
423    {
424       ... /* some magic happens here */
425    }
426
427    void my_second_isr(void *arg)
428    {
429       ... /* even more magic happens here */
430    }
431
432    void my_isr_installer(void)
433    {
434       ...
435       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_first_isr, MY_FST_ISR_ARG, MY_IRQ_FLAGS);
436       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_second_isr, MY_SND_ISR_ARG, MY_IRQ_FLAGS);
437       ...
438    }
439
440    void my_isr_uninstaller(void)
441    {
442       ...
443       irq_disconnect_dynamic(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_first_isr, MY_FST_ISR_ARG, MY_IRQ_FLAGS);
444       ...
445    }
446
447The :c:func:`irq_disconnect_dynamic` call will result in interrupt 24 becoming
448unshared, meaning the system will act as if the first :c:macro:`IRQ_CONNECT`
449call never happened. This behaviour is only allowed if
450:kconfig:option:`CONFIG_DYNAMIC_INTERRUPTS` is enabled, otherwise a linker
451error will be generated.
452
453Implementation Details
454======================
455
456Interrupt tables are set up at build time using some special build tools.  The
457details laid out here apply to all architectures except x86, which are
458covered in the `x86 Details`_ section below.
459
460The invocation of :c:macro:`IRQ_CONNECT` will declare an instance of
461struct _isr_list which is placed in a special .intList section.
462This section is placed in compiled code on precompilation stages only.
463It is meant to be used by Zephyr script to generate interrupt tables
464and is removed from the final build.
465The script implements different parsers to process the data from .intList section
466and produce the required output.
467
468The default parser generates C arrays filled with arguments and interrupt
469handlers in a form of addresses directly taken from .intList section entries.
470It works with all the architectures and compilers (with the exception mentioned above).
471The limitation of this parser is the fact that after the arrays are generated
472it is expected for the code not to relocate.
473Any relocation on this stage may lead to the situation where the entry in the interrupt array
474is no longer pointing to the function that was expected.
475It means that this parser, being more compatible is limiting us from using Link Time Optimization.
476
477The local isr declaration parser uses different approach to construct
478the same arrays at binnary level.
479All the entries to the arrays are declared and defined locally,
480directly in the file where :c:macro:`IRQ_CONNECT` is used.
481They are placed in a section with the unique, synthesized name.
482The name of the section is then placed in .intList section and it is used to create linker script
483to properly place the created entry in the right place in the memory.
484This parser is now limited to the supported architectures and toolchains but in reward it keeps
485the information about object relations for linker thus allowing the Link Time Optimization.
486
487Implementation using C arrays
488-----------------------------
489
490This is the default configuration available for all Zephyr supported architectures.
491
492Any invocation of :c:macro:`IRQ_CONNECT` will declare an instance of
493struct _isr_list which is placed in a special .intList section:
494
495.. code-block:: c
496
497    struct _isr_list {
498        /** IRQ line number */
499        int32_t irq;
500        /** Flags for this IRQ, see ISR_FLAG_* definitions */
501        int32_t flags;
502        /** ISR to call */
503        void *func;
504        /** Parameter for non-direct IRQs */
505        void *param;
506    };
507
508Zephyr is built in two phases; the first phase of the build produces
509``${ZEPHYR_PREBUILT_EXECUTABLE}``.elf which contains all the entries in
510the .intList section preceded by a header:
511
512.. code-block:: c
513
514    struct {
515        void *spurious_irq_handler;
516        void *sw_irq_handler;
517        uint32_t num_isrs;
518        uint32_t num_vectors;
519        struct _isr_list isrs[];  <- of size num_isrs
520    };
521
522This data consisting of the header and instances of struct _isr_list inside
523``${ZEPHYR_PREBUILT_EXECUTABLE}``.elf is then used by the
524gen_isr_tables.py script to generate a C file defining a vector table and
525software ISR table that are then compiled and linked into the final
526application.
527
528The priority level of any interrupt is not encoded in these tables, instead
529:c:macro:`IRQ_CONNECT` also has a runtime component which programs the desired
530priority level of the interrupt to the interrupt controller. Some architectures
531do not support the notion of interrupt priority, in which case the priority
532argument is ignored.
533
534Vector Table
535~~~~~~~~~~~~
536A vector table is generated when :kconfig:option:`CONFIG_GEN_IRQ_VECTOR_TABLE` is
537enabled.  This data structure is used natively by the CPU and is simply an
538array of function pointers, where each element n corresponds to the IRQ handler
539for IRQ line n, and the function pointers are:
540
541#. For 'direct' interrupts declared with :c:macro:`IRQ_DIRECT_CONNECT`, the
542   handler function will be placed here.
543#. For regular interrupts declared with :c:macro:`IRQ_CONNECT`, the address
544   of the common software IRQ handler is placed here. This code does common
545   kernel interrupt bookkeeping and looks up the ISR and parameter from the
546   software ISR table.
547#. For interrupt lines that are not configured at all, the address of the
548   spurious IRQ handler will be placed here. The spurious IRQ handler
549   causes a system fatal error if encountered.
550
551Some architectures (such as the Nios II internal interrupt controller) have a
552common entry point for all interrupts and do not support a vector table, in
553which case the :kconfig:option:`CONFIG_GEN_IRQ_VECTOR_TABLE` option should be
554disabled.
555
556Some architectures may reserve some initial vectors for system exceptions
557and declare this in a table elsewhere, in which case
558CONFIG_GEN_IRQ_START_VECTOR needs to be set to properly offset the indices
559in the table.
560
561SW ISR Table
562~~~~~~~~~~~~
563This is an array of struct _isr_table_entry:
564
565.. code-block:: c
566
567    struct _isr_table_entry {
568        void *arg;
569        void (*isr)(void *);
570    };
571
572This is used by the common software IRQ handler to look up the ISR and its
573argument and execute it. The active IRQ line is looked up in an interrupt
574controller register and used to index this table.
575
576Shared SW ISR Table
577~~~~~~~~~~~~~~~~~~~
578
579This is an array of struct z_shared_isr_table_entry:
580
581.. code-block:: c
582
583    struct z_shared_isr_table_entry {
584        struct _isr_table_entry clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS];
585        size_t client_num;
586    };
587
588This table keeps track of the registered clients for each of the interrupt
589lines. Whenever an interrupt line becomes shared, :c:func:`z_shared_isr` will
590replace the currently registered ISR in _sw_isr_table. This special ISR will
591iterate through the list of registered clients and invoke the ISRs.
592
593Implementation using linker script
594----------------------------------
595
596This way of prepare and parse .isrList section to implement interrupt vectors arrays
597is called local isr declaration.
598The name comes from the fact that all the entries to the arrays that would create
599interrupt vectors are created locally in place of invocation of :c:macro:`IRQ_CONNECT` macro.
600Then automatically generated linker scripts are used to place it in the right place in the memory.
601
602This option requires enabling by the choose of :kconfig:option:`ISR_TABLES_LOCAL_DECLARATION`.
603If this configuration is supported by the used architecture and toolchaing the
604:kconfig:option:`ISR_TABLES_LOCAL_DECLARATION_SUPPORTED` is set.
605See details of this option for the information about currently supported configurations.
606
607Any invocation of :c:macro:`IRQ_CONNECT` or :c:macro:`IRQ_DIRECT_CONNECT` will declare an instance
608of ``struct _isr_list_sname`` which is placed in a special .intList section:
609
610.. code-block:: c
611
612    struct _isr_list_sname {
613        /** IRQ line number */
614        int32_t irq;
615        /** Flags for this IRQ, see ISR_FLAG_* definitions */
616        int32_t flags;
617        /** The section name */
618        const char sname[];
619    };
620
621Note that the section name is placed in flexible array member.
622It means that the size of the initialized structure will vary depending on the
623structure name length.
624The whole entry is used by the script during the build of the application
625and has all the information needed for proper interrupt placement.
626
627Beside of the _isr_list_sname the :c:macro:`IRQ_CONNECT` macro generates an entry
628that would be the part of the interrupt array:
629
630.. code-block:: c
631
632    struct _isr_table_entry {
633        const void *arg;
634        void (*isr)(const void *);
635    };
636
637This array is placed in a section with the name saved in _isr_list_sname structure.
638
639The values created by :c:macro:`IRQ_DIRECT_CONNECT` macro depends on the architecture.
640It can be changed to variable that points to a interrupt handler:
641
642.. code-block:: c
643
644    static uintptr_t <unique name> = ((uintptr_t)func);
645
646Or to actually naked function that implements a jump to the interrupt handler:
647
648.. code-block:: c
649
650    static void <unique name>(void)
651    {
652        __asm(ARCH_IRQ_VECTOR_JUMP_CODE(func));
653    }
654
655Similar like for :c:macro:`IRQ_CONNECT`, the created variable or function is placed
656in a section, saved in _isr_list_sname section.
657
658Files generated by the script
659~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
660
661The interrupt tables generator script creates 3 files:
662isr_tables.c, isr_tables_swi.ld, and isr_tables_vt.ld.
663
664The isr_tables.c will contain all the structures for interrupts, direct interrupts and
665shared interrupts (if enabled). This file implements only all the structures that
666are not implemented by the application, leaving a comment where the interrupt
667not implemented here can be found.
668
669Then two linker files are used. The isr_tables_vt.ld file is included in place
670where the interrupt vectors are required to be placed in the selected architecture.
671The isr_tables_swi.ld file describes the placement of the software interrupt table
672elements. The separated file is required as it might be placed in writable on nonwritable
673section, depending on the current configuration.
674
675x86 Details
676-----------
677
678The x86 architecture has a special type of vector table called the Interrupt
679Descriptor Table (IDT) which must be laid out in a certain way per the x86
680processor documentation.  It is still fundamentally a vector table, and the
681:ref:`gen_idt.py` tool uses the .intList section to create it. However, on APIC-based
682systems the indexes in the vector table do not correspond to the IRQ line. The
683first 32 vectors are reserved for CPU exceptions, and all remaining vectors (up
684to index 255) correspond to the priority level, in groups of 16. In this
685scheme, interrupts of priority level 0 will be placed in vectors 32-47, level 1
68648-63, and so forth. When the :ref:`gen_idt.py` tool is constructing the IDT, when it
687configures an interrupt it will look for a free vector in the appropriate range
688for the requested priority level and set the handler there.
689
690On x86 when an interrupt or exception vector is executed by the CPU, there is
691no foolproof way to determine which vector was fired, so a software ISR table
692indexed by IRQ line is not used. Instead, the :c:macro:`IRQ_CONNECT` call
693creates a small assembly language function which calls the common interrupt
694code in :c:func:`_interrupt_enter` with the ISR and parameter as arguments.
695It is the address of this assembly interrupt stub which gets placed in the IDT.
696For interrupts declared with :c:macro:`IRQ_DIRECT_CONNECT` the parameterless
697ISR is placed directly in the IDT.
698
699On systems where the position in the vector table corresponds to the
700interrupt's priority level, the interrupt controller needs to know at
701runtime what vector is associated with an IRQ line. :ref:`gen_idt.py` additionally
702creates an _irq_to_interrupt_vector array which maps an IRQ line to its
703configured vector in the IDT. This is used at runtime by :c:macro:`IRQ_CONNECT`
704to program the IRQ-to-vector association in the interrupt controller.
705
706For dynamic interrupts, the build must generate some 4-byte dynamic interrupt
707stubs, one stub per dynamic interrupt in use. The number of stubs is controlled
708by the :kconfig:option:`CONFIG_X86_DYNAMIC_IRQ_STUBS` option. Each stub pushes an
709unique identifier which is then used to fetch the appropriate handler function
710and parameter out of a table populated when the dynamic interrupt was
711connected.
712
713Going Beyond the Default Supported Number of Interrupts
714-------------------------------------------------------
715
716When generating interrupts in the multi-level configuration, 8-bits per level is the default
717mask used when determining which level a given interrupt code belongs to. This can become
718a problem when dealing with CPUs that support more than 255 interrupts per single
719aggregator. In this case it may be desirable to override these defaults and use a custom
720number of bits per level. Regardless of how many bits used for each level, the sum of
721the total bits used between all levels must sum to be less than or equal to 32-bits,
722fitting into a single 32-bit integer. To modify the bit total per level, override the
723default 8 in :file:`Kconfig.multilevel` by setting :kconfig:option:`CONFIG_1ST_LEVEL_INTERRUPT_BITS`
724for the  first level, :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPT_BITS` for the second level and
725:kconfig:option:`CONFIG_3RD_LEVEL_INTERRUPT_BITS` for the third level. These masks control the
726length of the bit masks and shift to apply when generating interrupt values, when checking the
727interrupts level and converting interrupts to a different level. The logic controlling
728this can be found in :file:`irq_multilevel.h`
729
730Suggested Uses
731**************
732
733Use a regular or direct ISR to perform interrupt processing that requires a
734very rapid response, and can be done quickly without blocking.
735
736.. note::
737    Interrupt processing that is time consuming, or involves blocking,
738    should be handed off to a thread. See `Offloading ISR Work`_ for
739    a description of various techniques that can be used in an application.
740
741Configuration Options
742*********************
743
744Related configuration options:
745
746* :kconfig:option:`CONFIG_ISR_STACK_SIZE`
747
748Additional architecture-specific and device-specific configuration options
749also exist.
750
751API Reference
752*************
753
754.. doxygengroup:: isr_apis
755