Added convenience macro for defining host externals
This commit is contained in:
parent
86f466cdb0
commit
0775577d31
|
@ -4,135 +4,165 @@ use wasmi::{
|
|||
Signature, Trap, ValueType,
|
||||
};
|
||||
|
||||
const ADD_FUNC_INDEX: usize = 0;
|
||||
const GET_TIME_INDEX: usize = 2;
|
||||
const GET_RANDOM_INDEX: usize = 3;
|
||||
const GET_INPUT_INDEX: usize = 4;
|
||||
const PRINT_CHAR: usize = 6;
|
||||
const SEND_SIGNAL_INDEX: usize = 1;
|
||||
|
||||
pub struct HostExternals;
|
||||
impl HostExternals {
|
||||
fn check_signature(&self, index: usize, signature: &Signature) -> bool {
|
||||
let (params, ret_ty): (&[_], _) = match index {
|
||||
ADD_FUNC_INDEX => (&[ValueType::I32, ValueType::I32], Some(ValueType::I32)),
|
||||
SEND_SIGNAL_INDEX => (&[ValueType::I32, ValueType::I32], Some(ValueType::I32)),
|
||||
GET_TIME_INDEX => (&[], Some(ValueType::I32)),
|
||||
GET_RANDOM_INDEX => (&[], Some(ValueType::I32)),
|
||||
GET_INPUT_INDEX => (&[], Some(ValueType::I32)),
|
||||
PRINT_CHAR => (&[ValueType::I32], None),
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
if params.len() != signature.params().len() || ret_ty != signature.return_type() {
|
||||
false
|
||||
} else {
|
||||
params
|
||||
.iter()
|
||||
.zip(signature.params())
|
||||
.find(|(ty, param)| ty != param)
|
||||
.is_none()
|
||||
}
|
||||
}
|
||||
macro_rules! wasmi_type {
|
||||
(bool) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(u8) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(u16) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(u32) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(u64) => {
|
||||
ValueType::I64
|
||||
};
|
||||
(i8) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(i16) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(i32) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(i64) => {
|
||||
ValueType::I64
|
||||
};
|
||||
(f32) => {
|
||||
ValueType::F32
|
||||
};
|
||||
(f64) => {
|
||||
ValueType::F64
|
||||
};
|
||||
}
|
||||
|
||||
impl Externals for HostExternals {
|
||||
fn invoke_index(
|
||||
&mut self,
|
||||
index: usize,
|
||||
args: RuntimeArgs,
|
||||
) -> Result<Option<RuntimeValue>, Trap> {
|
||||
match index {
|
||||
ADD_FUNC_INDEX => {
|
||||
let a: u32 = args.nth_checked(0)?;
|
||||
let b: u32 = args.nth_checked(1)?;
|
||||
let result = a + b;
|
||||
trace!("SYSCALL: {} + {} = {}", a, b, result);
|
||||
Ok(Some(RuntimeValue::I32(result as i32)))
|
||||
}
|
||||
macro_rules! wasmi_return_type {
|
||||
() => {
|
||||
None
|
||||
};
|
||||
($type: ident) => {
|
||||
Some(wasmi_type!($type))
|
||||
};
|
||||
}
|
||||
|
||||
SEND_SIGNAL_INDEX => {
|
||||
let pid: u32 = args.nth_checked(0)?;
|
||||
let signal: u32 = args.nth_checked(1)?;
|
||||
|
||||
trace!("SYSCALL: send signal {} to pid {}", signal, pid);
|
||||
let ret = RuntimeValue::I32(0);
|
||||
Ok(Some(ret))
|
||||
}
|
||||
|
||||
GET_TIME_INDEX => {
|
||||
use core::sync::atomic::Ordering::*;
|
||||
trace!("SYSCALL: get time");
|
||||
|
||||
x86_64::instructions::interrupts::disable();
|
||||
let tick_time = kernel::TICK.load(Relaxed);
|
||||
x86_64::instructions::interrupts::enable();
|
||||
|
||||
let ret = RuntimeValue::I32(tick_time.try_into().unwrap());
|
||||
Ok(Some(ret))
|
||||
}
|
||||
|
||||
GET_RANDOM_INDEX => {
|
||||
trace!("SYSCALL: get random");
|
||||
let rand = generate_process_pass();
|
||||
|
||||
let ret = RuntimeValue::I32(rand as i32);
|
||||
|
||||
// let ret = RuntimeValue::I32(rand.try_into().unwrap());
|
||||
Ok(Some(ret))
|
||||
}
|
||||
|
||||
GET_INPUT_INDEX => {
|
||||
let input = None;
|
||||
x86_64::instructions::interrupts::without_interrupts(|| KEYBUFF.lock().pop());
|
||||
if let Some(chr) = input {
|
||||
trace!("SYSCALL: input: {}", chr);
|
||||
macro_rules! host_externals {
|
||||
(
|
||||
$($index: literal: $name: ident ($($arg_name: ident: $arg_type: ident),* $(,)?) $(-> $return_type: ident)? $block: block)*
|
||||
) => {
|
||||
pub struct HostExternals;
|
||||
impl Externals for HostExternals {
|
||||
fn invoke_index(
|
||||
&mut self,
|
||||
index: usize,
|
||||
args: RuntimeArgs
|
||||
) -> Result<Option<RuntimeValue>, Trap> {
|
||||
match index {
|
||||
$(
|
||||
$index => match args.as_ref() {
|
||||
[$($arg_name),*] => {
|
||||
$(
|
||||
let $arg_name: $arg_type = (*$arg_name)
|
||||
.try_into()
|
||||
.ok_or(wasmi::TrapKind::UnexpectedSignature)?;
|
||||
)*
|
||||
$block
|
||||
},
|
||||
_ => return Err(wasmi::TrapKind::UnexpectedSignature.into()),
|
||||
}
|
||||
),*
|
||||
_ => {
|
||||
error!("Unimplemented function at {index}");
|
||||
Err(Trap::new(wasmi::TrapKind::Unreachable))
|
||||
}
|
||||
}
|
||||
|
||||
let ret = RuntimeValue::I32(input.unwrap_or(0x00 as char) as i32);
|
||||
|
||||
Ok(Some(ret))
|
||||
}
|
||||
|
||||
PRINT_CHAR => {
|
||||
let chr: u8 = args.nth_checked(0)?;
|
||||
trace!("SYSCALL: print: {}", chr);
|
||||
print!("{}", char::from(chr));
|
||||
Ok(None)
|
||||
}
|
||||
_ => {
|
||||
error!("Unimplemented function at {}", index);
|
||||
Err(Trap::new(wasmi::TrapKind::Unreachable))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleImportResolver for HostExternals {
|
||||
fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result<FuncRef, Error> {
|
||||
let (index, param_types, return_type): (usize, &[ValueType], Option<ValueType>) =
|
||||
match field_name {
|
||||
$(
|
||||
stringify!($name) => (
|
||||
$index,
|
||||
&[$(wasmi_type!($arg_type)),*],
|
||||
wasmi_return_type!($($return_type)?),
|
||||
),
|
||||
)*
|
||||
_ => {
|
||||
return Err(Error::Instantiation(format!(
|
||||
"Export {field_name} not found",
|
||||
)));
|
||||
},
|
||||
};
|
||||
|
||||
if !(param_types.len() != signature.params().len() || return_type != signature.return_type())
|
||||
&& param_types
|
||||
.iter()
|
||||
.zip(signature.params())
|
||||
.find(|(ty, param)| ty != param)
|
||||
.is_none()
|
||||
{
|
||||
trace!("Resolved export {field_name} at func {index}");
|
||||
Ok(FuncInstance::alloc_host(signature.clone(), index))
|
||||
} else {
|
||||
Err(Error::Instantiation(format!(
|
||||
"Export {field_name} has a bad signature {signature:?}",
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl ModuleImportResolver for HostExternals {
|
||||
fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result<FuncRef, Error> {
|
||||
let index = match field_name {
|
||||
"add" => ADD_FUNC_INDEX,
|
||||
"send_signal" => SEND_SIGNAL_INDEX,
|
||||
"get_time" => GET_TIME_INDEX,
|
||||
"get_random" => GET_RANDOM_INDEX,
|
||||
"get_input" => GET_INPUT_INDEX,
|
||||
"print_char" => PRINT_CHAR,
|
||||
_ => {
|
||||
return Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
}
|
||||
};
|
||||
host_externals! {
|
||||
0: add(a: u32, b: u32) -> u32 {
|
||||
let result = a + b;
|
||||
trace!("SYSCALL: {} + {} = {}", a, b, result);
|
||||
Ok(Some(result.into()))
|
||||
}
|
||||
|
||||
if !self.check_signature(index, signature) {
|
||||
return Err(Error::Instantiation(format!(
|
||||
"Export {} has a bad signature {:?}",
|
||||
field_name, signature
|
||||
)));
|
||||
1: send_signal(pid: u32, signal: u32) -> i32 {
|
||||
trace!("SYSCALL: send signal {} to pid {}", signal, pid);
|
||||
Ok(Some(0.into()))
|
||||
}
|
||||
|
||||
2: get_time() -> u32 {
|
||||
use core::sync::atomic::Ordering::*;
|
||||
trace!("SYSCALL: get time");
|
||||
|
||||
x86_64::instructions::interrupts::disable();
|
||||
let tick_time = kernel::TICK.load(Relaxed);
|
||||
x86_64::instructions::interrupts::enable();
|
||||
|
||||
let ret: u32 = tick_time.try_into().unwrap();
|
||||
Ok(Some(ret.into()))
|
||||
}
|
||||
|
||||
3: get_random() -> i32 {
|
||||
trace!("SYSCALL: get random");
|
||||
let rand = generate_process_pass() as i32;
|
||||
Ok(Some(rand.into()))
|
||||
}
|
||||
|
||||
4: get_input() -> i32 {
|
||||
let input = None;
|
||||
x86_64::instructions::interrupts::without_interrupts(|| KEYBUFF.lock().pop());
|
||||
if let Some(chr) = input {
|
||||
trace!("SYSCALL: input: {}", chr);
|
||||
}
|
||||
|
||||
trace!("Resolved export {} as func {}", field_name, index);
|
||||
Ok(FuncInstance::alloc_host(signature.clone(), index))
|
||||
let ret = input.unwrap_or(0x00 as char) as i32;
|
||||
Ok(Some(ret.into()))
|
||||
}
|
||||
|
||||
5: print_char(chr: u8) {
|
||||
trace!("SYSCALL: print: {}", chr);
|
||||
print!("{}", char::from(chr));
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue