1 use core::intrinsics::unlikely; 2 3 use alloc::sync::Arc; 4 use log::error; 5 use system_error::SystemError; 6 7 use crate::{ 8 arch::MMArch, 9 ipc::shm::ShmFlags, 10 libs::align::{check_aligned, page_align_up}, 11 mm::MemoryManagementArch, 12 syscall::Syscall, 13 }; 14 15 use super::{ 16 allocator::page_frame::{PageFrameCount, VirtPageFrame}, 17 ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR}, 18 verify_area, VirtAddr, VmFlags, 19 }; 20 21 bitflags! { 22 /// Memory protection flags 23 pub struct ProtFlags: u64 { 24 const PROT_NONE = 0x0; 25 const PROT_READ = 0x1; 26 const PROT_WRITE = 0x2; 27 const PROT_EXEC = 0x4; 28 } 29 30 /// Memory mapping flags 31 pub struct MapFlags: u64 { 32 const MAP_NONE = 0x0; 33 /// share changes 34 const MAP_SHARED = 0x1; 35 /// changes are private 36 const MAP_PRIVATE = 0x2; 37 /// Interpret addr exactly 38 const MAP_FIXED = 0x10; 39 /// don't use a file 40 const MAP_ANONYMOUS = 0x20; 41 // linux-6.1-rc5/include/uapi/asm-generic/mman.h#7 42 /// stack-like segment 43 const MAP_GROWSDOWN = 0x100; 44 /// ETXTBSY 45 const MAP_DENYWRITE = 0x800; 46 /// Mark it as an executable 47 const MAP_EXECUTABLE = 0x1000; 48 /// Pages are locked 49 const MAP_LOCKED = 0x2000; 50 /// don't check for reservations 51 const MAP_NORESERVE = 0x4000; 52 /// populate (prefault) pagetables 53 const MAP_POPULATE = 0x8000; 54 /// do not block on IO 55 const MAP_NONBLOCK = 0x10000; 56 /// give out an address that is best suited for process/thread stacks 57 const MAP_STACK = 0x20000; 58 /// create a huge page mapping 59 const MAP_HUGETLB = 0x40000; 60 /// perform synchronous page faults for the mapping 61 const MAP_SYNC = 0x80000; 62 /// MAP_FIXED which doesn't unmap underlying mapping 63 const MAP_FIXED_NOREPLACE = 0x100000; 64 65 /// For anonymous mmap, memory could be uninitialized 66 const MAP_UNINITIALIZED = 0x4000000; 67 } 68 69 /// Memory mremapping flags 70 pub struct MremapFlags: u8 { 71 const MREMAP_MAYMOVE = 1; 72 const MREMAP_FIXED = 2; 73 const MREMAP_DONTUNMAP = 4; 74 } 75 76 77 pub struct MadvFlags: u64 { 78 /// 默认行为,系统会进行一定的预读和预写,适用于一般读取场景 79 const MADV_NORMAL = 0; 80 /// 随机访问模式,系统会尽量最小化数据读取量,适用于随机访问的场景 81 const MADV_RANDOM = 1; 82 /// 顺序访问模式,系统会进行积极的预读,访问后的页面可以尽快释放,适用于顺序读取场景 83 const MADV_SEQUENTIAL = 2; 84 /// 通知系统预读某些页面,用于应用程序提前准备数据 85 const MADV_WILLNEED = 3; 86 /// 通知系统应用程序不再需要某些页面,内核可以释放相关资源 87 const MADV_DONTNEED = 4; 88 89 /// 将指定范围的页面标记为延迟释放,真正的释放会延迟至内存压力发生时 90 const MADV_FREE = 8; 91 /// 应用程序请求释放指定范围的页面和相关的后备存储 92 const MADV_REMOVE = 9; 93 /// 在 fork 时排除指定区域 94 const MADV_DONTFORK = 10; 95 /// 取消 MADV_DONTFORK 的效果,不再在 fork 时排除指定区域 96 const MADV_DOFORK = 11; 97 /// 模拟内存硬件错误,触发内存错误处理器处理 98 const MADV_HWPOISON = 100; 99 /// 尝试软下线指定的内存范围 100 const MADV_SOFT_OFFLINE = 101; 101 102 /// 应用程序建议内核尝试合并指定范围内内容相同的页面 103 const MADV_MERGEABLE = 12; 104 /// 取消 MADV_MERGEABLE 的效果,不再合并页面 105 const MADV_UNMERGEABLE = 13; 106 107 /// 应用程序希望将指定范围以透明大页方式支持 108 const MADV_HUGEPAGE = 14; 109 /// 将指定范围标记为不值得用透明大页支持 110 const MADV_NOHUGEPAGE = 15; 111 112 /// 应用程序请求在核心转储时排除指定范围内的页面 113 const MADV_DONTDUMP = 16; 114 /// 取消 MADV_DONTDUMP 的效果,不再排除核心转储时的页面 115 const MADV_DODUMP = 17; 116 117 /// 在 fork 时将子进程的该区域内存填充为零 118 const MADV_WIPEONFORK = 18; 119 /// 取消 `MADV_WIPEONFORK` 的效果,不再在 fork 时填充子进程的内存 120 const MADV_KEEPONFORK = 19; 121 122 /// 应用程序不会立刻使用这些内存,内核将页面设置为非活动状态以便在内存压力发生时轻松回收 123 const MADV_COLD = 20; 124 /// 应用程序不会立刻使用这些内存,内核立即将这些页面换出 125 const MADV_PAGEOUT = 21; 126 127 /// 预先填充页面表,可读,通过触发读取故障 128 const MADV_POPULATE_READ = 22; 129 /// 预先填充页面表,可写,通过触发写入故障 130 const MADV_POPULATE_WRITE = 23; 131 132 /// 与 `MADV_DONTNEED` 类似,会将被锁定的页面释放 133 const MADV_DONTNEED_LOCKED = 24; 134 135 /// 同步将页面合并为新的透明大页 136 const MADV_COLLAPSE = 25; 137 138 } 139 } 140 141 impl From<MapFlags> for VmFlags { 142 fn from(map_flags: MapFlags) -> Self { 143 let mut vm_flags = VmFlags::VM_NONE; 144 145 if map_flags.contains(MapFlags::MAP_GROWSDOWN) { 146 vm_flags |= VmFlags::VM_GROWSDOWN; 147 } 148 149 if map_flags.contains(MapFlags::MAP_LOCKED) { 150 vm_flags |= VmFlags::VM_LOCKED; 151 } 152 153 if map_flags.contains(MapFlags::MAP_SYNC) { 154 vm_flags |= VmFlags::VM_SYNC; 155 } 156 157 vm_flags 158 } 159 } 160 161 impl From<ProtFlags> for VmFlags { 162 fn from(prot_flags: ProtFlags) -> Self { 163 let mut vm_flags = VmFlags::VM_NONE; 164 165 if prot_flags.contains(ProtFlags::PROT_READ) { 166 vm_flags |= VmFlags::VM_READ; 167 } 168 169 if prot_flags.contains(ProtFlags::PROT_WRITE) { 170 vm_flags |= VmFlags::VM_WRITE; 171 } 172 173 if prot_flags.contains(ProtFlags::PROT_EXEC) { 174 vm_flags |= VmFlags::VM_EXEC; 175 } 176 177 vm_flags 178 } 179 } 180 181 impl From<ShmFlags> for VmFlags { 182 fn from(shm_flags: ShmFlags) -> Self { 183 let mut vm_flags = VmFlags::VM_NONE; 184 185 if shm_flags.contains(ShmFlags::SHM_RDONLY) { 186 vm_flags |= VmFlags::VM_READ; 187 } else { 188 vm_flags |= VmFlags::VM_READ | VmFlags::VM_WRITE; 189 } 190 191 if shm_flags.contains(ShmFlags::SHM_EXEC) { 192 vm_flags |= VmFlags::VM_EXEC; 193 } 194 195 if shm_flags.contains(ShmFlags::SHM_HUGETLB) { 196 vm_flags |= VmFlags::VM_HUGETLB; 197 } 198 199 vm_flags 200 } 201 } 202 203 impl From<VmFlags> for MapFlags { 204 fn from(value: VmFlags) -> Self { 205 let mut map_flags = MapFlags::MAP_NONE; 206 207 if value.contains(VmFlags::VM_GROWSDOWN) { 208 map_flags |= MapFlags::MAP_GROWSDOWN; 209 } 210 211 if value.contains(VmFlags::VM_LOCKED) { 212 map_flags |= MapFlags::MAP_LOCKED; 213 } 214 215 if value.contains(VmFlags::VM_SYNC) { 216 map_flags |= MapFlags::MAP_SYNC; 217 } 218 219 if value.contains(VmFlags::VM_MAYSHARE) { 220 map_flags |= MapFlags::MAP_SHARED; 221 } 222 223 map_flags 224 } 225 } 226 227 impl From<VmFlags> for ProtFlags { 228 fn from(value: VmFlags) -> Self { 229 let mut prot_flags = ProtFlags::PROT_NONE; 230 231 if value.contains(VmFlags::VM_READ) { 232 prot_flags |= ProtFlags::PROT_READ; 233 } 234 235 if value.contains(VmFlags::VM_WRITE) { 236 prot_flags |= ProtFlags::PROT_WRITE; 237 } 238 239 if value.contains(VmFlags::VM_EXEC) { 240 prot_flags |= ProtFlags::PROT_EXEC; 241 } 242 243 prot_flags 244 } 245 } 246 247 impl Syscall { 248 pub fn brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError> { 249 // debug!("brk: new_addr={:?}", new_addr); 250 let address_space = AddressSpace::current()?; 251 let mut address_space = address_space.write(); 252 253 if new_addr < address_space.brk_start || new_addr >= MMArch::USER_END_VADDR { 254 return Ok(address_space.brk); 255 } 256 if new_addr == address_space.brk { 257 return Ok(address_space.brk); 258 } 259 260 unsafe { 261 address_space 262 .set_brk(VirtAddr::new(page_align_up(new_addr.data()))) 263 .ok(); 264 265 return Ok(address_space.sbrk(0).unwrap()); 266 } 267 } 268 269 pub fn sbrk(incr: isize) -> Result<VirtAddr, SystemError> { 270 let address_space = AddressSpace::current()?; 271 assert!(address_space.read().user_mapper.utable.is_current()); 272 let mut address_space = address_space.write(); 273 let r = unsafe { address_space.sbrk(incr) }; 274 275 return r; 276 } 277 278 /// ## mmap系统调用 279 /// 280 /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现 281 /// 282 /// ## 参数 283 /// 284 /// - `start_vaddr`:映射的起始地址 285 /// - `len`:映射的长度 286 /// - `prot`:保护标志 287 /// - `flags`:映射标志 288 /// - `fd`:文件描述符(暂时不支持) 289 /// - `offset`:文件偏移量 (暂时不支持) 290 /// 291 /// ## 返回值 292 /// 293 /// 成功时返回映射的起始地址,失败时返回错误码 294 pub fn mmap( 295 start_vaddr: VirtAddr, 296 len: usize, 297 prot_flags: usize, 298 map_flags: usize, 299 _fd: i32, 300 _offset: usize, 301 ) -> Result<usize, SystemError> { 302 let map_flags = MapFlags::from_bits_truncate(map_flags as u64); 303 let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64); 304 305 if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR) 306 && map_flags.contains(MapFlags::MAP_FIXED) 307 { 308 error!( 309 "mmap: MAP_FIXED is not supported for address below {}", 310 DEFAULT_MMAP_MIN_ADDR 311 ); 312 return Err(SystemError::EINVAL); 313 } 314 // 暂时不支持除匿名页以外的映射 315 if !map_flags.contains(MapFlags::MAP_ANONYMOUS) { 316 error!("mmap: not support file mapping"); 317 return Err(SystemError::ENOSYS); 318 } 319 320 // 暂时不支持巨页映射 321 if map_flags.contains(MapFlags::MAP_HUGETLB) { 322 error!("mmap: not support huge page mapping"); 323 return Err(SystemError::ENOSYS); 324 } 325 let current_address_space = AddressSpace::current()?; 326 let start_page = current_address_space.write().map_anonymous( 327 start_vaddr, 328 len, 329 prot_flags, 330 map_flags, 331 true, 332 true, 333 )?; 334 return Ok(start_page.virt_address().data()); 335 } 336 337 /// ## mremap系统调用 338 /// 339 /// 340 /// ## 参数 341 /// 342 /// - `old_vaddr`:原映射的起始地址 343 /// - `old_len`:原映射的长度 344 /// - `new_len`:重新映射的长度 345 /// - `mremap_flags`:重映射标志 346 /// - `new_vaddr`:重新映射的起始地址 347 /// 348 /// ## 返回值 349 /// 350 /// 成功时返回重映射的起始地址,失败时返回错误码 351 pub fn mremap( 352 old_vaddr: VirtAddr, 353 old_len: usize, 354 new_len: usize, 355 mremap_flags: MremapFlags, 356 new_vaddr: VirtAddr, 357 ) -> Result<usize, SystemError> { 358 // 需要重映射到新内存区域的情况下,必须包含MREMAP_MAYMOVE并且指定新地址 359 if mremap_flags.contains(MremapFlags::MREMAP_FIXED) 360 && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) 361 || new_vaddr == VirtAddr::new(0)) 362 { 363 return Err(SystemError::EINVAL); 364 } 365 366 // 不取消旧映射的情况下,必须包含MREMAP_MAYMOVE并且新内存大小等于旧内存大小 367 if mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) 368 && (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) || old_len != new_len) 369 { 370 return Err(SystemError::EINVAL); 371 } 372 373 // 旧内存地址必须对齐 374 if !old_vaddr.check_aligned(MMArch::PAGE_SIZE) { 375 return Err(SystemError::EINVAL); 376 } 377 378 // 将old_len、new_len 对齐页面大小 379 let old_len = page_align_up(old_len); 380 let new_len = page_align_up(new_len); 381 382 // 不允许重映射内存区域大小为0 383 if new_len == 0 { 384 return Err(SystemError::EINVAL); 385 } 386 387 let current_address_space = AddressSpace::current()?; 388 let vma = current_address_space.read().mappings.contains(old_vaddr); 389 if vma.is_none() { 390 return Err(SystemError::EINVAL); 391 } 392 let vma = vma.unwrap(); 393 let vm_flags = *vma.lock().vm_flags(); 394 395 // 暂时不支持巨页映射 396 if vm_flags.contains(VmFlags::VM_HUGETLB) { 397 error!("mmap: not support huge page mapping"); 398 return Err(SystemError::ENOSYS); 399 } 400 401 // 缩小旧内存映射区域 402 if old_len > new_len { 403 Self::munmap(old_vaddr + new_len, old_len - new_len)?; 404 return Ok(old_vaddr.data()); 405 } 406 407 // 重映射到新内存区域 408 let r = current_address_space.write().mremap( 409 old_vaddr, 410 old_len, 411 new_len, 412 mremap_flags, 413 new_vaddr, 414 vm_flags, 415 )?; 416 417 if !mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) { 418 Self::munmap(old_vaddr, old_len)?; 419 } 420 421 return Ok(r.data()); 422 } 423 424 /// ## munmap系统调用 425 /// 426 /// ## 参数 427 /// 428 /// - `start_vaddr`:取消映射的起始地址(已经对齐到页) 429 /// - `len`:取消映射的字节数(已经对齐到页) 430 /// 431 /// ## 返回值 432 /// 433 /// 成功时返回0,失败时返回错误码 434 pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> { 435 assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); 436 assert!(check_aligned(len, MMArch::PAGE_SIZE)); 437 438 if unlikely(verify_area(start_vaddr, len).is_err()) { 439 return Err(SystemError::EINVAL); 440 } 441 if unlikely(len == 0) { 442 return Err(SystemError::EINVAL); 443 } 444 445 let current_address_space: Arc<AddressSpace> = AddressSpace::current()?; 446 let start_frame = VirtPageFrame::new(start_vaddr); 447 let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); 448 449 current_address_space 450 .write() 451 .munmap(start_frame, page_count) 452 .map_err(|_| SystemError::EINVAL)?; 453 454 return Ok(0); 455 } 456 457 /// ## mprotect系统调用 458 /// 459 /// ## 参数 460 /// 461 /// - `start_vaddr`:起始地址(已经对齐到页) 462 /// - `len`:长度(已经对齐到页) 463 /// - `prot_flags`:保护标志 464 pub fn mprotect( 465 start_vaddr: VirtAddr, 466 len: usize, 467 prot_flags: usize, 468 ) -> Result<usize, SystemError> { 469 assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); 470 assert!(check_aligned(len, MMArch::PAGE_SIZE)); 471 472 if unlikely(verify_area(start_vaddr, len).is_err()) { 473 return Err(SystemError::EINVAL); 474 } 475 if unlikely(len == 0) { 476 return Err(SystemError::EINVAL); 477 } 478 479 let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?; 480 481 let current_address_space: Arc<AddressSpace> = AddressSpace::current()?; 482 let start_frame = VirtPageFrame::new(start_vaddr); 483 let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); 484 485 current_address_space 486 .write() 487 .mprotect(start_frame, page_count, prot_flags) 488 .map_err(|_| SystemError::EINVAL)?; 489 return Ok(0); 490 } 491 492 /// ## madvise系统调用 493 /// 494 /// ## 参数 495 /// 496 /// - `start_vaddr`:起始地址(已经对齐到页) 497 /// - `len`:长度(已经对齐到页) 498 /// - `madv_flags`:建议标志 499 pub fn madvise( 500 start_vaddr: VirtAddr, 501 len: usize, 502 madv_flags: usize, 503 ) -> Result<usize, SystemError> { 504 if !start_vaddr.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) { 505 return Err(SystemError::EINVAL); 506 } 507 508 if unlikely(verify_area(start_vaddr, len).is_err()) { 509 return Err(SystemError::EINVAL); 510 } 511 if unlikely(len == 0) { 512 return Err(SystemError::EINVAL); 513 } 514 515 let madv_flags = MadvFlags::from_bits(madv_flags as u64).ok_or(SystemError::EINVAL)?; 516 517 let current_address_space: Arc<AddressSpace> = AddressSpace::current()?; 518 let start_frame = VirtPageFrame::new(start_vaddr); 519 let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); 520 521 current_address_space 522 .write() 523 .madvise(start_frame, page_count, madv_flags) 524 .map_err(|_| SystemError::EINVAL)?; 525 return Ok(0); 526 } 527 } 528