in the name of zero

January 12, 2008

understanding how linux initializes the PIC

Filed under: hermetic studies

i started out trying to understand how the scheduler works, but had to get some
more details in check, the first of which is how linux generates frequent clock
ticks, which brought me to do a refresher to understand how linux programs the
intel 8259A PIC.

the defines being used are at:

arch/i386/mach-generic/io_ports.h
kernel/i8259.c :: void init_8259A(int auto_eoi)

the first piece of code i understood to be an OCW1 trying to mask all the interrupts in both the master and slave interrupt controller by setting all bits
to a ‘1′.

the weird thing is that these two OCWs are issued before any ICWs.. but i may still be missing something here.

outb(0xff, PIC_MASTER_IMR);
outb(0xff, PIC_SLAVE_IMR);

how does this work? well, at io_ports.h, the address of the master PIC is defined as PIC_MASTER_CMD 0x20 and the interrupt mask register
is defined as PIC_MASTER_IMR 0x21, the increment is used so that the A0 line will be a ‘1′ in order for certain ICWs or OCWs that require A0=1 to
work.

OCW1 looks like this:

a0 | d7 | d6 | d5 | d4 | d3 | d2 | d1 | d0
1  | m7 | m6 | m5 | m4 | m3 | m2 | m1 | m0

[ linux master pic init ]

1) outb_p(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */
2) outb_p(0x20 + 0, PIC_MASTER_IMR); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
3) outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); /* 8259A-1 (the master) has a slave on IR2 */

line 1, “outb_p(0x11, PIC_MASTER_CMD)”, sends the initialization command word one to the master pic.
PIC_MASTER_CMD is defined to be 0x20, making a0=0.

the format of the ICW1 looks like:

a0 | d7 | d6 | d5 | d4 | d3   | d2  | d1   | d0
0  | a7 | a6 | a5 | 1  | LTIM | ADI | SNGL | IC4

a7-a5: corresponds to the interrupt vector address if MCS 80/85 mode only
LTIM : 1 = level triggered mode, 0 = edge triggered mode (interrupt polarity)
ADI : 1 = call address interval is 4, 0 = call address interval is 8
SNGL : 1 = single PIC, 0 = cascaded mode (multiple pics, ICW3 will be issued?)
IC4 : 1 = ICW4 will be needed, 0 = otherwise

ICW1 is determined by a0=0 and d4=1 as specified in the above table.

the 0x11 in conjuction with PIC_MASTER_CMD means:
1) master pic operates in edge triggered mode (LTIM=0)
2) ADI is ignored on 8086 mode
3) master pic cascades with another pic (SNGL=0)
4) intialization control word 4 will be issued.

line 2, “outb_p(0x20 + 0, PIC_MASTER_IMR)”, remaps the vector table address to
0x20.

the format of the ICW2 looks like:

a0 | d7 | d6 | d5 | d4 | d3 | d2  | d1 | d0
1  | t7 | t6 | t5 | t4 | t3 | a10 | a9 | a8

and as further detail, the data sheet also presents the contents of the
interrupt vector byte for 8086 system mode.

    D7 D6 D5 D4 D3 D2 D1 D0
IR7 T7 T6 T5 T4 T3 1  1  1
IR6 T7 T6 T5 T4 T3 1  1  0
IR5 T7 T6 T5 T4 T3 1  0  1
IR4 T7 T6 T5 T4 T3 1  0  0
IR3 T7 T6 T5 T4 T3 0  1  1
IR2 T7 T6 T5 T4 T3 0  1  0
IR1 T7 T6 T5 T4 T3 0  0  1
IR0 T7 T6 T5 T4 T3 0  0  0

so if we map the new vector to 0x20, irq0 = 0x20, irq1 = 0x21 … irq7 = 0x27

line 3, “outb_p(1U > > PIC_CASCADE_IR, PIC_MASTER_IMR)”, initializes an interrupt
line to a slave device, specifically, irq2.

a0 | d7 | d6 | d5 | d4 | d3 | d2 | d1 | d0
1  | s7 | s6 | s5 | s4 | s3 | s2 | s1 | s0

PIC_CASCADE_IR is defined as 2, making (1U< d2=1, specifying that irq2 is connected to a slave device.

then, the kernel sets if master pic is auto end of interrupt or normal end of
interrupt via ICW4 thru:

if (auto_eoi) /* master does Auto EOI */
outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR);
else /* master expects normal EOI */
outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR);

after initializes the master pic, it then initializes the slave pic, the code
pretty much follows the same logic, except that setting ICW3 for the slave
device is simply just a matter of specifying the slave id connected to the
specific irq that was set in the ICW3 of the master pic. 0x2 in this case which
is actually the value of PIC_CASCADE_IR.

the next hurdle will be to study how linux registers the intel 8259A chip as an
interrupt source for each irq line. keywords include irq_desc and irq_chip.

references:
[1] intel 8259A programmable interrupt controller datasheet.

Comments »

The URI to TrackBack this entry is: http://gnurbs.blogsome.com/2008/01/12/understanding-how-linux-initializes-the-pic/trackback/

No comments yet.

RSS feed for comments on this post.

Leave a comment

Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>


Get free blog up and running in minutes with Blogsome | Theme designs available here