From cfffb164d5bb2c8dedefb341a381282d1473a4ee Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Sat, 10 Mar 2018 20:13:22 +0200 Subject: [PATCH] Documentation: lectures: Add draft 'Interrupts' lecture Signed-off-by: Daniel Baluta --- Documentation/teaching/index.rst | 1 + .../teaching/lectures/interrupts.rst | 581 ++++++++++++++++++ 2 files changed, 582 insertions(+) create mode 100644 Documentation/teaching/lectures/interrupts.rst diff --git a/Documentation/teaching/index.rst b/Documentation/teaching/index.rst index 4022467e45e301..e5db3b2d9ba999 100644 --- a/Documentation/teaching/index.rst +++ b/Documentation/teaching/index.rst @@ -37,6 +37,7 @@ then point your browser at **Documentation/output/labs/index.html**. lectures/so2.cs.pub.ro.rst lectures/intro.rst lectures/syscalls.rst + lectures/interrupts.rst labs/vm.rst labs/exercises.rst labs/introduction.rst diff --git a/Documentation/teaching/lectures/interrupts.rst b/Documentation/teaching/lectures/interrupts.rst new file mode 100644 index 00000000000000..b7141b9dae491c --- /dev/null +++ b/Documentation/teaching/lectures/interrupts.rst @@ -0,0 +1,581 @@ +========== +Interrupts +========== + +`View slides `_ + +.. slideconf:: + :autoslides: False + :theme: single-level + +Lecture objectives +================== + +.. slide:: Interrupts + :inline-contents: True + :level: 2 + + * Interrupts and exceptions (x86) + + * Interrupts and exceptions (Linux) + + * Deferrable work + + * Timers + +What is an interrupt? +===================== + +An interrupt is an event that alters the normal execution flow of a program and +can be generated by hardware devices or even by the CPU itself. + +Interrupts can be grouped into two categories based on the source of the interrupt: + +.. slide:: Interrupts + :inline-contents: True + :level: 2 + + * **synchronous**, generated by executing an instruction + * **asynchronous**, generated by an external event + * **maskable** + + * can be ignored + * signalled via INT pin + * **non-maskable** + + * cannot be ignored + * signalled via NMI pin + +Synchronous interrupts, usually named exceptions, handle conditions detected by the +processor itself in the course of executing an instruction. Divide by zero or +a system call are examples of exceptions. + +Asynchronous interrupts, usually named interrupts, are external events generated +by I/O devices. For example a network card generates an interrupts to signal +that a packet has arrived. + +Exceptions +---------- + +There are two sources for exceptions: + +.. slide:: Exceptions + :inline-contents: True + :level: 2 + + * processor detected + + - **faults** + - **traps** + - **aborts** + * programmed + + + - **int n** + +Processor detected exceptions are raised when an abornmal condition is +detected while executing an instruction. + +A fault is a type of exception that is reported before the execution of the +instruction and can be usually corrected. The saved EIP is the address of +the instruction that caused the fault, so after the fault is corrected +the program can re-execute the faulty instruction. (e.g page fault). + +A trap is a type of exception that is reported after the execution of the +instruction in which the exception was detected. The saved EIP is the address +of the instruction after the instuction that caused the trap. (e.g debug trap). + +Hardware +======== + +Programmable Interrupt Controller +--------------------------------- + +.. slide:: Hardware (PIC) + :inline-contents: True + :level: 2 + + .. ditaa:: + + +-----------+ NMI + | | + | |<----------+ + | | + | | +------------+ + | | | | IRQ0 + | | | |<------------+ device0 + | CPU | | | IRQ1 + | | INTR | PIC |<------------+ device1 + | |<----------+ | IRQN + | | | |<------------+ deviceN + | | | | + +-----------+ +------------+ + +A device supporting interrupts has an output pin used for signalling an Interrupt ReQuest. IRQ +pins are connected to a device named Programmable Interrupt Controller (PIC) which is connected +to CPU's INTR pin. + +A PIC usually has a set of ports used to exchange information with the CPU. When a device +connected to one of the PIC's IRQ lines needs CPU attention the following flow happens: + * device raises an interrupt on the corresponding IRQn pin + * PIC converts the IRQ into a vector number and writes it to a port for CPU to read + * PIC raises an interrupt on CPU INTR pin + * PIC waits for CPU to acknowledge an interrupt + * CPU handles the interrupt + +Will see later how the CPU handles the interrupt. Important to notice is that by design PIC won't raise +another interrupt until the CPU acknowledged the current interrupt. + +Each IRQ line can be individually disabled. This allows simplifying design by making sure that +interrupt handlers are always executed serially. + +Advanced Programmable Interrupt Controller +------------------------------------------ + +.. slide:: Hardware (APIC) + :inline-contents: True + :level: 2 + + .. ditaa:: + + + CPU0 CPU1 + +-------------+ +-------------+ + | | | | + | |local IRQs | |local IRQs + | +---------- | +---------- + | | | | + | local APIC | | local APIC | + | | LINT0, LINT1 | | LINT0, LINT1 + | +------------- | +------------- + | | | | + +-------+-----+ +------+------+ + | | + | | + | | + +-------+--------------------------------+------+ + | | + | Interrupt Controller Communication BUS | + +----------------------+------------------------+ + | + | + +--------+--------+ + | | + | I/O APIC | + | | + +--------+--------+ + | + | + | + External interrupts + +With multicore systems, each core has a local APIC used to process interrupts +from locally connected devices like timers or thermals sensors. + +I/O APIC is used to distributed IRQ from external devices to CPU cores. + +After discussing the hardware, now let's see how the processor handles an interrupt. + +.. slide:: Enabling/disabling the interrupts + :inline-contents: True + :level: 2 + + * at the PIC level + + * programming the PIC + * PIC can be programmed to disable a given IRQ line + + * at the CPU level + + * cli (CLear Interrupt flag) + * sti (SeT Interrupt flag) + +Interrupt Descriptor Table +-------------------------- + +The interrupt descriptor table (IDT) associates each interrupt or exception +identifier with a descriptor for the instructions that service the associated +event. We will name the identifier as vector number and the associated +instructions as interrupt/exception handler. + +An IDT has the following characteristics: + +.. slide:: Interrupt Descriptor Table + :inline-contents: True + :level: 2 + + * it is used as a jump table by the CPU when a given vector is triggered + * it is an array of 256 x 8 bytes entries + * may reside anywhere in physical memory + * processor locates IDT by the means of IDTR + +Below we can find Linux IRQ vector layout. The first 32 entries are reserved +for exceptions, vector 128 is used for sycall interface and the rest are +used mostly for hardware interrupts handlers. + +.. slide:: Linux IRQ vector layout + :inline-contents: True + :level: 2 + + .. ditaa:: + + arch/x86/include/asm/irq_vectors.h + +------+ + | 0 | 0..31, system traps and exceptions + +------+ + | 1 | + +------+ + | | + +------+ + | | + | | + | | + +------+ + | 32 | 32..127, device interrupts + +------+ + | | + | | + | | + +------+ + | 128 | int80 syscall interface + +------+ + | 129 | 129..255, other interrupts + +------+ + | | + | | + | | + +------+ + | 255 | + +------+ + +On x86 an IDT entry has 8 bytes and it is named gate. There can be 3 types of gates: + + * interrupt gate, holds the address of an interupt or exception handler. + Jumping to the handler disables maskable interrupts (IF flag is cleared). + * trap gates, similar with an interrupt gate but it does not disable maskable + interrupts while jumping to interupt/exception handler. + * task gates (not used in Linux) + +Lets have a look at several fields of an IDT entry: + + * segment selector, index into GDT/LDT to find the start of the code segment where + the interupt handlers resides + * offset, offset inside the code segment + * T, represents the type of gate + * DPL, minimum privilege required for using the segments content. + +.. slide:: Interrupt descriptor table entry (gate) + :inline-contents: True + :level: 2 + + .. ditaa:: + + 63 47 42 32 + +------------------------------+---+---+----+---+---------------+ + | | | D | | | | + | offset (16..31 | P | P | | T | | + | | | L | | | | + +------------------------------+---+---+----+---+---------------+ + | | | + | segment selector | offset (0..15) | + | | | + +------------------------------+--------------------------------+ + 31 15 0 + + +Interrupt handler address +------------------------- + +In order to find the interrupt handler address we first need to find the start +address of the code segment where interrupt handler resides. For this we +use the segment selector to index into GDT/LDT where we can find the corresponding +segment descriptor. This will provide the start address kept in the 'base' field. +Using base address and the offset we can now go at the start of the interrupt handler. + + +.. slide:: Interrupt handler address + :inline-contents: True + :level: 2 + + .. ditaa:: + + + Interrupt Descriptor + +----------------------------------------------+ + | | + | +------------------+ +--------+ +------+ | + | | segment selector | | offset| | PL | | + | +----+-------------+ +---+----+ +------+ | + | | | | + +----------------------------------------------+ + | | + | | + +-------------+ +----------------------------> +---------------+ + | ^ | ISR address | + | Segment Descriptor | +---------------+ + | +----------------------------------------------+ | + | | | | + +---->| +------------------+ +--------+ +------+ | | + | | base | | limit | | PL | | | + | +---------+--------+ +--------+ +------+ | | + | | | | + +----------------------------------------------+ | + | | + +--------------------------------------------+ + + +Stack of interrupt handler +-------------------------- + +Similar with control transfer to a normal function, a control transfer +to an interrupt or exception handler uses the stack to store the +information needed for returning to the interrupted code. + +As can be seen in the figure below, an interrupt pushes the EFLAGS register +before saving the address of the interrupted instruction. Certain types +of exceptions also cause an error code to be pushed on the stack to help +debug the exception. + + +.. slide:: Interrupt handler stack + :inline-contents: True + :level: 2 + + .. ditaa:: + + + w/o privilege transition w/ privilege transition + + + +---------------------+ +---------------------+ + | | | | | + | | | OLD SS:ESP | OLD SS | NEW SS:ESP from TSS + | +---------------------+ +---------------------+ + | | | | | + | | OLD EFLAGS | | OLD ESP | + | +---------------------+ +---------------------+ + | | | | | + | | OLD CS | | OLD EFLAGS | + | +---------------------+ +---------------------+ + | | | | | + | | OLD EIP | | OLD CS | + | +---------------------+ +---------------------+ + | | | | | + | | (error code) | NEW SS:ESP | OLD EIP | + | +---------------------+ +---------------------+ + | | | | | + | | | | (error code) | NEW SS:ESP + | | | +---------------------+ + | | | | | + | | | | | + | | | | | + | | | | | + | | | | | + | | | | | + | | | | | + v +---------------------+ +---------------------+ + + +Interrupt handler execution +--------------------------- + +.. slide:: Interrupt execution + :inline-contents: True + :level: 2 + + + * check current privilege level + * if need to change privilege level + + * change stack with the one associated with new privilege + * save old stack information on the new stack + + * save error code on stack in case of an abort + * save EFLAGS, CS, EIP on stack + * execute interrupt handler + +Returning from an interrupt +--------------------------- + +IRET is used to from an interrupt handler. IRET is similar with RET except +that IRET increments EIP by extra four bytes (because of the flags on stack) +and moves the saved flags into EFLAGS register. + +.. slide:: Returning from an interrupt + :inline-contents: True + :level: 2 + + * pop the eror code (in case of an abort) + * use IRET + + * pops CS, EIP, EFLAGS + * if privilege level changed returns to the old stack and old privilege level + +Nested interrupts and exceptions +-------------------------------- + +An interrupt handler may preempt both other interrupt handlers and exception handlers. +On the other hand, an exception handler never preempts an interrupt handler. + +.. slide:: Interrupt/Exception nesting + :inline-contents: True + :level: 2 + + .. ditaa:: + + + ^ + | | + | | + User Mode | IRQi | + | | + | | + +-------------------------------------------------------+ + | iret| + | | + Kernel Mode v-------+ ^-------+ ^--------+ + | | | | + IRQj| iret| IRQk| iret| + | | | | + v------+ v-----+ ^-----+ + | | + IRQn | iret| + v-----+ + +.. slide:: Interrupt context + :inline-contents: True + :level: 2 + + * runs as a result of an IRQ (not of an exception) + * there is no 'process' context associated + * can't trigger a context switch + + * no sleep + * no schedule + * no user memory access + +.. slide:: Interrupt handling + :inline-contents: True + :level: 2 + + .. ditaa:: + + + phase 1 + +----------------+ + | critical | phase 2 + +----------------+ +-----------------+ + | | | immediate | phase 3 + | - IRQ disabled | +-----------------+ +----------------+ + | - ACK IRQ +-----+ | | | deferred | + | | +---> - IRQ disabled | +----------------+ + +----------------+ | - device handler| | | + | +-----+ | - IRQ enabled | + +-----------------+ +----> - execute later| + | | + +----------------+ + +Deferrable actions +================== + + +.. slide:: Deferrable actions in Linux + :inline-contents: True + :level: 2 + + + * implemented using deferrable functions + * softIRQ + + * runs in interrupt context + * statically allocated + * same handler may run in parallel on multiple cores + + * tasklet + + * runs in interrupt context + * can be dinamically allocated + * same handler runs are serialized + * workqueues + + * run in process context + +.. slide:: Soft IRQ + :inline-contents: True + :level: 2 + + * init: open_softirq() + * activation: raise_softirq() + * execution: do_softirq() + * it runs + + * after an interrupt handler + * from the ksoftirqd kernel thread + +.. slide:: Types of soft IRQ + :inline-contents: True + :level: 2 + + * HI_SOFTIRQ + * TIMER_SOFTIRQ + * NET_TX_SOFTIRQ + * NET_RX_SOFTIRQ + * BLOCK_SOFTIRQ + * TASKLET_SOFTIRQ + * HRTIMER_SOFTIRQ + +.. slide:: ksoftirqd + :inline-contents: True + :level: 2 + + * minimum priority kernel thread + * runs self raised softirqs + * trade-off between softirqs and process/kernel threads + +.. slide:: Tasklets + :inline-contents: True + :level: 2 + + * implemented on top of soft IRQ + + * TASKLET_SOFITIRQ, HI_SOFTIRQ + * init: tasklet_init + * activation: tasklet_schedule + * masking: tasklet_disable(), tasklet_enable() + +.. slide:: Workqueues + :inline-contents: True + :level: 2 + + * implemented on top of kernel threads + + * TASKLET_SOFITIRQ, HI_SOFTIRQ + * init: INIT_WORK + * activation: schedule_work() + +.. slide:: Timers + :inline-contents: True + :level: 2 + + * implemented on top of TIMER_SOFTIRQ + + * init: setup_timer + * activation: mod_timer + + + + + + + + + + + + + + + + + + + +