From 1f606c7951068103d7532e3f7a8d7407fcf2eb3c Mon Sep 17 00:00:00 2001 From: Viktor Popp Date: Sat, 18 Jan 2025 16:32:39 +0100 Subject: [PATCH 1/5] Added simple task executor --- src/kernel/mod.rs | 1 + src/kernel/task/mod.rs | 21 +++++++++++++ src/kernel/task/simple_executor.rs | 47 ++++++++++++++++++++++++++++++ src/main.rs | 14 +++++++++ 4 files changed, 83 insertions(+) create mode 100644 src/kernel/task/mod.rs create mode 100644 src/kernel/task/simple_executor.rs diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 98c3c03..72b0179 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -5,4 +5,5 @@ pub mod interrupts; pub mod layouts; pub mod memory; pub mod string; +pub mod task; pub mod vga; diff --git a/src/kernel/task/mod.rs b/src/kernel/task/mod.rs new file mode 100644 index 0000000..d55e2a4 --- /dev/null +++ b/src/kernel/task/mod.rs @@ -0,0 +1,21 @@ +use alloc::boxed::Box; +use core::task::{Context, Poll}; +use core::{future::Future, pin::Pin}; + +pub mod simple_executor; + +pub struct Task { + future: Pin>>, +} + +impl Task { + pub fn new(future: impl Future + 'static) -> Task { + Task { + future: Box::pin(future), + } + } + + fn poll(&mut self, context: &mut Context) -> Poll<()> { + self.future.as_mut().poll(context) + } +} diff --git a/src/kernel/task/simple_executor.rs b/src/kernel/task/simple_executor.rs new file mode 100644 index 0000000..d3ca30a --- /dev/null +++ b/src/kernel/task/simple_executor.rs @@ -0,0 +1,47 @@ +use super::Task; +use alloc::collections::VecDeque; +use core::task::RawWakerVTable; +use core::task::{Context, Poll}; + +pub struct SimpleExecutor { + task_queue: VecDeque, +} + +impl SimpleExecutor { + pub fn new() -> SimpleExecutor { + SimpleExecutor { + task_queue: VecDeque::new(), + } + } + + pub fn spawn(&mut self, task: Task) { + self.task_queue.push_back(task) + } + + pub fn run(&mut self) { + while let Some(mut task) = self.task_queue.pop_front() { + let waker = dummy_waker(); + let mut context = Context::from_waker(&waker); + match task.poll(&mut context) { + Poll::Ready(()) => {} // task done + Poll::Pending => self.task_queue.push_back(task), + } + } + } +} + +use core::task::{RawWaker, Waker}; + +fn dummy_raw_waker() -> RawWaker { + fn no_op(_: *const ()) {} + fn clone(_: *const ()) -> RawWaker { + dummy_raw_waker() + } + + let vtable = &RawWakerVTable::new(clone, no_op, no_op, no_op); + RawWaker::new(0 as *const (), vtable) +} + +fn dummy_waker() -> Waker { + unsafe { Waker::from_raw(dummy_raw_waker()) } +} diff --git a/src/main.rs b/src/main.rs index e045aae..edc0ad5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ extern crate alloc; use bootloader::{entry_point, BootInfo}; use core::panic::PanicInfo; use infinity_os::kernel; +use infinity_os::kernel::task::{simple_executor::SimpleExecutor, Task}; use infinity_os::print; use infinity_os::user::shell; use x86_64::VirtAddr; @@ -28,6 +29,10 @@ pub fn kernel_main(boot_info: &'static BootInfo) -> ! { kernel::allocator::init_heap(&mut mapper, &mut frame_allocator) .expect("heap initialization failed"); + let mut executor = SimpleExecutor::new(); + executor.spawn(Task::new(example_task())); + executor.run(); + shell::print_prompt(); infinity_os::hlt_loop(); @@ -38,3 +43,12 @@ fn panic(info: &PanicInfo) -> ! { print!("{}\n", info); infinity_os::hlt_loop(); } + +async fn async_number() -> u32 { + 42 +} + +async fn example_task() { + let number = async_number().await; + print!("async number: {}\n", number); +} From facb4617d3a9b1981cc4849ecbeac27c0d637625 Mon Sep 17 00:00:00 2001 From: Viktor Popp Date: Sat, 18 Jan 2025 16:58:37 +0100 Subject: [PATCH 2/5] Removed shell --- src/kernel/interrupts.rs | 29 ------------------- src/lib.rs | 1 - src/main.rs | 5 ---- src/user/mod.rs | 1 - src/user/shell.rs | 60 ---------------------------------------- 5 files changed, 96 deletions(-) delete mode 100644 src/user/mod.rs delete mode 100644 src/user/shell.rs diff --git a/src/kernel/interrupts.rs b/src/kernel/interrupts.rs index 23bf7cc..cf0d0be 100644 --- a/src/kernel/interrupts.rs +++ b/src/kernel/interrupts.rs @@ -1,7 +1,6 @@ use crate::hlt_loop; use crate::kernel::{clock, gdt}; use crate::print; -use crate::user; use lazy_static::lazy_static; use pic8259::ChainedPics; use spin; @@ -84,34 +83,6 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFr } extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) { - use crate::kernel::layouts; - use pc_keyboard::{DecodedKey, HandleControl, Keyboard, ScancodeSet1}; - use spin::Mutex; - use x86_64::instructions::port::Port; - - lazy_static! { - static ref KEYBOARD: Mutex> = - Mutex::new(Keyboard::new( - layouts::Qwerty104Key, - ScancodeSet1, - HandleControl::MapLettersToUnicode - )); - } - - 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) { - //user::shell::key_handle(key); - match key { - DecodedKey::Unicode(c) => user::shell::key_handle(c), - DecodedKey::RawKey(_) => {} - } - } - } - unsafe { PICS.lock() .notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8()); diff --git a/src/lib.rs b/src/lib.rs index c69fc0b..50f89b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,6 @@ extern crate alloc; use core::panic::PanicInfo; pub mod kernel; -pub mod user; #[cfg(test)] use bootloader::{entry_point, BootInfo}; diff --git a/src/main.rs b/src/main.rs index edc0ad5..122b93e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,6 @@ use core::panic::PanicInfo; use infinity_os::kernel; use infinity_os::kernel::task::{simple_executor::SimpleExecutor, Task}; use infinity_os::print; -use infinity_os::user::shell; use x86_64::VirtAddr; entry_point!(kernel_main); @@ -19,8 +18,6 @@ entry_point!(kernel_main); pub fn kernel_main(boot_info: &'static BootInfo) -> ! { infinity_os::init(); - shell::print_banner(); - /* Memory Initialization */ let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset); let mut mapper = unsafe { kernel::memory::init(phys_mem_offset) }; @@ -33,8 +30,6 @@ pub fn kernel_main(boot_info: &'static BootInfo) -> ! { executor.spawn(Task::new(example_task())); executor.run(); - shell::print_prompt(); - infinity_os::hlt_loop(); } diff --git a/src/user/mod.rs b/src/user/mod.rs deleted file mode 100644 index 327cf1b..0000000 --- a/src/user/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod shell; diff --git a/src/user/shell.rs b/src/user/shell.rs deleted file mode 100644 index e10c668..0000000 --- a/src/user/shell.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::print; -use crate::kernel::clock; -use crate::kernel::string::String; -use lazy_static::lazy_static; -use spin::Mutex; - -lazy_static! { - pub static ref STDIN: Mutex = Mutex::new(String::new()); -} - -pub fn print_banner() { - print!(" ____\n"); - print!(" /|o | ()()\n"); - print!(" /o| o| (o.o )\n"); - print!("+-----------------/o_|_o_|------------> ^ <------------------------------------+\n"); - print!("| |\n"); - print!("| Infinity OS |\n"); - print!("| |\n"); - print!("| Lightweight Operating System |\n"); - print!("| |\n"); - print!("+------------------------------------------------------------------------------+\n"); -} - -pub fn print_prompt() { - print!("\n> "); -} - -pub fn key_handle(c: char) { - let mut stdin = STDIN.lock(); - if c == '\n' { - print!("\n"); - match stdin.as_str() { - "help" => { - print!("Lightweight easy to use operating system made to limit e-waste"); - }, - "version" => { - print!("Infinity OS v{}", env!("CARGO_PKG_VERSION")); - }, - "uptime" => { - print!("{:.0} seconds", clock::uptime()); - }, - _ => { - print!("Unknown command: {}", stdin.as_str()); - } - } - stdin.clear(); - print!("\n"); - print_prompt(); - } else { - if c == 0x08 as char { - if stdin.len() > 0 { - stdin.pop(); - print!("{}", c); - } - } else { - stdin.push(c as u8); - print!("{}", c); - } - } -} From 70006efa1e85263594acc29dff500c3565b52b4b Mon Sep 17 00:00:00 2001 From: Viktor Popp Date: Sat, 18 Jan 2025 17:11:44 +0100 Subject: [PATCH 3/5] Added better task support --- Cargo.lock | 73 +++++++++++++- Cargo.toml | 16 ++- src/kernel/interrupts.rs | 10 +- src/kernel/layouts.rs | 195 ------------------------------------ src/kernel/mod.rs | 1 - src/kernel/task/keyboard.rs | 82 +++++++++++++++ src/kernel/task/mod.rs | 1 + src/main.rs | 2 + 8 files changed, 180 insertions(+), 200 deletions(-) delete mode 100644 src/kernel/layouts.rs create mode 100644 src/kernel/task/keyboard.rs diff --git a/Cargo.lock b/Cargo.lock index 6f5f524..1e2787d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,6 +44,60 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "conquer-once" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96eb12fb69466716fbae9009d389e6a30830ae8975e170eff2d2cff579f9efa3" +dependencies = [ + "conquer-util", +] + +[[package]] +name = "conquer-util" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "654fb2472cc369d311c547103a1fa81d467bef370ae7a0680f65939895b1182a" + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + [[package]] name = "generic-array" version = "0.12.4" @@ -98,6 +152,9 @@ name = "infinity_os" version = "0.1.0" dependencies = [ "bootloader", + "conquer-once", + "crossbeam-queue", + "futures-util", "heapless", "lazy_static", "linked_list_allocator", @@ -138,9 +195,9 @@ dependencies = [ [[package]] name = "pc-keyboard" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6f2d937e3b8d63449b01401e2bae4041bc9dd1129c2e3e0d239407cf6635ac" +checksum = "ed089a1fbffe3337a1a345501c981f1eb1e47e69de5a40e852433e12953c3174" [[package]] name = "pic8259" @@ -151,6 +208,18 @@ dependencies = [ "x86_64", ] +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "rustversion" version = "1.0.19" diff --git a/Cargo.toml b/Cargo.toml index e0ff6f1..52502ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] volatile = "0.2.6" spin = "0.5.2" -pc-keyboard = "0.5.0" +pc-keyboard = "0.7.0" heapless = "0.6.1" linked_list_allocator = "0.9.0" @@ -19,6 +19,20 @@ pic8259 = "0.10.1" version = "1.0" features = ["spin_no_std"] +[dependencies.crossbeam-queue] +version = "0.3.11" +default-features = false +features = ["alloc"] + +[dependencies.conquer-once] +version = "0.2.0" +default-features = false + +[dependencies.futures-util] +version = "0.3.4" +default-features = false +features = ["alloc"] + [package.metadata.bootimage] test-args = [ "-device", diff --git a/src/kernel/interrupts.rs b/src/kernel/interrupts.rs index cf0d0be..bc3c42f 100644 --- a/src/kernel/interrupts.rs +++ b/src/kernel/interrupts.rs @@ -82,7 +82,15 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFr } } -extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) { +extern "x86-interrupt" fn keyboard_interrupt_handler( + _stack_frame: InterruptStackFrame +) { + use x86_64::instructions::port::Port; + + let mut port = Port::new(0x60); + let scancode: u8 = unsafe { port.read() }; + crate::kernel::task::keyboard::add_scancode(scancode); + unsafe { PICS.lock() .notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8()); diff --git a/src/kernel/layouts.rs b/src/kernel/layouts.rs deleted file mode 100644 index 66e1e88..0000000 --- a/src/kernel/layouts.rs +++ /dev/null @@ -1,195 +0,0 @@ -//! A standard United States 101-key (or 104-key including Windows keys) QWERTY keyboard. -//! Has a 1-row high Enter key, with Backslash above. - -use pc_keyboard::{DecodedKey, HandleControl, KeyCode, KeyboardLayout, Modifiers}; - -pub struct Qwerty104Key; - -impl KeyboardLayout for Qwerty104Key { - fn map_keycode( - keycode: KeyCode, - modifiers: &Modifiers, - _handle_ctrl: HandleControl, - ) -> DecodedKey { - match keycode { - KeyCode::BackTick => { - if modifiers.is_shifted() { - DecodedKey::Unicode('~') - } else { - DecodedKey::Unicode('`') - } - } - KeyCode::Key1 => { - if modifiers.is_shifted() { - DecodedKey::Unicode('!') - } else { - DecodedKey::Unicode('1') - } - } - KeyCode::Key2 => { - if modifiers.is_shifted() { - DecodedKey::Unicode('@') - } else { - DecodedKey::Unicode('2') - } - } - KeyCode::Key3 => { - if modifiers.is_shifted() { - DecodedKey::Unicode('#') - } else { - DecodedKey::Unicode('3') - } - } - KeyCode::Key4 => { - if modifiers.is_shifted() { - DecodedKey::Unicode('$') - } else { - DecodedKey::Unicode('4') - } - } - KeyCode::Key5 => { - if modifiers.is_shifted() { - DecodedKey::Unicode('%') - } else { - DecodedKey::Unicode('5') - } - } - KeyCode::Key6 => { - if modifiers.is_shifted() { - DecodedKey::Unicode('^') - } else { - DecodedKey::Unicode('6') - } - } - KeyCode::Key7 => { - if modifiers.is_shifted() { - DecodedKey::Unicode('&') - } else { - DecodedKey::Unicode('7') - } - } - KeyCode::Key8 => { - if modifiers.is_shifted() { - DecodedKey::Unicode('*') - } else { - DecodedKey::Unicode('8') - } - } - KeyCode::Key9 => { - if modifiers.is_shifted() { - DecodedKey::Unicode('(') - } else { - DecodedKey::Unicode('9') - } - } - KeyCode::Key0 => { - if modifiers.is_shifted() { - DecodedKey::Unicode(')') - } else { - DecodedKey::Unicode('0') - } - } - KeyCode::Minus => { - if modifiers.is_shifted() { - DecodedKey::Unicode('_') - } else { - DecodedKey::Unicode('-') - } - } - KeyCode::Equals => { - if modifiers.is_shifted() { - DecodedKey::Unicode('+') - } else { - DecodedKey::Unicode('=') - } - } - KeyCode::Backspace => DecodedKey::Unicode(0x08.into()), - KeyCode::Tab => DecodedKey::Unicode(0x09.into()), - KeyCode::Q => DecodedKey::Unicode(if modifiers.is_shifted() { 'Q' } else { 'q' }), - KeyCode::W => DecodedKey::Unicode(if modifiers.is_shifted() { 'W' } else { 'w' }), - KeyCode::E => DecodedKey::Unicode(if modifiers.is_shifted() { 'E' } else { 'e' }), - KeyCode::R => DecodedKey::Unicode(if modifiers.is_shifted() { 'R' } else { 'r' }), - KeyCode::T => DecodedKey::Unicode(if modifiers.is_shifted() { 'T' } else { 't' }), - KeyCode::Y => DecodedKey::Unicode(if modifiers.is_shifted() { 'Y' } else { 'y' }), - KeyCode::U => DecodedKey::Unicode(if modifiers.is_shifted() { 'U' } else { 'u' }), - KeyCode::I => DecodedKey::Unicode(if modifiers.is_shifted() { 'I' } else { 'i' }), - KeyCode::O => DecodedKey::Unicode(if modifiers.is_shifted() { 'O' } else { 'o' }), - KeyCode::P => DecodedKey::Unicode(if modifiers.is_shifted() { 'P' } else { 'p' }), - KeyCode::BracketSquareLeft => { - if modifiers.is_shifted() { - DecodedKey::Unicode('{') - } else { - DecodedKey::Unicode('[') - } - } - KeyCode::BracketSquareRight => { - if modifiers.is_shifted() { - DecodedKey::Unicode('}') - } else { - DecodedKey::Unicode(']') - } - } - KeyCode::BackSlash => { - if modifiers.is_shifted() { - DecodedKey::Unicode('|') - } else { - DecodedKey::Unicode('\\') - } - } - KeyCode::A => DecodedKey::Unicode(if modifiers.is_shifted() { 'A' } else { 'a' }), - KeyCode::S => DecodedKey::Unicode(if modifiers.is_shifted() { 'S' } else { 's' }), - KeyCode::D => DecodedKey::Unicode(if modifiers.is_shifted() { 'D' } else { 'd' }), - KeyCode::F => DecodedKey::Unicode(if modifiers.is_shifted() { 'F' } else { 'f' }), - KeyCode::G => DecodedKey::Unicode(if modifiers.is_shifted() { 'G' } else { 'g' }), - KeyCode::H => DecodedKey::Unicode(if modifiers.is_shifted() { 'H' } else { 'h' }), - KeyCode::J => DecodedKey::Unicode(if modifiers.is_shifted() { 'J' } else { 'j' }), - KeyCode::K => DecodedKey::Unicode(if modifiers.is_shifted() { 'K' } else { 'k' }), - KeyCode::L => DecodedKey::Unicode(if modifiers.is_shifted() { 'L' } else { 'l' }), - KeyCode::SemiColon => { - if modifiers.is_shifted() { - DecodedKey::Unicode(':') - } else { - DecodedKey::Unicode(';') - } - } - KeyCode::Quote => { - if modifiers.is_shifted() { - DecodedKey::Unicode('"') - } else { - DecodedKey::Unicode('\'') - } - } - KeyCode::Enter => DecodedKey::Unicode(10.into()), - KeyCode::Z => DecodedKey::Unicode(if modifiers.is_shifted() { 'Z' } else { 'z' }), - KeyCode::X => DecodedKey::Unicode(if modifiers.is_shifted() { 'X' } else { 'x' }), - KeyCode::C => DecodedKey::Unicode(if modifiers.is_shifted() { 'C' } else { 'c' }), - KeyCode::V => DecodedKey::Unicode(if modifiers.is_shifted() { 'V' } else { 'v' }), - KeyCode::B => DecodedKey::Unicode(if modifiers.is_shifted() { 'B' } else { 'b' }), - KeyCode::N => DecodedKey::Unicode(if modifiers.is_shifted() { 'N' } else { 'n' }), - KeyCode::M => DecodedKey::Unicode(if modifiers.is_shifted() { 'M' } else { 'm' }), - KeyCode::Comma => { - if modifiers.is_shifted() { - DecodedKey::Unicode('<') - } else { - DecodedKey::Unicode(',') - } - } - KeyCode::Fullstop => { - if modifiers.is_shifted() { - DecodedKey::Unicode('>') - } else { - DecodedKey::Unicode('.') - } - } - KeyCode::Slash => { - if modifiers.is_shifted() { - DecodedKey::Unicode('?') - } else { - DecodedKey::Unicode('/') - } - } - KeyCode::Spacebar => DecodedKey::Unicode(' '), - _ => DecodedKey::RawKey(keycode), - } - } -} diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 72b0179..06447cf 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -2,7 +2,6 @@ pub mod allocator; pub mod clock; pub mod gdt; pub mod interrupts; -pub mod layouts; pub mod memory; pub mod string; pub mod task; diff --git a/src/kernel/task/keyboard.rs b/src/kernel/task/keyboard.rs new file mode 100644 index 0000000..87b44da --- /dev/null +++ b/src/kernel/task/keyboard.rs @@ -0,0 +1,82 @@ +use crate::print; +use conquer_once::spin::OnceCell; +use core::{ + pin::Pin, + task::{Context, Poll}, +}; +use crossbeam_queue::ArrayQueue; +use futures_util::stream::Stream; +use futures_util::stream::StreamExt; +use futures_util::task::AtomicWaker; +use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; + +static SCANCODE_QUEUE: OnceCell> = OnceCell::uninit(); +static WAKER: AtomicWaker = AtomicWaker::new(); + +/// Called by the keyboard interrupt handler +/// +/// Must not block or allocate. +pub(crate) fn add_scancode(scancode: u8) { + if let Ok(queue) = SCANCODE_QUEUE.try_get() { + if let Err(_) = queue.push(scancode) { + print!("WARNING: scancode queue full; dropping keyboard input\n"); + } else { + WAKER.wake(); // new + } + } else { + print!("WARNING: scancode queue uninitialized\n"); + } +} + +pub struct ScancodeStream { + _private: (), +} + +impl ScancodeStream { + pub fn new() -> Self { + SCANCODE_QUEUE + .try_init_once(|| ArrayQueue::new(100)) + .expect("ScancodeStream::new should only be called once"); + ScancodeStream { _private: () } + } +} + +impl Stream for ScancodeStream { + type Item = u8; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { + let queue = SCANCODE_QUEUE + .try_get() + .expect("scancode queue not initialized"); + + if let Some(scancode) = queue.pop() { + return Poll::Ready(Some(scancode)); + } + + WAKER.register(&cx.waker()); + match queue.pop() { + Some(scancode) => { + WAKER.take(); + Poll::Ready(Some(scancode)) + } + None => Poll::Pending, + } + } +} + +pub async fn print_keypresses() { + let mut scancodes = ScancodeStream::new(); + let mut keyboard = Keyboard::new(ScancodeSet1::new(), + layouts::Us104Key, HandleControl::Ignore); + + while let Some(scancode) = scancodes.next().await { + 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), + } + } + } + } +} diff --git a/src/kernel/task/mod.rs b/src/kernel/task/mod.rs index d55e2a4..cfd1c1e 100644 --- a/src/kernel/task/mod.rs +++ b/src/kernel/task/mod.rs @@ -2,6 +2,7 @@ use alloc::boxed::Box; use core::task::{Context, Poll}; use core::{future::Future, pin::Pin}; +pub mod keyboard; pub mod simple_executor; pub struct Task { diff --git a/src/main.rs b/src/main.rs index 122b93e..173454f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ extern crate alloc; use bootloader::{entry_point, BootInfo}; use core::panic::PanicInfo; use infinity_os::kernel; +use infinity_os::kernel::task::keyboard; use infinity_os::kernel::task::{simple_executor::SimpleExecutor, Task}; use infinity_os::print; use x86_64::VirtAddr; @@ -28,6 +29,7 @@ pub fn kernel_main(boot_info: &'static BootInfo) -> ! { let mut executor = SimpleExecutor::new(); executor.spawn(Task::new(example_task())); + executor.spawn(Task::new(keyboard::print_keypresses())); executor.run(); infinity_os::hlt_loop(); From 93ed46e660c4b27e4ceee8944817e28eaca2a7e9 Mon Sep 17 00:00:00 2001 From: Viktor Popp Date: Sat, 18 Jan 2025 17:18:32 +0100 Subject: [PATCH 4/5] Added better keyboard task --- src/kernel/task/keyboard.rs | 34 ++++++++++++++++++---------------- src/main.rs | 14 +++----------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/kernel/task/keyboard.rs b/src/kernel/task/keyboard.rs index 87b44da..f8ab512 100644 --- a/src/kernel/task/keyboard.rs +++ b/src/kernel/task/keyboard.rs @@ -6,9 +6,8 @@ use core::{ }; use crossbeam_queue::ArrayQueue; use futures_util::stream::Stream; -use futures_util::stream::StreamExt; use futures_util::task::AtomicWaker; -use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; +use pc_keyboard::{layouts, HandleControl, Keyboard, ScancodeSet1}; static SCANCODE_QUEUE: OnceCell> = OnceCell::uninit(); static WAKER: AtomicWaker = AtomicWaker::new(); @@ -64,19 +63,22 @@ impl Stream for ScancodeStream { } } -pub async fn print_keypresses() { - let mut scancodes = ScancodeStream::new(); - let mut keyboard = Keyboard::new(ScancodeSet1::new(), - layouts::Us104Key, HandleControl::Ignore); +pub async fn keyboard_task() { + let mut _scancodes = ScancodeStream::new(); + let mut _keyboard = Keyboard::new( + ScancodeSet1::new(), + layouts::Us104Key, + HandleControl::Ignore, + ); - while let Some(scancode) = scancodes.next().await { - 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), - } - } - } - } + // while let Some(scancode) = scancodes.next().await { + // 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), + // } + // } + // } + // } } diff --git a/src/main.rs b/src/main.rs index 173454f..fe71ad1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,10 +28,11 @@ pub fn kernel_main(boot_info: &'static BootInfo) -> ! { .expect("heap initialization failed"); let mut executor = SimpleExecutor::new(); - executor.spawn(Task::new(example_task())); - executor.spawn(Task::new(keyboard::print_keypresses())); + executor.spawn(Task::new(keyboard::keyboard_task())); executor.run(); + print!("Hello, world!"); + infinity_os::hlt_loop(); } @@ -40,12 +41,3 @@ fn panic(info: &PanicInfo) -> ! { print!("{}\n", info); infinity_os::hlt_loop(); } - -async fn async_number() -> u32 { - 42 -} - -async fn example_task() { - let number = async_number().await; - print!("async number: {}\n", number); -} From 814c5454908bd2e94889b8e96a76f593671c7c1a Mon Sep 17 00:00:00 2001 From: Viktor Popp Date: Sat, 18 Jan 2025 17:51:58 +0100 Subject: [PATCH 5/5] Added advanced executor and task id's --- src/kernel/task/executor.rs | 104 ++++++++++++++++++++++++++++++++++++ src/kernel/task/keyboard.rs | 28 +++++----- src/kernel/task/mod.rs | 14 +++++ src/main.rs | 8 +-- 4 files changed, 134 insertions(+), 20 deletions(-) create mode 100644 src/kernel/task/executor.rs diff --git a/src/kernel/task/executor.rs b/src/kernel/task/executor.rs new file mode 100644 index 0000000..6b3247a --- /dev/null +++ b/src/kernel/task/executor.rs @@ -0,0 +1,104 @@ +use super::{Task, TaskId}; +use alloc::task::Wake; +use alloc::{collections::BTreeMap, sync::Arc}; +use core::task::Waker; +use core::task::{Context, Poll}; +use crossbeam_queue::ArrayQueue; + +pub struct Executor { + tasks: BTreeMap, + task_queue: Arc>, + waker_cache: BTreeMap, +} + +impl Executor { + pub fn new() -> Self { + Executor { + tasks: BTreeMap::new(), + task_queue: Arc::new(ArrayQueue::new(100)), + waker_cache: BTreeMap::new(), + } + } + + pub fn spawn(&mut self, task: Task) { + let task_id = task.id; + if self.tasks.insert(task.id, task).is_some() { + panic!("task with same ID already in tasks"); + } + self.task_queue.push(task_id).expect("queue full"); + } + + pub fn run(&mut self) -> ! { + loop { + self.run_ready_tasks(); + self.sleep_if_idle(); + } + } + + fn sleep_if_idle(&self) { + use x86_64::instructions::interrupts::{self, enable_and_hlt}; + + interrupts::disable(); + if self.task_queue.is_empty() { + enable_and_hlt(); + } else { + interrupts::enable(); + } + } + + fn run_ready_tasks(&mut self) { + // destructure `self` to avoid borrow checker errors + let Self { + tasks, + task_queue, + waker_cache, + } = self; + + while let Some(task_id) = task_queue.pop() { + let task = match tasks.get_mut(&task_id) { + Some(task) => task, + None => continue, // task no longer exists + }; + let waker = waker_cache + .entry(task_id) + .or_insert_with(|| TaskWaker::new(task_id, task_queue.clone())); + let mut context = Context::from_waker(waker); + match task.poll(&mut context) { + Poll::Ready(()) => { + // task done -> remove it and its cached waker + tasks.remove(&task_id); + waker_cache.remove(&task_id); + } + Poll::Pending => {} + } + } + } +} + +struct TaskWaker { + task_id: TaskId, + task_queue: Arc>, +} + +impl TaskWaker { + fn wake_task(&self) { + self.task_queue.push(self.task_id).expect("task_queue full"); + } + + fn new(task_id: TaskId, task_queue: Arc>) -> Waker { + Waker::from(Arc::new(TaskWaker { + task_id, + task_queue, + })) + } +} + +impl Wake for TaskWaker { + fn wake(self: Arc) { + self.wake_task(); + } + + fn wake_by_ref(self: &Arc) { + self.wake_task(); + } +} diff --git a/src/kernel/task/keyboard.rs b/src/kernel/task/keyboard.rs index f8ab512..3047e81 100644 --- a/src/kernel/task/keyboard.rs +++ b/src/kernel/task/keyboard.rs @@ -5,9 +5,9 @@ use core::{ task::{Context, Poll}, }; use crossbeam_queue::ArrayQueue; -use futures_util::stream::Stream; +use futures_util::{stream::Stream, StreamExt}; use futures_util::task::AtomicWaker; -use pc_keyboard::{layouts, HandleControl, Keyboard, ScancodeSet1}; +use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; static SCANCODE_QUEUE: OnceCell> = OnceCell::uninit(); static WAKER: AtomicWaker = AtomicWaker::new(); @@ -64,21 +64,21 @@ impl Stream for ScancodeStream { } pub async fn keyboard_task() { - let mut _scancodes = ScancodeStream::new(); - let mut _keyboard = Keyboard::new( + let mut scancodes = ScancodeStream::new(); + let mut keyboard = Keyboard::new( ScancodeSet1::new(), layouts::Us104Key, HandleControl::Ignore, ); - // while let Some(scancode) = scancodes.next().await { - // 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), - // } - // } - // } - // } + while let Some(scancode) = scancodes.next().await { + 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), + } + } + } + } } diff --git a/src/kernel/task/mod.rs b/src/kernel/task/mod.rs index cfd1c1e..4a6a425 100644 --- a/src/kernel/task/mod.rs +++ b/src/kernel/task/mod.rs @@ -1,17 +1,31 @@ use alloc::boxed::Box; +use core::sync::atomic::{AtomicU64, Ordering}; use core::task::{Context, Poll}; use core::{future::Future, pin::Pin}; +pub mod executor; pub mod keyboard; pub mod simple_executor; +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +struct TaskId(u64); + +impl TaskId { + fn new() -> Self { + static NEXT_ID: AtomicU64 = AtomicU64::new(0); + TaskId(NEXT_ID.fetch_add(1, Ordering::Relaxed)) + } +} + pub struct Task { + id: TaskId, future: Pin>>, } impl Task { pub fn new(future: impl Future + 'static) -> Task { Task { + id: TaskId::new(), future: Box::pin(future), } } diff --git a/src/main.rs b/src/main.rs index fe71ad1..63170fd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ use bootloader::{entry_point, BootInfo}; use core::panic::PanicInfo; use infinity_os::kernel; use infinity_os::kernel::task::keyboard; -use infinity_os::kernel::task::{simple_executor::SimpleExecutor, Task}; +use infinity_os::kernel::task::{executor::Executor, Task}; use infinity_os::print; use x86_64::VirtAddr; @@ -27,13 +27,9 @@ pub fn kernel_main(boot_info: &'static BootInfo) -> ! { kernel::allocator::init_heap(&mut mapper, &mut frame_allocator) .expect("heap initialization failed"); - let mut executor = SimpleExecutor::new(); + let mut executor = Executor::new(); executor.spawn(Task::new(keyboard::keyboard_task())); executor.run(); - - print!("Hello, world!"); - - infinity_os::hlt_loop(); } #[panic_handler]