furix
cute os
arch/x86_64/pic.c
1702 bytes raw
1#include <pic.h>
2
3#include <io.h>
4#include <types.h>
5
6/*
7 * 8259A master/slave. the slave sits on master IRQ2, so it must be masked
8 * before the master's IRQ2 is dealt with, or a spurious cascade can arrive.
9 */
10#define PIC1_CMD 0x20
11#define PIC1_DATA 0x21
12#define PIC2_CMD 0xA0
13#define PIC2_DATA 0xA1
14
15#define PIC_EOI 0x20 /* non-specific end of interrupt, to the master */
16
17#define ICW1_INIT 0x11 /* edge triggered, cascade, expect ICW4 */
18#define ICW4_8086 0x01 /* 8086/88 mode */
19
20/*
21 * remap both PICs out of the way of the CPU exception vectors, then mask every
22 * line.
23 *
24 * the remap matters as much as the mask: firmware may leave the PIC base at
25 * the default 0x08, which collides with the #DF vector, so even a fully masked
26 * stray line would be reported as a double fault. 0xF0 sits above our spurious
27 * vector (0xFF) and is otherwise unassigned.
28 */
29#define PIC1_BASE 0xF0
30#define PIC2_BASE 0xF8
31
32static void pic_init_one(uint16_t cmd, uint16_t data, uint8_t base) {
33 outb(cmd, ICW1_INIT);
34 outb(data, base);
35 outb(data, base + 8);
36 outb(data, ICW4_8086);
37
38 /* mask every line (bit set = masked) */
39 outb(data, 0xFF);
40}
41
42void pic_disarm(void) {
43 /* mask the slave first, then the master, so no cascade slips through */
44 outb(PIC2_DATA, 0xFF);
45 outb(PIC1_DATA, 0xFF);
46
47 /* acknowledge anything already pending, then remap and mask for real */
48 outb(PIC2_CMD, PIC_EOI);
49 outb(PIC1_CMD, PIC_EOI);
50
51 pic_init_one(PIC1_CMD, PIC1_DATA, PIC1_BASE);
52 pic_init_one(PIC2_CMD, PIC2_DATA, PIC2_BASE);
53
54 /*
55 * both PICs are masked now, but the master still needs to know the slave is
56 * cascaded on IRQ2 or it raises spurious interrupts forever.
57 */
58 outb(PIC1_DATA, 0xFF);
59}