kernel_api/
address_space.rs1use 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#[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);