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