//! The authority init starts with: per-device MMIO and IRQ capabilities plus one SystemControl. use domain::{error::KernelError, resource::Resource}; use platform::Platform; use types::{ address::PhysicalAddress, bounded::{CapSlot, PageCount}, id::{IrqId, ProcessId, RegionId}, permission::{Permission, PermissionSet}, }; use crate::Kernel; /// A device the board exposes to userspace: its MMIO window and, if it /// raises interrupts, its IRQ line. #[derive(Debug, Clone, Copy)] pub struct BoardDevice { pub base: PhysicalAddress, pub pages: PageCount, pub irq: Option, } /// Where `grant_boot_authority` put init's machine-wide capabilities. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct BootCaps { pub system_control: CapSlot, pub console: CapSlot, } /// Where `grant_boot_authority` put one device's capabilities in init. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct BoardCaps { pub region: CapSlot, pub irq: Option, } impl Kernel

{ /// Creates one device region per board device, owned by `init`; fails on the first invalid one. pub fn register_board( &mut self, init: ProcessId, devices: &[BoardDevice], ) -> Result<(), KernelError> { for device in devices { if let Some(irq) = device.irq && !self.irqs.is_valid(irq) { return Err(KernelError::InvalidIrq(irq)); } self.create_device_region(init, device.base, device.pages)?; } Ok(()) } /// Gives `init` (with Delegate) caps to every device region and IRQ, then SystemControl. /// Writes each device's slots into `placed` in order; returns the SystemControl /// and Console slots. pub fn grant_boot_authority( &mut self, init: ProcessId, devices: &[BoardDevice], placed: &mut [Option], ) -> Result { let delegate = PermissionSet::empty().with(Permission::Delegate); let control = delegate.with(Permission::Execute); let mmio = delegate.with(Permission::Read).with(Permission::Write); for (i, device) in devices.iter().enumerate() { let region = self .device_region_at(device.base) .filter(|id| self.regions.get(*id).is_some_and(|r| r.owner() == init)) .ok_or(KernelError::NoSuchObject)?; let region = self.grant_cap(init, Resource::Memory(region), mmio)?; let irq = match device.irq { Some(irq) => Some(self.grant_cap(init, Resource::Interrupt(irq), control)?), None => None, }; if let Some(slot) = placed.get_mut(i) { *slot = Some(BoardCaps { region, irq }); } } Ok(BootCaps { system_control: self.grant_cap(init, Resource::SystemControl, control)?, console: self.grant_cap(init, Resource::Console, delegate.with(Permission::Write))?, }) } /// The device region that starts at `base`. pub fn device_region_at(&self, base: PhysicalAddress) -> Option { self.regions .iter() .find(|(_, r)| r.backing() == domain::memory::RegionBacking::Device && r.base() == base) .map(|(id, _)| id) } }