corevm_engine/
host_calls.rs1use crate::ProgramData;
2use alloc::vec::Vec;
3use bytes::Bytes;
4use core::ops::Range;
5use corevm_host::{
6 fs::{self, ReadBlock},
7 PAGE_SIZE,
8};
9use jam_pvm_common::{ApiError, InvokeOutcome};
10use jam_types::{Segment, SignedGas};
11
12pub trait InnerVm {
14 fn void(&mut self, page: u64, num_pages: u64) -> Result<(), ApiError>;
15 fn zero(&mut self, page: u64, num_pages: u64) -> Result<(), ApiError>;
16 fn poke(&mut self, outer_src: &[u8], inner_dst: u64) -> Result<(), ApiError>;
17 fn peek_into(&mut self, outer_dst: &mut [u8], inner_src: u64) -> Result<(), ApiError>;
18 fn invoke(
19 &mut self,
20 gas: SignedGas,
21 regs: [u64; 13],
22 ) -> Result<(InvokeOutcome, SignedGas, [u64; 13]), ApiError>;
23 fn expunge(self) -> Result<u64, ApiError>;
24
25 fn zero_poke(&mut self, outer_src: &[u8], inner_dst: u64) -> Result<(), ApiError> {
26 let page = inner_dst / PAGE_SIZE;
28 let num_pages = (outer_src.len() as u64).div_ceil(PAGE_SIZE);
29 self.zero(page, num_pages)?;
30 self.poke(outer_src, inner_dst)?;
32 Ok(())
33 }
34
35 fn poke_ro_rw_data_page(
36 &mut self,
37 data: &[u8],
38 address_range: &Range<u64>,
39 address: u64,
40 ) -> Result<(), ApiError> {
41 debug_assert_eq!(0, address % PAGE_SIZE);
42 debug_assert!(address_range.contains(&address));
43 let data_start = address - address_range.start;
44 if data_start < data.len() as u64 {
45 let data_start = data_start as usize;
47 let data_end = (data_start + PAGE_SIZE as usize).min(data.len());
48 let data_range = data_start..data_end;
49 self.zero_poke(&data[data_range], address)?;
50 } else {
51 let page = address / PAGE_SIZE;
53 self.zero(page, 1)?;
54 }
55 Ok(())
56 }
57
58 fn poke_ro_data_page(
59 &mut self,
60 address: u64,
61 program_data: &ProgramData,
62 ) -> Result<(), ApiError> {
63 self.poke_ro_rw_data_page(&program_data.ro_data[..], program_data.ro_data_range(), address)
64 }
65
66 fn poke_rw_data_page(
67 &mut self,
68 address: u64,
69 program_data: &ProgramData,
70 ) -> Result<(), ApiError> {
71 self.poke_ro_rw_data_page(&program_data.rw_data[..], program_data.rw_data_range(), address)
72 }
73
74 fn zero_stack_page(
75 &mut self,
76 address: u64,
77 program_data: &ProgramData,
78 ) -> Result<(), ApiError> {
79 debug_assert_eq!(0, address % PAGE_SIZE);
80 debug_assert!(program_data.stack_range().contains(&address));
81 let page = address / PAGE_SIZE;
82 self.zero(page, 1)
83 }
84
85 fn zero_heap_page(&mut self, address: u64, program_data: &ProgramData) -> Result<(), ApiError> {
86 debug_assert_eq!(0, address % PAGE_SIZE);
87 debug_assert!(program_data.heap_range().contains(&address));
88 let page = address / PAGE_SIZE;
89 self.zero(page, 1)
90 }
91}
92
93pub trait OuterVm {
96 type InnerVm: crate::InnerVm;
98
99 fn get_imported_page(&mut self, address: u64) -> Option<Segment>;
102
103 fn export(&mut self, segment: &[u8]) -> Result<(), ApiError>;
108
109 fn read_file_block(&mut self, block_ref: &fs::BlockRef) -> Option<Bytes>;
111
112 fn get_export_count(&mut self) -> u16;
114
115 fn get_auth_output_len(&mut self) -> u32;
117
118 fn machine(&mut self, code: &[u8], program_counter: u64) -> Result<Self::InnerVm, ApiError>;
120
121 fn read_file(&mut self, block_ref: &fs::BlockRef) -> Result<Vec<u8>, fs::Error> {
125 let mut block_reader = self.block_reader();
126 let buf = fs::read(block_ref, &mut block_reader)?;
127 Ok(buf)
128 }
129
130 fn block_reader(&mut self) -> Lookup<'_, Self> {
133 Lookup { outer_vm: self }
134 }
135}
136
137pub struct Lookup<'a, O: OuterVm + ?Sized> {
139 pub outer_vm: &'a mut O,
140}
141
142impl<O: OuterVm + ?Sized> ReadBlock for Lookup<'_, O> {
143 fn read_block(&mut self, block_ref: &fs::BlockRef) -> Result<Bytes, fs::IoError> {
144 self.outer_vm.read_file_block(block_ref).ok_or(fs::IoError)
145 }
146}