Skip to main content

sbpf_runtime/syscalls/
memory.rs

1use {
2    crate::config::ExecutionCost,
3    sbpf_vm::{
4        compute::ComputeMeter,
5        errors::{SbpfVmError, SbpfVmResult},
6        memory::Memory,
7    },
8};
9
10fn mem_op_consume(n: u64, compute: &ComputeMeter, costs: &ExecutionCost) -> SbpfVmResult<()> {
11    let cost = costs
12        .mem_op_base_cost
13        .max(n.checked_div(costs.cpi_bytes_per_unit).unwrap_or(u64::MAX));
14    compute.consume(cost)
15}
16
17fn is_nonoverlapping(src: u64, src_len: u64, dst: u64, dst_len: u64) -> bool {
18    if src > dst {
19        src.saturating_sub(dst) >= dst_len
20    } else {
21        dst.saturating_sub(src) >= src_len
22    }
23}
24
25pub fn sol_memcpy(
26    registers: [u64; 5],
27    memory: &mut Memory,
28    compute: &ComputeMeter,
29    costs: &ExecutionCost,
30) -> SbpfVmResult<u64> {
31    let dst = registers[0];
32    let src = registers[1];
33    let n = registers[2];
34
35    mem_op_consume(n, compute, costs)?;
36
37    if !is_nonoverlapping(src, n, dst, n) {
38        return Err(SbpfVmError::OverlappingMemoryRegions);
39    }
40
41    let data = memory.read_bytes(src, n as usize)?.to_vec();
42    memory.write_bytes(dst, &data)?;
43    Ok(0)
44}
45
46pub fn sol_memmove(
47    registers: [u64; 5],
48    memory: &mut Memory,
49    compute: &ComputeMeter,
50    costs: &ExecutionCost,
51) -> SbpfVmResult<u64> {
52    let dst = registers[0];
53    let src = registers[1];
54    let n = registers[2];
55
56    mem_op_consume(n, compute, costs)?;
57
58    let data = memory.read_bytes(src, n as usize)?.to_vec();
59    memory.write_bytes(dst, &data)?;
60    Ok(0)
61}
62
63pub fn sol_memset(
64    registers: [u64; 5],
65    memory: &mut Memory,
66    compute: &ComputeMeter,
67    costs: &ExecutionCost,
68) -> SbpfVmResult<u64> {
69    let dst = registers[0];
70    let c = registers[1] as u8;
71    let n = registers[2];
72
73    mem_op_consume(n, compute, costs)?;
74
75    let data = vec![c; n as usize];
76    memory.write_bytes(dst, &data)?;
77    Ok(0)
78}
79
80pub fn sol_memcmp(
81    registers: [u64; 5],
82    memory: &mut Memory,
83    compute: &ComputeMeter,
84    costs: &ExecutionCost,
85) -> SbpfVmResult<u64> {
86    let s1 = registers[0];
87    let s2 = registers[1];
88    let n = registers[2];
89    let result_ptr = registers[3];
90
91    mem_op_consume(n, compute, costs)?;
92
93    let s1_bytes = memory.read_bytes(s1, n as usize)?;
94    let s2_bytes = memory.read_bytes(s2, n as usize)?;
95
96    let mut result: i32 = 0;
97    for i in 0..n as usize {
98        if s1_bytes[i] != s2_bytes[i] {
99            result = (s1_bytes[i] as i32).saturating_sub(s2_bytes[i] as i32);
100            break;
101        }
102    }
103
104    memory.write_u32(result_ptr, result as u32)?;
105    Ok(0)
106}