Support physmap via memory:physical@<mem type>.
This commit is contained in:
+112
-16
@@ -1,17 +1,52 @@
|
||||
use alloc::sync::Arc;
|
||||
use rmm::PhysicalAddress;
|
||||
use spin::RwLock;
|
||||
use syscall::MapFlags;
|
||||
|
||||
use crate::context;
|
||||
use crate::context::memory::{AddrSpace, Grant};
|
||||
use crate::memory::{free_frames, used_frames, PAGE_SIZE};
|
||||
use crate::memory::{free_frames, used_frames, PAGE_SIZE, Frame};
|
||||
|
||||
use crate::paging::entry::EntryFlags;
|
||||
use crate::syscall::data::{Map, StatVfs};
|
||||
use crate::syscall::error::*;
|
||||
use crate::syscall::scheme::Scheme;
|
||||
use crate::syscall::usercopy::UserSliceWo;
|
||||
|
||||
use super::KernelScheme;
|
||||
|
||||
pub struct MemoryScheme;
|
||||
|
||||
// TODO: Use crate that autogenerates conversion functions.
|
||||
#[repr(u8)]
|
||||
enum Handle {
|
||||
Anonymous = 0,
|
||||
|
||||
PhysicalWb = 1,
|
||||
PhysicalUc = 2,
|
||||
PhysicalWc = 3,
|
||||
|
||||
// TODO: More/make arch-specific?
|
||||
}
|
||||
pub enum MemoryType {
|
||||
Writeback,
|
||||
Uncacheable,
|
||||
WriteCombining,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
fn from_raw(raw: usize) -> Option<Self> {
|
||||
Some(match raw {
|
||||
0 => Self::Anonymous,
|
||||
|
||||
1 => Self::PhysicalWb,
|
||||
2 => Self::PhysicalUc,
|
||||
3 => Self::PhysicalWc,
|
||||
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl MemoryScheme {
|
||||
pub fn new() -> Self {
|
||||
MemoryScheme
|
||||
@@ -28,14 +63,68 @@ impl MemoryScheme {
|
||||
|
||||
Ok(page.start_address().data())
|
||||
}
|
||||
pub fn physmap(physical_address: usize, size: usize, flags: MapFlags, memory_type: MemoryType) -> Result<usize> {
|
||||
// TODO: Check physical_address against the real MAXPHYADDR.
|
||||
let end = 1 << 52;
|
||||
if (physical_address.saturating_add(size) as u64) > end || physical_address % PAGE_SIZE != 0 {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
// TODO: Check that the physical address is not owned by the frame allocator, although this
|
||||
// requires replacing physalloc and physfree with e.g. MAP_PHYS_CONTIGUOUS.
|
||||
|
||||
if size % PAGE_SIZE != 0 {
|
||||
log::warn!("physmap size {} is not multiple of PAGE_SIZE {}", size, PAGE_SIZE);
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
let page_count = size.div_ceil(PAGE_SIZE);
|
||||
|
||||
AddrSpace::current()?.write().mmap(None, page_count, flags, |dst_page, mut page_flags, dst_mapper, dst_flusher| {
|
||||
match memory_type {
|
||||
// Default
|
||||
MemoryType::Writeback => (),
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] // TODO: AARCH64
|
||||
MemoryType::WriteCombining => page_flags = page_flags.custom_flag(EntryFlags::HUGE_PAGE.bits(), true),
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] // TODO: AARCH64
|
||||
MemoryType::Uncacheable => page_flags = page_flags.custom_flag(EntryFlags::NO_CACHE.bits(), true),
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Grant::physmap(
|
||||
Frame::containing_address(PhysicalAddress::new(physical_address)),
|
||||
dst_page,
|
||||
page_count,
|
||||
page_flags,
|
||||
dst_mapper,
|
||||
dst_flusher,
|
||||
)
|
||||
}).map(|page| page.start_address().data())
|
||||
|
||||
}
|
||||
}
|
||||
impl Scheme for MemoryScheme {
|
||||
fn open(&self, _path: &str, _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
|
||||
Ok(0)
|
||||
fn open(&self, path: &str, _flags: usize, uid: u32, _gid: u32) -> Result<usize> {
|
||||
let intended_handle = match path.trim_start_matches('/') {
|
||||
"" => Handle::Anonymous,
|
||||
"physical" | "physical@wb" => Handle::PhysicalWb,
|
||||
"physical@uc" => Handle::PhysicalUc,
|
||||
"physical@wc" => Handle::PhysicalWc,
|
||||
|
||||
_ => return Err(Error::new(ENOENT)),
|
||||
};
|
||||
|
||||
if uid != 0 && !matches!(intended_handle, Handle::Anonymous) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
Ok(intended_handle as usize)
|
||||
}
|
||||
|
||||
fn fmap(&self, _id: usize, map: &Map) -> Result<usize> {
|
||||
Self::fmap_anonymous(&Arc::clone(context::current()?.read().addr_space()?), map)
|
||||
fn fmap(&self, id: usize, map: &Map) -> Result<usize> {
|
||||
self.kfmap(id, &AddrSpace::current()?, map, false)
|
||||
}
|
||||
|
||||
fn fcntl(&self, _id: usize, _cmd: usize, _arg: usize) -> Result<usize> {
|
||||
@@ -46,16 +135,24 @@ impl Scheme for MemoryScheme {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
impl crate::scheme::KernelScheme for MemoryScheme {
|
||||
fn kfmap(&self, _number: usize, addr_space: &Arc<RwLock<AddrSpace>>, map: &Map, _consume: bool) -> Result<usize> {
|
||||
Self::fmap_anonymous(addr_space, map)
|
||||
impl KernelScheme for MemoryScheme {
|
||||
fn kfmap(&self, id: usize, addr_space: &Arc<RwLock<AddrSpace>>, map: &Map, _consume: bool) -> Result<usize> {
|
||||
match Handle::from_raw(id).ok_or(Error::new(EBADF))? {
|
||||
Handle::Anonymous => Self::fmap_anonymous(addr_space, map),
|
||||
Handle::PhysicalWb => Self::physmap(map.offset, map.size, map.flags, MemoryType::Writeback),
|
||||
Handle::PhysicalUc => Self::physmap(map.offset, map.size, map.flags, MemoryType::Uncacheable),
|
||||
Handle::PhysicalWc => Self::physmap(map.offset, map.size, map.flags, MemoryType::WriteCombining),
|
||||
}
|
||||
}
|
||||
fn kfpath(&self, _id: usize, dst: UserSliceWo) -> Result<usize> {
|
||||
fn kfpath(&self, id: usize, dst: UserSliceWo) -> Result<usize> {
|
||||
// TODO: Copy scheme name elsewhere in the kernel?
|
||||
const SRC: &[u8] = b"memory:";
|
||||
let byte_count = core::cmp::min(SRC.len(), dst.len());
|
||||
dst.limit(byte_count).ok_or(Error::new(EINVAL))?.copy_from_slice(SRC)?;
|
||||
Ok(0)
|
||||
let src = match Handle::from_raw(id).ok_or(Error::new(EBADF))? {
|
||||
Handle::Anonymous => "memory:",
|
||||
Handle::PhysicalWb => "memory:physical@wb",
|
||||
Handle::PhysicalUc => "memory:physical@uc",
|
||||
Handle::PhysicalWc => "memory:physical@wc",
|
||||
};
|
||||
dst.copy_common_bytes_from_slice(src.as_bytes())
|
||||
}
|
||||
fn kfstatvfs(&self, _file: usize, dst: UserSliceWo) -> Result<usize> {
|
||||
let used = used_frames() as u64;
|
||||
@@ -67,9 +164,8 @@ impl crate::scheme::KernelScheme for MemoryScheme {
|
||||
f_bfree: free,
|
||||
f_bavail: free,
|
||||
};
|
||||
dst.limit(core::mem::size_of::<StatVfs>()).ok_or(Error::new(EINVAL))?.copy_from_slice(&stat)?;
|
||||
dst.copy_exactly(&stat)?;
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-43
@@ -1,13 +1,12 @@
|
||||
use crate::interrupt::InterruptStack;
|
||||
use crate::memory::{allocate_frames_complex, deallocate_frames, Frame, PAGE_SIZE};
|
||||
use crate::paging::{PageFlags, PhysicalAddress, VirtualAddress};
|
||||
use crate::paging::{PhysicalAddress, VirtualAddress};
|
||||
use crate::context;
|
||||
use crate::context::memory::Grant;
|
||||
use crate::scheme::memory::{MemoryScheme, MemoryType};
|
||||
use crate::syscall::error::{Error, EFAULT, EINVAL, ENOMEM, EPERM, ESRCH, Result};
|
||||
use crate::syscall::flag::{PhysallocFlags, PartialAllocStrategy, PhysmapFlags, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, PHYSMAP_NO_CACHE};
|
||||
use crate::syscall::flag::{MapFlags, PhysallocFlags, PartialAllocStrategy, PhysmapFlags};
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
use crate::paging::entry::EntryFlags;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
|
||||
@@ -92,49 +91,20 @@ pub fn physfree(physical_address: usize, size: usize) -> Result<usize> {
|
||||
inner_physfree(physical_address, size)
|
||||
}
|
||||
|
||||
//TODO: verify exlusive access to physical memory
|
||||
pub fn inner_physmap(physical_address: usize, size: usize, flags: PhysmapFlags) -> Result<usize> {
|
||||
// TODO: Check physical_address against MAXPHYADDR.
|
||||
let mut map_flags = MapFlags::MAP_SHARED | MapFlags::PROT_READ;
|
||||
map_flags.set(MapFlags::PROT_WRITE, flags.contains(PhysmapFlags::PHYSMAP_WRITE));
|
||||
|
||||
let end = 1 << 52;
|
||||
if (physical_address.saturating_add(size) as u64) > end || physical_address % PAGE_SIZE != 0 {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
if size % PAGE_SIZE != 0 {
|
||||
log::warn!("physmap size {} is not multiple of PAGE_SIZE {}", size, PAGE_SIZE);
|
||||
}
|
||||
let pages = size.div_ceil(PAGE_SIZE);
|
||||
|
||||
let addr_space = Arc::clone(context::current()?.read().addr_space()?);
|
||||
let mut addr_space = addr_space.write();
|
||||
|
||||
addr_space.mmap(None, pages, Default::default(), |dst_page, _, dst_mapper, dst_flusher| {
|
||||
let mut page_flags = PageFlags::new().user(true);
|
||||
if flags.contains(PHYSMAP_WRITE) {
|
||||
page_flags = page_flags.write(true);
|
||||
}
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] // TODO: AARCH64
|
||||
if flags.contains(PHYSMAP_WRITE_COMBINE) {
|
||||
page_flags = page_flags.custom_flag(EntryFlags::HUGE_PAGE.bits(), true);
|
||||
}
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] // TODO: AARCH64
|
||||
if flags.contains(PHYSMAP_NO_CACHE) {
|
||||
page_flags = page_flags.custom_flag(EntryFlags::NO_CACHE.bits(), true);
|
||||
}
|
||||
Grant::physmap(
|
||||
Frame::containing_address(PhysicalAddress::new(physical_address)),
|
||||
dst_page,
|
||||
pages,
|
||||
page_flags,
|
||||
dst_mapper,
|
||||
dst_flusher,
|
||||
)
|
||||
}).map(|page| page.start_address().data())
|
||||
let memory_type = if flags.contains(PhysmapFlags::PHYSMAP_NO_CACHE) {
|
||||
MemoryType::Uncacheable
|
||||
} else if flags.contains(PhysmapFlags::PHYSMAP_WRITE_COMBINE) {
|
||||
MemoryType::WriteCombining
|
||||
} else {
|
||||
MemoryType::Writeback
|
||||
};
|
||||
|
||||
MemoryScheme::physmap(physical_address, size, map_flags, memory_type)
|
||||
}
|
||||
// TODO: Replace physmap with e.g. fmap fd=`memory:physical@wc` or `memory:physical@uncacheable`,
|
||||
// or represent memory types as fmap flags.
|
||||
pub fn physmap(physical_address: usize, size: usize, flags: PhysmapFlags) -> Result<usize> {
|
||||
enforce_root()?;
|
||||
inner_physmap(physical_address, size, flags)
|
||||
|
||||
+2
-3
@@ -27,14 +27,13 @@ pub use self::process::*;
|
||||
pub use self::time::*;
|
||||
pub use self::usercopy::validate_region;
|
||||
|
||||
use self::scheme::Scheme as _;
|
||||
|
||||
use self::data::{Map, SigAction, TimeSpec};
|
||||
use self::error::{Error, Result, ENOSYS};
|
||||
use self::flag::{MapFlags, PhysmapFlags, WaitFlags};
|
||||
use self::number::*;
|
||||
|
||||
use crate::context::ContextId;
|
||||
use crate::context::memory::AddrSpace;
|
||||
use crate::interrupt::InterruptStack;
|
||||
use crate::scheme::{FileHandle, SchemeNamespace, memory::MemoryScheme};
|
||||
use crate::syscall::usercopy::UserSlice;
|
||||
@@ -78,7 +77,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack
|
||||
SYS_FMAP => {
|
||||
let map = unsafe { UserSlice::ro(c, d)?.read_exact::<Map>()? };
|
||||
if b == !0 {
|
||||
MemoryScheme.fmap(!0, &map)
|
||||
MemoryScheme::fmap_anonymous(&AddrSpace::current()?, &map)
|
||||
} else {
|
||||
file_op_generic(fd, |scheme, _, number| scheme.fmap(number, &map))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user