1#[cfg(target_family = "unix")]
2mod arch {
3 use ckb_vm::{
4 Error, Memory, Register, SupportMachine, Syscalls,
5 registers::{A0, A1, A2, A7},
6 };
7
8 #[derive(Clone, Debug, Default)]
9 #[repr(C)]
10 struct AbiStat {
11 dev: u64,
12 ino: u64,
13 mode: u32,
14 nlink: i32,
15 uid: u32,
16 gid: u32,
17 rdev: u64,
18 __pad1: u64,
19 size: i64,
20 blksize: i32,
21 __pad2: i32,
22 blocks: i64,
23 atime: i64,
24 atime_nsec: i64,
25 mtime: i64,
26 mtime_nsec: i64,
27 ctime: i64,
28 ctime_nsec: i64,
29 __unused4: i32,
30 __unused5: i32,
31 }
32
33 #[derive(Default)]
34 pub struct Stdio {
35 keep_stdios: bool,
36 }
37
38 impl Stdio {
39 pub fn new(keep_stdios: bool) -> Self {
40 Stdio { keep_stdios }
41 }
42
43 fn close<Mac: SupportMachine>(&mut self, machine: &mut Mac) -> Result<(), Error> {
44 let fd = machine.registers()[A0].to_i32();
45 if (fd >= 0 && fd <= 2) && self.keep_stdios {
46 machine.set_register(A0, Mac::REG::zero());
47 return Ok(());
48 }
49 let ret = match nix::unistd::close(fd) {
50 Ok(()) => 0,
51 Err(e) => {
52 println!("Error: {:?}", e);
53 (-1i64) as u64
54 }
55 };
56 machine.set_register(A0, Mac::REG::from_u64(ret));
57 Ok(())
58 }
59
60 fn fstat<Mac: SupportMachine>(&mut self, machine: &mut Mac) -> Result<(), Error> {
61 let stat = match nix::sys::stat::fstat(machine.registers()[A0].to_i32()) {
62 Ok(stat) => stat,
63 Err(e) => {
64 println!("Error: {:?}", e);
65 machine.set_register(A0, Mac::REG::from_i8(-1));
66 return Ok(());
67 }
68 };
69 let mut abi_stat = AbiStat::default();
70 abi_stat.dev = stat.st_dev as u64;
71 abi_stat.ino = stat.st_ino;
72 abi_stat.mode = stat.st_mode as u32;
73 abi_stat.nlink = stat.st_nlink as i32;
74 abi_stat.uid = stat.st_uid;
75 abi_stat.gid = stat.st_gid;
76 abi_stat.rdev = stat.st_rdev as u64;
77 abi_stat.size = stat.st_size;
78 abi_stat.blksize = stat.st_blksize as i32;
79 abi_stat.blocks = stat.st_blocks;
80 abi_stat.atime = stat.st_atime;
81 abi_stat.atime_nsec = stat.st_atime_nsec;
82 abi_stat.mtime = stat.st_mtime;
83 abi_stat.mtime_nsec = stat.st_mtime_nsec;
84 abi_stat.ctime = stat.st_ctime;
85 abi_stat.ctime_nsec = stat.st_ctime_nsec;
86 let len = std::mem::size_of::<AbiStat>();
87 let b: &[u8] = unsafe { std::slice::from_raw_parts(&abi_stat as *const AbiStat as *const u8, len) };
88 let addr = machine.registers()[A1].to_u64();
89 machine.memory_mut().store_bytes(addr, b)?;
90 machine.set_register(A0, Mac::REG::zero());
91 Ok(())
92 }
93
94 fn lseek<Mac: SupportMachine>(&mut self, machine: &mut Mac) -> Result<(), Error> {
95 let fd = machine.registers()[A0].to_i32();
96 let offset = machine.registers()[A1].to_i64();
97 let whence = match machine.registers()[A2].to_i32() {
98 libc::SEEK_SET => nix::unistd::Whence::SeekSet,
99 libc::SEEK_CUR => nix::unistd::Whence::SeekCur,
100 libc::SEEK_END => nix::unistd::Whence::SeekEnd,
101 _ => return Err(Error::Unexpected("Unexpected whence".into())),
102 };
103 let ret = nix::unistd::lseek(fd, offset, whence).unwrap_or_else(|e| {
104 println!("Error: {:?}", e);
105 -1
106 });
107 machine.set_register(A0, Mac::REG::from_i64(ret));
108 Ok(())
109 }
110
111 fn read<Mac: SupportMachine>(&mut self, machine: &mut Mac) -> Result<(), Error> {
112 let fd = machine.registers()[A0].to_i32();
113 let addr = machine.registers()[A1].to_u64();
114 let size = machine.registers()[A2].to_u64() as usize;
115 let mut buf = vec![0u8; size];
116
117 match nix::unistd::read(fd, &mut buf) {
118 Ok(read_size) => {
119 machine.memory_mut().store_bytes(addr, &buf[0..read_size])?;
120 machine.set_register(A0, Mac::REG::from_u64(read_size as u64));
121 }
122 Err(e) => {
123 println!("Error: {:?}", e);
124 machine.set_register(A0, Mac::REG::from_i64(-1i64));
125 }
126 };
127 Ok(())
128 }
129
130 fn write<Mac: SupportMachine>(&mut self, machine: &mut Mac) -> Result<(), Error> {
131 let fd = machine.registers()[A0].to_i32();
132 let addr = machine.registers()[A1].to_u64();
133 let size = machine.registers()[A2].to_u64() as usize;
134 let mut buf = vec![0u8; size];
135 for i in 0..size {
136 buf[i] = machine.memory_mut().load8(&Mac::REG::from_u64(addr + i as u64))?.to_u8();
137 }
138 let ret = nix::unistd::write(fd, &buf).unwrap_or_else(|e| {
139 println!("Error: {:?}", e);
140 (-1isize) as usize
141 });
142 machine.set_register(A0, Mac::REG::from_u64(ret as u64));
143 Ok(())
144 }
145
146 fn writev<Mac: SupportMachine>(&mut self, machine: &mut Mac) -> Result<(), Error> {
147 let fd = machine.registers()[A0].to_i32();
148 let iov = machine.registers()[A1].to_u64();
149 let iovcnt = machine.registers()[A2].to_u64();
150
151 let mut written = 0;
152 for i in 0..iovcnt {
153 let base = machine.memory_mut().load64(&Mac::REG::from_u64(iov + i * 16))?.to_u64();
154 let len = machine.memory_mut().load64(&Mac::REG::from_u64(iov + i * 16 + 8))?.to_u64();
155
156 let buf = machine.memory_mut().load_bytes(base, len)?;
157
158 written += match nix::unistd::write(fd, &buf) {
159 Ok(w) => w as u64,
160 Err(e) => {
161 println!("Error: {:?}", e);
162 machine.set_register(A0, Mac::REG::from_i64(-1));
163 return Ok(());
164 }
165 };
166 }
167 machine.set_register(A0, Mac::REG::from_u64(written));
168 Ok(())
169 }
170 }
171
172 impl<Mac: SupportMachine> Syscalls<Mac> for Stdio {
173 fn initialize(&mut self, _machine: &mut Mac) -> Result<(), Error> {
174 Ok(())
175 }
176
177 fn ecall(&mut self, machine: &mut Mac) -> Result<bool, Error> {
178 match machine.registers()[A7].to_u64() {
179 57 => self.close(machine)?,
180 62 => self.lseek(machine)?,
181 63 => self.read(machine)?,
182 64 => self.write(machine)?,
183 66 => self.writev(machine)?,
184 80 => self.fstat(machine)?,
185 _ => return Ok(false),
186 };
187 Ok(true)
188 }
189 }
190}
191
192#[cfg(any(target_family = "wasm", target_family = "windows"))]
193mod arch {
194 use ckb_vm::{Error, SupportMachine, Syscalls};
195
196 #[derive(Default)]
197 pub struct Stdio {}
198
199 impl Stdio {
200 pub fn new(_: bool) -> Self {
201 Stdio {}
202 }
203 }
204
205 impl<Mac: SupportMachine> Syscalls<Mac> for Stdio {
206 fn initialize(&mut self, _machine: &mut Mac) -> Result<(), Error> {
207 Ok(())
208 }
209
210 fn ecall(&mut self, _machine: &mut Mac) -> Result<bool, Error> {
211 Ok(false)
212 }
213 }
214}
215
216pub use arch::Stdio;