1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//! Level-3 execution: running a program with no guest kernel under it.
//!
//! `ROADMAP.md` §2 describes three depths a guest can be fed to rsemu at.
//! Level 1 emulates a machine, level 2 skips its firmware, and **level 3 has no
//! guest kernel at all**: the guest's `ecall` / `syscall` / `svc` does not
//! vector to a handler inside the guest, it leaves the core, and something in
//! Rust services it. There is no interrupt controller, no timer chip and no
//! block device, because nothing in the guest can see one.
//!
//! # Where the line is
//!
//! §2.1 settles which crate owns which half, with one test — *is it hardware?*
//! rsemu supplies the machine; [`KarpelesLab/nixvm`] supplies the Linux kernel
//! that runs on it and depends on this crate for the rest. So **this module
//! contains no syscall table, no file descriptors, no errno, no `procfs`, no
//! ELF loader and no process model.** It contains the four things a consumer
//! cannot build for itself:
//!
//! | | |
//! | --- | --- |
//! | [`core::exec`](crate::core::exec) | a core that stops *at* a syscall instruction and says so |
//! | [`mem`] | a memory map with no devices in it |
//! | [`sched`] | when guest threads run, and for how long |
//! | [`journal`] | the one door non-deterministic answers come through |
//!
//! Everything here is public, documented, and shaped to be driven from another
//! crate. That is not a nice property of this module, it is the point of it:
//! §2.1 calls a downstream consumer *"the strongest available test"* of §2's
//! claim that embedding rsemu is a supported use rather than a fork.
//!
//! [`KarpelesLab/nixvm`]: https://github.com/KarpelesLab/nixvm
//!
//! # Determinism is designed in, not added
//!
//! A syscall's result crossing into the guest is §0's *"non-deterministic input
//! crossing into the machine"*, and phase 5b makes that a gate rather than an
//! aspiration. Three decisions here discharge it, and they reinforce each
//! other:
//!
//! * **Time is virtual.** [`GuestClock`] advances by executed ticks, so a
//! consumer's `clock_gettime` is a function of the program. There is nothing
//! to record because there is nothing non-deterministic left.
//! * **Preemption is in ticks.** [`ThreadSet`] gives each thread a tick
//! quantum, so the interleaving is a function of the program too. A
//! wall-clock quantum — the obvious implementation — makes instruction counts
//! depend on how busy the host was, and quietly destroys replayability.
//! * **Everything else goes through [`Journal::ask`].** One funnel, three
//! modes, and a replay that reports the first divergence instead of
//! producing wrong output.
//!
//! # Driving it
//!
//! The loop is the consumer's; rsemu is pulled from, never called back into.
//!
//! ```no_run
//! use alloc::sync::Arc;
//! # extern crate alloc;
//! use rsemu::core::exec::{ExitMask, ExitReason, ExitingCore};
//! use rsemu::usermode::{GuestClock, Prot, ThreadSet, UserMemory};
//!
//! # fn demo(core: Arc<dyn ExitingCore>) -> rsemu::Result<()> {
//! let mem = Arc::new(UserMemory::new(48));
//! mem.map_at(0x1000, 0x1000, Prot::RX, "text")?;
//!
//! core.set_exit_mask(ExitMask::USER);
//! let threads = ThreadSet::new(Arc::new(GuestClock::new()));
//! let id = threads.insert(core);
//!
//! while let Some(stop) = threads.run_next() {
//! match stop.exit.map(|e| e.reason) {
//! Some(ExitReason::SYSCALL) => { /* service it, write the result register */ }
//! Some(ExitReason::FAULT) => { /* map a page, or deliver a signal */ }
//! _ => {} // the quantum ended; go round again
//! }
//! }
//! # let _ = id;
//! # Ok(())
//! # }
//! ```
pub use ;
pub use ;
pub use ;
pub use ;