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 unsafe { 76 address_space 77 .set_brk(VirtAddr::new(page_align_up(new_addr.data()))) 78 .ok(); 79 80 return Ok(address_space.sbrk(0).unwrap()); 81 } 82 } 83 84 pub fn sbrk(incr: isize) -> Result<VirtAddr, SystemError> { 85 // kdebug!("pid:{}, sbrk: incr={}", current_pcb().pid, incr); 86 87 let address_space = AddressSpace::current()?; 88 let mut address_space = address_space.write(); 89 let r = unsafe { address_space.sbrk(incr) }; 90 91 // kdebug!("pid:{}, sbrk: r={:?}", current_pcb().pid, r); 92 return r; 93 } 94 95 /// ## mmap系统调用 96 /// 97 /// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现 98 /// 99 /// ## 参数 100 /// 101 /// - `start_vaddr`:映射的起始地址 102 /// - `len`:映射的长度 103 /// - `prot`:保护标志 104 /// - `flags`:映射标志 105 /// - `fd`:文件描述符(暂时不支持) 106 /// - `offset`:文件偏移量 (暂时不支持) 107 /// 108 /// ## 返回值 109 /// 110 /// 成功时返回映射的起始地址,失败时返回错误码 111 pub fn mmap( 112 start_vaddr: VirtAddr, 113 len: usize, 114 prot_flags: usize, 115 map_flags: usize, 116 _fd: i32, 117 _offset: usize, 118 ) -> Result<usize, SystemError> { 119 let map_flags = MapFlags::from_bits_truncate(map_flags as u64); 120 let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64); 121 122 if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR) 123 && map_flags.contains(MapFlags::MAP_FIXED) 124 { 125 kerror!( 126 "mmap: MAP_FIXED is not supported for address below {}", 127 DEFAULT_MMAP_MIN_ADDR 128 ); 129 return Err(SystemError::EINVAL); 130 } 131 // 暂时不支持除匿名页以外的映射 132 if !map_flags.contains(MapFlags::MAP_ANONYMOUS) { 133 kerror!("mmap: not support file mapping"); 134 return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); 135 } 136 137 // 暂时不支持巨页映射 138 if map_flags.contains(MapFlags::MAP_HUGETLB) { 139 kerror!("mmap: not support huge page mapping"); 140 return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); 141 } 142 let current_address_space = AddressSpace::current()?; 143 let start_page = current_address_space.write().map_anonymous( 144 start_vaddr, 145 len, 146 prot_flags, 147 map_flags, 148 true, 149 )?; 150 return Ok(start_page.virt_address().data()); 151 } 152 153 /// ## munmap系统调用 154 /// 155 /// ## 参数 156 /// 157 /// - `start_vaddr`:取消映射的起始地址(已经对齐到页) 158 /// - `len`:取消映射的字节数(已经对齐到页) 159 /// 160 /// ## 返回值 161 /// 162 /// 成功时返回0,失败时返回错误码 163 pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> { 164 assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); 165 assert!(check_aligned(len, MMArch::PAGE_SIZE)); 166 167 if unlikely(verify_area(start_vaddr, len).is_err()) { 168 return Err(SystemError::EINVAL); 169 } 170 if unlikely(len == 0) { 171 return Err(SystemError::EINVAL); 172 } 173 174 let current_address_space: Arc<AddressSpace> = AddressSpace::current()?; 175 let start_frame = VirtPageFrame::new(start_vaddr); 176 let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); 177 178 current_address_space 179 .write() 180 .munmap(start_frame, page_count) 181 .map_err(|_| SystemError::EINVAL)?; 182 return Ok(0); 183 } 184 185 /// ## mprotect系统调用 186 /// 187 /// ## 参数 188 /// 189 /// - `start_vaddr`:起始地址(已经对齐到页) 190 /// - `len`:长度(已经对齐到页) 191 /// - `prot_flags`:保护标志 192 pub fn mprotect( 193 start_vaddr: VirtAddr, 194 len: usize, 195 prot_flags: usize, 196 ) -> Result<usize, SystemError> { 197 assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE)); 198 assert!(check_aligned(len, MMArch::PAGE_SIZE)); 199 200 if unlikely(verify_area(start_vaddr, len).is_err()) { 201 return Err(SystemError::EINVAL); 202 } 203 if unlikely(len == 0) { 204 return Err(SystemError::EINVAL); 205 } 206 207 let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?; 208 209 let current_address_space: Arc<AddressSpace> = AddressSpace::current()?; 210 let start_frame = VirtPageFrame::new(start_vaddr); 211 let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE); 212 213 current_address_space 214 .write() 215 .mprotect(start_frame, page_count, prot_flags) 216 .map_err(|_| SystemError::EINVAL)?; 217 return Ok(0); 218 } 219 } 220