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"
|
name = "wasmer"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
dependencies = [
|
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)",
|
"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)",
|
"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)",
|
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -19,6 +19,7 @@ include = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
byteorder = "1.3.1"
|
||||||
errno = "0.2.4"
|
errno = "0.2.4"
|
||||||
structopt = "0.2.11"
|
structopt = "0.2.11"
|
||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
|
@ -99,6 +99,14 @@ impl Instance for KernelInstance {
|
|||||||
entry_offset: self.offsets[id] as u32,
|
entry_offset: self.offsets[id] as u32,
|
||||||
params: &args,
|
params: &args,
|
||||||
}).map_err(|x| format!("{:?}", x))?;
|
}).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 {
|
pub enum Command {
|
||||||
LoadCode = 0x1001,
|
LoadCode = 0x1001,
|
||||||
RunCode = 0x1002,
|
RunCode = 0x1002,
|
||||||
|
ReadMemory = 0x1003,
|
||||||
|
WriteMemory = 0x1004,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -67,6 +69,27 @@ struct RunCodeRequest {
|
|||||||
entry_offset: u32,
|
entry_offset: u32,
|
||||||
params: *const u64,
|
params: *const u64,
|
||||||
param_count: u32,
|
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)]
|
#[repr(C)]
|
||||||
@ -144,20 +167,75 @@ impl ServiceContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_code(&mut self, run: RunProfile) -> ServiceResult<i32> {
|
pub fn run_code(&mut self, run: RunProfile) -> ServiceResult<u64> {
|
||||||
let req = RunCodeRequest {
|
let mut result: RunCodeResult = unsafe { ::std::mem::zeroed() };
|
||||||
|
let mut req = RunCodeRequest {
|
||||||
entry_offset: run.entry_offset,
|
entry_offset: run.entry_offset,
|
||||||
params: run.params.as_ptr(),
|
params: run.params.as_ptr(),
|
||||||
param_count: run.params.len() as u32,
|
param_count: run.params.len() as u32,
|
||||||
|
result: &mut result,
|
||||||
};
|
};
|
||||||
let fd = self.dev.as_raw_fd();
|
let fd = self.dev.as_raw_fd();
|
||||||
let ret = unsafe {
|
let err = unsafe {
|
||||||
::libc::ioctl(
|
::libc::ioctl(
|
||||||
fd,
|
fd,
|
||||||
Command::RunCode as i32 as ::libc::c_ulong,
|
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
|
&req as *const _ as ::libc::c_ulong
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
Ok(ret)
|
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 {
|
pub trait Instance {
|
||||||
type Error: Debug;
|
type Error: Debug;
|
||||||
fn call(&mut self, id: usize, args: &[Value]) -> Result<u64, Self::Error>;
|
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;
|
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