diff --git a/kernel/src/arch/x86_64/interrupts.rs b/kernel/src/arch/x86_64/interrupts.rs index ee00621..3ae642a 100644 --- a/kernel/src/arch/x86_64/interrupts.rs +++ b/kernel/src/arch/x86_64/interrupts.rs @@ -1,12 +1,18 @@ -use crate::arch::x86_64::mouse::mouse_interrupt; -use crate::driver::mouse::MOUSE; -use crate::driver::timer::TIMER; -use crate::{arch::x86_64::gdt, driver::keyboard::keyboard_interrupt_handler, println}; +use crate::{ + arch::x86_64::{gdt, mouse::mouse_interrupt}, + driver::{ + keyboard::{KEYBOARD_STATE, KeyboardEvent}, + mouse::MOUSE, + timer::TIMER, + }, + println, +}; use lazy_static::lazy_static; +use pc_keyboard::DecodedKey; use pic8259::ChainedPics; use spin::Mutex; -pub use x86_64::instructions::interrupts::without_interrupts; use x86_64::{ + instructions::port::Port, registers::control::Cr2, structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}, }; @@ -113,3 +119,27 @@ extern "x86-interrupt" fn mouse_interrupt_handler(_stack_frame: InterruptStackFr .notify_end_of_interrupt(InterruptIndex::Mouse.as_u8()); } } + +pub extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) { + let mut port = Port::new(0x60); + let scancode: u8 = unsafe { port.read() }; + let mut keyboard_state = KEYBOARD_STATE.lock(); + + if let Ok(Some(key_event)) = keyboard_state.keyboard.add_byte(scancode) { + if let Some(key) = keyboard_state.keyboard.process_keyevent(key_event) { + match key { + DecodedKey::Unicode(character) => keyboard_state + .event_queue + .push_back(KeyboardEvent::Unicode(character)), + DecodedKey::RawKey(key) => keyboard_state + .event_queue + .push_back(KeyboardEvent::RawKey(key)), + } + } + } + + unsafe { + PICS.lock() + .notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8()); + } +} diff --git a/kernel/src/driver/graphics/framebuffer.rs b/kernel/src/driver/graphics/framebuffer.rs index 7a3e344..a713d10 100644 --- a/kernel/src/driver/graphics/framebuffer.rs +++ b/kernel/src/driver/graphics/framebuffer.rs @@ -4,7 +4,7 @@ use limine::framebuffer::Framebuffer as LimineFramebuffer; use spin::Mutex; #[cfg(target_arch = "x86_64")] -use crate::arch::x86_64::interrupts::without_interrupts; +use x86_64::instructions::interrupts::without_interrupts; pub struct Framebuffer { addr: *mut u32, diff --git a/kernel/src/driver/keyboard.rs b/kernel/src/driver/keyboard.rs index bea3a87..5554e58 100644 --- a/kernel/src/driver/keyboard.rs +++ b/kernel/src/driver/keyboard.rs @@ -1,37 +1,35 @@ -use crate::{ - arch::x86_64::interrupts::{InterruptIndex, PICS}, - print, -}; +use alloc::collections::VecDeque; use lazy_static::lazy_static; -use pc_keyboard::{DecodedKey, HandleControl, Keyboard, ScancodeSet1, layouts}; -use spin::Mutex; -use x86_64::{instructions::port::Port, structures::idt::InterruptStackFrame}; +use pc_keyboard::{HandleControl, Keyboard, ScancodeSet1, layouts}; +use spin::mutex::Mutex; -lazy_static! { - static ref KEYBOARD: Mutex> = - Mutex::new(Keyboard::new( - ScancodeSet1::new(), - layouts::Us104Key, - HandleControl::Ignore - )); +#[derive(Debug, Clone)] +pub enum KeyboardEvent { + Unicode(char), + RawKey(pc_keyboard::KeyCode), } -pub extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) { - let mut port = Port::new(0x60); - let scancode: u8 = unsafe { port.read() }; - let mut keyboard = KEYBOARD.lock(); - - 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), - } +pub struct KeyboardState { + pub keyboard: Keyboard, + pub event_queue: VecDeque, +} +impl KeyboardState { + pub fn new() -> KeyboardState { + KeyboardState { + keyboard: Keyboard::new( + ScancodeSet1::new(), + layouts::Us104Key, + HandleControl::Ignore, + ), + event_queue: VecDeque::new(), } } - - unsafe { - PICS.lock() - .notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8()); - } +} + +lazy_static! { + pub static ref KEYBOARD_STATE: Mutex = Mutex::new(KeyboardState::new()); +} + +pub fn pop_event() -> Option { + KEYBOARD_STATE.lock().event_queue.pop_front() } diff --git a/kernel/src/driver/mouse.rs b/kernel/src/driver/mouse.rs index 8ff0c4f..5438278 100644 --- a/kernel/src/driver/mouse.rs +++ b/kernel/src/driver/mouse.rs @@ -1,6 +1,4 @@ -use core::sync::atomic::{AtomicI16, AtomicU8, AtomicUsize, Ordering}; - -use crate::driver::graphics::{base::rgb, framebuffer::Framebuffer}; +use core::sync::atomic::{AtomicI16, AtomicU8, Ordering}; pub struct Mouse { left_button_pressed: AtomicU8, @@ -9,15 +7,8 @@ pub struct Mouse { x_delta: AtomicI16, y_delta: AtomicI16, status: AtomicU8, - mouse_x: AtomicUsize, - mouse_y: AtomicUsize, } -static CURSOR_BYTES: &[u8] = include_bytes!("../../../assets/cursors/default.bmp"); -const BMP_HEADER_SIZE: usize = 138; -const CURSOR_W: usize = 24; -const CURSOR_H: usize = 24; - impl Mouse { const fn new() -> Mouse { Mouse { @@ -27,8 +18,6 @@ impl Mouse { x_delta: AtomicI16::new(0), y_delta: AtomicI16::new(0), status: AtomicU8::new(0), - mouse_x: AtomicUsize::new(100), - mouse_y: AtomicUsize::new(100), } } @@ -50,20 +39,18 @@ impl Mouse { self.y_delta.fetch_add(y_delta, Ordering::Relaxed); } - pub fn is_left_button_pressed(&self) -> u8 { - self.left_button_pressed.load(Ordering::Relaxed) + pub fn button_state(&self) -> (u8, u8, u8) { + ( + self.left_button_pressed.load(Ordering::Relaxed), + self.right_button_pressed.load(Ordering::Relaxed), + self.middle_button_pressed.load(Ordering::Relaxed), + ) } - pub fn is_right_button_pressed(&self) -> u8 { - self.right_button_pressed.load(Ordering::Relaxed) - } - pub fn is_middle_button_pressed(&self) -> u8 { - self.middle_button_pressed.load(Ordering::Relaxed) - } - pub fn get_x_delta(&self) -> i16 { - self.x_delta.swap(0, Ordering::Relaxed) - } - pub fn get_y_delta(&self) -> i16 { - self.y_delta.swap(0, Ordering::Relaxed) + pub fn take_motion(&self) -> (i16, i16) { + ( + self.x_delta.swap(0, Ordering::Relaxed), + self.y_delta.swap(0, Ordering::Relaxed), + ) } pub fn set_status(&self, status: u8) { self.status.store(status, Ordering::Relaxed); @@ -71,61 +58,6 @@ impl Mouse { pub fn get_status(&self) -> u8 { self.status.load(Ordering::Relaxed) } - - pub fn update(&self, width: usize, height: usize) { - let x_delta = self.get_x_delta() / 5; - let y_delta = self.get_y_delta() / 5; - - if x_delta != 0 { - self.mouse_x.store( - (self.mouse_x.load(Ordering::Relaxed) as isize + x_delta as isize).max(0) as usize, - Ordering::Relaxed, - ); - } - - if y_delta != 0 { - self.mouse_y.store( - (self.mouse_y.load(Ordering::Relaxed) as isize + y_delta as isize).max(0) as usize, - Ordering::Relaxed, - ); - } - - if self.mouse_x.load(Ordering::Relaxed) > width { - self.mouse_x.store(width - CURSOR_W, Ordering::Relaxed); - } - - if self.mouse_y.load(Ordering::Relaxed) > height { - self.mouse_y.store(height - CURSOR_H, Ordering::Relaxed); - } - } - - pub fn draw(&self, fb: &mut Framebuffer) { - let pixels = &CURSOR_BYTES[BMP_HEADER_SIZE..]; // remove header - - for row in 0..CURSOR_H { - let src_row = (CURSOR_H - 1 - row) * CURSOR_W * 4; - for col in 0..CURSOR_W { - let i = src_row + col * 4; // 4 because rgba - - let b = pixels[i]; - let g = pixels[i + 1]; - let r = pixels[i + 2]; - let a = pixels[i + 3]; - - if a < 255 { - continue; - } - - let color = rgb(r, g, b); - - fb.put_pixel( - (self.mouse_x.load(Ordering::Relaxed) + col) as usize, - (self.mouse_y.load(Ordering::Relaxed) + row) as usize, - color, - ); - } - } - } } pub static MOUSE: Mouse = Mouse::new(); diff --git a/kernel/src/driver/serial.rs b/kernel/src/driver/serial.rs index 9d09d72..236ede0 100644 --- a/kernel/src/driver/serial.rs +++ b/kernel/src/driver/serial.rs @@ -5,7 +5,7 @@ use core::fmt::{self, Write}; use spin::Mutex; #[cfg(target_arch = "x86_64")] -use crate::arch::x86_64::interrupts::without_interrupts; +use x86_64::instructions::interrupts::without_interrupts; pub struct ConsoleWriter<'a> { pub fb: &'a mut Framebuffer, diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 401ab21..fd000e1 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -10,9 +10,9 @@ use limine::request::{ DateAtBootRequest, FramebufferRequest, HhdmRequest, MemoryMapRequest, MpRequest, RequestsEndMarker, RequestsStartMarker, }; -use x86_64::instructions::interrupts::without_interrupts; pub mod arch; pub mod driver; +pub mod userspace_stub; pub mod util; use crate::arch::arch::{infinite_idle, init, kernel_crash, sleep}; @@ -24,9 +24,7 @@ use crate::driver::graphics::primitives::{ use crate::driver::mouse::MOUSE; use crate::driver::serial::{ConsoleWriter, init_serial_console, with_serial_console}; use crate::driver::timer::TIMER; -use crate::util::test_performance; -use alloc::{boxed::Box, string::ToString, vec::Vec}; - +use crate::userspace_stub::userspace_init; /// Sets the base revision to the latest revision supported by the crate. /// See specification for further info. /// Be sure to mark all limine requests with #[used], otherwise they may be removed by the compiler. @@ -127,92 +125,7 @@ unsafe extern "C" fn kmain() -> ! { println!("Could not get date at boot. Will default to 0.") } - boot_animation(); - - let mut mouse_status = 0; - let mut width = 0; - let mut height = 0; - - loop { - with_serial_console(|serial_console| serial_console.clear(0, 0)); - with_framebuffer(|fb| fb.clear(rgb(253, 129, 0))); - test_performance(|| { - mouse_status = MOUSE.get_status(); - with_framebuffer(|mut fb| { - width = fb.width; - height = fb.height; - MOUSE.update(width, height); - - rectangle_filled(&mut fb, 700, 400, 200, 200, rgb(0, 0, 0)); - rectangle_outline(&mut fb, 400, 400, 100, 100, rgb(0, 0, 0)); - circle_filled(&mut fb, 200, 200, 100, rgb(0, 0, 0)); - circle_outline(&mut fb, 400, 200, 100, rgb(0, 0, 0)); - triangle_outline(&mut fb, 100, 400, 200, 400, 150, 600, rgb(0, 0, 0)); - - MOUSE.draw(fb); - }); - - let (hours, minutes, seconds) = - unix_to_hms(TIMER.get_date_at_boot() + (TIMER.now().elapsed()) / 1000); - - print!( - "{:?}:{:?}:{:?}\nMouse status: {:?}", - hours, minutes, seconds, mouse_status - ); - }); - with_framebuffer(|fb| { - fb.swap(); - }); - sleep(16); - } -} - -fn boot_animation() { - let mut i = 1; - - while i < 10 { - let mut width = 0; - let mut height = 0; - - with_framebuffer(|fb| { - fb.clear(rgb(253, 129, 0)); - width = fb.width; - height = fb.height; - }); - - let text_width = ("XunilOS Loading".len() + ".".repeat(i).len()) * 4 * 2; - - with_serial_console(|serial_console| { - serial_console.clear(width / 2 - text_width / 2, height / 2) - }); - - println!( - "{}", - "XunilOS Loading".to_string() + &".".repeat(i).as_str() - ); - - i += 1; - - with_framebuffer(|fb| fb.swap()); - - sleep(200); - } - - with_serial_console(|serial_console| { - serial_console.clear(0, 0); - }); - - with_framebuffer(|fb| { - fb.clear(rgb(253, 129, 0)); - }); -} - -fn unix_to_hms(timestamp: u64) -> (u64, u64, u64) { - let seconds = timestamp % 86400; - let h = seconds / 3600; - let m = (seconds % 3600) / 60; - let s = seconds % 60; - (h, m, s) + userspace_init() } #[panic_handler] diff --git a/kernel/src/userspace_stub.rs b/kernel/src/userspace_stub.rs new file mode 100644 index 0000000..e960fd7 --- /dev/null +++ b/kernel/src/userspace_stub.rs @@ -0,0 +1,155 @@ +use alloc::string::ToString; + +use crate::{ + arch::arch::sleep, + driver::{ + graphics::{ + base::rgb, + framebuffer::with_framebuffer, + primitives::{ + circle_filled, circle_outline, rectangle_filled, rectangle_outline, + triangle_outline, + }, + }, + mouse::MOUSE, + serial::with_serial_console, + timer::TIMER, + }, + print, println, + util::test_performance, +}; + +static CURSOR_BYTES: &[u8] = include_bytes!("../../assets/cursors/default.bmp"); +const BMP_HEADER_SIZE: usize = 138; +pub const CURSOR_W: usize = 24; +pub const CURSOR_H: usize = 24; + +fn unix_to_hms(timestamp: u64) -> (u64, u64, u64) { + let seconds = timestamp % 86400; + let h = seconds / 3600; + let m = (seconds % 3600) / 60; + let s = seconds % 60; + (h, m, s) +} + +fn boot_animation() { + let mut i = 1; + + while i < 10 { + let mut width = 0; + let mut height = 0; + + with_framebuffer(|fb| { + fb.clear(rgb(253, 129, 0)); + width = fb.width; + height = fb.height; + }); + + let text_width = ("XunilOS Loading".len() + ".".repeat(i).len()) * 4 * 2; + + with_serial_console(|serial_console| { + serial_console.clear(width / 2 - text_width / 2, height / 2) + }); + + println!( + "{}", + "XunilOS Loading".to_string() + &".".repeat(i).as_str() + ); + + i += 1; + + with_framebuffer(|fb| fb.swap()); + + sleep(200); + } + + with_serial_console(|serial_console| { + serial_console.clear(0, 0); + }); + + with_framebuffer(|fb| { + fb.clear(rgb(253, 129, 0)); + }); +} + +pub fn userspace_init() -> ! { + // this is just a stub + boot_animation(); + + let mut mouse_status = 0; + let mut width = 0; + let mut height = 0; + let mut mouse_x = 100; + let mut mouse_y = 100; + + loop { + with_serial_console(|serial_console| serial_console.clear(0, 0)); + with_framebuffer(|fb| fb.clear(rgb(253, 129, 0))); + test_performance(|| { + mouse_status = MOUSE.get_status(); + with_framebuffer(|mut fb| { + width = fb.width; + height = fb.height; + + let (x_delta, y_delta) = MOUSE.take_motion(); + + if x_delta != 0 { + mouse_x = (mouse_x as isize + x_delta as isize).max(0) as usize; + } + if y_delta != 0 { + mouse_y = (mouse_y as isize + y_delta as isize).max(0) as usize; + } + if mouse_x > width { + mouse_x = width - CURSOR_W; + } + if mouse_y > height { + mouse_y = height - CURSOR_H; + } + + rectangle_filled(&mut fb, 700, 400, 200, 200, rgb(0, 0, 0)); + rectangle_outline(&mut fb, 400, 400, 100, 100, rgb(0, 0, 0)); + circle_filled(&mut fb, 200, 200, 100, rgb(0, 0, 0)); + circle_outline(&mut fb, 400, 200, 100, rgb(0, 0, 0)); + triangle_outline(&mut fb, 100, 400, 200, 400, 150, 600, rgb(0, 0, 0)); + + let pixels = &CURSOR_BYTES[BMP_HEADER_SIZE..]; // remove header + + for row in 0..CURSOR_H { + let src_row = (CURSOR_H - 1 - row) * CURSOR_W * 4; + for col in 0..CURSOR_W { + let i = src_row + col * 4; // 4 because rgba + + let b = pixels[i]; + let g = pixels[i + 1]; + let r = pixels[i + 2]; + let a = pixels[i + 3]; + + if a < 255 { + continue; + } + + let color = rgb(r, g, b); + + fb.put_pixel((mouse_x + col) as usize, (mouse_y + row) as usize, color); + } + } + }); + + let (hours, minutes, seconds) = + unix_to_hms(TIMER.get_date_at_boot() + (TIMER.now().elapsed()) / 1000); + + print!( + "{:?}:{:?}:{:?}\nMouse status: {:?}\nDesktop Size: {:?}", + hours, + minutes, + seconds, + mouse_status, + (width, height) + ); + }); + with_framebuffer(|fb| { + fb.swap(); + }); + sleep(1000 / 165); + } +}