From 5dc73e70003d7826f09ef3d8b3ed11a46eb61b81 Mon Sep 17 00:00:00 2001 From: Jacob Hinchliffe Date: Sun, 23 Feb 2025 03:15:19 +0000 Subject: [PATCH 1/8] Update Cargo.toml to use new registry --- kernel/Cargo.toml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 4005239..da63b77 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -5,14 +5,12 @@ edition = "2021" [dependencies] limine = "0.3.1" -lib_framebuffer = { path = "../lib/lib_framebuffer" } -lib_serial = { path = "../lib/lib_serial" } -lib_ascii = { path = "../lib/lib_ascii" } -lib_alloc = { path = "../lib/lib_alloc" } -lib_application = { path = "../lib/lib_application" } -lib_async = { path = "../lib/lib_async" } -lib_keyboard = { path = "../lib/lib_keyboard" } - +lib_framebuffer = { version = "0.1.0", path = "../lib/lib_framebuffer", registry = "gitea" } +lib_serial = { version = "0.1.0", path = "../lib/lib_serial", registry = "gitea" } +lib_ascii = { version = "0.1.0", path = "../lib/lib_ascii", registry = "gitea" } +lib_application = { version = "0.1.0", path = "../lib/lib_application", registry = "gitea" } +lib_async = { version = "0.1.0", path = "../lib/lib_async", registry = "gitea" } +lib_keyboard = { version = "0.1.0", path = "../lib/lib_keyboard", registry = "gitea" } x86_64 = "0.15.2" spin = "0.9.8" pic8259 = "0.11.0" From c763f512f11224d7c46eda66c1a20cb04bfb12c3 Mon Sep 17 00:00:00 2001 From: Jacob Hinchliffe Date: Sun, 23 Feb 2025 03:16:22 +0000 Subject: [PATCH 2/8] Accidentally forgot to add lib alloc lol --- kernel/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index da63b77..feb1490 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -11,6 +11,7 @@ lib_ascii = { version = "0.1.0", path = "../lib/lib_ascii", registry = "gitea" } lib_application = { version = "0.1.0", path = "../lib/lib_application", registry = "gitea" } lib_async = { version = "0.1.0", path = "../lib/lib_async", registry = "gitea" } lib_keyboard = { version = "0.1.0", path = "../lib/lib_keyboard", registry = "gitea" } +lib_alloc = { version = "0.1.0", path = "../lib/lib_alloc", registry = "gitea" } x86_64 = "0.15.2" spin = "0.9.8" pic8259 = "0.11.0" From 43b1db41caeb3db849cd3abfcff8f1248645a08d Mon Sep 17 00:00:00 2001 From: Jacob Hinchliffe Date: Sun, 23 Feb 2025 04:42:30 +0000 Subject: [PATCH 3/8] Introducing the hottest library crate in town (libk!) --- .cargo/config.toml | 12 +- .gitmodules | 21 - Cargo.lock | 76 +--- Cargo.toml | 12 +- kernel/Cargo.toml | 8 +- kernel/src/arch/x86_64/interrupts.rs | 6 +- kernel/src/lib.rs | 10 +- kernel/src/main.rs | 14 +- lib/lib_alloc | 1 - lib/lib_application | 1 - lib/lib_ascii | 1 - lib/lib_async | 1 - lib/lib_framebuffer | 1 - lib/lib_keyboard | 1 - lib/lib_serial | 1 - libk/Cargo.toml | 21 + libk/README.md | 24 ++ libk/src/alloc.rs | 3 + libk/src/alloc/allocator.rs | 45 +++ libk/src/io.rs | 17 + libk/src/io/ascii.rs | 210 ++++++++++ libk/src/io/ascii/font.rs | 578 +++++++++++++++++++++++++++ libk/src/io/framebuffer.rs | 83 ++++ libk/src/io/framebuffer/colour.rs | 53 +++ libk/src/io/keyboard.rs | 90 +++++ libk/src/io/port.rs | 25 ++ libk/src/io/serial.rs | 159 ++++++++ libk/src/lib.rs | 15 + libk/src/scheduling.rs | 1 + libk/src/scheduling/task.rs | 133 ++++++ 30 files changed, 1491 insertions(+), 132 deletions(-) delete mode 100644 .gitmodules delete mode 160000 lib/lib_alloc delete mode 160000 lib/lib_application delete mode 160000 lib/lib_ascii delete mode 160000 lib/lib_async delete mode 160000 lib/lib_framebuffer delete mode 160000 lib/lib_keyboard delete mode 160000 lib/lib_serial create mode 100644 libk/Cargo.toml create mode 100644 libk/README.md create mode 100644 libk/src/alloc.rs create mode 100644 libk/src/alloc/allocator.rs create mode 100644 libk/src/io.rs create mode 100644 libk/src/io/ascii.rs create mode 100644 libk/src/io/ascii/font.rs create mode 100644 libk/src/io/framebuffer.rs create mode 100644 libk/src/io/framebuffer/colour.rs create mode 100644 libk/src/io/keyboard.rs create mode 100644 libk/src/io/port.rs create mode 100644 libk/src/io/serial.rs create mode 100644 libk/src/lib.rs create mode 100644 libk/src/scheduling.rs create mode 100644 libk/src/scheduling/task.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index cd125e0..400f704 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -10,4 +10,14 @@ build-std-features = ["compiler-builtins-mem"] RUST_TARGET_PATH = { value = "kernel", relative = true } [target.x86_64-kernel] -runner = "scripts/run.sh" \ No newline at end of file +runner = "scripts/run.sh" + +[registry] +default = "gitea" + +[registries.gitea] +index = "sparse+https://git.zxq5.dev/api/packages/OsDev/cargo/" # Sparse index +# index = "https://gitea.example.com/{owner}/_cargo-index.git" # Git + +# [net] +# git-fetch-with-cli = true diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 66cee7a..0000000 --- a/.gitmodules +++ /dev/null @@ -1,21 +0,0 @@ -[submodule "lib/lib_application"] - path = lib/lib_application - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_application.git -[submodule "lib/lib_ascii"] - path = lib/lib_ascii - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_ascii.git -[submodule "lib/lib_framebuffer"] - path = lib/lib_framebuffer - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_framebuffer.git -[submodule "lib/lib_serial"] - path = lib/lib_serial - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_serial.git -[submodule "lib/lib_alloc"] - path = lib/lib_alloc - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_alloc.git -[submodule "lib/lib_async"] - path = lib/lib_async - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_async.git -[submodule "lib/lib_keyboard"] - path = lib/lib_keyboard - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_keyboard.git diff --git a/Cargo.lock b/Cargo.lock index 5f2a6c8..5d87614 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,9 +22,9 @@ checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "cc" -version = "1.2.14" +version = "1.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" +checksum = "c736e259eea577f443d5c86c304f9f4ae0295c43f3ba05c21f1d66b5f06001af" dependencies = [ "shlex", ] @@ -69,13 +69,7 @@ name = "foundry_os" version = "0.1.0" dependencies = [ "cc", - "lib_alloc", - "lib_application", - "lib_ascii", - "lib_async", - "lib_framebuffer", - "lib_keyboard", - "lib_serial", + "libk", "limine", "pc-keyboard", "pic8259", @@ -108,73 +102,15 @@ dependencies = [ ] [[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "lib_alloc" -version = "0.1.0" -dependencies = [ - "linked_list_allocator", - "x86_64", -] - -[[package]] -name = "lib_application" -version = "0.1.0" -dependencies = [ - "lib_ascii", -] - -[[package]] -name = "lib_ascii" -version = "0.1.0" -dependencies = [ - "lazy_static", - "lib_framebuffer", - "spin", - "x86_64", -] - -[[package]] -name = "lib_async" -version = "0.1.0" -dependencies = [ - "crossbeam", - "spin", - "x86_64", -] - -[[package]] -name = "lib_framebuffer" -version = "0.1.0" -dependencies = [ - "limine", - "spin", -] - -[[package]] -name = "lib_keyboard" +name = "libk" version = "0.1.0" dependencies = [ "crossbeam", "futures-util", - "lib_ascii", + "limine", + "linked_list_allocator", "pc-keyboard", "spin", -] - -[[package]] -name = "lib_serial" -version = "0.1.0" -dependencies = [ - "lazy_static", - "spin", "x86_64", ] diff --git a/Cargo.toml b/Cargo.toml index c6a9865..b3cb7bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,19 +1,11 @@ [workspace] -members = [ - "kernel", - "lib/lib_framebuffer", - "lib/lib_serial", - "lib/lib_ascii", - "lib/lib_application", - "lib/lib_alloc", - "lib/lib_async", - "lib/lib_keyboard", -] +members = ["kernel", "libk"] resolver = "2" [workspace.package] version = "0.1.0" edition = "2021" +authors = ["The Foundry OS contributors"] [profile.dev] opt-level = "z" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index feb1490..48f4be3 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -5,13 +5,7 @@ edition = "2021" [dependencies] limine = "0.3.1" -lib_framebuffer = { version = "0.1.0", path = "../lib/lib_framebuffer", registry = "gitea" } -lib_serial = { version = "0.1.0", path = "../lib/lib_serial", registry = "gitea" } -lib_ascii = { version = "0.1.0", path = "../lib/lib_ascii", registry = "gitea" } -lib_application = { version = "0.1.0", path = "../lib/lib_application", registry = "gitea" } -lib_async = { version = "0.1.0", path = "../lib/lib_async", registry = "gitea" } -lib_keyboard = { version = "0.1.0", path = "../lib/lib_keyboard", registry = "gitea" } -lib_alloc = { version = "0.1.0", path = "../lib/lib_alloc", registry = "gitea" } +libk = { path = "../libk" } x86_64 = "0.15.2" spin = "0.9.8" pic8259 = "0.11.0" diff --git a/kernel/src/arch/x86_64/interrupts.rs b/kernel/src/arch/x86_64/interrupts.rs index 3ad7ef9..f5e7d2e 100644 --- a/kernel/src/arch/x86_64/interrupts.rs +++ b/kernel/src/arch/x86_64/interrupts.rs @@ -1,6 +1,4 @@ -use lib_ascii::println_log; -use lib_serial::serial_println; -// use x86_64::instructions::port::Port; +use libk::prelude::*; use x86_64::registers::control::Cr2; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}; @@ -98,7 +96,7 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStac let mut port = Port::new(0x60); let scancode: u8 = unsafe { port.read() }; - lib_keyboard::add_scancode(scancode); + libk::io::keyboard::add_scancode(scancode); unsafe { PICS.lock() diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 68bf61b..4d1a129 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -4,13 +4,11 @@ extern crate alloc; use core::arch::asm; -use lib_alloc::allocator::init_heap; use limine::BaseRevision; -pub use lib_ascii::{print, print_log, println, println_log, WRITER}; -pub use lib_serial::{serial_print, serial_println, serial_read}; -// use x86_64::structures::paging::Translate; -// use x86_64::PhysAddr; +use libk::alloc::init_heap; +use libk::prelude::*; + use x86_64::VirtAddr; mod arch; @@ -53,7 +51,7 @@ pub fn boot() -> Result<(), &'static str> { let memory_map = memmap::get_memory_map(); print_log!(" Initialising Serial... "); - lib_serial::init()?; + libk::io::serial::init()?; println_log!("[Success]"); print_log!(" Setting Up Global Descriptor Table... "); diff --git a/kernel/src/main.rs b/kernel/src/main.rs index d9e5708..8b5b3b8 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -3,9 +3,11 @@ extern crate alloc; -use foundry_os::{println, println_log}; -use lib_async::task::{Executor, Task}; -use lib_keyboard::print_keypresses; +use libk::{ + io, + prelude::*, + scheduling::task::{Executor, Task}, +}; #[no_mangle] extern "C" fn kmain() -> ! { @@ -16,8 +18,8 @@ extern "C" fn kmain() -> ! { println_log!("[ Kernel Initialised Successfully ] "); - let dimensions = lib_ascii::screensize_chars(); - let dimensions2 = lib_framebuffer::screensize_px(); + let dimensions = io::ascii::screensize_chars(); + let dimensions2 = io::ascii::screensize_px(); println!("Dimensions: {}x{} (px)", dimensions2.0, dimensions2.1); println!("Dimensions: {}x{} (chars)", dimensions.0, dimensions.1); @@ -44,7 +46,7 @@ extern "C" fn kmain() -> ! { ); let mut executor = Executor::new(); - executor.spawn(Task::new(print_keypresses())); + executor.spawn(Task::new(io::keyboard::print_keypresses())); executor.try_run(); loop {} diff --git a/lib/lib_alloc b/lib/lib_alloc deleted file mode 160000 index cce44f5..0000000 --- a/lib/lib_alloc +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cce44f5273d51ff44a234f3745e97f97a5ed66d4 diff --git a/lib/lib_application b/lib/lib_application deleted file mode 160000 index 4b1c606..0000000 --- a/lib/lib_application +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4b1c60676a2f67c2f95139ef2820238cdcbbf19e diff --git a/lib/lib_ascii b/lib/lib_ascii deleted file mode 160000 index 70d528b..0000000 --- a/lib/lib_ascii +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 70d528b2e8dc4d5b522955c248f47da74ce28678 diff --git a/lib/lib_async b/lib/lib_async deleted file mode 160000 index 5e74d22..0000000 --- a/lib/lib_async +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5e74d22e25e1c2b79e50e40b3182828efcbc159c diff --git a/lib/lib_framebuffer b/lib/lib_framebuffer deleted file mode 160000 index 5355327..0000000 --- a/lib/lib_framebuffer +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 53553278d11e798f8dc770b9f5efe50d9b737c68 diff --git a/lib/lib_keyboard b/lib/lib_keyboard deleted file mode 160000 index b475480..0000000 --- a/lib/lib_keyboard +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b475480d8f3783acdba4d6cf457464794da7af70 diff --git a/lib/lib_serial b/lib/lib_serial deleted file mode 160000 index ed2fa6b..0000000 --- a/lib/lib_serial +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ed2fa6b50102607d33973c1851a0ec8c895ed4fa diff --git a/libk/Cargo.toml b/libk/Cargo.toml new file mode 100644 index 0000000..a6d272e --- /dev/null +++ b/libk/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "libk" +publish = ["gitea"] +version.workspace = true +edition.workspace = true +authors.workspace = true +description = "A library crate used to write the kernel for Foundry OS." + +[dependencies] +limine = "0.3.1" +x86_64 = "0.15.2" +crossbeam = { version = "0.8.4", default-features = false, features = [ + "alloc", + "crossbeam-queue", +] } +pc-keyboard = "0.8.0" +spin = "0.9.8" +futures-util = { version = "0.3.31", default-features = false, features = [ + "alloc", +] } +linked_list_allocator = "0.10.5" diff --git a/libk/README.md b/libk/README.md new file mode 100644 index 0000000..0603a21 --- /dev/null +++ b/libk/README.md @@ -0,0 +1,24 @@ +# libk is for the code that did not make the kernel* + +\*crate, lol. + +libk is an attempt to move away from the godforsaken git submodules that plagued our forefathers. Now we have a crate containing a bunch of code that didn't quite make the core kernel crate, which should be: + +* simpler to maintain +* has a catchier name +* less fighting with Cargo.toml manifests + +## TODO: + +A lot of things must be improved and worked on, feel free to add extra TODOs below. + +[] Create a kernel logging abstraction similar to Linux. (this should probably just use the serial drivers) + +The rationale behind this is that we want some sort of debug log/tracing support so we aren't just printf debugging forever. + +## Authors + +Again, write your name below if you like: + +* @zxq5 (wrote most of the libraries as of 23/02/25) +* @nullndvoid (made this lushious library crate) \ No newline at end of file diff --git a/libk/src/alloc.rs b/libk/src/alloc.rs new file mode 100644 index 0000000..56c2a60 --- /dev/null +++ b/libk/src/alloc.rs @@ -0,0 +1,3 @@ +pub mod allocator; + +pub use self::allocator::init_heap; diff --git a/libk/src/alloc/allocator.rs b/libk/src/alloc/allocator.rs new file mode 100644 index 0000000..31547ed --- /dev/null +++ b/libk/src/alloc/allocator.rs @@ -0,0 +1,45 @@ +use linked_list_allocator::LockedHeap; +use x86_64::{ + structures::paging::{ + mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB, + }, + VirtAddr, +}; + +/// We are currently using a linked list heap allocator which uses our underlying page allocator. +pub type FoundryAllocator = LockedHeap; + +#[global_allocator] +/// This is now Rust's global allocator, so we can use stuff requiring heap allocations. +static ALLOCATOR: FoundryAllocator = FoundryAllocator::empty(); + +pub const HEAP_START: usize = 0x4444_4444_0000; +pub const HEAP_SIZE: usize = 1000 * 1024; + +/// Sets up the heap using the backing page frame allocator. +pub fn init_heap( + mapper: &mut impl Mapper, + frame_allocator: &mut impl FrameAllocator, +) -> Result<(), MapToError> { + let range = { + let heap_start = VirtAddr::new(HEAP_START as u64); + let heap_end = heap_start + HEAP_SIZE as u64 - 1u64; + let heap_start_page = Page::::containing_address(heap_start); + let heap_end_page = Page::::containing_address(heap_end); + Page::range_inclusive(heap_start_page, heap_end_page) + }; + + for page in range { + let frame = frame_allocator + .allocate_frame() + .ok_or(MapToError::FrameAllocationFailed)?; + let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; + unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() }; + } + + unsafe { + ALLOCATOR.lock().init(HEAP_START as *mut u8, HEAP_SIZE); + } + + Ok(()) +} diff --git a/libk/src/io.rs b/libk/src/io.rs new file mode 100644 index 0000000..a1bd4a0 --- /dev/null +++ b/libk/src/io.rs @@ -0,0 +1,17 @@ +pub mod ascii; +pub mod framebuffer; +pub mod keyboard; +pub mod port; +pub mod serial; + +// Re-exported macro definitions. + +pub use crate::print; +pub use crate::print_log; +pub use crate::printerr; +pub use crate::println; +pub use crate::println_log; +pub use crate::printlnerr; + +pub use crate::serial_print; +pub use crate::serial_println; diff --git a/libk/src/io/ascii.rs b/libk/src/io/ascii.rs new file mode 100644 index 0000000..a75520b --- /dev/null +++ b/libk/src/io/ascii.rs @@ -0,0 +1,210 @@ +use core::fmt; +use spin::{Lazy, Mutex}; +use x86_64::instructions::interrupts; + +pub use super::framebuffer::screensize_px; +use super::framebuffer::{Color, FRAMEBUFFER_WRITER}; + +mod font; +use font::FONT; + +static FONT_WIDTH: u32 = 8; +static FONT_HEIGHT: u32 = 16; + +pub static WRITER: Lazy> = Lazy::new(|| Mutex::new(Writer::new())); + +pub fn screensize_chars() -> (u32, u32) { + let writer = WRITER.lock(); + (writer.screen_width, writer.screen_height) +} + +pub struct Writer { + /// Measured in chars not pixels. + screen_width: u32, + /// Measured in chars not pixels. + screen_height: u32, + /// 16 pixels tall. + text_line: u32, + /// 8 pixels wide. + text_col: u32, + + fg_color: Color, + bg_color: Color, + + offset1: usize, + offset2: usize, +} + +impl Writer { + pub fn new() -> Self { + if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { + Self { + screen_width: writer.width() as u32 / 8, + screen_height: writer.height() as u32 / 16, + text_line: 0, + text_col: 0, + fg_color: Color::White, + bg_color: Color::Black, + offset1: 16, + offset2: 0, + } + } else { + panic!("Framebuffer writer not initialized"); + } + } + + pub fn write_char(&mut self, c: u16) { + if c as u8 == b'\n' { + self.newline(); + return; + } + + // get the character data from the font array. -- each byte is a row of pixels + let data: &[u8] = &FONT[c as usize * 16..(c as usize + 1) * 16]; + + if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { + for row in 0..16 { + let line: u8 = data[row]; + for col in 0..8 { + let pixel_x: u32 = self.text_col * FONT_WIDTH + col; + let pixel_y: u32 = self.text_line * FONT_HEIGHT + row as u32; + + if line & (0x80 >> col) != 0 { + // write the foreground color + writer.write_pixel(pixel_x as usize, pixel_y as usize, self.fg_color); + } else { + // write the background color + writer.write_pixel(pixel_x as usize, pixel_y as usize, self.bg_color); + } + } + } + } + + // go to next position + if self.text_col + 1 >= self.screen_width { + self.newline(); + } else { + self.text_col += 1; + } + } + + pub fn set_offset(&mut self, offset1: usize, offset2: usize) { + self.offset1 = offset1; + self.offset2 = offset2; + } + + pub fn dimensions(&self) -> (u32, u32) { + (self.screen_width, self.screen_height) + } + + pub fn next_char(&mut self) { + self.text_col += 1; + } + + pub fn newline(&mut self) { + self.text_col = 0; + + if self.text_line + 1 >= self.screen_height { + self.text_line = 0; + } else { + self.text_line += 1; + } + } + + pub fn write_string(&mut self, s: &str) { + for c in s.chars() { + self.write_char(c as u16); + } + } + + pub fn set_colour(&mut self, fg: Color, bg: Color) { + self.fg_color = fg; + self.bg_color = bg; + } + + pub fn reset_colour(&mut self) { + self.fg_color = Color::White; + self.bg_color = Color::Black; + } +} + +impl core::fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + self.write_string(s); + Ok(()) + } +} + +fn write(args: fmt::Arguments, fg: Color, bg: Color) { + use core::fmt::Write; + + interrupts::without_interrupts(|| { + let mut writer = WRITER.lock(); + writer.set_colour(fg, bg); + writer.write_fmt(args).unwrap(); + writer.reset_colour(); + }); +} + +pub fn _print(args: fmt::Arguments) { + x86_64::instructions::interrupts::without_interrupts(|| { + write(args, Color::White, Color::Black); + }) +} + +pub fn _print_err(args: fmt::Arguments) { + x86_64::instructions::interrupts::without_interrupts(|| { + write(args, Color::Red, Color::Black); + }) +} + +pub fn _print_log(args: fmt::Arguments) { + x86_64::instructions::interrupts::without_interrupts(|| { + write(args, Color::Yellow, Color::Black); + }) +} + +pub fn clear_screen() { + interrupts::without_interrupts(|| { + let mut writer = WRITER.lock(); + writer.text_line = 0; + writer.text_col = 0; + + if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { + writer.clear(); + } + }); +} + +#[macro_export] +macro_rules! println_log { + () => ($crate::print_log!("\n")); + ($($arg:tt)*) => ($crate::print_log!("{}\n", format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! print_log { + ($($arg:tt)*) => ($crate::io::ascii::_print_log(format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::io::ascii::_print(format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! printlnerr { + () => ($crate::printerr!("\n")); + ($($arg:tt)*) => ($crate::printerr!("{}\n", format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! printerr { + ($($arg:tt)*) => ($crate::_print_err(format_args!($($arg)*))); +} diff --git a/libk/src/io/ascii/font.rs b/libk/src/io/ascii/font.rs new file mode 100644 index 0000000..6d5ded3 --- /dev/null +++ b/libk/src/io/ascii/font.rs @@ -0,0 +1,578 @@ +pub static FONT: [u8; 288 * 16] = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 0 + 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, + 0x00, // 1 + 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 2 + 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 3 + 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, + 0x00, // 4 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, // 5 + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 6 + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 8 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, // 9 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, // 10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, + 0xff, // 11 + 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, + 0x00, // 12 + 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 13 + 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, + 0x00, // 14 + 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 15 + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, + 0x00, // 16 + 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, + 0x00, // 17 + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, // 18 + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x00, // 19 + 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, + 0x00, // 20 + 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, + 0x00, // 21 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 22 + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 23 + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 24 + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, // 25 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 26 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 27 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 28 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 29 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, // 30 + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, // 31 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 32 + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 33 + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 34 + 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, + 0x00, // 35 + 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, + 0x00, // 36 + 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, + 0x00, // 37 + 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 38 + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 39 + 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, + 0x00, // 40 + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, // 41 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 42 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 43 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, + 0x00, // 44 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 45 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 46 + 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, + 0x00, // 47 + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xd6, 0xd6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, + 0x00, // 48 + 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 49 + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 50 + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 51 + 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, + 0x00, // 52 + 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 53 + 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 54 + 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, + 0x00, // 55 + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 56 + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, + 0x00, // 57 + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, // 58 + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, // 59 + 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, + 0x00, // 60 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 61 + 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, + 0x00, // 62 + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 63 + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 64 + 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 65 + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, + 0x00, // 66 + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 67 + 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, + 0x00, // 68 + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 69 + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, // 70 + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, + 0x00, // 71 + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 72 + 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 73 + 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, + 0x00, // 74 + 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, // 75 + 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 76 + 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 77 + 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 78 + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 79 + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, // 80 + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, + 0x00, // 81 + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, // 82 + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 83 + 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 84 + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 85 + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, + 0x00, // 86 + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0xee, 0x6c, 0x00, 0x00, 0x00, + 0x00, // 87 + 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x7c, 0x38, 0x38, 0x7c, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 88 + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 89 + 0x00, 0x00, 0xfe, 0xc6, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 90 + 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 91 + 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, + 0x00, // 92 + 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 93 + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 94 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, // 95 + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 96 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 97 + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 98 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 99 + 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 101 + 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, // 102 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, + 0x00, // 103 + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, // 104 + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 105 + 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, + 0x00, // 106 + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, // 107 + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 108 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 109 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x00, // 110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 111 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, + 0x00, // 112 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, + 0x00, // 113 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, // 114 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 115 + 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, + 0x00, // 116 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 117 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, // 118 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00, + 0x00, // 119 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 120 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, + 0x00, // 121 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 122 + 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, + 0x00, // 123 + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 124 + 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, + 0x00, // 125 + 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 126 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, // 127 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 128 + 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, // 129 + 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 130 + 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, + 0x00, // 131 + 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 132 + 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, + 0x00, // 133 + 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 134 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 135 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, // 136 + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 137 + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, // 138 + 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 139 + 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, + 0x00, // 140 + 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, + 0x00, // 141 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 142 + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 143 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 144 + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, + 0x00, // 145 + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00, + 0x00, // 146 + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 147 + 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 148 + 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 149 + 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, + 0x00, // 150 + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, + 0x00, // 151 + 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 152 + 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 153 + 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 154 + 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 155 + 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, + 0x00, // 156 + 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 157 + 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 158 + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 159 + 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 160 + 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 161 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, + 0x00, // 162 + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, + 0x00, // 163 + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 164 + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 165 + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 166 + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 167 + 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 168 + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 169 + 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 170 + 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 171 + 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x00, // 172 + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 173 + 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 174 + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 175 + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 176 + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, // 177 + 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 178 + 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 179 + 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 180 + 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 181 + 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, + 0x00, // 182 + 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, + 0x00, // 183 + 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, + 0x00, // 184 + 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, + 0x00, // 185 + 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 186 + 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 187 + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, + 0x00, // 188 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 189 + 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 190 + 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, + 0x00, // 191 + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, + 0x00, // 192 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, + 0x00, // 193 + 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 194 + 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, + 0x00, // 195 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 196 + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x00, // 197 + 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 198 + 0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 199 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 200 + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 201 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 202 + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, // 203 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 204 + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, // 205 + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 206 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 207 + 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, + 0x00, // 208 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 209 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 210 + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 211 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 212 + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, // 213 + 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 214 + 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 215 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, // 216 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, // 217 + 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 218 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, + 0x00, // 219 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 220 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 221 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 222 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 223 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 224 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 225 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 226 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 227 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 228 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 229 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 230 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 231 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 232 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 233 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 234 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 235 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 236 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 237 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 238 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 239 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 240 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 241 + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 242 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 243 + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 244 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 245 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 246 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 247 + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 248 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 249 + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 250 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 251 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 252 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 253 + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 254 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 255 + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 256 + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 257 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 258 + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 259 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 260 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, // 261 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, // 262 + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, // 263 + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, // 264 + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, + 0x44, // 265 + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, + 0xaa, // 266 + 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, + 0x77, // 267 + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, // 268 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 269 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, // 270 + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, + 0x00, // 271 + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, // 272 + 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, + 0x00, // 273 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, // 274 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, // 275 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, + 0xff, // 276 + 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 277 + 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 278 + 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 279 + 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 280 + 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, + 0x00, // 281 + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 282 + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 283 + 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, + 0x00, // 284 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, // 285 + 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, + 0x00, // 286 + 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, + 0x00, // 287 +]; diff --git a/libk/src/io/framebuffer.rs b/libk/src/io/framebuffer.rs new file mode 100644 index 0000000..29cf8e6 --- /dev/null +++ b/libk/src/io/framebuffer.rs @@ -0,0 +1,83 @@ +use limine::request::FramebufferRequest; + +#[used] +#[link_section = ".requests"] +static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(); + +mod colour; + +pub use colour::Color; +use core::panic; + +use limine::framebuffer::Framebuffer; +use spin::{Lazy, Mutex}; + +// use crate::{colour::Color, FRAMEBUFFER_REQUEST}; + +pub static FRAMEBUFFER_WRITER: Lazy>> = Lazy::new(|| { + Mutex::new( + if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() { + let framebuffer = framebuffer_response.framebuffers().next().unwrap(); + Some(FramebufferWriter::new(framebuffer)) + } else { + panic!("Framebuffer request failed"); + }, + ) +}); + +pub struct FramebufferWriter<'a> { + framebuffer: Framebuffer<'a>, +} + +unsafe impl<'a> Send for FramebufferWriter<'a> {} +unsafe impl<'a> Sync for FramebufferWriter<'a> {} +impl<'a> FramebufferWriter<'a> { + pub fn new(framebuffer: Framebuffer<'a>) -> Self { + Self { framebuffer } + } + + pub fn write_pixel(&self, x: usize, y: usize, color: Color) { + let pitch = self.framebuffer.pitch() as usize; + let bpp = (self.framebuffer.bpp() / 8) as usize; + let pixel_offset = y * pitch + x * bpp; + + unsafe { + *(self.framebuffer.addr().add(pixel_offset) as *mut u32) = color.into(); + } + } + + pub fn render_frame(&self, buffer: &[Color; 1280 * 800]) { + for (y, row) in buffer.chunks(1280).enumerate() { + for (x, pixel) in row.iter().enumerate() { + self.write_pixel(x, y, *pixel); + } + } + } + + pub fn width(&self) -> u32 { + self.framebuffer.width() as u32 + } + + pub fn height(&self) -> u32 { + self.framebuffer.height() as u32 + } + + pub fn clear(&self) { + let width = self.framebuffer.width() as usize; + let height = self.framebuffer.height() as usize; + + for y in 0..height { + for x in 0..width { + self.write_pixel(x, y, Color::Black); + } + } + } +} + +pub fn screensize_px() -> (u32, u32) { + if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { + (writer.width(), writer.height()) + } else { + (0, 0) + } +} diff --git a/libk/src/io/framebuffer/colour.rs b/libk/src/io/framebuffer/colour.rs new file mode 100644 index 0000000..bc80d80 --- /dev/null +++ b/libk/src/io/framebuffer/colour.rs @@ -0,0 +1,53 @@ +#[repr(u32)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Color { + ARGB(u8, u8, u8, u8), + RGB(u8, u8, u8), + HexARGB(u32), + Black = 0x000000FF, + Blue = 0x0000FFFF, + Green = 0x00FF00FF, + Cyan = 0x00FFFFFF, + Red = 0xFF0000FF, + Magenta = 0xFF00FFFF, + Yellow = 0xFFFF00FF, + White = 0xFFFFFFFF, +} + +impl Into for Color { + fn into(self) -> u32 { + match self { + Color::ARGB(a, r, g, b) => { + (a as u32) << 24 | (r as u32) << 16 | (g as u32) << 8 | (b as u32) + } + Color::RGB(r, g, b) => (0u32) << 24 | (r as u32) << 16 | (g as u32) << 8 | (b as u32), + Color::HexARGB(hex) => hex, + Color::Black => 0xFF000000, + Color::Blue => 0xFF0000FF, + Color::Green => 0xFF00FF00, + Color::Cyan => 0xFF00FFFF, + Color::Red => 0xFFFF0000, + Color::Magenta => 0xFFFF00FF, + Color::Yellow => 0xFFFFFF00, + Color::White => 0xFFFFFFFF, + } + } +} + +impl core::fmt::Display for Color { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Color::ARGB(r, g, b, a) => write!(f, "RGBA(#{:x}{:x}{:x}{:x})", r, g, b, a), + Color::RGB(r, g, b) => write!(f, "RGB(#{:x}{:x}{:x})", r, g, b), + Color::HexARGB(hex) => write!(f, "Hex(#{:x})", hex), + Color::Black => write!(f, "Black"), + Color::Blue => write!(f, "Blue"), + Color::Green => write!(f, "Green"), + Color::Cyan => write!(f, "Cyan"), + Color::Red => write!(f, "Red"), + Color::Magenta => write!(f, "Magenta"), + Color::Yellow => write!(f, "Yellow"), + Color::White => write!(f, "White"), + } + } +} diff --git a/libk/src/io/keyboard.rs b/libk/src/io/keyboard.rs new file mode 100644 index 0000000..3d2ad1a --- /dev/null +++ b/libk/src/io/keyboard.rs @@ -0,0 +1,90 @@ +extern crate alloc; + +use core::{ + pin::Pin, + task::{Context, Poll}, +}; + +use super::{print, println}; +use crossbeam::queue::ArrayQueue; +use futures_util::{task::AtomicWaker, Stream}; +use spin::Once; + +static KBD_QUEUE: Once> = Once::new(); +static WAKER: AtomicWaker = AtomicWaker::new(); + +pub fn add_scancode(scancode: u8) { + if let Some(queue) = KBD_QUEUE.get() { + if let Err(_) = queue.push(scancode) { + println!("WARNING: scancode queue full; dropping keyboard input"); + } else { + println!("waking waker"); + WAKER.wake(); + } + } else { + println!("WARNING: scancode queue not initialised"); + } +} + +pub struct ScanCodeStream { + _private: (), +} + +impl ScanCodeStream { + pub fn new() -> Self { + KBD_QUEUE.call_once(|| ArrayQueue::new(5)); + ScanCodeStream { _private: () } + } +} + +impl Stream for ScanCodeStream { + type Item = u8; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let queue = KBD_QUEUE.get().expect("scancode queue not initialized"); + print!("polling or smth"); + + // fast path + if let Some(scancode) = queue.pop() { + return Poll::Ready(Some(scancode)); + } + + WAKER.register(&cx.waker()); + match queue.pop() { + Some(scancode) => { + print!("scancode found"); + WAKER.take(); + Poll::Ready(Some(scancode)) + } + None => { + print!("returning"); + Poll::Pending + } + } + } +} + +use futures_util::stream::StreamExt; +use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; + +pub async fn print_keypresses() { + let mut scancodes = ScanCodeStream::new(); + let mut keyboard = Keyboard::new( + ScancodeSet1::new(), + layouts::Us104Key, + HandleControl::Ignore, + ); + + println!("OK!!!"); + + 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/libk/src/io/port.rs b/libk/src/io/port.rs new file mode 100644 index 0000000..860058d --- /dev/null +++ b/libk/src/io/port.rs @@ -0,0 +1,25 @@ +//! Functions for IO using ports. + +use core::arch::asm; + +#[inline] +pub unsafe fn inb(port: u16) -> u8 { + let value: u8; + asm!( + "in al, dx", + out("al") value, + in("dx") port, + options(nomem, nostack, preserves_flags) + ); + value +} + +#[inline] +pub unsafe fn outb(port: u16, value: u8) { + asm!( + "out dx, al", + in("dx") port, + in("al") value, + options(nomem, nostack, preserves_flags) + ); +} diff --git a/libk/src/io/serial.rs b/libk/src/io/serial.rs new file mode 100644 index 0000000..2d5d674 --- /dev/null +++ b/libk/src/io/serial.rs @@ -0,0 +1,159 @@ +use core::{ + fmt, + sync::atomic::{AtomicUsize, Ordering}, +}; +use spin::{Lazy, Mutex}; + +#[macro_export] +macro_rules! serial_println { + () => ($crate::serial_print!("\n")); + ($($arg:tt)*) => ($crate::io::serial_print!("{}\n", format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! serial_print { + ($($arg:tt)*) => ($crate::io::serial::_serial_write(format_args!($($arg)*))); +} + +use super::port::{inb, outb}; + +use x86_64::instructions::interrupts; + +pub fn _serial_write(args: fmt::Arguments) { + use core::fmt::Write; + + interrupts::without_interrupts(|| { + if let Some(writer) = WRITER.lock().as_mut() { + writer.write_fmt(args).unwrap(); + } + }) +} + +pub fn serial_read() -> &'static str { + serial_println!("getting value!"); + + interrupts::without_interrupts(|| { + if let Some(reader) = READER.lock().as_mut() { + serial_println!("stuff happnin."); + reader.read_str_to_buffer(); + } else { + serial_println!("failed to get writer"); + } + }); + + serial_println!("eee"); + + let i = BUFFER_LEN.load(Ordering::SeqCst); + + return unsafe { + if i != 0 { + core::str::from_utf8(&BUFFER[..i - 1]).unwrap() + } else { + serial_println!("empty string"); + "" + } + }; +} + +static PORT: u16 = 0x3f8; +static mut BUFFER: [u8; 256] = [0; 256]; +static BUFFER_LEN: AtomicUsize = AtomicUsize::new(0); + +static READER: Lazy>> = Lazy::new(|| Mutex::new(None)); +static WRITER: Lazy>> = Lazy::new(|| Mutex::new(None)); + +struct Reader; + +struct Writer; + +impl fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.chars() { + self.write_byte(c as u8); + } + Ok(()) + } +} + +impl Writer { + unsafe fn write_success(&self) -> bool { + inb(PORT + 5) & 0x20 != 0 + } + + pub fn write_byte(&self, data: u8) { + unsafe { + while !self.write_success() {} + outb(PORT + 0, data); + } + } +} + +pub fn init() -> Result<(), &'static str> { + if let Err(e) = test() { + return Err(e); + } + + if READER.lock().is_none() { + *READER.lock() = Some(Reader); + } + + if WRITER.lock().is_none() { + *WRITER.lock() = Some(Writer); + } + + Ok(()) +} + +pub fn test() -> Result<(), &'static str> { + unsafe { + outb(PORT + 1, 0x00); // Disable all interrupts + outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) + outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + outb(PORT + 1, 0x00); // (hi byte) + outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit + outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-bytethreshold + outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set + outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip + outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) + + if inb(PORT + 0) != 0xAE { + return Err("serial test failed"); + } + + outb(PORT + 4, 0x0F); + } + + Ok(()) +} + +impl Reader { + pub fn read_str_to_buffer(&mut self) { + unsafe { + while !self.read_ready() {} + + BUFFER_LEN.store(0, Ordering::SeqCst); + + while BUFFER_LEN.load(Ordering::SeqCst) < 256 { + let c = self.read(); + BUFFER[BUFFER_LEN.load(Ordering::SeqCst)] = c; + if c as char == '\r' { + break; + } + BUFFER_LEN.fetch_add(1, Ordering::SeqCst); + } + + serial_println!("returning") + } + } + + unsafe fn read_ready(&self) -> bool { + inb(PORT + 5) & 1 != 0 + } + + pub fn read(&self) -> u8 { + unsafe { + while !self.read_ready() {} + return inb(PORT + 0); + } + } +} diff --git a/libk/src/lib.rs b/libk/src/lib.rs new file mode 100644 index 0000000..dfcc3ba --- /dev/null +++ b/libk/src/lib.rs @@ -0,0 +1,15 @@ +#![no_std] + +// alloc +// io : serial, framebuffer, ascii(?), keyboard +// ????? +// scheduling / tasks : async + +pub mod alloc; +pub mod io; +pub mod scheduling; + +/// Re-exports most of the IO macros. +pub mod prelude { + pub use crate::{print_log, println, println_log, serial_print, serial_println}; +} diff --git a/libk/src/scheduling.rs b/libk/src/scheduling.rs new file mode 100644 index 0000000..cdafe4a --- /dev/null +++ b/libk/src/scheduling.rs @@ -0,0 +1 @@ +pub mod task; diff --git a/libk/src/scheduling/task.rs b/libk/src/scheduling/task.rs new file mode 100644 index 0000000..844b873 --- /dev/null +++ b/libk/src/scheduling/task.rs @@ -0,0 +1,133 @@ +extern crate alloc; +use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake}; +use core::{ + future::Future, + pin::Pin, + sync::atomic::{AtomicU64, Ordering}, + task::{Context, Poll, Waker}, +}; +use crossbeam::queue::ArrayQueue; + +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), + } + } + + fn poll(&mut self, context: &mut Context) -> Poll<()> { + self.future.as_mut().poll(context) + } +} + +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!("a task with this id has already been allocated"); + } + self.task_queue.push(task_id).expect("task queue is full"); + } + + fn run_ready_tasks(&mut self) { + 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, + }; + 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(()) => { + tasks.remove(&task_id); + waker_cache.remove(&task_id); + } + Poll::Pending => {} + } + } + } + + pub fn try_run(&mut self) { + 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(); + } + } +} + +struct TaskWaker { + task_id: TaskId, + task_queue: Arc>, +} + +impl TaskWaker { + fn new(task_id: TaskId, task_queue: Arc>) -> Waker { + Waker::from(Arc::new(TaskWaker { + task_id, + task_queue, + })) + } + + fn wake_task(&self) { + self.task_queue + .push(self.task_id) + .expect("task queue is full!"); + } +} + +impl Wake for TaskWaker { + fn wake(self: Arc) { + self.wake_task(); + } + + fn wake_by_ref(self: &Arc) { + self.wake_task(); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +struct TaskId(u64); + +impl TaskId { + fn new() -> Self { + static NEXT: AtomicU64 = AtomicU64::new(0); + TaskId(NEXT.fetch_add(1, Ordering::Relaxed)) + } +} From 914cb4e4092fe1031ced1b03346fd49b5b16f9df Mon Sep 17 00:00:00 2001 From: Jacob Hinchliffe Date: Sun, 23 Feb 2025 11:43:26 +0000 Subject: [PATCH 4/8] Enable support for $USE_GDB when running in debug mode. --- .cargo/config.toml | 17 +-- scripts/{run.sh => run_debug.sh} | 8 +- scripts/run_release.sh | 186 +++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+), 10 deletions(-) rename scripts/{run.sh => run_debug.sh} (96%) create mode 100755 scripts/run_release.sh diff --git a/.cargo/config.toml b/.cargo/config.toml index 400f704..0f4b13b 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -9,15 +9,16 @@ build-std-features = ["compiler-builtins-mem"] [env] RUST_TARGET_PATH = { value = "kernel", relative = true } -[target.x86_64-kernel] -runner = "scripts/run.sh" +# Run in debug mode. +[target.'cfg(all(target_arch = "x86_64", target_os = "none", debug_assertions))'] +runner = "scripts/run_debug.sh" -[registry] -default = "gitea" +# Otherwise we run in release mode. +[target.'cfg(all(target_arch = "x86_64", target_os = "none", not(debug_assertions)))'] +runner = "scripts/run_release.sh" + +# [registry] +# default = "gitea" [registries.gitea] index = "sparse+https://git.zxq5.dev/api/packages/OsDev/cargo/" # Sparse index -# index = "https://gitea.example.com/{owner}/_cargo-index.git" # Git - -# [net] -# git-fetch-with-cli = true diff --git a/scripts/run.sh b/scripts/run_debug.sh similarity index 96% rename from scripts/run.sh rename to scripts/run_debug.sh index 79359bf..138298c 100755 --- a/scripts/run.sh +++ b/scripts/run_debug.sh @@ -1,5 +1,7 @@ #!/bin/bash +# Script originally written by zxq5, I added separate scripts to remove `jq` dependency. + # Colors GREEN='\033[0;32m' BLUE='\033[0;34m' @@ -16,6 +18,8 @@ trap 'echo -e "${RED}${BOLD}error${NC}: build failed" >&2' ERR script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) project_root=$(cd "$script_dir/.." &>/dev/null && pwd) +echo -e "${GREEN}${BOLD} Running kernel in debug mode." + # Logging functions info() { echo -e "${BLUE}${BOLD}info${NC}: $1" @@ -124,8 +128,8 @@ else kvm_flag="" fi -# Check if we're running in debug mode -if [[ "$(cargo metadata --format-version=1 | jq -r '.workspace_members[0]' | cut -d' ' -f2)" == "(debug)" ]]; then +# Enable using GDB with $USE_GDB. +if [ $USE_GDB ]; then debug_flags="-s -S" else debug_flags="" diff --git a/scripts/run_release.sh b/scripts/run_release.sh new file mode 100755 index 0000000..97f6134 --- /dev/null +++ b/scripts/run_release.sh @@ -0,0 +1,186 @@ +#!/bin/bash + +# Script originally written by zxq5, I added separate scripts to remove `jq` dependency. + +# Colors +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[0;33m' +RED='\033[0;31m' +BOLD='\033[1m' +NC='\033[0m' # No Color + +# Error handling +set -e +trap 'echo -e "${RED}${BOLD}error${NC}: build failed" >&2' ERR + +# Get absolute path to project root +script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) +project_root=$(cd "$script_dir/.." &>/dev/null && pwd) + +echo -e "${GREEN}${BOLD} Running kernel in release mode." + +# Logging functions +info() { + echo -e "${BLUE}${BOLD}info${NC}: $1" +} + +compiling() { + echo -e "${GREEN}${BOLD}Compiling${NC}: $1" +} + +warning() { + echo -e "${YELLOW}${BOLD}warning${NC}: $1" >&2 +} + +building() { + echo -e "${GREEN}${BOLD}Building${NC}: $1" +} + +copying() { + echo -e "${GREEN}${BOLD} Copying${NC}: $1 to $2" +} + +error() { + echo -e "${RED}${BOLD}error${NC}: $1" >&2 + exit 1 +} + +copy_file() { + copying $1 $2 + cp "$1" "$2" || error $3 +} + +build_dir="$project_root/build" +iso_root="$build_dir/iso_root" + +# Check if we're running tests +is_test=0 +if [[ $1 == *"deps"* ]]; then + is_test=1 + kernel_path="$1" +else + # Build the kernel normally + cd "$project_root" + # cargo build + kernel_path="$build_dir/target/x86_64-kernel/release/kernel" +fi + +# Check for required tools +check_tools() { + local missing=0 + for tool in xorriso git qemu-system-x86_64; do + if ! command -v $tool >/dev/null 2>&1; then + error "required tool '$tool' is not installed" + missing=1 + fi + done + if [ $missing -eq 1 ]; then + error "missing required tools" + fi +} + +# Create build directory structure +info "Creating build directory structure" +mkdir -p "$iso_root/boot/limine" +mkdir -p "$iso_root/EFI/BOOT" + +# Clone Limine if needed +if [ ! -d "$build_dir/limine" ]; then + compiling "limine bootloader" + cd "$build_dir" + git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1 "$build_dir/limine" || error "failed to clone limine" + make -C "$build_dir/limine" || error "failed to build limine" + cd "$project_root" +fi + +# Copy files +info "Copying files to ISO root" +copy_file "$kernel_path" "$iso_root/boot/kernel" "failed to copy kernel" +copy_file "$project_root/config/limine.conf" "$iso_root/boot/limine/limine.conf" "failed to copy limine config" +copy_file "$build_dir/limine/limine-bios-cd.bin" "$iso_root/boot/limine/" "failed to copy limine-bios-cd.bin" +copy_file "$build_dir/limine/limine-uefi-cd.bin" "$iso_root/boot/limine/" "failed to copy limine-uefi-cd.bin" +copy_file "$build_dir/limine/limine-bios.sys" "$iso_root/boot/limine/" "failed to copy limine-bios.sys" +copy_file "$build_dir/limine/BOOTX64.EFI" "$iso_root/EFI/BOOT/" "failed to copy BOOTX64.EFI" +copy_file "$build_dir/limine/BOOTIA32.EFI" "$iso_root/EFI/BOOT/" "failed to copy BOOTIA32.EFI" + +# Create ISO +building "bootable ISO image" +xorriso -as mkisofs -R -r -J -b boot/limine/limine-bios-cd.bin \ + -no-emul-boot -boot-load-size 4 -boot-info-table -hfsplus \ + -apm-block-size 2048 --efi-boot boot/limine/limine-uefi-cd.bin \ + -efi-boot-part --efi-boot-image --protective-msdos-label \ + "$iso_root" -o "$build_dir/image.iso" || error "failed to create ISO" + +# Install Limine +info "Installing Limine bootloader" +"$build_dir/limine/limine" bios-install "$build_dir/image.iso" || error "failed to install limine" + +# Check if KVM is available +if [ "${KVM_FLAG:-enable}" = "disable" ]; then + warning "KVM acceleration disabled by user" + kvm_flag="" +elif [ -c "/dev/kvm" ] && [ -w "/dev/kvm" ]; then + info "KVM acceleration enabled" + kvm_flag="-enable-kvm" +else + warning "KVM acceleration not available (is kvm module loaded?)" + kvm_flag="" +fi + +# I'm lazy but I just remove GDB flags when running this script. +debug_flags="" + +# Set up test-specific flags +if [ $is_test -eq 1 ]; then + test_flags="-device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none" + serial_flags="-serial stdio" +else + test_flags="" + # serial_flags="-serial tcp:127.0.0.1:1234,server -monitor telnet:127.0.0.1:1235,server" + serial_flags="-serial stdio" +fi + +# Run in QEMU +if [[ ${QEMU_FLAGS} == *-S* ]]; then + info "Running OS in QEMU with GDB debugging enabled" + info "To connect GDB, run: gdb" + info "At the GDB prompt, type: target remote localhost:1234" +else + info "Running OS in QEMU..." +fi + +check_test_res() { + qemu_exit_code=$? + if [ $qemu_exit_code -eq 33 ]; then + # Success case (0x10 << 1) | 1 = 33 + info "All tests passed" + exit 0 + elif [ $qemu_exit_code -eq 35 ]; then + # Failure case (0x11 << 1) | 1 = 35 + warning "Some tests failed" + exit 1 + else + # Any other exit code is treated as a failure + warning "Some tests failed" + exit 1 + fi +} + + +kvm_flag="" + +trap 'check_test_res "tests completed"' ERR + +cd "$project_root" +qemu-system-x86_64 -M q35 \ + ${kvm_flag} \ + -cdrom "$build_dir/image.iso" \ + -boot d \ + -m 2G \ + ${serial_flags} \ + -no-reboot \ + ${test_flags} \ + ${debug_flags} \ + ${QEMU_FLAGS:-} + From b8aa203c05a1501d29725561b26e4921fb561c4a Mon Sep 17 00:00:00 2001 From: Jacob Hinchliffe Date: Sun, 23 Feb 2025 11:52:54 +0000 Subject: [PATCH 5/8] Bump edition to now stable 2024 edition (shiny!). --- Cargo.toml | 7 ++- kernel/Cargo.toml | 6 +- kernel/src/arch/x86_64/memmap.rs | 6 +- kernel/src/arch/x86_64/memory.rs | 14 +++-- kernel/src/lib.rs | 2 +- kernel/src/main.rs | 2 +- libk/src/io/ascii.rs | 64 +++++++++++---------- libk/src/io/framebuffer.rs | 92 ++++++++++++++++++------------- libk/src/io/framebuffer/colour.rs | 54 +++++++++--------- libk/src/io/keyboard.rs | 41 ++++++++------ libk/src/io/port.rs | 32 ++++++----- libk/src/io/serial.rs | 40 ++++++-------- libk/src/lib.rs | 5 +- libk/src/scheduling/task.rs | 20 ++++--- 14 files changed, 214 insertions(+), 171 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b3cb7bd..3abf5a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,12 +4,15 @@ resolver = "2" [workspace.package] version = "0.1.0" -edition = "2021" -authors = ["The Foundry OS contributors"] +edition = "2024" +authors = ["The FoundryOS Contributors"] [profile.dev] opt-level = "z" debug = true +# Leave this on to force Cargo to use the debug runner, +# which adds the necessary flags for GDB debugging if you +# set $USE_GDB (to any value) e.g. USE_GDB=1 cargo run debug-assertions = true overflow-checks = true lto = false diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 48f4be3..f8b95ce 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -1,7 +1,8 @@ [package] name = "foundry_os" -version = "0.1.0" -edition = "2021" +edition.workspace = true +version.workspace = true +authors.workspace = true [dependencies] limine = "0.3.1" @@ -20,3 +21,4 @@ default = [] [[bin]] name = "kernel" path = "src/main.rs" +test = false diff --git a/kernel/src/arch/x86_64/memmap.rs b/kernel/src/arch/x86_64/memmap.rs index a130616..cb0d8b7 100644 --- a/kernel/src/arch/x86_64/memmap.rs +++ b/kernel/src/arch/x86_64/memmap.rs @@ -7,11 +7,11 @@ use limine::{ use spin::Lazy; #[used] -#[link_section = ".requests"] +#[unsafe(link_section = ".requests")] static MEMORY_MAP_REQUEST: MemoryMapRequest = MemoryMapRequest::new(); #[used] -#[link_section = ".requests"] +#[unsafe(link_section = ".requests")] static HIGHER_HALF_DIRECT_MAP_REQUEST: HhdmRequest = HhdmRequest::new(); /// ```rs @@ -26,7 +26,7 @@ pub static PHYSICAL_MEMORY_OFFSET: Lazy = Lazy::new(|| { }); #[used] -#[link_section = ".requests"] +#[unsafe(link_section = ".requests")] static KERNEL_ADDRESS_REQUEST: KernelAddressRequest = KernelAddressRequest::new(); /// Converts virtual addresses in the kernel to a physical address like this: diff --git a/kernel/src/arch/x86_64/memory.rs b/kernel/src/arch/x86_64/memory.rs index cf29bb3..64f1245 100644 --- a/kernel/src/arch/x86_64/memory.rs +++ b/kernel/src/arch/x86_64/memory.rs @@ -1,6 +1,8 @@ // use lib_alloc::allocator::FoundryAllocator; use limine::{memory_map::EntryType, response::MemoryMapResponse}; use x86_64::{ + PhysAddr, + VirtAddr, // addr, registers::control::Cr3, structures::paging::{ @@ -11,8 +13,6 @@ use x86_64::{ PhysFrame, Size4KiB, }, - PhysAddr, - VirtAddr, }; /// Returns a mutable reference to the current level 4 page table. @@ -27,7 +27,7 @@ unsafe fn active_l4_table(physical_memory_offset: VirtAddr) -> &'static mut Page let phys_addr = level_4_frame.start_address(); let virt = phys_addr.as_u64() + physical_memory_offset.as_u64(); - &mut *(virt as *mut PageTable) + unsafe { &mut *(virt as *mut PageTable) } } /// Initializes the `OffsetPageTable` for the current CPU architecture. @@ -49,8 +49,10 @@ unsafe fn active_l4_table(physical_memory_offset: VirtAddr) -> &'static mut Page /// Returns an `OffsetPageTable` that allows for manipulation of the page /// tables for the current CPU architecture. pub unsafe fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> { - let l4_table = active_l4_table(physical_memory_offset); - OffsetPageTable::new(l4_table, physical_memory_offset) + unsafe { + let l4_table = active_l4_table(physical_memory_offset); + OffsetPageTable::new(l4_table, physical_memory_offset) + } } pub(crate) struct FoundryOSFrameAllocator { @@ -76,7 +78,7 @@ impl FoundryOSFrameAllocator { /// Yields one `PhysFrame` for each available 4KiB frame in the memory map. /// /// This function is used to allocate frames for the pagemap. - fn usable_frames(&self) -> impl Iterator { + fn usable_frames(&self) -> impl Iterator + use<> { let regions = self.memory_map.entries().iter(); let usable_regions = regions.filter(|region| region.entry_type == EntryType::USABLE); diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 4d1a129..6ece312 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -18,7 +18,7 @@ mod arch; /// Be sure to mark all limine requests with #[used], otherwise they may be removed by the compiler. #[used] // The .requests section allows limine to find the requests faster and more safely. -#[link_section = ".requests"] +#[unsafe(link_section = ".requests")] static BASE_REVISION: BaseRevision = BaseRevision::new(); #[panic_handler] diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 8b5b3b8..b3e3a86 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -9,7 +9,7 @@ use libk::{ scheduling::task::{Executor, Task}, }; -#[no_mangle] +#[unsafe(no_mangle)] extern "C" fn kmain() -> ! { println_log!(" [ Initialising Kernel Systems ] "); if let Err(err) = foundry_os::boot() { diff --git a/libk/src/io/ascii.rs b/libk/src/io/ascii.rs index a75520b..d85eff6 100644 --- a/libk/src/io/ascii.rs +++ b/libk/src/io/ascii.rs @@ -3,7 +3,7 @@ use spin::{Lazy, Mutex}; use x86_64::instructions::interrupts; pub use super::framebuffer::screensize_px; -use super::framebuffer::{Color, FRAMEBUFFER_WRITER}; +use super::framebuffer::{Colour, FRAMEBUFFER_WRITER}; mod font; use font::FONT; @@ -28,32 +28,39 @@ pub struct Writer { /// 8 pixels wide. text_col: u32, - fg_color: Color, - bg_color: Color, + fg_color: Colour, + bg_color: Colour, offset1: usize, offset2: usize, } +impl Default for Writer { + fn default() -> Self { + Self::new() + } +} + impl Writer { pub fn new() -> Self { - if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { - Self { - screen_width: writer.width() as u32 / 8, - screen_height: writer.height() as u32 / 16, + FRAMEBUFFER_WRITER.lock().as_mut().map_or_else( + || { + panic!("Framebuffer writer not initialized."); + }, + |writer| Self { + screen_width: writer.width() / 8, + screen_height: writer.height() / 16, text_line: 0, text_col: 0, - fg_color: Color::White, - bg_color: Color::Black, + fg_color: Colour::White, + bg_color: Colour::Black, offset1: 16, offset2: 0, - } - } else { - panic!("Framebuffer writer not initialized"); - } + }, + ) } - pub fn write_char(&mut self, c: u16) { + pub fn write_glyph(&mut self, c: u16) { if c as u8 == b'\n' { self.newline(); return; @@ -63,8 +70,7 @@ impl Writer { let data: &[u8] = &FONT[c as usize * 16..(c as usize + 1) * 16]; if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { - for row in 0..16 { - let line: u8 = data[row]; + for (row, line) in data.iter().enumerate().take(16) { for col in 0..8 { let pixel_x: u32 = self.text_col * FONT_WIDTH + col; let pixel_y: u32 = self.text_line * FONT_HEIGHT + row as u32; @@ -88,20 +94,20 @@ impl Writer { } } - pub fn set_offset(&mut self, offset1: usize, offset2: usize) { + pub const fn set_offset(&mut self, offset1: usize, offset2: usize) { self.offset1 = offset1; self.offset2 = offset2; } - pub fn dimensions(&self) -> (u32, u32) { + pub const fn dimensions(&self) -> (u32, u32) { (self.screen_width, self.screen_height) } - pub fn next_char(&mut self) { + pub const fn next_char(&mut self) { self.text_col += 1; } - pub fn newline(&mut self) { + pub const fn newline(&mut self) { self.text_col = 0; if self.text_line + 1 >= self.screen_height { @@ -113,18 +119,18 @@ impl Writer { pub fn write_string(&mut self, s: &str) { for c in s.chars() { - self.write_char(c as u16); + self.write_glyph(c as u16); } } - pub fn set_colour(&mut self, fg: Color, bg: Color) { + pub const fn set_colour(&mut self, fg: Colour, bg: Colour) { self.fg_color = fg; self.bg_color = bg; } - pub fn reset_colour(&mut self) { - self.fg_color = Color::White; - self.bg_color = Color::Black; + pub const fn reset_colour(&mut self) { + self.fg_color = Colour::White; + self.bg_color = Colour::Black; } } @@ -135,7 +141,7 @@ impl core::fmt::Write for Writer { } } -fn write(args: fmt::Arguments, fg: Color, bg: Color) { +fn write(args: fmt::Arguments, fg: Colour, bg: Colour) { use core::fmt::Write; interrupts::without_interrupts(|| { @@ -148,19 +154,19 @@ fn write(args: fmt::Arguments, fg: Color, bg: Color) { pub fn _print(args: fmt::Arguments) { x86_64::instructions::interrupts::without_interrupts(|| { - write(args, Color::White, Color::Black); + write(args, Colour::White, Colour::Black); }) } pub fn _print_err(args: fmt::Arguments) { x86_64::instructions::interrupts::without_interrupts(|| { - write(args, Color::Red, Color::Black); + write(args, Colour::Red, Colour::Black); }) } pub fn _print_log(args: fmt::Arguments) { x86_64::instructions::interrupts::without_interrupts(|| { - write(args, Color::Yellow, Color::Black); + write(args, Colour::Yellow, Colour::Black); }) } diff --git a/libk/src/io/framebuffer.rs b/libk/src/io/framebuffer.rs index 29cf8e6..a9dd243 100644 --- a/libk/src/io/framebuffer.rs +++ b/libk/src/io/framebuffer.rs @@ -1,52 +1,69 @@ use limine::request::FramebufferRequest; #[used] -#[link_section = ".requests"] +#[unsafe(link_section = ".requests")] static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(); mod colour; -pub use colour::Color; +pub use colour::Colour; use core::panic; use limine::framebuffer::Framebuffer; use spin::{Lazy, Mutex}; -// use crate::{colour::Color, FRAMEBUFFER_REQUEST}; - pub static FRAMEBUFFER_WRITER: Lazy>> = Lazy::new(|| { - Mutex::new( - if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() { - let framebuffer = framebuffer_response.framebuffers().next().unwrap(); - Some(FramebufferWriter::new(framebuffer)) - } else { + Mutex::new(FRAMEBUFFER_REQUEST.get_response().map_or_else( + || { panic!("Framebuffer request failed"); }, - ) + |framebuffer_response| { + let framebuffer = framebuffer_response.framebuffers().next().unwrap(); + Some(FramebufferWriter::new(framebuffer)) + }, + )) }); -pub struct FramebufferWriter<'a> { - framebuffer: Framebuffer<'a>, +/// The updated writer stores necessary fields from the [Framebuffer]. +/// This ensures that the contained types are Send, as Framebuffer was +/// not marked as Send. +/// +/// It also avoids the requirement for lifetimes. +/// +/// Note this does not implement Writer as these functions only handle drawing pixels. +pub struct FramebufferWriter { + pitch: u64, + bpp: u16, + addr: *mut u8, + width: u64, + height: u64, } -unsafe impl<'a> Send for FramebufferWriter<'a> {} -unsafe impl<'a> Sync for FramebufferWriter<'a> {} -impl<'a> FramebufferWriter<'a> { - pub fn new(framebuffer: Framebuffer<'a>) -> Self { - Self { framebuffer } - } +unsafe impl Send for FramebufferWriter {} +unsafe impl Sync for FramebufferWriter {} - pub fn write_pixel(&self, x: usize, y: usize, color: Color) { - let pitch = self.framebuffer.pitch() as usize; - let bpp = (self.framebuffer.bpp() / 8) as usize; - let pixel_offset = y * pitch + x * bpp; - - unsafe { - *(self.framebuffer.addr().add(pixel_offset) as *mut u32) = color.into(); +impl FramebufferWriter { + pub fn new(framebuffer: Framebuffer) -> Self { + Self { + pitch: framebuffer.pitch(), + bpp: framebuffer.bpp(), + addr: framebuffer.addr(), + width: framebuffer.width(), + height: framebuffer.height(), } } - pub fn render_frame(&self, buffer: &[Color; 1280 * 800]) { + pub fn write_pixel(&self, x: usize, y: usize, color: Colour) { + let pitch = self.pitch as usize; + let bpp = (self.bpp / 8) as usize; + let pixel_offset = y * pitch + x * bpp; + + unsafe { + *(self.addr.add(pixel_offset) as *mut u32) = color.into(); + } + } + + pub fn render_frame(&self, buffer: &[Colour; 1280 * 800]) { for (y, row) in buffer.chunks(1280).enumerate() { for (x, pixel) in row.iter().enumerate() { self.write_pixel(x, y, *pixel); @@ -54,30 +71,29 @@ impl<'a> FramebufferWriter<'a> { } } - pub fn width(&self) -> u32 { - self.framebuffer.width() as u32 + pub const fn width(&self) -> u32 { + self.width as u32 } - pub fn height(&self) -> u32 { - self.framebuffer.height() as u32 + pub const fn height(&self) -> u32 { + self.height as u32 } pub fn clear(&self) { - let width = self.framebuffer.width() as usize; - let height = self.framebuffer.height() as usize; + let width = self.width as usize; + let height = self.height as usize; for y in 0..height { for x in 0..width { - self.write_pixel(x, y, Color::Black); + self.write_pixel(x, y, Colour::Black); } } } } pub fn screensize_px() -> (u32, u32) { - if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { - (writer.width(), writer.height()) - } else { - (0, 0) - } + FRAMEBUFFER_WRITER + .lock() + .as_mut() + .map_or_else(|| (0, 0), |writer| (writer.width(), writer.height())) } diff --git a/libk/src/io/framebuffer/colour.rs b/libk/src/io/framebuffer/colour.rs index bc80d80..9e41b55 100644 --- a/libk/src/io/framebuffer/colour.rs +++ b/libk/src/io/framebuffer/colour.rs @@ -1,6 +1,6 @@ #[repr(u32)] #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum Color { +pub enum Colour { ARGB(u8, u8, u8, u8), RGB(u8, u8, u8), HexARGB(u32), @@ -14,40 +14,40 @@ pub enum Color { White = 0xFFFFFFFF, } -impl Into for Color { - fn into(self) -> u32 { - match self { - Color::ARGB(a, r, g, b) => { +impl From for u32 { + fn from(val: Colour) -> Self { + match val { + Colour::ARGB(a, r, g, b) => { (a as u32) << 24 | (r as u32) << 16 | (g as u32) << 8 | (b as u32) } - Color::RGB(r, g, b) => (0u32) << 24 | (r as u32) << 16 | (g as u32) << 8 | (b as u32), - Color::HexARGB(hex) => hex, - Color::Black => 0xFF000000, - Color::Blue => 0xFF0000FF, - Color::Green => 0xFF00FF00, - Color::Cyan => 0xFF00FFFF, - Color::Red => 0xFFFF0000, - Color::Magenta => 0xFFFF00FF, - Color::Yellow => 0xFFFFFF00, - Color::White => 0xFFFFFFFF, + Colour::RGB(r, g, b) => ((r as u32) << 16) | (g as u32) << 8 | (b as u32), + Colour::HexARGB(hex) => hex, + Colour::Black => 0xFF000000, + Colour::Blue => 0xFF0000FF, + Colour::Green => 0xFF00FF00, + Colour::Cyan => 0xFF00FFFF, + Colour::Red => 0xFFFF0000, + Colour::Magenta => 0xFFFF00FF, + Colour::Yellow => 0xFFFFFF00, + Colour::White => 0xFFFFFFFF, } } } -impl core::fmt::Display for Color { +impl core::fmt::Display for Colour { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - Color::ARGB(r, g, b, a) => write!(f, "RGBA(#{:x}{:x}{:x}{:x})", r, g, b, a), - Color::RGB(r, g, b) => write!(f, "RGB(#{:x}{:x}{:x})", r, g, b), - Color::HexARGB(hex) => write!(f, "Hex(#{:x})", hex), - Color::Black => write!(f, "Black"), - Color::Blue => write!(f, "Blue"), - Color::Green => write!(f, "Green"), - Color::Cyan => write!(f, "Cyan"), - Color::Red => write!(f, "Red"), - Color::Magenta => write!(f, "Magenta"), - Color::Yellow => write!(f, "Yellow"), - Color::White => write!(f, "White"), + Colour::ARGB(r, g, b, a) => write!(f, "RGBA(#{:x}{:x}{:x}{:x})", r, g, b, a), + Colour::RGB(r, g, b) => write!(f, "RGB(#{:x}{:x}{:x})", r, g, b), + Colour::HexARGB(hex) => write!(f, "Hex(#{:x})", hex), + Colour::Black => write!(f, "Black"), + Colour::Blue => write!(f, "Blue"), + Colour::Green => write!(f, "Green"), + Colour::Cyan => write!(f, "Cyan"), + Colour::Red => write!(f, "Red"), + Colour::Magenta => write!(f, "Magenta"), + Colour::Yellow => write!(f, "Yellow"), + Colour::White => write!(f, "White"), } } } diff --git a/libk/src/io/keyboard.rs b/libk/src/io/keyboard.rs index 3d2ad1a..13603a8 100644 --- a/libk/src/io/keyboard.rs +++ b/libk/src/io/keyboard.rs @@ -5,9 +5,9 @@ use core::{ task::{Context, Poll}, }; -use super::{print, println}; +use crate::prelude::*; use crossbeam::queue::ArrayQueue; -use futures_util::{task::AtomicWaker, Stream}; +use futures_util::{Stream, task::AtomicWaker}; use spin::Once; static KBD_QUEUE: Once> = Once::new(); @@ -15,7 +15,7 @@ static WAKER: AtomicWaker = AtomicWaker::new(); pub fn add_scancode(scancode: u8) { if let Some(queue) = KBD_QUEUE.get() { - if let Err(_) = queue.push(scancode) { + if queue.push(scancode).is_err() { println!("WARNING: scancode queue full; dropping keyboard input"); } else { println!("waking waker"); @@ -33,7 +33,14 @@ pub struct ScanCodeStream { impl ScanCodeStream { pub fn new() -> Self { KBD_QUEUE.call_once(|| ArrayQueue::new(5)); - ScanCodeStream { _private: () } + + Self { _private: () } + } +} + +impl Default for ScanCodeStream { + fn default() -> Self { + Self::new() } } @@ -42,30 +49,30 @@ impl Stream for ScanCodeStream { fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let queue = KBD_QUEUE.get().expect("scancode queue not initialized"); - print!("polling or smth"); + serial_println!("This is called once."); + WAKER.register(cx.waker()); // fast path if let Some(scancode) = queue.pop() { return Poll::Ready(Some(scancode)); } - WAKER.register(&cx.waker()); - match queue.pop() { - Some(scancode) => { - print!("scancode found"); + queue.pop().map_or_else( + || { + print!("Returning"); + Poll::Pending + }, + |scancode| { + print!("Scancode found"); WAKER.take(); Poll::Ready(Some(scancode)) - } - None => { - print!("returning"); - Poll::Pending - } - } + }, + ) } } use futures_util::stream::StreamExt; -use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; +use pc_keyboard::{DecodedKey, HandleControl, Keyboard, ScancodeSet1, layouts}; pub async fn print_keypresses() { let mut scancodes = ScanCodeStream::new(); @@ -75,7 +82,7 @@ pub async fn print_keypresses() { HandleControl::Ignore, ); - println!("OK!!!"); + serial_println!("Printing keypresses."); while let Some(scancode) = scancodes.next().await { if let Ok(Some(key_event)) = keyboard.add_byte(scancode) { diff --git a/libk/src/io/port.rs b/libk/src/io/port.rs index 860058d..77eafa0 100644 --- a/libk/src/io/port.rs +++ b/libk/src/io/port.rs @@ -3,23 +3,27 @@ use core::arch::asm; #[inline] -pub unsafe fn inb(port: u16) -> u8 { +pub fn inb(port: u16) -> u8 { let value: u8; - asm!( - "in al, dx", - out("al") value, - in("dx") port, - options(nomem, nostack, preserves_flags) - ); + unsafe { + asm!( + "in al, dx", + out("al") value, + in("dx") port, + options(nomem, nostack, preserves_flags) + ); + } value } #[inline] -pub unsafe fn outb(port: u16, value: u8) { - asm!( - "out dx, al", - in("dx") port, - in("al") value, - options(nomem, nostack, preserves_flags) - ); +pub fn outb(port: u16, value: u8) { + unsafe { + asm!( + "out dx, al", + in("dx") port, + in("al") value, + options(nomem, nostack, preserves_flags) + ); + } } diff --git a/libk/src/io/serial.rs b/libk/src/io/serial.rs index 2d5d674..03db09a 100644 --- a/libk/src/io/serial.rs +++ b/libk/src/io/serial.rs @@ -45,14 +45,14 @@ pub fn serial_read() -> &'static str { let i = BUFFER_LEN.load(Ordering::SeqCst); - return unsafe { + unsafe { if i != 0 { core::str::from_utf8(&BUFFER[..i - 1]).unwrap() } else { serial_println!("empty string"); "" } - }; + } } static PORT: u16 = 0x3f8; @@ -83,15 +83,13 @@ impl Writer { pub fn write_byte(&self, data: u8) { unsafe { while !self.write_success() {} - outb(PORT + 0, data); + outb(PORT, data); } } } pub fn init() -> Result<(), &'static str> { - if let Err(e) = test() { - return Err(e); - } + test()?; if READER.lock().is_none() { *READER.lock() = Some(Reader); @@ -105,24 +103,22 @@ pub fn init() -> Result<(), &'static str> { } pub fn test() -> Result<(), &'static str> { - unsafe { - outb(PORT + 1, 0x00); // Disable all interrupts - outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) - outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud - outb(PORT + 1, 0x00); // (hi byte) - outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit - outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-bytethreshold - outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set - outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip - outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) + outb(PORT + 1, 0x00); // Disable all interrupts + outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) + outb(PORT, 0x03); // Set divisor to 3 (lo byte) 38400 baud + outb(PORT + 1, 0x00); // (hi byte) + outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit + outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-bytethreshold + outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set + outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip + outb(PORT, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) - if inb(PORT + 0) != 0xAE { - return Err("serial test failed"); - } - - outb(PORT + 4, 0x0F); + if inb(PORT) != 0xAE { + return Err("serial test failed"); } + outb(PORT + 4, 0x0F); + Ok(()) } @@ -153,7 +149,7 @@ impl Reader { pub fn read(&self) -> u8 { unsafe { while !self.read_ready() {} - return inb(PORT + 0); + inb(PORT) } } } diff --git a/libk/src/lib.rs b/libk/src/lib.rs index dfcc3ba..962bf09 100644 --- a/libk/src/lib.rs +++ b/libk/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] - +#![warn(tail_expr_drop_order)] +#![warn(clippy::correctness, clippy::perf, clippy::nursery)] // alloc // io : serial, framebuffer, ascii(?), keyboard // ????? @@ -11,5 +12,5 @@ pub mod scheduling; /// Re-exports most of the IO macros. pub mod prelude { - pub use crate::{print_log, println, println_log, serial_print, serial_println}; + pub use crate::{print, print_log, println, println_log, serial_print, serial_println}; } diff --git a/libk/src/scheduling/task.rs b/libk/src/scheduling/task.rs index 844b873..ceaa2fa 100644 --- a/libk/src/scheduling/task.rs +++ b/libk/src/scheduling/task.rs @@ -14,8 +14,8 @@ pub struct Task { } impl Task { - pub fn new(future: impl Future + 'static) -> Task { - Task { + pub fn new(future: impl Future + 'static) -> Self { + Self { id: TaskId::new(), future: Box::pin(future), } @@ -32,9 +32,15 @@ pub struct Executor { waker_cache: BTreeMap, } +impl Default for Executor { + fn default() -> Self { + Self::new() + } +} + impl Executor { pub fn new() -> Self { - Executor { + Self { tasks: BTreeMap::new(), task_queue: Arc::new(ArrayQueue::new(100)), waker_cache: BTreeMap::new(), @@ -63,7 +69,7 @@ impl Executor { }; let waker = waker_cache .entry(task_id) - .or_insert_with(|| TaskWaker::new(task_id, task_queue.clone())); + .or_insert_with(|| TaskWaker::waker(task_id, task_queue.clone())); let mut context = Context::from_waker(waker); match task.poll(&mut context) { Poll::Ready(()) => { @@ -98,8 +104,8 @@ struct TaskWaker { } impl TaskWaker { - fn new(task_id: TaskId, task_queue: Arc>) -> Waker { - Waker::from(Arc::new(TaskWaker { + fn waker(task_id: TaskId, task_queue: Arc>) -> Waker { + Waker::from(Arc::new(Self { task_id, task_queue, })) @@ -128,6 +134,6 @@ struct TaskId(u64); impl TaskId { fn new() -> Self { static NEXT: AtomicU64 = AtomicU64::new(0); - TaskId(NEXT.fetch_add(1, Ordering::Relaxed)) + Self(NEXT.fetch_add(1, Ordering::Relaxed)) } } From 7e62bdae35c393ccd100c69e70e135d176b6d176 Mon Sep 17 00:00:00 2001 From: Jacob Hinchliffe Date: Sun, 23 Feb 2025 11:53:42 +0000 Subject: [PATCH 6/8] Make rust-analyzer use clippy as the check command. --- .vscode/settings.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c7cc8ca..deb9e98 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,6 +4,6 @@ "[rust]": { "editor.defaultFormatter": "rust-lang.rust-analyzer", "editor.formatOnSave": true - } -} - + }, + "rust-analyzer.check.command": "clippy", +} \ No newline at end of file From 2be5b63af7c62e3d02786ae472605988234cb48d Mon Sep 17 00:00:00 2001 From: Jacob Hinchliffe Date: Sun, 23 Feb 2025 11:58:52 +0000 Subject: [PATCH 7/8] Fix some more clippy lints. --- libk/src/io/framebuffer/colour.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/libk/src/io/framebuffer/colour.rs b/libk/src/io/framebuffer/colour.rs index 9e41b55..2d6c0b6 100644 --- a/libk/src/io/framebuffer/colour.rs +++ b/libk/src/io/framebuffer/colour.rs @@ -14,6 +14,7 @@ pub enum Colour { White = 0xFFFFFFFF, } +#[allow(clippy::use_self)] impl From for u32 { fn from(val: Colour) -> Self { match val { @@ -37,17 +38,17 @@ impl From for u32 { impl core::fmt::Display for Colour { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - Colour::ARGB(r, g, b, a) => write!(f, "RGBA(#{:x}{:x}{:x}{:x})", r, g, b, a), - Colour::RGB(r, g, b) => write!(f, "RGB(#{:x}{:x}{:x})", r, g, b), - Colour::HexARGB(hex) => write!(f, "Hex(#{:x})", hex), - Colour::Black => write!(f, "Black"), - Colour::Blue => write!(f, "Blue"), - Colour::Green => write!(f, "Green"), - Colour::Cyan => write!(f, "Cyan"), - Colour::Red => write!(f, "Red"), - Colour::Magenta => write!(f, "Magenta"), - Colour::Yellow => write!(f, "Yellow"), - Colour::White => write!(f, "White"), + Self::ARGB(r, g, b, a) => write!(f, "RGBA(#{:x}{:x}{:x}{:x})", r, g, b, a), + Self::RGB(r, g, b) => write!(f, "RGB(#{:x}{:x}{:x})", r, g, b), + Self::HexARGB(hex) => write!(f, "Hex(#{:x})", hex), + Self::Black => write!(f, "Black"), + Self::Blue => write!(f, "Blue"), + Self::Green => write!(f, "Green"), + Self::Cyan => write!(f, "Cyan"), + Self::Red => write!(f, "Red"), + Self::Magenta => write!(f, "Magenta"), + Self::Yellow => write!(f, "Yellow"), + Self::White => write!(f, "White"), } } } From d9b66f80082e23bec39e8fc738bc0c7c658cea14 Mon Sep 17 00:00:00 2001 From: nullndvoid Date: Sun, 23 Feb 2025 12:06:50 +0000 Subject: [PATCH 8/8] Update README to remove refs to submodules. --- README.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e013c0a..cb0c9b8 100644 --- a/README.md +++ b/README.md @@ -5,18 +5,20 @@ Here are some simple steps to get started: ```sh -# If you have not yet cloned the repo: -git clone --recurse-submodules https://git.zxq5.dev/OsDev/FoundryOS.git -# If you already cloned the repo: -git submodule update --init --recursive - -cargo build -# This will build the binaries if required - no need to call cargo build. +git clone https://git.zxq5.dev/OsDev/FoundryOS.git cargo run ``` +## Running in GDB: +```sh +USE_GDB=1 cargo run +``` + ### Build dependencies -* jq: checks whether the app is to be run in debugging mode. * libisoburn: creates ISO images to be booted from. * qemu: to run the kernel. + +Optionally, + +* GDB: for debugging the kernel. \ No newline at end of file