Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] less wretched abstraction for kernel addr translation #92

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions hal-core/src/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ use core::iter::Iterator;

pub trait BootInfo {
type MemoryMap: Iterator<Item = mem::Region>;
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;

Expand All @@ -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???)
Expand Down
10 changes: 9 additions & 1 deletion hal-core/src/mem/mod.rs
Original file line number Diff line number Diff line change
@@ -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<A = crate::PAddr> {
Expand Down
58 changes: 24 additions & 34 deletions hal-x86_64/src/mm/mod.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -44,16 +42,19 @@ pub struct Entry<L> {
_level: PhantomData<L>,
}

#[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::<level::Pml4>::current(vm_offset);
let pml4 = PageTable::<level::Pml4>::current();

// Log out some details about our starting page table.
let mut present_entries = 0;
Expand Down Expand Up @@ -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<level::Pml4> {
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<PAddr, Size4Kb>) -> &'static mut Self {

unsafe fn from_pml4_page(page: Page<PAddr, Size4Kb>) -> &'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::<Self>() as *mut _)
}
Expand Down Expand Up @@ -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),
}
Expand Down
19 changes: 12 additions & 7 deletions src/arch/x86_64.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand All @@ -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<MemRegionIter, fn(&bootinfo::MemoryRegion) -> 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 {
Expand Down Expand Up @@ -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)
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -60,7 +60,7 @@ pub fn kernel_main(bootinfo: &impl BootInfo) -> ! {
}

arch::interrupt::init::<arch::InterruptHandlers>();
bootinfo.init_paging();
arch::mm::init_paging(bootinfo);

#[cfg(test)]
{
Expand Down