rustubs/arch/x86_64/interrupt/
pic_8259.rs

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
use crate::arch::x86_64::io_port::*;
// code from: https://wiki.osdev.org/8259_PIC#Code_Examples
// data and control ports of PIC1 (master) and PIC2 (slave)
const IMR1: u16 = 0x21;
const IMR2: u16 = 0xa1;
const CTRL1: u16 = 0x20;
const CTRL2: u16 = 0xa0;
const PIC_VECTOR_OFFSET: u8 = 0x20;

pub struct PicDeviceInt;
impl PicDeviceInt {
	pub const TIMER: u8 = 0;
	pub const KEYBOARD: u8 = 1;
}

pub fn init() {
	// ICW1_ICW4 | ICW1_INIT
	// start init sequence in cascade mode
	outb(CTRL1, 0x11);
	outb(CTRL2, 0x11);
	// ICW2: MASTER PIC vector offset = 0x20
	outb(IMR1, PIC_VECTOR_OFFSET);
	// ICW2: SLAVE PIC vector offset = 0x28
	outb(IMR2, PIC_VECTOR_OFFSET + 8);
	// ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
	outb(IMR1, 0x04);
	// ICW3: tell Slave PIC its cascade identity (0000 0010)
	outb(IMR2, 0x02);
	// ICW4: 8086 mode | auto (normal) EOI
	outb(IMR1, 0x03);
	outb(IMR2, 0x03);
	// set masks
	outb(IMR1, 0xfb);
	outb(IMR2, 0xff);
}

// 8-bit registers IMR1 and IMR2 registers hold interrupt masking bit 0~7 and
// 8~15; if an interrupt is masked(set 1) on the respective bit, it's disabled
pub fn allow(interrupt: u8) {
	if interrupt < 8 {
		let old = inb(IMR1);
		outb(IMR1, old & !(1 << interrupt));
	} else {
		let old = inb(IMR2);
		outb(IMR2, old & !(1 << (interrupt - 8)));
	}
}

pub fn forbid(interrupt: u8) {
	if interrupt < 8 {
		let old = inb(IMR1);
		outb(IMR1, old | (1 << interrupt));
	} else {
		let old = inb(IMR2);
		outb(IMR2, old | (1 << (interrupt - 8)));
	}
}

pub fn is_masked(interrupt: u8) -> bool {
	if interrupt < 8 {
		let val = inb(IMR1);
		val & (interrupt) != 0
	} else {
		let val = inb(IMR2);
		val & (interrupt - 8) != 0
	}
}