Skip to content

Commit

Permalink
monolithic: introduce module axmm for virtual memory management
Browse files Browse the repository at this point in the history
  • Loading branch information
equation314 committed Jun 21, 2024
1 parent afa8ddd commit c695855
Show file tree
Hide file tree
Showing 21 changed files with 323 additions and 83 deletions.
18 changes: 15 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ members = [
"modules/axfs",
"modules/axhal",
"modules/axlog",
"modules/axmm",
"modules/axnet",
"modules/axruntime",
"modules/axsync",
Expand Down
21 changes: 11 additions & 10 deletions crates/memory_addr/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![no_std]
#![feature(effects)]
#![doc = include_str!("../README.md")]

use core::fmt;
Expand Down Expand Up @@ -98,7 +99,7 @@ impl PhysAddr {
///
/// See the [`align_down`] function for more information.
#[inline]
pub fn align_down<U>(self, align: U) -> Self
pub const fn align_down<U>(self, align: U) -> Self
where
U: Into<usize>,
{
Expand All @@ -109,7 +110,7 @@ impl PhysAddr {
///
/// See the [`align_up`] function for more information.
#[inline]
pub fn align_up<U>(self, align: U) -> Self
pub const fn align_up<U>(self, align: U) -> Self
where
U: Into<usize>,
{
Expand All @@ -120,7 +121,7 @@ impl PhysAddr {
///
/// See the [`align_offset`] function for more information.
#[inline]
pub fn align_offset<U>(self, align: U) -> usize
pub const fn align_offset<U>(self, align: U) -> usize
where
U: Into<usize>,
{
Expand All @@ -131,7 +132,7 @@ impl PhysAddr {
///
/// See the [`is_aligned`] function for more information.
#[inline]
pub fn is_aligned<U>(self, align: U) -> bool
pub const fn is_aligned<U>(self, align: U) -> bool
where
U: Into<usize>,
{
Expand All @@ -140,25 +141,25 @@ impl PhysAddr {

/// Aligns the address downwards to 4096 (bytes).
#[inline]
pub fn align_down_4k(self) -> Self {
pub const fn align_down_4k(self) -> Self {
self.align_down(PAGE_SIZE_4K)
}

/// Aligns the address upwards to 4096 (bytes).
#[inline]
pub fn align_up_4k(self) -> Self {
pub const fn align_up_4k(self) -> Self {
self.align_up(PAGE_SIZE_4K)
}

/// Returns the offset of the address within a 4K-sized page.
#[inline]
pub fn align_offset_4k(self) -> usize {
pub const fn align_offset_4k(self) -> usize {
self.align_offset(PAGE_SIZE_4K)
}

/// Checks whether the address is 4K-aligned.
#[inline]
pub fn is_aligned_4k(self) -> bool {
pub const fn is_aligned_4k(self) -> bool {
self.is_aligned(PAGE_SIZE_4K)
}
}
Expand Down Expand Up @@ -225,7 +226,7 @@ impl VirtAddr {
///
/// See the [`is_aligned`] function for more information.
#[inline]
pub fn is_aligned<U>(self, align: U) -> bool
pub const fn is_aligned<U>(self, align: U) -> bool
where
U: Into<usize>,
{
Expand All @@ -252,7 +253,7 @@ impl VirtAddr {

/// Checks whether the address is 4K-aligned.
#[inline]
pub fn is_aligned_4k(self) -> bool {
pub const fn is_aligned_4k(self) -> bool {
self.is_aligned(PAGE_SIZE_4K)
}
}
Expand Down
14 changes: 5 additions & 9 deletions crates/page_table/src/bits64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,16 +247,13 @@ impl<M: PagingMetaData, PTE: GenericPTE, IF: PagingIf> PageTable64<M, PTE, IF> {
)
}

/// Shallow clone the page table, keeping only the given virtual memory
/// region.
pub fn clone_shallow(&self, start: VirtAddr, size: usize) -> PagingResult<Self> {
let pt = Self::try_new()?;
/// Copy entries from another page table within the given virtual memory range.
pub fn copy_from(&mut self, other: &Self, start: VirtAddr, size: usize) {
if size == 0 {
return Ok(pt);
return;
}

let src_table = Self::table_of(self.root_paddr);
let dst_table = Self::table_of_mut(pt.root_paddr);
let src_table = Self::table_of(other.root_paddr);
let dst_table = Self::table_of_mut(self.root_paddr);
let index_fn = if M::LEVELS == 3 {
p3_index
} else if M::LEVELS == 4 {
Expand All @@ -269,7 +266,6 @@ impl<M: PagingMetaData, PTE: GenericPTE, IF: PagingIf> PageTable64<M, PTE, IF> {
assert!(start_idx < ENTRY_COUNT);
assert!(end_idx <= ENTRY_COUNT);
dst_table[start_idx..end_idx].copy_from_slice(&src_table[start_idx..end_idx]);
Ok(pt)
}
}

Expand Down
10 changes: 8 additions & 2 deletions crates/page_table_entry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@

mod arch;

use core::fmt::Debug;
use core::fmt::{self, Debug};
use memory_addr::PhysAddr;

pub use self::arch::*;

bitflags::bitflags! {
/// Generic page table entry flags that indicate the corresponding mapped
/// memory region permissions and attributes.
#[derive(Debug, Clone, Copy)]
#[derive(Clone, Copy)]
pub struct MappingFlags: usize {
/// The memory is readable.
const READ = 1 << 0;
Expand All @@ -41,6 +41,12 @@ bitflags::bitflags! {
}
}

impl Debug for MappingFlags {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.0, f)
}
}

/// A generic page table entry.
///
/// All architecture-specific page table entry types implement this trait.
Expand Down
4 changes: 4 additions & 0 deletions modules/axconfig/defconfig.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ kernel-base-vaddr = "0"
# Linear mapping offset, for quick conversions between physical and virtual
# addresses.
phys-virt-offset = "0"
# Kernel address space base.
kernel-aspace-base = "0"
# Kernel address space size.
kernel-aspace-size = "0"
# MMIO regions with format (`base_paddr`, `size`).
mmio-regions = []
# VirtIO MMIO regions with format (`base_paddr`, `size`).
Expand Down
1 change: 1 addition & 0 deletions modules/axhal/src/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub use memory_addr::{PhysAddr, VirtAddr, PAGE_SIZE_4K};

bitflags::bitflags! {
/// The flags of a physical memory region.
#[derive(Clone, Copy)]
pub struct MemRegionFlags: usize {
/// Readable.
const READ = 1 << 0;
Expand Down
19 changes: 19 additions & 0 deletions modules/axmm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "axmm"
version = "0.1.0"
edition = "2021"
authors = ["Yuekai Jia <[email protected]>"]
description = "ArceOS virtual memory management module"
license = "GPL-3.0-or-later OR Apache-2.0"
homepage = "https://github.com/rcore-os/arceos"
repository = "https://github.com/rcore-os/arceos/tree/main/modules/axmm"
documentation = "https://rcore-os.github.io/arceos/axmm/index.html"

[dependencies]
axhal = { path = "../axhal", features = ["paging"] }
axconfig = { path = "../../modules/axconfig" }

log = "0.4"
axerrno = { path = "../../crates/axerrno" }
lazy_init = { path = "../../crates/lazy_init" }
memory_addr = { path = "../../crates/memory_addr" }
122 changes: 122 additions & 0 deletions modules/axmm/src/aspace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use core::fmt;

use axerrno::{ax_err, AxResult};
use axhal::paging::{MappingFlags, PageTable};
use memory_addr::{PhysAddr, VirtAddr};

use crate::paging_err_to_ax_err;

/// The virtual memory address space.
pub struct AddrSpace {
base: VirtAddr,
end: VirtAddr,
pt: PageTable,
}

impl AddrSpace {
/// Returns the address space base.
pub const fn base(&self) -> VirtAddr {
self.base
}

/// Returns the address space end.
pub const fn end(&self) -> VirtAddr {
self.end
}

/// Returns the address space size.
pub const fn size(&self) -> usize {
self.end.as_usize() - self.base.as_usize()
}

/// Returns the reference to the inner page table.
pub const fn page_table(&self) -> &PageTable {
&self.pt
}

/// Returns the root physical address of the inner page table.
pub const fn page_table_root(&self) -> PhysAddr {
self.pt.root_paddr()
}

/// Checks if the address space contains the given virtual address.
pub const fn contains(&self, addr: VirtAddr) -> bool {
self.base.as_usize() <= addr.as_usize() && addr.as_usize() < self.end.as_usize()
}

/// Checks if the address space contains the given virtual address range.
pub const fn contains_range(&self, start: VirtAddr, size: usize) -> bool {
self.base.as_usize() <= start.as_usize() && start.as_usize() + size < self.end.as_usize()
}

/// Checks if the address space overlaps with the given virtual address range.
pub const fn overlaps_with(&self, start: VirtAddr, size: usize) -> bool {
let end = start.as_usize() + size;
!(end <= self.base.as_usize() || start.as_usize() >= self.end.as_usize())
}

/// Creates a new empty address space.
pub(crate) fn new_empty(base: VirtAddr, size: usize) -> AxResult<Self> {
Ok(Self {
base,
end: base + size,
pt: PageTable::try_new().map_err(paging_err_to_ax_err)?,
})
}

/// Copies page table mappings from another address space.
///
/// It copies the page table entries only rather than the memory regions,
/// usually usually used to copy a portion of the kernel space mapping to
/// the user space.
pub fn copy_mappings_from(&mut self, other: &AddrSpace) -> AxResult {
if self.overlaps_with(other.base(), other.size()) {
return ax_err!(InvalidInput, "address space overlap");
}
self.pt.copy_from(&other.pt, other.base(), other.size());
Ok(())
}

/// Add a new fixed mapping for the specified virtual and physical address
/// range.
///
/// The mapping is linear, i.e., `start_vaddr` is mapped to `start_paddr`,
/// and `start_vaddr + size` is mapped to `start_paddr + size`.
///
/// The `flags` parameter specifies the mapping permissions and attributes.
pub fn map_fixed(
&mut self,
start_vaddr: VirtAddr,
start_paddr: PhysAddr,
size: usize,
flags: MappingFlags,
) -> AxResult {
if !self.contains_range(start_vaddr, size) {
return ax_err!(InvalidInput, "address out of range");
}
self.pt
.map_region(start_vaddr, start_paddr, size, flags, true)
.map_err(paging_err_to_ax_err)?;
Ok(())
}

/// Removes the mappings for the specified virtual address range.
pub fn unmap(&mut self, start: VirtAddr, size: usize) -> AxResult {
if !self.contains_range(start, size) {
return ax_err!(InvalidInput, "address out of range");
}
self.pt
.unmap_region(start, size)
.map_err(paging_err_to_ax_err)?;
Ok(())
}
}

impl fmt::Debug for AddrSpace {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("AddrSpace")
.field("va_range", &(self.base.as_usize()..self.end.as_usize()))
.field("page_table_root", &self.pt.root_paddr())
.finish()
}
}
Loading

0 comments on commit c695855

Please sign in to comment.