summaryrefslogtreecommitdiff
path: root/stage3/pic.c
blob: 726a6da8b13c927bb49706a1a49ee706819ffedc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include "pic.h"
#include "io.h"

void disable_irqs()
{
	asm volatile("cli");
}

void enable_irqs()
{
	asm volatile("sti");
}

void ack_irq(u8 lane)
{
	if (lane >= 8)
		outb(IO_PIC2_CTRL, 1 << 5);

	outb(IO_PIC1_CTRL, 1 << 5);
}

void unmask_irq(u8 lane)
{
	u8 port = IO_PIC1_DATA;

	if (lane >= 8) {
		port = IO_PIC2_DATA;
		lane -= 8;
	}

	outb(port, inb(port) & ~(1 << lane));
}

void pic_init()
{
	typedef struct {
		bool ic4 : 1;
		bool single : 1;
		bool addr_interval : 1;
		bool level_triggered : 1;
		bool init : 1;
		unsigned int zeros : 3;
	} __attribute__((packed)) pic_icw1;

	u8 icw1 = BITCAST(((pic_icw1) {
		.ic4 = true,
		.single = false,
		.addr_interval = false,
		.level_triggered = false,
		.init = true,
		.zeros = 0,
	}), pic_icw1, u8);

	outb(IO_PIC1_CTRL, icw1);
	outb(IO_PIC2_CTRL, icw1);

	// map IRQs 0-15 to 0x20-0x2F
	// 0x1F is the highest reserved interrupt
	outb(IO_PIC1_DATA, 0x20);
	outb(IO_PIC2_DATA, 0x28);

	// pic2 is connected to IRQ2
	outb(IO_PIC1_DATA, 1 << 2);
	outb(IO_PIC2_DATA, 2);

	typedef struct {
		bool x86 : 1;
		bool auto_eoi : 1;
		bool primary_buffered : 1;
		bool buffered : 1;
		bool fully_nested : 1;
		unsigned int zeros : 3;
	} __attribute__((packed)) pic_icw4;

	u8 icw4 = BITCAST(((pic_icw4) {
		.x86 = true,
		.auto_eoi = false,
		.primary_buffered = false,
		.buffered = false,
		.fully_nested = false,
		.zeros = 0,
	}), pic_icw4, u8);

	outb(IO_PIC1_DATA, icw4);
	outb(IO_PIC2_DATA, icw4);

	// mask all interrupts
	outb(IO_PIC1_DATA, 0xff);
	outb(IO_PIC2_DATA, 0xff);

	disable_irqs();
}