use super::{CapFlags, SyscallMeta, domains}; /// Canonical identity triple for a syscall. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct SyscallIdentity { pub module: &'static str, pub name: &'static str, pub version: u16, } impl SyscallIdentity { pub fn key(&self) -> (&'static str, &'static str, u16) { (self.module, self.name, self.version) } } /// Resolved syscall information provided to the loader/VM. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct SyscallResolved { pub id: u32, pub meta: SyscallMeta, } /// Load-time error for syscall resolution. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum LoadError { UnknownSyscall { module: &'static str, name: &'static str, version: u16, }, MissingCapability { required: CapFlags, provided: CapFlags, module: &'static str, name: &'static str, version: u16, }, } /// Load-time error for PBX-declared syscall resolution. #[derive(Debug, Clone, PartialEq, Eq)] pub enum DeclaredLoadError { UnknownSyscall { module: String, name: String, version: u16, }, MissingCapability { required: CapFlags, provided: CapFlags, module: String, name: String, version: u16, }, AbiMismatch { module: String, name: String, version: u16, declared_arg_slots: u16, declared_ret_slots: u16, expected_arg_slots: u16, expected_ret_slots: u16, }, } fn resolve_syscall_impl(module: &str, name: &str, version: u16) -> Option { for entry in domains::all_entries() { if entry.meta.module == module && entry.meta.name == name && entry.meta.version == version { return Some(SyscallResolved { id: entry.meta.id, meta: entry.meta }); } } None } pub fn resolve_syscall( module: &'static str, name: &'static str, version: u16, ) -> Option { resolve_syscall_impl(module, name, version) } pub fn resolve_program_syscalls( declared: &[SyscallIdentity], caps: CapFlags, ) -> Result, LoadError> { let mut out = Vec::with_capacity(declared.len()); for ident in declared { let Some(res) = resolve_syscall(ident.module, ident.name, ident.version) else { return Err(LoadError::UnknownSyscall { module: ident.module, name: ident.name, version: ident.version, }); }; let missing = res.meta.caps & !caps; if missing != 0 { return Err(LoadError::MissingCapability { required: res.meta.caps, provided: caps, module: ident.module, name: ident.name, version: ident.version, }); } out.push(res); } Ok(out) } pub fn resolve_declared_program_syscalls( declared: &[prometeu_bytecode::SyscallDecl], caps: CapFlags, ) -> Result, DeclaredLoadError> { let mut out = Vec::with_capacity(declared.len()); for decl in declared { let Some(res) = resolve_syscall_impl(&decl.module, &decl.name, decl.version) else { return Err(DeclaredLoadError::UnknownSyscall { module: decl.module.clone(), name: decl.name.clone(), version: decl.version, }); }; let missing = res.meta.caps & !caps; if missing != 0 { return Err(DeclaredLoadError::MissingCapability { required: res.meta.caps, provided: caps, module: decl.module.clone(), name: decl.name.clone(), version: decl.version, }); } let expected_arg_slots = u16::from(res.meta.arg_slots); let expected_ret_slots = res.meta.ret_slots; if decl.arg_slots != expected_arg_slots || decl.ret_slots != expected_ret_slots { return Err(DeclaredLoadError::AbiMismatch { module: decl.module.clone(), name: decl.name.clone(), version: decl.version, declared_arg_slots: decl.arg_slots, declared_ret_slots: decl.ret_slots, expected_arg_slots, expected_ret_slots, }); } out.push(res); } Ok(out) }