diff --git a/src/driver/keyboard.rs b/src/driver/keyboard.rs index 967c51cf..772d7bfb 100644 --- a/src/driver/keyboard.rs +++ b/src/driver/keyboard.rs @@ -1,11 +1,38 @@ -use crate::{interrupts, print}; +use crate::{print, println, task::interrupt_wake}; +use conquer_once::spin::OnceCell; use core::future::Future; use core::{ pin::Pin, task::{Context, Poll}, }; +use crossbeam_queue::ArrayQueue; +use futures_util::task::AtomicWaker; use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; +static WAKER: AtomicWaker = AtomicWaker::new(); +static SCANCODE_QUEUE: OnceCell> = OnceCell::uninit(); + +pub fn init() { + SCANCODE_QUEUE + .try_init_once(|| ArrayQueue::new(10)) + .expect("failed to init scancode queue"); +} + +/// Called by the keyboard interrupt handler +/// +/// Must not block (including spinlocks). +pub(crate) fn keyboard_scancode(scancode: u8) { + let scancode_queue = SCANCODE_QUEUE + .try_get() + .expect("scancode queue not initialized"); + if let Err(_) = scancode_queue.push(scancode) { + println!("WARNING: dropping keyboard input"); + } + if let Some(waker) = WAKER.take() { + interrupt_wake(waker); + } +} + fn next_scancode() -> impl Future { NextScancode } @@ -16,7 +43,7 @@ impl Future for NextScancode { type Output = u8; fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { - let scancodes = interrupts::SCANCODE_QUEUE + let scancodes = SCANCODE_QUEUE .try_get() .expect("scancode queue not initialized"); // fast path @@ -24,7 +51,7 @@ impl Future for NextScancode { return Poll::Ready(scancode); } - interrupts::KEYBOARD_INTERRUPT_WAKER.register(&cx.waker()); + WAKER.register(&cx.waker()); match scancodes.pop() { Ok(scancode) => Poll::Ready(scancode), Err(crossbeam_queue::PopError) => Poll::Pending, @@ -32,7 +59,7 @@ impl Future for NextScancode { } } -pub async fn print_keypresses() { +pub async fn keyboard_task() { let mut keyboard = Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::Ignore); loop { diff --git a/src/driver/mod.rs b/src/driver/mod.rs index a80b91dc..8436164e 100644 --- a/src/driver/mod.rs +++ b/src/driver/mod.rs @@ -1,2 +1,6 @@ pub mod keyboard; pub mod timer; + +pub fn init() { + keyboard::init(); +} diff --git a/src/driver/timer.rs b/src/driver/timer.rs index ad73322b..a6215a71 100644 --- a/src/driver/timer.rs +++ b/src/driver/timer.rs @@ -1,14 +1,30 @@ -use crate::{interrupts, print}; +use crate::{print, task::interrupt_wake}; use core::future::Future; use core::{ pin::Pin, - sync::atomic::Ordering, + sync::atomic::{AtomicU64, Ordering}, task::{Context, Poll}, }; +use futures_util::task::AtomicWaker; + +static TICKS: AtomicU64 = AtomicU64::new(0); +static WAKER: AtomicWaker = AtomicWaker::new(); + +/// Called by the timer interrupt handler +/// +/// Must not block (including spinlocks). +pub(crate) fn tick() { + TICKS.fetch_add(1, Ordering::Release); + if let Some(waker) = WAKER.take() { + interrupt_wake(waker); + } +} + +fn next_tick() -> impl Future { + static NEXT_TICK: AtomicU64 = AtomicU64::new(1); -fn next_tick(current_tick: u64) -> impl Future { NextTick { - ticks: current_tick, + ticks: NEXT_TICK.fetch_add(1, Ordering::Release), } } @@ -20,15 +36,8 @@ impl Future for NextTick { type Output = u64; fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { - let current_ticks = interrupts::TIMER_TICKS.load(Ordering::Acquire); - - if self.ticks < current_ticks { - self.ticks += 1; - return Poll::Ready(self.ticks); - } - - interrupts::TIMER_INTERRUPT_WAKER.register(&cx.waker()); - let current_ticks = interrupts::TIMER_TICKS.load(Ordering::Acquire); + WAKER.register(&cx.waker()); + let current_ticks = TICKS.load(Ordering::Acquire); if self.ticks < current_ticks { self.ticks += 1; Poll::Ready(self.ticks) @@ -38,11 +47,9 @@ impl Future for NextTick { } } -pub async fn print_ticks() { - let mut current_ticks = interrupts::TIMER_TICKS.load(Ordering::Acquire); - +pub async fn timer_task() { loop { - current_ticks = next_tick(current_ticks).await; + next_tick().await; print!("."); } } diff --git a/src/interrupts.rs b/src/interrupts.rs index 2beccdc2..c083a485 100644 --- a/src/interrupts.rs +++ b/src/interrupts.rs @@ -1,11 +1,4 @@ use crate::{gdt, hlt_loop, println}; -use conquer_once::spin::OnceCell; -use core::{ - sync::atomic::{AtomicU64, Ordering}, - task::Waker, -}; -use crossbeam_queue::ArrayQueue; -use futures_util::task::AtomicWaker; use lazy_static::lazy_static; use pic8259_simple::ChainedPics; use spin; @@ -54,23 +47,6 @@ pub fn init_idt() { IDT.load(); } -pub fn init_queues() { - INTERRUPT_WAKEUPS - .try_init_once(|| ArrayQueue::new(10)) - .expect("failed to init interrupt wakeup queue"); - SCANCODE_QUEUE - .try_init_once(|| ArrayQueue::new(10)) - .expect("failed to init scancode queue"); -} - -static INTERRUPT_WAKEUPS: OnceCell> = OnceCell::uninit(); - -pub(crate) fn interrupt_wakeups() -> &'static ArrayQueue { - INTERRUPT_WAKEUPS - .try_get() - .expect("interrupt wakeup queue not initialized") -} - extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut InterruptStackFrame) { println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); } @@ -95,41 +71,21 @@ extern "x86-interrupt" fn double_fault_handler( panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame); } -pub(crate) static TIMER_TICKS: AtomicU64 = AtomicU64::new(0); -pub(crate) static TIMER_INTERRUPT_WAKER: AtomicWaker = AtomicWaker::new(); - extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: &mut InterruptStackFrame) { - TIMER_TICKS.fetch_add(1, Ordering::Release); - if let Some(waker) = TIMER_INTERRUPT_WAKER.take() { - if let Err(_) = interrupt_wakeups().push(waker) { - println!("WARNING: dropping interrupt wakeup"); - } - } + crate::driver::timer::tick(); + unsafe { PICS.lock() .notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); } } -pub(crate) static SCANCODE_QUEUE: OnceCell> = OnceCell::uninit(); -pub(crate) static KEYBOARD_INTERRUPT_WAKER: AtomicWaker = AtomicWaker::new(); - extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: &mut InterruptStackFrame) { use x86_64::instructions::port::Port; let mut port = Port::new(0x60); let scancode: u8 = unsafe { port.read() }; - let scancode_queue = SCANCODE_QUEUE - .try_get() - .expect("scancode queue not initialized"); - if let Err(_) = scancode_queue.push(scancode) { - println!("WARNING: dropping keyboard input"); - } - if let Some(waker) = KEYBOARD_INTERRUPT_WAKER.take() { - if let Err(_) = interrupt_wakeups().push(waker) { - println!("WARNING: dropping interrupt wakeup"); - } - } + crate::driver::keyboard::keyboard_scancode(scancode); unsafe { PICS.lock() diff --git a/src/lib.rs b/src/lib.rs index b6fc2750..8a8c7e05 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,11 @@ pub fn init() { unsafe { interrupts::PICS.lock().initialize() }; } +pub fn init_heap_structures() { + task::init(); + driver::init(); +} + pub fn test_runner(tests: &[&dyn Fn()]) { serial_println!("Running {} tests", tests.len()); for test in tests { diff --git a/src/main.rs b/src/main.rs index d30f28e5..45e0a993 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,7 +26,7 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! { let mut frame_allocator = unsafe { BootInfoFrameAllocator::init(&boot_info.memory_map) }; allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed"); - blog_os::interrupts::init_queues(); + blog_os::init_heap_structures(); // allocate a number on the heap let heap_value = Box::new(41); @@ -66,8 +66,8 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! { println!("It did not crash!"); }); - executor.spawn(blog_os::driver::timer::print_ticks()); - executor.spawn(blog_os::driver::keyboard::print_keypresses()); + executor.spawn(blog_os::driver::timer::timer_task()); + executor.spawn(blog_os::driver::keyboard::keyboard_task()); executor.run(); } diff --git a/src/task/executor.rs b/src/task/executor.rs index 72d11f9d..1428da37 100644 --- a/src/task/executor.rs +++ b/src/task/executor.rs @@ -1,4 +1,5 @@ -use crate::{interrupts, println}; +use super::interrupt_wakeups::interrupt_wakeups; +use crate::println; use alloc::{ boxed::Box, collections::{BTreeMap, VecDeque}, @@ -66,7 +67,7 @@ impl Executor { /// might execute arbitrary code, e.g. allocate, which should not be done /// in interrupt handlers to avoid deadlocks. fn apply_interrupt_wakeups(&mut self) { - while let Ok(waker) = interrupts::interrupt_wakeups().pop() { + while let Ok(waker) = interrupt_wakeups().pop() { waker.wake(); } } @@ -87,7 +88,7 @@ impl Executor { // disable interrupts to avoid races x86_64::instructions::interrupts::disable(); // check if relevant interrupts occured since the last check - if interrupts::interrupt_wakeups().is_empty() { + if interrupt_wakeups().is_empty() { // no interrupts occured -> hlt to wait for next interrupt x86_64::instructions::interrupts::enable_interrupts_and_hlt(); } else { diff --git a/src/task/interrupt_wakeups.rs b/src/task/interrupt_wakeups.rs new file mode 100644 index 00000000..470798dd --- /dev/null +++ b/src/task/interrupt_wakeups.rs @@ -0,0 +1,25 @@ +use crate::println; +use conquer_once::spin::OnceCell; +use core::task::Waker; +use crossbeam_queue::ArrayQueue; + +static INTERRUPT_WAKEUPS: OnceCell> = OnceCell::uninit(); + +pub fn init() { + INTERRUPT_WAKEUPS + .try_init_once(|| ArrayQueue::new(10)) + .expect("failed to init interrupt wakeup queue"); +} + +/// Queues a waker for waking in an interrupt-safe way +pub(crate) fn interrupt_wake(waker: Waker) { + if let Err(_) = interrupt_wakeups().push(waker) { + println!("WARNING: dropping interrupt wakeup"); + } +} + +pub(super) fn interrupt_wakeups() -> &'static ArrayQueue { + INTERRUPT_WAKEUPS + .try_get() + .expect("interrupt wakeup queue not initialized") +} diff --git a/src/task/mod.rs b/src/task/mod.rs index 0c95fdab..e7734dce 100644 --- a/src/task/mod.rs +++ b/src/task/mod.rs @@ -1 +1,8 @@ +pub(crate) use interrupt_wakeups::interrupt_wake; + pub mod executor; +mod interrupt_wakeups; + +pub fn init() { + interrupt_wakeups::init(); +}