1 use core::intrinsics::unlikely; 2 3 use alloc::sync::Arc; 4 use system_error::SystemError; 5 6 use crate::{ 7 arch::MMArch, 8 kerror, 9 libs::align::{check_aligned, page_align_up}, 10 mm::MemoryManagementArch, 11 syscall::Syscall, 12 }; 13 14 use super::{ 15 allocator::page_frame::{PageFrameCount, VirtPageFrame}, 16 ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR}, 17 verify_area, VirtAddr, VmFlags, 18 }; 19 20 bitflags! { 21 /// Memory protection flags 22 pub struct ProtFlags: u64 { 23 const PROT_NONE = 0x0; 24 const PROT_READ = 0x1; 25 const PROT_WRITE = 0x2; 26 const PROT_EXEC = 0x4; 27 } 28 29 /// Memory mapping flags 30 pub struct MapFlags: u64 { 31 const MAP_NONE = 0x0; 32 /// share changes 33 const MAP_SHARED = 0x1; 34 /// changes are private 35 const MAP_PRIVATE = 0x2; 36 /// Interpret addr exactly 37 const MAP_FIXED = 0x10; 38 /// don't use a file 39 const MAP_ANONYMOUS = 0x20; 40 // linux-6.1-rc5/include/uapi/asm-generic/mman.h#7 41 /// stack-like segment 42 const MAP_GROWSDOWN = 0x100; 43 /// ETXTBSY 44 const MAP_DENYWRITE = 0x800; 45 /// Mark it as an executable 46 const MAP_EXECUTABLE = 0x1000; 47 /// Pages are locked 48 const MAP_LOCKED = 0x2000; 49 /// don't check for reservations 50 const MAP_NORESERVE = 0x4000; 51 /// populate (prefault) pagetables 52 const MAP_POPULATE = 0x8000; 53 /// do not block on IO 54 const MAP_NONBLOCK = 0x10000; 55 /// give out an address that is best suited for process/thread stacks 56 const MAP_STACK = 0x20000; 57 /// create a huge page mapping 58 const MAP_HUGETLB = 0x40000; 59 /// perform synchronous page faults for the mapping 60 const MAP_SYNC = 0x80000; 61 /// MAP_FIXED which doesn't unmap underlying mapping 62 const MAP_FIXED_NOREPLACE = 0x100000; 63 64 /// For anonymous mmap, memory could be uninitialized 65 const MAP_UNINITIALIZED = 0x4000000; 66 } 67 68 /// Memory mremapping flags 69 pub struct MremapFlags: u8 { 70 const MREMAP_MAYMOVE = 1; 71 const MREMAP_FIXED = 2; 72 const MREMAP_DONTUNMAP = 4; 73 } 74 } 75 76 impl From<MapFlags> for VmFlags { from(map_flags: MapFlags) -> Self77 fn from(map_flags: MapFlags) -> Self { 78 let mut vm_flags = VmFlags::VM_NONE; 79 80 if map_flags.contains(MapFlags::MAP_GROWSDOWN) { 81 vm_flags |= VmFlags::VM_GROWSDOWN; 82 } 83 84 if map_flags.contains(MapFlags::MAP_LOCKED) { 85 vm_flags |= VmFlags::VM_LOCKED; 86 } 87 88 if map_flags.contains(MapFlags::MAP_SYNC) { 89 vm_flags |= VmFlags::VM_SYNC; 90 } 91 92 vm_flags 93 } 94 } 95 96 impl From<ProtFlags> for VmFlags { from(prot_flags: ProtFlags) -> Self97 fn from(prot_flags: ProtFlags) -> Self { 98 let mut vm_flags = VmFlags::VM_NONE; 99 100 if prot_flags.contains(ProtFlags::PROT_READ) { 101 vm_flags |= VmFlags::VM_READ; 102 } 103 104 if prot_flags.contains(ProtFlags::PROT_WRITE) { 105 vm_flags |= VmFlags::VM_WRITE; 106 } 107 108 if prot_flags.contains(ProtFlags::PROT_EXEC) { 109 vm_flags |= VmFlags::VM_EXEC; 110 } 111 112 vm_flags 113 } 114 } 115 116 impl Into<MapFlags> for VmFlags { into(self) -> MapFlags117 fn into(self) -> MapFlags { 118 let mut map_flags = MapFlags::MAP_NONE; 119 120 if self.contains(VmFlags::VM_GROWSDOWN) { 121 map_flags |= MapFlags::MAP_GROWSDOWN; 122 } 123 124 if self.contains(VmFlags::VM_LOCKED) { 125 map_flags |= MapFlags::MAP_LOCKED; 126 } 127 128 if self.contains(VmFlags::VM_SYNC) { 129 map_flags |= MapFlags::MAP_SYNC; 130 } 131 132 if self.contains(VmFlags::VM_MAYSHARE) { 133 map_flags |= MapFlags::MAP_SHARED; 134 } 135 136 map_flags 137 } 138 } 139 140 impl Into<ProtFlags> for VmFlags { into(self) -> ProtFlags141 fn into(self) -> ProtFlags { 142 let mut prot_flags = ProtFlags::PROT_NONE; 143 144 if self.contains(VmFlags::VM_READ) { 145 prot_flags |= ProtFlags::PROT_READ; 146 } 147 148 if self.contains(VmFlags::VM_WRITE) { 149 prot_flags |= ProtFlags::PROT_WRITE; 150 } 151 152 if self.contains(VmFlags::VM_EXEC) { 153 prot_flags |= ProtFlags::PROT_EXEC; 154 } 155 156 prot_flags 157 } 158 } 159 160 impl Syscall { brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError>161 pub fn brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError> { 162 // kdebug!("brk: new_addr={:?}", new_addr); 163 let address_space = AddressSpace::current()?; 164 let mut address_space = address_space.write(); 165 166 if new_addr < address_space.brk_start || new_addr >= MMArch::USER_END_VADDR { 167 return Ok(address_space.brk); 168 } 169 if new_addr == address_space.brk { 170 return Ok(address_space.brk); 171 } 172 173 unsafe { 174 address_space 175 .set_brk(VirtAddr::new(page_align_up(new_addr.data()))) 176 .ok(); 177 178 return Ok(address_space.sbrk(0).unwrap()); 179 } 180 } 181 sbrk(incr: isize) -> Result<VirtAddr, SystemError>182 pub fn sbrk(incr: isize) -> Result<VirtAddr, SystemError> { 183 let address_space = AddressSpace::current()?; 184 assert!(address_space.read().user_mapper.utable.is_current()); 185 let mut address_space = address_space.write(); 186 let r = unsafe { address_space.sbrk(incr) }; 187 188 return r; 189 } 190 191 /// ## mmap系统调用 192 /// 193 /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现 194 /// 195 /// ## 参数 196 /// 197 /// - `start_vaddr`:映射的起始地址 198 /// - `len`:映射的长度 199 /// - `prot`:保护标志 200 /// - `flags`:映射标志 201 /// - `fd`:文件描述符(暂时不支持) 202 /// - `offset`:文件偏移量 (暂时不支持) 203 /// 204 /// ## 返回值 205 /// 206 /// 成功时返回映射的起始地址,失败时返回错误码 mmap( start_vaddr: VirtAddr, len: usize, prot_flags: usize, map_flags: usize, _fd: i32, _offset: usize, ) -> Result<usize, SystemError>207 pub fn mmap( 208 start_vaddr: VirtAddr, 209 len: usize, 210 prot_flags: usize, 211 map_flags: usize, 212 _fd: i32, 213 _offset: usize, 214 ) -> Result<usize, SystemError> { 215 let map_flags = MapFlags::from_bits_truncate(map_flags as u64); 216 let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64); 217 218 if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR) 219 && map_flags.contains(MapFlags::MAP_FIXED) 220 { 221 kerror!( 222 "mmap: MAP_FIXED is not supported for address below {}", 223 DEFAULT_MMAP_MIN_ADDR 224 ); 225 return Err(SystemError::EINVAL); 226 } 227 // 暂时不支持除匿名页以外的映射 228 if !map_flags.contains(MapFlags::MAP_ANONYMOUS) { 229 kerror!("mmap: not support file mapping"); 230 return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); 231 } 232 233 // 暂时不支持巨页映射 234 if map_flags.contains(MapFlags::MAP_HUGETLB) { 235 kerror!("mmap: not support huge page mapping"); 236 return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); 237 } 238 let current_address_space = AddressSpace::current()?; 239 let start_page = current_address_space.write().map_anonymous( 240 start_vaddr, 241 len, 242 prot_flags, 243 map_flags, 244 true, 245 )?; 246 return Ok(start_page.virt_address().data()); 247 } 248 249 /// ## mremap系统调用 250 /// 251 /// 252 /// ## 参数 253 /// 254 /// - `old_vaddr`:原映射的起始地址 255 /// - `old_len`:原映射的长度 256 /// - `new_len`:重新映射的长度 257 /// - `mremap_flags`:重映射标志 258 /// - `new_vaddr`:重新映射的起始地址 259 /// 260 /// ## 返回值 261 /// 262 /// 成功时返回重映射的起始地址,失败时返回错误码 mremap( old_vaddr: VirtAddr, old_len: usize, new_len: usize, mremap_flags: MremapFlags, new_vaddr: VirtAddr, ) -> Result<usize, SystemError>263 pub fn mremap( 264 old_vaddr: VirtAddr, 265 old_len: usize, 266 new_len: usize, 267 mremap_flags: MremapFlags, 268 new_vaddr: VirtAddr, 269 ) -> Result<usize, SystemError> { 270 // 需要重映射到新内存区域的情况下,必须包含MREMAP_MAYMOVE并且指定新地址 271 if mremap_flags.contains(MremapFlags::MREMAP_FIXED) 272 && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) 273 || new_vaddr == VirtAddr::new(0)) 274 { 275 return Err(SystemError::EINVAL); 276 } 277 278 // 不取消旧映射的情况下,必须包含MREMAP_MAYMOVE并且新内存大小等于旧内存大小 279 if mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) 280 && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) || old_len != new_len) 281 { 282 return Err(SystemError::EINVAL); 283 } 284 285 // 旧内存地址必须对齐 286 if !old_vaddr.check_aligned(MMArch::PAGE_SIZE) { 287 return Err(SystemError::EINVAL); 288 } 289 290 // 将old_len、new_len 对齐页面大小 291 let old_len = page_align_up(old_len); 292 let new_len = page_align_up(new_len); 293 294 // 不允许重映射内存区域大小为0 295 if new_len == 0 { 296 return Err(SystemError::EINVAL); 297 } 298 299 let current_address_space = AddressSpace::current()?; 300 let vma = current_address_space.read().mappings.contains(old_vaddr); 301 if vma.is_none() { 302 return Err(SystemError::EINVAL); 303 } 304 let vma = vma.unwrap(); 305 let vm_flags = vma.lock().vm_flags().clone(); 306 307 // 暂时不支持巨页映射 308 if vm_flags.contains(VmFlags::VM_HUGETLB) { 309 kerror!("mmap: not support huge page mapping"); 310 return Err(SystemError::ENOSYS); 311 } 312 313 // 缩小旧内存映射区域 314 if old_len > new_len { 315 Self::munmap(old_vaddr + new_len, old_len - new_len)?; 316 return Ok(old_vaddr.data()); 317 } 318 319 // 重映射到新内存区域 320 let r = current_address_space.write().mremap( 321 old_vaddr, 322 old_len, 323 new_len, 324 mremap_flags, 325 new_vaddr, 326 vm_flags, 327 )?; 328 329 if !mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) { 330 Self::munmap(old_vaddr, old_len)?; 331 } 332 333 return Ok(r.data()); 334 } 335 336 /// ## munmap系统调用 337 /// 338 /// ## 参数 339 /// 340 /// - `start_vaddr`:取消映射的起始地址(已经对齐到页) 341 /// - `len`:取消映射的字节数(已经对齐到页) 342 /// 343 /// ## 返回值 344 /// 345 /// 成功时返回0,失败时返回错误码 munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError>346 pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> { 347 assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); 348 assert!(check_aligned(len, MMArch::PAGE_SIZE)); 349 350 if unlikely(verify_area(start_vaddr, len).is_err()) { 351 return Err(SystemError::EINVAL); 352 } 353 if unlikely(len == 0) { 354 return Err(SystemError::EINVAL); 355 } 356 357 let current_address_space: Arc<AddressSpace> = AddressSpace::current()?; 358 let start_frame = VirtPageFrame::new(start_vaddr); 359 let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); 360 361 current_address_space 362 .write() 363 .munmap(start_frame, page_count) 364 .map_err(|_| SystemError::EINVAL)?; 365 366 return Ok(0); 367 } 368 369 /// ## mprotect系统调用 370 /// 371 /// ## 参数 372 /// 373 /// - `start_vaddr`:起始地址(已经对齐到页) 374 /// - `len`:长度(已经对齐到页) 375 /// - `prot_flags`:保护标志 mprotect( start_vaddr: VirtAddr, len: usize, prot_flags: usize, ) -> Result<usize, SystemError>376 pub fn mprotect( 377 start_vaddr: VirtAddr, 378 len: usize, 379 prot_flags: usize, 380 ) -> Result<usize, SystemError> { 381 assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); 382 assert!(check_aligned(len, MMArch::PAGE_SIZE)); 383 384 if unlikely(verify_area(start_vaddr, len).is_err()) { 385 return Err(SystemError::EINVAL); 386 } 387 if unlikely(len == 0) { 388 return Err(SystemError::EINVAL); 389 } 390 391 let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?; 392 393 let current_address_space: Arc<AddressSpace> = AddressSpace::current()?; 394 let start_frame = VirtPageFrame::new(start_vaddr); 395 let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); 396 397 current_address_space 398 .write() 399 .mprotect(start_frame, page_count, prot_flags) 400 .map_err(|_| SystemError::EINVAL)?; 401 return Ok(0); 402 } 403 } 404