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