1#[cfg(unix)]
2use std::ffi::c_void;
3#[cfg(windows)]
4use winapi::ctypes::c_void;
5
6#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
9pub struct PageSize(pub usize);
10
11impl From<usize> for PageSize {
12 fn from(i: usize) -> Self {
13 Self(i)
14 }
15}
16
17impl PageSize {
18 #[cfg(unix)]
19 #[inline]
20 pub fn from_system() -> Self {
21 use nix::unistd::{sysconf, SysconfVar};
22
23 let page_size = sysconf(SysconfVar::PAGE_SIZE).unwrap().unwrap() as usize;
24 Self(page_size)
25 }
26
27 #[cfg(windows)]
28 #[inline]
29 pub fn from_system() -> Self {
30 use std::alloc::{alloc, dealloc, Layout};
31 use winapi::um::sysinfoapi;
32
33 let size = std::mem::size_of::<sysinfoapi::SYSTEM_INFO>();
34 let layout = Layout::from_size_align(size, 8).unwrap();
35 let sysinfo = unsafe { alloc(layout) } as *mut sysinfoapi::SYSTEM_INFO;
36
37 let page_size = unsafe {
38 sysinfoapi::GetSystemInfo(sysinfo);
39 (*sysinfo).dwPageSize as usize
40 };
41
42 unsafe {
43 dealloc(sysinfo as *mut u8, layout);
44 }
45 Self(page_size)
46 }
47}
48
49#[derive(Debug, Clone, Eq, PartialEq)]
50pub struct PageHandle {
51 pub ptr: *mut u8,
52 pub len: usize,
53 pub cap: usize,
54}
55
56impl PageHandle {
57 #[inline]
58 pub fn from(page_size: PageSize, src: &[u8]) -> Self {
59 let r = Self::new(src.len(), page_size);
60 unsafe {
61 std::ptr::copy(src.as_ptr(), r.ptr, r.len);
62 }
63 r.make_page_executable();
64 r
65 }
66
67 #[inline]
68 pub fn store(&self, src: &[u8]) {
69 if src.len() > self.len {
70 panic!("store length invilid");
71 }
72 unsafe {
73 std::ptr::copy(src.as_ptr(), self.ptr, self.len);
74 }
75 }
76
77 #[inline]
78 pub fn get_ptr(&self) -> *const u8 {
79 self.ptr
80 }
81}
82
83#[cfg(unix)]
84impl PageHandle {
85 #[inline]
86 pub fn new(size: usize, page_size: PageSize) -> Self {
87 use nix::sys::mman::{mmap, MapFlags, ProtFlags};
88 unsafe {
89 let page_size = page_size.0;
90 let size_mod = size % page_size;
91 let alloc_size = if size_mod == 0 {
92 size
93 } else {
94 size + page_size - size_mod
95 };
96 let ptr = mmap(
97 std::ptr::null_mut(),
98 alloc_size,
99 ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
100 MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
101 -1,
102 0,
103 )
104 .unwrap();
105 if ptr.is_null() {
106 panic!("VirtualAlloc failed");
107 }
108 PageHandle {
109 ptr: ptr as *mut u8,
110 len: size,
111 cap: alloc_size,
112 }
113 }
114 }
115
116 #[inline]
117 pub fn make_page_executable(&self) {
118 use nix::sys::mman::{mprotect, ProtFlags};
119 unsafe {
120 mprotect(
121 self.ptr as *mut c_void,
122 self.cap,
123 ProtFlags::PROT_READ | ProtFlags::PROT_EXEC,
124 )
125 .unwrap();
126 }
127 }
128}
129
130#[cfg(windows)]
131impl PageHandle {
132 #[inline]
133 pub fn new(size: usize, page_size: PageSize) -> Self {
134 use winapi::um::{memoryapi, winnt};
135 unsafe {
136 let page_size = page_size.0;
137 let size_mod = size % page_size;
138 let alloc_size = if size_mod == 0 {
139 size
140 } else {
141 size + page_size - size_mod
142 };
143 let ptr = memoryapi::VirtualAlloc(
144 std::ptr::null_mut(),
145 alloc_size,
146 winnt::MEM_COMMIT,
147 winnt::PAGE_READWRITE,
148 );
149 if ptr.is_null() {
150 panic!("VirtualAlloc failed");
151 }
152 PageHandle {
153 ptr: ptr as *mut u8,
154 len: size,
155 cap: alloc_size,
156 }
157 }
158 }
159
160 #[inline]
161 pub fn make_page_executable(&self) {
162 use winapi::um::{memoryapi, winnt};
163 unsafe {
164 let mut flag = winnt::PAGE_READWRITE;
165 let r = memoryapi::VirtualProtect(
166 self.ptr as *mut c_void,
167 self.cap,
168 winnt::PAGE_EXECUTE_READ,
169 &mut flag,
170 );
171 if r == 0 {
172 panic!("VirtualProtect failed");
173 }
174 }
175 }
176}
177
178#[cfg(unix)]
179impl Drop for PageHandle {
180 #[inline]
181 fn drop(&mut self) {
182 use nix::sys::mman::munmap;
183 unsafe {
184 munmap(self.ptr as *mut c_void, self.cap).unwrap();
185 }
186 }
187}
188
189#[cfg(windows)]
190impl Drop for PageHandle {
191 #[inline]
192 fn drop(&mut self) {
193 use winapi::um::{memoryapi, winnt};
194 unsafe {
195 memoryapi::VirtualFree(self.ptr as *mut c_void, 0, winnt::MEM_RELEASE);
196 }
197 }
198}