Added convenience macro for defining host externals
This commit is contained in:
parent
86f466cdb0
commit
0775577d31
|
@ -4,104 +4,78 @@ use wasmi::{
|
||||||
Signature, Trap, ValueType,
|
Signature, Trap, ValueType,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ADD_FUNC_INDEX: usize = 0;
|
macro_rules! wasmi_type {
|
||||||
const GET_TIME_INDEX: usize = 2;
|
(bool) => {
|
||||||
const GET_RANDOM_INDEX: usize = 3;
|
ValueType::I32
|
||||||
const GET_INPUT_INDEX: usize = 4;
|
};
|
||||||
const PRINT_CHAR: usize = 6;
|
(u8) => {
|
||||||
const SEND_SIGNAL_INDEX: usize = 1;
|
ValueType::I32
|
||||||
|
};
|
||||||
pub struct HostExternals;
|
(u16) => {
|
||||||
impl HostExternals {
|
ValueType::I32
|
||||||
fn check_signature(&self, index: usize, signature: &Signature) -> bool {
|
};
|
||||||
let (params, ret_ty): (&[_], _) = match index {
|
(u32) => {
|
||||||
ADD_FUNC_INDEX => (&[ValueType::I32, ValueType::I32], Some(ValueType::I32)),
|
ValueType::I32
|
||||||
SEND_SIGNAL_INDEX => (&[ValueType::I32, ValueType::I32], Some(ValueType::I32)),
|
};
|
||||||
GET_TIME_INDEX => (&[], Some(ValueType::I32)),
|
(u64) => {
|
||||||
GET_RANDOM_INDEX => (&[], Some(ValueType::I32)),
|
ValueType::I64
|
||||||
GET_INPUT_INDEX => (&[], Some(ValueType::I32)),
|
};
|
||||||
PRINT_CHAR => (&[ValueType::I32], None),
|
(i8) => {
|
||||||
_ => return false,
|
ValueType::I32
|
||||||
|
};
|
||||||
|
(i16) => {
|
||||||
|
ValueType::I32
|
||||||
|
};
|
||||||
|
(i32) => {
|
||||||
|
ValueType::I32
|
||||||
|
};
|
||||||
|
(i64) => {
|
||||||
|
ValueType::I64
|
||||||
|
};
|
||||||
|
(f32) => {
|
||||||
|
ValueType::F32
|
||||||
|
};
|
||||||
|
(f64) => {
|
||||||
|
ValueType::F64
|
||||||
};
|
};
|
||||||
|
|
||||||
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_return_type {
|
||||||
|
() => {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
($type: ident) => {
|
||||||
|
Some(wasmi_type!($type))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
impl Externals for HostExternals {
|
||||||
fn invoke_index(
|
fn invoke_index(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
args: RuntimeArgs,
|
args: RuntimeArgs
|
||||||
) -> Result<Option<RuntimeValue>, Trap> {
|
) -> Result<Option<RuntimeValue>, Trap> {
|
||||||
match index {
|
match index {
|
||||||
ADD_FUNC_INDEX => {
|
$(
|
||||||
let a: u32 = args.nth_checked(0)?;
|
$index => match args.as_ref() {
|
||||||
let b: u32 = args.nth_checked(1)?;
|
[$($arg_name),*] => {
|
||||||
let result = a + b;
|
$(
|
||||||
trace!("SYSCALL: {} + {} = {}", a, b, result);
|
let $arg_name: $arg_type = (*$arg_name)
|
||||||
Ok(Some(RuntimeValue::I32(result as i32)))
|
.try_into()
|
||||||
}
|
.ok_or(wasmi::TrapKind::UnexpectedSignature)?;
|
||||||
|
)*
|
||||||
SEND_SIGNAL_INDEX => {
|
$block
|
||||||
let pid: u32 = args.nth_checked(0)?;
|
},
|
||||||
let signal: u32 = args.nth_checked(1)?;
|
_ => return Err(wasmi::TrapKind::UnexpectedSignature.into()),
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
error!("Unimplemented function at {index}");
|
||||||
Err(Trap::new(wasmi::TrapKind::Unreachable))
|
Err(Trap::new(wasmi::TrapKind::Unreachable))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,29 +84,85 @@ impl Externals for HostExternals {
|
||||||
|
|
||||||
impl ModuleImportResolver for HostExternals {
|
impl ModuleImportResolver for HostExternals {
|
||||||
fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result<FuncRef, Error> {
|
fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result<FuncRef, Error> {
|
||||||
let index = match field_name {
|
let (index, param_types, return_type): (usize, &[ValueType], Option<ValueType>) =
|
||||||
"add" => ADD_FUNC_INDEX,
|
match field_name {
|
||||||
"send_signal" => SEND_SIGNAL_INDEX,
|
$(
|
||||||
"get_time" => GET_TIME_INDEX,
|
stringify!($name) => (
|
||||||
"get_random" => GET_RANDOM_INDEX,
|
$index,
|
||||||
"get_input" => GET_INPUT_INDEX,
|
&[$(wasmi_type!($arg_type)),*],
|
||||||
"print_char" => PRINT_CHAR,
|
wasmi_return_type!($($return_type)?),
|
||||||
|
),
|
||||||
|
)*
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::Instantiation(format!(
|
return Err(Error::Instantiation(format!(
|
||||||
"Export {} not found",
|
"Export {field_name} not found",
|
||||||
field_name
|
)));
|
||||||
)))
|
},
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !self.check_signature(index, signature) {
|
if !(param_types.len() != signature.params().len() || return_type != signature.return_type())
|
||||||
return Err(Error::Instantiation(format!(
|
&& param_types
|
||||||
"Export {} has a bad signature {:?}",
|
.iter()
|
||||||
field_name, signature
|
.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:?}",
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Resolved export {} as func {}", field_name, index);
|
host_externals! {
|
||||||
Ok(FuncInstance::alloc_host(signature.clone(), index))
|
0: add(a: u32, b: u32) -> u32 {
|
||||||
|
let result = a + b;
|
||||||
|
trace!("SYSCALL: {} + {} = {}", a, b, result);
|
||||||
|
Ok(Some(result.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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