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