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