diff --git a/Cargo.lock b/Cargo.lock index 16179b1..745f6c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,6 +28,11 @@ name = "cast" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cpuio" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lazy_static" version = "1.4.0" @@ -41,6 +46,19 @@ name = "nodrop" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pc-keyboard" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pic8259_simple" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cpuio 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "spin" version = "0.5.2" @@ -83,6 +101,8 @@ version = "0.1.0" dependencies = [ "bootloader 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pc-keyboard 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pic8259_simple 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "uart_16550 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -95,8 +115,11 @@ dependencies = [ "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum bootloader 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abfbe6cdea6367860818facc8e4a184f003cb83d7d004acaaf57baebf1949da0" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" +"checksum cpuio 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22b8e308ccfc5acf3b82f79c0eac444cf6114cb2ac67a230ca6c177210068daa" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +"checksum pc-keyboard 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fff50ab09ba31bcebc0669f4e64c0952fae1acdca9e6e0587e68e4e8443808ac" +"checksum pic8259_simple 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc64b2fd10828da8521b6cdabe0679385d7d2a3a6d4c336b819d1fa31ba35c72" "checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" "checksum uart_16550 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "803ea8cb602dbb32c1a657a866d2dd79fe7dbeab0fb2ac667cb4dcc7de12a58b" "checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" diff --git a/Cargo.toml b/Cargo.toml index 2803c32..ca9903c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,8 @@ volatile = "0.2.6" spin = "0.5.2" x86_64 = "0.7.5" uart_16550 = "0.2.0" +pic8259_simple = "0.1.1" +pc-keyboard = "0.3.1" [dependencies.lazy_static] version = "1.0" @@ -25,6 +27,7 @@ panic = "abort" [package.metadata.bootimage] run-args = [ + "-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-display", "curses" ] test-args = [ diff --git a/src/interrupts.rs b/src/interrupts.rs index 5c0e15b..e292c66 100644 --- a/src/interrupts.rs +++ b/src/interrupts.rs @@ -1,5 +1,5 @@ use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; -use crate::{gdt, println}; +use crate::{gdt, print, println}; use lazy_static::lazy_static; lazy_static! { @@ -10,6 +10,10 @@ 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 }; } @@ -40,3 +44,71 @@ fn test_breakpoint_exception() { x86_64::instructions::interrupts::int3(); serial_println!("[ok]"); } + +use pic8259_simple::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()) + } +} + +extern "x86-interrupt" fn timer_interrupt_handler( + _stack_frame: &mut InterruptStackFrame) +{ + //print!("."); + + unsafe { + PICS.lock() + .notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); + } +} + +extern "x86-interrupt" fn keyboard_interrupt_handler( + _stack_frame: &mut InterruptStackFrame) +{ + use x86_64::instructions::port::Port; + use pc_keyboard::{Keyboard, ScancodeSet1, DecodedKey, layouts}; + use spin::Mutex; + + lazy_static! { + static ref KEYBOARD: Mutex> = + Mutex::new(Keyboard::new(layouts::Us104Key, ScancodeSet1)); + } + + 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()); + } +} diff --git a/src/lib.rs b/src/lib.rs index 08f7e37..a04059a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,14 @@ use core::panic::PanicInfo; pub fn init() { gdt::init(); interrupts::init_idt(); + unsafe { interrupts::PICS.lock().initialize() }; + x86_64::instructions::interrupts::enable(); +} + +pub fn hlt_loop() -> ! { + loop { + x86_64::instructions::hlt(); + } } pub fn test_runner(tests: &[&dyn Fn()]) { @@ -29,7 +37,7 @@ pub fn test_panic_handler(info: &PanicInfo) -> ! { serial_println!("[failed]\n"); serial_println!("Error: {}\n", info); exit_qemu(QemuExitCode::Failed); - loop {} + hlt_loop(); } /// Entry point for `cargo xtest` @@ -38,7 +46,7 @@ pub fn test_panic_handler(info: &PanicInfo) -> ! { pub extern "C" fn _start() -> ! { init(); test_main(); - loop {} + hlt_loop(); } #[cfg(test)] diff --git a/src/main.rs b/src/main.rs index d3435eb..e47cab0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,7 @@ pub extern "C" fn _start() -> ! { test_main(); println!("It did not crash!"); - loop {} + xe_os::hlt_loop(); } // our existing panic handler @@ -24,7 +24,7 @@ pub extern "C" fn _start() -> ! { #[panic_handler] fn panic(info: &PanicInfo) -> ! { println!("{}", info); - loop {} + xe_os::hlt_loop(); } // our panic handler in test mode diff --git a/src/serial.rs b/src/serial.rs index e8073d9..2a69296 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -13,7 +13,11 @@ 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 183929e..47dc7f0 100644 --- a/src/vga_buffer.rs +++ b/src/vga_buffer.rs @@ -167,7 +167,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(); + }); } #[cfg(test)] @@ -191,14 +195,20 @@ fn test_println_many() { #[test_case] fn test_println_output() { + use core::fmt::Write; + use x86_64::instructions::interrupts; + serial_print!("test_println_output... "); 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); + } + }); serial_println!("[ok]"); }