From 0775577d31e7e24c265467d727bf1b39cb60096f Mon Sep 17 00:00:00 2001 From: Erin Date: Tue, 10 May 2022 18:41:45 +0200 Subject: [PATCH] Added convenience macro for defining host externals --- ableos/src/wasm_jumploader/host_functions.rs | 268 +++++++++++-------- 1 file changed, 149 insertions(+), 119 deletions(-) diff --git a/ableos/src/wasm_jumploader/host_functions.rs b/ableos/src/wasm_jumploader/host_functions.rs index a4f4d44e..2e6157b7 100644 --- a/ableos/src/wasm_jumploader/host_functions.rs +++ b/ableos/src/wasm_jumploader/host_functions.rs @@ -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, 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, 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 { + let (index, param_types, return_type): (usize, &[ValueType], Option) = + 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 { - 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) } }