ckb_vm/machine/
mod.rs

1#[cfg(has_asm)]
2pub mod asm;
3pub mod trace;
4
5use std::fmt::{self, Display};
6use std::sync::atomic::{AtomicU8, Ordering};
7use std::sync::Arc;
8
9use bytes::Bytes;
10
11use super::debugger::Debugger;
12use super::decoder::{build_decoder, Decoder};
13use super::elf::{parse_elf, LoadingAction, ProgramMetadata};
14use super::instructions::{execute, Instruction, Register};
15use super::memory::{load_c_string_byte_by_byte, Memory};
16use super::syscalls::Syscalls;
17use super::{
18    registers::{A0, A7, REGISTER_ABI_NAMES, SP},
19    Error, ISA_MOP, RISCV_GENERAL_REGISTER_NUMBER, RISCV_MAX_MEMORY,
20};
21
22// Version 0 is the initial launched CKB VM, it is used in CKB Lina mainnet
23pub const VERSION0: u32 = 0;
24// Version 1 fixes known bugs discovered in version 0:
25// * It's not possible to read the last byte in the VM memory;
26// * https://github.com/nervosnetwork/ckb-vm/issues/92
27// * https://github.com/nervosnetwork/ckb-vm/issues/97
28// * https://github.com/nervosnetwork/ckb-vm/issues/98
29// * https://github.com/nervosnetwork/ckb-vm/issues/106
30pub const VERSION1: u32 = 1;
31pub const VERSION2: u32 = 2;
32
33/// This is the core part of RISC-V that only deals with data part, it
34/// is extracted from Machine so we can handle lifetime logic in dynamic
35/// syscall support.
36pub trait CoreMachine {
37    type REG: Register;
38    type MEM: Memory<REG = Self::REG>;
39
40    fn pc(&self) -> &Self::REG;
41    fn update_pc(&mut self, pc: Self::REG);
42    fn commit_pc(&mut self);
43    fn memory(&self) -> &Self::MEM;
44    fn memory_mut(&mut self) -> &mut Self::MEM;
45    fn registers(&self) -> &[Self::REG];
46    fn set_register(&mut self, idx: usize, value: Self::REG);
47
48    // Current running machine version, used to support compatible behavior
49    // in case of bug fixes.
50    fn version(&self) -> u32;
51    fn isa(&self) -> u8;
52}
53
54/// This is the core trait describing a full RISC-V machine. Instruction
55/// package only needs to deal with the functions in this trait.
56pub trait Machine: CoreMachine {
57    fn ecall(&mut self) -> Result<(), Error>;
58    fn ebreak(&mut self) -> Result<(), Error>;
59}
60
61/// This traits extend on top of CoreMachine by adding additional support
62/// such as ELF range, cycles which might be needed on Rust side of the logic,
63/// such as runner or syscall implementations.
64pub trait SupportMachine: CoreMachine {
65    /// Instantiate using default memory size
66    fn new(isa: u8, version: u32, max_cycles: u64) -> Self
67    where
68        Self: Sized,
69    {
70        Self::new_with_memory(isa, version, max_cycles, RISCV_MAX_MEMORY)
71    }
72
73    /// Instantiation function
74    fn new_with_memory(isa: u8, version: u32, max_cycles: u64, memory_size: usize) -> Self
75    where
76        Self: Sized;
77
78    // Current execution cycles, it's up to the actual implementation to
79    // call add_cycles for each instruction/operation to provide cycles.
80    // The implementation might also choose not to do this to ignore this
81    // feature.
82    fn cycles(&self) -> u64;
83    fn set_cycles(&mut self, cycles: u64);
84    fn max_cycles(&self) -> u64;
85    fn set_max_cycles(&mut self, cycles: u64);
86
87    fn running(&self) -> bool;
88    fn set_running(&mut self, running: bool);
89
90    // Erase all the states of the virtual machine.
91    fn reset(&mut self, max_cycles: u64);
92    fn reset_signal(&mut self) -> bool;
93
94    fn add_cycles(&mut self, cycles: u64) -> Result<(), Error> {
95        let new_cycles = self
96            .cycles()
97            .checked_add(cycles)
98            .ok_or(Error::CyclesOverflow)?;
99        if new_cycles > self.max_cycles() {
100            return Err(Error::CyclesExceeded);
101        }
102        self.set_cycles(new_cycles);
103        Ok(())
104    }
105
106    fn add_cycles_no_checking(&mut self, cycles: u64) -> Result<(), Error> {
107        let new_cycles = self
108            .cycles()
109            .checked_add(cycles)
110            .ok_or(Error::CyclesOverflow)?;
111        self.set_cycles(new_cycles);
112        Ok(())
113    }
114
115    fn load_elf_inner(&mut self, program: &Bytes, update_pc: bool) -> Result<u64, Error> {
116        let version = self.version();
117        let metadata = parse_elf::<Self::REG>(program, version)?;
118        self.load_binary(program, &metadata, update_pc)
119    }
120
121    fn load_elf(&mut self, program: &Bytes, update_pc: bool) -> Result<u64, Error> {
122        // Allows to override load_elf by writing the real function body in load_elf_inner.
123        //
124        // impl SupportMachine for Somebody {
125        //     fn load_elf(&mut self, program: &Bytes, update_pc: bool) -> Result<u64, Error> {
126        //         // Do something before load_elf
127        //         let r = self.load_elf_inner(program, update_pc);
128        //         // Do something after
129        //         return r;
130        //     }
131        // }
132        self.load_elf_inner(program, update_pc)
133    }
134
135    fn load_binary_inner(
136        &mut self,
137        program: &Bytes,
138        metadata: &ProgramMetadata,
139        update_pc: bool,
140    ) -> Result<u64, Error> {
141        let version = self.version();
142        let mut bytes: u64 = 0;
143        for action in &metadata.actions {
144            let LoadingAction {
145                addr,
146                size,
147                flags,
148                source,
149                offset_from_addr,
150            } = action;
151
152            self.memory_mut().init_pages(
153                *addr,
154                *size,
155                *flags,
156                Some(program.slice(source.start as usize..source.end as usize)),
157                *offset_from_addr,
158            )?;
159            if version < VERSION1 {
160                self.memory_mut().store_byte(*addr, *offset_from_addr, 0)?;
161            }
162            bytes = bytes
163                .checked_add(source.end - source.start)
164                .ok_or_else(|| {
165                    Error::Unexpected(String::from("The bytes count overflowed on loading elf"))
166                })?;
167        }
168        if update_pc {
169            self.update_pc(Self::REG::from_u64(metadata.entry));
170            self.commit_pc();
171        }
172        Ok(bytes)
173    }
174
175    fn load_binary(
176        &mut self,
177        program: &Bytes,
178        metadata: &ProgramMetadata,
179        update_pc: bool,
180    ) -> Result<u64, Error> {
181        // Similar to load_elf, this provides a way to adjust the behavior of load_binary_inner
182        self.load_binary_inner(program, metadata, update_pc)
183    }
184
185    fn initialize_stack(
186        &mut self,
187        args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
188        stack_start: u64,
189        stack_size: u64,
190    ) -> Result<u64, Error> {
191        // When we re-ordered the sections of a program, writing data in high memory
192        // will cause unnecessary changes. At the same time, for ckb, argc is always 0
193        // and the memory is initialized to 0, so memory writing can be safely skipped.
194        //
195        // It should be noted that when "chaos_mode" enabled and "argv" is empty,
196        // reading "argc" will return an unexpected data. This situation is not very common.
197        //
198        // See https://github.com/nervosnetwork/ckb-vm/issues/106 for more details.
199        if self.version() >= VERSION1 && args.len() == 0 {
200            let argc_size = u64::from(Self::REG::BITS / 8);
201            let origin_sp = stack_start + stack_size;
202            let unaligned_sp_address = origin_sp - argc_size;
203            let aligned_sp_address = unaligned_sp_address & (!15);
204            let used_bytes = origin_sp - aligned_sp_address;
205            self.set_register(SP, Self::REG::from_u64(aligned_sp_address));
206            return Ok(used_bytes);
207        }
208
209        // We are enforcing WXorX now, there's no need to call init_pages here
210        // since all the required bits are already set.
211        self.set_register(SP, Self::REG::from_u64(stack_start + stack_size));
212        // First value in this array is argc, then it contains the address(pointer)
213        // of each argv object.
214        let mut values = vec![Self::REG::from_u64(args.len() as u64)];
215        for arg in args {
216            let arg = arg?;
217            let len = Self::REG::from_u64(arg.len() as u64 + 1);
218            let address = self.registers()[SP].overflowing_sub(&len);
219
220            self.memory_mut().store_bytes(address.to_u64(), &arg)?;
221            self.memory_mut()
222                .store_byte(address.to_u64() + arg.len() as u64, 1, 0)?;
223
224            values.push(address.clone());
225            self.set_register(SP, address.clone());
226
227            if self.version() >= VERSION2 && address.to_u64() < stack_start {
228                // Provides an early exit to large argv array.
229                return Err(Error::MemOutOfStack);
230            }
231        }
232        if self.version() >= VERSION1 {
233            // There are 2 standard requirements of the initialized stack:
234            // 1. argv[argc] should contain a null pointer here, hence we are
235            // pushing another 0 to the values array;
236            values.push(Self::REG::zero());
237            // 2. SP must be aligned to 16-byte boundary, also considering _start
238            // will read argc from SP and argv from SP + 8, we have to factor in
239            // alignment here first, then push the values.
240            let values_bytes =
241                Self::REG::from_u64(Self::REG::BITS as u64 / 8 * values.len() as u64);
242            let unaligned_sp_address = self.registers()[SP].overflowing_sub(&values_bytes).to_u64();
243            // Perform alignment at 16-byte boundary towards lower address
244            let aligned_sp_address = unaligned_sp_address & (!15);
245            let aligned_bytes = unaligned_sp_address - aligned_sp_address;
246            self.set_register(
247                SP,
248                self.registers()[SP].overflowing_sub(&Self::REG::from_u64(aligned_bytes)),
249            );
250        }
251        // Since we are dealing with a stack, we need to push items in reversed
252        // order
253        for value in values.iter().rev() {
254            let address =
255                self.registers()[SP].overflowing_sub(&Self::REG::from_u8(Self::REG::BITS / 8));
256            if self.version() >= VERSION1 {
257                if Self::REG::BITS == 64 {
258                    self.memory_mut().store64(&address, value)?;
259                } else {
260                    self.memory_mut().store32(&address, value)?;
261                }
262            } else {
263                self.memory_mut().store32(&address, value)?;
264            }
265            self.set_register(SP, address);
266        }
267        if self.registers()[SP].to_u64() < stack_start {
268            // Args exceed stack size.
269            return Err(Error::MemOutOfStack);
270        }
271        Ok(stack_start + stack_size - self.registers()[SP].to_u64())
272    }
273
274    #[cfg(feature = "pprof")]
275    fn code(&self) -> &Bytes;
276}
277
278/// A runner trait providing APIs to drive the included DefaultMachine
279pub trait DefaultMachineRunner {
280    type Inner: SupportMachine;
281
282    /// Creates a new runner
283    fn new(machine: DefaultMachine<Self::Inner>) -> Self;
284
285    /// Fetches DefaultMachine
286    fn machine(&self) -> &DefaultMachine<Self::Inner>;
287
288    /// Fetches mutable DefaultMachine
289    fn machine_mut(&mut self) -> &mut DefaultMachine<Self::Inner>;
290
291    /// Runs the VM till paused
292    fn run(&mut self) -> Result<i8, Error>;
293
294    /// Fetches the inner SupportMachine for more processing
295    fn inner_mut(&mut self) -> &mut Self::Inner {
296        self.machine_mut().inner_mut()
297    }
298
299    /// Loads program
300    fn load_program(
301        &mut self,
302        program: &Bytes,
303        args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
304    ) -> Result<u64, Error> {
305        self.machine_mut().load_program(program, args)
306    }
307
308    /// Loads program with lazy loading metadata
309    fn load_program_with_metadata(
310        &mut self,
311        program: &Bytes,
312        metadata: &ProgramMetadata,
313        args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
314    ) -> Result<u64, Error> {
315        self.machine_mut()
316            .load_program_with_metadata(program, metadata, args)
317    }
318}
319
320#[derive(Default)]
321pub struct DefaultCoreMachine<R, M> {
322    registers: [R; RISCV_GENERAL_REGISTER_NUMBER],
323    pc: R,
324    next_pc: R,
325    reset_signal: bool,
326    memory: M,
327    cycles: u64,
328    max_cycles: u64,
329    running: bool,
330    isa: u8,
331    version: u32,
332    #[cfg(feature = "pprof")]
333    code: Bytes,
334}
335
336impl<R: Register, M: Memory<REG = R>> CoreMachine for DefaultCoreMachine<R, M> {
337    type REG = R;
338    type MEM = M;
339    fn pc(&self) -> &Self::REG {
340        &self.pc
341    }
342
343    fn update_pc(&mut self, pc: Self::REG) {
344        self.next_pc = pc;
345    }
346
347    fn commit_pc(&mut self) {
348        self.pc = self.next_pc.clone();
349    }
350
351    fn memory(&self) -> &Self::MEM {
352        &self.memory
353    }
354
355    fn memory_mut(&mut self) -> &mut Self::MEM {
356        &mut self.memory
357    }
358
359    fn registers(&self) -> &[Self::REG] {
360        &self.registers
361    }
362
363    fn set_register(&mut self, idx: usize, value: Self::REG) {
364        self.registers[idx] = value;
365    }
366
367    fn isa(&self) -> u8 {
368        self.isa
369    }
370
371    fn version(&self) -> u32 {
372        self.version
373    }
374}
375
376impl<R: Register, M: Memory<REG = R>> SupportMachine for DefaultCoreMachine<R, M> {
377    fn new_with_memory(isa: u8, version: u32, max_cycles: u64, memory_size: usize) -> Self {
378        Self {
379            registers: Default::default(),
380            pc: Default::default(),
381            next_pc: Default::default(),
382            reset_signal: Default::default(),
383            memory: M::new_with_memory(memory_size),
384            cycles: Default::default(),
385            max_cycles,
386            running: Default::default(),
387            isa,
388            version,
389            #[cfg(feature = "pprof")]
390            code: Default::default(),
391        }
392    }
393
394    fn cycles(&self) -> u64 {
395        self.cycles
396    }
397
398    fn set_cycles(&mut self, cycles: u64) {
399        self.cycles = cycles;
400    }
401
402    fn max_cycles(&self) -> u64 {
403        self.max_cycles
404    }
405
406    fn set_max_cycles(&mut self, max_cycles: u64) {
407        self.max_cycles = max_cycles;
408    }
409
410    fn reset(&mut self, max_cycles: u64) {
411        self.registers = Default::default();
412        self.pc = Default::default();
413        self.memory = M::new_with_memory(self.memory().memory_size());
414        self.cycles = 0;
415        self.max_cycles = max_cycles;
416        self.reset_signal = true;
417        self.memory_mut().set_lr(&R::from_u64(u64::MAX));
418    }
419
420    fn reset_signal(&mut self) -> bool {
421        let ret = self.reset_signal;
422        self.reset_signal = false;
423        ret
424    }
425
426    fn running(&self) -> bool {
427        self.running
428    }
429
430    fn set_running(&mut self, running: bool) {
431        self.running = running;
432    }
433
434    fn load_binary(
435        &mut self,
436        program: &Bytes,
437        metadata: &ProgramMetadata,
438        update_pc: bool,
439    ) -> Result<u64, Error> {
440        #[cfg(feature = "pprof")]
441        {
442            self.code = program.clone();
443        }
444        self.load_binary_inner(program, metadata, update_pc)
445    }
446
447    fn load_elf(&mut self, program: &Bytes, update_pc: bool) -> Result<u64, Error> {
448        #[cfg(feature = "pprof")]
449        {
450            self.code = program.clone();
451        }
452        self.load_elf_inner(program, update_pc)
453    }
454
455    #[cfg(feature = "pprof")]
456    fn code(&self) -> &Bytes {
457        &self.code
458    }
459}
460
461impl<R: Register, M: Memory> DefaultCoreMachine<R, M> {
462    pub fn set_max_cycles(&mut self, cycles: u64) {
463        self.max_cycles = cycles;
464    }
465
466    pub fn take_memory(self) -> M {
467        self.memory
468    }
469}
470
471pub type InstructionCycleFunc = dyn Fn(Instruction) -> u64 + Send + Sync;
472
473pub struct DefaultMachine<Inner> {
474    inner: Inner,
475    pause: Pause,
476
477    // We have run benchmarks on secp256k1 verification, the performance
478    // cost of the Box wrapper here is neglectable, hence we are sticking
479    // with Box solution for simplicity now. Later if this becomes an issue,
480    // we can change to static dispatch.
481    instruction_cycle_func: Box<InstructionCycleFunc>,
482    debugger: Option<Box<dyn Debugger<Inner>>>,
483    syscalls: Vec<Box<dyn Syscalls<Inner>>>,
484    exit_code: i8,
485}
486
487impl<Inner: CoreMachine> CoreMachine for DefaultMachine<Inner> {
488    type REG = <Inner as CoreMachine>::REG;
489    type MEM = <Inner as CoreMachine>::MEM;
490
491    fn pc(&self) -> &Self::REG {
492        self.inner.pc()
493    }
494
495    fn update_pc(&mut self, pc: Self::REG) {
496        self.inner.update_pc(pc);
497    }
498
499    fn commit_pc(&mut self) {
500        self.inner.commit_pc();
501    }
502
503    fn memory(&self) -> &Self::MEM {
504        self.inner.memory()
505    }
506
507    fn memory_mut(&mut self) -> &mut Self::MEM {
508        self.inner.memory_mut()
509    }
510
511    fn registers(&self) -> &[Self::REG] {
512        self.inner.registers()
513    }
514
515    fn set_register(&mut self, idx: usize, value: Self::REG) {
516        self.inner.set_register(idx, value)
517    }
518
519    fn isa(&self) -> u8 {
520        self.inner.isa()
521    }
522
523    fn version(&self) -> u32 {
524        self.inner.version()
525    }
526}
527
528impl<Inner: SupportMachine> SupportMachine for DefaultMachine<Inner> {
529    fn new_with_memory(_isa: u8, _version: u32, _max_cycles: u64, _memory_size: usize) -> Self {
530        panic!("Please instantiate DefaultMachine using DefaultMachineBuilder!");
531    }
532
533    fn cycles(&self) -> u64 {
534        self.inner.cycles()
535    }
536
537    fn set_cycles(&mut self, cycles: u64) {
538        self.inner.set_cycles(cycles)
539    }
540
541    fn max_cycles(&self) -> u64 {
542        self.inner.max_cycles()
543    }
544
545    fn set_max_cycles(&mut self, max_cycles: u64) {
546        self.inner.set_max_cycles(max_cycles)
547    }
548
549    fn reset(&mut self, max_cycles: u64) {
550        self.inner_mut().reset(max_cycles);
551    }
552
553    fn reset_signal(&mut self) -> bool {
554        self.inner_mut().reset_signal()
555    }
556
557    fn running(&self) -> bool {
558        self.inner.running()
559    }
560
561    fn set_running(&mut self, running: bool) {
562        self.inner.set_running(running);
563    }
564
565    fn load_binary(
566        &mut self,
567        program: &Bytes,
568        metadata: &ProgramMetadata,
569        update_pc: bool,
570    ) -> Result<u64, Error> {
571        self.inner.load_binary(program, metadata, update_pc)
572    }
573
574    fn load_elf(&mut self, program: &Bytes, update_pc: bool) -> Result<u64, Error> {
575        self.inner.load_elf(program, update_pc)
576    }
577
578    #[cfg(feature = "pprof")]
579    fn code(&self) -> &Bytes {
580        self.inner.code()
581    }
582}
583
584impl<Inner: SupportMachine> Machine for DefaultMachine<Inner> {
585    fn ecall(&mut self) -> Result<(), Error> {
586        let code = self.registers()[A7].to_u64();
587        match code {
588            93 => {
589                // exit
590                self.exit_code = self.registers()[A0].to_i8();
591                self.set_running(false);
592                Ok(())
593            }
594            _ => {
595                for syscall in &mut self.syscalls {
596                    let processed = syscall.ecall(&mut self.inner)?;
597                    if processed {
598                        if self.cycles() > self.max_cycles() {
599                            return Err(Error::CyclesExceeded);
600                        }
601                        return Ok(());
602                    }
603                }
604                Err(Error::InvalidEcall(code))
605            }
606        }
607    }
608
609    fn ebreak(&mut self) -> Result<(), Error> {
610        if let Some(debugger) = &mut self.debugger {
611            debugger.ebreak(&mut self.inner)
612        } else {
613            // Unlike ecall, the default behavior of an EBREAK operation is
614            // a dummy one.
615            Ok(())
616        }
617    }
618}
619
620impl<Inner: CoreMachine> Display for DefaultMachine<Inner> {
621    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
622        writeln!(f, "pc  : 0x{:16X}", self.pc().to_u64())?;
623        for (i, name) in REGISTER_ABI_NAMES.iter().enumerate() {
624            write!(f, "{:4}: 0x{:16X}", name, self.registers()[i].to_u64())?;
625            if (i + 1) % 4 == 0 {
626                writeln!(f)?;
627            } else {
628                write!(f, " ")?;
629            }
630        }
631        Ok(())
632    }
633}
634
635impl<Inner: SupportMachine> DefaultMachineRunner for DefaultMachine<Inner> {
636    type Inner = Inner;
637
638    fn new(machine: DefaultMachine<Inner>) -> Self {
639        machine
640    }
641
642    fn machine(&self) -> &DefaultMachine<Inner> {
643        self
644    }
645
646    fn machine_mut(&mut self) -> &mut DefaultMachine<Inner> {
647        self
648    }
649
650    fn run(&mut self) -> Result<i8, Error> {
651        self.run()
652    }
653}
654
655impl<Inner: SupportMachine> DefaultMachine<Inner> {
656    pub fn load_program(
657        &mut self,
658        program: &Bytes,
659        args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
660    ) -> Result<u64, Error> {
661        let elf_bytes = self.load_elf(program, true)?;
662        let stack_bytes = self.initialize(args)?;
663        let bytes = elf_bytes.checked_add(stack_bytes).ok_or_else(|| {
664            Error::Unexpected(String::from(
665                "The bytes count overflowed on loading program",
666            ))
667        })?;
668        Ok(bytes)
669    }
670
671    pub fn load_program_with_metadata(
672        &mut self,
673        program: &Bytes,
674        metadata: &ProgramMetadata,
675        args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
676    ) -> Result<u64, Error> {
677        let elf_bytes = self.load_binary(program, metadata, true)?;
678        let stack_bytes = self.initialize(args)?;
679        let bytes = elf_bytes.checked_add(stack_bytes).ok_or_else(|| {
680            Error::Unexpected(String::from(
681                "The bytes count overflowed on loading program",
682            ))
683        })?;
684        Ok(bytes)
685    }
686
687    fn initialize(
688        &mut self,
689        args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
690    ) -> Result<u64, Error> {
691        for syscall in &mut self.syscalls {
692            syscall.initialize(&mut self.inner)?;
693        }
694        if let Some(debugger) = &mut self.debugger {
695            debugger.initialize(&mut self.inner)?;
696        }
697        let memory_size = self.memory().memory_size();
698        let stack_size = memory_size / 4;
699        let stack_bytes =
700            self.initialize_stack(args, (memory_size - stack_size) as u64, stack_size as u64)?;
701        // Make sure SP is 16 byte aligned
702        if self.inner.version() >= VERSION1 {
703            debug_assert!(self.registers()[SP].to_u64() % 16 == 0);
704        }
705        Ok(stack_bytes)
706    }
707
708    pub fn take_inner(self) -> Inner {
709        self.inner
710    }
711
712    pub fn pause(&self) -> Pause {
713        self.pause.clone()
714    }
715
716    pub fn set_pause(&mut self, pause: Pause) {
717        self.pause = pause;
718    }
719
720    pub fn exit_code(&self) -> i8 {
721        self.exit_code
722    }
723
724    pub fn instruction_cycle_func(&self) -> &InstructionCycleFunc {
725        &self.instruction_cycle_func
726    }
727
728    pub fn inner_mut(&mut self) -> &mut Inner {
729        &mut self.inner
730    }
731
732    // This is the most naive way of running the VM, it only decodes each
733    // instruction and run it, no optimization is performed here. It might
734    // not be practical in production, but it serves as a baseline and
735    // reference implementation
736    pub fn run(&mut self) -> Result<i8, Error> {
737        if self.isa() & ISA_MOP != 0 && self.version() == VERSION0 {
738            return Err(Error::InvalidVersion);
739        }
740        let mut decoder = build_decoder::<Inner::REG>(self.isa(), self.version());
741        self.set_running(true);
742        while self.running() {
743            if self.pause.has_interrupted() {
744                self.pause.free();
745                return Err(Error::Pause);
746            }
747            if self.reset_signal() {
748                decoder.reset_instructions_cache();
749            }
750            self.step(&mut decoder)?;
751        }
752        Ok(self.exit_code())
753    }
754
755    pub fn step(&mut self, decoder: &mut Decoder) -> Result<(), Error> {
756        let instruction = {
757            let pc = self.pc().to_u64();
758            let memory = self.memory_mut();
759            decoder.decode(memory, pc)?
760        };
761        let cycles = self.instruction_cycle_func()(instruction);
762        self.add_cycles(cycles)?;
763        execute(instruction, self)
764    }
765}
766
767pub struct DefaultMachineBuilder<Inner> {
768    inner: Inner,
769    instruction_cycle_func: Box<InstructionCycleFunc>,
770    debugger: Option<Box<dyn Debugger<Inner>>>,
771    syscalls: Vec<Box<dyn Syscalls<Inner>>>,
772    pause: Pause,
773}
774
775impl<Inner> DefaultMachineBuilder<Inner> {
776    pub fn new(inner: Inner) -> Self {
777        Self {
778            inner,
779            instruction_cycle_func: Box::new(|_| 0),
780            debugger: None,
781            syscalls: vec![],
782            pause: Pause::new(),
783        }
784    }
785
786    pub fn instruction_cycle_func(
787        mut self,
788        instruction_cycle_func: Box<InstructionCycleFunc>,
789    ) -> Self {
790        self.instruction_cycle_func = instruction_cycle_func;
791        self
792    }
793
794    pub fn syscall(mut self, syscall: Box<dyn Syscalls<Inner>>) -> Self {
795        self.syscalls.push(syscall);
796        self
797    }
798
799    pub fn pause(mut self, pause: Pause) -> Self {
800        self.pause = pause;
801        self
802    }
803
804    pub fn debugger(mut self, debugger: Box<dyn Debugger<Inner>>) -> Self {
805        self.debugger = Some(debugger);
806        self
807    }
808
809    pub fn build(self) -> DefaultMachine<Inner> {
810        DefaultMachine {
811            inner: self.inner,
812            pause: self.pause,
813            instruction_cycle_func: self.instruction_cycle_func,
814            debugger: self.debugger,
815            syscalls: self.syscalls,
816            exit_code: 0,
817        }
818    }
819}
820
821#[derive(Clone, Default)]
822pub struct Pause {
823    s: Arc<AtomicU8>,
824}
825
826impl Pause {
827    pub fn new() -> Self {
828        Self {
829            s: Arc::new(AtomicU8::new(0)),
830        }
831    }
832
833    pub fn interrupt(&self) {
834        self.s.store(1, Ordering::SeqCst);
835    }
836
837    pub fn has_interrupted(&self) -> bool {
838        self.s.load(Ordering::SeqCst) != 0
839    }
840
841    pub fn get_raw_ptr(&self) -> *mut u8 {
842        &*self.s as *const _ as *mut u8
843    }
844
845    pub fn free(&mut self) {
846        self.s.store(0, Ordering::SeqCst);
847    }
848}
849
850pub struct FlattenedArgsReader<'a, M: Memory> {
851    memory: &'a mut M,
852    argc: M::REG,
853    argv: M::REG,
854    cidx: M::REG,
855}
856impl<'a, M: Memory> FlattenedArgsReader<'a, M> {
857    pub fn new(memory: &'a mut M, argc: M::REG, argv: M::REG) -> Self {
858        Self {
859            memory,
860            argc,
861            argv,
862            cidx: M::REG::zero(),
863        }
864    }
865}
866impl<'a, M: Memory> Iterator for FlattenedArgsReader<'a, M> {
867    type Item = Result<Bytes, Error>;
868    fn next(&mut self) -> Option<Self::Item> {
869        if self.cidx.ge(&self.argc).to_u8() == 1 {
870            return None;
871        }
872        let addr = match M::REG::BITS {
873            32 => self.memory.load32(&self.argv),
874            64 => self.memory.load64(&self.argv),
875            _ => unreachable!(),
876        };
877        if let Err(err) = addr {
878            return Some(Err(err));
879        };
880        let addr = addr.unwrap();
881        let cstr = load_c_string_byte_by_byte(self.memory, &addr);
882        if let Err(err) = cstr {
883            return Some(Err(err));
884        };
885        let cstr = cstr.unwrap();
886        self.cidx = self.cidx.overflowing_add(&M::REG::from_u8(1));
887        self.argv = self
888            .argv
889            .overflowing_add(&M::REG::from_u8(M::REG::BITS / 8));
890        Some(Ok(cstr))
891    }
892}
893impl<'a, M: Memory> ExactSizeIterator for FlattenedArgsReader<'a, M> {
894    fn len(&self) -> usize {
895        self.argc.to_u64() as usize
896    }
897}
898
899#[cfg(test)]
900mod tests {
901    use std::sync::atomic::AtomicU8;
902
903    #[test]
904    fn test_atomicu8() {
905        // Assert AtomicU8 type has the same in-memory representation as u8.
906        // This ensures that Pause::get_raw_ptr() works properly.
907        assert_eq!(std::mem::size_of::<AtomicU8>(), 1);
908    }
909}