Skip to content

Commit

Permalink
mem+kernel+x86_64+examples: initial plumbing for token mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
Qix- committed Jan 25, 2025
1 parent 05c1c7a commit d48cb99
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 17 deletions.
16 changes: 14 additions & 2 deletions examples/no-std/page-alloc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion oro-arch-x86_64/src/mem/segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ unsafe impl Segment<AddressSpaceHandle> 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)?;
Expand Down
72 changes: 59 additions & 13 deletions oro-kernel/src/iface/kernel/mem_token_v0.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -13,10 +28,8 @@ impl KernelInterface for MemTokenV0 {
const TYPE_ID: u64 = oro_sysabi::id::iface::KERNEL_MEM_TOKEN_V0;

fn get<A: Arch>(thread: &Tab<Thread<A>>, 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);
};

Expand All @@ -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),
}
}
Expand All @@ -45,16 +59,48 @@ impl KernelInterface for MemTokenV0 {
thread: &Tab<Thread<A>>,
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),
}
}
}
16 changes: 16 additions & 0 deletions oro-kernel/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ impl<A: Arch> Instance<A> {
.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::<A>::user_data().provision_as_shared(handle.mapper())?;

let tab = crate::tab::get()
.add(Self {
module: module.clone(),
Expand Down Expand Up @@ -142,6 +151,13 @@ impl<A: Arch> Instance<A> {
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<Token>, virt: usize) -> Result<(), MapError> {
todo!("map token: {:016X} -> {virt:016X}", token.id());
}

/// Returns the instance's address space handle.
#[inline]
#[must_use]
Expand Down
2 changes: 1 addition & 1 deletion oro-mem/src/mapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ pub unsafe trait AddressSegment<Handle: Sized>: 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<A>(&self, space: &Handle, alloc: &A) -> Result<(), MapError>
where
A: Alloc;
Expand Down

0 comments on commit d48cb99

Please sign in to comment.