1use core::ffi::{c_int, c_void};
10
11use align_address::Align;
12use free_list::{FreeList, PageLayout, PageRange};
13use hermit_sync::SpinMutex;
14use memory_addresses::{PhysAddr, VirtAddr};
15
16#[cfg(target_arch = "x86_64")]
17use crate::arch::mm::paging::PageTableEntryFlagsExt;
18use crate::arch::mm::paging::{self, BasePageSize, PageSize, PageTableEntryFlags};
19use crate::mm::{FrameAlloc, PageAlloc, PageRangeAllocator};
20
21bitflags! {
22 #[repr(transparent)]
23 #[derive(Debug, Copy, Clone, Default)]
24 pub struct MemoryProtection: u32 {
25 const None = 0;
27 const Read = 1 << 0;
29 const Write = 1 << 1;
31 const Exec = 1 << 2;
33 }
34}
35
36static PROT_NONE_FREE_LIST: SpinMutex<FreeList<16>> = SpinMutex::new(FreeList::new());
37
38#[hermit_macro::system(errno)]
41#[unsafe(no_mangle)]
42pub extern "C" fn sys_mmap(size: usize, prot_flags: MemoryProtection, ret: &mut *mut u8) -> i32 {
43 let size = size.align_up(BasePageSize::SIZE as usize);
44 let layout = PageLayout::from_size(size).unwrap();
45 let page_range = PageAlloc::allocate(layout).unwrap();
46 let virtual_address = VirtAddr::from(page_range.start());
47 if prot_flags.is_empty() {
48 *ret = virtual_address.as_mut_ptr();
49 unsafe {
50 PROT_NONE_FREE_LIST.lock().deallocate(page_range).unwrap();
51 }
52 return 0;
53 }
54 let frame_layout = PageLayout::from_size(size).unwrap();
55 let frame_range = FrameAlloc::allocate(frame_layout).unwrap();
56 let physical_address = PhysAddr::from(frame_range.start());
57
58 debug!("Mmap {physical_address:X} -> {virtual_address:X} ({size})");
59 let count = size / BasePageSize::SIZE as usize;
60 let mut flags = PageTableEntryFlags::normal();
61 flags
62 .set_writable(prot_flags.contains(MemoryProtection::Write))
63 .set_execute(prot_flags.contains(MemoryProtection::Exec));
64
65 paging::map::<BasePageSize>(virtual_address, physical_address, count, flags);
66
67 *ret = virtual_address.as_mut_ptr();
68
69 0
70}
71
72#[hermit_macro::system(errno)]
74#[unsafe(no_mangle)]
75pub extern "C" fn sys_munmap(ptr: *mut u8, size: usize) -> i32 {
76 let virtual_address = VirtAddr::from_ptr(ptr);
77 let size = size.align_up(BasePageSize::SIZE as usize);
78 let page_range = PageRange::from_start_len(virtual_address.as_usize(), size).unwrap();
79
80 if PROT_NONE_FREE_LIST.lock().allocate_at(page_range).is_ok() {
81 return 0;
82 }
83
84 if let Some(physical_address) = paging::virtual_to_physical(virtual_address) {
85 paging::unmap::<BasePageSize>(virtual_address, size / BasePageSize::SIZE as usize);
86 debug!("Unmapping {virtual_address:X} ({size}) -> {physical_address:X}");
87
88 let frame_range =
89 PageRange::from_start_len(physical_address.as_u64() as usize, size).unwrap();
90 unsafe {
91 FrameAlloc::deallocate(frame_range);
92 }
93 }
94
95 unsafe {
96 PageAlloc::deallocate(page_range);
97 }
98
99 0
100}
101
102#[hermit_macro::system(errno)]
107#[unsafe(no_mangle)]
108pub extern "C" fn sys_mprotect(ptr: *mut u8, size: usize, prot_flags: MemoryProtection) -> i32 {
109 let count = size / BasePageSize::SIZE as usize;
110 let mut flags = PageTableEntryFlags::normal();
111 flags
112 .set_writable(prot_flags.contains(MemoryProtection::Write))
113 .set_execute(prot_flags.contains(MemoryProtection::Exec));
114
115 let virtual_address = VirtAddr::from_ptr(ptr);
116
117 debug!("Mprotect {virtual_address:X} ({size}) -> {prot_flags:?})");
118 if let Some(physical_address) = paging::virtual_to_physical(virtual_address) {
119 paging::map::<BasePageSize>(virtual_address, physical_address, count, flags);
120 0
121 } else {
122 let frame_layout = PageLayout::from_size(size).unwrap();
123 let frame_range = FrameAlloc::allocate(frame_layout).unwrap();
124 let physical_address = PhysAddr::from(frame_range.start());
125 paging::map::<BasePageSize>(virtual_address, physical_address, count, flags);
126 0
127 }
128}
129
130#[hermit_macro::system(errno)]
131#[unsafe(no_mangle)]
132pub extern "C" fn sys_mlock(_addr: *const c_void, _size: usize) -> i32 {
133 0
135}
136
137#[hermit_macro::system(errno)]
138#[unsafe(no_mangle)]
139pub extern "C" fn sys_munlock(_addr: *const c_void, _size: usize) -> i32 {
140 0
142}
143
144#[hermit_macro::system(errno)]
145#[unsafe(no_mangle)]
146pub extern "C" fn sys_mlockall(_flags: c_int) -> i32 {
147 0
149}
150
151#[hermit_macro::system(errno)]
152#[unsafe(no_mangle)]
153pub extern "C" fn sys_munlockall(_flags: c_int) -> i32 {
154 0
156}