1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use std::os::unix::io::RawFd;
use nix::fcntl::{self, OFlag};
use nix::sys::mman::{self, MapFlags, ProtFlags};
use nix::{sys::stat::Mode, unistd};
use super::mem::PMEM_MAP_VADDR;
use crate::{MMUFlags, PhysAddr, VirtAddr};
pub struct MockMemory {
size: usize,
fd: RawFd,
}
impl MockMemory {
pub fn new(size: usize) -> Self {
let dir = tempfile::tempdir().expect("failed to create pmem directory");
let path = dir.path().join("zcore_libos_pmem");
let fd = fcntl::open(
&path,
OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_RDWR,
Mode::S_IRWXU,
)
.expect("faild to open");
unistd::ftruncate(fd, size as _).expect("failed to set size of shared memory!");
let mem = Self { size, fd };
mem.mmap(PMEM_MAP_VADDR, size, 0, MMUFlags::READ | MMUFlags::WRITE);
mem
}
pub fn mmap(&self, vaddr: VirtAddr, len: usize, paddr: PhysAddr, prot: MMUFlags) {
assert!(paddr < self.size);
assert!(paddr + len <= self.size);
#[cfg(target_os = "macos")]
let prot = if prot.contains(MMUFlags::EXECUTE) {
prot | MMUFlags::WRITE
} else {
prot
};
let prot_noexec = ProtFlags::from(prot) - ProtFlags::PROT_EXEC;
let flags = MapFlags::MAP_SHARED | MapFlags::MAP_FIXED;
let fd = self.fd;
let offset = paddr as _;
trace!(
"mmap file: fd={}, offset={:#x}, len={:#x}, vaddr={:#x}, prot={:?}",
fd,
offset,
len,
vaddr,
prot,
);
unsafe { mman::mmap(vaddr as _, len, prot_noexec, flags, fd, offset) }.unwrap_or_else(
|err| {
panic!(
"failed to mmap: fd={}, offset={:#x}, len={:#x}, vaddr={:#x}, prot={:?}: {:?}",
fd, offset, len, vaddr, prot, err
)
},
);
if prot.contains(MMUFlags::EXECUTE) {
self.mprotect(vaddr, len, prot);
}
}
pub fn munmap(&self, vaddr: VirtAddr, len: usize) {
unsafe { mman::munmap(vaddr as _, len) }
.unwrap_or_else(|err| panic!("failed to munmap: vaddr={:#x}: {:?}", vaddr, err));
}
pub fn mprotect(&self, vaddr: VirtAddr, len: usize, prot: MMUFlags) {
unsafe { mman::mprotect(vaddr as _, len, prot.into()) }.unwrap_or_else(|err| {
panic!(
"failed to mprotect: vaddr={:#x}, prot={:?}: {:?}",
vaddr, prot, err
)
});
}
pub fn phys_to_virt(&self, paddr: PhysAddr) -> VirtAddr {
assert!(paddr < self.size);
PMEM_MAP_VADDR + paddr
}
pub fn as_ptr<T>(&self, paddr: PhysAddr) -> *const T {
self.phys_to_virt(paddr) as _
}
pub fn as_mut_ptr<T>(&self, paddr: PhysAddr) -> *mut T {
self.phys_to_virt(paddr) as _
}
}
impl Drop for MockMemory {
fn drop(&mut self) {
trace!("Drop MockMemory: fd={:?}", self.fd);
unistd::close(self.fd).expect("failed to close shared memory file!");
}
}
impl From<MMUFlags> for ProtFlags {
fn from(f: MMUFlags) -> Self {
let mut flags = Self::empty();
if f.contains(MMUFlags::READ) {
flags |= ProtFlags::PROT_READ;
}
if f.contains(MMUFlags::WRITE) {
flags |= ProtFlags::PROT_WRITE;
}
if f.contains(MMUFlags::EXECUTE) {
flags |= ProtFlags::PROT_EXEC;
}
flags
}
}