corevm_engine/
host_calls.rs1use crate::ProgramData;
2use alloc::vec::Vec;
3use core::ops::Range;
4use corevm_host::{
5 FileRef, PageSegment, MAX_FILE_BLOCK_LEN, MAX_FILE_LEN, MIN_FILE_BLOCK_LEN, PAGE_SIZE,
6};
7use jam_pvm_common::{ApiError, InvokeOutcome};
8use jam_types::{Hash, ServiceId, SignedGas};
9
10pub trait InnerVm {
12 fn void(&mut self, page: u64, num_pages: u64) -> Result<(), ApiError>;
13 fn zero(&mut self, page: u64, num_pages: u64) -> Result<(), ApiError>;
14 fn poke(&mut self, outer_src: &[u8], inner_dst: u64) -> Result<(), ApiError>;
15 fn peek_into(&mut self, outer_dst: &mut [u8], inner_src: u64) -> Result<(), ApiError>;
16 fn invoke(
17 &mut self,
18 gas: SignedGas,
19 regs: [u64; 13],
20 ) -> Result<(InvokeOutcome, SignedGas, [u64; 13]), ApiError>;
21 fn expunge(self) -> Result<u64, ApiError>;
22
23 fn zero_poke(&mut self, outer_src: &[u8], inner_dst: u64) -> Result<(), ApiError> {
24 let page = inner_dst / PAGE_SIZE;
26 let num_pages = (outer_src.len() as u64).div_ceil(PAGE_SIZE);
27 self.zero(page, num_pages)?;
28 self.poke(outer_src, inner_dst)?;
30 Ok(())
31 }
32
33 fn poke_ro_rw_data_page(
34 &mut self,
35 data: &[u8],
36 address_range: &Range<u64>,
37 address: u64,
38 ) -> Result<(), ApiError> {
39 debug_assert_eq!(0, address % PAGE_SIZE);
40 debug_assert!(address_range.contains(&address));
41 let data_start = address - address_range.start;
42 if data_start < data.len() as u64 {
43 let data_start = data_start as usize;
45 let data_end = (data_start + PAGE_SIZE as usize).min(data.len());
46 let data_range = data_start..data_end;
47 self.zero_poke(&data[data_range], address)?;
48 } else {
49 let page = address / PAGE_SIZE;
51 self.zero(page, 1)?;
52 }
53 Ok(())
54 }
55
56 fn poke_ro_data_page(
57 &mut self,
58 address: u64,
59 program_data: &ProgramData,
60 ) -> Result<(), ApiError> {
61 self.poke_ro_rw_data_page(&program_data.ro_data[..], program_data.ro_data_range(), address)
62 }
63
64 fn poke_rw_data_page(
65 &mut self,
66 address: u64,
67 program_data: &ProgramData,
68 ) -> Result<(), ApiError> {
69 self.poke_ro_rw_data_page(&program_data.rw_data[..], program_data.rw_data_range(), address)
70 }
71
72 fn zero_stack_page(
73 &mut self,
74 address: u64,
75 program_data: &ProgramData,
76 ) -> Result<(), ApiError> {
77 debug_assert_eq!(0, address % PAGE_SIZE);
78 debug_assert!(program_data.stack_range().contains(&address));
79 let page = address / PAGE_SIZE;
80 self.zero(page, 1)
81 }
82
83 fn zero_heap_page(&mut self, address: u64, program_data: &ProgramData) -> Result<(), ApiError> {
84 debug_assert_eq!(0, address % PAGE_SIZE);
85 debug_assert!(program_data.heap_range().contains(&address));
86 let page = address / PAGE_SIZE;
87 self.zero(page, 1)
88 }
89}
90
91pub trait OuterVm {
92 type InnerVm: crate::InnerVm;
93
94 fn import(&mut self, i: usize) -> Option<PageSegment>;
95 fn export(&mut self, segment: &[u8]) -> Result<(), ApiError>;
96 fn lookup(&mut self, service_id: ServiceId, hash: &Hash) -> Option<Vec<u8>>;
97 fn get_export_count(&mut self) -> u16;
98 fn get_auth_output_len(&mut self) -> u32;
99 fn machine(&mut self, code: &[u8], program_counter: u64) -> Result<Self::InnerVm, ApiError>;
100
101 fn read_file(&mut self, file: &FileRef) -> Option<Vec<u8>> {
102 let mut data = Vec::new();
103 let mut next_hash = file.hash;
104 while next_hash != [0; 32] {
105 let block = self.lookup(file.service_id, &next_hash)?;
106 if !(MIN_FILE_BLOCK_LEN..=MAX_FILE_BLOCK_LEN).contains(&(block.len() as u64)) {
107 return None;
109 }
110 if data.len() + block.len() > MAX_FILE_LEN as usize {
111 return None;
113 }
114 data.extend_from_slice(&block[32..]);
115 next_hash = block[..32].try_into().expect("The length is 32");
116 }
117 Some(data)
118 }
119}