Skip to main content

vm/
vm_mapping.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::arch_vm_aspace::ArchMmuFlags;
6use crate::vm_object::VmObject;
7use core::marker::{PhantomData, PhantomPinned};
8use core::ptr::NonNull;
9use fbl::RefPtr;
10use kalloc::AllocError;
11use zx_status::Status;
12
13unsafe extern "C" {
14    fn cpp_vm_mapping_get_ref_counted(mapping: *mut VmMapping) -> *mut fbl::RefCounted;
15    fn cpp_vm_mapping_free(mapping: *mut VmMapping);
16    fn cpp_vm_mapping_destroy(mapping: *mut VmMapping) -> i32;
17    fn cpp_vm_mapping_base(mapping: *mut VmMapping) -> usize;
18    fn cpp_vm_mapping_size(mapping: *mut VmMapping) -> usize;
19    fn cpp_vm_mapping_flags(mapping: *mut VmMapping) -> u32;
20    fn cpp_vm_mapping_object_offset(mapping: *mut VmMapping) -> u64;
21    fn cpp_vm_mapping_decommit_range(mapping: *mut VmMapping, offset: usize, len: usize) -> i32;
22    fn cpp_vm_mapping_map_range(
23        mapping: *mut VmMapping,
24        offset: usize,
25        len: usize,
26        commit: bool,
27        ignore_existing: bool,
28    ) -> i32;
29    fn cpp_vm_mapping_debug_unmap(mapping: *mut VmMapping, base: usize, size: usize) -> i32;
30    fn cpp_vm_mapping_debug_protect(
31        mapping: *mut VmMapping,
32        base: usize,
33        size: usize,
34        new_arch_mmu_flags: ArchMmuFlags,
35    ) -> i32;
36    fn cpp_vm_mapping_vmo(mapping: *mut VmMapping) -> *const VmObject;
37}
38
39/// A leaf mapping that maps a VMO into the address space.
40///
41/// This is an opaque FFI wrapper around Zircon's C++ `VmMapping` class.
42#[repr(C)]
43pub struct VmMapping {
44    _data: [u8; 0],
45    _marker: PhantomData<PhantomPinned>,
46}
47
48impl VmMapping {
49    fn as_mut_ptr(&self) -> *mut VmMapping {
50        self as *const VmMapping as *mut VmMapping
51    }
52
53    /// Destroys this mapping, unmapping all pages and removing dependencies on the underlying VMO.
54    pub fn destroy(&self) -> Result<(), Status> {
55        Status::ok(unsafe { cpp_vm_mapping_destroy(self.as_mut_ptr()) })
56    }
57
58    /// Returns the base virtual address of this mapping.
59    pub fn base(&self) -> usize {
60        unsafe { cpp_vm_mapping_base(self.as_mut_ptr()) }
61    }
62
63    /// Returns the size in bytes of this mapping.
64    pub fn size(&self) -> usize {
65        unsafe { cpp_vm_mapping_size(self.as_mut_ptr()) }
66    }
67
68    /// Returns the creation flags of this mapping.
69    pub fn flags(&self) -> u32 {
70        unsafe { cpp_vm_mapping_flags(self.as_mut_ptr()) }
71    }
72
73    /// Returns the offset into the underlying VMO for this mapping.
74    pub fn object_offset(&self) -> u64 {
75        unsafe { cpp_vm_mapping_object_offset(self.as_mut_ptr()) }
76    }
77
78    /// Convenience wrapper for vmo()->DecommitRange() with the necessary
79    /// offset modification and locking.
80    pub fn decommit_range(&self, offset: usize, len: usize) -> Result<(), Status> {
81        Status::ok(unsafe { cpp_vm_mapping_decommit_range(self.as_mut_ptr(), offset, len) })
82    }
83
84    /// Map in pages from the underlying vm object, optionally committing pages as it goes.
85    /// |ignore_existing| controls whether existing hardware mappings in the specified range should
86    /// be ignored or treated as an error. |ignore_existing| should only be set to true for user
87    /// mappings where populating mappings may already be racy with multiple threads, and where we
88    /// are already tolerant of mappings being arbitrarily created and destroyed.
89    pub fn map_range(
90        &self,
91        offset: usize,
92        len: usize,
93        commit: bool,
94        ignore_existing: bool,
95    ) -> Result<(), Status> {
96        Status::ok(unsafe {
97            cpp_vm_mapping_map_range(self.as_mut_ptr(), offset, len, commit, ignore_existing)
98        })
99    }
100
101    /// Unlocked convenience wrapper around unmap for testing.
102    pub fn debug_unmap(&self, base: usize, size: usize) -> Result<(), Status> {
103        Status::ok(unsafe { cpp_vm_mapping_debug_unmap(self.as_mut_ptr(), base, size) })
104    }
105
106    /// Unlocked convenience wrapper around protect for testing.
107    pub fn debug_protect(
108        &self,
109        base: usize,
110        size: usize,
111        new_arch_mmu_flags: ArchMmuFlags,
112    ) -> Result<(), Status> {
113        Status::ok(unsafe {
114            cpp_vm_mapping_debug_protect(self.as_mut_ptr(), base, size, new_arch_mmu_flags)
115        })
116    }
117
118    /// Returns the underlying VMO backing this mapping.
119    pub fn vmo(&self) -> Option<RefPtr<VmObject>> {
120        unsafe { RefPtr::try_from_raw(cpp_vm_mapping_vmo(self.as_mut_ptr())) }
121    }
122}
123
124impl fbl::HasRefCount for VmMapping {
125    fn ref_count(&self) -> &fbl::RefCounted {
126        unsafe { &*cpp_vm_mapping_get_ref_counted(self.as_mut_ptr()) }
127    }
128}
129
130unsafe impl fbl::Recyclable for VmMapping {
131    unsafe fn recycle(ptr: NonNull<Self>) {
132        unsafe {
133            cpp_vm_mapping_free(ptr.as_ptr());
134        }
135    }
136
137    fn allocate(_value: Self) -> Result<NonNull<Self>, AllocError> {
138        Err(AllocError)
139    }
140}