diff --git a/examples/no-std/page-alloc/src/main.rs b/examples/no-std/page-alloc/src/main.rs index 6c351f6..5b1fba9 100644 --- a/examples/no-std/page-alloc/src/main.rs +++ b/examples/no-std/page-alloc/src/main.rs @@ -41,10 +41,22 @@ fn main() { println!("token type: {:?}", Key(&ty)); - const TARGET_ADDR: usize = 0x400_0000_0000; + const TARGET_ADDR: u64 = 0x400_0000_0000; // Map it in. - // TODO: This is not yet implemented. + match syscall::set!( + KERNEL_MEM_TOKEN_V0, + KERNEL_MEM_TOKEN_V0, + token, + syscall::key!("base"), + TARGET_ADDR + ) { + Ok(_) => (), + Err((e, ex)) => { + println!("error mapping in token: {e:?}[{ex}]"); + return; + } + } // Try to read and write from it. unsafe { diff --git a/oro-arch-x86_64/src/mem/segment.rs b/oro-arch-x86_64/src/mem/segment.rs index b505ed4..6f750d1 100644 --- a/oro-arch-x86_64/src/mem/segment.rs +++ b/oro-arch-x86_64/src/mem/segment.rs @@ -519,7 +519,7 @@ unsafe impl Segment for &'static AddressSegment { let entry = &mut top_level[idx]; if entry.present() { - return Err(MapError::Exists); + continue; } let frame_phys_addr = alloc.allocate().ok_or(MapError::OutOfMemory)?; diff --git a/oro-kernel/src/iface/kernel/mem_token_v0.rs b/oro-kernel/src/iface/kernel/mem_token_v0.rs index 71528d8..0e4ec13 100644 --- a/oro-kernel/src/iface/kernel/mem_token_v0.rs +++ b/oro-kernel/src/iface/kernel/mem_token_v0.rs @@ -1,10 +1,25 @@ //! Allows for querying information about memory tokens. +use oro_mem::mapper::MapError; use oro_sysabi::{key, syscall::Error as SysError}; use super::KernelInterface; use crate::{arch::Arch, syscall::InterfaceResponse, tab::Tab, thread::Thread, token::Token}; +/// Interface specific errors. +#[derive(Debug, Clone, Copy)] +#[repr(u64)] +pub enum Error { + /// An address conflict (existing mapping) was encountered when mapping a token. + Conflict = key!("conflict"), + /// The requested address is not aligned to the page size. + NotAligned = key!("align"), + /// The requested address is out of the address space range. + OutOfRange = key!("range"), + /// The system ran out of memory trying to service the request. + OutOfMemory = key!("oom"), +} + /// Version 0 of the memory token query interface. #[repr(transparent)] pub struct MemTokenV0; @@ -13,10 +28,8 @@ impl KernelInterface for MemTokenV0 { const TYPE_ID: u64 = oro_sysabi::id::iface::KERNEL_MEM_TOKEN_V0; fn get(thread: &Tab>, index: u64, key: u64) -> InterfaceResponse { - let Some(token) = thread - .with(|t| t.instance().clone()) - .with(|i| i.token(index)) - else { + let instance = thread.with(|t| t.instance().clone()); + let Some(token) = instance.with(|i| i.token(index)) else { return InterfaceResponse::immediate(SysError::BadIndex, 0); }; @@ -34,6 +47,7 @@ impl KernelInterface for MemTokenV0 { key!("pages") => InterfaceResponse::ok(token.page_count() as u64), key!("size") => InterfaceResponse::ok(token.size() as u64), key!("commit") => InterfaceResponse::ok(token.commit() as u64), + key!("base") => InterfaceResponse::immediate(SysError::WriteOnly, 0), _ => InterfaceResponse::immediate(SysError::BadKey, 0), } } @@ -45,16 +59,48 @@ impl KernelInterface for MemTokenV0 { thread: &Tab>, index: u64, key: u64, - _value: u64, + value: u64, ) -> InterfaceResponse { - if key == key!("forget") { - let instance = thread.with(|t| t.instance().clone()); - return instance.with_mut(|i| i.forget_token(index)).map_or_else( - || InterfaceResponse::immediate(SysError::BadIndex, 0), - |_| InterfaceResponse::ok(0), - ); - } + match key { + key!("forget") => { + let instance = thread.with(|t| t.instance().clone()); + instance.with_mut(|i| i.forget_token(index)).map_or_else( + || InterfaceResponse::immediate(SysError::BadIndex, 0), + |_| InterfaceResponse::ok(0), + ) + } + key!("base") => { + let instance = thread.with(|t| t.instance().clone()); + instance.with_mut(|i| { + let Some(token) = i.token(index) else { + return InterfaceResponse::immediate(SysError::BadIndex, 0); + }; - InterfaceResponse::immediate(SysError::ReadOnly, 0) + let Ok(virt) = usize::try_from(value) else { + return InterfaceResponse::immediate( + SysError::InterfaceError, + Error::OutOfRange as u64, + ); + }; + + i.map_token(&token, virt).map_or_else( + |err| { + InterfaceResponse::immediate( + SysError::InterfaceError, + match err { + MapError::Exists => Error::Conflict as u64, + MapError::OutOfMemory => Error::OutOfMemory as u64, + MapError::VirtNotAligned => Error::NotAligned as u64, + MapError::VirtOutOfRange + | MapError::VirtOutOfAddressSpaceRange => Error::OutOfRange as u64, + }, + ) + }, + |()| InterfaceResponse::ok(0), + ) + }) + } + _ => InterfaceResponse::immediate(SysError::ReadOnly, 0), + } } } diff --git a/oro-kernel/src/instance.rs b/oro-kernel/src/instance.rs index 7c2b66a..6e11829 100644 --- a/oro-kernel/src/instance.rs +++ b/oro-kernel/src/instance.rs @@ -86,6 +86,15 @@ impl Instance { .apply_user_space_shallow(handle.mapper(), module.mapper()) })?; + // Make the entire memory space shared. + // TODO(qix-): This is a gross waste of memory, and will be addressed + // TODO(qix-): in the future to be more fine-grained. I don't have a good + // TODO(qix-): data structure written for random page fault fetches, so + // TODO(qix-): instead we share all memory between all threads + // TODO(qix-): in the instance, which requires around (255 * 4096) = 1MiB + // TODO(qix-): of memory per instance. This isn't ideal, but it works for now. + AddressSpace::::user_data().provision_as_shared(handle.mapper())?; + let tab = crate::tab::get() .add(Self { module: module.clone(), @@ -142,6 +151,13 @@ impl Instance { self.tokens.insert_tab(token) } + /// Maps a [`Token`] into the instance's address space. + /// + /// Returns the address segment of the mapping. + pub fn map_token(&self, token: &Tab, virt: usize) -> Result<(), MapError> { + todo!("map token: {:016X} -> {virt:016X}", token.id()); + } + /// Returns the instance's address space handle. #[inline] #[must_use] diff --git a/oro-mem/src/mapper.rs b/oro-mem/src/mapper.rs index 7962311..89501a2 100644 --- a/oro-mem/src/mapper.rs +++ b/oro-mem/src/mapper.rs @@ -321,7 +321,7 @@ pub unsafe trait AddressSegment: Send + 'static { /// Makes the segment shared across all address spaces. Uses the given allocator. /// - /// Returns an error if the segment is not empty. + /// **Skips any checks for emptiness;** must not return [`MapError::Exists`]. fn provision_as_shared_in(&self, space: &Handle, alloc: &A) -> Result<(), MapError> where A: Alloc;