1use crate::{
2 ckb_constants::{self as consts, CellField, HeaderField, InputField, Source},
3 error::SysError,
4 syscalls::internal::SpawnArgs,
5};
6use alloc::{string::String, vec::Vec};
7use core::ffi::CStr;
8
9pub trait SyscallImpls {
39 fn syscall(&self, _a0: u64, _a1: u64, _a2: u64, _a3: u64, _a4: u64, _a5: u64, _n: u64) -> u64 {
45 panic!("Default syscall function is not yet implemented!")
46 }
47
48 fn syscall_load(
49 &self,
50 buf: &mut [u8],
51 offset: usize,
52 a3: u64,
53 a4: u64,
54 a5: u64,
55 syscall_num: u64,
56 ) -> IoResult {
57 let mut actual_data_len: u64 = buf.len() as u64;
58 let len_ptr: *mut u64 = &mut actual_data_len;
59 let ret = self.syscall(
60 buf.as_ptr() as u64,
61 len_ptr as u64,
62 offset as u64,
63 a3,
64 a4,
65 a5,
66 syscall_num,
67 );
68 match ret {
69 0 => {
70 if actual_data_len > buf.len() as u64 {
71 IoResult::PartialLoaded {
72 loaded: buf.len(),
73 available: actual_data_len as usize,
74 }
75 } else {
76 IoResult::FullyLoaded(actual_data_len as usize)
77 }
78 }
79 _ => IoResult::Error(ret.try_into().unwrap()),
80 }
81 }
82
83 fn debug(&self, s: &CStr) {
84 self.syscall(s.as_ptr() as u64, 0, 0, 0, 0, 0, consts::SYS_DEBUG);
85 }
86 fn exit(&self, code: i8) -> ! {
87 self.syscall(code as u64, 0, 0, 0, 0, 0, consts::SYS_EXIT);
88 unreachable!()
89 }
90 fn load_cell(&self, buf: &mut [u8], offset: usize, index: usize, source: Source) -> IoResult {
91 self.syscall_load(
92 buf,
93 offset,
94 index as u64,
95 source as u64,
96 0,
97 consts::SYS_LOAD_CELL,
98 )
99 }
100 fn load_cell_by_field(
101 &self,
102 buf: &mut [u8],
103 offset: usize,
104 index: usize,
105 source: Source,
106 field: CellField,
107 ) -> IoResult {
108 self.syscall_load(
109 buf,
110 offset,
111 index as u64,
112 source as u64,
113 field as u64,
114 consts::SYS_LOAD_CELL_BY_FIELD,
115 )
116 }
117 fn load_cell_code(
118 &self,
119 buf_ptr: *mut u8,
120 len: usize,
121 content_offset: usize,
122 content_size: usize,
123 index: usize,
124 source: Source,
125 ) -> Result<(), Error> {
126 build_result(self.syscall(
127 buf_ptr as u64,
128 len as u64,
129 content_offset as u64,
130 content_size as u64,
131 index as u64,
132 source as u64,
133 consts::SYS_LOAD_CELL_DATA_AS_CODE,
134 ))
135 }
136 fn load_cell_data(
137 &self,
138 buf: &mut [u8],
139 offset: usize,
140 index: usize,
141 source: Source,
142 ) -> IoResult {
143 self.syscall_load(
144 buf,
145 offset,
146 index as u64,
147 source as u64,
148 0,
149 consts::SYS_LOAD_CELL_DATA,
150 )
151 }
152 fn load_header(&self, buf: &mut [u8], offset: usize, index: usize, source: Source) -> IoResult {
153 self.syscall_load(
154 buf,
155 offset,
156 index as u64,
157 source as u64,
158 0,
159 consts::SYS_LOAD_HEADER,
160 )
161 }
162 fn load_header_by_field(
163 &self,
164 buf: &mut [u8],
165 offset: usize,
166 index: usize,
167 source: Source,
168 field: HeaderField,
169 ) -> IoResult {
170 self.syscall_load(
171 buf,
172 offset,
173 index as u64,
174 source as u64,
175 field as u64,
176 consts::SYS_LOAD_HEADER_BY_FIELD,
177 )
178 }
179 fn load_input(&self, buf: &mut [u8], offset: usize, index: usize, source: Source) -> IoResult {
180 self.syscall_load(
181 buf,
182 offset,
183 index as u64,
184 source as u64,
185 0,
186 consts::SYS_LOAD_INPUT,
187 )
188 }
189 fn load_input_by_field(
190 &self,
191 buf: &mut [u8],
192 offset: usize,
193 index: usize,
194 source: Source,
195 field: InputField,
196 ) -> IoResult {
197 self.syscall_load(
198 buf,
199 offset,
200 index as u64,
201 source as u64,
202 field as u64,
203 consts::SYS_LOAD_INPUT_BY_FIELD,
204 )
205 }
206 fn load_script(&self, buf: &mut [u8], offset: usize) -> IoResult {
207 self.syscall_load(buf, offset, 0, 0, 0, consts::SYS_LOAD_SCRIPT)
208 }
209 fn load_script_hash(&self, buf: &mut [u8], offset: usize) -> IoResult {
210 self.syscall_load(buf, offset, 0, 0, 0, consts::SYS_LOAD_SCRIPT_HASH)
211 }
212 fn load_transaction(&self, buf: &mut [u8], offset: usize) -> IoResult {
213 self.syscall_load(buf, offset, 0, 0, 0, consts::SYS_LOAD_TRANSACTION)
214 }
215 fn load_tx_hash(&self, buf: &mut [u8], offset: usize) -> IoResult {
216 self.syscall_load(buf, offset, 0, 0, 0, consts::SYS_LOAD_TX_HASH)
217 }
218 fn load_witness(
219 &self,
220 buf: &mut [u8],
221 offset: usize,
222 index: usize,
223 source: Source,
224 ) -> IoResult {
225 self.syscall_load(
226 buf,
227 offset,
228 index as u64,
229 source as u64,
230 0,
231 consts::SYS_LOAD_WITNESS,
232 )
233 }
234
235 fn vm_version(&self) -> u64 {
236 self.syscall(0, 0, 0, 0, 0, 0, consts::SYS_VM_VERSION)
237 }
238 fn current_cycles(&self) -> u64 {
239 self.syscall(0, 0, 0, 0, 0, 0, consts::SYS_CURRENT_CYCLES)
240 }
241 fn exec(
242 &self,
243 index: usize,
244 source: Source,
245 place: usize,
246 bounds: usize,
247 argv: &[&CStr],
248 ) -> Result<(), Error> {
249 let argv_ptr: alloc::vec::Vec<*const i8> =
250 argv.iter().map(|e| e.as_ptr() as *const i8).collect();
251
252 build_result(self.syscall(
253 index as u64,
254 source as u64,
255 place as u64,
256 bounds as u64,
257 argv.len() as u64,
258 argv_ptr.as_ptr() as u64,
259 consts::SYS_EXEC,
260 ))
261 }
262
263 fn spawn(
265 &self,
266 index: usize,
267 source: Source,
268 place: usize,
269 bounds: usize,
270 argv: &[&CStr],
271 inherited_fds: &[u64],
272 ) -> Result<u64, Error> {
273 let mut fds_with_terminator = alloc::vec![0; inherited_fds.len() + 1];
274 fds_with_terminator[0..inherited_fds.len()].copy_from_slice(inherited_fds);
275
276 let argv_ptr: alloc::vec::Vec<*const i8> =
277 argv.iter().map(|e| e.as_ptr() as *const i8).collect();
278
279 let mut process_id = 0;
280 let mut spgs = SpawnArgs {
281 argc: argv.len() as u64,
282 argv: argv_ptr.as_ptr(),
283 process_id: &mut process_id,
284 inherited_fds: fds_with_terminator.as_ptr(),
285 };
286
287 build_result(self.syscall(
288 index as u64,
289 source as u64,
290 place as u64,
291 bounds as u64,
292 &mut spgs as *mut _ as u64,
293 0,
294 consts::SYS_SPAWN,
295 ))
296 .map(|_| process_id)
297 }
298 fn pipe(&self) -> Result<(u64, u64), Error> {
299 let mut fds: [u64; 2] = [0, 0];
300 build_result(self.syscall(fds.as_mut_ptr() as u64, 0, 0, 0, 0, 0, consts::SYS_PIPE))
301 .map(|_| (fds[0], fds[1]))
302 }
303 fn inherited_fds(&self, fds: &mut [u64]) -> Result<usize, Error> {
306 let mut length: u64 = fds.len() as u64;
307 build_result(self.syscall(
308 fds.as_mut_ptr() as u64,
309 &mut length as *mut _ as u64,
310 0,
311 0,
312 0,
313 0,
314 consts::SYS_INHERITED_FDS,
315 ))
316 .map(|_| length as usize)
317 }
318 fn read(&self, fd: u64, buffer: &mut [u8]) -> Result<usize, Error> {
323 let mut length: u64 = buffer.len() as u64;
324 build_result(self.syscall(
325 fd,
326 buffer.as_mut_ptr() as u64,
327 &mut length as *mut _ as u64,
328 0,
329 0,
330 0,
331 consts::SYS_READ,
332 ))
333 .map(|_| length as usize)
334 }
335 fn write(&self, fd: u64, buffer: &[u8]) -> Result<usize, Error> {
337 let mut length: u64 = buffer.len() as u64;
338 build_result(self.syscall(
339 fd,
340 buffer.as_ptr() as u64,
341 &mut length as *mut _ as u64,
342 0,
343 0,
344 0,
345 consts::SYS_WRITE,
346 ))
347 .map(|_| length as usize)
348 }
349 fn close(&self, fd: u64) -> Result<(), Error> {
350 build_result(self.syscall(fd, 0, 0, 0, 0, 0, consts::SYS_CLOSE))
351 }
352 fn wait(&self, pid: u64) -> Result<i8, Error> {
354 let mut code: u64 = u64::MAX;
355 build_result(self.syscall(
356 pid,
357 &mut code as *mut _ as u64,
358 0,
359 0,
360 0,
361 0,
362 consts::SYS_WAIT,
363 ))
364 .map(|_| code as i8)
365 }
366 fn process_id(&self) -> u64 {
367 self.syscall(0, 0, 0, 0, 0, 0, consts::SYS_PROCESS_ID)
368 }
369 fn load_block_extension(
370 &self,
371 buf: &mut [u8],
372 offset: usize,
373 index: usize,
374 source: Source,
375 ) -> IoResult {
376 self.syscall_load(
377 buf,
378 offset,
379 index as u64,
380 source as u64,
381 0,
382 consts::SYS_LOAD_BLOCK_EXTENSION,
383 )
384 }
385
386 fn debug_s(&self, mut s: String) {
387 s.push('\0');
388 let bytes = s.into_bytes();
389 let c_str = CStr::from_bytes_until_nul(&bytes).unwrap();
390 self.debug(c_str)
391 }
392}
393
394pub fn syscall_to_impls<S: SyscallImpls + ?Sized>(
398 impls: &S,
399 n: u64,
400 a0: u64,
401 a1: u64,
402 a2: u64,
403 a3: u64,
404 a4: u64,
405 a5: u64,
406) -> u64 {
407 match n {
408 consts::SYS_DEBUG => {
409 impls.debug(unsafe { CStr::from_ptr(a0 as *const _) });
410 0
411 }
412 consts::SYS_EXIT => impls.exit(a0 as i8),
413 consts::SYS_LOAD_CELL => load_to_impls(a0, a1, |buf| {
414 let source: Source = a4.try_into().expect("parse source");
415 impls.load_cell(buf, a2 as usize, a3 as usize, source)
416 }),
417 consts::SYS_LOAD_CELL_BY_FIELD => load_to_impls(a0, a1, |buf| {
418 let source: Source = a4.try_into().expect("parse source");
419 let field: CellField = a5.try_into().expect("parse cell field");
420 impls.load_cell_by_field(buf, a2 as usize, a3 as usize, source, field)
421 }),
422 consts::SYS_LOAD_CELL_DATA_AS_CODE => {
423 let source: Source = a5.try_into().expect("parse source");
424 match impls.load_cell_code(
425 a0 as *mut u8,
426 a1 as usize,
427 a2 as usize,
428 a3 as usize,
429 a4 as usize,
430 source,
431 ) {
432 Ok(()) => 0,
433 Err(e) => e.into(),
434 }
435 }
436 consts::SYS_LOAD_CELL_DATA => load_to_impls(a0, a1, |buf| {
437 let source: Source = a4.try_into().expect("parse source");
438 impls.load_cell_data(buf, a2 as usize, a3 as usize, source)
439 }),
440 consts::SYS_LOAD_HEADER => load_to_impls(a0, a1, |buf| {
441 let source: Source = a4.try_into().expect("parse source");
442 impls.load_header(buf, a2 as usize, a3 as usize, source)
443 }),
444 consts::SYS_LOAD_HEADER_BY_FIELD => load_to_impls(a0, a1, |buf| {
445 let source: Source = a4.try_into().expect("parse source");
446 let field: HeaderField = a5.try_into().expect("parse header field");
447 impls.load_header_by_field(buf, a2 as usize, a3 as usize, source, field)
448 }),
449 consts::SYS_LOAD_INPUT => load_to_impls(a0, a1, |buf| {
450 let source: Source = a4.try_into().expect("parse source");
451 impls.load_input(buf, a2 as usize, a3 as usize, source)
452 }),
453 consts::SYS_LOAD_INPUT_BY_FIELD => load_to_impls(a0, a1, |buf| {
454 let source: Source = a4.try_into().expect("parse source");
455 let field: InputField = a5.try_into().expect("parse input field");
456 impls.load_input_by_field(buf, a2 as usize, a3 as usize, source, field)
457 }),
458 consts::SYS_LOAD_SCRIPT => load_to_impls(a0, a1, |buf| impls.load_script(buf, a2 as usize)),
459 consts::SYS_LOAD_SCRIPT_HASH => {
460 load_to_impls(a0, a1, |buf| impls.load_script_hash(buf, a2 as usize))
461 }
462 consts::SYS_LOAD_TRANSACTION => {
463 load_to_impls(a0, a1, |buf| impls.load_transaction(buf, a2 as usize))
464 }
465 consts::SYS_LOAD_TX_HASH => {
466 load_to_impls(a0, a1, |buf| impls.load_tx_hash(buf, a2 as usize))
467 }
468 consts::SYS_LOAD_WITNESS => load_to_impls(a0, a1, |buf| {
469 let source: Source = a4.try_into().expect("parse source");
470 impls.load_witness(buf, a2 as usize, a3 as usize, source)
471 }),
472 consts::SYS_VM_VERSION => impls.vm_version(),
473 consts::SYS_CURRENT_CYCLES => impls.current_cycles(),
474 consts::SYS_EXEC => {
475 let source: Source = a1.try_into().expect("parse source");
476 let argv = build_argv(a4, a5 as *const *const i8);
477 match impls.exec(a0 as usize, source, a2 as usize, a3 as usize, &argv) {
478 Ok(()) => 0,
479 Err(e) => e.into(),
480 }
481 }
482 consts::SYS_SPAWN => {
483 let source: Source = a1.try_into().expect("parse source");
484 let spgs_addr = a4 as *mut SpawnArgs;
485 let spgs: &mut SpawnArgs = unsafe { &mut *spgs_addr };
486
487 let argv = build_argv(spgs.argc, spgs.argv);
488 let mut fds = Vec::new();
489 let mut fd_ptr: *const u64 = spgs.inherited_fds;
490 loop {
491 let fd = unsafe { fd_ptr.read() };
492 if fd == 0 {
493 break;
494 }
495 fds.push(fd);
496 fd_ptr = unsafe { fd_ptr.offset(1) };
497 }
498 match impls.spawn(a0 as usize, source, a2 as usize, a3 as usize, &argv, &fds) {
499 Ok(process_id) => {
500 unsafe { spgs.process_id.write(process_id) };
501 0
502 }
503 Err(e) => e.into(),
504 }
505 }
506 consts::SYS_PIPE => {
507 let fds = a0 as *mut u64;
508 match impls.pipe() {
509 Ok((fd1, fd2)) => {
510 unsafe { fds.write(fd1) };
511 unsafe { fds.offset(1).write(fd2) };
512 0
513 }
514 Err(e) => e.into(),
515 }
516 }
517 consts::SYS_INHERITED_FDS => {
518 let fds_ptr = a0 as *mut u64;
519 let length_ptr = a1 as *mut u64;
520 let length = unsafe { length_ptr.read() } as usize;
521 let fds = unsafe { core::slice::from_raw_parts_mut(fds_ptr, length) };
522
523 match impls.inherited_fds(fds) {
524 Ok(actual_length) => {
525 unsafe { length_ptr.write(actual_length as u64) };
526 0
527 }
528 Err(e) => e.into(),
529 }
530 }
531 consts::SYS_READ => {
532 let buffer_ptr = a1 as *mut u8;
533 let length_ptr = a2 as *mut u64;
534 let length = unsafe { length_ptr.read() } as usize;
535 let buffer = unsafe { core::slice::from_raw_parts_mut(buffer_ptr, length) };
536
537 match impls.read(a0, buffer) {
538 Ok(read) => {
539 unsafe { length_ptr.write(read as u64) };
540 0
541 }
542 Err(e) => e.into(),
543 }
544 }
545 consts::SYS_WRITE => {
546 let buffer_ptr = a1 as *const u8;
547 let length_ptr = a2 as *mut u64;
548 let length = unsafe { length_ptr.read() } as usize;
549 let buffer = unsafe { core::slice::from_raw_parts(buffer_ptr, length) };
550
551 match impls.write(a0, buffer) {
552 Ok(read) => {
553 unsafe { length_ptr.write(read as u64) };
554 0
555 }
556 Err(e) => e.into(),
557 }
558 }
559 consts::SYS_CLOSE => match impls.close(a0) {
560 Ok(()) => 0,
561 Err(e) => e.into(),
562 },
563 consts::SYS_WAIT => match impls.wait(a0) {
564 Ok(exit_code) => {
565 let p = a1 as *mut i8;
566 unsafe { p.write(exit_code) };
567 0
568 }
569 Err(e) => e.into(),
570 },
571 consts::SYS_PROCESS_ID => impls.process_id(),
572 consts::SYS_LOAD_BLOCK_EXTENSION => load_to_impls(a0, a1, |buf| {
573 let source: Source = a4.try_into().expect("parse source");
574 impls.load_block_extension(buf, a2 as usize, a3 as usize, source)
575 }),
576 _ => panic!("Unknown syscall: {}", n),
577 }
578}
579
580fn build_argv<'a>(argc: u64, argv_ptr: *const *const i8) -> Vec<&'a CStr> {
581 let mut argv = Vec::with_capacity(argc as usize);
582 for i in 0..argc as isize {
583 let p: *const i8 = unsafe { argv_ptr.offset(i as isize).read() };
584 argv.push(unsafe { CStr::from_ptr(p as *const _) });
585 }
586 argv
587}
588
589fn load_to_impls<F>(a0: u64, a1: u64, f: F) -> u64
590where
591 F: Fn(&mut [u8]) -> IoResult,
592{
593 let buf_ptr = a0 as *mut u8;
594 let length_ptr = a1 as *mut u64;
595
596 let length = unsafe { length_ptr.read() };
597 let buf = unsafe { core::slice::from_raw_parts_mut(buf_ptr, length as usize) };
598
599 match f(buf) {
600 IoResult::FullyLoaded(loaded) => {
601 unsafe { length_ptr.write(loaded as u64) };
602 0
603 }
604 IoResult::PartialLoaded { available, .. } => {
605 unsafe { length_ptr.write(available as u64) };
606 0
607 }
608 IoResult::Error(e) => e.into(),
609 }
610}
611
612#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
616pub enum Error {
617 IndexOutOfBound,
618 ItemMissing,
619 SliceOutOfBound,
620 WrongFormat,
621 WaitFailure,
622 InvalidFd,
623 OtherEndClosed,
624 MaxVmsSpawned,
625 MaxFdsCreated,
626 Other(u64),
627}
628
629impl From<Error> for u64 {
630 fn from(e: Error) -> u64 {
631 match e {
632 Error::IndexOutOfBound => 1,
633 Error::ItemMissing => 2,
634 Error::SliceOutOfBound => 3,
635 Error::WrongFormat => 4,
636 Error::WaitFailure => 5,
637 Error::InvalidFd => 6,
638 Error::OtherEndClosed => 7,
639 Error::MaxVmsSpawned => 8,
640 Error::MaxFdsCreated => 9,
641 Error::Other(e) => e,
642 }
643 }
644}
645
646pub fn build_result(v: u64) -> Result<(), Error> {
647 if v == 0 {
648 Ok(())
649 } else {
650 Err(v.try_into().unwrap())
651 }
652}
653
654impl TryFrom<u64> for Error {
655 type Error = &'static str;
656
657 fn try_from(v: u64) -> Result<Self, Self::Error> {
658 match v {
659 0 => Err("Error cannot be zero!"),
660 1 => Ok(Error::IndexOutOfBound),
661 2 => Ok(Error::ItemMissing),
662 3 => Ok(Error::SliceOutOfBound),
663 4 => Ok(Error::WrongFormat),
664 5 => Ok(Error::WaitFailure),
665 6 => Ok(Error::InvalidFd),
666 7 => Ok(Error::OtherEndClosed),
667 8 => Ok(Error::MaxVmsSpawned),
668 9 => Ok(Error::MaxFdsCreated),
669 _ => Ok(Error::Other(v)),
670 }
671 }
672}
673
674#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
676pub enum IoResult {
677 FullyLoaded(usize),
678 PartialLoaded { loaded: usize, available: usize },
679 Error(Error),
680}
681
682impl IoResult {
683 pub fn to_result(&self) -> Result<(), Error> {
684 match self {
685 IoResult::FullyLoaded(_) => Ok(()),
686 IoResult::PartialLoaded { .. } => Ok(()),
687 IoResult::Error(e) => Err(*e),
688 }
689 }
690
691 pub fn loaded(&self) -> Option<usize> {
692 match self {
693 IoResult::FullyLoaded(l) => Some(*l),
694 IoResult::PartialLoaded { loaded, .. } => Some(*loaded),
695 IoResult::Error(_) => None,
696 }
697 }
698
699 pub fn available(&self) -> Option<usize> {
700 match self {
701 IoResult::FullyLoaded(l) => Some(*l),
702 IoResult::PartialLoaded { available, .. } => Some(*available),
703 IoResult::Error(_) => None,
704 }
705 }
706}
707
708impl From<Error> for IoResult {
709 fn from(e: Error) -> IoResult {
710 IoResult::Error(e)
711 }
712}
713
714impl From<IoResult> for Result<usize, SysError> {
715 fn from(result: IoResult) -> Result<usize, SysError> {
716 match result {
717 IoResult::FullyLoaded(l) => Ok(l),
718 IoResult::PartialLoaded { available, .. } => Err(SysError::LengthNotEnough(available)),
719 IoResult::Error(e) => Err(e.into()),
720 }
721 }
722}
723
724impl From<Error> for SysError {
725 fn from(e: Error) -> SysError {
726 match e {
727 Error::IndexOutOfBound => SysError::IndexOutOfBound,
728 Error::ItemMissing => SysError::ItemMissing,
729 Error::SliceOutOfBound => SysError::Encoding,
730 Error::WrongFormat => SysError::Unknown(4),
731 Error::WaitFailure => SysError::WaitFailure,
732 Error::InvalidFd => SysError::InvalidFd,
733 Error::OtherEndClosed => SysError::OtherEndClosed,
734 Error::MaxVmsSpawned => SysError::MaxVmsSpawned,
735 Error::MaxFdsCreated => SysError::MaxFdsCreated,
736 Error::Other(e) => SysError::Unknown(e),
737 }
738 }
739}