Skip to main content

kernel/mm/
user.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! High-Level userspace memory management functions
3//!
4//! Authors: MarioS271
5
6use crate::lib::addr::VirtAddr;
7use crate::mm::layout;
8use crate::mm::mm_error::{MmError, MmResult};
9use crate::mm::pmm::FRAME_SIZE;
10use crate::mm::vmm::Vmm;
11use crate::mm::vmm::address_space::AddressSpace;
12use crate::mm::vmm::vma::VmaFlags;
13use crate::state::kstate::KSTATE;
14
15/// Lazily allocate memory in the given user process's address space
16///
17/// By passing the `fixed_addr` parameter, the caller can request the memory to be mapped into a
18/// specific location in the address space
19pub fn alloc(
20    addr_space: &mut AddressSpace,
21    fixed_addr: Option<VirtAddr>,
22    size: u64,
23    flags: VmaFlags
24) -> MmResult<VirtAddr> {
25    let size = VirtAddr::new(size).align_up(FRAME_SIZE).as_u64();
26
27    let virt = match fixed_addr {
28        Some(addr) => {
29            if !addr.is_aligned(FRAME_SIZE) {
30                return Err(MmError::MisalignedAddress);
31            }
32            addr
33        },
34        None => {
35            addr_space
36                .find_free_range(layout::USER_MMAP_BASE, layout::USER_STACK_TOP, size)
37                .ok_or(MmError::OutOfMemory)?
38        }
39    };
40
41    Vmm::lazy_map_region(addr_space, virt, size, flags | VmaFlags::USER)?;
42
43    Ok(virt)
44}
45
46/// Free previously by [`alloc`] allocated memory and release all associated frames back into
47/// the buddy allocator
48///
49/// # Safety
50/// The caller must ensure that no live code or data holds references into any address mapped
51/// within `[virt, vma.end_addr)` after this method call returns
52pub unsafe fn free(
53    addr_space: &mut AddressSpace,
54    virt: VirtAddr
55) -> MmResult<()> {
56    // Safety: the PMM is initialized in stage 2
57    let mut pmm = unsafe { KSTATE.mm.pmm().lock() };
58    unsafe { Vmm::unmap_region(&mut pmm, addr_space, virt)? };
59    Ok(())
60}
61
62/// Change an already mapped memory region's access flags
63///
64/// # Safety
65/// The caller must ensure that for example when removing the `WRITE` flag,
66/// no mutable references to the to be modified memory is held.
67pub unsafe fn remap_user_mem(
68    addr_space: &mut AddressSpace,
69    virt: VirtAddr,
70    new_flags: VmaFlags
71) -> MmResult<()> {
72    unsafe { Vmm::remap_region(addr_space, virt, new_flags | VmaFlags::USER)? };
73    Ok(())
74}