-
Notifications
You must be signed in to change notification settings - Fork 261
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #163 from arceos-org/axmm
- Loading branch information
Showing
18 changed files
with
289 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.