13
$\begingroup$

When an interrupt occurs, the processor preempts the current process and calls kernel code to handle the interrupt. How does the processor know where to enter the kernel?

I understand that there are interrupt handlers which can be installed for each interrupt line. But since the processor only executes 'hardwired logic', there has to exist some predefined place that points to either an interrupt handler itself, or some code that executes before the handler (since there can be multiple handlers for one interrupt line, I assume the latter).

$\endgroup$

migrated from operatingsystems.stackexchange.com Sep 11 '14 at 12:37

13
$\begingroup$

On startup, the kernel will initialize an interrupt vector table (called an interrupt descriptor table or IDT on x86) that points to an interrupt handler for each line.

Before the 80286, the IDT was always stored at a fixed address; starting with the 80286, the IDT is loaded using the LIDT instruction.

Interrupt vector tables point to a single handler per interrupt line; that being said, a kernel could choose to, for example, provide an interrupt handler that runs several other interrupt routines, or provide a single handler that covers some or all interrupts. Linux does these things by providing a generic interrupt handler that determines which interrupt line was called and finds the appropriate downstream handler to call.

$\endgroup$
  • 1
    $\begingroup$ so the processor uses the interrupt line as index to the IDT, puts the entry in the PC and starts executing? but isn't there a generic function that runs before all interrupt handlers? for linux it would be do_IRQ(). is this the function that every IDT entry points to, no matter the interrupt line? $\endgroup$ – Philipp Murry Aug 19 '14 at 21:02
  • $\begingroup$ @PhilippMurry yes. The kernel then uses its own set of interrupt handlers (of which there can be more than one per line) to actually handle the interrupt, before returning to the previously executing code. $\endgroup$ – Adam Maras Aug 19 '14 at 21:11
  • $\begingroup$ okay, so there are actually two types of interrupt handlers: those that the processor calls (always do_IRQ()), and those that the kernel calls (the one's i've registered via request_irq()). could you maybe add this to your answer? i think then i will accept it :) thanks a lot $\endgroup$ – Philipp Murry Aug 19 '14 at 21:19
  • 1
    $\begingroup$ @PhilippMurry I'm not an expert on how Linux handles interrupts (and how kernel developers tap into that system) but I added some further information in a more broad sense about how kernels can have their own ISR management. $\endgroup$ – Adam Maras Aug 19 '14 at 21:31
12
$\begingroup$

Yes, there is a predefined place that contains the address of code to jump to: an interrupt vector. Depending on the processor, this can be a specific location in physical memory (8088), a specific location in virtual memory, a processor register, a location in memory indicated by a register (ARM, 386), …

The details vary on different processors, but the main common elements to handling an interrupt in the processor are:

  • Mask interrupts (so that any subsequent interrupt will have to wait).
  • Set the processor mode to kernel or interrupt mode (if the processor has such modes).
  • Save the value of the program counter to a known place (register or memory).
  • Possibly save the value of other registers, or switch between register banks).
  • Execute the next instruction (at the new PC value).
$\endgroup$
1
$\begingroup$

The other two answers (at the time of writing) talk about interrupts and the IDT. This is correct, however, on a modern Intel-esque CPU, there are no fewer than three ways to call into a kernel.

Method #1: Interrupts.

This is explained above. You set up an entry in the interrupt descriptor table/interrupt vector, and then execute a software interrupt to enter the kernel.

The main advantage of this method is that a typical kernel needs to be able to handle interrupts anyway, and it works on archaic hardware.

Method #2: Call gates.

A call gate is a special kind of segment selector. The target of the call needs to be loaded in the global or local segment descriptor table (GDT and LDT respectively). If you then perform a far call instruction using the call gate as the segment (the offset of the call is ignored), this allows you to call more privileged code. Call gates are extremely flexible; the IA-32 architecture has four privilege levels, and call gates let you call any level.

I don't believe that Linux ever used call gates, but Windows 95 did. Win95 kernel services (krnl386.exe and kernel.dll) actually ran in user mode (ring 3). The highest privilege level (ring 0) was only used for drivers and a microkernel which performed only process switching. Calling into drivers was done using call gates. This allowed legacy 16-bit code (of which there was a lot!) to use Win95 drivers just using a standard far call, just like they always did.

Inadequate protection of the global descriptor table was the cause of several Windows 95 exploits, which managed to install their own call gates by writing over memory.

Method #3: SYSCALL/SYSRET and SYSENTER/SYSEXIT

These are two sets of instructions, independently invented by AMD and Intel, but they essentially do the same thing. SYSCALL/SYSRET came first and was AMD-only, SYSENTER/SYSEXIT was Intel, but AMD implements it now. So I'm going to describe SYSENTER/SYSEXIT.

Unlike call gates, SYSENTER can only be used to transfer to ring 0, and can only transfer to one location. However, it has the advantage of being extremely low-latency because unlike a call or interrupt it doesn't touch the stack.

The transfer location is set up using three model-specific registers: one for the segment information, and one each for the instruction pointer and stack pointer of the kernel code. Because nothing is "pushed" onto the stack, the user mode code is responsible for telling the kernel where to return to by passing the return instruction pointer and stack pointer in registers. The kernel is responsible for restoring the stack pointer, and the SYSEXIT instruction restores the instruction pointer.

Further information on the SYSENTER and SYSEXIT instructions.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.