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