javm_exec/ecall.rs
1//! `EcallHandler` trait: how the execution engine dispatches ecalls
2//! to the integration layer.
3//!
4//! Per architecture: the engine knows there are ecalls and that each
5//! carries a kind (custom-0 `ecall.jar`, funct3=001, no immediate, vs
6//! custom-0 `ecalli`, funct3=010, with a sign-extended imm12 carried
7//! as a u32). It doesn't know what the kind *means*. The caller
8//! supplies an `EcallHandler` that interprets ecalls as MGMT
9//! operations, host-call selectors, CALL / HALT / yield transfers, etc.
10//!
11//! The handler may either:
12//!
13//! - Return `Continue` — engine continues at the current PC
14//! (already advanced past the ecall instruction before the handler
15//! runs). Used for purely-stateful ecalls (MGMT_COPY, MGMT_MOVE,
16//! etc.) that just mutate `regs` / `mem` and resume.
17//!
18//! - Return `Exit(reason)` — engine returns this `ExitReason` from
19//! `execute()`. Used for control-flow ecalls (HALT, yield, CALL
20//! into another Instance) that require the integration layer.
21
22use crate::exit::ExitReason;
23use crate::mem::Memory;
24use crate::regs::Regs;
25
26/// Which custom-0 ecall encoding triggered this invocation.
27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
28pub enum EcallKind {
29 /// `ecall.jar` (custom-0 funct3=001). No immediate; the handler
30 /// reads the operand registers per the ABI convention it defines.
31 Ecall,
32 /// `ecalli imm` (custom-0 funct3=010). Carries the sign-extended
33 /// imm12 as a u32 payload.
34 Ecalli(u32),
35}
36
37/// Result of handling one ecall.
38#[derive(Clone, Debug, PartialEq, Eq)]
39pub enum EcallResult {
40 /// Engine continues at the current PC (advanced past the ecall).
41 Continue,
42 /// Engine exits with the given reason.
43 Exit(ExitReason),
44}
45
46/// Trait the integration layer implements to interpret ecalls.
47///
48/// PC has been advanced past the instruction by the engine; the
49/// handler operates on the post-advance register/memory state.
50pub trait EcallHandler {
51 fn handle(&mut self, kind: EcallKind, regs: &mut Regs, mem: &mut dyn Memory) -> EcallResult;
52}
53
54/// A no-op handler: every ecall exits with `Panic`. Useful as a
55/// default for tests where the engine isn't supposed to encounter
56/// ecalls.
57#[derive(Debug, Default)]
58pub struct PanickingHandler;
59
60impl EcallHandler for PanickingHandler {
61 fn handle(&mut self, _kind: EcallKind, _regs: &mut Regs, _mem: &mut dyn Memory) -> EcallResult {
62 EcallResult::Exit(ExitReason::Panic)
63 }
64}