7. IRQ and PIC ENGI 3655 Lab Sessions
Jan 08, 2018
7. IRQ and PICENGI 3655 Lab Sessions
Richard Khoury 2
Textbook Readings Interrupts
◦ Section 13.2.2
Richard Khoury 3
Interrupts Last week, we learned about interrupts
◦ Two kinds, software and hardware◦ Software signal errors◦ Hardware signal that a device needs attention
We coded routines to handle interrupts◦ 256 interrupt descriptors in the IDT◦ Special routine for the first 32 interrupts, default
handler for the others This week, we move on to hardware
interrupts
Richard Khoury 4
Hardware Interrupts
I/O Controller
Input or output ready, or error
Translate IRQ into Interrupt no.Send IRQ
Signal CPU’s Interrupt Request
line
Execute instruction
Check IR line
Execute instruction
Check IR line
Jump to location pointed in IDT
Save state information
Interrupt Handler Routine
Restore state information
Perform regular I/O functions
Programmable Interrupt Controller (PIC)
CPU
OS
Execute instruction
Richard Khoury 5
PIC Programmable Interrupt
Controller receives interrupts from system, asserts priority, and notifies the CPU◦ You should guess that it is
system-specific The Intel PIC is the 8259A chip
◦ Can handle 8 IRQs – insufficient for a modern computer
◦ Motherboard has two cascading 8259A chips, a master and a slave
Richard Khoury 6
Default Hardware InterruptsMASTER PIC IRQ 0: Programmable
Interval Timer (PIT) IRQ 1: Keyboard controller IRQ 2: Cascade from slave
PIC IRQ 3: Serial Port COM2 IRQ 4: Serial Port COM1 IRQ 5: Parallel Port LPT2 IRQ 6: Floppy disk controller IRQ 7: Parallel Port LPT1
SLAVE PIC IRQ 8: Real-Time Clock IRQ 9: CGA Retrace IRQ 10 is reserved IRQ 11 is reserved IRQ 12: PS/2 Mouse controller IRQ 13: Math coprocessor IRQ 14: Hard disk controller 1 IRQ 15: Hard disk controller 2
Handling IRQs We will need a function to set up IRQ
handling in our OS◦ Called by the HAL after the GDT and IDT
initialization functions Three steps
◦ Remap the PIC’s interrupt numbers◦ Install interrupt descriptors for the IRQ in the IDT◦ Initialize the values of variables needed for the
default IRQ functions
Richard Khoury 8
Remapping Interrupts The first thing we need to do is map IRQ 0-
15 to interrupts 0-255 in the IDT◦ By default, IRQ 0-7 are mapped to interrupts 8-15,
and IRQ 8-15 are mapped to interrupts 112-120◦ Not good; interrupts 8-15 are already used, and
this will lead to conflicts Recall from last week: 0-18 are already
used, 19-31 are reserved by Intel◦ So we will remap IRQ 0-15 to interrupt 32-47
Richard Khoury 9
Remapping Interrupts We will need to reinitialize the two PICs As with any chip, this will require us to write
data into the ports◦ Each PIC has a command port and a data port
Master PIC command port: 0x20, data port 0x21 Slave PIC command port: 0xA0, data port 0xA1
Recall: we have a port-writing function in our HAL◦ port.h/.c
Richard Khoury 10
Remapping Interrupts Initialization of a PIC is done by sending four
successive Initialization Control Words (ICW) The details are in the specs (on the website) ICW1 is the initialization command word (goes to
the command port)◦ Hints: Call address interval does not apply for us, and
we are using the PIC in edge triggered mode ICW2 is the new IDT value of the first IRQ to each
chip (data)◦ The next IRQ of the PIC will have the following seven
interrupt values◦ We will use 32 for the master and 40 for the slave
Richard Khoury 11
Remapping Interrupts ICW3 is the IRQ pin connecting the master
and the slave (IRQ2) (data)◦ Hint: remember that C does not handle binary
numbers directly, unlike Assembly! ICW4 defines the PIC behaviour (data)
◦ Hints: we will use normal end-of-interrupt (EOI) operations, we will not use buffered mode, and Special Fully Nested Mode only applies if there are more than 2 PIC
Richard Khoury 12
Remapping Interrupts After we’re done reinitializing the PICs, we
can clear the data port to zero◦ Or restore the previous state if we saved it before
initialization After that, the IRQs are mapped to
interrupts 32-47 So we have to update the information in the
IDT◦ Without modifying the code of IDT.c/.h◦ That’s something we learned last week!
Richard Khoury 13
Installing IRQs Recall: function i86_install_ir
◦ Writes an interrupt descriptor in the IDT and maps it to a function, the interrupt handler routine (IHR)
◦ We’ll use it to install the IRQ handler routines to interrupts 32-47
Recall: The IHR is a three-part function◦ Low Part is a global, interrupt-specific, Assembly
function that pushes the interrupt number and error code on the stack and calls the Common Part
◦ Common Part is a common Assembly function that pushes all the registers on the stack and calls the Top Part
◦ Top Part is a C function that receives the registers as argument and takes interrupt-specific action
◦ That’s what our IRQ handler routines will be as well
Richard Khoury 14
IRQ Handler Functions Structure of Low Part
◦ Identical to ISR function except we need to differentiate the IRQ number and interrupt number
_irq#: push byte 0 push byte ## jmp irq_common_stub
◦ Where ## = 32 + # Structure of Common Part
◦ Identical to ISR function except we call the irq_handler function instead of the fault_handler function
Richard Khoury 15
IRQ Handler Functions Structure of Top Partvoid irq_handler(struct isrregs *r){
◦ Execute hardware’s handler function, or default handler if none is available
◦ Send end-of-interrupt signal to PIC◦ Do NOT run an infinite loop
}
Richard Khoury 16
IRQ Handler Functions Each IRQ corresponds to a piece of
hardware When we install each of them we will write a
handler for it So for now, we need to make sure that our
OS’s IRQ functions can allow us to install and uninstall custom IRQ handler functions
Richard Khoury 17
IRQ Handler Functions There are 16 IRQs, so we will create an array of 16
pointers to handler functionsvoid *irq_routines[16]; Installing and uninstalling a handler function for an
IRQ is simply changing the corresponding pointervoid irq_install_handler(uint32_t irq, void (*handler)(struct isrregs *r))
{ irq_routines[irq] = handler; }
void irq_uninstall_handler(uint32_t irq){ irq_routines[irq] = 0; }
Richard Khoury 18
IRQ Handler Functions Initially, the pointers will all be 0
◦ We haven’t installed any hardware yet! Don’t forget to initialize them at 0 in the end
of the IRQ initialize function!
Richard Khoury 19
IRQ Handler Functions First function of Top Part: Checks the registers it received in
argument and retrieves the IRQ handler pointer corresponding to the correct interrupt
If not zero, call that function (pass registers as argument, as the handler function will need them)
If zero, take default action◦Create an array of messages and display
the one corresponding to the interrupt number
Richard Khoury 20
End Of Interrupt Signal Second function of the Top Part The EOI signals to the PIC that the interrupt
has been dealt with It’s a command word that has to be written
in the PIC command port◦ Which PIC?◦ IRQ 0-7, Master PIC ◦ IRQ 8-15, both PICs, because Slave PIC is
connected to Master PIC The command word is 0x20
Richard Khoury 21
Lab Assignment Write IRQ.h & IRQ.c You need an i86_irq_initialize function
◦ Called by cpu_initialize after initializing the IDT
◦ Reinitialize the PICs◦ Installs new descriptors for ints 32-47 in the IDT◦ Sets the IRQ handler pointers to 0
You’ll also need all the functions described◦ Install/Uninstall IRQ handler pointers◦ Top Part of the IRQ handler function◦ Array of pointers to IRQ handler functions
Add to GlobalCFunctions.inc◦ 16 Low parts and 1 Common part of the IRQ
handler functions
Richard Khoury 22
Lab Assignment Don’t forget to call the IRQ initialization function
from the CPU initialization function Otherwise it won’t do anything
Once you’re done (and if you did it correctly) it’s now safe to reinitialize interrupts◦ Recall: we had cleared them with the CLI command in the
bootloader before going into protected mode◦ We can restore them by adding this line in main(), after
initializing the HAL__asm__ __volatile__ ("sti");
If we did this previously, our OS crashed◦ Now, our OS immediately detects an IRQ0 ◦ We’ll deal with that next week
Richard Khoury 23
Lab Assignment So for this lab, you:
◦ Write IRQ.c/IRQ.h◦ Add functions in GlobalCFunctions.inc◦ Add one line in i86.c◦ Add one line in main.c
You should not be changing any other files◦ Especially IDT.c/IDT.h