proc: implement basic mmap with files, real_program in arg

This commit is contained in:
Mark Poliakov 2025-02-25 17:41:14 +02:00
parent d910e8c1a0
commit 7fdc57fd9f
40 changed files with 628 additions and 176 deletions

2
Cargo.lock generated
View File

@ -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",

View File

@ -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!()
}

View File

@ -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)> {

View File

@ -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> {

View File

@ -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!()
}
}

View File

@ -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!()
}
}

View File

@ -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!()
}
}

View File

@ -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,
};

View File

@ -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);
}
}

View File

@ -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)),

View File

@ -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) {

View File

@ -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!()
}
}

View File

@ -15,6 +15,7 @@ ygg_driver_pci = { path = "../../bus/pci", optional = true }
log.workspace = true
bytemuck.workspace = true
async-trait.workspace = true
[features]
default = []

View File

@ -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!()
}
}

View File

@ -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> {

View File

@ -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]

View File

@ -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

View File

@ -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,

View File

@ -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> {

View File

@ -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,
);

View File

@ -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!()
}
}

View File

@ -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 {

View File

@ -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,
);

View File

@ -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,
))
}

View File

@ -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,
))
}

View File

@ -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 })

View File

@ -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))
}

View File

@ -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

View File

@ -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)
}
}

View File

@ -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!()
}
}

View File

@ -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> {

View File

@ -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)
}
}

View File

@ -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!()
}

View File

@ -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) {

View File

@ -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 {

View File

@ -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)?;

View File

@ -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
View 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
View 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
View File

@ -0,0 +1,5 @@
#![no_std]
extern crate alloc;
pub mod fmt;