Interrupt Descriptor Table - IDT
At a Glance
Interrupts could be thought of as
notificationsto the CPU that tells it thatsome eventhappened on the system. Classic examples of interrupts are hardware interrupts such as mouse button or keyboard key presses, network packet activity and hardware generated exceptions such as a division by zero or a breakpoint - interrupts 0x00 and 0x03 respectivelyOnce the CPU gets interrupted, it stops doing what it was doing and responds to the new interrupt
CPU knows how to respond and what kernel routines to execute for the newly received interrupt by looking up Interrupt Service Routines (ISR) that are found in the Interrupt Descriptor Table (IDT)
IDT is a list of IDT descriptor entries which are 8 or 16 bytes in size depending on the architecture
Pointer to IDT is stored in an
IDTRregister for each physical processor or in other words, each processor has its ownIDTRregister pointing to its own Interrupt Descriptor Table
IDT Location
We can check where the Interrupt Descriptor Table is located in kernel by reading the register IDTR:
r idtr
As noted later, the command !idt allows us to dump the Interrupt Descriptor Table contents and it also confirms that the IDT is located at fffff803`536dda00 as shown below:

Dumping IDT
We can dump the IDT and see addresses of Interrupt Service Routines for a given interrupt. Below is a snippet of the Interrupt Descriptor Table:
Below shows the IDT dumping and ISR code execution in action:
IDT table is dumped with
!idtIRS entry point for the interrupt
a0is located atfffff8008f37f700This is the routine that gets executed first inside the kernel when a keyboard event such as a keypress is registered on the OS
Eventually, the routine
i8042prt!I8042KeyboardInterruptService(inside the actual keyboard driver) is hit once the code atfffff8008f37f700is finished
Putting a breakpoint on
i8042prt!I8042KeyboardInterruptServiceOnce the breakpoint is set, a key is pressed on the OS login prompt and our breakpoint is hit, confirming that
i8042prt!I8042KeyboardInterruptServiceindeed handles keyboard interrupts

Below is a heavily simplified diagram illustrating all of the above events taking place:
the keyboard interrupt
0xa0occursIDT table using index
0x0ais looked up (IDT address + 0xa0 * 0x10) and the ISR Entry Point is resolved and code jumps to itafter some hoops, the code is eventually redirected to the keyboard driver where the interrupt gets handled in
i8042prt!I8042KeyboardInterruptService

IDT Entry
IDT is made up of IDT entries _KIDTENTRY64 which is a kernel memory structure and is defined like so:
Members OffsetLow, OffsetMiddle and OffsetHigh at offsets 0x000, 0x006 and 0x008 make up the virtual address in the kernel and it's where the code execution will be transferred to by the CPU once that particular interrupt takes place - in other words - this is the Interrupt Service Routine's (ISR) entry point.
IDT Entry for the Keyboard Interrupt 0xa0
As an example, let's inspect the IDT entry for the keyboard interrupt which is located at index a0 in the IDT table as discovered earlier:

From earlier, we also know that the IDT resides at fffff803536dd000:
We can get the location of the a0 IDT entry by adding 0xa0*0x10 (interrupt index a0 times 0x10 since a descriptor entry is 16 bytes in size) to the IDT table address fffff803536dd000, which gives us fffff803`536dda00:
With the above information, we can overlay the a0 interrupt descriptor entry with _KIDTENTRY64 and inspect a0 IDT entry's content:
ISR for the Keyboard Interrupt a0
Based on the above IDT entry for the keyboard interrupt, the below re-enforces that the combination of Offset(High|Middle|Low) form the virtual address of the Interrupt Service Routine (ISR) entry point - the code that will be executed when a0 interrupt is triggered by the keyboard:

Below shows the instructions at fffff803`5156e700 (ISR entry point) to be executed by the CPU once interrupt a0 is triggered:
FFFFFFFFFFFFFFA0 will be pushed on the stack
jump to
fffff803`5156ea40will happen

...and eventually, the i8042prt!I8042KeyboardInterruptService will be hit and below confirms it - firstly, the breakpoint is hit for fffff803`5156e700 and i8042prt!I8042KeyboardInterruptService is hit immediately after:

_KINTERRUPT
_KINTERRUPT is a kernel memory structure that holds information about an interrupt. The key member of this structure for this lab is the member located at offset 0x18 - it's a pointer to the ServiceRoutine - the routine (inside the associated driver) that is responsible for actually handling the interrupt:
As an example - from earlier, we know that the ISR for keyboard interrupts is located at ffffd4816353ea00, therefore we can inspect the _KINTERRUPT structure of that our interrupt by overlaying it with memory contents at ffffd4816353ea00:
This allows us to confirm that the ServiceRoutine is again pointing correctly to i8042prt!I8042KeyboardInterruptService inside the keyboard driver:

Finding _KINTERRUPT
In order to manually find the location of _KINTERRUPT for a given interrupt, we need to leverage the following memory locations and structures.
Process Control Region or PCR (_KPCR memory structure in kernel) stores information about a given processor:
_KPCR location can be found like this:
Inside the _KPCR, at offset 0x180 there is a member that points to a Process Control Block memory structure _KPRCB which contains information about the state of a processor.
The key member we're interested when trying to find the _KINTERRUPT memory location for a given interrupt is InterruptObject as it contains a list of pointers to a list of _KINTERRUPT objects. InterrupObject is located at offset 0x2e80 as shown below:
With the above knowledge, we can now find the _KINTERRUPT location for the keyboard interrupt a0:
Below confirms that the _KINTERRUPT for the interrupt a0 we found manually matches that given by the !idt command:

References
Last updated
