kernel_api/ptr/
x86_64.rs

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			// todo: "stac",
13			"2: mov {}, [{}]",
14			"   mov {}, 1",
15			// todo: "clac",
16			".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, // we need to use `inout` here to ensure the initial value is what we want if the `mov` is never reached
24			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			// todo: "stac",
44			".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			// todo: "clac",
55			inout(reg) MaybeUninit::<u16>::uninit() => r, // we need to use `inout` here to ensure the initial value is what we want if the `mov` is never reached
56			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			// todo: "stac",
76			".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			// todo: "clac",
87			inout(reg) MaybeUninit::<u32>::uninit() => r, // we need to use `inout` here to ensure the initial value is what we want if the `mov` is never reached
88			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			// todo: "stac",
109			".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			// todo: "clac",
120			inout(reg) MaybeUninit::<u64>::uninit() => r, // we need to use `inout` here to ensure the initial value is what we want if the `mov` is never reached
121			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			// todo: "stac",
140			".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			// todo: "clac",
151			in(reg) ptr,
152			in(reg_byte) val,
153			inout(reg) 0usize => success, // we need to use `inout` here to ensure the initial value is what we want if the `mov` is never reached
154			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			// todo: "stac",
171			".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			// todo: "clac",
182			in(reg) ptr,
183			in(reg) val,
184			inout(reg) 0usize => success, // we need to use `inout` here to ensure the initial value is what we want if the `mov` is never reached
185			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			// todo: "stac",
202			".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			// todo: "clac",
213			in(reg) ptr,
214			in(reg) val,
215			inout(reg) 0usize => success, // we need to use `inout` here to ensure the initial value is what we want if the `mov` is never reached
216			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			// todo: "stac",
234			".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			// todo: "clac",
245			in(reg) ptr,
246			in(reg) val,
247			inout(reg) 0usize => success, // we need to use `inout` here to ensure the initial value is what we want if the `mov` is never reached
248			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			// todo: "stac",
265			".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			// todo: "clac",
276			inout(reg) 0usize => success, // we need to use `inout` here to ensure the initial value is what we want if the `mov` is never reached
277			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}