1#[cfg(feature = "full")] pub use full::*;
2
3use crate::newtype_enum;
4
5newtype_enum! {
6 pub enum Ty: pub u8 => {
7 FB = 1,
8 KERNEL_DATA = 2,
9 KERNEL_CODE = 3,
10 KERNEL_TLS = 4,
11 KERNEL_OTHER = 5,
12 KERNEL_STACK = 6,
13 MEM_MAP = 7,
14 LOADER_CODE = 8,
15 LOADER_DATA = 9,
16 BGRT_BMP_HEADER = 10,
17 IOAPIC_REGISTERS = 11,
18 APIC_REGISTERS = 12,
19 HPET_HEADER = 13,
20 HPET_FULL = 14,
21 PHYSMAP_OTHER = 15,
22 ACPI_SDT_HEADER = 16,
23 ACPI_RSDP = 17,
24 ACPI_HPET = 18,
25 ACPI_FADT = 19,
26 ACPI_BGRT = 20,
27 BYTE_ARRAY = 21,
28 THREAD_KERNEL_STACK = 22,
29 TLS = 23,
30 USER_STACK = 24,
31 PAGE_TABLE = 25,
32 USER_MMAP = 26,
33 USER_MMIO = 27,
34 USER_CODE = 28,
35 USER_PACKET_BUFFER = 29,
36 SHADOW_MEM = 30,
37 HEAP = 31,
38 }
39}
40
41#[cfg(feature = "full")]
42mod full {
43 use alloc::borrow::Cow;
44 use alloc::boxed::Box;
45 use alloc::sync::Arc;
46 use core::mem::ManuallyDrop;
47 use core::num::NonZero;
48 use core::ops::DerefMut;
49 use core::ptr;
50 use log::trace;
51 use crate::mapping::{MapPageError, Mappable, Mapping, Ty};
52 use crate::address_space;
53 use crate::address_space::{AddressSpace, MappingKey, Userspace};
54 use crate::allocator::{highmem, AllocError, DynPmm};
55 use crate::mapping::full::Backing;
56 use crate::memory::{RawFrame, RawPage};
57 use crate::syscall::handle::Handle;
58
59 #[derive(Debug, Copy, Clone)]
60 pub struct Protection {
61 pub executable: bool,
62 pub writable: bool,
63 pub user_accessible: bool,
64 }
65
66 impl Protection {
67 pub const fn new() -> Self {
68 Self {
69 executable: false,
70 writable: false,
71 user_accessible: false
72 }
73 }
74 }
75
76 impl Default for Protection {
77 fn default() -> Self {
78 Self::new()
79 }
80 }
81
82 #[derive(Debug, Copy, Clone)]
83 pub enum Caching {
84 Normal,
85 Mmio,
86 WriteCombine,
87 }
88
89 impl Caching {
90 pub const fn new() -> Self {
91 Self::Normal
92 }
93 }
94
95 impl Default for Caching {
96 fn default() -> Self {
97 Self::new()
98 }
99 }
100
101 #[derive(Debug)]
102 pub enum Location<T> {
103 Any,
104 At(T),
105 }
106
107 #[derive(Debug)]
108 enum AllocatorTy {
109 Vmo(Arc<Handle>),
110 Pmm(DynPmm<'static, false>),
111 }
112
113 #[derive(Debug)]
114 pub struct Config {
115 physical_location: Location<RawFrame>,
116 virtual_location: Location<RawPage>,
117 page_count: NonZero<usize>,
118 physical_allocator: AllocatorTy,
119 protection: Protection,
120 caching: Caching,
121 reason: Ty,
122 }
123
124 impl Config {
125 pub fn map<R: Mappable + Default>(self) -> Result<Mapping<R, address_space::Kernel>, AllocError> {
127 trace!("create mmap({}) with {self:#?}", core::any::type_name::<R>());
128
129 let address_space = address_space::Kernel {};
130 let raw = R::default();
131
132 self.do_map(raw, address_space)
133 }
134
135 pub fn map_in<'a, R: Mappable + Default + Send + 'static>(self, name: Cow<'static, str>, address_space: &'a AddressSpace) -> Result<(MappingKey, impl DerefMut<Target = Mapping<Box<dyn Mappable + Send>, Userspace>> + 'a), AllocError> {
196 trace!("create mmap({}) with {self:#?}", core::any::type_name::<R>());
197 let userspace = Userspace {
198 inner: AddressSpace::clone(address_space),
199 };
200 let raw = R::default();
201
202 let map = ManuallyDrop::new(self.do_map(raw, userspace)?);
203 let map = Mapping {
204 raw: Box::new(unsafe { ptr::read(&map.raw) }) as Box<dyn Mappable + Send>,
205 address_space: unsafe { ptr::read(&map.address_space) },
206 backing: unsafe { ptr::read(&map.backing) },
207 caching: map.caching,
208 virtual_start: map.virtual_start,
209 protection: map.protection,
210 };
211
212 Ok(address_space.push_mapping(name, map))
213 }
214
215 fn do_map<R: Mappable, A: address_space::Ty>(self, raw: R, address_space: A) -> Result<Mapping<R, A>, AllocError> {
217 let Self {
218 physical_allocator,
219 ..
220 } = self;
221
222 let (base, backing) = match (physical_allocator, self.physical_location) {
223 (AllocatorTy::Pmm(allocator), Location::At(frame)) => {
224 let frames = allocator.allocate_at(frame, self.page_count)?;
225 (frames.base(), Backing::Contiguous(frames))
226 },
227 (AllocatorTy::Pmm(allocator), Location::Any) => {
228 let mut frames = allocator.allocate(self.page_count)?;
229 (frames.base(), Backing::Contiguous(frames))
230 },
231 (AllocatorTy::Vmo(vmo), _) => {
232 let base_addr = crate::bridge::handle::kernel_syscall_blocking(
233 &vmo,
234 6,
235 1,
236 [ 0 , self.page_count.get() * 4096 , 0, 0 ],
237 )?;
238 (RawFrame::new(base_addr as usize), Backing::Vmo { handle: vmo, frame_count: self.page_count.get() })
239 }
240 };
241
242 let virtual_len = raw.virtual_size(self.page_count.get());
243 let pages = match self.virtual_location {
244 Location::At(frame) => address_space.allocator().allocate_contiguous_at(frame, virtual_len.get())?,
245 Location::Any => address_space.allocator().allocate_contiguous(virtual_len.get())?,
246 };
247 let virtual_valid_start = pages + raw.base_virtual_offset();
248
249 match address_space.map_contiguous(
250 virtual_valid_start,
251 base,
252 self.page_count.get(),
253 self.reason,
254 self.protection,
255 self.caching,
256 ) {
257 Ok(_) => {}
258 Err(MapPageError::AllocError) => return Err(AllocError::default()),
259 Err(MapPageError::AlreadyMapped(ty)) => unreachable!("unallocated memory already allocated as {ty:?}"),
260 }
261
262 Ok(Mapping {
263 raw,
264 address_space: ManuallyDrop::new(address_space),
265 backing: ManuallyDrop::new(backing),
266 caching: self.caching,
267 virtual_start: pages,
268 protection: self.protection,
269 })
270 }
271
272 pub const fn new(page_count: NonZero<usize>, ty: Ty) -> Self {
273 Self {
274 physical_location: Location::Any,
275 virtual_location: Location::Any,
276 page_count,
277 physical_allocator: AllocatorTy::Pmm(DynPmm::from(highmem()).into()),
278 protection: Protection::new(),
279 caching: Caching::new(),
280 reason: ty,
281 }
282 }
283
284 pub const fn caching(mut self, caching: Caching) -> Self {
285 self.caching = caching;
286 self
287 }
288
289 pub const fn protection(mut self, writable: bool, executable: bool, user_accessible: bool) -> Self {
290 self.protection = Protection { writable, executable, user_accessible };
291 self
292 }
293
294 pub fn with_vmo(self, vmo: Arc<Handle>, offset: usize) -> Self {
295 assert!(vmo.has_protocols(&[6]), "vmo handle must support `core.mem.Pager`");
296 assert_eq!(offset % 4096, 0, "vmo offset must be page aligned");
297 Self {
298 physical_allocator: AllocatorTy::Vmo(vmo),
299 .. self
300 }
301 }
302
303 pub fn with_allocator<const RAM_ONLY: bool>(self, allocator: impl Into<DynPmm<'static, RAM_ONLY>>) -> Self {
304 Self {
305 physical_allocator: AllocatorTy::Pmm(allocator.into().into()),
306 .. self
307 }
308 }
309
310 pub const fn physical_location(mut self, at: RawFrame) -> Self {
311 self.physical_location = Location::At(at);
312 self
313 }
314
315 pub const fn virtual_location(mut self, at: RawPage) -> Self {
316 self.virtual_location = Location::At(at);
317 self
318 }
319 }
320}