From 87f0156c7ebceca2230fa2d3c3e15fbb0f4c4136 Mon Sep 17 00:00:00 2001 From: mtgmonkey Date: Fri, 28 Mar 2025 21:37:24 -0400 Subject: [PATCH] uber simple memory stuff --- .cargo/config.toml | 2 +- src/allocator.rs | 26 +++++++++++++++++ src/lib.rs | 15 ++++++++-- src/main.rs | 35 +++++++++++++++++++++-- src/memory.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 src/allocator.rs create mode 100644 src/memory.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 0a504cf..105c918 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -5,5 +5,5 @@ target = "x86_64-rustos.json" # target OS specifications runner = "bootimage runner" # run with QEMU [unstable] -build-std = ["core", "compiler_builtins"] +build-std = ["core", "compiler_builtins", "alloc"] build-std-features = ["compiler-builtins-mem"] diff --git a/src/allocator.rs b/src/allocator.rs new file mode 100644 index 0000000..4c8b9d1 --- /dev/null +++ b/src/allocator.rs @@ -0,0 +1,26 @@ +use alloc::alloc::{GlobalAlloc, Layout}; +use core::ptr::null_mut; + +// struct Dummy ::: +pub struct Dummy; + +unsafe impl GlobalAlloc for Dummy { + // fn alloc ::: + // &self :param: + // _layout: Layout :param: + unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { + null_mut() + } + + // fn dealloc ::: + // &self :param: + // _ptr: *mut u8 :param: + // _layout: Layout :param: + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { + panic!("allocator::dealloc() should never be called") + } +} + +// ALLOCATOR: Dummy ::: +#[global_allocator] +static ALLOCATOR: Dummy = Dummy; diff --git a/src/lib.rs b/src/lib.rs index 9f018ad..d0b5eac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,13 +5,22 @@ #![test_runner(test_runner)] #![reexport_test_harness_main = "test_main"] +extern crate alloc; + +pub mod allocator; pub mod gdt; pub mod interrupts; +pub mod memory; pub mod serial; pub mod vga_buffer; +#[cfg(test)] +use bootloader::{entry_point, BootInfo}; use core::panic::PanicInfo; +#[cfg(test)] +entry_point!(test_kernel_main); + // trait Testable ::: defines run() for all test functions pub trait Testable { fn run(&self) -> (); @@ -38,10 +47,10 @@ pub enum QemuExitCode { Failed = 0x11, } -// fn _start ::: runs tests +// fn test_kernel_main ::: +// _boot_info: &'static BootInfo :param: #[cfg(test)] -#[unsafe(no_mangle)] -pub extern "C" fn _start() -> ! { +fn test_kernel_main(_boot_info: &'static BootInfo) -> ! { init(); test_main(); hlt_loop(); diff --git a/src/main.rs b/src/main.rs index f23f266..c92d851 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,15 +4,44 @@ #![test_runner(rustos::test_runner)] #![reexport_test_harness_main = "test_main"] +use bootloader::{entry_point, BootInfo}; use core::panic::PanicInfo; use rustos::println; -// fn _start ::: called on start -#[unsafe(no_mangle)] // SAFETY: make sure no other global fn _start exists -pub extern "C" fn _start() -> ! { +// define entry point for bootloader +entry_point!(kernel_main); + +// fn kernel_main ::: +// boot_info: &'static BootInfo :param: +fn kernel_main(boot_info: &'static BootInfo) -> ! { + use rustos::memory; + use x86_64::structures::paging::Translate; + use x86_64::VirtAddr; + println!("Hello World{}", "!"); rustos::init(); // initializes kernel + let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset); + + let mapper = unsafe { memory::init(phys_mem_offset) }; + + let addresses = [ + // identity-mapped vga buffer + 0xb8000, + // some code page + 0x201008, + // some stack page + 0x0100_0020_1a10, + // VirtAddr mapped to PhysAddr 0 + boot_info.physical_memory_offset, + ]; + + for &address in &addresses { + let virt = VirtAddr::new(address); + let phys = mapper.translate_addr(virt); + println!("{:?} -> {:?}", virt, phys); + } + #[cfg(test)] test_main(); diff --git a/src/memory.rs b/src/memory.rs new file mode 100644 index 0000000..abecfdd --- /dev/null +++ b/src/memory.rs @@ -0,0 +1,71 @@ +use x86_64::structures::paging::{OffsetPageTable, PageTable}; +use x86_64::{PhysAddr, VirtAddr}; + +// fn active_level_4_table ::: +// physical_memory_offset: VirtAddr :param: +// : &'static mut PageTable :ret: +// TODO add SAFETY block and descriptions +unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable { + use x86_64::registers::control::Cr3; + + let (level_4_table_frame, _) = Cr3::read(); + + let phys = level_4_table_frame.start_address(); + let virt = physical_memory_offset + phys.as_u64(); + let page_table_ptr: *mut PageTable = virt.as_mut_ptr(); + + unsafe { &mut *page_table_ptr } +} + +// fn init ::: +// physical_memory_offet: VirtAddr :param: +// : OffsetPageTable<'static> :ret: +// TODO add SAFETY block and descriptions +pub unsafe fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> { + unsafe { + let level_4_table = active_level_4_table(physical_memory_offset); + OffsetPageTable::new(level_4_table, physical_memory_offset) + } +} + +// fn translate_addr ::: wrapper for translate_addr_inner; see translate_addr_inner +// addr: VirtAddr :param: +// physical_memory_offset: VirtAddr :param: +// SAFETY ensure complete physical memory is mapped at physical_memory_offset +pub unsafe fn translate_addr(addr: VirtAddr, physical_memory_offset: VirtAddr) -> Option { + translate_addr_inner(addr, physical_memory_offset) +} + +// fn translate_addr_inner ::: finds PhysAddr, if it exists, given a VirtAddr +// addr: VirtAddr :param: +// physical_memory_offset: VirtAddr :param: +// SAFETY ensure complete physical memory is mapped at physical_memory_offset +fn translate_addr_inner(addr: VirtAddr, physical_memory_offset: VirtAddr) -> Option { + use x86_64::registers::control::Cr3; + use x86_64::structures::paging::page_table::FrameError; + + let (level_4_table_frame, _) = Cr3::read(); + + let table_indexes = [ + addr.p4_index(), + addr.p3_index(), + addr.p2_index(), + addr.p1_index(), + ]; + let mut frame = level_4_table_frame; + + for &index in &table_indexes { + let virt = physical_memory_offset + frame.start_address().as_u64(); + let table_ptr: *const PageTable = virt.as_ptr(); + let table = unsafe { &*table_ptr }; + + let entry = &table[index]; + frame = match entry.frame() { + Ok(frame) => frame, + Err(FrameError::FrameNotPresent) => return None, + Err(FrameError::HugeFrame) => panic!("huge panes not supported"), + }; + } + + Some(frame.start_address() + u64::from(addr.page_offset())) +}