1use crate::mm::memory::MemoryObject;
6use crate::mm::memory_manager::MemoryManagerState;
7use crate::mm::{
8 FaultRegisterMode, GUARD_PAGE_COUNT_FOR_GROWSDOWN_MAPPINGS, MappingOptions, PAGE_SIZE,
9 ProtectionFlags,
10};
11use crate::vfs::FileMapping;
12use crate::vfs::aio::AioContext;
13use bitflags::bitflags;
14use flyweights::FlyByteStr;
15use fuchsia_inspect::HistogramProperty;
16use starnix_uapi::errors::Errno;
17use starnix_uapi::file_mode::Access;
18use starnix_uapi::user_address::UserAddress;
19use starnix_uapi::{PROT_EXEC, PROT_READ, PROT_WRITE, errno};
20use static_assertions::const_assert_eq;
21use std::mem::MaybeUninit;
22use std::ops::Range;
23use std::sync::Arc;
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum MappingMode {
27 Eager,
28 Lazy,
29}
30
31#[split_enum_storage::container] #[must_use]
38pub struct Mapping {
39 backing: MappingBacking,
41
42 flags: MappingFlags,
44
45 #[split_enum_storage::decomposed]
58 name: MappingName,
59}
60
61#[cfg(not(any(test, debug_assertions)))]
64static_assertions::assert_eq_size!(Mapping, [u8; 24]);
65
66impl Mapping {
67 pub fn new(backing: MappingBacking, flags: MappingFlags, mode: MappingMode) -> Mapping {
68 Self::with_name(backing, flags, MappingName::None, mode)
69 }
70
71 pub fn with_name(
72 backing: MappingBacking,
73 mut flags: MappingFlags,
74 name: MappingName,
75 mode: MappingMode,
76 ) -> Mapping {
77 flags.set(MappingFlags::MAPPED_IN_VMAR, mode == MappingMode::Eager);
78 MappingUnsplit { backing, flags, name }.decompose()
79 }
80
81 pub fn flags(&self) -> MappingFlags {
82 self.flags
83 }
84
85 pub fn mapping_mode(&self) -> MappingMode {
86 if self.flags.contains(MappingFlags::MAPPED_IN_VMAR) {
87 MappingMode::Eager
88 } else {
89 MappingMode::Lazy
90 }
91 }
92
93 pub fn set_mapping_mode(&mut self, mode: MappingMode) {
94 self.flags.set(MappingFlags::MAPPED_IN_VMAR, mode == MappingMode::Eager);
95 }
96
97 pub fn set_flags(&mut self, new_flags: MappingFlags) {
98 self.flags = new_flags;
99 }
100
101 fn max_access(&self) -> Access {
104 match self.name() {
105 MappingNameRef::None
106 | MappingNameRef::Stack
107 | MappingNameRef::Heap
108 | MappingNameRef::Vma(_)
109 | MappingNameRef::Ashmem(_)
110 | MappingNameRef::AioContext(_) => Access::rwx(),
111 MappingNameRef::Vdso => Access::READ | Access::EXEC,
114 MappingNameRef::Vvar => Access::READ,
115 MappingNameRef::File(file) => {
116 let mut access = file.file().max_access_for_memory_mapping();
117 if !self.flags.contains(MappingFlags::SHARED) {
121 access |= Access::WRITE;
122 }
123 access
124 }
125 }
126 }
127
128 pub fn get_backing_internal(&self) -> &MappingBacking {
129 &self.backing
130 }
131
132 pub fn set_backing_internal(&mut self, backing: MappingBacking) {
133 self.backing = backing;
134 }
135
136 pub fn set_uffd(&mut self, mode: FaultRegisterMode) {
137 self.flags |= MappingFlags::UFFD;
138 if mode == FaultRegisterMode::MISSING {
139 self.flags |= MappingFlags::UFFD_MISSING;
140 }
141 }
142
143 pub fn clear_uffd(&mut self) {
144 self.flags = self.flags.difference(MappingFlags::UFFD | MappingFlags::UFFD_MISSING);
145 }
146
147 pub fn set_mlock(&mut self) {
148 self.flags |= MappingFlags::LOCKED;
149 }
150
151 pub fn clear_mlock(&mut self) {
152 self.flags = self.flags.difference(MappingFlags::LOCKED);
153 }
154
155 pub fn new_private_anonymous(
156 flags: MappingFlags,
157 name: MappingName,
158 mode: MappingMode,
159 ) -> Mapping {
160 Self::with_name(MappingBacking::PrivateAnonymous, flags, name, mode)
161 }
162
163 pub fn inflate_to_include_guard_pages(&self, range: &Range<UserAddress>) -> Range<UserAddress> {
164 let start = if self.flags.contains(MappingFlags::GROWSDOWN) {
165 range
166 .start
167 .saturating_sub(*PAGE_SIZE as usize * GUARD_PAGE_COUNT_FOR_GROWSDOWN_MAPPINGS)
168 } else {
169 range.start
170 };
171 start..range.end
172 }
173
174 pub fn address_to_offset(&self, addr: UserAddress) -> u64 {
176 match &self.backing {
177 MappingBacking::Memory(backing) => backing.address_to_offset(addr),
178 MappingBacking::PrivateAnonymous => {
179 addr.ptr() as u64
181 }
182 }
183 }
184
185 pub fn can_read(&self) -> bool {
186 self.flags.contains(MappingFlags::READ)
187 }
188
189 pub fn can_write(&self) -> bool {
190 self.flags.contains(MappingFlags::WRITE)
191 }
192
193 pub fn can_exec(&self) -> bool {
194 self.flags.contains(MappingFlags::EXEC)
195 }
196
197 pub fn private_anonymous(&self) -> bool {
198 if let MappingBacking::PrivateAnonymous = &self.backing {
199 return true;
200 }
201 !self.flags.contains(MappingFlags::SHARED) && self.flags.contains(MappingFlags::ANONYMOUS)
202 }
203
204 pub fn vm_flags(&self) -> String {
205 let mut string = String::default();
206 let max_access = self.max_access();
207 if self.flags.contains(MappingFlags::READ) {
211 string.push_str("rd ");
212 }
213 if self.flags.contains(MappingFlags::WRITE) {
215 string.push_str("wr ");
216 }
217 if self.flags.contains(MappingFlags::EXEC) {
219 string.push_str("ex ");
220 }
221 if self.flags.contains(MappingFlags::SHARED) && max_access.contains(Access::WRITE) {
223 string.push_str("sh ");
224 }
225 if max_access.contains(Access::READ) {
227 string.push_str("mr ");
228 }
229 if max_access.contains(Access::WRITE) {
231 string.push_str("mw ");
232 }
233 if max_access.contains(Access::EXEC) {
235 string.push_str("me ");
236 }
237 if self.flags.contains(MappingFlags::SHARED) {
239 string.push_str("ms ");
240 }
241 if self.flags.contains(MappingFlags::GROWSDOWN) {
243 string.push_str("gd ");
244 }
245 if self.flags.contains(MappingFlags::LOCKED) {
249 string.push_str("lo ");
250 }
251 if self.flags.contains(MappingFlags::DONTFORK) {
256 string.push_str("dc ");
257 }
258 if self.flags.contains(MappingFlags::DONT_EXPAND) {
260 string.push_str("de ");
261 }
262 string.push_str("ac ");
264 if self.flags.contains(MappingFlags::WIPEONFORK) {
271 string.push_str("wf ");
272 }
273 if self.flags.contains(MappingFlags::UFFD_MISSING) {
281 string.push_str("um");
282 }
283 string
286 }
287}
288
289#[derive(Debug, Eq, PartialEq, Clone)]
290pub enum MappingBacking {
291 Memory(Box<MappingBackingMemory>),
292
293 PrivateAnonymous,
294}
295
296#[derive(Debug, Eq, PartialEq, Clone, split_enum_storage::SplitStorage)]
297pub enum MappingName {
298 None,
300
301 Stack,
303
304 Heap,
306
307 Vdso,
309
310 Vvar,
312
313 File(Arc<FileMapping>),
315
316 Vma(FlyByteStr),
321
322 Ashmem(FlyByteStr),
325
326 AioContext(Arc<AioContext>),
328}
329
330#[derive(Debug, Eq, PartialEq, Clone)]
331pub struct MappingBackingMemory {
332 memory: Arc<MemoryObject>,
334
335 address_to_offset_delta: u64,
337}
338
339impl MappingBackingMemory {
340 pub fn new(base: UserAddress, memory: Arc<MemoryObject>, memory_offset: u64) -> Self {
341 let address_to_offset_delta = memory_offset.wrapping_sub(base.ptr() as u64);
342 Self { memory, address_to_offset_delta }
343 }
344
345 pub fn memory(&self) -> &Arc<MemoryObject> {
346 &self.memory
347 }
348
349 pub fn read_memory<'a>(
355 &self,
356 addr: UserAddress,
357 bytes: &'a mut [MaybeUninit<u8>],
358 ) -> Result<&'a mut [u8], Errno> {
359 self.memory.read_uninit(bytes, self.address_to_offset(addr)).map_err(|_| errno!(EFAULT))
360 }
361
362 pub fn write_memory(&self, addr: UserAddress, bytes: &[u8]) -> Result<(), Errno> {
368 self.memory.write(bytes, self.address_to_offset(addr)).map_err(|_| errno!(EFAULT))
369 }
370
371 pub fn zero(&self, addr: UserAddress, length: usize) -> Result<usize, Errno> {
372 self.memory
373 .op_range(zx::VmoOp::ZERO, self.address_to_offset(addr), length as u64)
374 .map_err(|_| errno!(EFAULT))?;
375 Ok(length)
376 }
377
378 pub fn address_to_offset(&self, addr: UserAddress) -> u64 {
380 (addr.ptr() as u64).wrapping_add(self.address_to_offset_delta)
381 }
382}
383
384bitflags! {
385 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
386 #[rustfmt::skip] pub struct MappingFlags: u16 {
388 const READ = 1 << 0; const WRITE = 1 << 1; const EXEC = 1 << 2; const SHARED = 1 << 3;
392 const ANONYMOUS = 1 << 4;
393 const LOWER_32BIT = 1 << 5;
394 const GROWSDOWN = 1 << 6;
395 const ELF_BINARY = 1 << 7;
396 const DONTFORK = 1 << 8;
397 const WIPEONFORK = 1 << 9;
398 const DONT_SPLIT = 1 << 10;
399 const DONT_EXPAND = 1 << 11;
400 const LOCKED = 1 << 12;
401 const UFFD = 1 << 13;
402 const UFFD_MISSING = 1 << 14;
403 const MAPPED_IN_VMAR = 1 << 15;
404 }
405}
406
407const_assert_eq!(MappingFlags::READ.bits(), PROT_READ as u16);
409const_assert_eq!(MappingFlags::WRITE.bits(), PROT_WRITE as u16);
410const_assert_eq!(MappingFlags::EXEC.bits(), PROT_EXEC as u16);
411
412const_assert_eq!(MappingFlags::SHARED.bits(), MappingOptions::SHARED.bits() << 3);
414const_assert_eq!(MappingFlags::ANONYMOUS.bits(), MappingOptions::ANONYMOUS.bits() << 3);
415const_assert_eq!(MappingFlags::LOWER_32BIT.bits(), MappingOptions::LOWER_32BIT.bits() << 3);
416const_assert_eq!(MappingFlags::GROWSDOWN.bits(), MappingOptions::GROWSDOWN.bits() << 3);
417const_assert_eq!(MappingFlags::ELF_BINARY.bits(), MappingOptions::ELF_BINARY.bits() << 3);
418const_assert_eq!(MappingFlags::DONTFORK.bits(), MappingOptions::DONTFORK.bits() << 3);
419const_assert_eq!(MappingFlags::WIPEONFORK.bits(), MappingOptions::WIPEONFORK.bits() << 3);
420const_assert_eq!(MappingFlags::DONT_SPLIT.bits(), MappingOptions::DONT_SPLIT.bits() << 3);
421const_assert_eq!(MappingFlags::DONT_EXPAND.bits(), MappingOptions::DONT_EXPAND.bits() << 3);
422
423impl MappingFlags {
424 pub fn access_flags(&self) -> ProtectionFlags {
425 ProtectionFlags::from_bits_truncate(
426 self.bits() as u32 & ProtectionFlags::ACCESS_FLAGS.bits(),
427 )
428 }
429
430 pub fn with_access_flags(&self, prot_flags: ProtectionFlags) -> Self {
431 let mapping_flags =
432 *self & (MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXEC).complement();
433 mapping_flags | Self::from_bits_truncate(prot_flags.access_flags().bits() as u16)
434 }
435
436 pub fn options(&self) -> MappingOptions {
437 MappingOptions::from_bits_truncate(self.bits() >> 3)
438 }
439
440 pub fn from_access_flags_and_options(
441 prot_flags: ProtectionFlags,
442 options: MappingOptions,
443 ) -> Self {
444 Self::from_bits_truncate(prot_flags.access_flags().bits() as u16)
445 | Self::from_bits_truncate(options.bits() << 3)
446 }
447}
448
449#[derive(Debug, Default)]
450pub struct MappingSummary {
451 no_kind: MappingKindSummary,
452 stack: MappingKindSummary,
453 heap: MappingKindSummary,
454 vdso: MappingKindSummary,
455 vvar: MappingKindSummary,
456 file: MappingKindSummary,
457 vma: MappingKindSummary,
458 ashmem: MappingKindSummary,
459 aiocontext: MappingKindSummary,
460
461 name_lengths: Vec<usize>,
462}
463
464impl MappingSummary {
465 pub fn add(&mut self, mm_state: &MemoryManagerState, mapping: &Mapping) {
466 let kind_summary = match mapping.name() {
467 MappingNameRef::None => &mut self.no_kind,
468 MappingNameRef::Stack => &mut self.stack,
469 MappingNameRef::Heap => &mut self.heap,
470 MappingNameRef::Vdso => &mut self.vdso,
471 MappingNameRef::Vvar => &mut self.vvar,
472 MappingNameRef::File(_) => &mut self.file,
473 MappingNameRef::Vma(name) => {
474 self.name_lengths.push(name.len());
475 &mut self.vma
476 }
477 MappingNameRef::Ashmem(name) => {
478 self.name_lengths.push(name.len());
479 &mut self.ashmem
480 }
481 MappingNameRef::AioContext(_) => &mut self.aiocontext,
482 };
483
484 kind_summary.count += 1;
485 if mapping.flags.contains(MappingFlags::SHARED) {
486 kind_summary.num_shared += 1;
487 } else {
488 kind_summary.num_private += 1;
489 }
490 match mm_state.get_mapping_backing(mapping) {
491 MappingBacking::Memory(_) => {
492 kind_summary.num_memory_objects += 1;
493 }
494 MappingBacking::PrivateAnonymous => kind_summary.num_private_anon += 1,
495 }
496 }
497
498 pub fn record(self, node: &fuchsia_inspect::Node) {
499 node.record_child("no_kind", |node| self.no_kind.record(node));
500 node.record_child("stack", |node| self.stack.record(node));
501 node.record_child("heap", |node| self.heap.record(node));
502 node.record_child("vdso", |node| self.vdso.record(node));
503 node.record_child("vvar", |node| self.vvar.record(node));
504 node.record_child("file", |node| self.file.record(node));
505 node.record_child("vma", |node| self.vma.record(node));
506 node.record_child("ashmem", |node| self.ashmem.record(node));
507 node.record_child("aiocontext", |node| self.aiocontext.record(node));
508
509 let name_lengths = node.create_uint_linear_histogram(
510 "name_lengths",
511 fuchsia_inspect::LinearHistogramParams { floor: 0, step_size: 8, buckets: 4 },
512 );
513 for l in self.name_lengths {
514 name_lengths.insert(l as u64);
515 }
516 node.record(name_lengths);
517 }
518}
519
520#[derive(Debug, Default)]
521struct MappingKindSummary {
522 count: u64,
523 num_private: u64,
524 num_shared: u64,
525 num_memory_objects: u64,
526 num_private_anon: u64,
527}
528
529impl MappingKindSummary {
530 fn record(&self, node: &fuchsia_inspect::Node) {
531 node.record_uint("count", self.count);
532 node.record_uint("num_private", self.num_private);
533 node.record_uint("num_shared", self.num_shared);
534 node.record_uint("num_memory_objects", self.num_memory_objects);
535 node.record_uint("num_private_anon", self.num_private_anon);
536 }
537}