-
Notifications
You must be signed in to change notification settings - Fork 308
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
monolithic: introduce crate memory_set to implement mmap and munmap
- Loading branch information
1 parent
3b4bc02
commit 4202056
Showing
12 changed files
with
656 additions
and
43 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[package] | ||
name = "memory_set" | ||
version = "0.1.0" | ||
edition = "2021" | ||
authors = ["Yuekai Jia <[email protected]>"] | ||
description = "Data structures and operations for managing memory mappings" | ||
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/crates/memory_set" | ||
documentation = "https://rcore-os.github.io/arceos/memory_set/index.html" | ||
keywords = ["arceos", "virtual-memory", "memory-area", "mmap"] | ||
categories = ["os", "memory-management", "no-std"] | ||
|
||
[dependencies] | ||
memory_addr = { path = "../memory_addr" } |
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,151 @@ | ||
use core::fmt; | ||
use core::marker::PhantomData; | ||
|
||
use memory_addr::{VirtAddr, VirtAddrRange}; | ||
|
||
use crate::{MappingError, MappingResult}; | ||
|
||
/// Underlying memory mapping operations specific to a memory area. | ||
/// | ||
/// The backend can be different for different memory areas. e.g., for fixed | ||
/// mappings, the target physical address is known when it is added to the page | ||
/// table. For lazy mappings, an empty mapping needs to be added to the page table | ||
/// to trigger a page fault. | ||
pub trait MappingBackend<F: Copy, P>: Clone { | ||
/// Maps a memory region with the given flags. | ||
fn map(&self, start: VirtAddr, size: usize, flags: F, page_table: &mut P) -> bool; | ||
/// Unmaps a memory region. | ||
fn unmap(&self, start: VirtAddr, size: usize, page_table: &mut P) -> bool; | ||
} | ||
|
||
/// A memory area represents a continuous range of virtual memory with the same | ||
/// flags. | ||
/// | ||
/// The target physical memory frames are determined by [`MappingBackend`] and | ||
/// may not be contiguous. | ||
pub struct MemoryArea<F: Copy, P, B: MappingBackend<F, P>> { | ||
va_range: VirtAddrRange, | ||
flags: F, | ||
backend: B, | ||
_phantom: PhantomData<(F, P)>, | ||
} | ||
|
||
impl<F: Copy, P, B: MappingBackend<F, P>> MemoryArea<F, P, B> { | ||
/// Creates a new memory area. | ||
pub const fn new(start: VirtAddr, size: usize, flags: F, backend: B) -> Self { | ||
Self { | ||
va_range: VirtAddrRange::from_start_size(start, size), | ||
flags, | ||
backend, | ||
_phantom: PhantomData, | ||
} | ||
} | ||
|
||
/// Returns the virtual address range. | ||
pub const fn va_range(&self) -> VirtAddrRange { | ||
self.va_range | ||
} | ||
|
||
/// Returns the memory flags, e.g., the permission bits. | ||
pub const fn flags(&self) -> F { | ||
self.flags | ||
} | ||
|
||
/// Returns the start address of the memory area. | ||
pub const fn start(&self) -> VirtAddr { | ||
self.va_range.start | ||
} | ||
|
||
/// Returns the end address of the memory area. | ||
pub const fn end(&self) -> VirtAddr { | ||
self.va_range.end | ||
} | ||
|
||
/// Returns the size of the memory area. | ||
pub const fn size(&self) -> usize { | ||
self.va_range.size() | ||
} | ||
} | ||
|
||
impl<F: Copy, P, B: MappingBackend<F, P>> MemoryArea<F, P, B> { | ||
/// Maps the whole memory area in the page table. | ||
pub(crate) fn map_area(&self, page_table: &mut P) -> MappingResult { | ||
self.backend | ||
.map(self.start(), self.size(), self.flags, page_table) | ||
.then_some(()) | ||
.ok_or(MappingError::BadState) | ||
} | ||
|
||
/// Unmaps the whole memory area in the page table. | ||
pub(crate) fn unmap_area(&self, page_table: &mut P) -> MappingResult { | ||
self.backend | ||
.unmap(self.start(), self.size(), page_table) | ||
.then_some(()) | ||
.ok_or(MappingError::BadState) | ||
} | ||
|
||
/// Shrinks the memory area at the left side. | ||
/// | ||
/// The start address of the memory area is increased by `new_size`. The | ||
/// shrunk part is unmapped. | ||
pub(crate) fn shrink_left(&mut self, new_size: usize, page_table: &mut P) -> MappingResult { | ||
let unmap_size = self.size() - new_size; | ||
if !self.backend.unmap(self.start(), unmap_size, page_table) { | ||
return Err(MappingError::BadState); | ||
} | ||
self.va_range.start += unmap_size; | ||
Ok(()) | ||
} | ||
|
||
/// Shrinks the memory area at the right side. | ||
/// | ||
/// The end address of the memory area is decreased by `new_size`. The | ||
/// shrunk part is unmapped. | ||
pub(crate) fn shrink_right(&mut self, new_size: usize, page_table: &mut P) -> MappingResult { | ||
let unmap_size = self.size() - new_size; | ||
if !self | ||
.backend | ||
.unmap(self.start() + new_size, unmap_size, page_table) | ||
{ | ||
return Err(MappingError::BadState); | ||
} | ||
self.va_range.end -= unmap_size; | ||
Ok(()) | ||
} | ||
|
||
/// Splits the memory area at the given position. | ||
/// | ||
/// The original memory area is shrunk to the left part, and the right part | ||
/// is returned. | ||
/// | ||
/// Returns `None` if the given position is not in the memory area, or one | ||
/// of the parts is empty after splitting. | ||
pub(crate) fn split(&mut self, pos: VirtAddr) -> Option<Self> { | ||
let start = self.start(); | ||
let end = self.end(); | ||
if start < pos && pos < end { | ||
let new_area = Self::new( | ||
pos, | ||
end.as_usize() - pos.as_usize(), | ||
self.flags, | ||
self.backend.clone(), | ||
); | ||
self.va_range.end = pos; | ||
Some(new_area) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
|
||
impl<F, P, B: MappingBackend<F, P>> fmt::Debug for MemoryArea<F, P, B> | ||
where | ||
F: fmt::Debug + Copy, | ||
{ | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
f.debug_struct("MemoryArea") | ||
.field("va_range", &self.va_range) | ||
.field("flags", &self.flags) | ||
.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,28 @@ | ||
//! Data structures and operations for managing memory mappings. | ||
#![cfg_attr(not(test), no_std)] | ||
|
||
extern crate alloc; | ||
|
||
mod area; | ||
mod set; | ||
|
||
#[cfg(test)] | ||
mod tests; | ||
|
||
pub use self::area::{MappingBackend, MemoryArea}; | ||
pub use self::set::MemorySet; | ||
|
||
/// Error type for memory mapping operations. | ||
#[derive(Debug, Eq, PartialEq)] | ||
pub enum MappingError { | ||
/// Invalid parameter (e.g., `addr`, `size`, `flags`, etc.) | ||
InvalidParam, | ||
/// The given range clashes with an existing. | ||
AlreadyExists, | ||
/// The backend page table is in a bad state. | ||
BadState, | ||
} | ||
|
||
/// A [`Result`] type with [`MappingError`] as the error type. | ||
pub type MappingResult<T = ()> = Result<T, MappingError>; |
Oops, something went wrong.