proc: implement basic mmap with files, real_program in arg
This commit is contained in:
parent
d910e8c1a0
commit
7fdc57fd9f
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1292,6 +1292,7 @@ dependencies = [
|
||||
name = "libk-mm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"kernel-arch",
|
||||
"libk-mm-interface",
|
||||
"libk-util",
|
||||
@ -2909,6 +2910,7 @@ dependencies = [
|
||||
name = "ygg_driver_virtio_gpu"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytemuck",
|
||||
"device-api",
|
||||
"libk",
|
||||
|
@ -160,7 +160,7 @@ impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceI
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
unsafe fn unmap_page(&mut self, _address: usize) -> Result<PhysicalAddress, Error> {
|
||||
unsafe fn unmap_page(&mut self, _address: usize) -> Result<(PhysicalAddress, bool), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceI
|
||||
self.write_l3_entry(address, PageEntry::page(physical, flags.into()), false)
|
||||
}
|
||||
|
||||
unsafe fn unmap_page(&mut self, address: usize) -> Result<PhysicalAddress, Error> {
|
||||
unsafe fn unmap_page(&mut self, address: usize) -> Result<(PhysicalAddress, bool), Error> {
|
||||
self.pop_l3_entry(address)
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ impl<TA: TableAllocator> ProcessAddressSpaceImpl<TA> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pop_l3_entry(&mut self, virt: usize) -> Result<PhysicalAddress, Error> {
|
||||
fn pop_l3_entry(&mut self, virt: usize) -> Result<(PhysicalAddress, bool), Error> {
|
||||
let l0i = virt.page_index::<L0>();
|
||||
let l1i = virt.page_index::<L1>();
|
||||
let l2i = virt.page_index::<L2>();
|
||||
@ -123,13 +123,14 @@ impl<TA: TableAllocator> ProcessAddressSpaceImpl<TA> {
|
||||
let mut l3 = l2.get_mut(l2i).ok_or(Error::DoesNotExist)?;
|
||||
|
||||
let page = l3[l3i].as_page().ok_or(Error::DoesNotExist)?;
|
||||
let dirty = l3[l3i].is_dirty();
|
||||
|
||||
l3[l3i] = PageEntry::INVALID;
|
||||
unsafe {
|
||||
flush_tlb_entry(virt);
|
||||
}
|
||||
|
||||
Ok(page)
|
||||
Ok((page, dirty))
|
||||
}
|
||||
|
||||
fn read_l3_entry(&self, virt: usize) -> Option<(PhysicalAddress, MapAttributes)> {
|
||||
|
@ -31,6 +31,8 @@ bitflags! {
|
||||
/// For tables, allows user access to further translation levels, for pages/blocks, allows
|
||||
/// user access to the region covered by the entry
|
||||
const USER = 1 << 2;
|
||||
/// If set, the page has been written to
|
||||
const DIRTY = 1 << 6;
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,6 +105,10 @@ impl PageEntry<L3> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_dirty(&self) -> bool {
|
||||
self.0 & PageAttributes::DIRTY.bits() != 0
|
||||
}
|
||||
}
|
||||
|
||||
impl PageEntry<L2> {
|
||||
|
@ -17,6 +17,7 @@ use libk::{
|
||||
};
|
||||
use libk_mm::{
|
||||
address::PhysicalAddress, device::DeviceMemoryIo, table::MapAttributes, PageProvider,
|
||||
VirtualPage,
|
||||
};
|
||||
use libk_util::{sync::IrqSafeSpinlock, waker::QueueWaker, OneTimeInit};
|
||||
use tock_registers::interfaces::{Readable, Writeable};
|
||||
@ -365,8 +366,21 @@ impl Device for AhciPort {
|
||||
}
|
||||
|
||||
impl PageProvider for AhciPort {
|
||||
fn get_page(&self, _offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
todo!()
|
||||
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_page(&self, _offset: u64) -> Result<VirtualPage, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn release_page(
|
||||
&self,
|
||||
_offset: u64,
|
||||
_phys: PhysicalAddress,
|
||||
_dirty: bool,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn clone_page(
|
||||
@ -375,10 +389,6 @@ impl PageProvider for AhciPort {
|
||||
_src_phys: PhysicalAddress,
|
||||
_src_attrs: MapAttributes,
|
||||
) -> Result<PhysicalAddress, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn release_page(&self, _offset: u64, _phys: PhysicalAddress) -> Result<(), Error> {
|
||||
todo!()
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use libk::{
|
||||
use libk_mm::{
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
table::MapAttributes,
|
||||
PageProvider, PageSlice,
|
||||
PageProvider, PageSlice, VirtualPage,
|
||||
};
|
||||
|
||||
use crate::{command::IdentifyNamespaceRequest, register_nvme_namespace, IoDirection};
|
||||
@ -151,8 +151,21 @@ impl BlockDevice for NvmeNamespace {
|
||||
}
|
||||
|
||||
impl PageProvider for NvmeNamespace {
|
||||
fn get_page(&self, _offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
todo!()
|
||||
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_page(&self, _offset: u64) -> Result<VirtualPage, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn release_page(
|
||||
&self,
|
||||
_offset: u64,
|
||||
_phys: PhysicalAddress,
|
||||
_dirty: bool,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn clone_page(
|
||||
@ -161,10 +174,6 @@ impl PageProvider for NvmeNamespace {
|
||||
_src_phys: PhysicalAddress,
|
||||
_src_attrs: MapAttributes,
|
||||
) -> Result<PhysicalAddress, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn release_page(&self, _offset: u64, _phys: PhysicalAddress) -> Result<(), Error> {
|
||||
todo!()
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ use libk::{
|
||||
fs::devfs,
|
||||
task::{runtime, sync::AsyncMutex},
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider};
|
||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider, VirtualPage};
|
||||
use libk_util::{
|
||||
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
|
||||
OneTimeInit,
|
||||
@ -278,12 +278,21 @@ impl BlockDevice for ScsiUnit {
|
||||
}
|
||||
|
||||
impl PageProvider for ScsiUnit {
|
||||
fn get_page(&self, _offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
Err(Error::NotImplemented)
|
||||
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn release_page(&self, _offset: u64, _phys: PhysicalAddress) -> Result<(), Error> {
|
||||
Err(Error::NotImplemented)
|
||||
fn get_page(&self, _offset: u64) -> Result<VirtualPage, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn release_page(
|
||||
&self,
|
||||
_offset: u64,
|
||||
_phys: PhysicalAddress,
|
||||
_dirty: bool,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn clone_page(
|
||||
@ -292,7 +301,7 @@ impl PageProvider for ScsiUnit {
|
||||
_src_phys: PhysicalAddress,
|
||||
_src_attrs: MapAttributes,
|
||||
) -> Result<PhysicalAddress, Error> {
|
||||
Err(Error::NotImplemented)
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,8 +135,9 @@ impl<'a> DirentIter<'a> {
|
||||
let dirent_struct_end = self.offset + size_of::<Dirent>();
|
||||
let dirent: &Dirent = bytemuck::from_bytes(&self.block[self.offset..dirent_struct_end]);
|
||||
let record_size = (dirent.ent_size as usize).max(size_of::<Dirent>());
|
||||
let end = (self.offset + record_size).min(self.block.len());
|
||||
let record = Record {
|
||||
data: &self.block[self.offset..self.offset + record_size],
|
||||
data: &self.block[self.offset..end],
|
||||
fs: self.fs,
|
||||
offset: self.offset,
|
||||
};
|
||||
|
@ -183,6 +183,7 @@ impl<'a, A: BlockAllocator> BVec<'a, A> {
|
||||
let block = unsafe { self.index_unchecked_mut(index) };
|
||||
assert!(block.is_null());
|
||||
*block = BlockData::new()?;
|
||||
block.fill(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
|
||||
use libk::vfs::{
|
||||
@ -6,7 +8,7 @@ use libk::vfs::{
|
||||
};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{block::BlockAllocator, file::FileNode, MemoryFilesystem};
|
||||
use crate::{block::BlockAllocator, file::FileNode, MemoryFilesystem, INO_COUNTER};
|
||||
|
||||
pub(crate) struct DirectoryNode<A: BlockAllocator> {
|
||||
fs: Arc<MemoryFilesystem<A>>,
|
||||
@ -31,7 +33,8 @@ impl<A: BlockAllocator> DirectoryImpl for DirectoryNode<A> {
|
||||
}
|
||||
|
||||
fn create_node(&self, _parent: &NodeRef, info: &CreateInfo) -> Result<NodeRef, Error> {
|
||||
let metadata = Metadata::now(info.uid, info.gid, info.mode);
|
||||
let ino = INO_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
let metadata = Metadata::now(info.uid, info.gid, info.mode, ino);
|
||||
match info.ty {
|
||||
CreateFileType::File => Ok(FileNode::<A>::new(self.fs.clone(), metadata)),
|
||||
CreateFileType::Directory => Ok(DirectoryNode::<A>::new(self.fs.clone(), metadata)),
|
||||
|
@ -4,7 +4,10 @@
|
||||
#![allow(clippy::new_without_default, clippy::new_ret_no_self)]
|
||||
#![feature(maybe_uninit_uninit_array, maybe_uninit_array_assume_init)]
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use core::{
|
||||
marker::PhantomData,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use block::BlockAllocator;
|
||||
@ -57,6 +60,8 @@ mod dir;
|
||||
mod file;
|
||||
mod tar;
|
||||
|
||||
static INO_COUNTER: AtomicU32 = AtomicU32::new(1);
|
||||
|
||||
/// In-memory read/write filesystem
|
||||
pub struct MemoryFilesystem<A: BlockAllocator> {
|
||||
root: IrqSafeSpinlock<Option<NodeRef>>,
|
||||
@ -91,7 +96,8 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
|
||||
return Err(Error::DoesNotExist);
|
||||
}
|
||||
|
||||
let node = DirectoryNode::<A>::new(self.clone(), Metadata::now_root(mode));
|
||||
let ino = INO_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
let node = DirectoryNode::<A>::new(self.clone(), Metadata::now_root(mode, ino));
|
||||
at.add_child(filename, node.clone())?;
|
||||
|
||||
node
|
||||
@ -114,11 +120,15 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
|
||||
let kind = hdr.node_kind();
|
||||
let mode = usize::from(&hdr.mode);
|
||||
let mode = FileMode::new(0o777 & (mode as u32));
|
||||
let ino = INO_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
match kind {
|
||||
FileType::File => Ok(FileNode::<A>::new(self.clone(), Metadata::now_root(mode))),
|
||||
FileType::File => Ok(FileNode::<A>::new(
|
||||
self.clone(),
|
||||
Metadata::now_root(mode, ino),
|
||||
)),
|
||||
FileType::Directory => Ok(DirectoryNode::<A>::new(
|
||||
self.clone(),
|
||||
Metadata::now_root(mode),
|
||||
Metadata::now_root(mode, ino),
|
||||
)),
|
||||
FileType::Symlink => {
|
||||
let target = hdr.symlink_target()?;
|
||||
@ -129,7 +139,8 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
|
||||
}
|
||||
|
||||
fn from_slice_internal(self: &Arc<Self>, tar_data: &'static [u8]) -> Result<NodeRef, Error> {
|
||||
let root = DirectoryNode::<A>::new(self.clone(), Metadata::now_root(FileMode::new(0o755)));
|
||||
let root =
|
||||
DirectoryNode::<A>::new(self.clone(), Metadata::now_root(FileMode::new(0o755), 0));
|
||||
|
||||
// 1. Create paths in tar
|
||||
for item in TarIterator::new(tar_data) {
|
||||
|
@ -17,7 +17,7 @@ use libk::{
|
||||
fs::devfs,
|
||||
task::runtime,
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider};
|
||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider, VirtualPage};
|
||||
use libk_util::sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock};
|
||||
use ygg_driver_pci::{
|
||||
device::{PciDeviceInfo, PreferredInterruptMode},
|
||||
@ -329,8 +329,21 @@ impl<T: Transport + 'static> BlockDevice for VirtioBlk<T> {
|
||||
}
|
||||
|
||||
impl<T: Transport + 'static> PageProvider for VirtioBlk<T> {
|
||||
fn get_page(&self, _offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
todo!()
|
||||
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_page(&self, _offset: u64) -> Result<VirtualPage, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn release_page(
|
||||
&self,
|
||||
_offset: u64,
|
||||
_phys: PhysicalAddress,
|
||||
_dirty: bool,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn clone_page(
|
||||
@ -339,11 +352,7 @@ impl<T: Transport + 'static> PageProvider for VirtioBlk<T> {
|
||||
_src_phys: PhysicalAddress,
|
||||
_src_attrs: MapAttributes,
|
||||
) -> Result<PhysicalAddress, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn release_page(&self, _offset: u64, _phys: PhysicalAddress) -> Result<(), Error> {
|
||||
todo!()
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ ygg_driver_pci = { path = "../../bus/pci", optional = true }
|
||||
|
||||
log.workspace = true
|
||||
bytemuck.workspace = true
|
||||
async-trait.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
@ -5,7 +5,8 @@ extern crate alloc;
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
use async_trait::async_trait;
|
||||
use command::{CommandExecution, ScanoutInfo};
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
@ -23,7 +24,7 @@ use libk::{
|
||||
use libk_mm::{
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
table::MapAttributes,
|
||||
PageProvider, L3_PAGE_SIZE,
|
||||
PageProvider, VirtualPage, L3_PAGE_SIZE,
|
||||
};
|
||||
use libk_util::{
|
||||
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
|
||||
@ -293,34 +294,54 @@ impl<T: Transport + 'static> Device for VirtioGpu<T> {
|
||||
}
|
||||
|
||||
impl<T: Transport + 'static> PageProvider for VirtioGpu<T> {
|
||||
fn get_page(&self, offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
// TODO check that the page is mapped by framebuffer owner
|
||||
let config = self.config.read();
|
||||
let framebuffer = config.framebuffer.as_ref().ok_or(Error::DoesNotExist)?;
|
||||
if offset as usize + L3_PAGE_SIZE > framebuffer.dma_buffer.page_count() * L3_PAGE_SIZE {
|
||||
log::warn!(
|
||||
"virtio-gpu: offset {:#x} outside of framebuffer bounds {:#x}",
|
||||
offset,
|
||||
framebuffer.size
|
||||
);
|
||||
return Err(Error::InvalidMemoryOperation);
|
||||
}
|
||||
let phys = unsafe { framebuffer.dma_buffer.as_physical_address() }.add(offset as usize);
|
||||
// fn get_page(&self, offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
// // TODO check that the page is mapped by framebuffer owner
|
||||
// let config = self.config.read();
|
||||
// let framebuffer = config.framebuffer.as_ref().ok_or(Error::DoesNotExist)?;
|
||||
// if offset as usize + L3_PAGE_SIZE > framebuffer.dma_buffer.page_count() * L3_PAGE_SIZE {
|
||||
// log::warn!(
|
||||
// "virtio-gpu: offset {:#x} outside of framebuffer bounds {:#x}",
|
||||
// offset,
|
||||
// framebuffer.size
|
||||
// );
|
||||
// return Err(Error::InvalidMemoryOperation);
|
||||
// }
|
||||
// let phys = unsafe { framebuffer.dma_buffer.as_physical_address() }.add(offset as usize);
|
||||
//
|
||||
// Ok(phys)
|
||||
// }
|
||||
//
|
||||
// fn clone_page(
|
||||
// &self,
|
||||
// _offset: u64,
|
||||
// _src_phys: PhysicalAddress,
|
||||
// _src_attrs: MapAttributes,
|
||||
// ) -> Result<PhysicalAddress, Error> {
|
||||
// todo!()
|
||||
// }
|
||||
//
|
||||
// fn release_page(&self, _offset: u64, _phys: PhysicalAddress) -> Result<(), Error> {
|
||||
// Ok(())
|
||||
// }
|
||||
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
Ok(phys)
|
||||
fn get_page(&self, offset: u64) -> Result<VirtualPage, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn release_page(&self, offset: u64, phys: PhysicalAddress, _dirty: bool) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn clone_page(
|
||||
&self,
|
||||
_offset: u64,
|
||||
_src_phys: PhysicalAddress,
|
||||
_src_attrs: MapAttributes,
|
||||
offset: u64,
|
||||
src_phys: PhysicalAddress,
|
||||
src_attrs: MapAttributes,
|
||||
) -> Result<PhysicalAddress, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn release_page(&self, _offset: u64, _phys: PhysicalAddress) -> Result<(), Error> {
|
||||
Ok(())
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,17 @@ impl<D: RangeData> VirtualMemoryAllocator<D> {
|
||||
Ok(start_pfn)
|
||||
}
|
||||
|
||||
/// Retrieves an entry corresponding to given PF#
|
||||
pub fn get(&self, pfn: usize) -> Option<(Range<usize>, &D)> {
|
||||
match self.map.get_entry_at_point(pfn as u64) {
|
||||
Ok((range, data)) => {
|
||||
let range = range.start() as usize..range.end() as usize + 1;
|
||||
Some((range, data))
|
||||
}
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to insert given PF# range with its associated metadata as allocated memory,
|
||||
/// returning [Error] if requested range overlaps any existing allocated ranges
|
||||
pub fn insert(&mut self, start_pfn: usize, page_count: usize, data: D) -> Result<(), Error> {
|
||||
|
@ -12,6 +12,7 @@ vmalloc.workspace = true
|
||||
|
||||
libyalloc = { path = "../../../lib/libyalloc", default-features = false, features = ["dep-of-kernel"] }
|
||||
|
||||
async-trait.workspace = true
|
||||
log.workspace = true
|
||||
|
||||
[lints.rust]
|
||||
|
@ -33,7 +33,7 @@ pub trait ProcessAddressSpaceManager<TA: TableAllocator>: Sized {
|
||||
///
|
||||
/// The caller must ensure the process to which this address space belongs does not and
|
||||
/// will not access this page.
|
||||
unsafe fn unmap_page(&mut self, address: usize) -> Result<PhysicalAddress, Error>;
|
||||
unsafe fn unmap_page(&mut self, address: usize) -> Result<(PhysicalAddress, bool), Error>;
|
||||
|
||||
/// Returns the [PhysicalAddress] and [MapAttributes] associated with given virtual `address`,
|
||||
/// if one is mapped
|
||||
|
@ -21,6 +21,8 @@ use core::{
|
||||
};
|
||||
|
||||
use address::Virtualize;
|
||||
use alloc::boxed::Box;
|
||||
use async_trait::async_trait;
|
||||
use kernel_arch::{mem::PhysicalMemoryAllocator, Architecture, ArchitectureImpl};
|
||||
use libk_mm_interface::{
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
@ -60,9 +62,18 @@ pub const L2_PAGE_SIZE: usize = 1 << 21;
|
||||
#[cfg(target_arch = "x86")]
|
||||
pub const L2_PAGE_SIZE: usize = 1 << 22;
|
||||
|
||||
pub enum VirtualPage {
|
||||
OnDemand,
|
||||
Immediate(PhysicalAddress),
|
||||
}
|
||||
|
||||
pub trait PageProvider: Send + Sync {
|
||||
fn get_page(&self, offset: u64) -> Result<PhysicalAddress, Error>;
|
||||
fn release_page(&self, offset: u64, phys: PhysicalAddress) -> Result<(), Error>;
|
||||
fn ondemand_fetch(&self, opaque: u64) -> Result<PhysicalAddress, Error>;
|
||||
|
||||
fn get_page(&self, offset: u64) -> Result<VirtualPage, Error>;
|
||||
|
||||
fn release_page(&self, offset: u64, phys: PhysicalAddress, dirty: bool) -> Result<(), Error>;
|
||||
|
||||
fn clone_page(
|
||||
&self,
|
||||
offset: u64,
|
||||
|
@ -1,6 +1,10 @@
|
||||
use core::ops::{Deref, Range};
|
||||
use core::{
|
||||
cmp,
|
||||
ops::{Deref, Range},
|
||||
};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use kernel_arch::ProcessAddressSpaceImpl;
|
||||
use libk_mm_interface::{
|
||||
address::PhysicalAddress,
|
||||
@ -14,7 +18,7 @@ use yggdrasil_abi::error::Error;
|
||||
use crate::{
|
||||
phys,
|
||||
pointer::{PhysicalRef, PhysicalRefMut},
|
||||
PageProvider, TableAllocatorImpl, L3_PAGE_SIZE,
|
||||
PageProvider, TableAllocatorImpl, VirtualPage, L3_PAGE_SIZE,
|
||||
};
|
||||
|
||||
/// Describes how the physical memory is provided for the mapping
|
||||
@ -58,20 +62,27 @@ impl VirtualRangeBacking {
|
||||
}
|
||||
|
||||
impl PageProvider for VirtualRangeBacking {
|
||||
fn get_page(&self, offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
fn ondemand_fetch(&self, opaque: u64) -> Result<PhysicalAddress, Error> {
|
||||
match self {
|
||||
Self::Anonymous => phys::alloc_page(),
|
||||
Self::Anonymous => unreachable!(),
|
||||
Self::File(f) => f.file.ondemand_fetch(f.offset + opaque),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_page(&self, offset: u64) -> Result<VirtualPage, Error> {
|
||||
match self {
|
||||
Self::Anonymous => phys::alloc_page().map(VirtualPage::Immediate),
|
||||
Self::File(f) => f.file.get_page(f.offset + offset),
|
||||
}
|
||||
}
|
||||
|
||||
fn release_page(&self, offset: u64, phys: PhysicalAddress) -> Result<(), Error> {
|
||||
fn release_page(&self, offset: u64, phys: PhysicalAddress, dirty: bool) -> Result<(), Error> {
|
||||
match self {
|
||||
Self::Anonymous => unsafe {
|
||||
phys::free_page(phys);
|
||||
Ok(())
|
||||
},
|
||||
Self::File(f) => f.file.release_page(f.offset + offset, phys),
|
||||
Self::File(f) => f.file.release_page(f.offset + offset, phys, dirty),
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,16 +148,27 @@ impl<TA: TableAllocator> Inner<TA> {
|
||||
for i in 0..page_count {
|
||||
let offset = (i * L3_PAGE_SIZE) as u64;
|
||||
let virt = address + i * L3_PAGE_SIZE;
|
||||
let phys = match backing.get_page(offset) {
|
||||
let page = match backing.get_page(offset) {
|
||||
Ok(page) => page,
|
||||
Err(err) => {
|
||||
return Err((i, err));
|
||||
}
|
||||
};
|
||||
// let phys = match backing.get_page(offset) {
|
||||
// Ok(page) => page,
|
||||
// Err(err) => {
|
||||
// return Err((i, err));
|
||||
// }
|
||||
// };
|
||||
|
||||
if let Err(err) = unsafe { self.table.map_page(virt, phys, attributes) } {
|
||||
backing.release_page(offset, phys).unwrap();
|
||||
return Err((i, err));
|
||||
match page {
|
||||
VirtualPage::OnDemand => (),
|
||||
VirtualPage::Immediate(phys) => {
|
||||
if let Err(err) = unsafe { self.table.map_page(virt, phys, attributes) } {
|
||||
backing.release_page(offset, phys, false).unwrap();
|
||||
return Err((i, err));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,9 +189,9 @@ impl<TA: TableAllocator> Inner<TA> {
|
||||
let offset = (pfn - origin_pfn) * L3_PAGE_SIZE;
|
||||
let virt = pfn * L3_PAGE_SIZE;
|
||||
|
||||
let phys = self.table.unmap_page(virt)?;
|
||||
|
||||
backing.release_page(offset as u64, phys)?;
|
||||
if let Ok((phys, dirty)) = self.table.unmap_page(virt) {
|
||||
backing.release_page(offset as u64, phys, dirty)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,16 +224,16 @@ impl<TA: TableAllocator> Inner<TA> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn map_single(
|
||||
fn map_single_anon(
|
||||
&mut self,
|
||||
address: usize,
|
||||
backing: VirtualRangeBacking,
|
||||
attributes: MapAttributes,
|
||||
) -> Result<PhysicalAddress, Error> {
|
||||
let start_pfn = address / L3_PAGE_SIZE;
|
||||
self.allocator.insert(start_pfn, 1, backing.clone())?;
|
||||
self.allocator
|
||||
.insert(start_pfn, 1, VirtualRangeBacking::anonymous())?;
|
||||
|
||||
let phys = match backing.get_page(0) {
|
||||
let phys = match phys::alloc_page() {
|
||||
Ok(page) => page,
|
||||
Err(err) => {
|
||||
// Do nothing, as the page has not been allocated to this range yet
|
||||
@ -266,9 +288,13 @@ impl<TA: TableAllocator> Inner<TA> {
|
||||
let offset = ((pfn - origin_pfn) * L3_PAGE_SIZE) as u64;
|
||||
|
||||
let virt = pfn * L3_PAGE_SIZE;
|
||||
let phys = self.table.unmap_page(virt)?;
|
||||
let (phys, dirty) = match self.table.unmap_page(virt) {
|
||||
Ok(res) => res,
|
||||
Err(Error::DoesNotExist) => continue,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
|
||||
backing.release_page(offset, phys)?;
|
||||
backing.release_page(offset, phys, dirty)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -284,9 +310,13 @@ impl<TA: TableAllocator> Inner<TA> {
|
||||
let offset = ((pfn - origin_pfn) * L3_PAGE_SIZE) as u64;
|
||||
|
||||
let virt = pfn * L3_PAGE_SIZE;
|
||||
let phys = unsafe { self.table.unmap_page(virt)? };
|
||||
let (phys, dirty) = match unsafe { self.table.unmap_page(virt) } {
|
||||
Ok(res) => res,
|
||||
Err(Error::DoesNotExist) => continue,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
|
||||
backing.release_page(offset, phys)?;
|
||||
backing.release_page(offset, phys, dirty)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -325,6 +355,36 @@ impl<TA: TableAllocator> Inner<TA> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_fault(&mut self, address: usize) -> Result<(), Error> {
|
||||
// TODO hardcoded "prefetch" hint
|
||||
const PREFETCH_HINT: usize = 16;
|
||||
|
||||
let pfn = address / L3_PAGE_SIZE;
|
||||
let (pfn_range, backing) = self.allocator.get(pfn).ok_or(Error::DoesNotExist)?;
|
||||
let remaining = (pfn_range.end - pfn).min(PREFETCH_HINT);
|
||||
// TODO rollback
|
||||
for i in 0..remaining {
|
||||
let address = (pfn + i) * L3_PAGE_SIZE;
|
||||
let offset = (pfn - pfn_range.start + i) * L3_PAGE_SIZE;
|
||||
|
||||
if self.table.translate(address).is_ok() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let phys = backing.ondemand_fetch(offset as u64)?;
|
||||
// TODO don't guess attributes
|
||||
match unsafe { self.table.map_page(address, phys, MapAttributes::USER_READ) } {
|
||||
Ok(()) => (),
|
||||
Err(error) => {
|
||||
log::warn!("Failed to map on-demand resolved page: {error:?}");
|
||||
backing.release_page(offset as u64, phys, false).ok();
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<TA: TableAllocator> ProcessAddressSpace<TA> {
|
||||
@ -406,15 +466,14 @@ impl<TA: TableAllocator> ProcessAddressSpace<TA> {
|
||||
}
|
||||
|
||||
/// Adds a single-page mapping to the address space
|
||||
pub fn map_single(
|
||||
pub fn map_single_anon(
|
||||
&self,
|
||||
address: usize,
|
||||
backing: VirtualRangeBacking,
|
||||
attributes: MapAttributes,
|
||||
) -> Result<PhysicalAddress, Error> {
|
||||
assert_eq!(address & (L3_PAGE_SIZE - 1), 0);
|
||||
|
||||
self.inner.lock().map_single(address, backing, attributes)
|
||||
self.inner.lock().map_single_anon(address, attributes)
|
||||
}
|
||||
|
||||
/// Returns the [PhysicalAddress] associated with given virtual `address`,
|
||||
@ -462,6 +521,11 @@ impl<TA: TableAllocator> ProcessAddressSpace<TA> {
|
||||
let mut inner = self.inner.lock();
|
||||
unsafe { inner.clear() }
|
||||
}
|
||||
|
||||
/// Handles a translation fault, possibly fetching on-demand pages
|
||||
pub fn handle_fault(&self, address: usize) -> Result<(), Error> {
|
||||
self.inner.lock().handle_fault(address)
|
||||
}
|
||||
}
|
||||
|
||||
impl<TA: TableAllocator> Drop for ProcessAddressSpace<TA> {
|
||||
|
@ -219,7 +219,7 @@ pub fn add_kernel_log_file(parent: &NodeRef) {
|
||||
let node = Node::regular(
|
||||
LogFile,
|
||||
NodeFlags::IN_MEMORY_SIZE | NodeFlags::IN_MEMORY_PROPS,
|
||||
Some(Metadata::now_root(FileMode::new(0o400))),
|
||||
Some(Metadata::now_root(FileMode::new(0o400), 0)),
|
||||
None,
|
||||
);
|
||||
|
||||
|
@ -3,7 +3,7 @@ use core::mem::MaybeUninit;
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use device_api::device::Device;
|
||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider};
|
||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider, VirtualPage};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::dma::{DmaBuffer, DmaSlice, DmaSliceMut};
|
||||
@ -32,8 +32,21 @@ impl Partition {
|
||||
}
|
||||
|
||||
impl PageProvider for Partition {
|
||||
fn get_page(&self, _offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
todo!()
|
||||
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_page(&self, _offset: u64) -> Result<VirtualPage, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn release_page(
|
||||
&self,
|
||||
_offset: u64,
|
||||
_phys: PhysicalAddress,
|
||||
_dirty: bool,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn clone_page(
|
||||
@ -42,11 +55,7 @@ impl PageProvider for Partition {
|
||||
_src_phys: PhysicalAddress,
|
||||
_src_attrs: MapAttributes,
|
||||
) -> Result<PhysicalAddress, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn release_page(&self, _offset: u64, _phys: PhysicalAddress) -> Result<(), Error> {
|
||||
todo!()
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,9 @@ use core::mem::MaybeUninit;
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use device_api::device::Device;
|
||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider, L3_PAGE_SIZE};
|
||||
use libk_mm::{
|
||||
address::PhysicalAddress, table::MapAttributes, PageProvider, VirtualPage, L3_PAGE_SIZE,
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
bitflags,
|
||||
error::Error,
|
||||
@ -214,6 +216,34 @@ impl BlockDevice for DisplayWrapper {
|
||||
}
|
||||
|
||||
impl PageProvider for DisplayWrapper {
|
||||
// fn clone_page(
|
||||
// &self,
|
||||
// offset: u64,
|
||||
// src_phys: PhysicalAddress,
|
||||
// src_attrs: MapAttributes,
|
||||
// ) -> Result<PhysicalAddress, Error> {
|
||||
// self.device.clone_page(offset, src_phys, src_attrs)
|
||||
// }
|
||||
|
||||
// fn get_page(&self, offset: u64) -> Result<VirtualPage, Error> {
|
||||
// self.device.get_page(offset)
|
||||
// }
|
||||
|
||||
// fn release_page(&self, offset: u64, phys: PhysicalAddress) -> Result<(), Error> {
|
||||
// self.device.release_page(offset, phys)
|
||||
// }
|
||||
fn ondemand_fetch(&self, opaque: u64) -> Result<PhysicalAddress, Error> {
|
||||
self.device.ondemand_fetch(opaque)
|
||||
}
|
||||
|
||||
fn get_page(&self, offset: u64) -> Result<VirtualPage, Error> {
|
||||
self.device.get_page(offset)
|
||||
}
|
||||
|
||||
fn release_page(&self, offset: u64, phys: PhysicalAddress, dirty: bool) -> Result<(), Error> {
|
||||
self.device.release_page(offset, phys, dirty)
|
||||
}
|
||||
|
||||
fn clone_page(
|
||||
&self,
|
||||
offset: u64,
|
||||
@ -222,14 +252,6 @@ impl PageProvider for DisplayWrapper {
|
||||
) -> Result<PhysicalAddress, Error> {
|
||||
self.device.clone_page(offset, src_phys, src_attrs)
|
||||
}
|
||||
|
||||
fn get_page(&self, offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
self.device.get_page(offset)
|
||||
}
|
||||
|
||||
fn release_page(&self, offset: u64, phys: PhysicalAddress) -> Result<(), Error> {
|
||||
self.device.release_page(offset, phys)
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for DisplayWrapper {
|
||||
|
@ -60,7 +60,7 @@ pub fn add_named_char_device<S: AsRef<str>>(
|
||||
let node = Node::char(
|
||||
dev,
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
Metadata::now_root(mode),
|
||||
Metadata::now_root(mode, 0),
|
||||
None,
|
||||
);
|
||||
|
||||
@ -80,7 +80,7 @@ pub fn add_named_block_device<S: AsRef<str>>(
|
||||
let node = Node::block(
|
||||
dev,
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
Metadata::now_root(mode),
|
||||
Metadata::now_root(mode, 0),
|
||||
None,
|
||||
);
|
||||
|
||||
|
@ -118,7 +118,7 @@ impl<V: BytesAttributeOps> Attribute<V::Data> for BytesAttribute<V> {
|
||||
_pd: PhantomData::<V>,
|
||||
},
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
Some(Metadata::now_root(mode)),
|
||||
Some(Metadata::now_root(mode, 0)),
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ impl<V: StringAttributeOps> Attribute<V::Data> for StringAttribute<V> {
|
||||
_pd: PhantomData::<V>,
|
||||
},
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
Some(Metadata::now_root(mode)),
|
||||
Some(Metadata::now_root(mode, 0)),
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ impl<D> KObject<D> {
|
||||
let node = Node::directory(
|
||||
MemoryDirectory,
|
||||
NodeFlags::IN_MEMORY_SIZE | NodeFlags::IN_MEMORY_PROPS,
|
||||
Some(Metadata::now_root(FileMode::new(0o555))),
|
||||
Some(Metadata::now_root(FileMode::new(0o555), 0)),
|
||||
None,
|
||||
);
|
||||
Arc::new(Self { data, node })
|
||||
|
@ -112,14 +112,14 @@ impl<'a> ArgPlacer<'a> {
|
||||
fn setup_program_env(
|
||||
space: &ProcessAddressSpace,
|
||||
virt: usize,
|
||||
real_program: Option<&str>,
|
||||
args: &Vec<String>,
|
||||
envs: &Vec<String>,
|
||||
aux: &[AuxValue],
|
||||
) -> Result<usize, Error> {
|
||||
// TODO growing buffer
|
||||
let phys_page = space.map_single(
|
||||
let phys_page = space.map_single_anon(
|
||||
virt,
|
||||
VirtualRangeBacking::anonymous(),
|
||||
MapAttributes::USER_READ | MapAttributes::USER_WRITE | MapAttributes::NON_GLOBAL,
|
||||
)?;
|
||||
let mut buffer = unsafe { PhysicalRefMut::map_slice(phys_page, 4096) };
|
||||
@ -139,6 +139,10 @@ fn setup_program_env(
|
||||
let argv = placer.put_ptr_array(&arg_ptrs)? + virt;
|
||||
let envp = placer.put_ptr_array(&env_ptrs)? + virt;
|
||||
let auxv = placer.put_aux_array(aux)? + virt;
|
||||
let real_program = match real_program {
|
||||
Some(path) => placer.put_str(path)? + virt,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
// Put ProgramArgumentInner struct
|
||||
let arg_address = placer.position + virt;
|
||||
@ -146,6 +150,7 @@ fn setup_program_env(
|
||||
placer.put(&argv)?;
|
||||
placer.put(&envp)?;
|
||||
placer.put(&auxv)?;
|
||||
placer.put(&real_program)?;
|
||||
|
||||
Ok(arg_address)
|
||||
}
|
||||
@ -154,6 +159,7 @@ fn setup_context<P>(
|
||||
options: &LoadOptions<P>,
|
||||
space: &ProcessAddressSpace,
|
||||
image: &ProcessImage,
|
||||
image_path: &str,
|
||||
args: &Vec<String>,
|
||||
envs: &Vec<String>,
|
||||
) -> Result<TaskContextImpl, Error>
|
||||
@ -198,7 +204,7 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
let argument = setup_program_env(space, virt_args_base, args, envs, &auxv)?;
|
||||
let argument = setup_program_env(space, virt_args_base, Some(image_path), args, envs, &auxv)?;
|
||||
|
||||
let user_sp =
|
||||
virt_stack_base + USER_STACK_PAGES * 0x1000 - TaskContextImpl::USER_STACK_EXTRA_ALIGN;
|
||||
@ -241,6 +247,7 @@ fn setup_binary<S, P>(
|
||||
name: S,
|
||||
space: ProcessAddressSpace,
|
||||
image: ProcessImage,
|
||||
image_path: &str,
|
||||
args: &Vec<String>,
|
||||
envs: &Vec<String>,
|
||||
) -> Result<LoadedProcess, Error>
|
||||
@ -248,7 +255,7 @@ where
|
||||
S: Into<String>,
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let context = setup_context(options, &space, &image, args, envs)?;
|
||||
let context = setup_context(options, &space, &image, image_path, args, envs)?;
|
||||
let info = ProcessCreateInfo {
|
||||
name,
|
||||
context,
|
||||
@ -332,12 +339,12 @@ pub fn load<P: AsRef<Path>>(
|
||||
let space = ProcessAddressSpace::new()?;
|
||||
let (image, args, envs) =
|
||||
xxx_load_program(&space, ioctx, path, args, envs, !options.disable_aslr)?;
|
||||
let name = path.display();
|
||||
let name = match name.rsplit_once('/') {
|
||||
let real_path = path.display();
|
||||
let name = match real_path.rsplit_once('/') {
|
||||
Some((_, name)) => name,
|
||||
None => name,
|
||||
None => real_path,
|
||||
};
|
||||
setup_binary(options, name, space, image, &args, &envs)
|
||||
setup_binary(options, name, space, image, real_path, &args, &envs)
|
||||
}
|
||||
|
||||
pub fn load_into<P: AsRef<Path>>(
|
||||
@ -359,7 +366,7 @@ pub fn load_into<P: AsRef<Path>>(
|
||||
envs,
|
||||
!options.disable_aslr,
|
||||
)?;
|
||||
let context = setup_context(options, &space, &image, &args, &envs)?;
|
||||
let context = setup_context(options, &space, &image, path.display(), &args, &envs)?;
|
||||
|
||||
Ok((context, image))
|
||||
}
|
||||
|
@ -674,6 +674,10 @@ impl CurrentThread {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_page_fault(&self, address: usize) -> Result<(), Error> {
|
||||
self.address_space().handle_fault(address)
|
||||
}
|
||||
|
||||
/// Sets up a return frame to handle a pending signal, if any is present in the task's queue.
|
||||
///
|
||||
/// # Safety
|
||||
|
@ -12,7 +12,7 @@ use alloc::{
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use device::{BlockFile, CharFile};
|
||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider};
|
||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider, VirtualPage};
|
||||
use libk_util::{
|
||||
io::{ReadAt, WriteAt},
|
||||
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
|
||||
@ -149,8 +149,11 @@ impl File {
|
||||
let (master, slave) = pty::create(config, size)?;
|
||||
let master = Arc::new(master);
|
||||
let slave = Arc::new(slave);
|
||||
let (master_node, slave_node) =
|
||||
Node::pseudo_terminal_nodes(&master, &slave, Metadata::now_root(FileMode::new(0o644)));
|
||||
let (master_node, slave_node) = Node::pseudo_terminal_nodes(
|
||||
&master,
|
||||
&slave,
|
||||
Metadata::now_root(FileMode::new(0o644), 0),
|
||||
);
|
||||
|
||||
let master = Self::from_inner(FileInner::PtyMaster(TerminalHalfWrapper {
|
||||
half: master,
|
||||
@ -406,32 +409,38 @@ impl File {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_page_provider(&self) -> Result<&dyn PageProvider, Error> {
|
||||
match &self.inner {
|
||||
FileInner::Regular(f) => Ok(f),
|
||||
FileInner::Block(f) => Ok(f.device.0.as_ref()),
|
||||
FileInner::SharedMemory(f) => Ok(f.as_ref()),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PageProvider for File {
|
||||
fn get_page(&self, offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
match &self.inner {
|
||||
FileInner::Block(f) => f.device.get_page(offset),
|
||||
FileInner::SharedMemory(f) => f.get_page(offset),
|
||||
_ => Err(Error::InvalidOperation),
|
||||
}
|
||||
fn ondemand_fetch(&self, opaque: u64) -> Result<PhysicalAddress, Error> {
|
||||
self.as_page_provider()?.ondemand_fetch(opaque)
|
||||
}
|
||||
|
||||
fn release_page(&self, offset: u64, phys: PhysicalAddress) -> Result<(), Error> {
|
||||
match &self.inner {
|
||||
FileInner::Block(f) => f.device.release_page(offset, phys),
|
||||
FileInner::SharedMemory(f) => f.release_page(offset, phys),
|
||||
_ => Err(Error::InvalidOperation),
|
||||
}
|
||||
fn get_page(&self, offset: u64) -> Result<VirtualPage, Error> {
|
||||
self.as_page_provider()?.get_page(offset)
|
||||
}
|
||||
|
||||
fn release_page(&self, offset: u64, phys: PhysicalAddress, dirty: bool) -> Result<(), Error> {
|
||||
self.as_page_provider()?.release_page(offset, phys, dirty)
|
||||
}
|
||||
|
||||
fn clone_page(
|
||||
&self,
|
||||
_offset: u64,
|
||||
_src_phys: PhysicalAddress,
|
||||
_src_attrs: MapAttributes,
|
||||
offset: u64,
|
||||
src_phys: PhysicalAddress,
|
||||
src_attrs: MapAttributes,
|
||||
) -> Result<PhysicalAddress, Error> {
|
||||
todo!()
|
||||
self.as_page_provider()?
|
||||
.clone_page(offset, src_phys, src_attrs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,14 @@
|
||||
use alloc::boxed::Box;
|
||||
use async_trait::async_trait;
|
||||
use libk_mm::{
|
||||
address::PhysicalAddress, phys, pointer::PhysicalRef, table::MapAttributes, PageBox,
|
||||
PageProvider, VirtualPage, L3_PAGE_SIZE,
|
||||
};
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
use yggdrasil_abi::{error::Error, io::SeekFrom};
|
||||
|
||||
use super::InstanceData;
|
||||
use crate::vfs::node::NodeRef;
|
||||
use crate::{debug, vfs::node::NodeRef};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RegularFile {
|
||||
@ -109,3 +115,56 @@ impl Drop for RegularFile {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PageProvider for RegularFile {
|
||||
fn ondemand_fetch(&self, opaque: u64) -> Result<PhysicalAddress, Error> {
|
||||
assert_eq!(opaque as usize % L3_PAGE_SIZE, 0);
|
||||
let reg = self.node.as_regular()?;
|
||||
let mut page = PageBox::new_slice(0, L3_PAGE_SIZE)?;
|
||||
let len = reg.read(
|
||||
&self.node,
|
||||
self.instance_data.as_ref(),
|
||||
opaque,
|
||||
&mut page[..],
|
||||
)?;
|
||||
if len != page.len() {
|
||||
page[len..].fill(0);
|
||||
}
|
||||
let page = PageBox::into_physical_raw(page);
|
||||
Ok(page)
|
||||
}
|
||||
|
||||
fn get_page(&self, offset: u64) -> Result<VirtualPage, Error> {
|
||||
Ok(VirtualPage::OnDemand)
|
||||
}
|
||||
|
||||
fn release_page(&self, offset: u64, phys: PhysicalAddress, dirty: bool) -> Result<(), Error> {
|
||||
if dirty && self.write {
|
||||
let page = unsafe { PhysicalRef::map_slice(phys, 0x1000) };
|
||||
let reg = self.node.as_regular()?;
|
||||
let size = reg.size(&self.node)?;
|
||||
if offset < size {
|
||||
let amount = (size - offset).min(0x1000) as usize;
|
||||
reg.write(
|
||||
&self.node,
|
||||
self.instance_data.as_ref(),
|
||||
offset,
|
||||
&page[..amount],
|
||||
)?;
|
||||
} else {
|
||||
log::warn!("Writeback {phys:#x} @ {offset} beyond the end of the file {size}");
|
||||
}
|
||||
}
|
||||
unsafe { phys::free_page(phys) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clone_page(
|
||||
&self,
|
||||
offset: u64,
|
||||
src_phys: PhysicalAddress,
|
||||
src_attrs: MapAttributes,
|
||||
) -> Result<PhysicalAddress, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ where
|
||||
Node::regular(
|
||||
Self::new(read),
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
Some(Metadata::now_root(FileMode::new(0o444))),
|
||||
Some(Metadata::now_root(FileMode::new(0o444), 0)),
|
||||
None,
|
||||
)
|
||||
}
|
||||
@ -233,7 +233,7 @@ where
|
||||
Node::regular(
|
||||
Self::new(read, write),
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
Some(Metadata::now_root(FileMode::new(0o644))),
|
||||
Some(Metadata::now_root(FileMode::new(0o644), 0)),
|
||||
None,
|
||||
)
|
||||
}
|
||||
@ -374,7 +374,7 @@ impl MemoryDirectory {
|
||||
Node::directory(
|
||||
MemoryDirectory,
|
||||
NodeFlags::IN_MEMORY_PROPS | NodeFlags::IN_MEMORY_SIZE,
|
||||
Some(Metadata::now_root(mode)),
|
||||
Some(Metadata::now_root(mode, 0)),
|
||||
None,
|
||||
)
|
||||
}
|
||||
@ -458,7 +458,7 @@ pub fn read_fn_node<R: ReadFn + 'static>(read: R) -> NodeRef {
|
||||
Node::regular(
|
||||
ReadOnlyFnNode::new(read),
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
Some(Metadata::now_root(FileMode::new(0o444))),
|
||||
Some(Metadata::now_root(FileMode::new(0o444), 0)),
|
||||
None,
|
||||
)
|
||||
}
|
||||
@ -471,7 +471,7 @@ where
|
||||
let dir = Node::directory(
|
||||
MemoryDirectory,
|
||||
NodeFlags::IN_MEMORY_PROPS | NodeFlags::IN_MEMORY_SIZE,
|
||||
Some(Metadata::now_root(FileMode::new(0o555))),
|
||||
Some(Metadata::now_root(FileMode::new(0o555), 0)),
|
||||
None,
|
||||
);
|
||||
for (name, node) in it {
|
||||
@ -492,7 +492,7 @@ pub fn fixed_path_symlink_ext(target: impl Into<String>, metadata: Metadata) ->
|
||||
}
|
||||
|
||||
pub fn fixed_path_symlink(target: impl Into<String>) -> NodeRef {
|
||||
fixed_path_symlink_ext(target, Metadata::now_root(FileMode::new(0o555)))
|
||||
fixed_path_symlink_ext(target, Metadata::now_root(FileMode::new(0o555), 0))
|
||||
}
|
||||
|
||||
pub fn fixed_hardlink(target: NodeRef) -> Result<NodeRef, Error> {
|
||||
|
@ -147,7 +147,7 @@ pub struct Node {
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
pub fn now(uid: UserId, gid: GroupId, mode: FileMode) -> Metadata {
|
||||
pub fn now(uid: UserId, gid: GroupId, mode: FileMode, ino: u32) -> Metadata {
|
||||
let now = real_time().seconds();
|
||||
Metadata {
|
||||
mode,
|
||||
@ -155,14 +155,14 @@ impl Metadata {
|
||||
gid,
|
||||
ctime: now,
|
||||
mtime: now,
|
||||
inode: None,
|
||||
inode: Some(ino),
|
||||
block_size: 4096,
|
||||
block_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn now_root(mode: FileMode) -> Metadata {
|
||||
Self::now(UserId::root(), GroupId::root(), mode)
|
||||
pub fn now_root(mode: FileMode, ino: u32) -> Metadata {
|
||||
Self::now(UserId::root(), GroupId::root(), mode, ino)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use async_trait::async_trait;
|
||||
use libk_mm::{
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
table::MapAttributes,
|
||||
PageBox, PageProvider,
|
||||
PageBox, PageProvider, VirtualPage, L3_PAGE_SIZE,
|
||||
};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
@ -27,25 +28,33 @@ impl SharedMemory {
|
||||
}
|
||||
|
||||
impl PageProvider for SharedMemory {
|
||||
fn get_page(&self, offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
// TODO: magic numbers
|
||||
let index = (offset / 0x1000) as usize;
|
||||
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn get_page(&self, offset: u64) -> Result<VirtualPage, Error> {
|
||||
let index = (offset / L3_PAGE_SIZE as u64) as usize;
|
||||
self.pages
|
||||
.get(index)
|
||||
.map(|bx| unsafe { bx.as_physical_address() })
|
||||
.ok_or(Error::InvalidMemoryOperation)
|
||||
.map(VirtualPage::Immediate)
|
||||
}
|
||||
|
||||
fn release_page(&self, _offset: u64, _phys: PhysicalAddress) -> Result<(), Error> {
|
||||
// TODO track get/release?
|
||||
fn release_page(
|
||||
&self,
|
||||
_offset: u64,
|
||||
_phys: PhysicalAddress,
|
||||
_dirty: bool,
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clone_page(
|
||||
&self,
|
||||
_offset: u64,
|
||||
_src_phys: PhysicalAddress,
|
||||
_src_attrs: MapAttributes,
|
||||
offset: u64,
|
||||
src_phys: PhysicalAddress,
|
||||
src_attrs: MapAttributes,
|
||||
) -> Result<PhysicalAddress, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! x86-64 exception and interrupt handling
|
||||
use core::{arch::global_asm, mem::size_of};
|
||||
|
||||
use abi::{primitive_enum, process::Signal};
|
||||
use abi::{bitflags, primitive_enum, process::Signal};
|
||||
use kernel_arch_x86::registers::{CR2, CR3};
|
||||
use kernel_arch_x86_64::context::ExceptionFrame;
|
||||
use libk::task::thread::Thread;
|
||||
@ -112,6 +112,15 @@ impl Entry {
|
||||
|
||||
static IDT: IrqSafeRwLock<[Entry; SIZE]> = IrqSafeRwLock::new([Entry::NULL; SIZE]);
|
||||
|
||||
bitflags! {
|
||||
struct PageFaultFlags: usize {
|
||||
/// If clear, fault was caused by a non-present page entry
|
||||
const P: bit 0;
|
||||
/// If set, fault was caused by a write
|
||||
const W: bit 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn dump_user_exception(kind: ExceptionKind, frame: &ExceptionFrame) {
|
||||
let thread = Thread::current();
|
||||
log::warn!("{:?} in {} ({:?})", kind, thread.id, *thread.name.read());
|
||||
@ -135,8 +144,15 @@ fn user_exception_inner(kind: ExceptionKind, frame: &mut ExceptionFrame) {
|
||||
}
|
||||
}
|
||||
ExceptionKind::PageFault => {
|
||||
thread.raise_signal(Signal::MemoryAccessViolation);
|
||||
true
|
||||
let cr2 = CR2.get();
|
||||
let flags = PageFaultFlags::new(frame.exc_code as usize);
|
||||
|
||||
if !flags.contains(PageFaultFlags::P) && thread.handle_page_fault(cr2).is_ok() {
|
||||
false
|
||||
} else {
|
||||
thread.raise_signal(Signal::MemoryAccessViolation);
|
||||
true
|
||||
}
|
||||
}
|
||||
ExceptionKind::GeneralProtectionFault => {
|
||||
if thread.handle_breakpoint(frame) {
|
||||
|
@ -3,6 +3,8 @@
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use abi::error::Error;
|
||||
use alloc::boxed::Box;
|
||||
use async_trait::async_trait;
|
||||
use device_api::device::Device;
|
||||
use libk::device::display::{
|
||||
DisplayDevice, DisplayMode, DisplayOwner, DriverFlags, FramebufferInfo, PixelFormat,
|
||||
@ -11,7 +13,7 @@ use libk_mm::{
|
||||
address::PhysicalAddress,
|
||||
device::{DeviceMemoryAttributes, DeviceMemoryCaching, RawDeviceMemoryMapping},
|
||||
table::{EntryLevel, MapAttributes},
|
||||
PageProvider,
|
||||
PageProvider, VirtualPage,
|
||||
};
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
|
||||
@ -89,7 +91,11 @@ impl LinearFramebuffer {
|
||||
}
|
||||
|
||||
impl PageProvider for LinearFramebuffer {
|
||||
fn get_page(&self, offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn get_page(&self, offset: u64) -> Result<VirtualPage, Error> {
|
||||
let offset = offset as usize;
|
||||
if offset + L3::SIZE > self.size {
|
||||
log::warn!(
|
||||
@ -100,11 +106,16 @@ impl PageProvider for LinearFramebuffer {
|
||||
Err(Error::InvalidMemoryOperation)
|
||||
} else {
|
||||
let page = self.phys_base.add(offset);
|
||||
Ok(page)
|
||||
Ok(VirtualPage::Immediate(page))
|
||||
}
|
||||
}
|
||||
|
||||
fn release_page(&self, _offset: u64, _phys: PhysicalAddress) -> Result<(), Error> {
|
||||
fn release_page(
|
||||
&self,
|
||||
_offset: u64,
|
||||
_phys: PhysicalAddress,
|
||||
_dirty: bool,
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -116,6 +127,21 @@ impl PageProvider for LinearFramebuffer {
|
||||
) -> Result<PhysicalAddress, Error> {
|
||||
todo!()
|
||||
}
|
||||
// fn get_page(&self, offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
// }
|
||||
//
|
||||
// fn release_page(&self, _offset: u64, _phys: PhysicalAddress) -> Result<(), Error> {
|
||||
// Ok(())
|
||||
// }
|
||||
//
|
||||
// fn clone_page(
|
||||
// &self,
|
||||
// _offset: u64,
|
||||
// _src_phys: PhysicalAddress,
|
||||
// _src_attrs: MapAttributes,
|
||||
// ) -> Result<PhysicalAddress, Error> {
|
||||
// todo!()
|
||||
// }
|
||||
}
|
||||
|
||||
impl Device for LinearFramebuffer {
|
||||
|
@ -61,10 +61,7 @@ pub(crate) fn map_memory(
|
||||
pub(crate) fn unmap_memory(address: usize, len: usize) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let space = thread.address_space();
|
||||
|
||||
if len & 0xFFF != 0 {
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
let len = len.page_align_up::<L3>();
|
||||
|
||||
unsafe {
|
||||
space.unmap(address, len)?;
|
||||
|
@ -125,6 +125,8 @@ pub struct ProgramArgumentInner {
|
||||
pub envs: *const *const u8,
|
||||
/// Auxiliary value list
|
||||
pub auxv: *const AuxValue,
|
||||
/// Real program path
|
||||
pub real_program: *const u8,
|
||||
}
|
||||
|
||||
impl ProcessId {
|
||||
@ -201,6 +203,14 @@ impl ProgramArgumentInner {
|
||||
_pd: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the real program name provided, if any
|
||||
pub fn real_program(&self) -> Option<&CStr> {
|
||||
if self.real_program.is_null() {
|
||||
return None;
|
||||
}
|
||||
Some(unsafe { CStr::from_ptr(self.real_program.cast()) })
|
||||
}
|
||||
}
|
||||
|
||||
impl Signal {
|
||||
|
9
lib/libutil/Cargo.toml
Normal file
9
lib/libutil/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "libutil"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
99
lib/libutil/src/fmt.rs
Normal file
99
lib/libutil/src/fmt.rs
Normal file
@ -0,0 +1,99 @@
|
||||
use core::fmt;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct FormatSizeOptions {}
|
||||
|
||||
pub struct FormatSize(u64, FormatSizeOptions);
|
||||
|
||||
pub struct CharsWriter<'a> {
|
||||
buffer: &'a mut [u8],
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl<'a> CharsWriter<'a> {
|
||||
pub const fn new(buffer: &'a mut [u8]) -> Self {
|
||||
Self { buffer, pos: 0 }
|
||||
}
|
||||
|
||||
pub fn push_char(&mut self, ch: char) -> bool {
|
||||
let w = ch.len_utf8();
|
||||
if self.pos + w < self.buffer.len() {
|
||||
ch.encode_utf8(&mut self.buffer[self.pos..]);
|
||||
self.pos += w;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
// Safe, the implementation only allows full valid chars to be inserted
|
||||
unsafe { core::str::from_utf8_unchecked(&self.buffer[..self.pos]) }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for CharsWriter<'_> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
for ch in s.chars() {
|
||||
if !self.push_char(ch) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FormatSize {
|
||||
pub fn default(size: u64) -> Self {
|
||||
Self(size, FormatSizeOptions::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FormatSize {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use fmt::Write;
|
||||
|
||||
let mut buffer = [0; 128];
|
||||
let mut writer = CharsWriter::new(&mut buffer);
|
||||
let ilog2 = self.0.checked_ilog2().unwrap_or(0);
|
||||
let (dot, div, suffix) = match ilog2 / 10 {
|
||||
0 => (false, 1, "B"),
|
||||
1 => (true, 1024, " KiB"),
|
||||
2 => (true, 1024 * 1024, " MiB"),
|
||||
3 => (true, 1024 * 1024 * 1024, " GiB"),
|
||||
_ => (true, 1024 * 1024 * 1024 * 1024, " TiB"),
|
||||
};
|
||||
let integer = self.0 / div;
|
||||
if dot && integer < 100 {
|
||||
let fractional = (((self.0 * 1000) / div) % 1000) / 10;
|
||||
write!(writer, "{integer}.{fractional:02}{suffix}")?;
|
||||
} else {
|
||||
write!(writer, "{integer}{suffix}")?;
|
||||
}
|
||||
|
||||
let chars = writer.as_str();
|
||||
fmt::Display::fmt(chars, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use alloc::format;
|
||||
|
||||
use crate::fmt::FormatSize;
|
||||
|
||||
#[test]
|
||||
fn test_fmt_size() {
|
||||
assert_eq!(format!("{}", FormatSize::default(1023)), "1023B");
|
||||
assert_eq!(format!("{}", FormatSize::default(1024)), "1.00 KiB");
|
||||
assert_eq!(format!("{}", FormatSize::default(1025)), "1.00 KiB");
|
||||
assert_eq!(format!("{}", FormatSize::default(1111)), "1.08 KiB");
|
||||
assert_eq!(format!("{}", FormatSize::default(5000)), "4.88 KiB");
|
||||
assert_eq!(format!("{}", FormatSize::default(5000000)), "4.76 MiB");
|
||||
assert_eq!(format!("{}", FormatSize::default(5000000000)), "4.65 GiB");
|
||||
assert_eq!(
|
||||
format!("{}", FormatSize::default(5000000000000)),
|
||||
"4.54 TiB"
|
||||
);
|
||||
}
|
||||
}
|
5
lib/libutil/src/lib.rs
Normal file
5
lib/libutil/src/lib.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub mod fmt;
|
Loading…
x
Reference in New Issue
Block a user