From de86827da5ab4ca24b9bbc09aaa56e1d3d6f638b Mon Sep 17 00:00:00 2001 From: charlesbvll Date: Thu, 22 Jul 2021 12:25:39 +0200 Subject: [PATCH] interrupts --- Cargo.lock | 10 +++++++++ Cargo.toml | 1 + src/gdt.rs | 4 ++-- src/interrupts.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 12 +++++++++-- src/main.rs | 4 ++-- src/serial.rs | 9 +++++++- src/vga_buffer.rs | 22 +++++++++++++------ 8 files changed, 102 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75d1dc9..7e9d4c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,12 +29,22 @@ dependencies = [ "spin", ] +[[package]] +name = "pic8259" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08cc920d83ee33c0f9b73aa441e75468bf2d10c959a3eb6260cf720b05ac91a1" +dependencies = [ + "x86_64", +] + [[package]] name = "rust_os" version = "0.1.0" dependencies = [ "bootloader", "lazy_static", + "pic8259", "spin", "uart_16550", "volatile 0.2.7", diff --git a/Cargo.toml b/Cargo.toml index a341d9a..badb8d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ volatile = "0.2.6" spin = "0.5.2" x86_64 = "0.14.2" uart_16550 = "0.2.0" +pic8259 = "0.10.1" [dependencies.lazy_static] version = "1.0" diff --git a/src/gdt.rs b/src/gdt.rs index 4acc941..138c5b1 100644 --- a/src/gdt.rs +++ b/src/gdt.rs @@ -36,12 +36,12 @@ struct Selectors { } pub fn init() { - use x86_64::instructions::segmentation::set_cs; + use x86_64::instructions::segmentation::{CS, Segment}; use x86_64::instructions::tables::load_tss; GDT.0.load(); unsafe { - set_cs(GDT.1.code_selector); + CS::set_reg(GDT.1.code_selector); load_tss(GDT.1.tss_selector); } } \ No newline at end of file diff --git a/src/interrupts.rs b/src/interrupts.rs index 06590b5..66bbe86 100644 --- a/src/interrupts.rs +++ b/src/interrupts.rs @@ -1,5 +1,6 @@ use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; use crate::println; +use crate::print; use lazy_static::lazy_static; use crate::gdt; @@ -10,9 +11,12 @@ lazy_static! { idt.breakpoint.set_handler_fn(breakpoint_handler); unsafe { idt.double_fault.set_handler_fn(double_fault_handler) - .set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX); // new + .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 }; } @@ -23,6 +27,27 @@ extern "x86-interrupt" fn double_fault_handler( panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame); } +extern "x86-interrupt" fn timer_interrupt_handler( + _stack_frame: InterruptStackFrame) +{ + print!("."); + unsafe { + PICS.lock() + .notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); + } +} + +extern "x86-interrupt" fn keyboard_interrupt_handler( + _stack_frame: InterruptStackFrame) +{ + print!("k"); + + unsafe { + PICS.lock() + .notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8()); + } +} + pub fn init_idt() { IDT.load(); } @@ -36,4 +61,30 @@ extern "x86-interrupt" fn breakpoint_handler( stack_frame: InterruptStackFrame) { println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); +} + +use pic8259::ChainedPics; +use spin; + +pub const PIC_1_OFFSET: u8 = 32; +pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; + +pub static PICS: spin::Mutex = + spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) }); + +#[derive(Debug, Clone, Copy)] +#[repr(u8)] +pub enum InterruptIndex { + Timer = PIC_1_OFFSET, + Keyboard, +} + +impl InterruptIndex { + fn as_u8(self) -> u8 { + self as u8 + } + + fn as_usize(self) -> usize { + usize::from(self.as_u8()) + } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 9e77f4b..30bc9e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,12 +39,14 @@ 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 init() { gdt::init(); interrupts::init_idt(); + unsafe { interrupts::PICS.lock().initialize() }; + x86_64::instructions::interrupts::enable(); } #[cfg(test)] @@ -52,7 +54,7 @@ pub fn init() { pub extern "C" fn _start() -> ! { init(); // new test_main(); - loop {} + hlt_loop(); } #[cfg(test)] @@ -75,4 +77,10 @@ pub fn exit_qemu(exit_code: QemuExitCode) { let mut port = Port::new(0xf4); port.write(exit_code as u32); } +} + +pub fn hlt_loop() -> ! { + loop { + x86_64::instructions::hlt(); + } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index a27e532..bd88a97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ pub extern "C" fn _start() -> ! { test_main(); println!("It did not crash!"); - loop {} + rust_os::hlt_loop(); } /// This function is called on panic. @@ -26,7 +26,7 @@ pub extern "C" fn _start() -> ! { #[panic_handler] fn panic(info: &PanicInfo) -> ! { println!("{}", info); - loop {} + rust_os::hlt_loop(); } #[cfg(test)] diff --git a/src/serial.rs b/src/serial.rs index 07129bb..ed16aae 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -13,7 +13,14 @@ 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. diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs index 365aa0e..61b3a25 100644 --- a/src/vga_buffer.rs +++ b/src/vga_buffer.rs @@ -142,7 +142,11 @@ macro_rules! println { #[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] @@ -159,10 +163,16 @@ fn test_println_many() { #[test_case] fn test_println_output() { + use core::fmt::Write; + use x86_64::instructions::interrupts; + let s = "Some test string that fits on a single line"; - println!("{}", s); - for (i, c) in s.chars().enumerate() { - let screen_char = WRITER.lock().buffer.chars[BUFFER_HEIGHT - 2][i].read(); - assert_eq!(char::from(screen_char.ascii_character), c); - } + interrupts::without_interrupts(|| { + let mut writer = WRITER.lock(); + writeln!(writer, "\n{}", s).expect("writeln failed"); + for (i, c) in s.chars().enumerate() { + let screen_char = writer.buffer.chars[BUFFER_HEIGHT - 2][i].read(); + assert_eq!(char::from(screen_char.ascii_character), c); + } + }); } \ No newline at end of file