Merging with origin/unified

This commit is contained in:
2025-03-05 21:04:58 +00:00
38 changed files with 674 additions and 154 deletions
+2 -1
View File
@@ -5,5 +5,6 @@
"editor.defaultFormatter": "rust-lang.rust-analyzer", "editor.defaultFormatter": "rust-lang.rust-analyzer",
"editor.formatOnSave": true "editor.formatOnSave": true
}, },
"rust-analyzer.check.command": "clippy" "rust-analyzer.check.command": "clippy",
"rust-analyzer.cargo.buildScripts.enable": true
} }
Generated
+14
View File
@@ -99,6 +99,12 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "elf"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@@ -111,7 +117,9 @@ version = "0.1.0"
dependencies = [ dependencies = [
"cc", "cc",
"crossbeam", "crossbeam",
"elf",
"futures-util", "futures-util",
"gimli",
"libm", "libm",
"limine", "limine",
"linked_list_allocator", "linked_list_allocator",
@@ -145,6 +153,12 @@ dependencies = [
"pin-utils", "pin-utils",
] ]
[[package]]
name = "gimli"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]] [[package]]
name = "ident_case" name = "ident_case"
version = "1.0.1" version = "1.0.1"
+2
View File
@@ -19,6 +19,8 @@ futures-util = { version = "0.3.31", default-features = false, features = [
"alloc", "alloc",
] } ] }
linked_list_allocator = { version = "0.10.5", features = ["use_spin"] } 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] [build-dependencies]
cc = "1.2.14" cc = "1.2.14"
+1 -2
View File
@@ -62,9 +62,8 @@ SECTIONS
*(COMMON) *(COMMON)
} :data } :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/ : { /DISCARD/ : {
*(.eh_frame*)
*(.note .note.*) *(.note .note.*)
} }
} }
+2
View File
@@ -1,3 +1,5 @@
#![expect(unused)]
use core::arch::x86_64::__cpuid; use core::arch::x86_64::__cpuid;
use crate::arch::x86_64::memory::mapping::PHYSICAL_MEMORY_OFFSET; use crate::arch::x86_64::memory::mapping::PHYSICAL_MEMORY_OFFSET;
+1
View File
@@ -1,3 +1,4 @@
#![expect(unused)]
use core::arch::x86_64::__cpuid; use core::arch::x86_64::__cpuid;
use spin::Lazy; use spin::Lazy;
use x86_64::registers::model_specific::Msr; use x86_64::registers::model_specific::Msr;
+2
View File
@@ -1,3 +1,5 @@
#![allow(clippy::missing_safety_doc)]
use x86_64::instructions::port::Port; use x86_64::instructions::port::Port;
const CMD_INIT: u8 = 0x11; const CMD_INIT: u8 = 0x11;
+24 -11
View File
@@ -2,14 +2,17 @@ use core::fmt;
use spin::{Lazy, Mutex}; use spin::{Lazy, Mutex};
use x86_64::instructions::interrupts; 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}; use crate::resources::font::{FONT_SPLEEN_8X16, Font};
static FONT_WIDTH: u32 = 8; static FONT_WIDTH: u32 = 8;
static FONT_HEIGHT: u32 = 16; static FONT_HEIGHT: u32 = 16;
pub static WRITER: Lazy<Mutex<Writer>> = Lazy::new(|| Mutex::new(Writer::new())); pub static WRITER: Lazy<Mutex<Writer>> =
Lazy::new(|| Mutex::new(Writer::new()));
pub fn screensize_chars() -> (u32, u32) { pub fn screensize_chars() -> (u32, u32) {
let writer = WRITER.lock(); let writer = WRITER.lock();
@@ -71,21 +74,31 @@ impl Writer {
return; 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); let data: &[u8] = self.font.glyph_for(c as u16);
if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() {
for (row, line) in data.iter().enumerate().take(16) { for (row, line) in data.iter().enumerate().take(16) {
for col in 0..8 { for col in 0..8 {
let pixel_x: u32 = self.text_col * FONT_WIDTH + col; 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 { if line & (0x80 >> col) != 0 {
// Write the foreground color // 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 { } else {
// Write the background color // 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 /// Handles the backspace character. TODO: Implement VT-100 style terminal
/// codes alongside a shell. Not simple. /// control codes alongside a shell. Not simple.
pub fn backspace(&mut self) { pub fn backspace(&mut self) {
if self.text_col > 0 { if self.text_col > 0 {
self.text_col -= 1; self.text_col -= 1;
@@ -224,12 +237,12 @@ macro_rules! print {
} }
#[macro_export] #[macro_export]
macro_rules! printlnerr { macro_rules! eprintln {
() => ($crate::printerr!("\n")); () => ($crate::printerr!("\n"));
($($arg:tt)*) => ($crate::printerr!("{}\n", format_args!($($arg)*))); ($($arg:tt)*) => ($crate::eprint!("{}\n", format_args!($($arg)*)));
} }
#[macro_export] #[macro_export]
macro_rules! printerr { macro_rules! eprint {
($($arg:tt)*) => ($crate::prelude::_print_err(format_args!($($arg)*))); ($($arg:tt)*) => ($crate::prelude::_print_err(format_args!($($arg)*)));
} }
@@ -19,9 +19,14 @@ impl From<Colour> for u32 {
fn from(val: Colour) -> Self { fn from(val: Colour) -> Self {
match val { match val {
Colour::ARGB(a, r, g, b) => { 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::HexARGB(hex) => hex,
Colour::Black => 0xFF000000, Colour::Black => 0xFF000000,
Colour::Blue => 0xFF0000FF, Colour::Blue => 0xFF0000FF,
@@ -38,7 +43,9 @@ impl From<Colour> for u32 {
impl core::fmt::Display for Colour { impl core::fmt::Display for Colour {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self { 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::RGB(r, g, b) => write!(f, "RGB(#{:x}{:x}{:x})", r, g, b),
Self::HexARGB(hex) => write!(f, "Hex(#{:x})", hex), Self::HexARGB(hex) => write!(f, "Hex(#{:x})", hex),
Self::Black => write!(f, "Black"), Self::Black => write!(f, "Black"),
@@ -10,17 +10,19 @@ use core::panic;
use limine::framebuffer::Framebuffer; use limine::framebuffer::Framebuffer;
use spin::{Lazy, Mutex}; use spin::{Lazy, Mutex};
pub static FRAMEBUFFER_WRITER: Lazy<Mutex<Option<FramebufferWriter>>> = Lazy::new(|| { pub static FRAMEBUFFER_WRITER: Lazy<Mutex<Option<FramebufferWriter>>> =
Mutex::new(FRAMEBUFFER_REQUEST.get_response().map_or_else( Lazy::new(|| {
|| { Mutex::new(FRAMEBUFFER_REQUEST.get_response().map_or_else(
panic!("Framebuffer request failed"); || {
}, panic!("Framebuffer request failed");
|framebuffer_response| { },
let framebuffer = framebuffer_response.framebuffers().next().unwrap(); |framebuffer_response| {
Some(FramebufferWriter::new(framebuffer)) let framebuffer =
}, framebuffer_response.framebuffers().next().unwrap();
)) Some(FramebufferWriter::new(framebuffer))
}); },
))
});
/// The updated writer stores necessary fields from the [Framebuffer]. /// The updated writer stores necessary fields from the [Framebuffer].
/// This ensures that the contained types are Send, as Framebuffer was /// This ensures that the contained types are Send, as Framebuffer was
@@ -28,7 +30,8 @@ pub static FRAMEBUFFER_WRITER: Lazy<Mutex<Option<FramebufferWriter>>> = Lazy::ne
/// ///
/// It also avoids the requirement for lifetimes. /// 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 { pub struct FramebufferWriter {
pitch: u64, pitch: u64,
bpp: u16, bpp: u16,
+17 -10
View File
@@ -6,20 +6,24 @@ use core::{
use crate::println; use crate::println;
use crossbeam::queue::ArrayQueue; use crossbeam::queue::ArrayQueue;
use futures_util::{Stream, StreamExt, task::AtomicWaker}; 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}; use spin::{Lazy, Mutex, Once};
static KBD_QUEUE: Once<ArrayQueue<u8>> = Once::new(); static KBD_QUEUE: Once<ArrayQueue<u8>> = Once::new();
static WAKER: AtomicWaker = AtomicWaker::new(); static WAKER: AtomicWaker = AtomicWaker::new();
pub static KEYBOARD: Lazy<Mutex<Keyboard<Uk105Key, ScancodeSet1>>> = Lazy::new(|| { pub static KEYBOARD: Lazy<Mutex<Keyboard<Uk105Key, ScancodeSet1>>> =
Mutex::new(Keyboard::new( Lazy::new(|| {
ScancodeSet1::new(), Mutex::new(Keyboard::new(
// TODO: Expose an API to change the default KB layout. ScancodeSet1::new(),
Uk105Key, // TODO: Expose an API to change the default KB layout.
HandleControl::Ignore, Uk105Key,
)) HandleControl::Ignore,
}); ))
});
pub static SCANCODE_STREAM: Lazy<Mutex<ScancodeStream>> = pub static SCANCODE_STREAM: Lazy<Mutex<ScancodeStream>> =
Lazy::new(|| Mutex::new(ScancodeStream::new())); Lazy::new(|| Mutex::new(ScancodeStream::new()));
@@ -59,7 +63,10 @@ impl Default for ScancodeStream {
impl Stream for ScancodeStream { impl Stream for ScancodeStream {
type Item = u8; type Item = u8;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
let queue = KBD_QUEUE.get().unwrap(); let queue = KBD_QUEUE.get().unwrap();
if let Some(scancode) = queue.pop() { if let Some(scancode) = queue.pop() {
+2 -1
View File
@@ -138,7 +138,8 @@ extern "x86-interrupt" fn page_fault_handler(
let frame = f.allocate_frame().unwrap(); let frame = f.allocate_frame().unwrap();
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
let page: Page<Size4KiB> = Page::containing_address(Cr2::read().unwrap()); let page: Page<Size4KiB> =
Page::containing_address(Cr2::read().unwrap());
unsafe { unsafe {
let mut mapper = OFFSET_PAGE_TABLE.get().unwrap().lock(); let mut mapper = OFFSET_PAGE_TABLE.get().unwrap().lock();
@@ -1,3 +1,3 @@
pub mod heap_alloc; pub mod heap_alloc;
pub mod stack_alloc;
pub(crate) mod page_alloc; pub(crate) mod page_alloc;
pub mod stack_alloc;
@@ -14,14 +14,17 @@ pub struct FoundryOSFrameAllocator {
impl FoundryOSFrameAllocator { impl FoundryOSFrameAllocator {
/// Creates a new `FoundryOSFrameAllocator` from a memory map. /// Creates a new `FoundryOSFrameAllocator` from a memory map.
/// ///
/// This function takes a reference to a `MemoryMapResponse` and initializes a /// This function takes a reference to a `MemoryMapResponse` and initializes
/// `FoundryOSFrameAllocator` with it. The `next` field is set to 0, indicating that /// a `FoundryOSFrameAllocator` with it. The `next` field is set to 0,
/// the first frame to be allocated is the first frame in the memory map. /// indicating that the first frame to be allocated is the first frame
/// in the memory map.
pub fn init(memory_map: &'static MemoryMapResponse) { pub fn init(memory_map: &'static MemoryMapResponse) {
FRAME_ALLOCATOR.call_once(|| Mutex::new(Self { FRAME_ALLOCATOR.call_once(|| {
memory_map, Mutex::new(Self {
next: 0, memory_map,
})); next: 0,
})
});
} }
pub fn count_usable_frames(&self) -> u64 { pub fn count_usable_frames(&self) -> u64 {
@@ -70,9 +73,9 @@ impl FoundryOSFrameAllocator {
unsafe impl FrameAllocator<Size4KiB> for FoundryOSFrameAllocator { unsafe impl FrameAllocator<Size4KiB> for FoundryOSFrameAllocator {
/// Allocates a frame from the list of usable frames. /// Allocates a frame from the list of usable frames.
/// ///
/// This function returns the next available `PhysFrame` from the memory map, /// This function returns the next available `PhysFrame` from the memory
/// if one exists. Once a frame is allocated, the internal counter is incremented /// map, if one exists. Once a frame is allocated, the internal counter
/// to point to the next frame for future allocations. /// is incremented to point to the next frame for future allocations.
/// ///
/// # Returns /// # Returns
/// ///
@@ -80,9 +83,6 @@ unsafe impl FrameAllocator<Size4KiB> for FoundryOSFrameAllocator {
/// - `None`: If there are no more usable frames to allocate. /// - `None`: If there are no more usable frames to allocate.
fn allocate_frame(&mut self) -> Option<PhysFrame> { fn allocate_frame(&mut self) -> Option<PhysFrame> {
let frame = self.usable_frames().nth(self.next); let frame = self.usable_frames().nth(self.next);
if frame.is_none() {
panic!("this shouldnt happen!");
}
self.next += 1; self.next += 1;
frame frame
} }
@@ -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 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 { fn reserve_stack_memory(size_in_pages: u64) -> Page {
use core::sync::atomic::{AtomicU64, Ordering}; use core::sync::atomic::{AtomicU64, Ordering};
static STACK_ALLOC_NEXT: AtomicU64 = AtomicU64::new(STACK_VIRTUAL_SPACE as u64); static STACK_ALLOC_NEXT: AtomicU64 =
let start_addr = VirtAddr::new(STACK_ALLOC_NEXT.fetch_add( AtomicU64::new(STACK_VIRTUAL_SPACE as u64);
size_in_pages * Page::<Size4KiB>::SIZE, let start_addr =
Ordering::Relaxed, VirtAddr::new(STACK_ALLOC_NEXT.fetch_add(
)); size_in_pages * Page::<Size4KiB>::SIZE,
Ordering::Relaxed,
));
Page::from_start_address(start_addr) Page::from_start_address(start_addr)
.expect("`STACK_ALLOC_NEXT` not page aligned") .expect("`STACK_ALLOC_NEXT` not page aligned")
} }
/// Allocates a stack in the virtual address space, mapped to physical pages. /// 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. /// This function allocates a stack in the virtual address space, mapped to
/// The stack is allocated as a sequence of pages, with the first page allocated as a guard page. /// physical pages. The stack is allocated as a sequence of pages, with the
/// The stack is then mapped to the allocated physical frame. /// 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 /// The function takes the size of the stack in pages, a mutable reference to a
/// mutable reference to a frame allocator. It returns a `Result` containing a `StackBounds` /// mapper, and a mutable reference to a frame allocator. It returns a `Result`
/// struct, which contains the start and end virtual addresses of the allocated stack. /// containing a `StackBounds` struct, which contains the start and end virtual
/// addresses of the allocated stack.
/// ///
/// # Safety /// # Safety
/// ///
/// This function is unsafe because it maps physical frames to virtual addresses without any /// This function is unsafe because it maps physical frames to virtual addresses
/// protection. This can lead to bugs if the physical frames are not correctly allocated, or if the /// without any protection. This can lead to bugs if the physical frames are not
/// virtual addresses are not correctly aligned. /// correctly allocated, or if the virtual addresses are not correctly aligned.
/// ///
/// # Panics /// # Panics
/// ///
@@ -36,27 +42,28 @@ pub unsafe fn alloc_stack(
size_in_pages: u64, size_in_pages: u64,
mapper: &mut impl Mapper<Size4KiB>, mapper: &mut impl Mapper<Size4KiB>,
frame_allocator: &mut impl FrameAllocator<Size4KiB>, frame_allocator: &mut impl FrameAllocator<Size4KiB>,
) -> Result<StackBounds, mapper::MapToError<Size4KiB>> { unsafe { ) -> Result<StackBounds, mapper::MapToError<Size4KiB>> {
use x86_64::structures::paging::PageTableFlags as Flags; 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;
for page in Page::range(stack_start, stack_end) { let guard_page = reserve_stack_memory(size_in_pages + 1);
let frame = frame_allocator let stack_start = guard_page + 1;
.allocate_frame() let stack_end = stack_start + size_in_pages;
.ok_or(mapper::MapToError::FrameAllocationFailed)?;
let flags = Flags::PRESENT | Flags::WRITABLE; for page in Page::range(stack_start, stack_end) {
mapper.map_to(page, frame, flags, frame_allocator)?.flush(); 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)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct StackBounds { pub struct StackBounds {
@@ -76,4 +83,4 @@ impl StackBounds {
pub const fn end(&self) -> VirtAddr { pub const fn end(&self) -> VirtAddr {
self.end self.end
} }
} }
+2 -1
View File
@@ -16,7 +16,8 @@ static HIGHER_HALF_DIRECT_MAP_REQUEST: HhdmRequest = HhdmRequest::new();
#[used] #[used]
#[unsafe(link_section = ".requests")] #[unsafe(link_section = ".requests")]
static KERNEL_ADDRESS_REQUEST: KernelAddressRequest = KernelAddressRequest::new(); pub static KERNEL_ADDRESS_REQUEST: KernelAddressRequest =
KernelAddressRequest::new();
/// ```rs /// ```rs
/// let virt_addr = phys_addr + offset; /// let virt_addr = phys_addr + offset;
+11 -10
View File
@@ -2,20 +2,19 @@ pub mod allocation;
pub mod mapping; pub mod mapping;
pub mod units; 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 allocation::page_alloc::FoundryOSFrameAllocator;
use spin::{Mutex, Once};
use units::MemoryUnits::*; 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 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_VIRTUAL_SPACE: usize = 0x4444_4444_0000; // start address of heap allocated memory
pub const HEAP_SIZE: usize = MiB(1).to_bytes(); pub const HEAP_SIZE: usize = MiB(1).to_bytes();
pub static FRAME_ALLOCATOR: Once<Mutex<FoundryOSFrameAllocator>> = Once::new(); pub static FRAME_ALLOCATOR: Once<Mutex<FoundryOSFrameAllocator>> = Once::new();
pub static OFFSET_PAGE_TABLE: Once<Mutex<OffsetPageTable>> = Once::new(); pub static OFFSET_PAGE_TABLE: Once<Mutex<OffsetPageTable>> = Once::new();
/// Returns a mutable reference to the current level 4 page table. /// Returns a mutable reference to the current level 4 page table.
@@ -25,7 +24,9 @@ pub static OFFSET_PAGE_TABLE: Once<Mutex<OffsetPageTable>> = Once::new();
/// The caller must ensure that the level 4 page table is not modified /// The caller must ensure that the level 4 page table is not modified
/// simultaneously. The caller must also ensure that the physical memory offset /// simultaneously. The caller must also ensure that the physical memory offset
/// is correct, to ensure that the correct virtual address is constructed. /// 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 (level_4_frame, _) = Cr3::read();
let phys_addr = level_4_frame.start_address(); 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) { pub fn init_page_table(physical_memory_offset: VirtAddr) {
unsafe { unsafe {
let l4_table = active_l4_table(physical_memory_offset); 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)); OFFSET_PAGE_TABLE.call_once(|| Mutex::new(offset_table));
} }
} }
+2 -2
View File
@@ -30,7 +30,7 @@ impl MemoryUnits {
pub const fn convert(&mut self) { pub const fn convert(&mut self) {
match self { match self {
Self::B(b) if *b > 1024 => *self = Self::KiB(*b / 1024), 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), 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), Self::GiB(gib) => write!(f, "{} GiB", gib),
} }
} }
} }
@@ -2,7 +2,6 @@
//! //!
//! Written by @zxq5 for the most part with code from //! Written by @zxq5 for the most part with code from
//! [here](https://github.com/phil-opp/blog_os/). //! [here](https://github.com/phil-opp/blog_os/).
//!
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::collections::BTreeMap; use alloc::collections::BTreeMap;
@@ -81,9 +80,9 @@ impl Executor {
Some(task) => task, Some(task) => task,
None => continue, // task no longer exists None => continue, // task no longer exists
}; };
let waker = waker_cache let waker = waker_cache.entry(task_id).or_insert_with(|| {
.entry(task_id) TaskWaker::new_waker(task_id, task_queue.clone())
.or_insert_with(|| TaskWaker::new_waker(task_id, task_queue.clone())); });
let mut context = Context::from_waker(waker); let mut context = Context::from_waker(waker);
match task.poll(&mut context) { match task.poll(&mut context) {
Poll::Ready(()) => { Poll::Ready(()) => {
@@ -129,7 +128,10 @@ impl TaskWaker {
self.task_queue.push(self.task_id).expect("task_queue full"); self.task_queue.push(self.task_id).expect("task_queue full");
} }
fn new_waker(task_id: TaskId, task_queue: Arc<ArrayQueue<TaskId>>) -> Waker { fn new_waker(
task_id: TaskId,
task_queue: Arc<ArrayQueue<TaskId>>,
) -> Waker {
Waker::from(Arc::new(Self { Waker::from(Arc::new(Self {
task_id, task_id,
task_queue, task_queue,
+2 -1
View File
@@ -1,3 +1,4 @@
#![expect(unused)]
pub mod async_io; pub mod async_io;
pub mod threading;
mod taskrunner; mod taskrunner;
pub mod threading;
@@ -6,7 +6,7 @@ pub struct Task {
} }
impl Task { impl Task {
pub fn new() {} // pub const fn new() {}
pub fn run() {} pub const fn run() {}
} }
@@ -1,5 +1,5 @@
use x86_64::VirtAddr;
use crate::arch::x86_64::memory::allocation::stack_alloc::StackBounds; use crate::arch::x86_64::memory::allocation::stack_alloc::StackBounds;
use x86_64::VirtAddr;
mod switch; mod switch;
@@ -10,8 +10,6 @@ pub struct Thread {
stack_bounds: Option<StackBounds>, stack_bounds: Option<StackBounds>,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct ThreadId(u64); pub struct ThreadId(u64);
+23 -11
View File
@@ -12,42 +12,43 @@
)] )]
extern crate alloc; extern crate alloc;
use crate::{ use crate::{arch::x86_64::memory::init_page_table, prelude::*};
arch::x86_64::memory::init_page_table,
prelude::*,
};
use arch::x86_64::memory::allocation::heap_alloc::init_heap; use arch::x86_64::memory::allocation::heap_alloc::init_heap;
use arch::x86_64::memory::mapping; use arch::x86_64::memory::mapping;
use core::arch::asm; use core::arch::asm;
use limine::BaseRevision; use limine::BaseRevision;
use std::unwind;
use std::unwind::eh_info::ELF;
use x86_64::VirtAddr; use x86_64::VirtAddr;
use arch::x86_64::memory::allocation::page_alloc::FoundryOSFrameAllocator; use arch::x86_64::memory::allocation::page_alloc::FoundryOSFrameAllocator;
use crate::arch::x86_64::cpu::apic::enable_apic; use crate::arch::x86_64::cpu::apic::enable_apic;
use crate::arch::x86_64::drivers::ascii::screensize_chars; use crate::arch::x86_64::drivers::ascii::screensize_chars;
use crate::arch::x86_64::drivers::framebuffer::display::screensize_px; 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::FRAME_ALLOCATOR;
use crate::arch::x86_64::memory::units::MemoryUnits; use crate::arch::x86_64::memory::units::MemoryUnits;
pub mod arch; pub mod arch;
mod panic;
pub mod resources; pub mod resources;
#[allow(unused)] // We aren't using much of this right now. #[allow(unused)] // We aren't using much of this right now.
pub mod std; pub mod std;
pub mod util; pub mod util;
pub mod prelude { pub mod prelude {
pub use crate::std::io::{_print, _print_log, _serial_write};
pub use crate::std::debug::_debug;
pub use crate::{ 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. /// Sets the base revision to the latest revision supported by the crate.
/// See specification for further info. /// 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] #[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")] #[unsafe(link_section = ".requests")]
static BASE_REVISION: BaseRevision = BaseRevision::new(); static BASE_REVISION: BaseRevision = BaseRevision::new();
@@ -69,7 +70,7 @@ pub fn hcf() -> ! {
pub fn boot() -> Result<(), &'static str> { pub fn boot() -> Result<(), &'static str> {
if !BASE_REVISION.is_supported() { if !BASE_REVISION.is_supported() {
return Err("base revision not supported"); return Err("Base revision not supported");
} }
use arch::x86_64::{gdt, interrupts}; use arch::x86_64::{gdt, interrupts};
@@ -131,5 +132,16 @@ pub fn boot() -> Result<(), &'static str> {
x86_64::instructions::interrupts::enable(); x86_64::instructions::interrupts::enable();
debugln!("[Success]"); 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(()) Ok(())
} }
+75
View File
@@ -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<usize> = 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} - <unknown>",
// 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<dyn Any + Send>) -> ! {
// 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<M: 'static + Any + Send>(msg: M) -> ! {
// eprintln!("Panicked at {}", Location::caller());
// do_panic(Box::new(msg))
// }
+6 -4
View File
@@ -1,8 +1,8 @@
use libm::include_font; 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")); 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")); Font::new(include_font!("../../../resources/font/cp850-8x16.psf"));
// pub struct Font(pub [[u8; 16]; 512]); // pub struct Font(pub [[u8; 16]; 512]);
@@ -39,8 +39,10 @@ impl Font {
pub const fn height(&self) -> usize { pub const fn height(&self) -> usize {
self.height self.height
} }
}
pub fn default() -> &'static Self { impl Default for Font {
&FONT_CP850_8X16 fn default() -> Self {
FONT_CP850_8X16
} }
} }
+4 -1
View File
@@ -8,7 +8,10 @@ pub mod window;
pub trait Application { pub trait Application {
type Output; type Output;
fn run(&mut self, args: Vec<String>) -> impl Future<Output = Result<Self::Output, Error>> + Send; fn run(
&mut self,
args: Vec<String>,
) -> impl Future<Output = Result<Self::Output, Error>> + Send;
} }
#[derive(Debug)] #[derive(Debug)]
+15 -4
View File
@@ -11,20 +11,31 @@ pub struct Frame<'f> {
impl<'a> Frame<'a> { impl<'a> Frame<'a> {
pub fn new(window: &'a Window) -> Self { pub fn new(window: &'a Window) -> Self {
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, window,
} }
} }
pub fn render(&self) -> Result<(), RenderError> { pub fn render(&self) -> Result<(), RenderError> {
let data: Vec<&[Colour]> = self.data.iter().map(|v| v.as_slice()).collect::<Vec<_>>(); let data: Vec<&[Colour]> =
self.data.iter().map(|v| v.as_slice()).collect::<Vec<_>>();
self.window self.window
.render(data.as_slice()) .render(data.as_slice())
.map_err(|_| RenderError::Generic) .map_err(|_| RenderError::Generic)
} }
pub fn write_pixel(&mut self, x: usize, y: usize, color: Colour) -> Result<(), RenderError> { pub fn write_pixel(
if x >= self.window.dimensions().x() || y >= self.window.dimensions().y() { &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); return Err(RenderError::Generic);
} }
self.data[y][x] = color; self.data[y][x] = color;
+2 -1
View File
@@ -24,7 +24,8 @@ impl Window {
} }
pub fn render(&self, _data: &[&[Colour]]) -> Result<(), RenderError> { 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() { if let Some(fb) = FRAMEBUFFER_WRITER.lock().as_mut() {
fb.render_frame(_data); fb.render_frame(_data);
} }
+5 -1
View File
@@ -46,7 +46,11 @@ impl<'a> Writer<'a> {
if line & (0x80 >> col) != 0 { if line & (0x80 >> col) != 0 {
for i in 0..scale { for i in 0..scale {
for j 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,
)?;
} }
} }
} }
+114
View File
@@ -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<elf::ParseError> 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<Self, ElfError> {
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<u64, ElfError> {
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<SectionHeader, ElfError> {
let section_hdr = self
.elf
.section_header_by_name(section_name)
.map_err(|_e| ElfError::SectionNotExists)?;
section_hdr.ok_or(ElfError::SectionNotExists)
}
}
+6
View File
@@ -0,0 +1,6 @@
pub use crate::arch::x86_64::drivers::{
ascii::{_print, _print_err, _print_log},
serial::_serial_write,
};
pub mod stdin;
+75
View File
@@ -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<KeyStroke> {
get_keystroke_optional()
}
+2
View File
@@ -1,5 +1,7 @@
pub mod application; pub mod application;
pub mod ascii; pub mod ascii;
pub mod elf;
pub mod io; pub mod io;
pub mod maths; pub mod maths;
pub mod unwind;
pub mod debug; pub mod debug;
+135
View File
@@ -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<EndianSlice<'static, LittleEndian>>,
/// 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<EndianSlice<'static, LittleEndian>>,
}
/// Stores the [ElfReader] struct for this ELF file.
pub static ELF: Lazy<ElfReader> =
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,
}
}
}
+1
View File
@@ -0,0 +1 @@
pub mod eh_info;
+20 -11
View File
@@ -1,15 +1,14 @@
use crate::serial_print;
use crate::arch::x86_64::drivers::keyboard::{KeyStroke, get_keystroke_async}; use crate::arch::x86_64::drivers::keyboard::{KeyStroke, get_keystroke_async};
use crate::resources::font::Font; use crate::resources::font::Font;
use crate::std::application::frame::Frame; use crate::serial_print;
use crate::std::application::render::RenderError; use crate::serial_println;
use crate::std::application::window::Window; use crate::std::application::{
use crate::std::application::{Application, Error}; Application, Error, frame::Frame, render::RenderError, window::Window,
};
use crate::std::ascii::Writer; use crate::std::ascii::Writer;
use crate::std::maths::geometry::Vec2; use crate::std::maths::geometry::Vec2;
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
use alloc::vec::Vec; use alloc::vec::Vec;
use crate::serial_println;
pub struct Editor { pub struct Editor {
cursor_line: usize, cursor_line: usize,
@@ -42,7 +41,8 @@ impl<'a> Editor {
fn render(&'a self) -> Result<Frame<'a>, RenderError> { fn render(&'a self) -> Result<Frame<'a>, RenderError> {
let mut frame = Frame::new(&self.window); 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(); let (width, height) = writer.font_size().into();
@@ -65,7 +65,10 @@ impl<'a> Editor {
writer.render_glyph( writer.render_glyph(
&mut frame, &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, ch as u8,
scale, scale,
)?; )?;
@@ -124,7 +127,8 @@ impl<'a> Editor {
fn get_char_idx(&self) -> usize { fn get_char_idx(&self) -> usize {
let frame = Frame::new(&self.window); 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 (width, _height) = writer.font_size().into();
let mut col = 0; let mut col = 0;
@@ -157,7 +161,10 @@ impl<'a> Editor {
impl Application for Editor { impl Application for Editor {
type Output = (); type Output = ();
async fn run(&mut self, _args: Vec<alloc::string::String>) -> Result<Self::Output, Error> { async fn run(
&mut self,
_args: Vec<alloc::string::String>,
) -> Result<Self::Output, Error> {
self.window.set_dimensions(Vec2::new(1280, 800)); self.window.set_dimensions(Vec2::new(1280, 800));
self.window.set_position(Vec2::new(0, 0)); self.window.set_position(Vec2::new(0, 0));
self.window.open(); self.window.open();
@@ -167,7 +174,9 @@ impl Application for Editor {
loop { loop {
if let Err(_err) = self.render().and_then(|frame| frame.render()) { if let Err(_err) = self.render().and_then(|frame| frame.render()) {
// TODO: Handle error // 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; let keystroke = get_keystroke_async().await;
+10 -6
View File
@@ -1,3 +1,4 @@
#![allow(dead_code)]
#![feature(proc_macro_span)] #![feature(proc_macro_span)]
#![warn( #![warn(
clippy::correctness, clippy::correctness,
@@ -10,9 +11,6 @@
rustdoc::missing_panics_doc rustdoc::missing_panics_doc
)] )]
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use proc_macro::{Span, TokenStream}; use proc_macro::{Span, TokenStream};
use quote::quote; use quote::quote;
use std::path::PathBuf; use std::path::PathBuf;
@@ -36,7 +34,8 @@ pub fn include_font(item: TokenStream) -> TokenStream {
let source_filepath: PathBuf = source_file.path(); let source_filepath: PathBuf = source_file.path();
let file_path = format!( 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() filename.value()
); );
@@ -80,7 +79,12 @@ impl FontBuilder {
fn revision(data: &[u8]) -> u8 { fn revision(data: &[u8]) -> u8 {
if (data[0] as u16) << 8 | data[1] as u16 == Self::PSF1_MAGIC { if (data[0] as u16) << 8 | data[1] as u16 == Self::PSF1_MAGIC {
1 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 2
} else { } else {
0 0
@@ -119,7 +123,7 @@ impl FontBuilder {
}) })
} }
fn parse_psf2(data: &[u8]) -> Result<FontData, &'static str> { const fn parse_psf2(_data: &[u8]) -> Result<FontData, &'static str> {
Err("PSF2 support is not implemented yet!") Err("PSF2 support is not implemented yet!")
} }
} }
+4
View File
@@ -0,0 +1,4 @@
wrap_comments = true
max_width = 80
comment_width = 80
format_code_in_doc_comments = true