1. Interrupts:
We'll cover the whole interrupt stuff in two sections:
Interrupt setup - Explanation of Generic and architecture specific setup that kernel does.
Interrupt handling - Explanation of what happens after processor receives an interrupt.
[MMU is enabled before we reach here]
1. Interrupt setup:
Interrupt setup can also be divided into 2 parts:
Setting up for the processor
Setting up for the linux
The first step for system to start handling interrupt is setting up the interrupt vector table
and vector stubs.
When interrupt occurs processor sets the pc (program counter) to specific memory
address. Interrupt vector table needs to be placed at this location.
Entries in the vector table are instructions that will branch to specific routines designed to
handle the particular interrupt.
ARM:
Trap_init function, which is called from start_kernel, is responsible for setting up the
interrupt vector table at location 0xffff0000. Ideally the vector table is at 0x00000000
location but can located at higher address. So Linux uses this in case of ARM and copies
the table to 0xffff00000.
Before copying need to flush the icache for address 0xffff0000 of size equal to PAGE
SIZE.
There are 7 exceptions/interrupt:
Reset
Undefined instruction
Software interrupt(SWI)
Prefetch abort
Data abort
Interrupt request
Fast interrupt request
In ARM the code snippet of vector table looks like this:
File: entry-armv.S,
----------------------------------------------------
.equ __real_stubs_start, .LCvectors + 0x200
.LCvectors:
swi SYS_ERROR0
b __real_stubs_start + (vector_und - __stubs_start)
ldr pc, __real_stubs_start + (.LCvswi - __stubs_start)
b __real_stubs_start + (vector_pabt - __stubs_start)
b __real_stubs_start + (vector_dabt - __stubs_start)
2. b __real_stubs_start + (vector_addrexcptn - __stubs_start)
b __real_stubs_start + (vector_irq - __stubs_start)
b __real_stubs_start + (vector_fiq - __stubs_start)
ENTRY(__trap_init)
stmfd sp!, {r4 - r6, lr}
mov r0, #0xff000000
orr r0, r0, #0x00ff0000 @ high vectors position
adr r1, .LCvectors @ set up the vectors
ldmia r1, {r1, r2, r3, r4, r5, r6, ip, lr}
stmia r0, {r1, r2, r3, r4, r5, r6, ip, lr}
add r2, r0, #0x200
adr r0, __stubs_start @ copy stubs to 0x200
adr r1, __stubs_end
1: ldr r3, [r0], #4
str r3, [r2], #4
cmp r0, r1
blt 1b
LOADREGS(fd, sp!, {r4 - r6, pc})
All Exception handlers will be at +0x200 offset from starting address of vector table.
Setting up for Kernel:
Init_IRQ function will initialize irq structures and perform the interrupt initialization.
irq_desc is the interrupt descriptor.
System will define the array elements of irq_desc corresponding to the number of
interrupts defined for system.
Setup the interrupt unitization function callback (arch_init_irq). The system
interrupt init function is statically defined in MACHINE_START.
o This function is responsible of initializing the interrupt controller and
setting up low level functions like chip acknowledgment.
ARM has number of hard interrupts for which it requires to setup handler for each or a
default handler as entry point. At this point either interrupt handlers need to be setup
which will be called when interrupt is triggered to the processor or setup the default
handler. The other option is to register entry function that will help in maintining the ISR
design generic.
There are primarily two types of interrupts trigger mechanism:
Level triggered
Edge Triggered
For further understanding refer: http://en.wikipedia.org/wiki/Interrupt
Setup do_level_IRQ ( more commonly used ) as IRQ handlers entry function using
kernel function set_irq_handler.
3. Device drivers can now register IRQ handlers with request_irq.
Request_irq will now add the ISR handler to the list of IRQ handlers registered to a
particular IRQ line.
Some devices can be statically connected on specific interrupt line like timer on IRQ0
line. Therefore system timer is not registered in way explained above and has different
flow.
Interrupt Handling:
Once processor receives interrupt, it stops the current execution. Thereon the sequence of
events:
disables IRQ
copies CPSR in SPSR
copies current PC to LR
Switch to IRQ mode ( processor mode- ARM has 7 modes)
Places the vector table address into PC
Jumps to vector handler code. In this case vector_irq for IRQ.
Condier intetrrupt occurred while processor was in Supervisor mode, processor
will switch to SVC mode (supervisor mode)
Irq_svc save the registers (r0-r12) on kernel stack. Kernel stack is nothing but the
respective process kernel stack.
Next step is to identify the irq line/number.
On getting the IRQ details, flow will jump to asm_do_IRQ.
Asm_do_IRQ will call the registered function during interrupt setup –
do_level_irq.
Do_level_IRQ will now call the registered ISR for the respective interrupt line.
Mask the corresponsding interrupt line. Just to highlight interrupts are disables at
the start of the flow,and here we are just masking the particular interrupt line.
If there is ISR registered, __do_irq function will be executed. It will enable the
Interrupts. ( As we have masked the particular interrupt line, so same interrupt
line will not interrupt the processor, rest all can raise interrupt).
Registered ISR is now all set to be executed.
Once ISR is complete, irq_svc will return and restore the processor state by
restoring the registers(r0-r12) values, PC and CPSR.
4. MIPS:
Address of vector table: (0xBFC00000)
Trap_init:
Set up the EBase register. This is processor register that should have base address of the
memory where vector table will be placed for processor. On interrupt signel,processor
will jump to the adresss rang of EBase register
Setup the 32 exception handler array. Register the exception vector handler in one of the
exception array index.
Setting up for Kernel:
Init_IRQ function will initialize irq structures and perform the interrupt initialization.
irq_desc is the interrupt descriptor.
System will define the array elements of irq_desc corresponding to the number of
interrupts defined for system.
Setup the interrupt unitization function callback (arch_init_irq). The system
interrupt init function is statically defined in MACHINE_START.
o This function is responsible of initializing the interrupt controller and
setting up low level functions like chip acknowledgment.
Arch_int_irq - "somewhere in arch/mips/"
set c0 status and cause register
set irq_desc
Set irq controller low level functions:irq_ack,enable,disable,start,shutdown.
Each irq_desc can register the irq_chip functions which defines the IRQ low level
handling.
Setup timer interrupt.
Interrupt Handling:
Handle_int
Plat_irq_dispatch
- call respective registered first level handler
xxx_do_IRQ
do_IRQ
Proc/interrupts – Provides the runtime view on the running system about the system
interrupts.
Interrupt number ---- Number of interrupts generated on CPU0 ---- Interrupt name