Rename crates from jinux-* to aster-*

This commit is contained in:
Jianfeng Jiang
2023-12-25 03:12:25 +00:00
committed by Tate, Hongliang Tian
parent 6dbf5d560d
commit 93781df27b
460 changed files with 596 additions and 595 deletions

View File

@ -0,0 +1,262 @@
use crate::arch::mm::PageTableFlags;
use crate::config::PAGE_SIZE;
use crate::sync::Mutex;
use bitflags::bitflags;
use core::ops::Range;
use super::VmFrameVec;
use super::{is_page_aligned, Vaddr};
use super::{MapArea, MemorySet};
use crate::{prelude::*, Error};
use super::VmIo;
/// Virtual memory space.
///
/// A virtual memory space (`VmSpace`) can be created and assigned to a user space so that
/// the virtual memory of the user space can be manipulated safely. For example,
/// given an arbitrary user-space pointer, one can read and write the memory
/// location refered to by the user-space pointer without the risk of breaking the
/// memory safety of the kernel space.
///
/// A newly-created `VmSpace` is not backed by any physical memory pages.
/// To provide memory pages for a `VmSpace`, one can allocate and map
/// physical memory (`VmFrames`) to the `VmSpace`.
#[derive(Debug, Clone)]
pub struct VmSpace {
memory_set: Arc<Mutex<MemorySet>>,
}
impl VmSpace {
/// Creates a new VM address space.
pub fn new() -> Self {
Self {
memory_set: Arc::new(Mutex::new(MemorySet::new())),
}
}
/// Activate the page table, load root physical address to cr3
#[allow(clippy::missing_safety_doc)]
pub unsafe fn activate(&self) {
#[cfg(target_arch = "x86_64")]
crate::arch::x86::mm::activate_page_table(
self.memory_set.lock().pt.root_paddr(),
x86_64::registers::control::Cr3Flags::PAGE_LEVEL_CACHE_DISABLE,
);
}
/// Maps some physical memory pages into the VM space according to the given
/// options, returning the address where the mapping is created.
///
/// the frames in variable frames will delete after executing this function
///
/// For more information, see `VmMapOptions`.
pub fn map(&self, frames: VmFrameVec, options: &VmMapOptions) -> Result<Vaddr> {
let flags = PageTableFlags::from(options.perm);
if options.addr.is_none() {
return Err(Error::InvalidArgs);
}
// if can overwrite, the old mapping should be unmapped.
if options.can_overwrite {
let addr = options.addr.unwrap();
let size = frames.nbytes();
let _ = self.unmap(&(addr..addr + size));
}
// debug!("map to vm space: 0x{:x}", options.addr.unwrap());
let mut memory_set = self.memory_set.lock();
// FIXME: This is only a hack here. The interface of MapArea cannot simply deal with unmap part of memory,
// so we only map MapArea of page size now.
for (idx, frame) in frames.into_iter().enumerate() {
let addr = options.addr.unwrap() + idx * PAGE_SIZE;
let frames = VmFrameVec::from_one_frame(frame);
memory_set.map(MapArea::new(addr, PAGE_SIZE, flags, frames));
}
Ok(options.addr.unwrap())
}
/// determine whether a vaddr is already mapped
pub fn is_mapped(&self, vaddr: Vaddr) -> bool {
let memory_set = self.memory_set.lock();
memory_set.is_mapped(vaddr)
}
/// Unmaps the physical memory pages within the VM address range.
///
/// The range is allowed to contain gaps, where no physical memory pages
/// are mapped.
pub fn unmap(&self, range: &Range<Vaddr>) -> Result<()> {
assert!(is_page_aligned(range.start) && is_page_aligned(range.end));
let mut start_va = range.start;
let page_size = (range.end - range.start) / PAGE_SIZE;
let mut inner = self.memory_set.lock();
for i in 0..page_size {
inner.unmap(start_va)?;
start_va += PAGE_SIZE;
}
Ok(())
}
/// clear all mappings
pub fn clear(&self) {
self.memory_set.lock().clear();
#[cfg(target_arch = "x86_64")]
x86_64::instructions::tlb::flush_all();
}
/// Update the VM protection permissions within the VM address range.
///
/// The entire specified VM range must have been mapped with physical
/// memory pages.
pub fn protect(&self, range: &Range<Vaddr>, perm: VmPerm) -> Result<()> {
debug_assert!(range.start % PAGE_SIZE == 0);
debug_assert!(range.end % PAGE_SIZE == 0);
let start_page = range.start / PAGE_SIZE;
let end_page = range.end / PAGE_SIZE;
let flags = PageTableFlags::from(perm);
for page_idx in start_page..end_page {
let addr = page_idx * PAGE_SIZE;
self.memory_set.lock().protect(addr, flags)
}
Ok(())
}
}
impl Default for VmSpace {
fn default() -> Self {
Self::new()
}
}
impl VmIo for VmSpace {
fn read_bytes(&self, vaddr: usize, buf: &mut [u8]) -> Result<()> {
self.memory_set.lock().read_bytes(vaddr, buf)
}
fn write_bytes(&self, vaddr: usize, buf: &[u8]) -> Result<()> {
self.memory_set.lock().write_bytes(vaddr, buf)
}
}
/// Options for mapping physical memory pages into a VM address space.
/// See `VmSpace::map`.
#[derive(Clone, Debug)]
pub struct VmMapOptions {
/// start virtual address
addr: Option<Vaddr>,
/// map align
align: usize,
/// permission
perm: VmPerm,
/// can overwrite
can_overwrite: bool,
}
impl VmMapOptions {
/// Creates the default options.
pub fn new() -> Self {
Self {
addr: None,
align: PAGE_SIZE,
perm: VmPerm::empty(),
can_overwrite: false,
}
}
/// Sets the alignment of the address of the mapping.
///
/// The alignment must be a power-of-2 and greater than or equal to the
/// page size.
///
/// The default value of this option is the page size.
pub fn align(&mut self, align: usize) -> &mut Self {
self.align = align;
self
}
/// Sets the permissions of the mapping, which affects whether
/// the mapping can be read, written, or executed.
///
/// The default value of this option is read-only.
pub fn perm(&mut self, perm: VmPerm) -> &mut Self {
self.perm = perm;
self
}
/// Sets the address of the new mapping.
///
/// The default value of this option is `None`.
pub fn addr(&mut self, addr: Option<Vaddr>) -> &mut Self {
if addr.is_none() {
return self;
}
self.addr = Some(addr.unwrap());
self
}
/// Sets whether the mapping can overwrite any existing mappings.
///
/// If this option is `true`, then the address option must be `Some(_)`.
///
/// The default value of this option is `false`.
pub fn can_overwrite(&mut self, can_overwrite: bool) -> &mut Self {
self.can_overwrite = can_overwrite;
self
}
}
impl Default for VmMapOptions {
fn default() -> Self {
Self::new()
}
}
bitflags! {
/// Virtual memory protection permissions.
pub struct VmPerm: u8 {
/// Readable.
const R = 0b00000001;
/// Writable.
const W = 0b00000010;
/// Executable.
const X = 0b00000100;
/// User
const U = 0b00001000;
/// Readable + writable.
const RW = Self::R.bits | Self::W.bits;
/// Readable + execuable.
const RX = Self::R.bits | Self::X.bits;
/// Readable + writable + executable.
const RWX = Self::R.bits | Self::W.bits | Self::X.bits;
/// Readable + writable + user.
const RWU = Self::R.bits | Self::W.bits | Self::U.bits;
/// Readable + execuable + user.
const RXU = Self::R.bits | Self::X.bits | Self::U.bits;
/// Readable + writable + executable + user.
const RWXU = Self::R.bits | Self::W.bits | Self::X.bits | Self::U.bits;
}
}
impl TryFrom<u64> for VmPerm {
type Error = Error;
fn try_from(value: u64) -> Result<Self> {
VmPerm::from_bits(value as u8).ok_or(Error::InvalidArgs)
}
}
impl From<VmPerm> for PageTableFlags {
fn from(vm_perm: VmPerm) -> Self {
let mut flags = PageTableFlags::PRESENT | PageTableFlags::USER;
if vm_perm.contains(VmPerm::W) {
flags |= PageTableFlags::WRITABLE;
}
// FIXME: how to respect executable flags?
if !vm_perm.contains(VmPerm::X) {
flags |= PageTableFlags::NO_EXECUTE;
}
flags
}
}