Interrupts Basics

During program execution if devices like mouse, keyboard needs service from CPU, device will generate interrupt and gets the service from CPU.

We can connect peripheral devices to same PCI (Peripheral Component Interconnect) Bus. Connected device to PCI bus can again has option to connect other devices. For ex: USB Controller is connected to PCI bus, we can connect more USB based devices to this USB controller. In this way when user wants to communicate with the device (In case of Interactive device) which is connected to USB Controller, Operating system will send data to USB Controller using PCI bus. This USB Controller knows how to communicate with each connected USB device using standard protocol.

During booting of the Operating System, OS will enumerate all connected devices on PCI bus including USB devices connected to USB controller. After completion of enumerating devices on PCI bus, Operating System will check its configuration which drivers are calming the each of these devices and loads driver. Driver knows to connect to its own devices through Operating System DDK functions. In WinNT, it uses IoConnectInterrupt() to connect to any interrupt. This function takes ISR callback, where Operating systems will callback when interrupt occurs from device.

Mapping of Interrupts like exceptions or interrupts has done using IDT (Interrupt Descriptor Table). If there is interrupt, CPU will suspend the current program execution and transfer control by looking at IDT table for Interrupt Handler. In 255, many interrupts are unused. IDT Descriptor size is 64 bits and IDT table can store anywhere in Linear address space. IDT is accessed through IDTR register. This register will have IDT Base address and IDT Limit. IDT Descriptor can be used for Task Gate Descriptor, Interrupt Gate Descriptor and Trap Gate Descriptor.

Interrupt generation happens in software using INT Instructions and in hardware, processor receives interrupt event in INTR pin. Both of the software and hardware interrupts are going to use same IDT. Consider INT 1 instruction is for single step purpose and hardware IRQ (Interrupt Request) 1 is for keyboard. When there is any keyboard interrupt, processor receives signal through INTR pin from APIC (Advanced Programmable Interrupt Controller). How does ISR know which one to call? Trap/Fault handler of INT 1 or ISR of keyboard?. This is completely depend on the IF (Interrupt Flag) in EFLAGS. If flag IF is enabled, then it calls the ISR of keyboard or else it is going to call INT 1 single step Trap/Fault handler.

Using STI (Set Interrupt Flag) or CLI (Clear Interrupt Flag) you can enable/disable Interrupt Flag (IF) in EFLAGS. These 2 instructions are privileged and can execute only in kernel mode or if the CPL (Current Privileged Level) is equal to or less then the IOPL (Input/Output Privileged Level). If there is less privilege or user mode executes these instruction it will result in General Protection exception.

You can share same IRQ with different hardware; this sharing is done through the hardware and software support. While connecting to any hardware in your driver using IoConnectInterrupt() DDK function, you need to specify whether others can share this IRQ or not.

Example: You want to share IRQ-1 with 2 hardware, when some device interrupt CPU, CPU will check what kind of interrupt based on the INTR pin which it got signal and then identified the index number in IDT, then transfers the control immediately. But, how does it know which hardware to transfer? For this reasons, This IRQ-1’s ISR will have Operating system code by default, which it gets control from the CPU, then calls each driver, if driver don’t own this device it just returns FALSE, it continues calling all the callbacks till it gets result of TRUE. TRUE means that driver owns that device. This way, any number of devices can share the same IRQ.