feat(kernel): add RequestPages and ReleasePages syscalls

This commit is contained in:
2026-10-18 00:19:24 +02:00
parent 95c023f286
commit 471d96b9a4
5 changed files with 171 additions and 0 deletions

View File

@@ -125,6 +125,10 @@ impl<P: Platform> Kernel<P> {
} }
} }
pub fn free_page_count(&self) -> usize {
self.page_pool.free_count()
}
pub fn process_exists(&self, pid: ProcessId) -> bool { pub fn process_exists(&self, pid: ProcessId) -> bool {
self.processes.get(pid).is_ok() self.processes.get(pid).is_ok()
} }

View File

@@ -16,6 +16,8 @@ impl<P: Platform> Kernel<P> {
Syscall::Yield => self.handle_yield(tid), Syscall::Yield => self.handle_yield(tid),
Syscall::Exit => self.handle_exit(tid, pid), Syscall::Exit => self.handle_exit(tid, pid),
Syscall::ExitThread => self.handle_exit_thread(tid, pid), Syscall::ExitThread => self.handle_exit_thread(tid, pid),
Syscall::RequestPages { count } => self.handle_request_pages(pid, count),
Syscall::ReleasePages { addr, count } => self.handle_release_pages(pid, addr, count),
_ => SyscallOutcome::Complete(SyscallResult::Error( _ => SyscallOutcome::Complete(SyscallResult::Error(
domain::error::KernelError::WouldBlock, domain::error::KernelError::WouldBlock,
)), )),
@@ -110,4 +112,80 @@ impl<P: Platform> Kernel<P> {
} }
} }
} }
fn handle_request_pages(
&mut self,
pid: types::id::ProcessId,
count: types::bounded::PageCount,
) -> SyscallOutcome {
let pages = count.value() as usize;
if let Some(pm) = &mut self.process_memory[pid.raw() as usize] {
if pm.grant(pages).is_err() {
return SyscallOutcome::Complete(SyscallResult::Error(
domain::error::KernelError::OutOfMemory,
));
}
} else {
return SyscallOutcome::Complete(SyscallResult::Error(
domain::error::KernelError::InvalidProcess(pid),
));
}
let addr = match self.page_pool.allocate(pages) {
Some(a) => a,
None => {
if let Some(pm) = &mut self.process_memory[pid.raw() as usize] {
let _ = pm.release(pages);
}
return SyscallOutcome::Complete(SyscallResult::Error(
domain::error::KernelError::OutOfMemory,
));
}
};
let region = domain::memory::MemoryRegion::new(
types::id::RegionId::from_raw(0),
pid,
addr,
count,
types::generation::Generation::initial(),
);
let _region_id = self.regions.insert(region);
let slot = match self.grant_cap(
pid,
domain::resource::Resource::Memory(types::id::RegionId::from_raw(0)),
types::permission::PermissionSet::empty()
.with(types::permission::Permission::Read)
.with(types::permission::Permission::Write),
) {
Ok(s) => s,
Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)),
};
SyscallOutcome::Complete(SyscallResult::Slot(slot))
}
fn handle_release_pages(
&mut self,
pid: types::id::ProcessId,
addr: types::address::VirtualAddress,
count: types::bounded::PageCount,
) -> SyscallOutcome {
let pages = count.value() as usize;
let phys = types::address::PhysicalAddress::from_raw(addr.raw());
if !self.page_pool.free(phys, pages) {
return SyscallOutcome::Complete(SyscallResult::Error(
domain::error::KernelError::OutOfMemory,
));
}
if let Some(pm) = &mut self.process_memory[pid.raw() as usize] {
let _ = pm.release(pages);
}
SyscallOutcome::Complete(SyscallResult::Ok)
}
} }

View File

@@ -0,0 +1,49 @@
use super::*;
use crate::{SyscallOutcome, SyscallResult};
use domain::syscall::Syscall;
use types::bounded::PageCount;
use types::address::VirtualAddress;
#[test]
fn request_pages_allocates_and_grants_cap() {
let (mut k, _) = kernel_with_process();
let outcome = k.handle_syscall(Syscall::RequestPages {
count: PageCount::new(4).unwrap(),
});
assert!(matches!(
outcome,
SyscallOutcome::Complete(SyscallResult::Slot(_))
));
}
#[test]
fn request_pages_reduces_pool() {
let (mut k, _) = kernel_with_process();
let before = k.free_page_count();
k.handle_syscall(Syscall::RequestPages {
count: PageCount::new(10).unwrap(),
});
assert_eq!(k.free_page_count(), before - 10);
}
#[test]
fn release_pages_frees_and_restores_pool() {
let (mut k, _) = kernel_with_process();
let before = k.free_page_count();
let slot = match k.handle_syscall(Syscall::RequestPages {
count: PageCount::new(4).unwrap(),
}) {
SyscallOutcome::Complete(SyscallResult::Slot(s)) => s,
_ => panic!("expected slot"),
};
let outcome = k.handle_syscall(Syscall::ReleasePages {
addr: VirtualAddress::from_raw(0x8000_0000),
count: PageCount::new(4).unwrap(),
});
assert!(matches!(
outcome,
SyscallOutcome::Complete(SyscallResult::Ok)
));
assert_eq!(k.free_page_count(), before);
}

View File

@@ -1,4 +1,5 @@
mod exit; mod exit;
mod memory;
mod simple; mod simple;
mod tick; mod tick;

View File

@@ -1,12 +1,42 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EntryPoint(usize); pub struct EntryPoint(usize);
impl EntryPoint {
pub fn from_raw(addr: usize) -> Self {
Self(addr)
}
pub fn raw(&self) -> usize {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct StackPointer(usize); pub struct StackPointer(usize);
impl StackPointer {
pub fn from_raw(addr: usize) -> Self {
Self(addr)
}
pub fn raw(&self) -> usize {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct VirtualAddress(usize); pub struct VirtualAddress(usize);
impl VirtualAddress {
pub fn from_raw(addr: usize) -> Self {
Self(addr)
}
pub fn raw(&self) -> usize {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PhysicalAddress(usize); pub struct PhysicalAddress(usize);
@@ -29,3 +59,12 @@ pub struct DataRef {
addr: VirtualAddress, addr: VirtualAddress,
len: usize, len: usize,
} }
impl DataRef {
pub fn empty() -> Self {
Self {
addr: VirtualAddress::from_raw(0),
len: 0,
}
}
}