Skip to main content

kernel_api/ptr/
user_local.rs

1use alloc::boxed::Box;
2use core::cmp::min;
3use core::fmt;
4use core::fmt::Formatter;
5use core::mem::MaybeUninit;
6use crate::memory::VirtualAddress;
7use crate::ptr::{impls, PointerError};
8
9/// A pointer to a potentially invalid address, tied to the current address space.
10///
11/// While the pointer may safely point to an invalid or unaligned address, in the case that
12/// it points to a valid address and is read from, then it is unsound for the address to not
13/// hold a valid bit-pattern for the type `T`.
14///
15/// For example, it is always sound to create a `LocalUser<*const u8>` regardless of the address it points
16/// to, and always safe to call `read()` on it, but it would be unsound to create a
17/// `LocalUser<*const bool>`if it's not guaranteed that the pointed value is either `1` or `0`.
18///
19/// Additionally, to make the API require less `unsafe` for common cases, `LocalUser<*mut T>` is always
20/// safe to construct, with the additional requirement that it becomes write-only.
21#[derive(Clone, Copy)]
22pub struct LocalUser<T> {
23	pub(super) ptr: T,
24}
25
26// LocalUser pointer is only valid in the thread that created it
27impl<T> !Send for LocalUser<T> {}
28impl<T> !Sync for LocalUser<T> {}
29
30impl<T: fmt::Pointer> fmt::Pointer for LocalUser<T> {
31	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
32		fmt::Pointer::fmt(&self.ptr, f)
33	}
34}
35
36impl<T: fmt::Pointer> fmt::Debug for LocalUser<T> {
37	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
38		fmt::Pointer::fmt(&self.ptr, f)
39	}
40}
41
42impl<T: ?Sized> LocalUser<*const T> {
43	/// Creates a new `LocalUser<*const T>` with tied to the current address space.
44	///
45	/// # Safety
46	///
47	/// `addr`, if valid, must point to a valid bit pattern for `T` in the current address space.
48	/// This means that in almost all cases, it is unsound to create a `LocalUser<*const T>` where `T`
49	/// has a niche.
50	///
51	/// For all types with no invalid bit-patterns (i.e. all numeric types) it is sound to create
52	/// a `LocalUser<*const T>`.
53	pub unsafe fn new(addr: usize) -> Self where T: Sized {
54		Self {
55			ptr: addr as *const T,
56		}
57	}
58
59	/// Returns `true` if the pointer has a null address
60	pub const fn is_null(&self) -> bool {
61		self.ptr.is_null()
62	}
63
64	/// Adds a signed offset to a pointer.
65	///
66	/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
67	/// offset of `3 * size_of::<T>()` bytes.
68	///
69	/// # Safety
70	///
71	/// See safety requirements for [`<*const T>::offset()`]
72	pub const unsafe fn offset(self, count: isize) -> Self where T: Sized {
73		Self {
74			// SAFETY: this function has the same safety requirements as `<*const T>::offset()`
75			ptr: unsafe { self.ptr.offset(count) },
76		}
77	}
78
79	/// Adds a signed offset in bytes to a pointer.
80	///
81	/// # Safety
82	///
83	/// See safety requirements for [`<*const T>::byte_offset()`]
84	pub const unsafe fn byte_offset(self, count: isize) -> Self {
85		Self {
86			// SAFETY: this function has the same safety requirements as `<*const T>::byte_offset()`
87			ptr: unsafe { self.ptr.byte_offset(count) },
88		}
89	}
90
91	/// Adds an offset to a pointer.
92	///
93	/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
94	/// offset of `3 * size_of::<T>()` bytes.
95	///
96	/// # Safety
97	///
98	/// See safety requirements for [`<*const T>::add()`]
99	pub const unsafe fn add(self, count: usize) -> Self where T: Sized {
100		Self {
101			// SAFETY: this function has the same safety requirements as `<*const T>::add()`
102			ptr: unsafe { self.ptr.add(count) },
103		}
104	}
105
106	/// Adds an offset in bytes to a pointer.
107	///
108	/// # Safety
109	///
110	/// See safety requirements for [`<*const T>::byte_add()`]
111	pub const unsafe fn byte_add(self, count: usize) -> Self {
112		Self {
113			// SAFETY: this function has the same safety requirements as `<*const T>::byte_add()`
114			ptr: unsafe { self.ptr.byte_add(count) },
115		}
116	}
117
118	/// Subtracts an offset from a pointer.
119	///
120	/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
121	/// offset of `3 * size_of::<T>()` bytes.
122	///
123	/// # Safety
124	///
125	/// See safety requirements for [`<*const T>::sub()`]
126	pub const unsafe fn sub(self, count: usize) -> Self where T: Sized {
127		Self {
128			// SAFETY: this function has the same safety requirements as `<*const T>::sub()`
129			ptr: unsafe { self.ptr.sub(count) },
130		}
131	}
132
133	/// Subtracts an offset in bytes from a pointer.
134	///
135	/// # Safety
136	///
137	/// See safety requirements for [`<*const T>::byte_sub()`]
138	pub const unsafe fn byte_sub(self, count: usize) -> Self {
139		Self {
140			// SAFETY: this function has the same safety requirements as `<*const T>::byte_sub()`
141			ptr: unsafe { self.ptr.byte_sub(count) },
142		}
143	}
144
145	/// Tries to read the value pointed to by the pointer
146	///
147	/// # Errors
148	///
149	/// If the pointer is invalid due to unmapped memory or similar, returns [`PointerError`]
150	// todo: do we need the `Copy` bound
151	pub fn read(self) -> Result<T, PointerError> where T: Sized + Copy {
152		match size_of::<T>() {
153			1 => unsafe {
154				impls::checked_read_1(self.ptr.cast())
155						.map(|val| (&val as *const MaybeUninit<u8>).cast::<T>().read())
156			},
157			2 => unsafe {
158				impls::checked_read_2(self.ptr.cast())
159						.map(|val| (&val as *const MaybeUninit<u16>).cast::<T>().read())
160			},
161			4 => unsafe {
162				impls::checked_read_4(self.ptr.cast())
163						.map(|val| (&val as *const MaybeUninit<u32>).cast::<T>().read())
164			},
165			#[cfg(target_pointer_width = "64")] 8 => unsafe {
166				impls::checked_read_8(self.ptr.cast())
167						.map(|val| (&val as *const MaybeUninit<u64>).cast::<T>().read())
168			},
169			size => {
170				let mut buf = MaybeUninit::<T>::uninit();
171				impls::checked_memcpy(self.ptr.cast(), buf.as_mut_ptr().cast(), size)
172						.map(|_| unsafe { buf.assume_init() })
173			}
174		}.ok_or(PointerError {})
175	}
176
177	/// Casts a pointer to another type
178	///
179	/// # Safety
180	///
181	/// If `self` has a valid address, then it must point to a valid bit pattern for `U` in the current
182	/// address space.
183	/// This means that in almost all cases, it is unsound to cast to a `LocalUser<*const U>` where `U`
184	/// has a niche.
185	///
186	/// For all types with no invalid bit-patterns (i.e. all numeric types) it is sound to cast to
187	/// a `User<*const U>`.
188	pub const unsafe fn cast<U>(self) -> LocalUser<*const U> {
189		LocalUser {
190			ptr: self.ptr.cast(),
191		}
192	}
193
194	/// Casts to a writable pointer
195	pub const fn cast_mut(self) -> LocalUser<*mut T> {
196		LocalUser {
197			ptr: self.ptr.cast_mut(),
198		}
199	}
200
201	pub fn is_aligned_to(self, align: usize) -> bool {
202		self.ptr.is_aligned_to(align)
203	}
204
205	pub fn addr(self) -> VirtualAddress {
206		VirtualAddress::new(self.ptr.addr())
207	}
208
209	pub fn align_offset(self, align: usize) -> usize where T: Sized {
210		self.ptr.align_offset(align)
211	}
212}
213
214impl<T: ?Sized> LocalUser<*mut T> {
215	/// Creates a new `LocalUser<*mut T>` with the provided address tied to the current address space
216	pub fn new(addr: usize) -> Self where T: Sized {
217		Self {
218			ptr: addr as *mut T,
219		}
220	}
221
222	/// Returns `true` if the pointer has a null address
223	pub const fn is_null(&self) -> bool {
224		self.ptr.is_null()
225	}
226
227	/// Adds a signed offset to a pointer.
228	///
229	/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
230	/// offset of `3 * size_of::<T>()` bytes.
231	///
232	/// # Safety
233	///
234	/// See safety requirements for [`<*mut T>::offset()`]
235	pub const unsafe fn offset(self, count: isize) -> Self where T: Sized {
236		Self {
237			// SAFETY: this function has the same safety requirements as `<*mut T>::offset()`
238			ptr: unsafe { self.ptr.offset(count) },
239		}
240	}
241
242	/// Adds a signed offset in bytes to a pointer.
243	///
244	/// # Safety
245	///
246	/// See safety requirements for [`<*mut T>::byte_offset()`]
247	pub const unsafe fn byte_offset(self, count: isize) -> Self {
248		Self {
249			// SAFETY: this function has the same safety requirements as `<*mut T>::byte_offset()`
250			ptr: unsafe { self.ptr.byte_offset(count) },
251		}
252	}
253
254	/// Adds an offset to a pointer.
255	///
256	/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
257	/// offset of `3 * size_of::<T>()` bytes.
258	///
259	/// # Safety
260	///
261	/// See safety requirements for [`<*mut T>::add()`]
262	pub const unsafe fn add(self, count: usize) -> Self where T: Sized {
263		Self {
264			// SAFETY: this function has the same safety requirements as `<*mut T>::add()`
265			ptr: unsafe { self.ptr.add(count) },
266		}
267	}
268
269	/// Adds an offset in bytes to a pointer.
270	///
271	/// # Safety
272	///
273	/// See safety requirements for [`<*mut T>::byte_add()`]
274	pub const unsafe fn byte_add(self, count: usize) -> Self {
275		Self {
276			// SAFETY: this function has the same safety requirements as `<*mut T>::byte_add()`
277			ptr: unsafe { self.ptr.byte_add(count) },
278		}
279	}
280
281	/// Subtracts an offset from a pointer.
282	///
283	/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
284	/// offset of `3 * size_of::<T>()` bytes.
285	///
286	/// # Safety
287	///
288	/// See safety requirements for [`<*mut T>::sub()`]
289	pub const unsafe fn sub(self, count: usize) -> Self where T: Sized {
290		Self {
291			// SAFETY: this function has the same safety requirements as `<*mut T>::sub()`
292			ptr: unsafe { self.ptr.sub(count) },
293		}
294	}
295
296	/// Subtracts an offset in bytes from a pointer.
297	///
298	/// # Safety
299	///
300	/// See safety requirements for [`<*mut T>::byte_sub()`]
301	pub const unsafe fn byte_sub(self, count: usize) -> Self {
302		Self {
303			// SAFETY: this function has the same safety requirements as `<*mut T>::byte_sub()`
304			ptr: unsafe { self.ptr.byte_sub(count) },
305		}
306	}
307
308	/// Tries to write to the value pointed to by the pointer
309	///
310	/// # Errors
311	///
312	/// If the pointer is invalid due to unmapped memory or similar, returns [`PointerError`]
313	pub fn write(self, value: T) -> Result<(), PointerError> where T: Sized {
314		match size_of::<T>() {
315			1 => unsafe {
316				impls::checked_write_1(self.ptr.cast(), (&value as *const T).cast::<MaybeUninit<u8>>().read())
317			},
318			2 => unsafe {
319				impls::checked_write_2(self.ptr.cast(), (&value as *const T).cast::<MaybeUninit<u16>>().read())
320			},
321			4 => unsafe {
322				impls::checked_write_4(self.ptr.cast(), (&value as *const T).cast::<MaybeUninit<u32>>().read())
323			},
324			#[cfg(target_pointer_width = "64")] 8 => unsafe {
325				impls::checked_write_8(self.ptr.cast(), (&value as *const T).cast::<MaybeUninit<u64>>().read())
326			},
327			size => {
328				impls::checked_memcpy((&value as *const T).cast(), self.ptr.cast(), size)
329			}
330		}.ok_or(PointerError {})
331	}
332
333	/// Casts a pointer to another type
334	pub const fn cast<U>(self) -> LocalUser<*mut U> {
335		LocalUser {
336			ptr: self.ptr.cast(),
337		}
338	}
339
340	/// Casts to a readable pointer
341	///
342	/// # Safety
343	///
344	/// `addr`, if valid, must point to a valid bit pattern for `T` in the current address space.
345	/// This means that in almost all cases, it is unsound to cast to a `LocalUser<*const T>` where `T`
346	/// has a niche.
347	///
348	/// For all types with no invalid bit-patterns (i.e. all numeric types) it is sound to cast to
349	/// a `LocalUser<*const T>`.
350	pub const unsafe fn cast_const(self) -> LocalUser<*const T> {
351		LocalUser {
352			ptr: self.ptr.cast_const(),
353		}
354	}
355
356	pub fn is_aligned_to(self, align: usize) -> bool {
357		self.ptr.is_aligned_to(align)
358	}
359
360	pub fn addr(self) -> VirtualAddress {
361		VirtualAddress::new(self.ptr.addr())
362	}
363
364	pub fn align_offset(self, align: usize) -> usize where T: Sized {
365		self.ptr.align_offset(align)
366	}
367}
368
369impl<T> LocalUser<*const [T]> {
370	pub const fn len(self) -> usize { self.ptr.len() }
371
372	pub const fn is_empty(self) -> bool { self.ptr.is_empty() }
373
374	pub const fn as_ptr(self) -> LocalUser<*const T> {
375		LocalUser {
376			ptr: self.ptr.as_ptr(),
377		}
378	}
379
380	pub fn read_to_box(self) -> Result<Box<[T]>, PointerError> {
381		let mut buf = Box::new_uninit_slice(self.len());
382		let size = self.read_to_buffer(&mut buf)?;
383		assert_eq!(size, buf.len(), "box should be big enough");
384		Ok(unsafe { buf.assume_init() })
385	}
386
387	pub fn read_to_buffer(self, buffer: &mut [MaybeUninit<T>]) -> Result<usize, PointerError> {
388		let count = min(buffer.len(), self.len());
389
390		impls::checked_memcpy(
391			self.ptr.cast(),
392			buffer.as_mut_ptr().cast(),
393			size_of::<T>() * count
394		).ok_or(PointerError {})?;
395
396		Ok(count)
397	}
398}
399
400impl<T> LocalUser<*mut [T]> {
401	pub const fn len(self) -> usize { self.ptr.len() }
402
403	pub const fn is_empty(self) -> bool { self.ptr.is_empty() }
404
405	pub const fn as_mut_ptr(self) -> LocalUser<*mut T> {
406		LocalUser {
407			ptr: self.ptr.as_mut_ptr(),
408		}
409	}
410
411	pub fn write_from_slice(self, slice: &[T]) -> Result<usize, PointerError> {
412		let count = min(slice.len(), self.len());
413
414		impls::checked_memcpy(
415			slice.as_ptr().cast(),
416			self.ptr.cast(),
417			size_of::<T>() * count
418		).ok_or(PointerError {})?;
419
420		Ok(count)
421	}
422}
423
424/// # Safety
425///
426/// If `data` points to accessible memory, it must point to `len` elements of type `T`.
427/// See [`LocalUser::<*const T>::new`](`LocalUser::<*const T>::new#safety`) for more details.
428pub unsafe fn local_slice_from_raw_parts<T>(data: LocalUser<*const T>, len: usize) -> LocalUser<*const [T]> {
429	let ptr = core::ptr::slice_from_raw_parts(data.ptr, len);
430	LocalUser {
431		ptr,
432	}
433}
434
435pub fn local_slice_from_raw_parts_mut<T>(data: LocalUser<*mut T>, len: usize) -> LocalUser<*mut [T]> {
436	let ptr = core::ptr::slice_from_raw_parts_mut(data.ptr, len);
437	LocalUser {
438		ptr,
439	}
440}