Interrupt priority is 0-0xF
Each CPU core has 32 software interrupts that are private and belong to that core. These interrupts are numbers 0-0x1F for each core. The hardware interrupts are not core-specific and start at interrupt ID 0x20.
|0x5||Kernel||MPCore software-interrupt. Does apparently nothing.|
|0x6||Kernel||MPCore software-interrupt. Extensively used by KernelSetState (and contains most of the actual code of the latter).|
|0x8||Kernel||MPCore software-interrupt. Used for scheduling.|
|0x9||Kernel||MPCore software-interrupt. Used by, e.g., FlushProcessDataCache.|
|0xF||dmnt/debugger||MPCore software-interrupt. Used to abstract FIQ (debug). This interrupt is never sent to core2 nor core3 on N3DS.|
|0x1E||Kernel||MPCore watchdog - set when the watchdog counter reaches 0 in timer mode, causes interrupt 30 to set as pending. Only set on core 1 as core 1's timer is used for everything.|
There are 0x60 hardware interrupts starting at 0x20 and continuing up to 0x7F. These are not private and are accessible from any core.
|0x40||nwm||WIFI SDIO Controller @ 0x10122000|
|0x42||nwm_dev?||WIFI SDIO Controller @ 0x10100000|
|0x4B||camera||Y2R Conversion Finished|
|0x52||pxi, TwlBg||Send Fifo Empty|
|0x53||pxi, TwlBg||Receive Fifo Not Empty|
|0x60||gpio, TwlBg||Asserted when shell is opened?|
|0x62||gpio, TwlBg||Asserted when shell is closed?|
|0x64||gpio, TwlBg||Headphone jack plugged in|
|0x70||gpio, TwlBg||Headphone jack plugged out|
|0x71||gpio, TwlBg||MCU (HOME/POWER pressed)|
There are 2 tables in the ARM11 kernel: the first has 32 * 2(or 32 * 4) 8-byte entries. This table is for the private interrupts that belong to each core. The data for each interrupt can be found by doing table_base + (core_num * 0x100) + (intr_num * 8). The second table is for public hardware interrupts and the data for each interrupt can be retrieved by doing table_base + (intr_num * 8).
|0x0||InterruptEvent *||Pointer to the InterruptEvent object for that interrupt|
|0x4||u8||Interrupt will be masked by the IRQ handler as soon as it is acknowledged|
|0x5||u8||Interrupt is masked|
Interrupt Table (New3DS)
(0xFFF318F4 in 10.3)
|0x0||InterruptData||Data for all hardware and software interrupts|
|0x700||KThread*||Thread currently acting on the interrupt table|
|0x704||s16||Error tracker for thread above|
Abstract base class for interrupt events.
|0x0||void **||Pointer to vtable|
The first method in the table is
virtual KInterruptEvent* InterruptEvent::getKInterruptEvent(u32 interruptID) = 0. It's actually the function called by the IRQ handler, which returns a KInterruptEvent to signal.
If NULL or 1 is returned, no event will be signaled. If NULL is returned, no post-interrupt rescheduling will be done.
The second method is
virtual void InterruptEvent::signalEvent(void) = 0, which signals the associated KEvent object.
The kernel uses the KInterruptEvent field of a KEvent when binding public interrupts per svcBindInterrupt request, whereas it internally uses a static object of another subclass to bind interrupt 0x0F (FIQ abstraction).