157 lines
4.4 KiB
Rust
157 lines
4.4 KiB
Rust
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<SyscallResolved> {
|
|
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<SyscallResolved> {
|
|
resolve_syscall_impl(module, name, version)
|
|
}
|
|
|
|
pub fn resolve_program_syscalls(
|
|
declared: &[SyscallIdentity],
|
|
caps: CapFlags,
|
|
) -> Result<Vec<SyscallResolved>, 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<Vec<SyscallResolved>, 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)
|
|
}
|