Tag Archives | x86 IDT Linux Kernel IRQ Preemptions

Linux Kernel Preemptions in the “Interrupt Context”: The x86 Interrupt Descriptor Table IDT

The term Interrupt / IRQ context in the kernel needs to be considered in the context of X86, and the low-level INTERRUPT and FAULT / TRAP handlers. INTERRUPTS are asynchronous events, FAULTS and TRAPS are programmatically generated events (i.e. can be “pegged” to a specific instruction) .

The purpose of this blog is to create an unambiguous delineation between Faults, Traps and Interrupts (COC Change-Of-Control events) . And then  create a lead-in into a future discussion on the implications to the kernel.

The actual entry into the fault handler is based on the Interrupt Number INT# (14 for Page Fault)… so for Page Fault, the index 14 will be used to index into the Interrupt Descriptor Table (IDT), a “gate descriptor is fetched (which has the Offset / EIP of the IRQ Handler). The Gate points to a “target descriptor”, which will have a Segment Selector , which will be used to fetch a Segment Descriptor per the normal mechanisms described in an older blog below the BASE and the OFFSET get added, and we have the Linear Address of the IRQ Handler…..where control will transfer when a COC events occurs.

In the case of an INTERRUPT (not a FAULT or a TRAP), the INT# is returned from the interrupting device, an INT# it was given at the time of device initialization (we will definitely blog on this later) at the time of request_irq, and the process hardware uses that INT# to vector through the IDT Gizmo.

All COCs “push” the  the following x86 state onto the stack: CS (Code Segment Selector.. see Blog below), EIP (Program Counter) and EFLAGS. However,  in the case of an Interrupt, we really dont know which CS:EIP will be pushed onto the stack, it will be the determined by the hardware as to when the INTR pin is raised inside the processor, and which “Instruction Boundary” that INTR is raised.

In the case of the FAULT (for example a Page Fault), the CS:EIP pushed onto the Stack will belong to the Instruction generating the Page Fault (which could be based on the Instruction fetch, Or an Operand Fetch).

In the case of a TRAP, the CS:EIP belongs to the Instruction following the instruction that generated the trap for operands, and to the Instruction itself when the TRAP is generated on an Instruction Fetch.

Now, the entry into the Kernel for all these events, INTERRUPTS, FAULTS, TRAPS etc etc happen through the same IDT, so the Linux Kernel calls them all IRQ events. The entry point into the “C” part of the Kernel (past the Low-Level interrupt drivers in entry_32.S) when preemption may be needed is unified for all these events, and  is preempt_schedule_irq.

However, the state  with which the Linux kernel will enter preempt_schedule_irq will be different based on whether the entry is in the INTERRUPT context or not. For discussion later.  Regardless, an entry into this routine is grounds for a “Preemption”.  Remember, these Preemptions are caused by IRQs.

We will  discuss “non-IRQ” Kernel-induced preemptions later also.

All this is probably a good review for our students. We explain these specific x86 features, Linux Kernel concepts and more in detail in my classes ( Advanced Linux Kernel Programming @UCSC-Extension), and also in other classes that I teach independently. Please take note, and take advantage also, of upcoming training sessions. As always, Feedback, Questions and Comments are appreciated and will be responded to. Cheers  Carlos !

 

Comments { 0 }