use core::ops::Range;
use corevm_host::PAGE_SIZE;
pub struct MemoryMap {
address_ranges: [Range<u32>; 4],
}
impl MemoryMap {
pub fn new(memory_map: &polkavm::MemoryMap) -> Self {
let heap_start = memory_map.heap_base().next_multiple_of(PAGE_SIZE);
let heap_end = heap_start + memory_map.max_heap_size();
let heap_range = heap_start..heap_end;
let stack_range = memory_map.stack_range();
let stack_range = stack_range.start..stack_range.end;
let ro_data_range = memory_map.ro_data_range();
let ro_data_range = ro_data_range.start..ro_data_range.end;
let rw_data_range = memory_map.rw_data_range();
let rw_data_range = rw_data_range.start..rw_data_range.end;
Self { address_ranges: [ro_data_range, rw_data_range, stack_range, heap_range] }
}
pub fn classify_address(&self, address: u32) -> Option<AddressKind> {
AddressKind::ALL
.into_iter()
.find(|&kind| self.address_ranges[kind as usize].contains(&address))
}
pub fn classify_page(&self, page: u32) -> Option<AddressKind> {
let address = page.checked_mul(PAGE_SIZE)?;
AddressKind::ALL
.into_iter()
.find(|&kind| self.address_ranges[kind as usize].contains(&address))
}
pub fn address_range(&self, kind: AddressKind) -> &Range<u32> {
&self.address_ranges[kind as usize]
}
pub fn stack_range(&self) -> &Range<u32> {
self.address_range(AddressKind::Stack)
}
pub fn heap_range(&self) -> &Range<u32> {
self.address_range(AddressKind::Heap)
}
pub fn ro_data_range(&self) -> &Range<u32> {
self.address_range(AddressKind::RoData)
}
pub fn rw_data_range(&self) -> &Range<u32> {
self.address_range(AddressKind::RwData)
}
}
impl core::fmt::Debug for MemoryMap {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("MemoryMap")
.field("ro_data_range", &format_args!("{:#x?}", self.ro_data_range()))
.field("rw_data_range", &format_args!("{:#x?}", self.rw_data_range()))
.field("stack_range", &format_args!("{:#x?}", self.stack_range()))
.field("heap_range", &format_args!("{:#x?}", self.heap_range()))
.finish_non_exhaustive()
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum AddressKind {
RoData = 0,
RwData = 1,
Stack = 2,
Heap = 3,
}
impl AddressKind {
pub const ALL: [Self; 4] = [Self::RoData, Self::RwData, Self::Stack, Self::Heap];
pub(crate) const fn as_str(self) -> &'static str {
match self {
Self::RoData => "ro",
Self::RwData => "rw",
Self::Stack => "stack",
Self::Heap => "heap",
}
}
}
impl core::fmt::Debug for AddressKind {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(self.as_str())
}
}