1mod config;
4pub use config::*;
5
6#[cfg(feature = "full")] mod mappable;
7#[cfg(feature = "full")] pub use mappable::*;
8#[cfg(feature = "full")] pub use full::*;
9
10#[cfg(feature = "full")]
11mod full {
12 use alloc::sync::Arc;
13 use super::*;
14 use core::fmt::{Debug, Formatter};
15 use crate::{address_space, dbg};
16 use core::mem::ManuallyDrop;
17 use core::num::NonZero;
18 use core::ops::Range;
19 use log::{debug, info, warn};
20 use crate::allocator::{AllocError, DynPmm};
21 use crate::memory::{Frames, RawFrame, RawPage, PAGE_SIZE};
22 use crate::ptr::User;
23 use crate::syscall::handle::Handle;
24
25 #[derive(Debug)]
26 pub enum MapPageError {
27 AlreadyMapped(Ty),
28 AllocError,
29 }
30
31 impl From<AllocError> for MapPageError {
32 fn from(_value: AllocError) -> Self {
33 Self::AllocError
34 }
35 }
36
37 pub(super) enum Backing {
39 Contiguous(Frames<false>),
41
42 Discontiguous { pmm: DynPmm<'static, false>, frame_count: usize },
44
45 Vmo { handle: Arc<Handle>, frame_count: usize },
47 }
48
49 impl Backing {
50 fn frame_len(&self) -> usize {
51 match self {
52 Backing::Contiguous(frames) => frames.count(),
53 Backing::Discontiguous { frame_count, .. } => *frame_count,
54 Backing::Vmo { frame_count, .. } => *frame_count,
55 }
56 }
57
58 fn byte_len(&self) -> usize {
59 self.frame_len() * PAGE_SIZE
60 }
61
62 fn pmm(&self) -> &DynPmm<'static, false> {
63 match self {
64 Backing::Contiguous(frames) => frames.pmm(),
65 Backing::Discontiguous { pmm, .. } => pmm,
66 Backing::Vmo { .. } => todo!(),
67 }
68 }
69 }
70
71 pub struct Mapping<R: Mappable, A: address_space::Ty> {
76 pub(super) raw: R,
77
78 pub(super) address_space: ManuallyDrop<A>,
80
81 pub(super) backing: ManuallyDrop<Backing>,
82 pub(super) caching: Caching,
85
86 pub(super) virtual_start: RawPage,
87
88 pub(super) protection: Protection,
90 }
91
92 impl<R: Mappable> Mapping<R, address_space::Kernel> {
93 pub fn as_mut_ptr_range(&mut self) -> Range<*mut u8> {
94 let start = self.virtual_valid_start().as_ptr();
95 Range {
96 start,
97 end: unsafe { start.byte_add(self.byte_len()) }
98 }
99 }
100
101 pub fn as_ptr_range(&self) -> Range<*const u8> {
102 let start = self.virtual_valid_start().as_ptr().cast_const();
103 Range {
104 start,
105 end: unsafe { start.byte_add(self.byte_len()) }
106 }
107 }
108
109 pub fn as_mut_ptr(&mut self) -> *mut u8 {
110 self.as_mut_ptr_range().start
111 }
112
113 pub fn as_ptr(&self) -> *const u8 {
114 self.as_ptr_range().start
115 }
116
117 pub unsafe fn from_raw_parts<const RAM: bool, T>(
119 frames: Frames<RAM, T>,
120 base_page: RawPage,
121 protection: Protection,
122 caching: Caching,
123 ) -> Self where R: Default {
124 Self {
125 raw: R::default(),
126 address_space: ManuallyDrop::new(address_space::Kernel {}),
127 backing: ManuallyDrop::new(Backing::Contiguous(unsafe { Frames::<false>::from_raw_tuple(Frames::into_raw(frames)) })),
128 virtual_start: base_page,
129 protection,
130 caching,
131 }
132 }
133
134 pub fn into_raw_parts(self) -> (Option<Frames<false>>, RawPage, Protection, Caching) {
136 let mut this = ManuallyDrop::new(self);
137 (
138 match unsafe { ManuallyDrop::take(&mut this.backing) } {
139 Backing::Contiguous(frames) => Some(frames),
140 Backing::Discontiguous { .. } => None,
141 Backing::Vmo { .. } => todo!(),
142 },
143 this.virtual_start,
144 this.protection,
145 this.caching,
146 )
147 }
148 }
149
150 #[cfg(not(feature = "use_std"))]
151 impl<R: Mappable> Mapping<R, address_space::Userspace> {
152 pub fn as_mut_ptr_range(&mut self) -> Range<User<'_, *mut u8>> {
153 let start = self.virtual_valid_start().as_ptr();
154 let end = unsafe { start.byte_add(self.byte_len()) };
155 let start = User::<*mut u8>::new(start, &self.address_space.inner);
156 let end = User::<*mut u8>::new(end, &self.address_space.inner);
157 start..end
158 }
159
160 pub fn as_ptr_range(&self) -> Range<User<'_, *const u8>> {
161 let start = self.virtual_valid_start().as_ptr().cast_const();
162 let end = unsafe { start.byte_add(self.byte_len()) };
163 let start = unsafe { User::<*const u8>::new(start, &self.address_space.inner) };
164 let end = unsafe { User::<*const u8>::new(end, &self.address_space.inner) };
165 start..end
166 }
167
168 pub fn as_mut_ptr(&mut self) -> User<'_, *mut u8> {
169 self.as_mut_ptr_range().start
170 }
171
172 pub fn as_ptr(&self) -> User<'_, *const u8> {
173 self.as_ptr_range().start
174 }
175 }
176
177 impl<R: Mappable, A: address_space::Ty> Mapping<R, A> {
178 pub fn grow_in_place_by(&mut self, extra_length: usize) -> Result<(), AllocError> {
179 let Some(extra_length) = NonZero::new(extra_length) else { return Ok(()); };
180 let extra_frames = self.backing.pmm().allocate(extra_length)?;
181
182 let extra_pages = self.address_space.allocator()
183 .allocate_contiguous_at(
184 self.virtual_start + self.raw.virtual_size(self.page_len()).get(),
185 extra_length.get(),
186 )?;
187
188 debug!("growing mmap({})", core::any::type_name::<R>());
189 let _ = dbg!(self.virtual_start);
190 let _ = dbg!(self.virtual_valid_start());
191 let _ = dbg!(self.page_len());
192 let _ = dbg!(extra_length);
193 let _ = dbg!(self.raw.virtual_size(self.page_len()));
194
195 match self.address_space.map_contiguous(
196 self.virtual_valid_start() + self.page_len(),
197 extra_frames.into_raw().0.start,
198 extra_length.get(),
199 Ty(0),
200 self.protection,
201 self.caching,
202 ) {
203 Ok(_) => Ok(()),
204 Err(MapPageError::AllocError) => {
205 self.address_space.allocator()
206 .deallocate_contiguous(extra_pages, extra_length.get());
207 Err(AllocError::default())
208 }
209 Err(MapPageError::AlreadyMapped(ty)) => unreachable!("unallocated memory already allocated as {ty:?}"),
210 }?;
211
212 let new_backing = Backing::Discontiguous {
213 pmm: *self.backing.pmm(),
214 frame_count: self.backing.frame_len().checked_add(extra_length.get()).unwrap()
215 };
216 self.backing = ManuallyDrop::new(new_backing); Ok(())
219 }
220
221 pub fn byte_len(&self) -> usize {
222 self.backing.byte_len()
223 }
224
225 pub fn page_len(&self) -> usize {
226 self.backing.frame_len()
227 }
228
229 pub fn physical_start(&self) -> Option<RawFrame> {
230 match &*self.backing {
231 Backing::Contiguous(frames) => Some(frames.base()),
232 Backing::Discontiguous { .. } => None,
233 Backing::Vmo { handle, .. } => Some({
234 RawFrame::new(crate::bridge::handle::kernel_syscall_blocking(
235 handle,
236 6,
237 1,
238 [0 , self.page_len() * PAGE_SIZE , 0, 0 ],
239 ).ok()? as usize)
240 }),
241 }
242 }
243
244 pub fn virtual_valid_start(&self) -> RawPage { self.virtual_start + self.raw.base_virtual_offset() }
247
248 pub fn set_writable(&mut self, writable: bool) {
249 self.protection.writable = writable;
250 todo!()
251 }
252 }
253
254 impl<R: Mappable, A: address_space::Ty> Debug for Mapping<R, A> {
255 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
256 f.debug_struct("Mapping")
257 .field_with(
258 "backing",
259 |f| {
260 #[cfg(not(feature = "use_std"))] match &*self.backing {
261 Backing::Contiguous(frame) => Debug::fmt(frame, f),
262 Backing::Discontiguous { frame_count, .. } => write!(f, "Discontiguous {{ frame_count: {frame_count} }}"),
263 Backing::Vmo { handle, frame_count } => write!(f, "Vmo {{ handle: {handle:?}, frame_count: {frame_count} }}"),
264 }
265 #[cfg(feature = "use_std")] Ok(())
266 }
267 )
268 .field("address_space", &"<address space>")
269 .field("protection", &self.protection)
270 .field("caching", &self.caching)
271 .finish_non_exhaustive()
272 }
273 }
274
275 impl<R: Mappable, A: address_space::Ty> Drop for Mapping<R, A> {
276 fn drop(&mut self) {
277 info!("drop mmap({})", core::any::type_name::<R>());
278
279 match unsafe { ManuallyDrop::take(&mut self.backing) } {
280 Backing::Contiguous(frames) => drop(frames),
281 Backing::Discontiguous { pmm, frame_count } => {
282 warn!("ignoring discontiguous page drop");
283 }
284 Backing::Vmo { handle, .. } => drop(handle),
285 }
286 }
287 }
288}