Skip to content

Commit

Permalink
Add timer and keyboard interrupt handling (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
JuozasVainauskas authored Jan 1, 2024
1 parent 959ba8e commit e94625a
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 6 deletions.
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ volatile = "0.2.6"
spin = "0.5.2"
x86_64 = "0.14.2"
uart_16550 = "0.2.0"
pic8259 = "0.10.1"
pc-keyboard = "0.5.0"

[dependencies.lazy_static]
version = "1.0"
Expand Down
65 changes: 65 additions & 0 deletions src/interrupts.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
use crate::println;
use crate::print;
use crate::gdt;
use lazy_static::lazy_static;
use pic8259::ChainedPics;
use spin;

#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum InterruptIndex {
Timer = PIC_1_OFFSET,
Keyboard,
}

lazy_static! {
static ref IDT: InterruptDescriptorTable = {
Expand All @@ -11,6 +21,8 @@ lazy_static! {
idt.double_fault.set_handler_fn(double_fault_handler)
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
}
idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
idt
};
}
Expand All @@ -27,6 +39,59 @@ extern "x86-interrupt" fn double_fault_handler(stack_frame: InterruptStackFrame,
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
}

extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
unsafe {
PICS.lock().notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
}
}

extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
use spin::Mutex;
use x86_64::instructions::port::Port;

lazy_static! {
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
Mutex::new(Keyboard::new(layouts::Us104Key, ScancodeSet1,
HandleControl::Ignore)
);
}

let mut keyboard = KEYBOARD.lock();
let mut port = Port::new(0x60);

let scancode: u8 = unsafe { port.read() };
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
if let Some(key) = keyboard.process_keyevent(key_event) {
match key {
DecodedKey::Unicode(character) => print!("{}", character),
DecodedKey::RawKey(key) => print!("{:?}", key),
}
}
}

unsafe {
PICS.lock()
.notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
}
}

pub const PIC_1_OFFSET: u8 = 32;
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;

impl InterruptIndex {
fn as_u8(self) -> u8 {
self as u8
}

fn as_usize(self) -> usize {
usize::from(self.as_u8())
}
}

pub static PICS: spin::Mutex<ChainedPics> =
spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });

#[test_case]
fn test_breakpoint_exceptions() {
x86_64::instructions::interrupts::int3();
Expand Down
12 changes: 10 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub mod gdt;
pub fn init() {
gdt::init();
interrupts::init_idt();
unsafe { interrupts::PICS.lock().initialize() };
x86_64::instructions::interrupts::enable();
}

pub trait Testable {
Expand Down Expand Up @@ -44,7 +46,13 @@ pub fn test_panic_handler(info: &PanicInfo) -> ! {
serial_println!("[failed]\n");
serial_println!("Error: {}\n", info);
exit_qemu(QemuExitCode::Failed);
loop {}
hlt_loop();
}

pub fn hlt_loop() -> ! {
loop {
x86_64::instructions::hlt();
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand All @@ -69,7 +77,7 @@ pub fn exit_qemu(exit_code: QemuExitCode) {
pub extern "C" fn _start() -> ! {
init();
test_main();
loop {}
hlt_loop();
}

#[cfg(test)]
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ pub extern "C" fn _start() -> ! {
#[cfg(test)]
test_main();

loop {}
os::hlt_loop();
}

// This function is called on panic in non-test mode.
#[cfg(not(test))] // new attribute
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
println!("{}", info);
loop {}
os::hlt_loop();
}

#[cfg(test)]
Expand Down
8 changes: 7 additions & 1 deletion src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ lazy_static! {
#[doc(hidden)]
pub fn _print(args: ::core::fmt::Arguments) {
use core::fmt::Write;
SERIAL1.lock().write_fmt(args).expect("Printing to serial failed");
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
SERIAL1
.lock()
.write_fmt(args)
.expect("Printing to serial failed");
});
}

/// Prints to the host through the serial interface.
Expand Down
6 changes: 5 additions & 1 deletion src/vga_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,14 @@ macro_rules! println {
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
}

// Prints the given formatted string to the VGA text buffer through the global `WRITER` instance.
#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
use core::fmt::Write;
WRITER.lock().write_fmt(args).unwrap();
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
WRITER.lock().write_fmt(args).unwrap();
});
}

#[test_case]
Expand Down

0 comments on commit e94625a

Please sign in to comment.