Skip to content

Commit

Permalink
wip attempt to rewrite paging to support hugepage
Browse files Browse the repository at this point in the history
  • Loading branch information
hawkw committed Jan 4, 2025
1 parent 4b4298e commit 670a68b
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 69 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ maitake = { path = "maitake", features = ["tracing-02"] }
mycelium-pci = { path = "pci" }
mycelium-util = { path = "util" }
mycelium-trace = { path = "trace", features = ["embedded-graphics"] }

rand_xoshiro = "0.6"
rand = { version = "0.8", default_features = false }
rlibc = "1.0"
Expand Down
121 changes: 75 additions & 46 deletions hal-core/src/mem/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,9 @@ pub unsafe trait Alloc<S: Size> {
fn dealloc_range(&self, range: PageRange<PAddr, S>) -> Result<(), AllocError>;
}

pub trait Map<S, A>
pub trait Map<'mapper, S, A>
where
S: Size,
A: Alloc<S>,
{
type Entry: PageFlags<S>;

Expand Down Expand Up @@ -95,13 +94,13 @@ where
///
/// Good luck and have fun!
unsafe fn map_page(
&mut self,
&'mapper mut self,
virt: Page<VAddr, S>,
phys: Page<PAddr, S>,
frame_alloc: &A,
) -> Handle<'_, S, Self::Entry>;
) -> Handle<S, Self::Entry>;

fn flags_mut(&mut self, virt: Page<VAddr, S>) -> Handle<'_, S, Self::Entry>;
fn flags_mut(&'mapper mut self, virt: Page<VAddr, S>) -> Handle<S, Self::Entry>;

/// Unmap the provided virtual page, returning the physical page it was
/// previously mapped to.
Expand All @@ -121,10 +120,10 @@ where
/// Identity map the provided physical page to the virtual page with the
/// same address.
fn identity_map(
&mut self,
&'mapper mut self,
phys: Page<PAddr, S>,
frame_alloc: &A,
) -> Handle<'_, S, Self::Entry> {
) -> Handle<S, Self::Entry> {
let base_paddr = phys.base_addr().as_usize();
let virt = Page::containing(VAddr::from_usize(base_paddr), phys.size());
unsafe { self.map_page(virt, phys, frame_alloc) }
Expand Down Expand Up @@ -169,34 +168,35 @@ where
///
/// Good luck and have fun!
unsafe fn map_range<F>(
&mut self,
&'mapper mut self,
virt: PageRange<VAddr, S>,
phys: PageRange<PAddr, S>,
mut set_flags: F,
frame_alloc: &A,
) -> PageRange<VAddr, S>
where
F: FnMut(&mut Handle<'_, S, Self::Entry>),
F: FnMut(&mut Handle<S, Self::Entry>),
{
let _span = tracing::trace_span!("map_range", ?virt, ?phys).entered();
assert_eq!(
virt.len(),
phys.len(),
"virtual and physical page ranges must have the same number of pages"
);
assert_eq!(
virt.size(),
phys.size(),
"virtual and physical pages must be the same size"
);
for (virt, phys) in virt.into_iter().zip(&phys) {
tracing::trace!(virt.page = ?virt, phys.page = ?phys, "mapping...");
let mut flags = self.map_page(virt, phys, frame_alloc);
set_flags(&mut flags);
flags.commit();
tracing::trace!(virt.page = ?virt, phys.page = ?phys, "mapped");
}
virt
todo!("agh, mutability");
// let _span = tracing::trace_span!("map_range", ?virt, ?phys).entered();
// assert_eq!(
// virt.len(),
// phys.len(),
// "virtual and physical page ranges must have the same number of pages"
// );
// assert_eq!(
// virt.size(),
// phys.size(),
// "virtual and physical pages must be the same size"
// );
// for (virt, phys) in virt.into_iter().zip(&phys) {
// tracing::trace!(virt.page = ?virt, phys.page = ?phys, "mapping...");
// let mut flags = self.map_page(virt, phys, frame_alloc);
// set_flags(&mut flags);
// flags.commit();
// tracing::trace!(virt.page = ?virt, phys.page = ?phys, "mapped");
// }
// virt
}

/// Unmap the provided range of virtual pages.
Expand Down Expand Up @@ -254,13 +254,13 @@ where
/// - If any page's physical address is invalid.
/// - If any page is already mapped.
fn identity_map_range<F>(
&mut self,
&'mapper mut self,
phys: PageRange<PAddr, S>,
set_flags: F,
frame_alloc: &A,
) -> PageRange<VAddr, S>
where
F: FnMut(&mut Handle<'_, S, Self::Entry>),
F: FnMut(&mut Handle<S, Self::Entry>),
{
let base_paddr = phys.base_addr().as_usize();
let page_size = phys.start().size();
Expand All @@ -272,26 +272,25 @@ where
}
}

impl<M, A, S> Map<S, A> for &mut M
impl<'mapper, M, A, S> Map<'mapper, S, A> for &'mapper mut M
where
M: Map<S, A>,
M: Map<'mapper, S, A>,
S: Size,
A: Alloc<S>,
{
type Entry = M::Entry;

#[inline]
unsafe fn map_page(
&mut self,
&'mapper mut self,
virt: Page<VAddr, S>,
phys: Page<PAddr, S>,
frame_alloc: &A,
) -> Handle<'_, S, Self::Entry> {
) -> Handle<S, Self::Entry> {
(*self).map_page(virt, phys, frame_alloc)
}

#[inline]
fn flags_mut(&mut self, virt: Page<VAddr, S>) -> Handle<'_, S, Self::Entry> {
fn flags_mut(&'mapper mut self, virt: Page<VAddr, S>) -> Handle<S, Self::Entry> {
(*self).flags_mut(virt)
}

Expand All @@ -302,10 +301,10 @@ where

#[inline]
fn identity_map(
&mut self,
&'mapper mut self,
phys: Page<PAddr, S>,
frame_alloc: &A,
) -> Handle<'_, S, Self::Entry> {
) -> Handle<S, Self::Entry> {
(*self).identity_map(phys, frame_alloc)
}
}
Expand Down Expand Up @@ -362,13 +361,43 @@ pub trait PageFlags<S: Size>: fmt::Debug {
fn commit(&mut self, page: Page<VAddr, S>);
}

impl<S: Size> PageFlags<S> for &'_ mut dyn PageFlags<S> {
unsafe fn set_writable(&mut self, writable: bool) {
(*self).set_writable(writable)
}

unsafe fn set_executable(&mut self, executable: bool) {
(*self).set_executable(executable)
}

unsafe fn set_present(&mut self, present: bool) {
(*self).set_present(present)
}

fn is_writable(&self) -> bool {
<dyn PageFlags<S>>::is_writable(*self)
}

fn is_executable(&self) -> bool {
<dyn PageFlags<S>>::is_executable(*self)
}

fn is_present(&self) -> bool {
<dyn PageFlags<S>>::is_present(*self)
}

fn commit(&mut self, page: Page<VAddr, S>) {
(*self).commit(page)
}
}

/// A page in the process of being remapped.
///
/// This reference allows updating page table flags prior to committing changes.
#[derive(Debug)]
#[must_use = "page table updates may not be reflected until changes are committed (using `Handle::commit`)"]
pub struct Handle<'mapper, S: Size, E: PageFlags<S>> {
entry: &'mapper mut E,
pub struct Handle<S: Size, E: PageFlags<S>> {
entry: E,
page: Page<VAddr, S>,
}

Expand Down Expand Up @@ -721,12 +750,12 @@ where

// === impl Handle ===

impl<'mapper, S, E> Handle<'mapper, S, E>
impl<S, E> Handle<S, E>
where
S: Size,
E: PageFlags<S>,
{
pub fn new(page: Page<VAddr, S>, entry: &'mapper mut E) -> Self {
pub fn new(page: Page<VAddr, S>, entry: E) -> Self {
Self { entry, page }
}

Expand All @@ -745,7 +774,7 @@ where
/// page table (i.e. it has multiple page table entries pointing to it) may
/// also cause undefined behavior.
#[inline]
pub unsafe fn set_writable(self, writable: bool) -> Self {
pub unsafe fn set_writable(mut self, writable: bool) -> Self {
self.entry.set_writable(writable);
self
}
Expand All @@ -759,7 +788,7 @@ where
/// undefined behavior. Also, this can be used to execute the contents of
/// arbitrary memory, which (of course) is wildly unsafe.
#[inline]
pub unsafe fn set_executable(self, executable: bool) -> Self {
pub unsafe fn set_executable(mut self, executable: bool) -> Self {
self.entry.set_executable(executable);
self
}
Expand All @@ -770,7 +799,7 @@ where
///
/// Manual control of page flags can be used to violate Rust invariants.
#[inline]
pub unsafe fn set_present(self, present: bool) -> Self {
pub unsafe fn set_present(mut self, present: bool) -> Self {
self.entry.set_present(present);
self
}
Expand All @@ -791,7 +820,7 @@ where
}

#[inline]
pub fn commit(self) -> Page<VAddr, S> {
pub fn commit(mut self) -> Page<VAddr, S> {
tracing::debug!(
page = ?self.page,
entry = ?self.entry,
Expand Down
9 changes: 5 additions & 4 deletions hal-x86_64/src/interrupt/apic/ioapic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,12 +320,13 @@ impl IoApic {
/// # Returns
/// - `Some(IoApic)` if this CPU supports the APIC interrupt model.
/// - `None` if this CPU does not support APIC interrupt handling.
pub fn try_new<A>(
pub fn try_new<'m, A, M>(
base_paddr: PAddr,
pagectrl: &mut impl page::Map<Size4Kb, A>,
pagectrl: &'m mut M,
frame_alloc: &A,
) -> Result<Self, FeatureNotSupported>
where
M: page::Map<'m, mm::size::AnySize, A>,
A: page::Alloc<Size4Kb>,
{
if !super::is_supported() {
Expand All @@ -338,8 +339,8 @@ impl IoApic {

unsafe {
// ensure the I/O APIC's MMIO page is mapped and writable.
let virt = VirtPage::<Size4Kb>::containing_fixed(base);
let phys = PhysPage::<Size4Kb>::containing_fixed(base_paddr);
let virt = VirtPage::containing_addr(base, mm::size::AnySize::Size4Kb);
let phys = PhysPage::containing_addr(base_paddr, mm::size::AnySize::Size4Kb).unwrap();
tracing::debug!(?virt, ?phys, "mapping I/O APIC MMIO page...");
pagectrl
.map_page(virt, phys, frame_alloc)
Expand Down
Loading

0 comments on commit 670a68b

Please sign in to comment.