#![no_std] //! Fixed-capacity INIT service declarations with no resource acquisition. use turkos_os_user_runtime_abi::compatible; pub const MAX_SERVICES: usize = 8; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Budget { pub pages: u32, pub handles: u32, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Entry { pub id: u16, pub required_abi: u64, pub image_sha256: [u8; 32], pub pages: u16, pub handles: u8, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { Empty, TooMany, InvalidId(usize), Duplicate { first: usize, second: usize }, MissingImage(usize), UnsupportedAbi(usize), ZeroPages(usize), BudgetExceeded { pages: u32, handles: u32 }, } pub struct Manifest { entries: [Entry; N], budget: Budget, } /// Only validation produces this token. INIT may pass it to later start logic. pub struct Validated { entries: [Entry; N], budget: Budget, } impl Manifest { pub const fn new(entries: [Entry; N], budget: Budget) -> Self { Self { entries, budget } } pub fn validate(self) -> Result, Error> { if N == 0 { return Err(Error::Empty); } if N > MAX_SERVICES { return Err(Error::TooMany); } let mut pages = 0u32; let mut handles = 0u32; for (index, entry) in self.entries.iter().enumerate() { if entry.id == 0 { return Err(Error::InvalidId(index)); } if entry.image_sha256 == [0; 32] { return Err(Error::MissingImage(index)); } if compatible(entry.required_abi, 2).is_err() { return Err(Error::UnsupportedAbi(index)); } if entry.pages == 0 { return Err(Error::ZeroPages(index)); } for first in 0..index { if self.entries[first].id == entry.id { return Err(Error::Duplicate { first, second: index }); } } pages += u32::from(entry.pages); handles += u32::from(entry.handles); } if pages > self.budget.pages || handles > self.budget.handles { return Err(Error::BudgetExceeded { pages, handles }); } Ok(Validated { entries: self.entries, budget: self.budget }) } } impl Validated { pub const fn entries(&self) -> &[Entry; N] { &self.entries } pub const fn budget(&self) -> Budget { self.budget } pub fn into_entries(self) -> [Entry; N] { self.entries } }