Skip to main content

corevm_host/
page.rs

1use codec::{ConstEncodedLen, Decode, Encode, MaxEncodedLen};
2use jam_types::SEGMENT_LEN;
3
4/// Inner VM page size.
5pub const PAGE_SIZE: u32 = 4096;
6
7pub(crate) const MIN_PAGE: u32 = 16;
8pub(crate) const MAX_PAGE: u32 = u32::MAX / PAGE_SIZE;
9
10/// Page number.
11#[derive(
12	Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Encode, Decode, MaxEncodedLen,
13)]
14pub struct PageNum(pub u32);
15
16impl PageNum {
17	pub const fn from_address(address: u32) -> Self {
18		Self(address / PAGE_SIZE)
19	}
20
21	pub const fn address(self) -> u32 {
22		self.0 * PAGE_SIZE
23	}
24}
25
26impl core::fmt::Debug for PageNum {
27	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
28		let page = self.0;
29		let address = page.saturating_mul(PAGE_SIZE);
30		let comment = if (MIN_PAGE..=MAX_PAGE).contains(&page) { "" } else { " (invalid!)" };
31		write!(f, "{page}/{address:#x}{comment}")
32	}
33}
34
35impl core::fmt::Display for PageNum {
36	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37		core::fmt::Debug::fmt(self, f)
38	}
39}
40
41impl ConstEncodedLen for PageNum {}
42
43/// An import/export segment that stores an inner VM page and its number.
44///
45/// The page is stored in the first 4096 bytes,
46/// the number is encoded using little-endian format in the next 4 bytes.
47/// The last 4 bytes are unused.
48///
49/// `[ page(4096) | page_number(4) | unused(4) ]`
50pub trait PageSegmentOps {
51	/// Get immutable reference to the page contents (excluding the address).
52	fn page(&self) -> &[u8; PAGE_SIZE as usize];
53
54	/// Get mutable reference to the page contents (excluding the address).
55	fn page_mut(&mut self) -> &mut [u8; PAGE_SIZE as usize];
56
57	/// Get page number.
58	fn page_number(&self) -> PageNum;
59
60	/// Set page number.
61	fn set_page_number(&mut self, page: PageNum);
62}
63
64impl PageSegmentOps for [u8; SEGMENT_LEN] {
65	fn page(&self) -> &[u8; PAGE_SIZE as usize] {
66		(&self[..PAGE_SIZE as usize])
67			.try_into()
68			.expect("Slice and array have the same length")
69	}
70
71	fn page_mut(&mut self) -> &mut [u8; PAGE_SIZE as usize] {
72		(&mut self[..PAGE_SIZE as usize])
73			.try_into()
74			.expect("Slice and array have the same length")
75	}
76
77	fn page_number(&self) -> PageNum {
78		let a = &self[PAGE_SIZE as usize..];
79		let page = u32::from_le_bytes([a[0], a[1], a[2], a[3]]);
80		PageNum(page)
81	}
82
83	fn set_page_number(&mut self, page: PageNum) {
84		self[PAGE_SIZE as usize..][..4].copy_from_slice(&page.0.to_le_bytes()[..]);
85	}
86}