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