Skip to content

Commit 7b352b8

Browse files
committed
feat: configure PIC, configure timer interrupt, PS2 keyboard, prevent deadlocks in VGA buffer/serial, configure double fault handler
1 parent f9652ea commit 7b352b8

File tree

7 files changed

+140
-18
lines changed

7 files changed

+140
-18
lines changed

Cargo.lock

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ volatile = "0.2.6"
99
spin = "0.5.2"
1010
x86_64 = "0.14.2"
1111
uart_16550 = "0.2.0"
12+
pic8259 = "0.10.1"
13+
pc-keyboard = "0.7.0"
1214

1315
[dependencies.lazy_static]
1416
version = "1.0"

src/interrupts.rs

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,46 @@
1+
use crate::{gdt, print, println};
12
use lazy_static::lazy_static;
3+
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
4+
use pic8259::ChainedPics;
5+
use spin::{self, Mutex};
26
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
37

4-
use crate::println;
8+
// PIC primário
9+
pub const PIC_1_OFFSET: u8 = 32;
10+
// PIC secundário
11+
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
12+
13+
pub static PICS: spin::Mutex<ChainedPics> =
14+
spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });
15+
16+
#[derive(Debug, Clone, Copy)]
17+
#[repr(u8)]
18+
pub enum InterruptIndex {
19+
Timer = PIC_1_OFFSET,
20+
Keyboard,
21+
}
22+
23+
impl InterruptIndex {
24+
fn as_u8(self) -> u8 {
25+
self as u8
26+
}
27+
28+
fn as_usize(self) -> usize {
29+
usize::from(self.as_u8())
30+
}
31+
}
532

633
lazy_static! {
734
static ref IDT: InterruptDescriptorTable = {
835
let mut idt = InterruptDescriptorTable::new();
936
idt.breakpoint.set_handler_fn(breakpoint_handler);
37+
unsafe {
38+
idt.double_fault
39+
.set_handler_fn(double_fault_handler)
40+
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
41+
}
42+
idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
43+
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
1044
idt
1145
};
1246
}
@@ -15,10 +49,59 @@ pub fn init_idt() {
1549
IDT.load();
1650
}
1751

52+
// as interrupções utilizam um calling convention específico.
1853
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
1954
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
2055
}
2156

57+
extern "x86-interrupt" fn double_fault_handler(
58+
stack_frame: InterruptStackFrame,
59+
_error_code: u64,
60+
) -> ! {
61+
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
62+
}
63+
64+
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
65+
print!(".");
66+
67+
unsafe {
68+
PICS.lock()
69+
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
70+
}
71+
}
72+
73+
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
74+
use x86_64::instructions::port::Port;
75+
76+
lazy_static! {
77+
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
78+
Mutex::new(Keyboard::new(
79+
ScancodeSet1::new(),
80+
layouts::Us104Key,
81+
HandleControl::Ignore
82+
));
83+
}
84+
85+
let mut keyboard = KEYBOARD.lock();
86+
let mut port = Port::new(0x60);
87+
88+
let scancode: u8 = unsafe { port.read() };
89+
90+
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
91+
if let Some(key) = keyboard.process_keyevent(key_event) {
92+
match key {
93+
DecodedKey::Unicode(character) => print!("{}", character),
94+
DecodedKey::RawKey(key) => print!("{:?}", key),
95+
}
96+
}
97+
}
98+
99+
unsafe {
100+
PICS.lock()
101+
.notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
102+
}
103+
}
104+
22105
#[test_case]
23106
fn test_breakpoint_exception() {
24107
x86_64::instructions::interrupts::int3();

src/lib.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,28 @@ pub fn test_panic_handler(info: &PanicInfo) -> ! {
4141
serial_println!("[failed]\n");
4242
serial_println!("Error: {}\n", info);
4343
exit_qemu(QemuExitCode::Failed);
44-
loop {}
44+
hlt_loop();
4545
}
4646

4747
pub fn init() {
4848
interrupts::init_idt();
4949
gdt::init();
50+
unsafe { interrupts::PICS.lock().initialize() };
51+
x86_64::instructions::interrupts::enable();
52+
}
53+
54+
pub fn hlt_loop() -> ! {
55+
loop {
56+
x86_64::instructions::hlt();
57+
}
5058
}
5159

5260
#[cfg(test)]
5361
#[no_mangle]
5462
pub extern "C" fn _start() -> ! {
5563
init();
5664
test_main();
57-
loop {}
65+
hlt_loop();
5866
}
5967

6068
#[cfg(test)]

src/main.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,20 @@ pub extern "C" fn _start() -> ! {
1313

1414
osdev_rust::init();
1515

16-
x86_64::instructions::interrupts::int3();
17-
1816
#[cfg(test)]
1917
test_main();
2018

21-
println!("It did not crash.................. AJJUAJAJAHJSHHHAHS");
19+
println!("It did not crash!");
2220

23-
loop {}
21+
osdev_rust::hlt_loop();
2422
}
2523

2624
#[cfg(not(test))]
2725
#[panic_handler]
2826
fn panic(info: &PanicInfo) -> ! {
2927
println!("{}", info);
3028

31-
loop {}
29+
osdev_rust::hlt_loop();
3230
}
3331

3432
#[cfg(test)]

src/serial.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ lazy_static! {
1313
#[doc(hidden)]
1414
pub fn _print(args: ::core::fmt::Arguments) {
1515
use core::fmt::Write;
16+
use x86_64::instructions::interrupts;
1617

17-
SERIAL1
18-
.lock()
19-
.write_fmt(args)
20-
.expect("Printing to serial port failed.")
18+
interrupts::without_interrupts(|| {
19+
SERIAL1
20+
.lock()
21+
.write_fmt(args)
22+
.expect("Printing to serial port failed.");
23+
})
2124
}
2225

2326
#[macro_export]

src/vga_buffer.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,11 @@ macro_rules! println {
140140
#[doc(hidden)]
141141
pub fn _print(args: fmt::Arguments) {
142142
use core::fmt::Write;
143-
WRITER.lock().write_fmt(args).unwrap();
143+
use x86_64::instructions::interrupts;
144+
145+
interrupts::without_interrupts(|| {
146+
WRITER.lock().write_fmt(args).unwrap();
147+
});
144148
}
145149

146150
#[test_case]
@@ -157,10 +161,17 @@ fn test_println_many() {
157161

158162
#[test_case]
159163
fn test_println_output() {
164+
use core::fmt::Write;
165+
use x86_64::instructions::interrupts;
166+
160167
let s = "tatakae";
161-
println!("{}", s);
162-
for (i, c) in s.chars().enumerate() {
163-
let screen_char = WRITER.lock().buffer.chars[BUFFER_HEIGHT - 2][i].read();
164-
assert_eq!(char::from(screen_char.ascii_character), c);
165-
}
168+
169+
interrupts::without_interrupts(|| {
170+
let mut writer = WRITER.lock();
171+
writeln!(writer, "\n{}", s).expect("writeln failed");
172+
for (i, c) in s.chars().enumerate() {
173+
let screen_char = WRITER.lock().buffer.chars[BUFFER_HEIGHT - 2][i].read();
174+
assert_eq!(char::from(screen_char.ascii_character), c);
175+
}
176+
});
166177
}

0 commit comments

Comments
 (0)