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::empty();
61 flags.normal().writable();
62 if prot_flags.contains(MemoryProtection::Write) {
63 flags.writable();
64 }
65 if !prot_flags.contains(MemoryProtection::Exec) {
66 flags.execute_disable();
67 }
68
69 paging::map::<BasePageSize>(virtual_address, physical_address, count, flags);
70
71 *ret = virtual_address.as_mut_ptr();
72
73 0
74}
75
76#[hermit_macro::system(errno)]
78#[unsafe(no_mangle)]
79pub extern "C" fn sys_munmap(ptr: *mut u8, size: usize) -> i32 {
80 let virtual_address = VirtAddr::from_ptr(ptr);
81 let size = size.align_up(BasePageSize::SIZE as usize);
82 let page_range = PageRange::from_start_len(virtual_address.as_usize(), size).unwrap();
83
84 if PROT_NONE_FREE_LIST.lock().allocate_at(page_range).is_ok() {
85 return 0;
86 }
87
88 if let Some(physical_address) = paging::virtual_to_physical(virtual_address) {
89 paging::unmap::<BasePageSize>(virtual_address, size / BasePageSize::SIZE as usize);
90 debug!("Unmapping {virtual_address:X} ({size}) -> {physical_address:X}");
91
92 let frame_range =
93 PageRange::from_start_len(physical_address.as_u64() as usize, size).unwrap();
94 unsafe {
95 FrameAlloc::deallocate(frame_range);
96 }
97 }
98
99 unsafe {
100 PageAlloc::deallocate(page_range);
101 }
102
103 0
104}
105
106#[hermit_macro::system(errno)]
111#[unsafe(no_mangle)]
112pub extern "C" fn sys_mprotect(ptr: *mut u8, size: usize, prot_flags: MemoryProtection) -> i32 {
113 let count = size / BasePageSize::SIZE as usize;
114 let mut flags = PageTableEntryFlags::empty();
115 flags.normal().writable();
116 if prot_flags.contains(MemoryProtection::Write) {
117 flags.writable();
118 }
119 if !prot_flags.contains(MemoryProtection::Exec) {
120 flags.execute_disable();
121 }
122
123 let virtual_address = VirtAddr::from_ptr(ptr);
124
125 debug!("Mprotect {virtual_address:X} ({size}) -> {prot_flags:?})");
126 if let Some(physical_address) = paging::virtual_to_physical(virtual_address) {
127 paging::map::<BasePageSize>(virtual_address, physical_address, count, flags);
128 0
129 } else {
130 let frame_layout = PageLayout::from_size(size).unwrap();
131 let frame_range = FrameAlloc::allocate(frame_layout).unwrap();
132 let physical_address = PhysAddr::from(frame_range.start());
133 paging::map::<BasePageSize>(virtual_address, physical_address, count, flags);
134 0
135 }
136}
137
138#[hermit_macro::system(errno)]
139#[unsafe(no_mangle)]
140pub extern "C" fn sys_mlock(_addr: *const c_void, _size: usize) -> i32 {
141 0
143}
144
145#[hermit_macro::system(errno)]
146#[unsafe(no_mangle)]
147pub extern "C" fn sys_munlock(_addr: *const c_void, _size: usize) -> i32 {
148 0
150}
151
152#[hermit_macro::system(errno)]
153#[unsafe(no_mangle)]
154pub extern "C" fn sys_mlockall(_flags: c_int) -> i32 {
155 0
157}
158
159#[hermit_macro::system(errno)]
160#[unsafe(no_mangle)]
161pub extern "C" fn sys_munlockall(_flags: c_int) -> i32 {
162 0
164}