@@ -7,7 +7,10 @@ use axerrno::LinuxError;
77use axtask:: current;
88use axtask:: TaskExtRef ;
99use axhal:: paging:: MappingFlags ;
10- use arceos_posix_api as api;
10+
11+ use arceos_posix_api:: { self as api, get_file_like} ;
12+ use memory_addr:: { align_up_4k, AddrRange , PAGE_SIZE_4K } ;
13+ use crate :: task:: TaskExt ;
1114
1215const SYS_IOCTL : usize = 29 ;
1316const SYS_OPENAT : usize = 56 ;
@@ -49,7 +52,7 @@ bitflags::bitflags! {
4952 /// permissions for sys_mmap
5053 ///
5154 /// See <https://github.com/bminor/glibc/blob/master/bits/mman.h>
52- struct MmapProt : i32 {
55+ struct MmapProt : i32 { //prot标志定义
5356 /// Page can be read.
5457 const PROT_READ = 1 << 0 ;
5558 /// Page can be written.
@@ -80,7 +83,7 @@ bitflags::bitflags! {
8083 /// flags for sys_mmap
8184 ///
8285 /// See <https://github.com/bminor/glibc/blob/master/bits/mman.h>
83- struct MmapFlags : i32 {
86+ struct MmapFlags : i32 { //flags标志定义
8487 /// Share changes
8588 const MAP_SHARED = 1 << 0 ;
8689 /// Changes private; copy pages on write.
@@ -140,7 +143,64 @@ fn sys_mmap(
140143 fd : i32 ,
141144 _offset : isize ,
142145) -> isize {
143- unimplemented ! ( "no sys_mmap!" ) ;
146+ // unimplemented!("no sys_mmap!");
147+ let curr = current ( ) ; //得到当前进程的task 相当于任务控制块
148+ let ext = unsafe { & mut * ( curr. task_ext_ptr ( ) as * mut TaskExt ) } ; //获取任务扩展数据
149+ let mut space = ext. aspace . lock ( ) ; //得到任务的地址空间
150+
151+ let flags = MmapFlags :: from_bits_truncate ( flags) ; //两个标志转换 flags代表映射行为标志 包括修改后对其他进程是否共享等
152+ let prot = MmapProt :: from_bits_truncate ( prot) ; //prot表示映射的内存权限 是否可读写等
153+ let len = align_up_4k ( len) ;
154+
155+ // 1. 选地址
156+ let vaddr = if flags. contains ( MmapFlags :: MAP_FIXED ) {
157+ VirtAddr :: from ( addr as usize ) //CASE1:强制使用指定地址 无论地址是否可用
158+ } else if addr. is_null ( ) { //CASE2:addr.is_null() 代表内核自己决定
159+ space. find_free_area ( space. base ( ) + PAGE_SIZE_4K , len,
160+ AddrRange :: new ( space. base ( ) , space. end ( ) ) ) ?
161+ } else {
162+ VirtAddr :: from ( addr as usize ) //CASE3:其他情况 使用提示的地址
163+ } ;
164+
165+ // 2. 映射页表
166+ space. map_alloc ( vaddr, len, MappingFlags :: from ( prot) | MappingFlags :: USER , true )
167+ . map_err ( |_| LinuxError :: ENOMEM ) ?;
168+ //在用户地址空间中,建立从虚拟地址 vaddr 开始、长度为 len 的区域与物理页的映射关系
169+ //分配了物理页 并在页表建立了映射
170+
171+ // 3. 填充内容
172+ if !flags. contains ( MmapFlags :: MAP_ANONYMOUS ) {
173+ let file = get_file_like ( fd) ?;
174+ let file_size = file. get_size ( ) ; // 获取文件大小
175+
176+ // 计算实际需要读取的字节数
177+ let read_len = len. min ( file_size. saturating_sub ( offset as usize ) ) ;
178+
179+ let mut remain = read_len;
180+ let mut off = offset as usize ;
181+ let mut va = vaddr;
182+ //将虚拟地址转化为内核可访问的多个内核缓冲区 内部是转化为物理地址 再转化为内核虚拟地址
183+ //这样将文件读到这些内核缓冲区
184+ for buf in space. translated_byte_buffer ( va, read_len) ? {
185+ if remain == 0 { break ; }
186+
187+ let read = file. read_at ( off, buf) ? as usize ;
188+ if read == 0 {
189+ // 文件结束但还有剩余空间,填充0或报错?
190+ break ;
191+ }
192+
193+ off += read;
194+ remain = remain. saturating_sub ( read) ;
195+ }
196+
197+ // 如果是 MAP_PRIVATE,标记为写时复制?
198+ if flags. contains ( MmapFlags :: MAP_PRIVATE ) {
199+ // 可能需要特殊的处理
200+ }
201+ }
202+
203+ Ok ( vaddr. as_usize ( ) as isize )
144204}
145205
146206fn sys_openat ( dfd : c_int , fname : * const c_char , flags : c_int , mode : api:: ctypes:: mode_t ) -> isize {
0 commit comments