1use 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#[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 pub fn hashable_key(&self) -> Key {
125 Key(self.__extract_ptr(Ordering::Relaxed).addr())
126 }
127
128 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#[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);