Skip to content

Commit

Permalink
Merge pull request #163 from arceos-org/axmm
Browse files Browse the repository at this point in the history
  • Loading branch information
equation314 authored Jul 30, 2024
2 parents 3598fd1 + 16b4676 commit 0d42139
Show file tree
Hide file tree
Showing 18 changed files with 289 additions and 41 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:
continue-on-error: ${{ matrix.rust-toolchain == 'nightly' }}
run: make ARCH=${{ matrix.arch }} A=examples/httpserver
- name: Build shell
continue-on-error: ${{ matrix.rust-toolchain == 'shell' }}
continue-on-error: ${{ matrix.rust-toolchain == 'nightly' }}
run: make ARCH=${{ matrix.arch }} A=examples/shell

- uses: ./.github/workflows/actions/setup-musl
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on: [push, pull_request]
env:
qemu-version: 8.2.0
rust-toolchain: nightly-2024-05-02
arceos-apps: b36b9d5

jobs:
unit-test:
Expand Down Expand Up @@ -43,4 +44,5 @@ jobs:
run: |
make disk_img
git clone https://github.com/arceos-org/arceos-apps.git
cd arceos-apps && git reset --hard ${{ env.arceos-apps }} && cd ..
make -C arceos-apps test AX_ROOT=$(pwd) ARCH=${{ matrix.arch }}
25 changes: 20 additions & 5 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ members = [
"modules/axfs",
"modules/axhal",
"modules/axlog",
"modules/axmm",
"modules/axnet",
"modules/axruntime",
"modules/axsync",
Expand Down Expand Up @@ -53,6 +54,7 @@ axdriver = { path = "modules/axdriver" }
axfs = { path = "modules/axfs" }
axhal = { path = "modules/axhal" }
axlog = { path = "modules/axlog" }
axmm = { path = "modules/axmm" }
axnet = { path = "modules/axnet" }
axruntime = { path = "modules/axruntime" }
axsync = { path = "modules/axsync" }
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
4 changes: 2 additions & 2 deletions modules/axhal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ percpu = "0.1"
memory_addr = "0.2"
handler_table = "0.1"
crate_interface = "0.1"
page_table_entry = "0.1"
page_table_multiarch = { version = "0.1", optional = true }
page_table_entry = "0.3"
page_table_multiarch = { version = "0.3", optional = true }
axlog = { workspace = true }
axconfig = { workspace = true }
axalloc = { workspace = true, optional = true }
Expand Down
20 changes: 20 additions & 0 deletions modules/axmm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "axmm"
version.workspace = true
edition = "2021"
authors = ["Yuekai Jia <equation618@gmail.com>"]
description = "ArceOS virtual memory management module"
license.workspace = true
homepage.workspace = true
repository = "https://github.com/arceos-org/arceos/tree/main/modules/axmm"
documentation = "https://arceos-org.github.io/arceos/axmm/index.html"

[dependencies]
axhal = { workspace = true, features = ["paging"] }
axconfig = { workspace = true }

log = "0.4"
axerrno = "0.1"
lazyinit = "0.2"
memory_addr = "0.2"
kspin = "0.1"
139 changes: 139 additions & 0 deletions modules/axmm/src/aspace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use core::fmt;

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

use crate::paging_err_to_ax_err;

/// The virtual memory address space.
pub struct AddrSpace {
va_range: VirtAddrRange,
pt: PageTable,
}

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

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

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

/// 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 address range.
pub const fn contains_range(&self, start: VirtAddr, size: usize) -> bool {
self.va_range
.contains_range(VirtAddrRange::from_start_size(start, size))
}

/// Creates a new empty address space.
pub(crate) fn new_empty(base: VirtAddr, size: usize) -> AxResult<Self> {
Ok(Self {
va_range: VirtAddrRange::from_start_size(base, size),
pt: PageTable::try_new().map_err(|_| AxError::NoMemory)?,
})
}

/// Add a new linear mapping.
///
/// 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 indicates the mapping permissions and attributes.
///
/// Returns an error if the address range is out of the address space or not
/// aligned.
pub fn map_linear(
&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");
}
if !start_vaddr.is_aligned_4k() || !start_paddr.is_aligned_4k() || !is_aligned_4k(size) {
return ax_err!(InvalidInput, "address not aligned");
}

let offset = start_vaddr.as_usize() - start_paddr.as_usize();
self.pt
.map_region(
start_vaddr,
|va| PhysAddr::from(va.as_usize() - offset),
size,
flags,
false, // allow_huge
false, // flush_tlb_by_page
)
.map_err(paging_err_to_ax_err)?
.flush();
Ok(())
}

/// Removes mappings within the specified virtual address range.
///
/// Returns an error if the address range is out of the address space or not
/// aligned.
pub fn unmap(&mut self, start: VirtAddr, size: usize) -> AxResult {
if !self.contains_range(start, size) {
return ax_err!(InvalidInput, "address out of range");
}
if !start.is_aligned_4k() || !is_aligned_4k(size) {
return ax_err!(InvalidInput, "address not aligned");
}

self.pt
.unmap_region(start, size, true)
.map_err(paging_err_to_ax_err)?
.ignore();
Ok(())
}

/// Updates mapping within the specified virtual address range.
///
/// Returns an error if the address range is out of the address space or not
/// aligned.
pub fn protect(&mut self, start: VirtAddr, size: usize, flags: MappingFlags) -> AxResult {
if !self.contains_range(start, size) {
return ax_err!(InvalidInput, "address out of range");
}
if !start.is_aligned_4k() || !is_aligned_4k(size) {
return ax_err!(InvalidInput, "address not aligned");
}

self.pt
.protect_region(start, size, flags, true)
.map_err(paging_err_to_ax_err)?
.ignore();
Ok(())
}
}

impl fmt::Debug for AddrSpace {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("AddrSpace")
.field("va_range", &self.va_range)
.field("page_table_root", &self.pt.root_paddr())
.finish()
}
}
71 changes: 71 additions & 0 deletions modules/axmm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//! [ArceOS](https://github.com/arceos-org/arceos) memory management module.

#![no_std]

#[macro_use]
extern crate log;
extern crate alloc;

mod aspace;

pub use self::aspace::AddrSpace;

use axerrno::{AxError, AxResult};
use axhal::mem::phys_to_virt;
use axhal::paging::PagingError;
use kspin::SpinNoIrq;
use lazyinit::LazyInit;
use memory_addr::{PhysAddr, VirtAddr};

static KERNEL_ASPACE: LazyInit<SpinNoIrq<AddrSpace>> = LazyInit::new();

fn paging_err_to_ax_err(err: PagingError) -> AxError {
warn!("Paging error: {:?}", err);
match err {
PagingError::NoMemory => AxError::NoMemory,
PagingError::NotAligned => AxError::InvalidInput,
PagingError::NotMapped => AxError::NotFound,
PagingError::AlreadyMapped => AxError::AlreadyExists,
PagingError::MappedToHugePage => AxError::InvalidInput,
}
}

/// Creates a new address space for kernel itself.
pub fn new_kernel_aspace() -> AxResult<AddrSpace> {
let mut aspace = AddrSpace::new_empty(
VirtAddr::from(axconfig::KERNEL_ASPACE_BASE),
axconfig::KERNEL_ASPACE_SIZE,
)?;
for r in axhal::mem::memory_regions() {
aspace.map_linear(phys_to_virt(r.paddr), r.paddr, r.size, r.flags.into())?;
}
Ok(aspace)
}

/// Returns the globally unique kernel address space.
pub fn kernel_aspace() -> &'static SpinNoIrq<AddrSpace> {
&KERNEL_ASPACE
}

/// Returns the root physical address of the kernel page table.
pub fn kernel_page_table_root() -> PhysAddr {
KERNEL_ASPACE.lock().page_table_root()
}

/// Initializes virtual memory management.
///
/// It mainly sets up the kernel virtual memory address space and recreate a
/// fine-grained kernel page table.
pub fn init_memory_management() {
info!("Initialize virtual memory management...");

let kernel_aspace = new_kernel_aspace().expect("failed to initialize kernel address space");
debug!("kernel address space init OK: {:#x?}", kernel_aspace);
KERNEL_ASPACE.init_once(SpinNoIrq::new(kernel_aspace));
unsafe { axhal::arch::write_page_table_root(kernel_page_table_root()) };
}

/// Initializes kernel paging for secondary CPUs.
pub fn init_memory_management_secondary() {
unsafe { axhal::arch::write_page_table_root(kernel_page_table_root()) };
}
4 changes: 2 additions & 2 deletions modules/axruntime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ smp = ["axhal/smp"]
irq = ["axhal/irq", "axtask?/irq", "percpu", "kernel_guard"]
tls = ["axhal/tls", "axtask?/tls"]
alloc = ["axalloc"]
paging = ["axhal/paging", "lazyinit"]
paging = ["axhal/paging", "axmm"]

multitask = ["axtask/multitask"]
fs = ["axdriver", "axfs"]
Expand All @@ -29,6 +29,7 @@ axhal = { workspace = true }
axlog = { workspace = true }
axconfig = { workspace = true }
axalloc = { workspace = true, optional = true }
axmm = { workspace = true, optional = true }
axdriver = { workspace = true, optional = true }
axfs = { workspace = true, optional = true }
axnet = { workspace = true, optional = true }
Expand All @@ -38,6 +39,5 @@ axtask = { workspace = true, optional = true }
crate_interface = "0.1"
percpu = { version = "0.1", optional = true }
kernel_guard = { version = "0.1", optional = true }
lazyinit = { version = "0.2", optional = true }

chrono = { version = "0.4.38", default-features = false }
Loading

0 comments on commit 0d42139

Please sign in to comment.