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