1 use core::intrinsics::unlikely; 2 3 use alloc::sync::Arc; 4 5 use crate::{ 6 arch::MMArch, 7 kerror, 8 libs::align::{check_aligned, page_align_up}, 9 mm::MemoryManagementArch, 10 syscall::{Syscall, SystemError}, 11 }; 12 13 use super::{ 14 allocator::page_frame::{PageFrameCount, VirtPageFrame}, 15 ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR}, 16 verify_area, VirtAddr, 17 }; 18 19 bitflags! { 20 /// Memory protection flags 21 pub struct ProtFlags: u64 { 22 const PROT_NONE = 0x0; 23 const PROT_READ = 0x1; 24 const PROT_WRITE = 0x2; 25 const PROT_EXEC = 0x4; 26 } 27 28 /// Memory mapping flags 29 pub struct MapFlags: u64 { 30 const MAP_NONE = 0x0; 31 /// share changes 32 const MAP_SHARED = 0x1; 33 /// changes are private 34 const MAP_PRIVATE = 0x2; 35 /// Interpret addr exactly 36 const MAP_FIXED = 0x10; 37 /// don't use a file 38 const MAP_ANONYMOUS = 0x20; 39 // linux-6.1-rc5/include/uapi/asm-generic/mman.h#7 40 /// stack-like segment 41 const MAP_GROWSDOWN = 0x100; 42 /// ETXTBSY 43 const MAP_DENYWRITE = 0x800; 44 /// Mark it as an executable 45 const MAP_EXECUTABLE = 0x1000; 46 /// Pages are locked 47 const MAP_LOCKED = 0x2000; 48 /// don't check for reservations 49 const MAP_NORESERVE = 0x4000; 50 /// populate (prefault) pagetables 51 const MAP_POPULATE = 0x8000; 52 /// do not block on IO 53 const MAP_NONBLOCK = 0x10000; 54 /// give out an address that is best suited for process/thread stacks 55 const MAP_STACK = 0x20000; 56 /// create a huge page mapping 57 const MAP_HUGETLB = 0x40000; 58 /// perform synchronous page faults for the mapping 59 const MAP_SYNC = 0x80000; 60 /// MAP_FIXED which doesn't unmap underlying mapping 61 const MAP_FIXED_NOREPLACE = 0x100000; 62 63 /// For anonymous mmap, memory could be uninitialized 64 const MAP_UNINITIALIZED = 0x4000000; 65 66 } 67 } 68 69 impl Syscall { 70 pub fn brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError> { 71 // kdebug!("brk: new_addr={:?}", new_addr); 72 let address_space = AddressSpace::current()?; 73 let mut address_space = address_space.write(); 74 75 if new_addr < address_space.brk_start || new_addr >= MMArch::USER_END_VADDR { 76 return Ok(address_space.brk); 77 } 78 if new_addr == address_space.brk { 79 return Ok(address_space.brk); 80 } 81 82 unsafe { 83 address_space 84 .set_brk(VirtAddr::new(page_align_up(new_addr.data()))) 85 .ok(); 86 87 return Ok(address_space.sbrk(0).unwrap()); 88 } 89 } 90 91 pub fn sbrk(incr: isize) -> Result<VirtAddr, SystemError> { 92 let address_space = AddressSpace::current()?; 93 assert!(address_space.read().user_mapper.utable.is_current()); 94 let mut address_space = address_space.write(); 95 let r = unsafe { address_space.sbrk(incr) }; 96 97 return r; 98 } 99 100 /// ## mmap系统调用 101 /// 102 /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现 103 /// 104 /// ## 参数 105 /// 106 /// - `start_vaddr`:映射的起始地址 107 /// - `len`:映射的长度 108 /// - `prot`:保护标志 109 /// - `flags`:映射标志 110 /// - `fd`:文件描述符(暂时不支持) 111 /// - `offset`:文件偏移量 (暂时不支持) 112 /// 113 /// ## 返回值 114 /// 115 /// 成功时返回映射的起始地址,失败时返回错误码 116 pub fn mmap( 117 start_vaddr: VirtAddr, 118 len: usize, 119 prot_flags: usize, 120 map_flags: usize, 121 _fd: i32, 122 _offset: usize, 123 ) -> Result<usize, SystemError> { 124 let map_flags = MapFlags::from_bits_truncate(map_flags as u64); 125 let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64); 126 127 if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR) 128 && map_flags.contains(MapFlags::MAP_FIXED) 129 { 130 kerror!( 131 "mmap: MAP_FIXED is not supported for address below {}", 132 DEFAULT_MMAP_MIN_ADDR 133 ); 134 return Err(SystemError::EINVAL); 135 } 136 // 暂时不支持除匿名页以外的映射 137 if !map_flags.contains(MapFlags::MAP_ANONYMOUS) { 138 kerror!("mmap: not support file mapping"); 139 return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); 140 } 141 142 // 暂时不支持巨页映射 143 if map_flags.contains(MapFlags::MAP_HUGETLB) { 144 kerror!("mmap: not support huge page mapping"); 145 return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); 146 } 147 let current_address_space = AddressSpace::current()?; 148 let start_page = current_address_space.write().map_anonymous( 149 start_vaddr, 150 len, 151 prot_flags, 152 map_flags, 153 true, 154 )?; 155 return Ok(start_page.virt_address().data()); 156 } 157 158 /// ## munmap系统调用 159 /// 160 /// ## 参数 161 /// 162 /// - `start_vaddr`:取消映射的起始地址(已经对齐到页) 163 /// - `len`:取消映射的字节数(已经对齐到页) 164 /// 165 /// ## 返回值 166 /// 167 /// 成功时返回0,失败时返回错误码 168 pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> { 169 assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); 170 assert!(check_aligned(len, MMArch::PAGE_SIZE)); 171 172 if unlikely(verify_area(start_vaddr, len).is_err()) { 173 return Err(SystemError::EINVAL); 174 } 175 if unlikely(len == 0) { 176 return Err(SystemError::EINVAL); 177 } 178 179 let current_address_space: Arc<AddressSpace> = AddressSpace::current()?; 180 let start_frame = VirtPageFrame::new(start_vaddr); 181 let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); 182 183 current_address_space 184 .write() 185 .munmap(start_frame, page_count) 186 .map_err(|_| SystemError::EINVAL)?; 187 return Ok(0); 188 } 189 190 /// ## mprotect系统调用 191 /// 192 /// ## 参数 193 /// 194 /// - `start_vaddr`:起始地址(已经对齐到页) 195 /// - `len`:长度(已经对齐到页) 196 /// - `prot_flags`:保护标志 197 pub fn mprotect( 198 start_vaddr: VirtAddr, 199 len: usize, 200 prot_flags: usize, 201 ) -> Result<usize, SystemError> { 202 assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); 203 assert!(check_aligned(len, MMArch::PAGE_SIZE)); 204 205 if unlikely(verify_area(start_vaddr, len).is_err()) { 206 return Err(SystemError::EINVAL); 207 } 208 if unlikely(len == 0) { 209 return Err(SystemError::EINVAL); 210 } 211 212 let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?; 213 214 let current_address_space: Arc<AddressSpace> = AddressSpace::current()?; 215 let start_frame = VirtPageFrame::new(start_vaddr); 216 let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); 217 218 current_address_space 219 .write() 220 .mprotect(start_frame, page_count, prot_flags) 221 .map_err(|_| SystemError::EINVAL)?; 222 return Ok(0); 223 } 224 } 225