ECE391- Computer System
Engineering
Lecture 11
Copyright By PowCoder代写 加微信 powcoder
Linux abstraction of PIC (cont)
University of Illinois at Urbana- Champaign
Announcements
• If an online student wishes to attend the in-person exam,
they must email by the
end of Thursday (9/23).
• If any student has a conflict, please also email the professors
with your proof of conflict and availability by the end of
Thursday (9/23).
• NO Lecture on Tuesday, September 28
• Review Session
• EXAM I – Wednesday, September 29th, 7:00pm-9:00 PM
• Location: ECEB 1002
• MP2 Posted – All checkpoints should be committed to the
master(main) branch on GitLab by:
• Checkpoint 1: 5:59PM on 10/5
• Final Checkpoint: 5:59PM on 10/12
Exam 1 info for online students
• Your first exam is on Wednesday 9/29 at 7pm-9pm CST
(same as in-person).
• The exam will be distributed on compass at 6:55pm on the
• You will be asked to join a zoom meeting and share
your screen with the camera on that shows your hands
and above.
• The zoom link will be announced later.
• Once you are done with the exam you have to
scan/take pictures of your solution and upload on
• You will have additional 10 minutes for this, so you should
finish uploading by 7:10pm.
Lecture Topics
• Linux abstraction of PIC
• General interrupt abstractions
• Linux interrupt system
• data structures
• handler installation & removal
• invocation
• execution
• tasklets
Interrupt Descriptor Table (IDT)
• Before the kernel
enables interrupts it
must initialize the idtr
register to point to the
IDT table (set by the kernel
using lidt instruction)
• Kernel initialization
(setup_idt()) fills all
the 256 entries of IDT
with the provisional (or
null) handler
• Associates the interrupt line
with the int. handler routine.
• 256 entries (each 8-bytes) or
descriptors; each corresponds
to an interrupt vector
• hardware interrupts mapped
into vectors 0x20 to 0x2F
• All Linux interrupt handlers are
activated by so called: interrupt
gates (a descriptor type)
• Whenever an interrupt gate is
hit, interrupts are disabled
automatically by the processor
interrupt[x]
irq_desc Array
• Every interrupt vector has its
own irq_desc_t
descriptor
• Descriptors are grouped
together in irq_desc array,
a data structure supported
• When a device driver calls
the request_irq()
function a new structure to
represent the handler is
allocated and initialized
IRQ descriptor array (irq_desc)
action list
disable depth
device name
struct irqaction
flow handler
Basic functions
• Installing an interrupt handler
• Uninstalling an interrupt handler
• Interrupt invocation
• Interrupt Execution
device name
Add the new action structure
to the link list of actions
Upon failure free the action structure
Dynamically allocate
new action structure for
linked list of actions
Fill in the new
action structure
irq # (0-15 for PIC)
bit vector
pointer to interrupt handler
pointer to device-specific
human-readable device name
Linux’ request_irq
(kernel/irq/manage.c)
Comments on request_irq
• Arguments
• irq – irq # (0-15 for PIC)
• handler – pointer to interrupt handler with following arguments
• dev_id pointer (type void*)
• handlers should return 1 if handled, 0 if not
• irqflags – bit vector
• IRQF_SHARED – interrupt chaining is allowed
• IRQF_DISABLED – execute handlers with IF=0
• IRQF_SAMPLE_RANDOM – use device timing as source of random
• devname – human-readable device name (visible in
/proc/interrupts)
• dev_id – pointer to device-specific data (returned to handler when
Comments on request_irq
• Start by checking values
• Dynamically allocate new action structure for
linked list of actions
• Fill in the new action structure
• Try to add it
• using setup_irq
• if call fails, free the action structure
Critical section begins
Critical section ends
New action is added at the end of the link list
Startup PIC for this interrupt
Create new /proc/irq/
action list
disable depth
flow handler
descriptor
human-readable name
startup function
shutdown function
disable function
enable function
(+ several others…)
mask function
mask_ack function
unmask function
jump table
Add handler subdirectory in /proc/irq/
Linux setup_irq
(kernel/irq/manage.c)
Comments on setup_irq
• Start with a couple of sanity checks
• If random sampling flag is set
• initialize as source of random numbers
• good random numbers are hard to find!
• devices such as disks can be used because of “random”
rotational latency to read data (for example)
Comments on setup_irq (cont.)
• Critical section (most of function)
• blocks other activity on descriptor
• uses irqsave/restore to allow handlers to be added from
any context
• Note that new action goes at the end of the linked
list, not the start
• Interrupt chaining only allowed
• if all handlers agree to it
• otherwise only first handler is successfully added
Comments on setup_irq (cont.)
• If this handler is the first
• make sure that PIC jump table has proper default
• clear some status flags
• clear any previous software disablement (depth)
• call the PIC startup function
• After critical section
• create /proc/irq/
• add handler subdirectory in /proc/irq/
Free the action structure
Linux free_irq
(kernel/irq/manage.c)
Comments on free_irq
• Arguments
• irq – irq # (0-15 for PIC)
• dev_id – MUST match pointer value used in request_irq
• Start by checking arguments
• Critical section starts to prevent manipulations of
descriptor
• blocks interrupt from starting to execute
• (interrupt may already be executing on another
processor)
Comments on free_irq (cont.)
• Search for action in list
• based on dev_id pointer
• hence need for matching pointer
• passing NULL dev_id not allowed with chained interrupts
• Once found (notice that most of the loop executes
exactly once)
• remove the action
• if this action/handler was the last for this interrupt,
• turn on software disablement
• (doing so signals interrupts waiting for descriptor lock
to abort once they obtain the lock)
• call the PIC shutdown function
Comments on free_irq (cont.)
• Remove the /proc/irq/
• On an SMP
• interrupt may be executing on another processor
• need to wait for it to finish after releasing descriptor
• Finally, free the action structure
Interrupt Invocation
interrupt[4]
PUSHL $0xFFFFFFFB
JMP common_interrupt
save all regs
linkage to C func
ESP->EAX (first arg.)
call do_IRQ
JMP ret_from_intr
context switch?
restore all registers
Saves the IRQ
through negative
(-5 in the example)
movl %esp, %eax
Interrupt Invocation (cont.)
• Why funnel all IRQs into one piece of code(instead
of producing one function per IRQ) ?
• kernel code/size versus speed tradeoff
• perhaps no big deal for 16
• keep in mind that you’re saving a tiny number of instructions
• APIC used by most SMPs has 256 vectors
• Signature for do_IRQ
fastcall unsigned int do_IRQ
(struct pt_regs* regs);
• fastcall macro in Linux tells gcc to pass args in EAX, EDX,
• EAX points to saved registers (regs argument)
• saved registers already on stack
• note that processor clears IF when it takes an interrupt
• EFLAGS stored by processor include original IF value
Interrupt Invocation (cont.)
Linux do_IRQ
arch/i386/kernel/irq.c
fastcall convention used to pass arguments in registers;
reduces the number of memory accesses required for the call
call interrupt flow handler handle_level_irq for all 8259A interrupts
Exit irq context and process softirqs if needed
gets the interrupt number from the orig_eax filed in the regs structure
Increments counter of nested interrupt handlers
Record registers at time of interrupt
• Value pushed by irq-specific code re-converted to find
• Start with a sanity check
• set_irq_regs calls record registers at time of
• per-CPU storage
• Example use: CPU state accounting on timer interrupts
• Chained via local old_regs
Comments on do_irq
• irq_enter / irq_exit
• necessary for proper priority
• e.g., second hard interrupt occurs
• after new interrupt handled, should return to first
• must delay processing of soft interrupts
• irq_exit processes soft interrupts when appropriate
Comments on do_irq (cont.)
• Central component
• call interrupt flow handler
• handle_level_irq for all 8259A interrupts
• Return value ignored (probably intended to indicate interrupt
Comments on do_irq (cont.)
Critical section begins
Critical section ends
Critical section ends
Call PIC’s mask_ack function
If interrupt already in progress, do nothing
Atomically decide whether to execute handlers
Set status for execution: in-progress and no longer pending
Handler execution done via handle_IRQ_event
Critical section begins
When done, remove in-progress flag
and unmask on PIC (unless disabled)
Linux handle_level_irq
kernel/irq/chip.c
• Critical section starts
• to read descriptor status and action (handler) list
• IF=0 at this point (set by processor when taking interrupt)
• Immediately call PIC’s mask_ack function (via a
wrapper function)
• If interrupt already in progress, do nothing
• Interrupt already re-masked and re-acknowledged on PIC
• extra interrupt can be lost [makes no sense of edge triggered]
• Remove software replay and autoprobe flags
• Kernel statistics track # of interrupts seen (see
/proc/interrupts)
Comments on handle_level_irq
Comments on handle_level_irq
• Atomically decide whether to execute handlers
immediately
• do so if handler defined and not disabled by software
• if not, skip to end
• mark as pending and end interrupt handling
• replayed after last nested enable_irq call
• Set status for execution: in-progress, and no longer
• Handler execution done via handle_IRQ_event
• done without descriptor lock
• allows handlers to use infrastructure
• e.g., enable_irq/disable_irq,
request_irq/free_irq
• usually done with IF=1 (changed inside
handle_IRQ_event)
• done without descriptor lock
• otherwise this code can deadlock with self
• When done, remove in-progress flag and unmask on
PIC (unless disabled)
Comments on handle_level_irq
call translates basically to STI
(local means “on this CPU”)
Walk through list; call each handler
(return value 1 means handled)
Turn interrupts back off (IF=0 / CLI)
Linux handle_IRQ_event
kernel/irq/handle.c
• Set IF=1 unless the first handler asked to be
executed with IF=0
• indicated by IRQF_DISABLED flag
• call translates basically to STI (local means “on this
• Walk through list
• call each handler
• return value 1 means handled
• Generate random numbers if desired
• Turn interrupts back off (IF=0 / CLI)
Comments on
handle_IRQ_event
• IRQ_PENDING—interrupt raised by hardware;
waiting to be executed
• IRQ_INPROGRESS—some processor is executing
• IRQ_DISABLED—interrupt disabled in software;
postpone execution
• IRQ_REPLAY—software replay of previously
postponed execution
Summary on Descriptor Flags
Soft Interrupts in Linux
linux/interrupt.h and kernel/softirq.c
• When are soft interrupts executed?
• after a hard interrupt completes
• periodically by a daemon in the kernel
• seven or eight prioritized types, including high and low tasklet
priorities
• linked list for each tasklet priority
• run on processor on which interrupt is scheduled
• each handler atomic with respect to itself (only)
Soft Interrupts in Linux (cont.)
linux/interrupt.h and kernel/softirq.c
Declaring a handler
name for tasklet_struct
an unsigned long
DECLARE_TASKLET (name, func, data);
void (*func) (unsigned long);
linked list
TASKLET_STATE_SCHED, TASKLET_STATE_RUN
# of disables
pointer to the tasklet function
integer which can be used by the tasklet function
Tasklet Scheduling
• The following two calls schedule a tasklet for execution
void tasklet_schedule (struct tasklet_struct* t);
void tasklet_hi_schedule (struct tasklet_struct* t);
• First form
• schedules tasklet at low priority
• on the executing processor
• Second form schedules at high priority
• Enable and disable calls analogous to hard interrupts
(including nesting)
Tasklet Execution
• do_softirq call
• checks per-processor bit vector of pending priorities (high,
low, etc.)
• executes action for each priority [softirq_vec]
• tasklet_action walks through linked list
[tasklet_hi_action walks through high-priority list ]
• repeats up to 10 times or until no softirqs are raised
Tasklet Execution Atomicity
• Two bits in state changed atomically
• TASKLET_STATE_SCHED – tasklet scheduled for execution
• TASKLET_STATE_RUN – tasklet executing on some processor
• When scheduling
• set TASKLET_STATE_SCHED atomically
• if already set, schedule call does nothing
Tasklet Execution Atomicity (cont.)
When executing, for each tasklet in linked list (at either priority)
A. set TASKLET_STATE_RUN atomically (if already set, stop)
B. check if tasklet is software disabled (count field)
• if so, clear TASKLET_STATE_RUN
• leave the tasklet in the linked list for this priority
• set the pending bit for this priority
• daemon will try again later
C. clear TASKLET_STATE_SCHED
D. execute handler
E. clear TASKLET_STATE_RUN
flags SCHED
execute/step C
(disabled)
execution (execute/step D) occurs in lower two states (and execute/step A fails in these states)
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com