use crate::{ckb_constants::*, error::SysError};
use core::ffi::CStr;
#[cfg(target_arch = "riscv64")]
unsafe fn syscall(mut a0: u64, a1: u64, a2: u64, a3: u64, a4: u64, a5: u64, a7: u64) -> u64 {
unsafe {
core::arch::asm!(
"ecall",
inout("a0") a0,
in("a1") a1,
in("a2") a2,
in("a3") a3,
in("a4") a4,
in("a5") a5,
in("a7") a7
);
a0
}
}
#[cfg(not(target_arch = "riscv64"))]
unsafe fn syscall(_a0: u64, _a1: u64, _a2: u64, _a3: u64, _a4: u64, _a5: u64, _a7: u64) -> u64 {
u64::MAX
}
pub fn exit(code: i8) -> ! {
unsafe { syscall(code as u64, 0, 0, 0, 0, 0, SYS_EXIT) };
loop {}
}
fn syscall_load(
buf_ptr: *mut u8,
len: usize,
offset: usize,
a3: u64,
a4: u64,
a5: u64,
syscall_num: u64,
) -> Result<usize, SysError> {
let mut actual_data_len = len;
let len_ptr: *mut usize = &mut actual_data_len;
let ret = unsafe {
syscall(
buf_ptr as u64,
len_ptr as u64,
offset as u64,
a3,
a4,
a5,
syscall_num,
)
};
SysError::build_syscall_result(ret, len, actual_data_len)
}
pub fn load_tx_hash(buf: &mut [u8], offset: usize) -> Result<usize, SysError> {
syscall_load(
buf.as_mut_ptr(),
buf.len(),
offset,
0,
0,
0,
SYS_LOAD_TX_HASH,
)
}
pub fn load_script_hash(buf: &mut [u8], offset: usize) -> Result<usize, SysError> {
syscall_load(
buf.as_mut_ptr(),
buf.len(),
offset,
0,
0,
0,
SYS_LOAD_SCRIPT_HASH,
)
}
pub fn load_cell(
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
) -> Result<usize, SysError> {
syscall_load(
buf.as_mut_ptr(),
buf.len(),
offset,
index as u64,
source as u64,
0,
SYS_LOAD_CELL,
)
}
pub fn load_input(
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
) -> Result<usize, SysError> {
syscall_load(
buf.as_mut_ptr(),
buf.len(),
offset,
index as u64,
source as u64,
0,
SYS_LOAD_INPUT,
)
}
pub fn load_header(
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
) -> Result<usize, SysError> {
syscall_load(
buf.as_mut_ptr(),
buf.len(),
offset,
index as u64,
source as u64,
0,
SYS_LOAD_HEADER,
)
}
pub fn load_witness(
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
) -> Result<usize, SysError> {
syscall_load(
buf.as_mut_ptr(),
buf.len(),
offset,
index as u64,
source as u64,
0,
SYS_LOAD_WITNESS,
)
}
pub fn load_transaction(buf: &mut [u8], offset: usize) -> Result<usize, SysError> {
syscall_load(
buf.as_mut_ptr(),
buf.len(),
offset,
0,
0,
0,
SYS_LOAD_TRANSACTION,
)
}
pub fn load_cell_by_field(
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
field: CellField,
) -> Result<usize, SysError> {
syscall_load(
buf.as_mut_ptr(),
buf.len(),
offset,
index as u64,
source as u64,
field as u64,
SYS_LOAD_CELL_BY_FIELD,
)
}
pub fn load_header_by_field(
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
field: HeaderField,
) -> Result<usize, SysError> {
syscall_load(
buf.as_mut_ptr(),
buf.len(),
offset,
index as u64,
source as u64,
field as u64,
SYS_LOAD_HEADER_BY_FIELD,
)
}
pub fn load_input_by_field(
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
field: InputField,
) -> Result<usize, SysError> {
syscall_load(
buf.as_mut_ptr(),
buf.len(),
offset,
index as u64,
source as u64,
field as u64,
SYS_LOAD_INPUT_BY_FIELD,
)
}
pub fn load_cell_data(
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
) -> Result<usize, SysError> {
syscall_load(
buf.as_mut_ptr(),
buf.len(),
offset,
index as u64,
source as u64,
0,
SYS_LOAD_CELL_DATA,
)
}
pub fn load_script(buf: &mut [u8], offset: usize) -> Result<usize, SysError> {
syscall_load(
buf.as_mut_ptr(),
buf.len(),
offset,
0,
0,
0,
SYS_LOAD_SCRIPT,
)
}
pub fn debug(mut s: alloc::string::String) {
s.push('\0');
let c_str = s.into_bytes();
unsafe {
syscall(c_str.as_ptr() as u64, 0, 0, 0, 0, 0, SYS_DEBUG);
}
}
pub fn load_cell_data_raw(
buf_ptr: *mut u8,
len: usize,
offset: usize,
index: usize,
source: Source,
) -> Result<usize, SysError> {
syscall_load(
buf_ptr,
len,
offset,
index as u64,
source as u64,
0,
SYS_LOAD_CELL_DATA,
)
}
pub fn load_cell_code(
buf_ptr: *mut u8,
len: usize,
content_offset: usize,
content_size: usize,
index: usize,
source: Source,
) -> Result<usize, SysError> {
let ret = unsafe {
syscall(
buf_ptr as u64,
len as u64,
content_offset as u64,
content_size as u64,
index as u64,
source as u64,
SYS_LOAD_CELL_DATA_AS_CODE,
)
};
SysError::build_syscall_result(ret, len, len)
}
pub fn vm_version() -> Result<u64, SysError> {
let ret = unsafe { syscall(0, 0, 0, 0, 0, 0, SYS_VM_VERSION) };
match ret {
1 | 2 => Ok(ret),
_ => Err(SysError::Unknown(ret)),
}
}
pub fn current_cycles() -> u64 {
unsafe { syscall(0, 0, 0, 0, 0, 0, SYS_CURRENT_CYCLES) }
}
pub fn exec(index: usize, source: Source, place: usize, bounds: usize, argv: &[&CStr]) -> u64 {
let argc = argv.len();
let argv_ptr: alloc::vec::Vec<*const i8> =
argv.iter().map(|e| e.as_ptr() as *const i8).collect();
unsafe {
syscall(
index as u64,
source as u64,
place as u64,
bounds as u64,
argc as u64,
argv_ptr.as_ptr() as u64,
SYS_EXEC,
)
}
}
pub use crate::syscalls::internal::SpawnArgs;
pub fn spawn(
index: usize,
source: Source,
place: usize,
bounds: usize,
spgs: &mut SpawnArgs,
) -> Result<u64, SysError> {
let ret = unsafe {
syscall(
index as u64,
source as u64,
place as u64,
bounds as u64,
spgs as *mut SpawnArgs as u64,
0,
SYS_SPAWN,
)
};
match ret {
0 => Ok(unsafe { *spgs.process_id }),
1 => Err(SysError::IndexOutOfBound),
2 => Err(SysError::ItemMissing),
3 => Err(SysError::Encoding),
6 => Err(SysError::InvalidFd),
8 => Err(SysError::MaxVmsSpawned),
x => Err(SysError::Unknown(x)),
}
}
pub fn wait(pid: u64) -> Result<i8, SysError> {
let mut code: u64 = 0;
let ret = unsafe { syscall(pid, &mut code as *mut u64 as u64, 0, 0, 0, 0, SYS_WAIT) };
match ret {
0 => Ok(code as i8),
5 => Err(SysError::WaitFailure),
x => Err(SysError::Unknown(x)),
}
}
pub fn process_id() -> u64 {
unsafe { syscall(0, 0, 0, 0, 0, 0, SYS_PROCESS_ID) }
}
pub fn pipe() -> Result<(u64, u64), SysError> {
let mut fds: [u64; 2] = [0, 0];
let ret = unsafe { syscall(fds.as_mut_ptr() as u64, 0, 0, 0, 0, 0, SYS_PIPE) };
match ret {
0 => Ok((fds[0], fds[1])),
9 => Err(SysError::MaxFdsCreated),
x => Err(SysError::Unknown(x)),
}
}
pub fn read(fd: u64, buffer: &mut [u8]) -> Result<usize, SysError> {
let mut l: u64 = buffer.len() as u64;
let ret = unsafe {
syscall(
fd,
buffer.as_mut_ptr() as u64,
&mut l as *mut u64 as u64,
0,
0,
0,
SYS_READ,
)
};
match ret {
0 => Ok(l as usize),
1 => Err(SysError::IndexOutOfBound),
6 => Err(SysError::InvalidFd),
7 => Err(SysError::OtherEndClosed),
x => Err(SysError::Unknown(x)),
}
}
pub fn write(fd: u64, buffer: &[u8]) -> Result<usize, SysError> {
let mut l: u64 = buffer.len() as u64;
let ret = unsafe {
syscall(
fd,
buffer.as_ptr() as u64,
&mut l as *mut u64 as u64,
0,
0,
0,
SYS_WRITE,
)
};
match ret {
0 => Ok(l as usize),
1 => Err(SysError::IndexOutOfBound),
6 => Err(SysError::InvalidFd),
7 => Err(SysError::OtherEndClosed),
x => Err(SysError::Unknown(x)),
}
}
pub fn inherited_fds(fds: &mut [u64]) -> u64 {
let mut l: u64 = fds.len() as u64;
unsafe {
syscall(
fds.as_mut_ptr() as u64,
&mut l as *mut u64 as u64,
0,
0,
0,
0,
SYS_INHERITED_FDS,
)
};
l
}
pub fn close(fd: u64) -> Result<(), SysError> {
let ret = unsafe { syscall(fd, 0, 0, 0, 0, 0, SYS_CLOSE) };
match ret {
0 => Ok(()),
6 => Err(SysError::InvalidFd),
x => Err(SysError::Unknown(x)),
}
}
pub fn load_block_extension(
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
) -> Result<usize, SysError> {
syscall_load(
buf.as_mut_ptr(),
buf.len(),
offset,
index as u64,
source as u64,
0,
SYS_LOAD_BLOCK_EXTENSION,
)
}