mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-21 20:51:32 +00:00
kwasmd.
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2240,6 +2240,7 @@ dependencies = [
|
||||
name = "wasmer"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -19,6 +19,7 @@ include = [
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.3.1"
|
||||
errno = "0.2.4"
|
||||
structopt = "0.2.11"
|
||||
wabt = "0.7.2"
|
||||
|
@ -99,6 +99,14 @@ impl Instance for KernelInstance {
|
||||
entry_offset: self.offsets[id] as u32,
|
||||
params: &args,
|
||||
}).map_err(|x| format!("{:?}", x))?;
|
||||
Ok(ret as u64)
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn read_memory(&mut self, offset: u32, len: u32) -> Result<Vec<u8>, String> {
|
||||
self.context.read_memory(offset, len).map_err(|x| format!("{:?}", x))
|
||||
}
|
||||
|
||||
fn write_memory(&mut self, offset: u32, len: u32, buf: &[u8]) -> Result<(), String> {
|
||||
self.context.write_memory(offset, len, buf).map_err(|x| format!("{:?}", x))
|
||||
}
|
||||
}
|
@ -17,6 +17,8 @@ macro_rules! impl_debug_display {
|
||||
pub enum Command {
|
||||
LoadCode = 0x1001,
|
||||
RunCode = 0x1002,
|
||||
ReadMemory = 0x1003,
|
||||
WriteMemory = 0x1004,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -67,6 +69,27 @@ struct RunCodeRequest {
|
||||
entry_offset: u32,
|
||||
params: *const u64,
|
||||
param_count: u32,
|
||||
result: *mut RunCodeResult,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct RunCodeResult {
|
||||
success: u32,
|
||||
retval: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct ReadMemoryRequest {
|
||||
out: *mut u8,
|
||||
offset: u32,
|
||||
len: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct WriteMemoryRequest {
|
||||
_in: *const u8,
|
||||
offset: u32,
|
||||
len: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@ -144,20 +167,75 @@ impl ServiceContext {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_code(&mut self, run: RunProfile) -> ServiceResult<i32> {
|
||||
let req = RunCodeRequest {
|
||||
pub fn run_code(&mut self, run: RunProfile) -> ServiceResult<u64> {
|
||||
let mut result: RunCodeResult = unsafe { ::std::mem::zeroed() };
|
||||
let mut req = RunCodeRequest {
|
||||
entry_offset: run.entry_offset,
|
||||
params: run.params.as_ptr(),
|
||||
param_count: run.params.len() as u32,
|
||||
result: &mut result,
|
||||
};
|
||||
let fd = self.dev.as_raw_fd();
|
||||
let ret = unsafe {
|
||||
let err = unsafe {
|
||||
::libc::ioctl(
|
||||
fd,
|
||||
Command::RunCode as i32 as ::libc::c_ulong,
|
||||
&mut req as *mut _ as ::libc::c_ulong
|
||||
)
|
||||
};
|
||||
if err < 0 {
|
||||
Err(ServiceError::Code(err))
|
||||
} else if result.success == 0 {
|
||||
println!("Rejected {} {}", result.success, result.retval);
|
||||
Err(ServiceError::Rejected)
|
||||
} else {
|
||||
Ok(result.retval)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_memory(&mut self, offset: u32, len: u32) -> ServiceResult<Vec<u8>> {
|
||||
let fd = self.dev.as_raw_fd();
|
||||
let mut ret = Vec::with_capacity(len as usize);
|
||||
unsafe {
|
||||
ret.set_len(len as usize);
|
||||
}
|
||||
let req = ReadMemoryRequest {
|
||||
out: ret.as_mut_ptr(),
|
||||
offset: offset,
|
||||
len: len,
|
||||
};
|
||||
let err = unsafe {
|
||||
::libc::ioctl(
|
||||
fd,
|
||||
Command::ReadMemory as i32 as ::libc::c_ulong,
|
||||
&req as *const _ as ::libc::c_ulong
|
||||
)
|
||||
};
|
||||
if err < 0 {
|
||||
Err(ServiceError::Code(err))
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_memory(&mut self, offset: u32, len: u32, buf: &[u8]) -> ServiceResult<()> {
|
||||
let fd = self.dev.as_raw_fd();
|
||||
let req = WriteMemoryRequest {
|
||||
_in: buf.as_ptr(),
|
||||
offset: offset,
|
||||
len: len,
|
||||
};
|
||||
let err = unsafe {
|
||||
::libc::ioctl(
|
||||
fd,
|
||||
Command::WriteMemory as i32 as ::libc::c_ulong,
|
||||
&req as *const _ as ::libc::c_ulong
|
||||
)
|
||||
};
|
||||
if err < 0 {
|
||||
Err(ServiceError::Code(err))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,13 @@ pub trait Loader {
|
||||
pub trait Instance {
|
||||
type Error: Debug;
|
||||
fn call(&mut self, id: usize, args: &[Value]) -> Result<u64, Self::Error>;
|
||||
fn read_memory(&mut self, offset: u32, len: u32) -> Result<Vec<u8>, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn write_memory(&mut self, offset: u32, len: u32, buf: &[u8]) -> Result<(), Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LocalLoader;
|
||||
|
156
src/bin/kwasmd.rs
Normal file
156
src/bin/kwasmd.rs
Normal file
@ -0,0 +1,156 @@
|
||||
extern crate structopt;
|
||||
extern crate byteorder;
|
||||
|
||||
use std::thread;
|
||||
use structopt::StructOpt;
|
||||
use wasmer::*;
|
||||
use wasmer_runtime::{
|
||||
error::RuntimeError,
|
||||
Func, Value,
|
||||
};
|
||||
use wasmer_runtime_core::{
|
||||
self,
|
||||
backend::{Compiler, CompilerConfig},
|
||||
loader::{self, Loader, Instance as LoadedInstance, LocalLoader},
|
||||
};
|
||||
use wasmer_singlepass_backend::SinglePassCompiler;
|
||||
|
||||
use std::os::unix::net::{UnixStream, UnixListener};
|
||||
use std::io::prelude::*;
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(name = "kwasmd", about = "Kernel-mode WebAssembly service.")]
|
||||
enum CLIOptions {
|
||||
#[structopt(name = "listen")]
|
||||
Listen(Listen),
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
struct Listen {
|
||||
#[structopt(long = "socket")]
|
||||
socket: String,
|
||||
}
|
||||
|
||||
const CMD_RUN_CODE: u32 = 0x901;
|
||||
const CMD_READ_MEMORY: u32 = 0x902;
|
||||
const CMD_WRITE_MEMORY: u32 = 0x903;
|
||||
|
||||
fn handle_client(mut stream: UnixStream) {
|
||||
let binary_size = stream.read_u32::<LittleEndian>().unwrap();
|
||||
if binary_size > 1048576 * 16 {
|
||||
println!("binary too large");
|
||||
return;
|
||||
}
|
||||
let mut wasm_binary: Vec<u8> = Vec::with_capacity(binary_size as usize);
|
||||
unsafe { wasm_binary.set_len(binary_size as usize) };
|
||||
stream.read_exact(&mut wasm_binary).unwrap();
|
||||
let module = webassembly::compile_with_config_with(
|
||||
&wasm_binary[..],
|
||||
CompilerConfig {
|
||||
symbol_map: None,
|
||||
},
|
||||
&SinglePassCompiler::new(),
|
||||
).unwrap();
|
||||
|
||||
let mut import_object = wasmer_runtime_core::import::ImportObject::new();
|
||||
import_object.allow_missing_functions = true; // Import initialization might be left to the loader.
|
||||
let instance = module.instantiate(&import_object).unwrap();
|
||||
let mut ins = instance.load(::kwasm_loader::KernelLoader).unwrap();
|
||||
|
||||
loop {
|
||||
let cmd = stream.read_u32::<LittleEndian>().unwrap();
|
||||
match cmd {
|
||||
CMD_RUN_CODE => {
|
||||
let func_name_len = stream.read_u32::<LittleEndian>().unwrap();
|
||||
if func_name_len > 32 {
|
||||
println!("function name too long");
|
||||
return;
|
||||
}
|
||||
let mut func_name: Vec<u8> = Vec::with_capacity(func_name_len as usize);
|
||||
unsafe { func_name.set_len(func_name_len as usize) };
|
||||
stream.read_exact(&mut func_name).unwrap();
|
||||
let func_name = ::std::str::from_utf8(&func_name).unwrap();
|
||||
let arg_count = stream.read_u32::<LittleEndian>().unwrap();
|
||||
if arg_count > 0 {
|
||||
println!("Too many arguments");
|
||||
return;
|
||||
}
|
||||
let mut args: Vec<Value> = Vec::with_capacity(arg_count as usize);
|
||||
for _ in 0..arg_count {
|
||||
args.push(Value::I64(stream.read_u64::<LittleEndian>().unwrap() as _));
|
||||
}
|
||||
|
||||
let index = instance.resolve_local_func(func_name).unwrap();
|
||||
let ret = ins.call(index, &args);
|
||||
match ret {
|
||||
Ok(x) => {
|
||||
stream.write_u32::<LittleEndian>(1).unwrap();
|
||||
stream.write_u64::<LittleEndian>(x).unwrap();
|
||||
},
|
||||
Err(e) => {
|
||||
println!("Execution error: {:?}", e);
|
||||
stream.write_u32::<LittleEndian>(0).unwrap();
|
||||
},
|
||||
}
|
||||
},
|
||||
CMD_READ_MEMORY => {
|
||||
let offset = stream.read_u32::<LittleEndian>().unwrap();
|
||||
let len = stream.read_u32::<LittleEndian>().unwrap();
|
||||
if len > 1048576 * 16 {
|
||||
println!("memory size too large");
|
||||
return;
|
||||
}
|
||||
let buf = ins.read_memory(offset, len).unwrap();
|
||||
stream.write_all(&buf).unwrap();
|
||||
},
|
||||
CMD_WRITE_MEMORY => {
|
||||
let offset = stream.read_u32::<LittleEndian>().unwrap();
|
||||
let len = stream.read_u32::<LittleEndian>().unwrap();
|
||||
if len > 1048576 * 16 {
|
||||
println!("memory size too large");
|
||||
return;
|
||||
}
|
||||
let mut buf: Vec<u8> = Vec::with_capacity(len as usize);
|
||||
unsafe { buf.set_len(len as usize) };
|
||||
stream.read_exact(&mut buf).unwrap();
|
||||
ins.write_memory(offset, len, &buf).unwrap();
|
||||
},
|
||||
_ => {
|
||||
println!("Unknown command");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_listen(opts: Listen) {
|
||||
let listener = UnixListener::bind(&opts.socket).unwrap();
|
||||
for stream in listener.incoming() {
|
||||
match stream {
|
||||
Ok(stream) => {
|
||||
thread::spawn(|| {
|
||||
match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| {
|
||||
handle_client(stream);
|
||||
})) {
|
||||
Ok(()) => {},
|
||||
Err(_) => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(err) => {
|
||||
panic!("{:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let options = CLIOptions::from_args();
|
||||
match options {
|
||||
CLIOptions::Listen(listen) => {
|
||||
run_listen(listen);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user