Skip to content

Commit

Permalink
Rewrite some syscalls (#10)
Browse files Browse the repository at this point in the history
* Rewrite current_cycles

* Rewrite process_id

* Rewrite pipe

* Rewrite wait

* Rewrite read/write

* Rewrite inherited_fd

* Rewrite close
  • Loading branch information
mohanson authored Mar 7, 2024
1 parent da968be commit af11e31
Show file tree
Hide file tree
Showing 14 changed files with 447 additions and 264 deletions.
37 changes: 37 additions & 0 deletions script/src/syscalls/close.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use crate::syscalls::CLOSE;
use crate::v2_types::{Message, PipeId, VmId};
use ckb_vm::{
registers::{A0, A7},
Error as VMError, Register, SupportMachine, Syscalls,
};
use std::sync::{Arc, Mutex};

#[derive(Debug)]
pub struct Close {
id: VmId,
message_box: Arc<Mutex<Vec<Message>>>,
}

impl Close {
pub fn new(id: VmId, message_box: Arc<Mutex<Vec<Message>>>) -> Self {
Self { id, message_box }
}
}

impl<Mac: SupportMachine> Syscalls<Mac> for Close {
fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> {
Ok(())
}

fn ecall(&mut self, machine: &mut Mac) -> Result<bool, VMError> {
if machine.registers()[A7].to_u64() != CLOSE {
return Ok(false);
}
let pipe = PipeId(machine.registers()[A0].to_u64());
self.message_box
.lock()
.map_err(|e| VMError::Unexpected(e.to_string()))?
.push(Message::Close(self.id, pipe));
Err(VMError::External("YIELD".to_string()))
}
}
7 changes: 5 additions & 2 deletions script/src/syscalls/current_cycles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ use ckb_vm::{
registers::{A0, A7},
Error as VMError, Register, SupportMachine, Syscalls,
};
use std::sync::{Arc, Mutex};

#[derive(Debug, Default)]
pub struct CurrentCycles {
base: u64,
base: Arc<Mutex<u64>>,
}

impl CurrentCycles {
pub fn new(base: u64) -> Self {
pub fn new(base: Arc<Mutex<u64>>) -> Self {
Self { base }
}
}
Expand All @@ -26,6 +27,8 @@ impl<Mac: SupportMachine> Syscalls<Mac> for CurrentCycles {
}
let cycles = self
.base
.lock()
.map_err(|e| VMError::Unexpected(e.to_string()))?
.checked_add(machine.cycles())
.ok_or(VMError::CyclesOverflow)?;
machine.set_register(A0, Mac::REG::from_u64(cycles));
Expand Down
46 changes: 46 additions & 0 deletions script/src/syscalls/inherited_fd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use crate::syscalls::INHERITED_FD;
use crate::v2_types::{Message, PipeId, PipeIoArgs, VmId};
use ckb_vm::{
registers::{A0, A1, A7},
Error as VMError, Register, SupportMachine, Syscalls,
};
use std::sync::{Arc, Mutex};

#[derive(Debug)]
pub struct InheritedFd {
id: VmId,
message_box: Arc<Mutex<Vec<Message>>>,
}

impl InheritedFd {
pub fn new(id: VmId, message_box: Arc<Mutex<Vec<Message>>>) -> Self {
Self { id, message_box }
}
}

impl<Mac: SupportMachine> Syscalls<Mac> for InheritedFd {
fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> {
Ok(())
}

fn ecall(&mut self, machine: &mut Mac) -> Result<bool, VMError> {
if machine.registers()[A7].to_u64() != INHERITED_FD {
return Ok(false);
}
let buffer_addr = machine.registers()[A0].to_u64();
let length_addr = machine.registers()[A1].to_u64();
self.message_box
.lock()
.map_err(|e| VMError::Unexpected(e.to_string()))?
.push(Message::InheritedFileDescriptor(
self.id,
PipeIoArgs {
pipe: PipeId(0),
length: 0,
buffer_addr,
length_addr,
},
));
Err(VMError::External("YIELD".to_string()))
}
}
25 changes: 23 additions & 2 deletions script/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
mod close;
mod current_cycles;
mod current_memory;
mod debugger;
mod exec;
mod get_memory_limit;
mod inherited_fd;
mod load_block_extension;
mod load_cell;
mod load_cell_data;
Expand All @@ -12,22 +14,29 @@ mod load_script;
mod load_script_hash;
mod load_tx;
mod load_witness;
mod pipe;
mod process_id;
mod read;
mod set_content;
pub(crate) mod spawn;
mod utils;
mod vm_version;
mod wait;
mod write;

#[cfg(test)]
mod pause;

#[cfg(test)]
mod tests;

pub use self::close::Close;
pub use self::current_cycles::CurrentCycles;
pub use self::current_memory::CurrentMemory;
pub use self::debugger::Debugger;
pub use self::exec::Exec;
pub use self::get_memory_limit::GetMemoryLimit;
pub use self::inherited_fd::InheritedFd;
pub use self::load_block_extension::LoadBlockExtension;
pub use self::load_cell::LoadCell;
pub use self::load_cell_data::LoadCellData;
Expand All @@ -37,9 +46,14 @@ pub use self::load_script::LoadScript;
pub use self::load_script_hash::LoadScriptHash;
pub use self::load_tx::LoadTx;
pub use self::load_witness::LoadWitness;
pub use self::pipe::Pipe;
pub use self::process_id::ProcessID;
pub use self::read::Read;
pub use self::set_content::SetContent;
pub use self::spawn::Spawn;
pub use self::vm_version::VMVersion;
pub use self::wait::Wait;
pub use self::write::Write;

#[cfg(test)]
pub use self::pause::Pause;
Expand Down Expand Up @@ -75,10 +89,17 @@ pub const LOAD_HEADER_BY_FIELD_SYSCALL_NUMBER: u64 = 2082;
pub const LOAD_INPUT_BY_FIELD_SYSCALL_NUMBER: u64 = 2083;
pub const LOAD_CELL_DATA_AS_CODE_SYSCALL_NUMBER: u64 = 2091;
pub const LOAD_CELL_DATA_SYSCALL_NUMBER: u64 = 2092;
pub const SPAWN: u64 = 2101;
pub const LOAD_BLOCK_EXTENSION: u64 = 2104;
pub const SPAWN: u64 = 2601;
pub const WAIT: u64 = 2602;
pub const PROCESS_ID: u64 = 2603;
pub const PIPE: u64 = 2604;
pub const WRITE: u64 = 2605;
pub const READ: u64 = 2606;
pub const INHERITED_FD: u64 = 2607;
pub const CLOSE: u64 = 2608;
pub const GET_MEMORY_LIMIT: u64 = 2102;
pub const SET_CONTENT: u64 = 2103;
pub const LOAD_BLOCK_EXTENSION: u64 = 2104;
pub const CURRENT_MEMORY: u64 = 2105;
pub const DEBUG_PRINT_SYSCALL_NUMBER: u64 = 2177;
#[cfg(test)]
Expand Down
44 changes: 44 additions & 0 deletions script/src/syscalls/pipe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use crate::syscalls::PIPE;
use crate::v2_types::{Message, PipeArgs, VmId};
use ckb_vm::{
registers::{A0, A7},
Error as VMError, Register, SupportMachine, Syscalls,
};
use std::sync::{Arc, Mutex};

#[derive(Debug)]
pub struct Pipe {
id: VmId,
message_box: Arc<Mutex<Vec<Message>>>,
}

impl Pipe {
pub fn new(id: VmId, message_box: Arc<Mutex<Vec<Message>>>) -> Self {
Self { id, message_box }
}
}

impl<Mac: SupportMachine> Syscalls<Mac> for Pipe {
fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> {
Ok(())
}

fn ecall(&mut self, machine: &mut Mac) -> Result<bool, VMError> {
if machine.registers()[A7].to_u64() != PIPE {
return Ok(false);
}
let pipe1_addr = machine.registers()[A0].to_u64();
let pipe2_addr = pipe1_addr.wrapping_add(8);
self.message_box
.lock()
.map_err(|e| VMError::Unexpected(e.to_string()))?
.push(Message::Pipe(
self.id,
PipeArgs {
pipe1_addr,
pipe2_addr,
},
));
Err(VMError::External("YIELD".to_string()))
}
}
30 changes: 30 additions & 0 deletions script/src/syscalls/process_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use crate::syscalls::PROCESS_ID;
use ckb_vm::{
registers::{A0, A7},
Error as VMError, Register, SupportMachine, Syscalls,
};

#[derive(Debug, Default)]
pub struct ProcessID {
id: u64,
}

impl ProcessID {
pub fn new(id: u64) -> Self {
Self { id }
}
}

impl<Mac: SupportMachine> Syscalls<Mac> for ProcessID {
fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> {
Ok(())
}

fn ecall(&mut self, machine: &mut Mac) -> Result<bool, VMError> {
if machine.registers()[A7].to_u64() != PROCESS_ID {
return Ok(false);
}
machine.set_register(A0, Mac::REG::from_u64(self.id));
Ok(true)
}
}
62 changes: 62 additions & 0 deletions script/src/syscalls/read.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use crate::cost_model::transferred_byte_cycles;
use crate::syscalls::READ;
use crate::v2_syscalls::INVALID_PIPE;
use crate::v2_types::{Message, PipeId, PipeIoArgs, VmId};
use ckb_vm::{
registers::{A0, A1, A2, A7},
Error as VMError, Memory, Register, SupportMachine, Syscalls,
};
use std::sync::{Arc, Mutex};

#[derive(Debug)]
pub struct Read {
id: VmId,
message_box: Arc<Mutex<Vec<Message>>>,
}

impl Read {
pub fn new(id: VmId, message_box: Arc<Mutex<Vec<Message>>>) -> Self {
Self { id, message_box }
}
}

impl<Mac: SupportMachine> Syscalls<Mac> for Read {
fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> {
Ok(())
}

fn ecall(&mut self, machine: &mut Mac) -> Result<bool, VMError> {
if machine.registers()[A7].to_u64() != READ {
return Ok(false);
}
let pipe = PipeId(machine.registers()[A0].to_u64());
let buffer_addr = machine.registers()[A1].to_u64();
let length_addr = machine.registers()[A2].to_u64();
let length = machine
.memory_mut()
.load64(&Mac::REG::from_u64(length_addr))?
.to_u64();

// We can only do basic checks here, when the message is actually processed,
// more complete checks will be performed.
// We will also leave to the actual write operation to test memory permissions.
if !pipe.is_read() {
machine.set_register(A0, Mac::REG::from_u8(INVALID_PIPE));
return Ok(true);
}
machine.add_cycles_no_checking(transferred_byte_cycles(length))?;
self.message_box
.lock()
.map_err(|e| VMError::Unexpected(e.to_string()))?
.push(Message::PipeRead(
self.id,
PipeIoArgs {
pipe,
length,
buffer_addr,
length_addr,
},
));
Err(VMError::External("YIELD".to_string()))
}
}
5 changes: 2 additions & 3 deletions script/src/syscalls/spawn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,9 +291,8 @@ pub fn build_child_machine<
let machine_builder = machine_syscalls
.into_iter()
.fold(machine_builder, |builder, syscall| builder.syscall(syscall));
let machine_builder = machine_builder.syscall(Box::new(
syscalls_generator.build_current_cycles(*cycles_base),
));
let machine_builder =
machine_builder.syscall(Box::new(syscalls_generator.build_current_cycles()));
let machine_builder = machine_builder.syscall(Box::new(
syscalls_generator.build_get_memory_limit(*callee_memory_limit),
));
Expand Down
2 changes: 1 addition & 1 deletion script/src/syscalls/tests/vm_latest/syscalls_2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fn test_current_cycles() {

machine.set_cycles(cycles);

let result = CurrentCycles::new(0).ecall(&mut machine);
let result = CurrentCycles::new(Arc::new(Mutex::new(0))).ecall(&mut machine);

assert!(result.unwrap());
assert_eq!(machine.registers()[A0], cycles);
Expand Down
44 changes: 44 additions & 0 deletions script/src/syscalls/wait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use crate::syscalls::WAIT;
use crate::v2_types::{Message, VmId, WaitArgs};
use ckb_vm::{
registers::{A0, A1, A7},
Error as VMError, Register, SupportMachine, Syscalls,
};
use std::sync::{Arc, Mutex};

#[derive(Debug)]
pub struct Wait {
id: VmId,
message_box: Arc<Mutex<Vec<Message>>>,
}

impl Wait {
pub fn new(id: VmId, message_box: Arc<Mutex<Vec<Message>>>) -> Self {
Self { id, message_box }
}
}

impl<Mac: SupportMachine> Syscalls<Mac> for Wait {
fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> {
Ok(())
}

fn ecall(&mut self, machine: &mut Mac) -> Result<bool, VMError> {
if machine.registers()[A7].to_u64() != WAIT {
return Ok(false);
}
let target_id = machine.registers()[A0].to_u64();
let exit_code_addr = machine.registers()[A1].to_u64();
self.message_box
.lock()
.map_err(|e| VMError::Unexpected(e.to_string()))?
.push(Message::Wait(
self.id,
WaitArgs {
target_id,
exit_code_addr,
},
));
Err(VMError::External("YIELD".to_string()))
}
}
Loading

0 comments on commit af11e31

Please sign in to comment.