wasmer/lib/kernel-loader/src/service.rs

256 lines
6.4 KiB
Rust
Raw Normal View History

2019-05-14 08:04:08 +00:00
use std::error::Error;
2019-05-04 06:07:07 +00:00
use std::fs::File;
use std::io;
use std::os::unix::io::AsRawFd;
macro_rules! impl_debug_display {
($target:ident) => {
impl ::std::fmt::Display for $target {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
<Self as ::std::fmt::Debug>::fmt(self, f)
}
}
2019-05-14 08:04:08 +00:00
};
2019-05-04 06:07:07 +00:00
}
#[repr(i32)]
pub enum Command {
2019-05-05 12:03:07 +00:00
LoadCode = 0x1001,
RunCode = 0x1002,
2019-05-05 16:32:35 +00:00
ReadMemory = 0x1003,
WriteMemory = 0x1004,
2019-05-04 06:07:07 +00:00
}
#[derive(Debug)]
pub enum ServiceError {
Io(io::Error),
2019-05-05 12:03:07 +00:00
Code(i32),
2019-05-04 06:07:07 +00:00
InvalidInput,
2019-05-14 08:04:08 +00:00
Rejected,
2019-05-04 06:07:07 +00:00
}
pub type ServiceResult<T> = Result<T, ServiceError>;
impl_debug_display!(ServiceError);
impl Error for ServiceError {
fn description(&self) -> &str {
"ServiceError"
}
}
impl From<io::Error> for ServiceError {
fn from(other: io::Error) -> ServiceError {
ServiceError::Io(other)
}
}
#[repr(C)]
2019-05-05 12:03:07 +00:00
struct LoadCodeRequest {
2019-05-04 06:07:07 +00:00
code: *const u8,
code_len: u32,
memory: *const u8,
memory_len: u32,
memory_max: u32,
2019-05-04 16:56:52 +00:00
table: *const TableEntryRequest,
2019-05-04 06:07:07 +00:00
table_count: u32,
globals: *const u128,
2019-05-04 06:07:07 +00:00
global_count: u32,
2019-05-04 15:28:13 +00:00
imported_funcs: *const ImportRequest,
imported_func_count: u32,
2019-05-04 16:56:52 +00:00
dynamic_sigindices: *const u32,
dynamic_sigindice_count: u32,
2019-05-05 12:03:07 +00:00
}
2019-05-04 16:56:52 +00:00
2019-05-05 12:03:07 +00:00
#[repr(C)]
struct RunCodeRequest {
2019-05-04 06:07:07 +00:00
entry_offset: u32,
params: *const u128,
2019-05-04 06:07:07 +00:00
param_count: u32,
2019-05-05 16:32:35 +00:00
result: *mut RunCodeResult,
}
#[repr(C)]
struct RunCodeResult {
success: u32,
retval: u128,
2019-05-05 16:32:35 +00:00
}
#[repr(C)]
struct ReadMemoryRequest {
out: *mut u8,
offset: u32,
len: u32,
}
#[repr(C)]
struct WriteMemoryRequest {
_in: *const u8,
offset: u32,
len: u32,
2019-05-04 06:07:07 +00:00
}
2019-05-04 15:28:13 +00:00
#[repr(C)]
struct ImportRequest {
name: [u8; 64],
param_count: u32,
2019-05-04 15:28:13 +00:00
}
2019-05-04 16:56:52 +00:00
#[repr(C)]
pub struct TableEntryRequest {
pub offset: usize,
pub sig_id: u32,
}
2019-05-05 12:03:07 +00:00
pub struct LoadProfile<'a> {
2019-05-04 06:07:07 +00:00
pub code: &'a [u8],
pub memory: Option<&'a [u8]>,
pub memory_max: usize,
pub globals: &'a [u128],
pub imports: &'a [ImportInfo],
2019-05-04 16:56:52 +00:00
pub dynamic_sigindices: &'a [u32],
pub table: Option<&'a [TableEntryRequest]>,
2019-05-04 06:07:07 +00:00
}
pub struct ImportInfo {
pub name: String,
pub param_count: usize,
}
2019-05-05 12:03:07 +00:00
pub struct RunProfile<'a> {
pub entry_offset: u32,
pub params: &'a [u128],
2019-05-05 12:03:07 +00:00
}
2019-05-04 06:07:07 +00:00
pub struct ServiceContext {
2019-05-14 08:04:08 +00:00
dev: File,
2019-05-04 06:07:07 +00:00
}
impl ServiceContext {
2019-05-05 12:03:07 +00:00
pub fn new(load: LoadProfile) -> ServiceResult<ServiceContext> {
let dev = File::open("/dev/wasmctl")?;
2019-05-14 08:04:08 +00:00
let imports: Vec<ImportRequest> = load
.imports
.iter()
.map(|x| {
let mut req = ImportRequest {
name: [0u8; 64],
param_count: x.param_count as u32,
};
let name = x.name.as_bytes();
let mut count = req.name.len() - 1;
if name.len() < count {
count = name.len();
}
req.name[..count].copy_from_slice(&name[..count]);
req
})
.collect();
2019-05-05 12:03:07 +00:00
let req = LoadCodeRequest {
code: load.code.as_ptr(),
code_len: load.code.len() as u32,
2019-05-14 08:04:08 +00:00
memory: load
.memory
.map(|x| x.as_ptr())
.unwrap_or(::std::ptr::null()),
2019-05-05 12:03:07 +00:00
memory_len: load.memory.map(|x| x.len() as u32).unwrap_or(0),
memory_max: load.memory_max as u32,
table: load.table.map(|x| x.as_ptr()).unwrap_or(::std::ptr::null()),
table_count: load.table.map(|x| x.len() as u32).unwrap_or(0),
globals: load.globals.as_ptr(),
global_count: load.globals.len() as u32,
2019-05-04 15:28:13 +00:00
imported_funcs: imports.as_ptr(),
imported_func_count: imports.len() as u32,
2019-05-05 12:03:07 +00:00
dynamic_sigindices: load.dynamic_sigindices.as_ptr(),
dynamic_sigindice_count: load.dynamic_sigindices.len() as u32,
};
let fd = dev.as_raw_fd();
let ret = unsafe {
::libc::ioctl(
fd,
Command::LoadCode as i32 as ::libc::c_ulong,
2019-05-14 08:04:08 +00:00
&req as *const _ as ::libc::c_ulong,
2019-05-05 12:03:07 +00:00
)
};
if ret != 0 {
Err(ServiceError::Code(ret))
} else {
2019-05-14 08:04:08 +00:00
Ok(ServiceContext { dev: dev })
2019-05-05 12:03:07 +00:00
}
}
pub fn run_code(&mut self, run: RunProfile) -> ServiceResult<u128> {
2019-05-05 16:32:35 +00:00
let mut result: RunCodeResult = unsafe { ::std::mem::zeroed() };
let mut req = RunCodeRequest {
2019-05-05 12:03:07 +00:00
entry_offset: run.entry_offset,
2019-05-04 06:07:07 +00:00
params: run.params.as_ptr(),
param_count: run.params.len() as u32,
2019-05-05 16:32:35 +00:00
result: &mut result,
2019-05-04 06:07:07 +00:00
};
let fd = self.dev.as_raw_fd();
2019-05-05 16:32:35 +00:00
let err = unsafe {
2019-05-04 06:07:07 +00:00
::libc::ioctl(
fd,
Command::RunCode as i32 as ::libc::c_ulong,
2019-05-14 08:04:08 +00:00
&mut req as *mut _ as ::libc::c_ulong,
2019-05-05 16:32:35 +00:00
)
};
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,
2019-05-14 08:04:08 +00:00
&req as *const _ as ::libc::c_ulong,
2019-05-04 06:07:07 +00:00
)
};
2019-05-05 16:32:35 +00:00
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,
2019-05-14 08:04:08 +00:00
&req as *const _ as ::libc::c_ulong,
2019-05-05 16:32:35 +00:00
)
};
if err < 0 {
Err(ServiceError::Code(err))
} else {
Ok(())
}
2019-05-04 06:07:07 +00:00
}
}