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` and whose handlers are declared using
329:c:macro:`ISR_DIRECT_DECLARE`. These direct interrupts have some special
330implementation requirements and a reduced feature set; see the definitions
331of :c:macro:`IRQ_DIRECT_CONNECT` and :c:macro:`ISR_DIRECT_DECLARE` for details.
332
333The following code demonstrates a direct ISR:
334
335.. code-block:: c
336
337    #define MY_DEV_IRQ  24       /* device uses IRQ 24 */
338    #define MY_DEV_PRIO  2       /* device uses interrupt priority 2 */
339    /* argument passed to my_isr(), in this case a pointer to the device */
340    #define MY_IRQ_FLAGS 0       /* IRQ flags */
341
342    ISR_DIRECT_DECLARE(my_isr)
343    {
344       do_stuff();
345       ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency */
346       return 1; /* We should check if scheduling decision should be made */
347    }
348
349    void my_isr_installer(void)
350    {
351       ...
352       IRQ_DIRECT_CONNECT(MY_DEV_IRQ, MY_DEV_PRIO, my_isr, MY_IRQ_FLAGS);
353       irq_enable(MY_DEV_IRQ);
354       ...
355    }
356
357Installation of dynamic direct interrupts is supported on an
358architecture-specific basis. (The feature is currently implemented in
359ARM Cortex-M architecture variant. Dynamic direct interrupts feature is
360exposed to the user via an ARM-only API.)
361
362Sharing an interrupt line
363=========================
364
365The following code defines two ISRs using the same interrupt number.
366
367.. code-block:: c
368
369    #define MY_DEV_IRQ 24		/* device uses INTID 24 */
370    #define MY_DEV_IRQ_PRIO 2		/* device uses interrupt priority 2 */
371    /*  this argument may be anything */
372    #define MY_FST_ISR_ARG INT_TO_POINTER(1)
373    /*  this argument may be anything */
374    #define MY_SND_ISR_ARG INT_TO_POINTER(2)
375    #define MY_IRQ_FLAGS 0		/* IRQ flags */
376
377    void my_first_isr(void *arg)
378    {
379       ... /* some magic happens here */
380    }
381
382    void my_second_isr(void *arg)
383    {
384       ... /* even more magic happens here */
385    }
386
387    void my_isr_installer(void)
388    {
389       ...
390       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_first_isr, MY_FST_ISR_ARG, MY_IRQ_FLAGS);
391       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_second_isr, MY_SND_ISR_ARG, MY_IRQ_FLAGS);
392       ...
393    }
394
395The same restrictions regarding :c:macro:`IRQ_CONNECT` described in `Defining a regular ISR`_
396are applicable here. If :kconfig:option:`CONFIG_SHARED_INTERRUPTS` is disabled, the above
397code will generate a build error. Otherwise, the above code will result in the two ISRs
398being invoked each time interrupt 24 is triggered.
399
400If :kconfig:option:`CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS` is set to a value lower than 2
401(current number of clients), a build error will be generated.
402
403If dynamic interrupts are enabled, :c:func:`irq_connect_dynamic` will allow sharing interrupts
404during runtime. Exceeding the configured maximum number of allowed clients will result in
405a failed assertion.
406
407Dynamically disconnecting an ISR
408================================
409
410The following code defines two ISRs using the same interrupt number. The second
411ISR is disconnected during runtime.
412
413.. code-block:: c
414
415    #define MY_DEV_IRQ 24		/* device uses INTID 24 */
416    #define MY_DEV_IRQ_PRIO 2		/* device uses interrupt priority 2 */
417    /*  this argument may be anything */
418    #define MY_FST_ISR_ARG INT_TO_POINTER(1)
419    /*  this argument may be anything */
420    #define MY_SND_ISR_ARG INT_TO_POINTER(2)
421    #define MY_IRQ_FLAGS 0		/* IRQ flags */
422
423    void my_first_isr(void *arg)
424    {
425       ... /* some magic happens here */
426    }
427
428    void my_second_isr(void *arg)
429    {
430       ... /* even more magic happens here */
431    }
432
433    void my_isr_installer(void)
434    {
435       ...
436       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_first_isr, MY_FST_ISR_ARG, MY_IRQ_FLAGS);
437       IRQ_CONNECT(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_second_isr, MY_SND_ISR_ARG, MY_IRQ_FLAGS);
438       ...
439    }
440
441    void my_isr_uninstaller(void)
442    {
443       ...
444       irq_disconnect_dynamic(MY_DEV_IRQ, MY_DEV_IRQ_PRIO, my_first_isr, MY_FST_ISR_ARG, MY_IRQ_FLAGS);
445       ...
446    }
447
448The :c:func:`irq_disconnect_dynamic` call will result in interrupt 24 becoming
449unshared, meaning the system will act as if the first :c:macro:`IRQ_CONNECT`
450call never happened. This behaviour is only allowed if
451:kconfig:option:`CONFIG_DYNAMIC_INTERRUPTS` is enabled, otherwise a linker
452error will be generated.
453
454Implementation Details
455======================
456
457Interrupt tables are set up at build time using some special build tools.  The
458details laid out here apply to all architectures except x86, which are
459covered in the `x86 Details`_ section below.
460
461The invocation of :c:macro:`IRQ_CONNECT` will declare an instance of
462struct _isr_list which is placed in a special .intList section.
463This section is placed in compiled code on precompilation stages only.
464It is meant to be used by Zephyr script to generate interrupt tables
465and is removed from the final build.
466The script implements different parsers to process the data from .intList section
467and produce the required output.
468
469The default parser generates C arrays filled with arguments and interrupt
470handlers in a form of addresses directly taken from .intList section entries.
471It works with all the architectures and compilers (with the exception mentioned above).
472The limitation of this parser is the fact that after the arrays are generated
473it is expected for the code not to relocate.
474Any relocation on this stage may lead to the situation where the entry in the interrupt array
475is no longer pointing to the function that was expected.
476It means that this parser, being more compatible is limiting us from using Link Time Optimization.
477
478The local isr declaration parser uses different approach to construct
479the same arrays at binnary level.
480All the entries to the arrays are declared and defined locally,
481directly in the file where :c:macro:`IRQ_CONNECT` is used.
482They are placed in a section with the unique, synthesized name.
483The name of the section is then placed in .intList section and it is used to create linker script
484to properly place the created entry in the right place in the memory.
485This parser is now limited to the supported architectures and toolchains but in reward it keeps
486the information about object relations for linker thus allowing the Link Time Optimization.
487
488Implementation using C arrays
489-----------------------------
490
491This is the default configuration available for all Zephyr supported architectures.
492
493Any invocation of :c:macro:`IRQ_CONNECT` will declare an instance of
494struct _isr_list which is placed in a special .intList section:
495
496.. code-block:: c
497
498    struct _isr_list {
499        /** IRQ line number */
500        int32_t irq;
501        /** Flags for this IRQ, see ISR_FLAG_* definitions */
502        int32_t flags;
503        /** ISR to call */
504        void *func;
505        /** Parameter for non-direct IRQs */
506        void *param;
507    };
508
509Zephyr is built in two phases; the first phase of the build produces
510``${ZEPHYR_PREBUILT_EXECUTABLE}``.elf which contains all the entries in
511the .intList section preceded by a header:
512
513.. code-block:: c
514
515    struct {
516        void *spurious_irq_handler;
517        void *sw_irq_handler;
518        uint32_t num_isrs;
519        uint32_t num_vectors;
520        struct _isr_list isrs[];  <- of size num_isrs
521    };
522
523This data consisting of the header and instances of struct _isr_list inside
524``${ZEPHYR_PREBUILT_EXECUTABLE}``.elf is then used by the
525gen_isr_tables.py script to generate a C file defining a vector table and
526software ISR table that are then compiled and linked into the final
527application.
528
529The priority level of any interrupt is not encoded in these tables, instead
530:c:macro:`IRQ_CONNECT` also has a runtime component which programs the desired
531priority level of the interrupt to the interrupt controller. Some architectures
532do not support the notion of interrupt priority, in which case the priority
533argument is ignored.
534
535Vector Table
536~~~~~~~~~~~~
537A vector table is generated when :kconfig:option:`CONFIG_GEN_IRQ_VECTOR_TABLE` is
538enabled.  This data structure is used natively by the CPU and is simply an
539array of function pointers, where each element n corresponds to the IRQ handler
540for IRQ line n, and the function pointers are:
541
542#. For 'direct' interrupts declared with :c:macro:`IRQ_DIRECT_CONNECT`, the
543   handler function will be placed here.
544#. For regular interrupts declared with :c:macro:`IRQ_CONNECT`, the address
545   of the common software IRQ handler is placed here. This code does common
546   kernel interrupt bookkeeping and looks up the ISR and parameter from the
547   software ISR table.
548#. For interrupt lines that are not configured at all, the address of the
549   spurious IRQ handler will be placed here. The spurious IRQ handler
550   causes a system fatal error if encountered.
551
552Some architectures (such as the Nios II internal interrupt controller) have a
553common entry point for all interrupts and do not support a vector table, in
554which case the :kconfig:option:`CONFIG_GEN_IRQ_VECTOR_TABLE` option should be
555disabled.
556
557Some architectures may reserve some initial vectors for system exceptions
558and declare this in a table elsewhere, in which case
559CONFIG_GEN_IRQ_START_VECTOR needs to be set to properly offset the indices
560in the table.
561
562SW ISR Table
563~~~~~~~~~~~~
564This is an array of struct _isr_table_entry:
565
566.. code-block:: c
567
568    struct _isr_table_entry {
569        void *arg;
570        void (*isr)(void *);
571    };
572
573This is used by the common software IRQ handler to look up the ISR and its
574argument and execute it. The active IRQ line is looked up in an interrupt
575controller register and used to index this table.
576
577Shared SW ISR Table
578~~~~~~~~~~~~~~~~~~~
579
580This is an array of struct z_shared_isr_table_entry:
581
582.. code-block:: c
583
584    struct z_shared_isr_table_entry {
585        struct _isr_table_entry clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS];
586        size_t client_num;
587    };
588
589This table keeps track of the registered clients for each of the interrupt
590lines. Whenever an interrupt line becomes shared, :c:func:`z_shared_isr` will
591replace the currently registered ISR in _sw_isr_table. This special ISR will
592iterate through the list of registered clients and invoke the ISRs.
593
594Implementation using linker script
595----------------------------------
596
597This way of prepare and parse .isrList section to implement interrupt vectors arrays
598is called local isr declaration.
599The name comes from the fact that all the entries to the arrays that would create
600interrupt vectors are created locally in place of invocation of :c:macro:`IRQ_CONNECT` macro.
601Then automatically generated linker scripts are used to place it in the right place in the memory.
602
603This option requires enabling by the choose of :kconfig:option:`ISR_TABLES_LOCAL_DECLARATION`.
604If this configuration is supported by the used architecture and toolchaing the
605:kconfig:option:`ISR_TABLES_LOCAL_DECLARATION_SUPPORTED` is set.
606See details of this option for the information about currently supported configurations.
607
608Any invocation of :c:macro:`IRQ_CONNECT` or :c:macro:`IRQ_DIRECT_CONNECT` will declare an instance
609of ``struct _isr_list_sname`` which is placed in a special .intList section:
610
611.. code-block:: c
612
613    struct _isr_list_sname {
614        /** IRQ line number */
615        int32_t irq;
616        /** Flags for this IRQ, see ISR_FLAG_* definitions */
617        int32_t flags;
618        /** The section name */
619        const char sname[];
620    };
621
622Note that the section name is placed in flexible array member.
623It means that the size of the initialized structure will vary depending on the
624structure name length.
625The whole entry is used by the script during the build of the application
626and has all the information needed for proper interrupt placement.
627
628Beside of the _isr_list_sname the :c:macro:`IRQ_CONNECT` macro generates an entry
629that would be the part of the interrupt array:
630
631.. code-block:: c
632
633    struct _isr_table_entry {
634        const void *arg;
635        void (*isr)(const void *);
636    };
637
638This array is placed in a section with the name saved in _isr_list_sname structure.
639
640The values created by :c:macro:`IRQ_DIRECT_CONNECT` macro depends on the architecture.
641It can be changed to variable that points to a interrupt handler:
642
643.. code-block:: c
644
645    static uintptr_t <unique name> = ((uintptr_t)func);
646
647Or to actually naked function that implements a jump to the interrupt handler:
648
649.. code-block:: c
650
651    static void <unique name>(void)
652    {
653        __asm(ARCH_IRQ_VECTOR_JUMP_CODE(func));
654    }
655
656Similar like for :c:macro:`IRQ_CONNECT`, the created variable or function is placed
657in a section, saved in _isr_list_sname section.
658
659Files generated by the script
660~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
661
662The interrupt tables generator script creates 3 files:
663isr_tables.c, isr_tables_swi.ld, and isr_tables_vt.ld.
664
665The isr_tables.c will contain all the structures for interrupts, direct interrupts and
666shared interrupts (if enabled). This file implements only all the structures that
667are not implemented by the application, leaving a comment where the interrupt
668not implemented here can be found.
669
670Then two linker files are used. The isr_tables_vt.ld file is included in place
671where the interrupt vectors are required to be placed in the selected architecture.
672The isr_tables_swi.ld file describes the placement of the software interrupt table
673elements. The separated file is required as it might be placed in writable on nonwritable
674section, depending on the current configuration.
675
676x86 Details
677-----------
678
679The x86 architecture has a special type of vector table called the Interrupt
680Descriptor Table (IDT) which must be laid out in a certain way per the x86
681processor documentation.  It is still fundamentally a vector table, and the
682:ref:`gen_idt.py` tool uses the .intList section to create it. However, on APIC-based
683systems the indexes in the vector table do not correspond to the IRQ line. The
684first 32 vectors are reserved for CPU exceptions, and all remaining vectors (up
685to index 255) correspond to the priority level, in groups of 16. In this
686scheme, interrupts of priority level 0 will be placed in vectors 32-47, level 1
68748-63, and so forth. When the :ref:`gen_idt.py` tool is constructing the IDT, when it
688configures an interrupt it will look for a free vector in the appropriate range
689for the requested priority level and set the handler there.
690
691On x86 when an interrupt or exception vector is executed by the CPU, there is
692no foolproof way to determine which vector was fired, so a software ISR table
693indexed by IRQ line is not used. Instead, the :c:macro:`IRQ_CONNECT` call
694creates a small assembly language function which calls the common interrupt
695code in :c:func:`_interrupt_enter` with the ISR and parameter as arguments.
696It is the address of this assembly interrupt stub which gets placed in the IDT.
697For interrupts declared with :c:macro:`IRQ_DIRECT_CONNECT` the parameterless
698ISR is placed directly in the IDT.
699
700On systems where the position in the vector table corresponds to the
701interrupt's priority level, the interrupt controller needs to know at
702runtime what vector is associated with an IRQ line. :ref:`gen_idt.py` additionally
703creates an _irq_to_interrupt_vector array which maps an IRQ line to its
704configured vector in the IDT. This is used at runtime by :c:macro:`IRQ_CONNECT`
705to program the IRQ-to-vector association in the interrupt controller.
706
707For dynamic interrupts, the build must generate some 4-byte dynamic interrupt
708stubs, one stub per dynamic interrupt in use. The number of stubs is controlled
709by the :kconfig:option:`CONFIG_X86_DYNAMIC_IRQ_STUBS` option. Each stub pushes an
710unique identifier which is then used to fetch the appropriate handler function
711and parameter out of a table populated when the dynamic interrupt was
712connected.
713
714Going Beyond the Default Supported Number of Interrupts
715-------------------------------------------------------
716
717When generating interrupts in the multi-level configuration, 8-bits per level is the default
718mask used when determining which level a given interrupt code belongs to. This can become
719a problem when dealing with CPUs that support more than 255 interrupts per single
720aggregator. In this case it may be desirable to override these defaults and use a custom
721number of bits per level. Regardless of how many bits used for each level, the sum of
722the total bits used between all levels must sum to be less than or equal to 32-bits,
723fitting into a single 32-bit integer. To modify the bit total per level, override the
724default 8 in :file:`Kconfig.multilevel` by setting :kconfig:option:`CONFIG_1ST_LEVEL_INTERRUPT_BITS`
725for the  first level, :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPT_BITS` for the second level and
726:kconfig:option:`CONFIG_3RD_LEVEL_INTERRUPT_BITS` for the third level. These masks control the
727length of the bit masks and shift to apply when generating interrupt values, when checking the
728interrupts level and converting interrupts to a different level. The logic controlling
729this can be found in :file:`irq_multilevel.h`
730
731Suggested Uses
732**************
733
734Use a regular or direct ISR to perform interrupt processing that requires a
735very rapid response, and can be done quickly without blocking.
736
737.. note::
738    Interrupt processing that is time consuming, or involves blocking,
739    should be handed off to a thread. See `Offloading ISR Work`_ for
740    a description of various techniques that can be used in an application.
741
742Configuration Options
743*********************
744
745Related configuration options:
746
747* :kconfig:option:`CONFIG_ISR_STACK_SIZE`
748
749Additional architecture-specific and device-specific configuration options
750also exist.
751
752API Reference
753*************
754
755.. doxygengroup:: isr_apis
756