zkvmc_core/memory/
mod.rs

1mod forkable;
2mod mmap;
3
4use core::ptr::copy_nonoverlapping;
5use std::{
6    ptr::{self, NonNull},
7    slice::from_raw_parts,
8};
9
10pub use forkable::ForkableMemory;
11pub use mmap::{Mmap, MmapOffset};
12
13use crate::send_sync_ptr::SendSyncPtr;
14
15/// Memory access functions.
16pub unsafe fn read_bytes<'a>(mem: *const u8, addr: u32, len: usize) -> &'a [u8] {
17    from_raw_parts(mem.add(addr as usize), len)
18}
19
20pub unsafe fn read_words<'a>(mem: *const u8, addr: u32, len: usize) -> &'a [u32] {
21    let bytes = read_bytes(mem, addr, len * 4);
22    from_raw_parts(bytes.as_ptr() as _, bytes.len() / 4)
23}
24
25pub unsafe fn read_word(mem: *const u8, addr: u32) -> u32 {
26    read_words(mem, addr, 1)[0]
27}
28
29/// Writes bytes to the context memory at the given addr.
30pub unsafe fn write_bytes(mem: *mut u8, addr: u32, bytes: &[u8]) {
31    copy_nonoverlapping(bytes.as_ptr(), mem.add(addr as usize), bytes.len());
32}
33
34pub unsafe fn write_word(mem: *mut u8, addr: u32, word: u32) {
35    write_words(mem, addr, &[word]);
36}
37
38pub unsafe fn write_words(mem: *mut u8, addr: u32, words: &[u32]) {
39    let bytes = from_raw_parts(words.as_ptr() as _, words.len() * 4);
40    write_bytes(mem, addr, bytes);
41}
42
43#[derive(Debug, Clone, Copy)]
44#[repr(C)]
45pub struct Layout {
46    pub size: usize,
47    pub align: usize,
48}
49
50impl Layout {
51    pub fn new(size: usize, align: usize) -> Self {
52        Self { size, align }
53    }
54
55    pub fn empty() -> Self {
56        Self::new(0, 0)
57    }
58}
59
60fn empty_mmap() -> SendSyncPtr<[u8]> {
61    // Callers of this API assume that `.as_ptr()` below returns something
62    // page-aligned and non-null. This is because the pointer returned from
63    // that location is casted to other types which reside at a higher
64    // alignment than a byte for example. Despite the length being zero we
65    // still need to ensure that the pointer is suitably aligned.
66    //
67    // To handle that do a bit of trickery here to get the compiler to
68    // generate an empty array to a high-alignment type (here 4k which is
69    // the min page size we work with today). Then use this empty array as
70    // the source pointer for an empty byte slice. It's a bit wonky but this
71    // makes it such that the returned length is always zero (so this is
72    // safe) but the pointer is always 4096 or suitably aligned.
73    #[repr(C, align(4096))]
74    struct PageAligned;
75    let empty_page_alloc: &mut [PageAligned] = &mut [];
76    let empty = NonNull::new(ptr::slice_from_raw_parts_mut(
77        empty_page_alloc.as_mut_ptr().cast(),
78        0,
79    ))
80    .unwrap();
81    SendSyncPtr::from(empty)
82}