From 3c9bbc5a3798f3c6fd947ea57bd3757fa4f0d3d5 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 24 Dec 2020 12:20:59 -0800 Subject: [PATCH 1/2] nicer abstraction for translating kernel addrs Signed-off-by: Eliza Weisman --- hal-core/src/boot.rs | 7 +++-- hal-core/src/mem/mod.rs | 10 ++++++- hal-x86_64/src/mm/mod.rs | 58 +++++++++++++++++----------------------- src/arch/x86_64.rs | 17 +++++++----- src/lib.rs | 4 +-- 5 files changed, 51 insertions(+), 45 deletions(-) diff --git a/hal-core/src/boot.rs b/hal-core/src/boot.rs index 42594545..af452256 100644 --- a/hal-core/src/boot.rs +++ b/hal-core/src/boot.rs @@ -3,11 +3,16 @@ use core::iter::Iterator; pub trait BootInfo { type MemoryMap: Iterator; + type KernelAddrs: mem::TranslateKernelAddrs + Send + Sync; type Writer: core::fmt::Write; /// Returns the boot info's memory map. fn memory_map(&self) -> Self::MemoryMap; + /// Returns a type representing a way of translating between kernel-space physical + /// and virtual addresses. + fn kernel_addrs(&self) -> &Self::KernelAddrs; + /// Returns a writer for printing early kernel diagnostics fn writer(&self) -> Self::Writer; @@ -21,8 +26,6 @@ pub trait BootInfo { None } - fn init_paging(&self); - // TODO(eliza): figure out a non-bad way to represent boot command lines (is // it reasonable to convert them to rust strs when we barely have an operating // system???) diff --git a/hal-core/src/mem/mod.rs b/hal-core/src/mem/mod.rs index e5945726..c4cd1164 100644 --- a/hal-core/src/mem/mod.rs +++ b/hal-core/src/mem/mod.rs @@ -1,7 +1,15 @@ -use crate::Address; +use crate::{Address, PAddr, VAddr}; use core::fmt; pub mod page; +/// Translates kernel-mode addresses. +pub trait TranslateKernelAddrs { + /// Translate a kernel virtual address into a physical address. + fn to_kernel_paddr(&self, vaddr: VAddr) -> PAddr; + /// Translate a kernel physical address into a virtual address. + fn to_kernel_vaddr(&self, paddr: PAddr) -> VAddr; +} + /// A cross-platform representation of a memory region. #[derive(Clone)] pub struct Region { diff --git a/hal-x86_64/src/mm/mod.rs b/hal-x86_64/src/mm/mod.rs index 99fe62a2..06258f7f 100644 --- a/hal-x86_64/src/mm/mod.rs +++ b/hal-x86_64/src/mm/mod.rs @@ -1,19 +1,17 @@ use self::size::*; use crate::{PAddr, VAddr}; -use core::{ - fmt, - marker::PhantomData, - ops, - ptr::NonNull, - sync::atomic::{AtomicUsize, Ordering}, -}; +use core::{fmt, marker::PhantomData, ops, ptr::NonNull}; use hal_core::{ - mem::page::{ - self, Map, Page, Size, StaticSize, TranslateAddr, TranslateError, TranslatePage, - TranslateResult, + mem::{ + page::{ + self, Map, Page, Size, StaticSize, TranslateAddr, TranslateError, TranslatePage, + TranslateResult, + }, + TranslateKernelAddrs, }, - Address, + Address, BootInfo, }; +use mycelium_util::sync::InitOnce; const ENTRIES: usize = 512; @@ -44,16 +42,19 @@ pub struct Entry { _level: PhantomData, } -#[tracing::instrument(level = "info")] -pub fn init_paging(vm_offset: VAddr) { - VM_OFFSET.store(vm_offset.as_usize(), Ordering::Release); +static KERNEL_ADDRS: InitOnce<&'static (dyn TranslateKernelAddrs + Send + Sync)> = + InitOnce::uninitialized(); + +#[tracing::instrument(level = "info", skip(bootinfo))] +pub fn init_paging(bootinfo: &'static impl BootInfo) { + KERNEL_ADDRS.init(bootinfo.kernel_addrs()); tracing::info!("initializing paging..."); let (pml4_page, flags) = crate::control_regs::cr3::read(); tracing::debug!(?pml4_page, ?flags); tracing::trace!("old PML4:"); - let pml4 = PageTable::::current(vm_offset); + let pml4 = PageTable::::current(); // Log out some details about our starting page table. let mut present_entries = 0; @@ -89,25 +90,21 @@ pub fn init_paging(vm_offset: VAddr) { tracing::trace!(idx, ?entry); present_entries += 1; } + tracing::trace!(present_entries); } - tracing::trace!(present_entries); } -/// This value should only be set once, early in the kernel boot process before -/// we have access to multiple cores. So, technically, it could be a `static -/// mut`. But, using an atomic is safe, even though it's not strictly necessary. -static VM_OFFSET: AtomicUsize = AtomicUsize::new(core::usize::MAX); - impl PageTable { - fn current(vm_offset: VAddr) -> &'static mut Self { + fn current() -> &'static mut Self { let (phys, _) = crate::control_regs::cr3::read(); - unsafe { Self::from_pml4_page(vm_offset, phys) } + unsafe { Self::from_pml4_page(phys) } } - unsafe fn from_pml4_page(vm_offset: VAddr, page: Page) -> &'static mut Self { + + unsafe fn from_pml4_page(page: Page) -> &'static mut Self { let pml4_paddr = page.base_addr(); - tracing::trace!(?pml4_paddr, ?vm_offset); + tracing::trace!(?pml4_paddr); - let virt = vm_offset + VAddr::from_usize(pml4_paddr.as_usize()); + let virt = KERNEL_ADDRS.get_unchecked().to_kernel_vaddr(pml4_paddr); tracing::debug!(current_pml4_vaddr = ?virt); &mut *(virt.as_ptr::() as *mut _) } @@ -174,14 +171,7 @@ where impl PageCtrl { pub fn current() -> Self { - let vm_offset = VM_OFFSET.load(Ordering::Acquire); - assert_ne!( - vm_offset, - core::usize::MAX, - "`init_paging` must be called before calling `PageTable::current`!" - ); - let vm_offset = VAddr::from_usize(vm_offset); - let pml4 = PageTable::current(vm_offset); + let pml4 = PageTable::current(); Self { pml4: NonNull::from(pml4), } diff --git a/src/arch/x86_64.rs b/src/arch/x86_64.rs index 8f86fe03..94267eb8 100644 --- a/src/arch/x86_64.rs +++ b/src/arch/x86_64.rs @@ -12,10 +12,11 @@ pub struct RustbootBootInfo { type MemRegionIter = core::slice::Iter<'static, bootinfo::MemoryRegion>; impl BootInfo for RustbootBootInfo { - // TODO(eliza): implement type MemoryMap = core::iter::Map mem::Region>; type Writer = vga::Writer; + /// Translate kernel addresses using the fixed virtual memory offset. + type KernelAddrs = Self; /// Returns the boot info's memory map. fn memory_map(&self) -> Self::MemoryMap { @@ -64,14 +65,18 @@ impl BootInfo for RustbootBootInfo { "rust-bootloader" } - fn init_paging(&self) { - mm::init_paging(self.vm_offset()) + fn kernel_addrs(&self) -> &Self::KernelAddrs { + self } } -impl RustbootBootInfo { - fn vm_offset(&self) -> VAddr { - VAddr::from_u64(self.inner.physical_memory_offset) +impl mem::TranslateKernelAddrs for RustbootBootInfo { + fn to_kernel_paddr(&self, vaddr: VAddr) -> PAddr { + PAddr::from_u64(vaddr.as_usize() as u64 - self.inner.physical_memory_offset) + } + + fn to_kernel_vaddr(&self, paddr: PAddr) -> VAddr { + VAddr::from_usize((paddr.as_u64() + self.inner.physical_memory_offset) as usize) } } diff --git a/src/lib.rs b/src/lib.rs index 544a195d..a624c7fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ use hal_core::{boot::BootInfo, mem}; mod wasm; -pub fn kernel_main(bootinfo: &impl BootInfo) -> ! { +pub fn kernel_main(bootinfo: &'static impl BootInfo) -> ! { let mut writer = bootinfo.writer(); writeln!( &mut writer, @@ -60,7 +60,7 @@ pub fn kernel_main(bootinfo: &impl BootInfo) -> ! { } arch::interrupt::init::(); - bootinfo.init_paging(); + arch::mm::init_paging(bootinfo); #[cfg(test)] { From f7409caea4be21967620aad42d317f2550f493a6 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 24 Dec 2020 12:24:49 -0800 Subject: [PATCH 2/2] whoops gotta import `Address` Signed-off-by: Eliza Weisman --- src/arch/x86_64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arch/x86_64.rs b/src/arch/x86_64.rs index 94267eb8..70e79d2d 100644 --- a/src/arch/x86_64.rs +++ b/src/arch/x86_64.rs @@ -1,6 +1,6 @@ use bootloader::bootinfo; use core::sync::atomic::{AtomicUsize, Ordering}; -use hal_core::{boot::BootInfo, mem, PAddr, VAddr}; +use hal_core::{boot::BootInfo, mem, Address, PAddr, VAddr}; use hal_x86_64::{cpu, interrupt::Registers as X64Registers, serial, vga}; pub use hal_x86_64::{interrupt, mm, NAME};