1use core::arch::asm;
2use core::hint::unreachable_unchecked;
3use core::mem::MaybeUninit;
4
5#[no_mangle]
6#[inline]
7pub fn checked_read_1(ptr: *const MaybeUninit<u8>) -> Option<MaybeUninit<u8>> {
8 let r: MaybeUninit<_>;
9 let success: usize;
10 unsafe {
11 asm!(
12 "2: mov {}, [{}]",
14 " mov {}, 1",
15 ".pushsection .popcorn.deref_handlers.check",
17 ".quad 2b",
18 ".popsection",
19 ".pushsection .popcorn.deref_handlers.handle",
20 ".quad 3f",
21 ".popsection",
22 "3: ",
23 inout(reg_byte) MaybeUninit::<u8>::uninit() => r, in(reg) ptr,
25 inout(reg) 0usize => success,
26 options(nostack, preserves_flags, readonly)
27 );
28 }
29
30 match success {
31 0 => None,
32 1 => Some(r),
33 _ => unsafe { unreachable_unchecked() }
34 }
35}
36
37#[inline]
38pub fn checked_read_2(ptr: *const MaybeUninit<u16>) -> Option<MaybeUninit<u16>> {
39 let r: MaybeUninit<_>;
40 let success: usize;
41 unsafe {
42 asm!(
43 ".pushsection .popcorn.deref_handlers.check",
45 ".quad 2f",
46 ".popsection",
47 "2:",
48 "mov {:x}, [{}]",
49 "mov {}, 1",
50 ".pushsection .popcorn.deref_handlers.handle",
51 ".quad 3f",
52 ".popsection",
53 "3:",
54 inout(reg) MaybeUninit::<u16>::uninit() => r, in(reg) ptr,
57 inout(reg) 0usize => success,
58 options(nostack, preserves_flags, readonly)
59 );
60 }
61
62 match success {
63 0 => None,
64 1 => Some(r),
65 _ => unsafe { unreachable_unchecked() }
66 }
67}
68
69#[inline]
70pub fn checked_read_4(ptr: *const MaybeUninit<u32>) -> Option<MaybeUninit<u32>> {
71 let r: MaybeUninit<_>;
72 let success: usize;
73 unsafe {
74 asm!(
75 ".pushsection .popcorn.deref_handlers.check",
77 ".quad 2f",
78 ".popsection",
79 "2:",
80 "mov {:e}, [{}]",
81 "mov {}, 1",
82 ".pushsection .popcorn.deref_handlers.handle",
83 ".quad 3f",
84 ".popsection",
85 "3:",
86 inout(reg) MaybeUninit::<u32>::uninit() => r, in(reg) ptr,
89 inout(reg) 0usize => success,
90 options(nostack, preserves_flags, readonly)
91 );
92 }
93
94 match success {
95 0 => None,
96 1 => Some(r),
97 _ => unsafe { unreachable_unchecked() }
98 }
99}
100
101#[cfg(target_arch = "x86_64")]
102#[inline]
103pub fn checked_read_8(ptr: *const MaybeUninit<u64>) -> Option<MaybeUninit<u64>> {
104 let r: MaybeUninit<_>;
105 let success: usize;
106 unsafe {
107 asm!(
108 ".pushsection .popcorn.deref_handlers.check",
110 ".quad 12",
111 ".popsection",
112 "2:",
113 "mov {:r}, [{}]",
114 "mov {}, 1",
115 ".pushsection .popcorn.deref_handlers.handle",
116 ".quad 3f",
117 ".popsection",
118 "3:",
119 inout(reg) MaybeUninit::<u64>::uninit() => r, in(reg) ptr,
122 inout(reg) 0usize => success,
123 options(nostack, preserves_flags, readonly)
124 );
125 }
126
127 match success {
128 0 => None,
129 1 => Some(r),
130 _ => unsafe { unreachable_unchecked() }
131 }
132}
133
134#[inline]
135pub fn checked_write_1(ptr: *mut MaybeUninit<u8>, val: MaybeUninit<u8>) -> Option<()> {
136 let success: usize;
137 unsafe {
138 asm!(
139 ".pushsection .popcorn.deref_handlers.check",
141 ".quad 2f",
142 ".popsection",
143 "2:",
144 "mov [{}], {}",
145 "mov {}, 1",
146 ".pushsection .popcorn.deref_handlers.handle",
147 ".quad 3f",
148 ".popsection",
149 "3:",
150 in(reg) ptr,
152 in(reg_byte) val,
153 inout(reg) 0usize => success, options(nostack, preserves_flags, readonly)
155 );
156 }
157
158 match success {
159 0 => None,
160 1 => Some(()),
161 _ => unsafe { unreachable_unchecked() }
162 }
163}
164
165#[inline]
166pub fn checked_write_2(ptr: *mut MaybeUninit<u16>, val: MaybeUninit<u16>) -> Option<()> {
167 let success: usize;
168 unsafe {
169 asm!(
170 ".pushsection .popcorn.deref_handlers.check",
172 ".quad 2f",
173 ".popsection",
174 "2:",
175 "mov [{}], {:x}",
176 "mov {}, 1",
177 ".pushsection .popcorn.deref_handlers.handle",
178 ".quad 3f",
179 ".popsection",
180 "3:",
181 in(reg) ptr,
183 in(reg) val,
184 inout(reg) 0usize => success, options(nostack, preserves_flags, readonly)
186 );
187 }
188
189 match success {
190 0 => None,
191 1 => Some(()),
192 _ => unsafe { unreachable_unchecked() }
193 }
194}
195
196#[inline]
197pub fn checked_write_4(ptr: *mut MaybeUninit<u32>, val: MaybeUninit<u32>) -> Option<()> {
198 let success: usize;
199 unsafe {
200 asm!(
201 ".pushsection .popcorn.deref_handlers.check",
203 ".quad 2f",
204 ".popsection",
205 "2:",
206 "mov [{}], {:e}",
207 "mov {}, 1",
208 ".pushsection .popcorn.deref_handlers.handle",
209 ".quad 3f",
210 ".popsection",
211 "3:",
212 in(reg) ptr,
214 in(reg) val,
215 inout(reg) 0usize => success, options(nostack, preserves_flags, readonly)
217 );
218 }
219
220 match success {
221 0 => None,
222 1 => Some(()),
223 _ => unsafe { unreachable_unchecked() }
224 }
225}
226
227#[cfg(target_arch = "x86_64")]
228#[inline]
229pub fn checked_write_8(ptr: *mut MaybeUninit<u64>, val: MaybeUninit<u64>) -> Option<()> {
230 let success: usize;
231 unsafe {
232 asm!(
233 ".pushsection .popcorn.deref_handlers.check",
235 ".quad 2f",
236 ".popsection",
237 "2:",
238 "mov [{}], {:r}",
239 "mov {}, 1",
240 ".pushsection .popcorn.deref_handlers.handle",
241 ".quad 3f",
242 ".popsection",
243 "3:",
244 in(reg) ptr,
246 in(reg) val,
247 inout(reg) 0usize => success, options(nostack, preserves_flags, readonly)
249 );
250 }
251
252 match success {
253 0 => None,
254 1 => Some(()),
255 _ => unsafe { unreachable_unchecked() }
256 }
257}
258
259#[inline]
260pub fn checked_memcpy(src: *const MaybeUninit<u8>, dest: *mut MaybeUninit<u8>, count: usize) -> Option<()> {
261 let success: usize;
262 unsafe {
263 asm!(
264 ".pushsection .popcorn.deref_handlers.check",
266 ".quad 2f",
267 ".popsection",
268 "2:",
269 "rep movsb [rdi], [rsi]",
270 "mov {}, 1",
271 ".pushsection .popcorn.deref_handlers.handle",
272 ".quad 3f",
273 ".popsection",
274 "3:",
275 inout(reg) 0usize => success, in("rdi") dest,
278 in("rsi") src,
279 inout("rcx") count => _,
280 options(nostack)
281 );
282 }
283
284 match success {
285 0 => None,
286 1 => Some(()),
287 _ => unsafe { unreachable_unchecked() }
288 }
289}