Skip to main content

kernel_api/mapping/
config.rs

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		//#[cfg(not(feature = "use_std"))]
126		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		/*#[cfg(feature = "use_std")]
136		pub fn map<R: Mappable + Default>(self) -> Result<Mapping<R, address_space::Kernel>, AllocError> {
137			trace!("create mmap({}) with {self:#?}", core::any::type_name::<R>());
138
139			let address_space = address_space::Kernel {};
140			let raw = R::default();
141
142			let Location::Any = self.physical_location else {
143				panic!("specific location not supported under test yet");
144			};
145			let Location::Any = self.virtual_location else {
146				panic!("specific location not supported under test yet");
147			};
148
149			let virtual_len = raw.virtual_size(self.page_count.get());
150
151			let mut prot = libc::PROT_READ;
152			if self.protection.writable { prot |= libc::PROT_WRITE; }
153			if self.protection.executable { prot |= libc::PROT_EXEC; }
154
155			let base = unsafe {
156				let res = libc::mmap(
157					ptr::null_mut(),
158					virtual_len.get() * PAGE_SIZE,
159					prot,
160					libc::MAP_ANON,
161					0,
162					0
163				);
164				if res.is_null() { return Err(AllocError::default()); }
165				res
166			};
167
168			let guard_below = raw.base_virtual_offset();
169			unsafe {
170				libc::mprotect(
171					base,
172					(guard_below as usize) * PAGE_SIZE,
173					libc::PROT_NONE,
174				);
175			}
176			let guard_above = virtual_len.get() - self.page_count.get() - (guard_below as usize);
177			unsafe {
178				libc::mprotect(
179					base.byte_add(((guard_below as usize) + self.page_count.get()) * PAGE_SIZE),
180					(guard_above as usize) * PAGE_SIZE,
181					libc::PROT_NONE,
182				);
183			}
184
185			Ok(Mapping {
186				raw,
187				address_space: ManuallyDrop::new(address_space),
188				backing: base,
189				caching: self.caching,
190				protection: self.protection,
191			})
192		}*/
193
194		//#[cfg(not(feature = "use_std"))]
195		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		//#[cfg(not(feature = "use_std"))]
216		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 /* offset */, self.page_count.get() * 4096 /* len */, 0, 0 /* unused args */],
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}