Skip to main content

kernel_api/
address_space.rs

1//! Types to manipulate the kernel and userspace address spaces.
2//!
3//! This module provides two sets of address space types - the [`Kernel`] and [`Userspace`] marker types
4//! for use with [`Mapping`], as well as the [`AddressSpace`] type for directly
5//! manipulating the address space of a thread.
6//!
7//! # Kernel address space
8//!
9//! TODO(doc).
10//!
11//! # User address space
12//!
13//! TODO(doc).
14
15use alloc::borrow::Cow;
16use alloc::boxed::Box;
17use alloc::sync::{Arc, Weak};
18use core::any::Any;
19use core::fmt::{Debug, Formatter};
20use core::hash::Hash;
21use core::mem::ManuallyDrop;
22use core::ops::{Deref, DerefMut};
23use core::ptr;
24use core::ptr::DynMetadata;
25use core::sync::atomic::Ordering;
26use crate::allocator::Vmm;
27use crate::mapping::{Caching, MapPageError, Mappable, Mapping, Protection};
28use crate::memory::{RawFrame, RawPage};
29use crate::sync::RwReadGuard;
30
31#[cfg(debug_assertions)] use core::sync::atomic::AtomicBool;
32use crate::num::{ufat, AtomicUfat};
33
34// this an Arc around `kernel::memory::virtual::AddressSpaceInner`
35// we could also use an extern type here instead of `dyn Any` but that
36// means we need extra effort to keep uses of `drop(AddressSpace)`
37// from panicking, as the last drop will panic trying to compute
38// the offset of the data with `align_of_val`
39//pub type AddressSpace = Arc<dyn Any + Send + Sync>;
40#[derive(Debug)]
41pub(crate) struct WeakAddressSpace(Weak<dyn Any + Send + Sync>);
42
43pub struct AddressSpace {
44	#[doc(hidden)]
45	pub __ptr: AtomicUfat,
46	#[cfg(debug_assertions)] personality: AtomicBool,
47}
48
49impl AddressSpace {
50	#[doc(hidden)]
51	pub fn __new(address_space: Arc<dyn Any + Send + Sync>) -> Self {
52		let ptr = Arc::into_raw(address_space);
53		AddressSpace {
54			__ptr: AtomicUfat::new(Self::convert_ufat(ptr)),
55			#[cfg(debug_assertions)] personality: AtomicBool::new(false),
56		}
57	}
58
59	pub(crate) fn downgrade(&self) -> WeakAddressSpace {
60		let address_space = ManuallyDrop::new(self.clone());
61		let ptr = address_space.__extract_ptr(Ordering::SeqCst);
62		let strong = unsafe { Arc::from_raw(ptr) };
63		WeakAddressSpace(Arc::downgrade(&strong))
64	}
65
66	fn convert_ufat(ptr: *const (dyn Any + Send + Sync)) -> ufat {
67		let (ptr, meta) = ptr.to_raw_parts();
68		ufat::new(
69			ptr.expose_provenance(),
70			unsafe { core::mem::transmute::<DynMetadata<dyn Any + Send + Sync>, usize>(meta) }
71		)
72	}
73
74	#[doc(hidden)]
75	pub fn __extract_ptr(&self, ordering: Ordering) -> *const (dyn Any + Send + Sync) {
76		let val = self.__ptr.load(ordering);
77		let meta = unsafe { core::mem::transmute::<usize, DynMetadata<dyn Any + Send + Sync>>(val.lower()) };
78		let ptr = ptr::with_exposed_provenance::<()>(val.upper());
79		ptr::from_raw_parts(ptr, meta)
80	}
81
82	#[doc(hidden)]
83	#[must_use]
84	pub fn __assert_in_use(&self) -> impl Drop + '_ {
85		#[cfg(debug_assertions)] {
86			struct InUseGuard<'s>(&'s AtomicBool);
87
88			impl Drop for InUseGuard<'_> {
89				fn drop(&mut self) {
90					self.0.store(false, Ordering::Release);
91				}
92			}
93
94			self.personality.compare_exchange(
95				false,
96				true,
97				Ordering::Acquire,
98				Ordering::Relaxed
99			).unwrap_or_else(|_| panic!("UB detected: potential race between `AddressSpace::clone()` and `AddressSpace::swap()`"));
100
101			InUseGuard(&self.personality)
102		}
103
104		#[cfg(not(debug_assertions))] {
105			struct S;
106
107			impl Drop for S {
108				fn drop(&mut self) {}
109			}
110
111			S
112		}
113	}
114
115	pub(crate) fn push_mapping(&self, name: Cow<'static, str>, mapping: Mapping<Box<dyn Mappable + Send>, Userspace>) -> (MappingKey, impl DerefMut<Target = Mapping<Box<dyn Mappable + Send>, Userspace>>) {
116		crate::bridge::address_space::user::push_mapping(self, name, mapping)
117	}
118
119	pub fn ptr_eq(this: &Self, other: &Self) -> bool {
120		this.__ptr.load(Ordering::Relaxed) == other.__ptr.load(Ordering::Relaxed)
121	}
122
123	/// Returns a hashable identifier for this address space.
124	pub fn hashable_key(&self) -> Key {
125		Key(self.__extract_ptr(Ordering::Relaxed).addr())
126	}
127
128	/// # Safety
129	///
130	/// Must not execute simultaneously with any other methods being called on `self`.
131	pub unsafe fn swap(&self, other: AddressSpace, ordering: Ordering) -> AddressSpace {
132		let _guard = self.__assert_in_use();
133		let other = ManuallyDrop::new(other);
134		let other = other.__ptr.load(ordering);
135		let old = self.__ptr.swap(other, ordering);
136		AddressSpace {
137			__ptr: AtomicUfat::new(old),
138			#[cfg(debug_assertions)] personality: AtomicBool::new(false),
139		}
140	}
141}
142
143impl Clone for AddressSpace {
144	fn clone(&self) -> Self {
145		let _guard = self.__assert_in_use();
146		let ptr = self.__extract_ptr(Ordering::SeqCst);
147		unsafe { Arc::increment_strong_count(ptr) };
148		Self {
149			__ptr: AtomicUfat::new(Self::convert_ufat(ptr)),
150			#[cfg(debug_assertions)] personality: AtomicBool::new(false),
151		}
152	}
153}
154
155impl Drop for AddressSpace {
156	fn drop(&mut self) {
157		let _guard = self.__assert_in_use();
158		let ptr = self.__extract_ptr(Ordering::Relaxed);
159		unsafe { Arc::decrement_strong_count(ptr) }
160	}
161}
162
163impl Debug for AddressSpace {
164	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
165		write!(f, "AddressSpace {{ .. }}")
166	}
167}
168
169pub trait Ty: crate::sealed::Sealed {
170	fn allocator(&self) -> impl Deref<Target = dyn Vmm> + '_;
171	fn map_contiguous(&self, base_page: RawPage, base_frame: RawFrame, count: usize, reason: crate::mapping::Ty, protection: Protection, caching: Caching) -> Result<(), MapPageError>;
172}
173
174/// A hashable key to refer to an [`AddressSpace`].
175///
176/// This cannot be used to derive the original [`AddressSpace`] as there is
177/// no guarantee it is still alive.
178#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
179pub struct Key(usize);
180
181impl WeakAddressSpace {
182	pub fn ptr_eq(this: &Self, other: &AddressSpace) -> bool {
183		let val = this.0.as_ptr();
184		AddressSpace::convert_ufat(val) == other.__ptr.load(Ordering::Relaxed)
185	}
186}
187
188#[non_exhaustive]
189pub struct Kernel {}
190pub struct Userspace {
191	pub(crate) inner: AddressSpace,
192}
193
194impl crate::sealed::Sealed for Kernel {}
195impl crate::sealed::Sealed for Userspace {}
196
197impl Ty for Kernel {
198	fn allocator(&self) -> impl Deref<Target = dyn Vmm> + '_ {
199		RwReadGuard::map(
200			crate::bridge::memory::GLOBAL_VIRTUAL_ALLOCATOR.read(),
201			|vmm| *vmm as &dyn Vmm
202		)
203	}
204
205	fn map_contiguous(&self, base_page: RawPage, base_frame: RawFrame, count: usize, reason: crate::mapping::Ty, protection: Protection, caching: Caching) -> Result<(), MapPageError> {
206		let flags = {
207			let mut base = 0u8;
208			if protection.writable { base |= 1<<1; }
209			if protection.executable { base |= 1<<2; }
210			if protection.user_accessible { base |= 1<<3; }
211			match caching {
212				Caching::Normal => {},
213				Caching::Mmio => { base |= 1<<5; },
214				Caching::WriteCombine => { base |= 1<<4; },
215			}
216			base
217		};
218
219		crate::bridge::address_space::kernel::map_contiguous(
220			base_page,
221			base_frame,
222			count,
223			reason,
224			flags,
225		)
226	}
227}
228
229impl Ty for Userspace {
230	fn allocator(&self) -> impl Deref<Target = dyn Vmm> + '_ {
231		crate::bridge::address_space::user::get_allocator(&self.inner)
232    }
233
234	fn map_contiguous(&self, base_page: RawPage, base_frame: RawFrame, count: usize, reason: crate::mapping::Ty, protection: Protection, caching: Caching) -> Result<(), MapPageError> {
235		let flags = {
236			let mut base = 0u8;
237			if protection.writable { base |= 1<<1; }
238			if protection.executable { base |= 1<<2; }
239			if protection.user_accessible { base |= 1<<3; }
240			match caching {
241				Caching::Normal => {},
242				Caching::Mmio => { base |= 1<<5; },
243				Caching::WriteCombine => { base |= 1<<4; },
244			}
245			base
246		};
247
248		crate::bridge::address_space::user::map_contiguous(
249			&self.inner,
250			base_page,
251			base_frame,
252			count,
253			reason,
254			flags,
255		)
256	}
257}
258
259#[derive(Debug, Copy, Clone)]
260pub struct MappingKey(pub usize);