diff --git a/.cargo/config.toml b/.cargo/config.toml index cd125e0..0f4b13b 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -9,5 +9,16 @@ build-std-features = ["compiler-builtins-mem"] [env] RUST_TARGET_PATH = { value = "kernel", relative = true } -[target.x86_64-kernel] -runner = "scripts/run.sh" \ No newline at end of file +# Run in debug mode. +[target.'cfg(all(target_arch = "x86_64", target_os = "none", debug_assertions))'] +runner = "scripts/run_debug.sh" + +# 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 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/.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 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..3abf5a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,23 +1,18 @@ [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" +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/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 diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 4005239..f8b95ce 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -1,18 +1,12 @@ [package] name = "foundry_os" -version = "0.1.0" -edition = "2021" +edition.workspace = true +version.workspace = true +authors.workspace = true [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" } - +libk = { path = "../libk" } x86_64 = "0.15.2" spin = "0.9.8" pic8259 = "0.11.0" @@ -27,3 +21,4 @@ default = [] [[bin]] name = "kernel" path = "src/main.rs" +test = false 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/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 68bf61b..6ece312 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; @@ -20,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] @@ -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..b3e3a86 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -3,11 +3,13 @@ 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] +#[unsafe(no_mangle)] extern "C" fn kmain() -> ! { println_log!(" [ Initialising Kernel Systems ] "); if let Err(err) = foundry_os::boot() { @@ -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..d85eff6 --- /dev/null +++ b/libk/src/io/ascii.rs @@ -0,0 +1,216 @@ +use core::fmt; +use spin::{Lazy, Mutex}; +use x86_64::instructions::interrupts; + +pub use super::framebuffer::screensize_px; +use super::framebuffer::{Colour, 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: Colour, + bg_color: Colour, + + offset1: usize, + offset2: usize, +} + +impl Default for Writer { + fn default() -> Self { + Self::new() + } +} + +impl Writer { + pub fn new() -> Self { + 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: Colour::White, + bg_color: Colour::Black, + offset1: 16, + offset2: 0, + }, + ) + } + + pub fn write_glyph(&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, 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; + + 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 const fn set_offset(&mut self, offset1: usize, offset2: usize) { + self.offset1 = offset1; + self.offset2 = offset2; + } + + pub const fn dimensions(&self) -> (u32, u32) { + (self.screen_width, self.screen_height) + } + + pub const fn next_char(&mut self) { + self.text_col += 1; + } + + pub const 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_glyph(c as u16); + } + } + + pub const fn set_colour(&mut self, fg: Colour, bg: Colour) { + self.fg_color = fg; + self.bg_color = bg; + } + + pub const fn reset_colour(&mut self) { + self.fg_color = Colour::White; + self.bg_color = Colour::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: Colour, bg: Colour) { + 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, Colour::White, Colour::Black); + }) +} + +pub fn _print_err(args: fmt::Arguments) { + x86_64::instructions::interrupts::without_interrupts(|| { + write(args, Colour::Red, Colour::Black); + }) +} + +pub fn _print_log(args: fmt::Arguments) { + x86_64::instructions::interrupts::without_interrupts(|| { + write(args, Colour::Yellow, Colour::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..a9dd243 --- /dev/null +++ b/libk/src/io/framebuffer.rs @@ -0,0 +1,99 @@ +use limine::request::FramebufferRequest; + +#[used] +#[unsafe(link_section = ".requests")] +static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(); + +mod colour; + +pub use colour::Colour; +use core::panic; + +use limine::framebuffer::Framebuffer; +use spin::{Lazy, Mutex}; + +pub static FRAMEBUFFER_WRITER: Lazy>> = Lazy::new(|| { + 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)) + }, + )) +}); + +/// 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 Send for FramebufferWriter {} +unsafe impl Sync for FramebufferWriter {} + +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 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); + } + } + } + + pub const fn width(&self) -> u32 { + self.width as u32 + } + + pub const fn height(&self) -> u32 { + self.height as u32 + } + + pub fn clear(&self) { + 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, Colour::Black); + } + } + } +} + +pub fn screensize_px() -> (u32, u32) { + 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 new file mode 100644 index 0000000..2d6c0b6 --- /dev/null +++ b/libk/src/io/framebuffer/colour.rs @@ -0,0 +1,54 @@ +#[repr(u32)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Colour { + 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, +} + +#[allow(clippy::use_self)] +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) + } + 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 Colour { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + 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"), + } + } +} diff --git a/libk/src/io/keyboard.rs b/libk/src/io/keyboard.rs new file mode 100644 index 0000000..13603a8 --- /dev/null +++ b/libk/src/io/keyboard.rs @@ -0,0 +1,97 @@ +extern crate alloc; + +use core::{ + pin::Pin, + task::{Context, Poll}, +}; + +use crate::prelude::*; +use crossbeam::queue::ArrayQueue; +use futures_util::{Stream, task::AtomicWaker}; +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 queue.push(scancode).is_err() { + 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)); + + Self { _private: () } + } +} + +impl Default for ScanCodeStream { + fn default() -> Self { + Self::new() + } +} + +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"); + serial_println!("This is called once."); + WAKER.register(cx.waker()); + + // fast path + if let Some(scancode) = queue.pop() { + return Poll::Ready(Some(scancode)); + } + + queue.pop().map_or_else( + || { + print!("Returning"); + Poll::Pending + }, + |scancode| { + print!("Scancode found"); + WAKER.take(); + Poll::Ready(Some(scancode)) + }, + ) + } +} + +use futures_util::stream::StreamExt; +use pc_keyboard::{DecodedKey, HandleControl, Keyboard, ScancodeSet1, layouts}; + +pub async fn print_keypresses() { + let mut scancodes = ScanCodeStream::new(); + let mut keyboard = Keyboard::new( + ScancodeSet1::new(), + layouts::Us104Key, + HandleControl::Ignore, + ); + + serial_println!("Printing keypresses."); + + 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..77eafa0 --- /dev/null +++ b/libk/src/io/port.rs @@ -0,0 +1,29 @@ +//! Functions for IO using ports. + +use core::arch::asm; + +#[inline] +pub fn inb(port: u16) -> u8 { + let value: u8; + unsafe { + asm!( + "in al, dx", + out("al") value, + in("dx") port, + options(nomem, nostack, preserves_flags) + ); + } + value +} + +#[inline] +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 new file mode 100644 index 0000000..03db09a --- /dev/null +++ b/libk/src/io/serial.rs @@ -0,0 +1,155 @@ +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); + + 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, data); + } + } +} + +pub fn init() -> Result<(), &'static str> { + test()?; + + 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> { + 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) != 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() {} + inb(PORT) + } + } +} diff --git a/libk/src/lib.rs b/libk/src/lib.rs new file mode 100644 index 0000000..962bf09 --- /dev/null +++ b/libk/src/lib.rs @@ -0,0 +1,16 @@ +#![no_std] +#![warn(tail_expr_drop_order)] +#![warn(clippy::correctness, clippy::perf, clippy::nursery)] +// 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, 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..ceaa2fa --- /dev/null +++ b/libk/src/scheduling/task.rs @@ -0,0 +1,139 @@ +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) -> Self { + Self { + 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 Default for Executor { + fn default() -> Self { + Self::new() + } +} + +impl Executor { + pub fn new() -> Self { + Self { + 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::waker(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 waker(task_id: TaskId, task_queue: Arc>) -> Waker { + Waker::from(Arc::new(Self { + 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); + Self(NEXT.fetch_add(1, Ordering::Relaxed)) + } +} 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:-} +