1#[cfg(feature = "full")] pub use full::*;
2
3use crate::newtype_enum;
4
5newtype_enum! {
6 pub enum Ty: pub u8 => {
14 UNKNOWN = 0,
16 FB = 1,
18 KERNEL_DATA = 2,
20 KERNEL_CODE = 3,
22 KERNEL_TLS = 4,
24 KERNEL_STACK = 6,
26 KERNEL_OTHER = 5,
28 MEM_MAP = 7,
30 LOADER_CODE = 8,
32 LOADER_DATA = 9,
34 #[doc(hidden)] BGRT_BMP_HEADER = 10,
35 #[doc(hidden)] IOAPIC_REGISTERS = 11,
36 #[doc(hidden)] APIC_REGISTERS = 12,
37 #[doc(hidden)] HPET_HEADER = 13,
38 #[doc(hidden)] HPET_FULL = 14,
39 #[doc(hidden)] PHYSMAP_OTHER = 15,
40 #[doc(hidden)] ACPI_SDT_HEADER = 16,
41 #[doc(hidden)] ACPI_RSDP = 17,
42 #[doc(hidden)] ACPI_HPET = 18,
43 #[doc(hidden)] ACPI_FADT = 19,
44 #[doc(hidden)] ACPI_BGRT = 20,
45 #[doc(hidden)] BYTE_ARRAY = 21,
46 USER_STACK = 24,
48 PAGE_TABLE = 25,
50 USER_MMAP = 26,
52 USER_MMIO = 27,
54 USER_CODE = 28,
56 USER_PACKET_BUFFER = 29,
58 SHADOW_MEM = 30,
60 HEAP = 31,
62 }
63}
64
65#[cfg(feature = "full")]
66mod full {
67 use alloc::borrow::Cow;
68 use alloc::boxed::Box;
69 use alloc::sync::Arc;
70 use core::mem::ManuallyDrop;
71 use core::num::NonZero;
72 use core::ops::DerefMut;
73 use core::ptr;
74 use log::trace;
75 use crate::mapping::{MapPageError, Mappable, Mapping, Ty};
76 use crate::address_space;
77 use crate::address_space::{AddressSpace, MappingKey, Userspace};
78 use crate::allocator::{highmem, AllocError, DynPmm};
79 use crate::mapping::full::Backing;
80 use crate::memory::{RawFrame, RawPage};
81 use crate::syscall::handle::Handle;
82
83 #[derive(Debug, Copy, Clone)]
85 pub struct Protection {
86 pub executable: bool,
88 pub writable: bool,
90 pub user_accessible: bool,
92 }
93
94 impl Protection {
95 const fn new() -> Self {
96 Self {
97 executable: false,
98 writable: false,
99 user_accessible: false
100 }
101 }
102 }
103
104 impl Default for Protection {
105 fn default() -> Self {
106 Self::new()
107 }
108 }
109
110 #[derive(Debug, Copy, Clone)]
112 #[non_exhaustive]
113 pub enum Caching {
114 Normal,
117 Mmio,
121 WriteCombine,
124 }
125
126 impl Caching {
127 pub const fn new() -> Self {
128 Self::Normal
129 }
130 }
131
132 impl Default for Caching {
133 fn default() -> Self {
134 Self::new()
135 }
136 }
137
138 #[derive(Debug)]
140 #[non_exhaustive]
141 pub enum Location<T> {
142 Any,
144 At(T),
146 }
147
148 #[derive(Debug)]
149 enum AllocatorTy {
150 Vmo(Arc<Handle>),
151 Pmm(DynPmm<'static, false>),
152 }
153
154 #[derive(Debug)]
156 #[non_exhaustive]
157 pub struct MappingMeta<T: DerefMut<Target = Mapping<Box<dyn Mappable + Send>, Userspace>>> {
158 pub key: MappingKey,
160 pub mapping: T,
162 }
163
164 #[derive(Debug)]
166 #[must_use = "mapping config does nothing unless mapped"]
167 pub struct Config {
168 physical_location: Location<RawFrame>,
169 virtual_location: Location<RawPage>,
170 page_count: NonZero<usize>,
171 physical_allocator: AllocatorTy,
172 protection: Protection,
173 caching: Caching,
174 reason: Ty,
175 }
176
177 impl Config {
178 pub fn map<R: Mappable + Default>(self) -> Result<Mapping<R, address_space::Kernel>, AllocError> {
189 trace!("create mmap({}) with {self:#?}", core::any::type_name::<R>());
190
191 let address_space = address_space::Kernel {};
192 let raw = R::default();
193
194 self.do_map(raw, address_space)
195 }
196
197 #[expect(clippy::type_complexity, reason = "cannot simplify further")]
269 pub fn map_in<'a, R: Mappable + Default + Send + 'static>(self, name: Cow<'static, str>, address_space: &'a AddressSpace) -> Result<MappingMeta<impl DerefMut<Target = Mapping<Box<dyn Mappable + Send>, Userspace>> + 'a>, AllocError> {
270 trace!("create mmap({}) with {self:#?}", core::any::type_name::<R>());
271 let userspace = Userspace {
272 inner: AddressSpace::clone(address_space),
273 };
274 let raw = R::default();
275
276 let map = ManuallyDrop::new(self.do_map(raw, userspace)?);
277 let map = Mapping {
278 raw: Box::new(unsafe { ptr::read(&raw const map.raw) }) as Box<dyn Mappable + Send>,
280 address_space: unsafe { ptr::read(&raw const map.address_space) },
282 backing: unsafe { ptr::read(&raw const map.backing) },
284 caching: map.caching,
285 virtual_start: map.virtual_start,
286 protection: map.protection,
287 };
288
289 let (key, mapping) = address_space.push_mapping(name, map);
290 Ok(MappingMeta { key, mapping })
291 }
292
293 fn do_map<R: Mappable, A: address_space::Ty>(self, raw: R, address_space: A) -> Result<Mapping<R, A>, AllocError> {
297 let Self {
298 physical_allocator,
299 ..
300 } = self;
301
302 let (base, backing) = match (physical_allocator, self.physical_location) {
303 (AllocatorTy::Pmm(allocator), Location::At(frame)) => {
304 let frames = allocator.allocate_at(frame, self.page_count)?;
305 (frames.base(), Backing::Contiguous(frames))
306 },
307 (AllocatorTy::Pmm(allocator), Location::Any) => {
308 let frames = allocator.allocate(self.page_count)?;
309 (frames.base(), Backing::Contiguous(frames))
310 },
311 (AllocatorTy::Vmo(vmo), _) => {
312 let base_addr = crate::bridge::handle::kernel_syscall_blocking(
313 &vmo,
314 6,
315 1,
316 [ 0 , self.page_count.get() * 4096 , 0, 0 ],
317 )?;
318 (RawFrame::new(base_addr as usize), Backing::Vmo { handle: vmo, frame_count: self.page_count.get() })
319 }
320 };
321
322 let virtual_len = raw.virtual_size(self.page_count.get());
323 let pages = match self.virtual_location {
324 Location::At(frame) => address_space.allocator().allocate_contiguous_at(frame, virtual_len.get())?,
325 Location::Any => address_space.allocator().allocate_contiguous(virtual_len.get())?,
326 };
327 let virtual_valid_start = pages + raw.base_virtual_offset();
328
329 match address_space.map_contiguous(
330 virtual_valid_start,
331 base,
332 self.page_count.get(),
333 self.reason,
334 self.protection,
335 self.caching,
336 ) {
337 Ok(()) => {}
338 Err(MapPageError::AllocError) => return Err(AllocError::default()),
339 Err(MapPageError::AlreadyMapped(ty)) => unreachable!("unallocated memory already allocated as {ty:?}"),
340 }
341
342 Ok(Mapping {
343 raw,
344 address_space: ManuallyDrop::new(address_space),
345 backing: ManuallyDrop::new(backing),
346 caching: self.caching,
347 virtual_start: pages,
348 protection: self.protection,
349 })
350 }
351
352 pub const fn new(page_count: NonZero<usize>, ty: Ty) -> Self {
365 Self {
366 physical_location: Location::Any,
367 virtual_location: Location::Any,
368 page_count,
369 physical_allocator: AllocatorTy::Pmm(highmem().into()),
370 protection: Protection::new(),
371 caching: Caching::new(),
372 reason: ty,
373 }
374 }
375
376 pub const fn caching(mut self, caching: Caching) -> Self {
380 self.caching = caching;
381 self
382 }
383
384 pub const fn protection(mut self, writable: bool, executable: bool, user_accessible: bool) -> Self {
386 self.protection = Protection { executable, writable, user_accessible };
387 self
388 }
389
390 pub fn with_allocator<const RAM_ONLY: bool>(self, allocator: impl Into<DynPmm<'static, RAM_ONLY>>) -> Self {
392 Self {
393 physical_allocator: AllocatorTy::Pmm(allocator.into().into()),
394 .. self
395 }
396 }
397
398 pub const fn physical_location(mut self, at: RawFrame) -> Self {
400 self.physical_location = Location::At(at);
401 self
402 }
403
404 pub const fn virtual_location(mut self, at: RawPage) -> Self {
406 self.virtual_location = Location::At(at);
407 self
408 }
409 }
410}