feat(kernel): per-process budgets (pages, endpoints, notifs, regions) carved from creator, returned on death; init owns pool

This commit is contained in:
2026-10-27 15:08:58 +01:00
parent 7415bab7f5
commit 4049ba5007
46 changed files with 672 additions and 119 deletions

View File

@@ -91,22 +91,13 @@ impl<P: Platform> Kernel<P> {
}
fn quota_mut(&mut self, pid: ProcessId) -> Result<&mut Quota, KernelError> {
self.quotas
.get_mut(pid.raw() as usize)
.ok_or(KernelError::InvalidProcess(pid))
self.budget_mut(pid).map(|b| &mut b.pages)
}
pub fn page_usage(&self, pid: ProcessId) -> usize {
self.quotas.get(pid.raw() as usize).map_or(0, Quota::used)
}
pub fn set_page_limit(&mut self, pid: ProcessId, limit: usize) -> Result<(), KernelError> {
self.processes.get(pid)?;
if self.quota_mut(pid)?.set_limit(limit) {
Ok(())
} else {
Err(KernelError::OutOfMemory)
}
self.budgets
.get(pid.raw() as usize)
.map_or(0, |b| b.pages.used())
}
pub fn free_page_count(&self) -> usize {
@@ -121,10 +112,11 @@ impl<P: Platform> Kernel<P> {
pa: PhysicalAddress,
perms: PagePerms,
) -> Result<(), KernelError> {
let quota = self
.quotas
let quota = &mut self
.budgets
.get_mut(pid.raw() as usize)
.ok_or(KernelError::InvalidProcess(pid))?;
.ok_or(KernelError::InvalidProcess(pid))?
.pages;
let mut source = ChargedFrames {
frames: &mut self.frames,
quota,
@@ -136,11 +128,11 @@ impl<P: Platform> Kernel<P> {
}
pub(crate) fn create_address_space(&mut self, pid: ProcessId) -> Result<(), KernelError> {
let quota = self
.quotas
let quota = &mut self
.budgets
.get_mut(pid.raw() as usize)
.ok_or(KernelError::InvalidProcess(pid))?;
*quota = Quota::default();
.ok_or(KernelError::InvalidProcess(pid))?
.pages;
let mut source = ChargedFrames {
frames: &mut self.frames,
quota,
@@ -152,9 +144,6 @@ impl<P: Platform> Kernel<P> {
.map_err(map_error);
if created.is_err() {
self.frames.free_owned_by(pid);
if let Some(q) = self.quotas.get_mut(pid.raw() as usize) {
*q = Quota::default();
}
}
created
}
@@ -188,8 +177,8 @@ impl<P: Platform> Kernel<P> {
if let Some((pa, _)) = self.user_frame(pid, va) {
self.platform.unmap_page(pid, va);
self.frames.free(pa);
if let Some(q) = self.quotas.get_mut(pid.raw() as usize) {
q.uncharge(1);
if let Some(b) = self.budgets.get_mut(pid.raw() as usize) {
b.pages.uncharge(1);
}
}
}
@@ -200,9 +189,6 @@ impl<P: Platform> Kernel<P> {
self.teardown_regions(pid);
self.platform.destroy_address_space(pid);
self.frames.free_owned_by(pid);
if let Some(q) = self.quotas.get_mut(pid.raw() as usize) {
*q = Quota::default();
}
if let Some(c) = self.heap_cursors.get_mut(pid.raw() as usize) {
*c = 0;
}

View File

@@ -28,7 +28,9 @@ impl<P: Platform> Kernel<P> {
self.processes.get(owner)?;
let id = self.regions.next_free_id().ok_or(KernelError::NoFreeSlot)?;
let count = pages.value() as usize;
self.charge_object(owner, crate::budget::REGIONS)?;
if !self.quota_mut(owner)?.charge(count) {
self.uncharge_object(owner, crate::budget::REGIONS);
return Err(KernelError::OutOfMemory);
}
let Some(base) = self
@@ -36,6 +38,7 @@ impl<P: Platform> Kernel<P> {
.alloc_contiguous(count, |_| FrameUse::Region { region: id })
else {
self.quota_mut(owner)?.uncharge(count);
self.uncharge_object(owner, crate::budget::REGIONS);
return Err(KernelError::OutOfMemory);
};
for i in 0..count {
@@ -76,9 +79,11 @@ impl<P: Platform> Kernel<P> {
if overlaps {
return Err(KernelError::AddressInUse);
}
self.charge_object(owner, crate::budget::REGIONS)?;
self.regions
.insert(Region::new(owner, RegionBacking::Device, base, pages))
.ok_or(KernelError::NoFreeSlot)
.inspect_err(|_| self.uncharge_object(owner, crate::budget::REGIONS))
}
pub fn region_base(&self, id: RegionId) -> Option<PhysicalAddress> {