Skip to main content

sbpf_common/execute/
mod.rs

1mod alu32;
2mod alu64;
3mod call;
4mod endian;
5mod helpers;
6mod jump;
7mod load;
8mod store;
9#[cfg(test)]
10mod test_utils;
11
12#[cfg(test)]
13pub use test_utils::{MockVm, make_test_instruction};
14use {
15    crate::{errors::ExecutionError, instruction::Instruction, opcode::Opcode},
16    alu32::{execute_alu32_imm, execute_alu32_reg, execute_neg32},
17    alu64::{execute_alu64_imm, execute_alu64_reg, execute_neg64},
18    load::{execute_lddw, execute_ldxb, execute_ldxdw, execute_ldxh, execute_ldxw},
19    store::{
20        execute_stb, execute_stdw, execute_sth, execute_stw, execute_stxb, execute_stxdw,
21        execute_stxh, execute_stxw,
22    },
23};
24pub use {
25    call::{execute_call_immediate, execute_call_register, execute_exit},
26    endian::execute_endian,
27    jump::{execute_jump, execute_jump_immediate, execute_jump_register},
28};
29
30pub type ExecutionResult<T> = Result<T, ExecutionError>;
31
32pub trait Vm {
33    fn get_register(&self, reg: usize) -> u64;
34    fn set_register(&mut self, reg: usize, value: u64);
35
36    fn get_pc(&self) -> usize;
37    fn set_pc(&mut self, pc: usize);
38    fn advance_pc(&mut self) {
39        self.set_pc(self.get_pc() + 1);
40    }
41
42    fn read_u8(&self, addr: u64) -> ExecutionResult<u8>;
43    fn read_u16(&self, addr: u64) -> ExecutionResult<u16>;
44    fn read_u32(&self, addr: u64) -> ExecutionResult<u32>;
45    fn read_u64(&self, addr: u64) -> ExecutionResult<u64>;
46
47    fn write_u8(&mut self, addr: u64, value: u8) -> ExecutionResult<()>;
48    fn write_u16(&mut self, addr: u64, value: u16) -> ExecutionResult<()>;
49    fn write_u32(&mut self, addr: u64, value: u32) -> ExecutionResult<()>;
50    fn write_u64(&mut self, addr: u64, value: u64) -> ExecutionResult<()>;
51
52    fn get_call_depth(&self) -> usize;
53    fn max_call_depth(&self) -> usize;
54    fn push_frame(
55        &mut self,
56        return_pc: usize,
57        saved_registers: [u64; 4],
58        saved_frame_pointer: u64,
59    ) -> ExecutionResult<()>;
60    fn pop_frame(&mut self) -> Option<(usize, [u64; 4], u64)>;
61
62    fn halt(&mut self, exit_code: u64);
63
64    fn get_stack_frame_size(&self) -> u64;
65
66    fn handle_syscall(&mut self, name: &str) -> ExecutionResult<u64>;
67}
68
69pub fn execute_binary_immediate(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
70    match inst.opcode {
71        Opcode::Add64Imm
72        | Opcode::Sub64Imm
73        | Opcode::Mul64Imm
74        | Opcode::Div64Imm
75        | Opcode::Or64Imm
76        | Opcode::And64Imm
77        | Opcode::Lsh64Imm
78        | Opcode::Rsh64Imm
79        | Opcode::Mod64Imm
80        | Opcode::Xor64Imm
81        | Opcode::Mov64Imm
82        | Opcode::Arsh64Imm => execute_alu64_imm(vm, inst),
83        Opcode::Add32Imm
84        | Opcode::Sub32Imm
85        | Opcode::Mul32Imm
86        | Opcode::Div32Imm
87        | Opcode::Or32Imm
88        | Opcode::And32Imm
89        | Opcode::Lsh32Imm
90        | Opcode::Rsh32Imm
91        | Opcode::Mod32Imm
92        | Opcode::Xor32Imm
93        | Opcode::Mov32Imm
94        | Opcode::Arsh32Imm => execute_alu32_imm(vm, inst),
95        _ => Err(ExecutionError::InvalidInstruction),
96    }
97}
98
99pub fn execute_binary_register(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
100    match inst.opcode {
101        Opcode::Add64Reg
102        | Opcode::Sub64Reg
103        | Opcode::Mul64Reg
104        | Opcode::Div64Reg
105        | Opcode::Or64Reg
106        | Opcode::And64Reg
107        | Opcode::Lsh64Reg
108        | Opcode::Rsh64Reg
109        | Opcode::Mod64Reg
110        | Opcode::Xor64Reg
111        | Opcode::Mov64Reg
112        | Opcode::Arsh64Reg => execute_alu64_reg(vm, inst),
113        Opcode::Add32Reg
114        | Opcode::Sub32Reg
115        | Opcode::Mul32Reg
116        | Opcode::Div32Reg
117        | Opcode::Or32Reg
118        | Opcode::And32Reg
119        | Opcode::Lsh32Reg
120        | Opcode::Rsh32Reg
121        | Opcode::Mod32Reg
122        | Opcode::Xor32Reg
123        | Opcode::Mov32Reg
124        | Opcode::Arsh32Reg => execute_alu32_reg(vm, inst),
125        _ => Err(ExecutionError::InvalidInstruction),
126    }
127}
128
129pub fn execute_unary(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
130    match inst.opcode {
131        Opcode::Neg64 => execute_neg64(vm, inst),
132        Opcode::Neg32 => execute_neg32(vm, inst),
133        _ => Err(ExecutionError::InvalidInstruction),
134    }
135}
136
137pub fn execute_load_immediate(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
138    execute_lddw(vm, inst)
139}
140
141pub fn execute_load_memory(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
142    match inst.opcode {
143        Opcode::Ldxb => execute_ldxb(vm, inst),
144        Opcode::Ldxh => execute_ldxh(vm, inst),
145        Opcode::Ldxw => execute_ldxw(vm, inst),
146        Opcode::Ldxdw => execute_ldxdw(vm, inst),
147        _ => Err(ExecutionError::InvalidInstruction),
148    }
149}
150
151pub fn execute_store_immediate(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
152    match inst.opcode {
153        Opcode::Stb => execute_stb(vm, inst),
154        Opcode::Sth => execute_sth(vm, inst),
155        Opcode::Stw => execute_stw(vm, inst),
156        Opcode::Stdw => execute_stdw(vm, inst),
157        _ => Err(ExecutionError::InvalidInstruction),
158    }
159}
160
161pub fn execute_store_register(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
162    match inst.opcode {
163        Opcode::Stxb => execute_stxb(vm, inst),
164        Opcode::Stxh => execute_stxh(vm, inst),
165        Opcode::Stxw => execute_stxw(vm, inst),
166        Opcode::Stxdw => execute_stxdw(vm, inst),
167        _ => Err(ExecutionError::InvalidInstruction),
168    }
169}