diff --git a/.vscode/settings.json b/.vscode/settings.json index 17d2304..5b7e9e1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,5 +5,6 @@ "editor.defaultFormatter": "rust-lang.rust-analyzer", "editor.formatOnSave": true }, - "rust-analyzer.check.command": "clippy" + "rust-analyzer.check.command": "clippy", + "rust-analyzer.cargo.buildScripts.enable": true } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 16db54d..caceaa5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,6 +99,12 @@ dependencies = [ "syn", ] +[[package]] +name = "elf" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" + [[package]] name = "fnv" version = "1.0.7" @@ -111,7 +117,9 @@ version = "0.1.0" dependencies = [ "cc", "crossbeam", + "elf", "futures-util", + "gimli", "libm", "limine", "linked_list_allocator", @@ -145,6 +153,12 @@ dependencies = [ "pin-utils", ] +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + [[package]] name = "ident_case" version = "1.0.1" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 8a42939..1f8948d 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -19,6 +19,8 @@ futures-util = { version = "0.3.31", default-features = false, features = [ "alloc", ] } linked_list_allocator = { version = "0.10.5", features = ["use_spin"] } +gimli = { version = "0.31.1", default-features = false, features = ["read"] } +elf = { version = "0.7.4", default-features = false, features = ["nightly"] } [build-dependencies] cc = "1.2.14" diff --git a/kernel/linker.ld b/kernel/linker.ld index b327207..bd24c18 100644 --- a/kernel/linker.ld +++ b/kernel/linker.ld @@ -62,9 +62,8 @@ SECTIONS *(COMMON) } :data - /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ + /* Discard .note.* and ~~.eh_frame*~~ since they may cause issues on some hosts. */ /DISCARD/ : { - *(.eh_frame*) *(.note .note.*) } } diff --git a/kernel/src/arch/x86_64/cpu/apic.rs b/kernel/src/arch/x86_64/cpu/apic.rs index 57c7d55..669db9e 100644 --- a/kernel/src/arch/x86_64/cpu/apic.rs +++ b/kernel/src/arch/x86_64/cpu/apic.rs @@ -1,3 +1,5 @@ +#![expect(unused)] + use core::arch::x86_64::__cpuid; use crate::arch::x86_64::memory::mapping::PHYSICAL_MEMORY_OFFSET; diff --git a/kernel/src/arch/x86_64/cpu/msr.rs b/kernel/src/arch/x86_64/cpu/msr.rs index 5dae062..0463b70 100644 --- a/kernel/src/arch/x86_64/cpu/msr.rs +++ b/kernel/src/arch/x86_64/cpu/msr.rs @@ -1,3 +1,4 @@ +#![expect(unused)] use core::arch::x86_64::__cpuid; use spin::Lazy; use x86_64::registers::model_specific::Msr; diff --git a/kernel/src/arch/x86_64/cpu/pic.rs b/kernel/src/arch/x86_64/cpu/pic.rs index b43313d..4f95008 100644 --- a/kernel/src/arch/x86_64/cpu/pic.rs +++ b/kernel/src/arch/x86_64/cpu/pic.rs @@ -1,3 +1,5 @@ +#![allow(clippy::missing_safety_doc)] + use x86_64::instructions::port::Port; const CMD_INIT: u8 = 0x11; diff --git a/kernel/src/arch/x86_64/drivers/ascii/mod.rs b/kernel/src/arch/x86_64/drivers/ascii/mod.rs index 6e3cb37..e2a75fa 100644 --- a/kernel/src/arch/x86_64/drivers/ascii/mod.rs +++ b/kernel/src/arch/x86_64/drivers/ascii/mod.rs @@ -2,14 +2,17 @@ use core::fmt; use spin::{Lazy, Mutex}; use x86_64::instructions::interrupts; -use crate::arch::x86_64::drivers::framebuffer::{colour::Colour, display::FRAMEBUFFER_WRITER}; +use crate::arch::x86_64::drivers::framebuffer::{ + colour::Colour, display::FRAMEBUFFER_WRITER, +}; use crate::resources::font::{FONT_SPLEEN_8X16, Font}; static FONT_WIDTH: u32 = 8; static FONT_HEIGHT: u32 = 16; -pub static WRITER: Lazy> = Lazy::new(|| Mutex::new(Writer::new())); +pub static WRITER: Lazy> = + Lazy::new(|| Mutex::new(Writer::new())); pub fn screensize_chars() -> (u32, u32) { let writer = WRITER.lock(); @@ -71,21 +74,31 @@ impl Writer { return; } - // Get the character data from the font array. -- each byte is a row of pixels + // Get the character data from the font array. -- each byte is a row of + // pixels let data: &[u8] = self.font.glyph_for(c as u16); 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; + 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); + 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); + writer.write_pixel( + pixel_x as usize, + pixel_y as usize, + self.bg_color, + ); } } } @@ -117,8 +130,8 @@ impl Writer { } } - /// Handles the backspace character. TODO: Implement VT-100 style terminal control - /// codes alongside a shell. Not simple. + /// Handles the backspace character. TODO: Implement VT-100 style terminal + /// control codes alongside a shell. Not simple. pub fn backspace(&mut self) { if self.text_col > 0 { self.text_col -= 1; @@ -224,12 +237,12 @@ macro_rules! print { } #[macro_export] -macro_rules! printlnerr { +macro_rules! eprintln { () => ($crate::printerr!("\n")); - ($($arg:tt)*) => ($crate::printerr!("{}\n", format_args!($($arg)*))); + ($($arg:tt)*) => ($crate::eprint!("{}\n", format_args!($($arg)*))); } #[macro_export] -macro_rules! printerr { +macro_rules! eprint { ($($arg:tt)*) => ($crate::prelude::_print_err(format_args!($($arg)*))); } diff --git a/kernel/src/arch/x86_64/drivers/framebuffer/colour.rs b/kernel/src/arch/x86_64/drivers/framebuffer/colour.rs index 2d6c0b6..f6ccb7d 100644 --- a/kernel/src/arch/x86_64/drivers/framebuffer/colour.rs +++ b/kernel/src/arch/x86_64/drivers/framebuffer/colour.rs @@ -19,9 +19,14 @@ 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) + (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::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, @@ -38,7 +43,9 @@ impl From for u32 { 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::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"), diff --git a/kernel/src/arch/x86_64/drivers/framebuffer/display.rs b/kernel/src/arch/x86_64/drivers/framebuffer/display.rs index 576b77b..49d2726 100644 --- a/kernel/src/arch/x86_64/drivers/framebuffer/display.rs +++ b/kernel/src/arch/x86_64/drivers/framebuffer/display.rs @@ -10,17 +10,19 @@ 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)) - }, - )) -}); +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 @@ -28,7 +30,8 @@ pub static FRAMEBUFFER_WRITER: Lazy>> = Lazy::ne /// /// It also avoids the requirement for lifetimes. /// -/// Note this does not implement Writer as these functions only handle drawing pixels. +/// Note this does not implement Writer as these functions only handle drawing +/// pixels. pub struct FramebufferWriter { pitch: u64, bpp: u16, diff --git a/kernel/src/arch/x86_64/drivers/keyboard.rs b/kernel/src/arch/x86_64/drivers/keyboard.rs index 928d17a..90929ba 100644 --- a/kernel/src/arch/x86_64/drivers/keyboard.rs +++ b/kernel/src/arch/x86_64/drivers/keyboard.rs @@ -6,20 +6,24 @@ use core::{ use crate::println; use crossbeam::queue::ArrayQueue; use futures_util::{Stream, StreamExt, task::AtomicWaker}; -use pc_keyboard::{DecodedKey, HandleControl, KeyCode, Keyboard, ScancodeSet1, layouts::Uk105Key}; +use pc_keyboard::{ + DecodedKey, HandleControl, KeyCode, Keyboard, ScancodeSet1, + layouts::Uk105Key, +}; use spin::{Lazy, Mutex, Once}; static KBD_QUEUE: Once> = Once::new(); static WAKER: AtomicWaker = AtomicWaker::new(); -pub static KEYBOARD: Lazy>> = Lazy::new(|| { - Mutex::new(Keyboard::new( - ScancodeSet1::new(), - // TODO: Expose an API to change the default KB layout. - Uk105Key, - HandleControl::Ignore, - )) -}); +pub static KEYBOARD: Lazy>> = + Lazy::new(|| { + Mutex::new(Keyboard::new( + ScancodeSet1::new(), + // TODO: Expose an API to change the default KB layout. + Uk105Key, + HandleControl::Ignore, + )) + }); pub static SCANCODE_STREAM: Lazy> = Lazy::new(|| Mutex::new(ScancodeStream::new())); @@ -59,7 +63,10 @@ impl Default for ScancodeStream { impl Stream for ScancodeStream { type Item = u8; - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll_next( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { let queue = KBD_QUEUE.get().unwrap(); if let Some(scancode) = queue.pop() { diff --git a/kernel/src/arch/x86_64/interrupts.rs b/kernel/src/arch/x86_64/interrupts.rs index 2849e65..2626e0b 100644 --- a/kernel/src/arch/x86_64/interrupts.rs +++ b/kernel/src/arch/x86_64/interrupts.rs @@ -138,7 +138,8 @@ extern "x86-interrupt" fn page_fault_handler( let frame = f.allocate_frame().unwrap(); let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; - let page: Page = Page::containing_address(Cr2::read().unwrap()); + let page: Page = + Page::containing_address(Cr2::read().unwrap()); unsafe { let mut mapper = OFFSET_PAGE_TABLE.get().unwrap().lock(); diff --git a/kernel/src/arch/x86_64/memory/allocation/mod.rs b/kernel/src/arch/x86_64/memory/allocation/mod.rs index 6877073..979df58 100644 --- a/kernel/src/arch/x86_64/memory/allocation/mod.rs +++ b/kernel/src/arch/x86_64/memory/allocation/mod.rs @@ -1,3 +1,3 @@ pub mod heap_alloc; -pub mod stack_alloc; pub(crate) mod page_alloc; +pub mod stack_alloc; diff --git a/kernel/src/arch/x86_64/memory/allocation/page_alloc.rs b/kernel/src/arch/x86_64/memory/allocation/page_alloc.rs index 37e1185..6d393df 100644 --- a/kernel/src/arch/x86_64/memory/allocation/page_alloc.rs +++ b/kernel/src/arch/x86_64/memory/allocation/page_alloc.rs @@ -14,14 +14,17 @@ pub struct FoundryOSFrameAllocator { impl FoundryOSFrameAllocator { /// Creates a new `FoundryOSFrameAllocator` from a memory map. /// - /// This function takes a reference to a `MemoryMapResponse` and initializes a - /// `FoundryOSFrameAllocator` with it. The `next` field is set to 0, indicating that - /// the first frame to be allocated is the first frame in the memory map. + /// This function takes a reference to a `MemoryMapResponse` and initializes + /// a `FoundryOSFrameAllocator` with it. The `next` field is set to 0, + /// indicating that the first frame to be allocated is the first frame + /// in the memory map. pub fn init(memory_map: &'static MemoryMapResponse) { - FRAME_ALLOCATOR.call_once(|| Mutex::new(Self { - memory_map, - next: 0, - })); + FRAME_ALLOCATOR.call_once(|| { + Mutex::new(Self { + memory_map, + next: 0, + }) + }); } pub fn count_usable_frames(&self) -> u64 { @@ -70,9 +73,9 @@ impl FoundryOSFrameAllocator { unsafe impl FrameAllocator for FoundryOSFrameAllocator { /// Allocates a frame from the list of usable frames. /// - /// This function returns the next available `PhysFrame` from the memory map, - /// if one exists. Once a frame is allocated, the internal counter is incremented - /// to point to the next frame for future allocations. + /// This function returns the next available `PhysFrame` from the memory + /// map, if one exists. Once a frame is allocated, the internal counter + /// is incremented to point to the next frame for future allocations. /// /// # Returns /// @@ -80,9 +83,6 @@ unsafe impl FrameAllocator for FoundryOSFrameAllocator { /// - `None`: If there are no more usable frames to allocate. fn allocate_frame(&mut self) -> Option { let frame = self.usable_frames().nth(self.next); - if frame.is_none() { - panic!("this shouldnt happen!"); - } self.next += 1; frame } diff --git a/kernel/src/arch/x86_64/memory/allocation/stack_alloc.rs b/kernel/src/arch/x86_64/memory/allocation/stack_alloc.rs index 513b9fe..1665f22 100644 --- a/kernel/src/arch/x86_64/memory/allocation/stack_alloc.rs +++ b/kernel/src/arch/x86_64/memory/allocation/stack_alloc.rs @@ -1,33 +1,39 @@ -use x86_64::structures::paging::{mapper, FrameAllocator, Mapper, Page, Size4KiB}; -use x86_64::VirtAddr; use crate::arch::x86_64::memory::STACK_VIRTUAL_SPACE; +use x86_64::VirtAddr; +use x86_64::structures::paging::{ + FrameAllocator, Mapper, Page, Size4KiB, mapper, +}; fn reserve_stack_memory(size_in_pages: u64) -> Page { use core::sync::atomic::{AtomicU64, Ordering}; - static STACK_ALLOC_NEXT: AtomicU64 = AtomicU64::new(STACK_VIRTUAL_SPACE as u64); - let start_addr = VirtAddr::new(STACK_ALLOC_NEXT.fetch_add( - size_in_pages * Page::::SIZE, - Ordering::Relaxed, - )); + static STACK_ALLOC_NEXT: AtomicU64 = + AtomicU64::new(STACK_VIRTUAL_SPACE as u64); + let start_addr = + VirtAddr::new(STACK_ALLOC_NEXT.fetch_add( + size_in_pages * Page::::SIZE, + Ordering::Relaxed, + )); Page::from_start_address(start_addr) .expect("`STACK_ALLOC_NEXT` not page aligned") } /// Allocates a stack in the virtual address space, mapped to physical pages. /// -/// This function allocates a stack in the virtual address space, mapped to physical pages. -/// The stack is allocated as a sequence of pages, with the first page allocated as a guard page. -/// The stack is then mapped to the allocated physical frame. +/// This function allocates a stack in the virtual address space, mapped to +/// physical pages. The stack is allocated as a sequence of pages, with the +/// first page allocated as a guard page. The stack is then mapped to the +/// allocated physical frame. /// -/// The function takes the size of the stack in pages, a mutable reference to a mapper, and a -/// mutable reference to a frame allocator. It returns a `Result` containing a `StackBounds` -/// struct, which contains the start and end virtual addresses of the allocated stack. +/// The function takes the size of the stack in pages, a mutable reference to a +/// mapper, and a mutable reference to a frame allocator. It returns a `Result` +/// containing a `StackBounds` struct, which contains the start and end virtual +/// addresses of the allocated stack. /// /// # Safety /// -/// This function is unsafe because it maps physical frames to virtual addresses without any -/// protection. This can lead to bugs if the physical frames are not correctly allocated, or if the -/// virtual addresses are not correctly aligned. +/// This function is unsafe because it maps physical frames to virtual addresses +/// without any protection. This can lead to bugs if the physical frames are not +/// correctly allocated, or if the virtual addresses are not correctly aligned. /// /// # Panics /// @@ -36,27 +42,28 @@ pub unsafe fn alloc_stack( size_in_pages: u64, mapper: &mut impl Mapper, frame_allocator: &mut impl FrameAllocator, -) -> Result> { unsafe { - use x86_64::structures::paging::PageTableFlags as Flags; - - let guard_page = reserve_stack_memory(size_in_pages + 1); - let stack_start = guard_page + 1; - let stack_end = stack_start + size_in_pages; +) -> Result> { + unsafe { + use x86_64::structures::paging::PageTableFlags as Flags; - for page in Page::range(stack_start, stack_end) { - let frame = frame_allocator - .allocate_frame() - .ok_or(mapper::MapToError::FrameAllocationFailed)?; - let flags = Flags::PRESENT | Flags::WRITABLE; - mapper.map_to(page, frame, flags, frame_allocator)?.flush(); + let guard_page = reserve_stack_memory(size_in_pages + 1); + let stack_start = guard_page + 1; + let stack_end = stack_start + size_in_pages; + + for page in Page::range(stack_start, stack_end) { + let frame = frame_allocator + .allocate_frame() + .ok_or(mapper::MapToError::FrameAllocationFailed)?; + let flags = Flags::PRESENT | Flags::WRITABLE; + mapper.map_to(page, frame, flags, frame_allocator)?.flush(); + } + + Ok(StackBounds { + start: stack_start.start_address(), + end: stack_end.start_address(), + }) } - - Ok(StackBounds { - start: stack_start.start_address(), - end: stack_end.start_address(), - }) -}} - +} #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct StackBounds { @@ -76,4 +83,4 @@ impl StackBounds { pub const fn end(&self) -> VirtAddr { self.end } -} \ No newline at end of file +} diff --git a/kernel/src/arch/x86_64/memory/mapping.rs b/kernel/src/arch/x86_64/memory/mapping.rs index 1df8437..a64ceaf 100644 --- a/kernel/src/arch/x86_64/memory/mapping.rs +++ b/kernel/src/arch/x86_64/memory/mapping.rs @@ -16,7 +16,8 @@ static HIGHER_HALF_DIRECT_MAP_REQUEST: HhdmRequest = HhdmRequest::new(); #[used] #[unsafe(link_section = ".requests")] -static KERNEL_ADDRESS_REQUEST: KernelAddressRequest = KernelAddressRequest::new(); +pub static KERNEL_ADDRESS_REQUEST: KernelAddressRequest = + KernelAddressRequest::new(); /// ```rs /// let virt_addr = phys_addr + offset; diff --git a/kernel/src/arch/x86_64/memory/mod.rs b/kernel/src/arch/x86_64/memory/mod.rs index fe6d18b..0ee8807 100644 --- a/kernel/src/arch/x86_64/memory/mod.rs +++ b/kernel/src/arch/x86_64/memory/mod.rs @@ -2,20 +2,19 @@ pub mod allocation; pub mod mapping; pub mod units; -use spin::{Mutex, Once}; -use x86_64::{ - registers::control::Cr3, structures::paging::{FrameAllocator, OffsetPageTable, PageTable} - , - VirtAddr, -}; use allocation::page_alloc::FoundryOSFrameAllocator; +use spin::{Mutex, Once}; use units::MemoryUnits::*; +use x86_64::{ + VirtAddr, + registers::control::Cr3, + structures::paging::{OffsetPageTable, PageTable}, +}; pub const STACK_VIRTUAL_SPACE: usize = 0x5555_5555_0000; // start address of the memory space where we store allocated stacks pub const HEAP_VIRTUAL_SPACE: usize = 0x4444_4444_0000; // start address of heap allocated memory pub const HEAP_SIZE: usize = MiB(1).to_bytes(); - pub static FRAME_ALLOCATOR: Once> = Once::new(); pub static OFFSET_PAGE_TABLE: Once> = Once::new(); /// Returns a mutable reference to the current level 4 page table. @@ -25,7 +24,9 @@ pub static OFFSET_PAGE_TABLE: Once> = Once::new(); /// The caller must ensure that the level 4 page table is not modified /// simultaneously. The caller must also ensure that the physical memory offset /// is correct, to ensure that the correct virtual address is constructed. -unsafe fn active_l4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable { +unsafe fn active_l4_table( + physical_memory_offset: VirtAddr, +) -> &'static mut PageTable { let (level_4_frame, _) = Cr3::read(); let phys_addr = level_4_frame.start_address(); @@ -54,8 +55,8 @@ unsafe fn active_l4_table(physical_memory_offset: VirtAddr) -> &'static mut Page pub fn init_page_table(physical_memory_offset: VirtAddr) { unsafe { let l4_table = active_l4_table(physical_memory_offset); - let offset_table = OffsetPageTable::new(l4_table, physical_memory_offset); + let offset_table = + OffsetPageTable::new(l4_table, physical_memory_offset); OFFSET_PAGE_TABLE.call_once(|| Mutex::new(offset_table)); } } - diff --git a/kernel/src/arch/x86_64/memory/units.rs b/kernel/src/arch/x86_64/memory/units.rs index 4d24d50..7129ab8 100644 --- a/kernel/src/arch/x86_64/memory/units.rs +++ b/kernel/src/arch/x86_64/memory/units.rs @@ -30,7 +30,7 @@ impl MemoryUnits { pub const fn convert(&mut self) { match self { Self::B(b) if *b > 1024 => *self = Self::KiB(*b / 1024), - Self::KiB(kib) if *kib > 1024 => *self = Self::MiB(*kib / 1024), + Self::KiB(kib) if *kib > 1024 => *self = Self::MiB(*kib / 1024), Self::MiB(mib) if *mib > 1024 => *self = Self::GiB(*mib / 1024), _ => (), } @@ -46,4 +46,4 @@ impl core::fmt::Display for MemoryUnits { Self::GiB(gib) => write!(f, "{} GiB", gib), } } -} \ No newline at end of file +} diff --git a/kernel/src/arch/x86_64/processing/async_io/task.rs b/kernel/src/arch/x86_64/processing/async_io/task.rs index e522af0..c2ccf20 100644 --- a/kernel/src/arch/x86_64/processing/async_io/task.rs +++ b/kernel/src/arch/x86_64/processing/async_io/task.rs @@ -2,7 +2,6 @@ //! //! Written by @zxq5 for the most part with code from //! [here](https://github.com/phil-opp/blog_os/). -//! use alloc::boxed::Box; use alloc::collections::BTreeMap; @@ -81,9 +80,9 @@ impl Executor { Some(task) => task, None => continue, // task no longer exists }; - let waker = waker_cache - .entry(task_id) - .or_insert_with(|| TaskWaker::new_waker(task_id, task_queue.clone())); + let waker = waker_cache.entry(task_id).or_insert_with(|| { + TaskWaker::new_waker(task_id, task_queue.clone()) + }); let mut context = Context::from_waker(waker); match task.poll(&mut context) { Poll::Ready(()) => { @@ -129,7 +128,10 @@ impl TaskWaker { self.task_queue.push(self.task_id).expect("task_queue full"); } - fn new_waker(task_id: TaskId, task_queue: Arc>) -> Waker { + fn new_waker( + task_id: TaskId, + task_queue: Arc>, + ) -> Waker { Waker::from(Arc::new(Self { task_id, task_queue, diff --git a/kernel/src/arch/x86_64/processing/mod.rs b/kernel/src/arch/x86_64/processing/mod.rs index 01f827c..b30ed57 100644 --- a/kernel/src/arch/x86_64/processing/mod.rs +++ b/kernel/src/arch/x86_64/processing/mod.rs @@ -1,3 +1,4 @@ +#![expect(unused)] pub mod async_io; -pub mod threading; mod taskrunner; +pub mod threading; diff --git a/kernel/src/arch/x86_64/processing/taskrunner/mod.rs b/kernel/src/arch/x86_64/processing/taskrunner/mod.rs index 0198236..7b041a1 100644 --- a/kernel/src/arch/x86_64/processing/taskrunner/mod.rs +++ b/kernel/src/arch/x86_64/processing/taskrunner/mod.rs @@ -6,7 +6,7 @@ pub struct Task { } impl Task { - pub fn new() {} + // pub const fn new() {} - pub fn run() {} -} \ No newline at end of file + pub const fn run() {} +} diff --git a/kernel/src/arch/x86_64/processing/threading/mod.rs b/kernel/src/arch/x86_64/processing/threading/mod.rs index 2aa540f..db5bf89 100644 --- a/kernel/src/arch/x86_64/processing/threading/mod.rs +++ b/kernel/src/arch/x86_64/processing/threading/mod.rs @@ -1,5 +1,5 @@ -use x86_64::VirtAddr; use crate::arch::x86_64::memory::allocation::stack_alloc::StackBounds; +use x86_64::VirtAddr; mod switch; @@ -10,8 +10,6 @@ pub struct Thread { stack_bounds: Option, } - - #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct ThreadId(u64); diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 995df90..718213e 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -12,42 +12,43 @@ )] extern crate alloc; -use crate::{ - arch::x86_64::memory::init_page_table, - prelude::*, -}; +use crate::{arch::x86_64::memory::init_page_table, prelude::*}; use arch::x86_64::memory::allocation::heap_alloc::init_heap; use arch::x86_64::memory::mapping; use core::arch::asm; use limine::BaseRevision; +use std::unwind; +use std::unwind::eh_info::ELF; use x86_64::VirtAddr; use arch::x86_64::memory::allocation::page_alloc::FoundryOSFrameAllocator; use crate::arch::x86_64::cpu::apic::enable_apic; use crate::arch::x86_64::drivers::ascii::screensize_chars; use crate::arch::x86_64::drivers::framebuffer::display::screensize_px; -use crate::arch::x86_64::memory::allocation::heap_alloc::FoundryAllocator; use crate::arch::x86_64::memory::FRAME_ALLOCATOR; use crate::arch::x86_64::memory::units::MemoryUnits; pub mod arch; +mod panic; pub mod resources; #[allow(unused)] // We aren't using much of this right now. pub mod std; pub mod util; pub mod prelude { - pub use crate::std::io::{_print, _print_log, _serial_write}; - pub use crate::std::debug::_debug; pub use crate::{ - print, print_log, printerr, println, println_log, printlnerr, serial_print, serial_println, debug + eprint, eprintln, print, print_log, println, println_log, serial_print, + serial_println, + std::io::{_print, _print_err, _print_log, _serial_write}, }; } /// Sets the base revision to the latest revision supported by the crate. /// See specification for further info. -/// Be sure to mark all limine requests with #[used], otherwise they may be removed by the compiler. +/// 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. +// The .requests section allows limine to find the requests faster and more +// safely. #[unsafe(link_section = ".requests")] static BASE_REVISION: BaseRevision = BaseRevision::new(); @@ -69,7 +70,7 @@ pub fn hcf() -> ! { pub fn boot() -> Result<(), &'static str> { if !BASE_REVISION.is_supported() { - return Err("base revision not supported"); + return Err("Base revision not supported"); } use arch::x86_64::{gdt, interrupts}; @@ -131,5 +132,16 @@ pub fn boot() -> Result<(), &'static str> { x86_64::instructions::interrupts::enable(); debugln!("[Success]"); + debug!(" Setting up stack unwinder, panic handler... "); + // Setup stack traces and proper panic handler. TODO: Handle panics + // differently if not initialised. + let eh_frame_ptr = ELF + .get_section_addr(".eh_frame_hdr") + .expect("Could not get `.eh_frame_hdr` address."); + + let _eh_info = + unsafe { unwind::eh_info::EhInfo::from_hdr_ptr(eh_frame_ptr) }; + debugln!("[Success]"); + Ok(()) } diff --git a/kernel/src/panic.rs b/kernel/src/panic.rs new file mode 100644 index 0000000..a10718d --- /dev/null +++ b/kernel/src/panic.rs @@ -0,0 +1,75 @@ +// //! Stack-unwinding code for the Kernel. This is a modified version of https://github.com/nbdd0121/unwinding/blob/trunk/src/panic_handler.rs +// //! which does not support environment variables for obvious reasons, however we +// //! may implement a cmdline similar to Linux in the near future. + +// #![expect( +// clippy::empty_loop, +// reason = "We don't yet have working power management. This is OK for now." +// )] +// use crate::prelude::*; +// use alloc::boxed::Box; +// use core::any::Any; +// use core::cell::Cell; +// use core::ffi::c_void; +// use core::panic::{Location, PanicInfo}; +// use unwinding::abi::*; +// use unwinding::panic::begin_panic; + +// #[thread_local] +// static PANIC_COUNT: Cell = Cell::new(0); + +// #[link(name = "c")] +// unsafe extern "C" {} + +// fn stack_trace() { +// struct CallbackData { +// counter: usize, +// } + +// extern "C" fn callback( +// unwind_ctx: &UnwindContext<'_>, +// arg: *mut c_void, +// ) -> UnwindReasonCode { +// let data = unsafe { &mut *(arg as *mut CallbackData) }; +// data.counter += 1; +// eprintln!( +// "{:4}:{:#19x} - ", +// data.counter, +// _Unwind_GetIP(unwind_ctx) +// ); +// UnwindReasonCode::NO_REASON +// } +// let mut data = CallbackData { counter: 0 }; +// _Unwind_Backtrace(callback, &mut data as *mut _ as _); +// } + +// fn do_panic(msg: Box) -> ! { +// if PANIC_COUNT.get() >= 1 { +// stack_trace(); +// eprintln!("Thread panicked while processing panic. aborting."); +// loop {} +// } + +// PANIC_COUNT.set(1); +// stack_trace(); + +// let code = begin_panic(Box::new(msg)); +// eprintln!("Failed to initiate panic: error {}", code.0); + +// loop {} +// } + +// #[panic_handler] +// fn panic(info: &PanicInfo<'_>) -> ! { +// eprintln!("{}", info); + +// struct NoPayload; +// do_panic(Box::new(NoPayload)) +// } + +// #[track_caller] +// #[expect(unused, reason = "May still be used in the future.")] +// pub fn panic_any(msg: M) -> ! { +// eprintln!("Panicked at {}", Location::caller()); +// do_panic(Box::new(msg)) +// } diff --git a/kernel/src/resources/font/mod.rs b/kernel/src/resources/font/mod.rs index ebe52ed..cc6b52a 100644 --- a/kernel/src/resources/font/mod.rs +++ b/kernel/src/resources/font/mod.rs @@ -1,8 +1,8 @@ use libm::include_font; -pub static FONT_SPLEEN_8X16: Font = +pub const FONT_SPLEEN_8X16: Font = Font::new(include_font!("../../../resources/font/spleen-8x16.psf")); -pub static FONT_CP850_8X16: Font = +pub const FONT_CP850_8X16: Font = Font::new(include_font!("../../../resources/font/cp850-8x16.psf")); // pub struct Font(pub [[u8; 16]; 512]); @@ -39,8 +39,10 @@ impl Font { pub const fn height(&self) -> usize { self.height } +} - pub fn default() -> &'static Self { - &FONT_CP850_8X16 +impl Default for Font { + fn default() -> Self { + FONT_CP850_8X16 } } diff --git a/kernel/src/std/application.rs b/kernel/src/std/application.rs index 7131253..7976172 100644 --- a/kernel/src/std/application.rs +++ b/kernel/src/std/application.rs @@ -8,7 +8,10 @@ pub mod window; pub trait Application { type Output; - fn run(&mut self, args: Vec) -> impl Future> + Send; + fn run( + &mut self, + args: Vec, + ) -> impl Future> + Send; } #[derive(Debug)] diff --git a/kernel/src/std/application/frame.rs b/kernel/src/std/application/frame.rs index a1cdfb6..b8a6346 100644 --- a/kernel/src/std/application/frame.rs +++ b/kernel/src/std/application/frame.rs @@ -11,20 +11,31 @@ pub struct Frame<'f> { impl<'a> Frame<'a> { pub fn new(window: &'a Window) -> Self { Self { - data: vec![vec![Colour::Black; window.dimensions().x()]; window.dimensions().y()], + data: vec![ + vec![Colour::Black; window.dimensions().x()]; + window.dimensions().y() + ], window, } } pub fn render(&self) -> Result<(), RenderError> { - let data: Vec<&[Colour]> = self.data.iter().map(|v| v.as_slice()).collect::>(); + let data: Vec<&[Colour]> = + self.data.iter().map(|v| v.as_slice()).collect::>(); self.window .render(data.as_slice()) .map_err(|_| RenderError::Generic) } - pub fn write_pixel(&mut self, x: usize, y: usize, color: Colour) -> Result<(), RenderError> { - if x >= self.window.dimensions().x() || y >= self.window.dimensions().y() { + pub fn write_pixel( + &mut self, + x: usize, + y: usize, + color: Colour, + ) -> Result<(), RenderError> { + if x >= self.window.dimensions().x() + || y >= self.window.dimensions().y() + { return Err(RenderError::Generic); } self.data[y][x] = color; diff --git a/kernel/src/std/application/window.rs b/kernel/src/std/application/window.rs index 758cbf6..bcc4156 100644 --- a/kernel/src/std/application/window.rs +++ b/kernel/src/std/application/window.rs @@ -24,7 +24,8 @@ impl Window { } pub fn render(&self, _data: &[&[Colour]]) -> Result<(), RenderError> { - // TODO: error handling!! the kernel should return an error in some cases + // TODO: error handling!! the kernel should return an error in some + // cases if let Some(fb) = FRAMEBUFFER_WRITER.lock().as_mut() { fb.render_frame(_data); } diff --git a/kernel/src/std/ascii.rs b/kernel/src/std/ascii.rs index 1a37feb..97eb294 100644 --- a/kernel/src/std/ascii.rs +++ b/kernel/src/std/ascii.rs @@ -46,7 +46,11 @@ impl<'a> Writer<'a> { if line & (0x80 >> col) != 0 { for i in 0..scale { for j in 0..scale { - frame.write_pixel(pixel_x + i, pixel_y + j, Colour::White)?; + frame.write_pixel( + pixel_x + i, + pixel_y + j, + Colour::White, + )?; } } } diff --git a/kernel/src/std/elf/mod.rs b/kernel/src/std/elf/mod.rs new file mode 100644 index 0000000..021f0c7 --- /dev/null +++ b/kernel/src/std/elf/mod.rs @@ -0,0 +1,114 @@ +//! Basic ELF parsing functionality using the `elf` crate. +//! +//! This may be extended in the future to support loading programs, however we +//! currently use this for getting the sizes of sections in our kernel ELF at +//! runtime. +//! +//! This is used for implementing stacktraces in std::unwind. +//! +//! # TODO +//! +//! * Add support for loading binary programs (this should probably be written +//! in a different module) + +use alloc::format; +use elf::{ + ElfBytes, ParseError, + endian::LittleEndian, + parse::{ParseAt, ParsingTable}, + section::{SectionHeader, SectionHeaderTable}, + string_table::StringTable, +}; +use limine::request::KernelFileRequest; + +use crate::prelude::*; + +#[cfg(target_arch = "x86_64")] +/// The length of the ELF header in bytes. +pub const ELF_HEADER_LEN: usize = 64; + +/// Information about our own ELF file to make ELF parsing easier, such as the +/// length of the file and a pointer to the contents. +#[used] +pub static KERNEL_FILE_REQUEST: KernelFileRequest = KernelFileRequest::new(); + +/// A list of errors that may occur when parsing ELF files. +#[derive(Debug)] +pub enum ElfError { + /// Returned if a section did not exist in [ElfReader::get_section_size]. + SectionNotExists, + /// Parse errors returned by the `elf` crate. + OtherParseError(elf::ParseError), +} + +impl From for ElfError { + fn from(err: elf::ParseError) -> Self { + Self::OtherParseError(err) + } +} + +pub struct ElfReader { + /// Structure returned by the `elf` crate having parsed the ELF header. + elf: ElfBytes<'static, LittleEndian>, +} + +impl ElfReader { + /// Parses the ELF file for the kernel, this uses data from Limine's Kernel + /// File Request to get a slice over the whole executable file. + /// + /// # Safety + /// + /// Assumes a properly formed ELF file, and that Limine returns a correct + /// pointer to the start of the file as well as a valid length in bytes. + /// + /// Both of these should be satisfied, but this function is marked unsafe + /// just in case, because we are derefererencing arbitrary pointers. + pub unsafe fn new() -> Result { + let response = KERNEL_FILE_REQUEST + .get_response() + .expect("Didn't get the kernel file from Limine. That's odd."); + + // We fetch these from Limine and use them to parse our own ELF file. + let file = response.file(); + let file_start_ptr = file.addr(); + let file_size = file.size() as usize; + + // Safety: This slice should contain the whole bytes of the ELF file. + let elf_hdr_slice = + unsafe { core::slice::from_raw_parts(file_start_ptr, file_size) }; + + let elf: ElfBytes<'static, LittleEndian> = + elf::ElfBytes::minimal_parse(elf_hdr_slice)?; + + Ok(Self { elf }) + } + + /// Gets the section size of `section_name` in bytes. + pub fn get_section_size( + &self, + section_name: &'static str, + ) -> Result { + Ok(self.get_section_header(section_name)?.sh_size) + } + + /// Gets the start address of the section `section_name` in memory. + pub fn get_section_addr( + &self, + section_name: &'static str, + ) -> Result<*const u8, ElfError> { + Ok(self.get_section_header(section_name)?.sh_addr as *const u8) + } + + /// Gets the section header of `section_name`. + pub fn get_section_header( + &self, + section_name: &'static str, + ) -> Result { + let section_hdr = self + .elf + .section_header_by_name(section_name) + .map_err(|_e| ElfError::SectionNotExists)?; + + section_hdr.ok_or(ElfError::SectionNotExists) + } +} diff --git a/kernel/src/std/io/mod.rs b/kernel/src/std/io/mod.rs new file mode 100644 index 0000000..b43503a --- /dev/null +++ b/kernel/src/std/io/mod.rs @@ -0,0 +1,6 @@ +pub use crate::arch::x86_64::drivers::{ + ascii::{_print, _print_err, _print_log}, + serial::_serial_write, +}; + +pub mod stdin; diff --git a/kernel/src/std/io/stdin.rs b/kernel/src/std/io/stdin.rs new file mode 100644 index 0000000..d9934a8 --- /dev/null +++ b/kernel/src/std/io/stdin.rs @@ -0,0 +1,75 @@ +use crate::arch::x86_64::drivers::{ + ascii::WRITER, + keyboard::{KeyStroke, get_keystroke_async, get_keystroke_optional}, +}; +use alloc::string::String; + +/// Reads a line of input from standard input asynchronously, returning a +/// `String` containing the input line. Does not include the newline +/// character at the end of the line. +/// +/// If the user presses the abort key (usually Ctrl+C), the returned string +/// will be empty. +pub async fn read_line() -> String { + let mut writer = WRITER.lock(); + + let mut buff = String::new(); + loop { + match get_keystroke_async().await { + KeyStroke::Char(c) => match c { + '\n' => { + writer.write_glyph(c as u8); + return buff; + } + '\r' => { + writer.write_glyph(c as u8); + return buff; + } + '\x08' => { + if !buff.is_empty() { + buff.pop(); + writer.backspace(); + } + } + + c => { + writer.write_glyph(c as u8); + buff.push(c) + } + }, + KeyStroke::Enter => { + writer.write_glyph(b'\n'); + return buff; + } + KeyStroke::Backspace => { + if !buff.is_empty() { + buff.pop(); + writer.backspace(); + } + } + _ => continue, + } + } +} + +/// Reads a character from standard input and blocks the current task until +/// a character is available. +/// +/// # Note +/// +/// This function is not yet implemented. +pub async fn async_keystroke() -> KeyStroke { + get_keystroke_async().await +} + +/// Attempt to read a character from standard input without blocking the +/// current task. +/// +/// If no character is available, returns `None`. +/// +/// # Note +/// +/// This function is not yet implemented. +pub fn keystroke() -> Option { + get_keystroke_optional() +} diff --git a/kernel/src/std/mod.rs b/kernel/src/std/mod.rs index eb09545..678d2ec 100644 --- a/kernel/src/std/mod.rs +++ b/kernel/src/std/mod.rs @@ -1,5 +1,7 @@ pub mod application; pub mod ascii; +pub mod elf; pub mod io; pub mod maths; +pub mod unwind; pub mod debug; diff --git a/kernel/src/std/unwind/eh_info.rs b/kernel/src/std/unwind/eh_info.rs new file mode 100644 index 0000000..8048d12 --- /dev/null +++ b/kernel/src/std/unwind/eh_info.rs @@ -0,0 +1,135 @@ +//! Contains a [EhInfo] struct that contains the parsed DWARF exception header +//! data from the ELF .eh_frame and .eh_frame_hdr sections. + +use alloc::{boxed::Box, slice}; +use gimli::{ + BaseAddresses, EhFrame, EhFrameHdr, EhHdrTable, EndianSlice, LittleEndian, + ParsedEhFrameHdr, +}; +use spin::Lazy; + +use crate::{println_log, std::elf::ElfReader}; + +/// Contains useful data parsed from the ELF file in question. In the kernel +/// this will be our own process. +/// +/// We use this to implement stack traces and potential unwinding. +/// +/// # Sources +/// +/// This code is reproduced from [lesenchal.fr](https://lesenechal.fr/en/linux/unwinding-the-stack-the-hard-way#h5.1-parsing-eh_frame-and-eh_frame_hdr-with-gimli) +/// and will later be extended as required. +pub struct EhInfo { + /// A set of base addresses used for relative addressing. + base_addrs: BaseAddresses, + /// The parsed `.eh_frame_hdr` section. + hdr: &'static ParsedEhFrameHdr>, + /// The lookup table in the parsed `.eh_frame_hdr` section. + /// This is a binary search table, it is optional but should be present as + /// we are linking with LLD(?) \[needs citation]. + hdr_table: EhHdrTable<'static, EndianSlice<'static, LittleEndian>>, + /// The parsed `.eh_frame` containing the CFIs (call frame information). + eh_frame: EhFrame>, +} + +/// Stores the [ElfReader] struct for this ELF file. +pub static ELF: Lazy = + Lazy::new(|| unsafe { ElfReader::new().unwrap() }); + +impl EhInfo { + /// Gets the `.eh_frame_hdr` size in bytes. + /// + /// # Panics + /// + /// If we can't get the size of `.eh_frame_hdr`. + pub fn eh_frame_hdr_size() -> usize { + ELF.get_section_size(".eh_frame_hdr") + .expect("Cannot get size of `.eh_frame_hdr`.") as usize + } + + /// Gets the `.eh_frame` size in bytes. + /// + /// # Panics + /// + /// If we can't get the size of `.eh_frame`. + pub fn eh_frame_size() -> usize { + ELF.get_section_size(".eh_frame") + .expect("Cannot get size of `.eh_frame`.") as usize + } + + /// Constructs a [EhInfo] from the base address. This is defined for a + /// symbol in the linker script so we can initialise stack traces and -- in + /// the future -- unwinding. + /// + /// # Safety + /// + /// Assumes the `.eh_frame_hdr` pointer to be valid, as well as the sizes of + /// the containing sections. These sizes are computed using [ElfReader]. + /// + /// # Panics + /// + /// This function panics if Gimli throws parsing errors -- for example due + /// to a malformed or corrupted binary, or because this is called in + /// release-mode, or on a stripped binary. + /// + /// # TODOs + /// + /// * Support external System.map files which list symbols and contain + /// debugging information. + pub unsafe fn from_hdr_ptr(eh_frame_hdr: *const u8) -> Self { + let mut base_addrs = BaseAddresses::default(); + // We add the `.eh_frame_hdr` pointer to the set of base addresses which + // are used by Gimli for later parsing. This may be used to compute a + // pointer to `.eh_frame`. + base_addrs = base_addrs.set_eh_frame_hdr(eh_frame_hdr as u64); + + // Leaking the Box gives us a reference with `'static` lifetime to use + // in Self. + let hdr = Box::leak(Box::new( + // We need to construct a slice as input for `EhFrameHdr::new`. + // This is sound if data pointer and length are known to be + // correct. + EhFrameHdr::new( + unsafe { + core::slice::from_raw_parts( + eh_frame_hdr, + Self::eh_frame_hdr_size(), + ) + }, + LittleEndian, + ) // Parse the header using the base address we provided (virtual + // memory). Address size is how many bytes make an + // address (64 bits). + .parse(&base_addrs, 8) + .expect( + "Could not parse `.eh_frame_hdr`. The ELF must be malformed.", + ), + )); + + // Create a pointer to the `.eh_frame` ready to parse it. + let eh_frame = match hdr.eh_frame_ptr() { + gimli::Pointer::Direct(addr) => addr as *mut u8, + _ => unimplemented!(), + }; + + // Add the `.eh_frame` address for addresses relative to this section. + base_addrs = base_addrs.set_eh_frame(eh_frame as u64); + + // Finally parse the `.eh_frame` section of our ELF. + let eh_frame = EhFrame::new( + unsafe { + core::slice::from_raw_parts(eh_frame, Self::eh_frame_size()) + }, + LittleEndian, + ); + + Self { + base_addrs, + hdr, + hdr_table: hdr.table().expect( + "The CFI binary search table was not present in this binary, oh dear.", + ), + eh_frame, + } + } +} diff --git a/kernel/src/std/unwind/mod.rs b/kernel/src/std/unwind/mod.rs new file mode 100644 index 0000000..99eb251 --- /dev/null +++ b/kernel/src/std/unwind/mod.rs @@ -0,0 +1 @@ +pub mod eh_info; diff --git a/kernel/src/util/editor.rs b/kernel/src/util/editor.rs index 594d2a8..abb21c1 100644 --- a/kernel/src/util/editor.rs +++ b/kernel/src/util/editor.rs @@ -1,15 +1,14 @@ -use crate::serial_print; use crate::arch::x86_64::drivers::keyboard::{KeyStroke, get_keystroke_async}; use crate::resources::font::Font; -use crate::std::application::frame::Frame; -use crate::std::application::render::RenderError; -use crate::std::application::window::Window; -use crate::std::application::{Application, Error}; +use crate::serial_print; +use crate::serial_println; +use crate::std::application::{ + Application, Error, frame::Frame, render::RenderError, window::Window, +}; use crate::std::ascii::Writer; use crate::std::maths::geometry::Vec2; use alloc::string::{String, ToString}; use alloc::vec::Vec; -use crate::serial_println; pub struct Editor { cursor_line: usize, @@ -42,7 +41,8 @@ impl<'a> Editor { fn render(&'a self) -> Result, RenderError> { let mut frame = Frame::new(&self.window); - let writer = Writer::new(Font::default()); + let font = Font::default(); + let writer = Writer::new(&font); let (width, height) = writer.font_size().into(); @@ -65,7 +65,10 @@ impl<'a> Editor { writer.render_glyph( &mut frame, - Vec2::new(col * width + Self::PADDING, line * height + Self::PADDING), + Vec2::new( + col * width + Self::PADDING, + line * height + Self::PADDING, + ), ch as u8, scale, )?; @@ -124,7 +127,8 @@ impl<'a> Editor { fn get_char_idx(&self) -> usize { let frame = Frame::new(&self.window); - let writer = Writer::new(Font::default()); + let font = Font::default(); + let writer = Writer::new(&font); let (width, _height) = writer.font_size().into(); let mut col = 0; @@ -157,7 +161,10 @@ impl<'a> Editor { impl Application for Editor { type Output = (); - async fn run(&mut self, _args: Vec) -> Result { + async fn run( + &mut self, + _args: Vec, + ) -> Result { self.window.set_dimensions(Vec2::new(1280, 800)); self.window.set_position(Vec2::new(0, 0)); self.window.open(); @@ -167,7 +174,9 @@ impl Application for Editor { loop { if let Err(_err) = self.render().and_then(|frame| frame.render()) { // TODO: Handle error - return Err(Error::ApplicationFailed("Rendering failed".to_string())); + return Err(Error::ApplicationFailed( + "Rendering failed".to_string(), + )); } let keystroke = get_keystroke_async().await; diff --git a/libm/src/lib.rs b/libm/src/lib.rs index 7480206..bf776c0 100644 --- a/libm/src/lib.rs +++ b/libm/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] #![feature(proc_macro_span)] #![warn( clippy::correctness, @@ -10,9 +11,6 @@ rustdoc::missing_panics_doc )] -use std::fs::File; -use std::io::{Read, Seek, SeekFrom}; - use proc_macro::{Span, TokenStream}; use quote::quote; use std::path::PathBuf; @@ -36,7 +34,8 @@ pub fn include_font(item: TokenStream) -> TokenStream { let source_filepath: PathBuf = source_file.path(); let file_path = format!( "{}/{}", - source_filepath.parent().unwrap_or_else(|| panic!("Expected to find the calling source file in a folder like src! Got: {}", source_filepath.display())).display(), + source_filepath.parent() + .unwrap_or_else(|| panic!("Expected to find the calling source file in a folder like src! Got: {}", source_filepath.display())).display(), filename.value() ); @@ -80,7 +79,12 @@ impl FontBuilder { fn revision(data: &[u8]) -> u8 { if (data[0] as u16) << 8 | data[1] as u16 == Self::PSF1_MAGIC { 1 - } else if (data[0] as u32) << 24 | (data[1] as u32) << 16 | (data[2] as u32) << 8 | data[3] as u32 == Self::PSF2_MAGIC { + } else if (data[0] as u32) << 24 + | (data[1] as u32) << 16 + | (data[2] as u32) << 8 + | data[3] as u32 + == Self::PSF2_MAGIC + { 2 } else { 0 @@ -119,7 +123,7 @@ impl FontBuilder { }) } - fn parse_psf2(data: &[u8]) -> Result { + const fn parse_psf2(_data: &[u8]) -> Result { Err("PSF2 support is not implemented yet!") } } diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..f661675 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,4 @@ +wrap_comments = true +max_width = 80 +comment_width = 80 +format_code_in_doc_comments = true