11//! Process management syscalls
22use crate :: task:: { change_program_brk, exit_current_and_run_next, suspend_current_and_run_next, current_user_token, get_current_syscall_stats} ;
33use crate :: timer:: get_time_us;
4- use crate :: mm:: { PageTable , translated_and_write, VirtAddr , frame_alloc, PTEFlags } ;
4+ use crate :: mm:: { PageTable , translated_and_write, VirtAddr , frame_alloc, PTEFlags , frame_dealloc } ;
55use crate :: config:: { PAGE_SIZE , USER_SPACE_END } ;
66use alloc:: vec:: Vec ;
77
@@ -114,24 +114,23 @@ pub fn sys_trace(trace_request: usize, id: usize, data: usize) -> isize {
114114pub fn sys_mmap ( start : usize , len : usize , prot : usize ) -> isize {
115115 trace ! ( "kernel: sys_mmap" ) ;
116116
117- // 1. 校验start按页对齐(页大小为PAGE_SIZE,4KB为4096)
117+ // 1. 校验start按页对齐
118118 if start % PAGE_SIZE != 0 {
119119 return -1 ;
120120 }
121121
122- // 2. 校验prot合法性:仅低3位有效,且至少有一个权限位
122+ // 2. 校验prot合法性
123123 if ( prot & !0x7 ) != 0 || ( prot & 0x7 ) == 0 {
124124 return -1 ;
125125 }
126126
127- // 3. 计算映射区间[start, end),处理len=0的特殊情况
127+ // 3. 计算映射区间
128128 let end = start. checked_add ( len) . unwrap_or ( usize:: MAX ) ;
129- // 校验区间不超出用户空间(避免映射内核地址)
130129 if start >= USER_SPACE_END || end > USER_SPACE_END {
131130 return -1 ;
132131 }
133132
134- // 4. 计算需要映射的页数(向上取整)
133+ // 4. 处理len=0的情况
135134 if len == 0 {
136135 return 0 ;
137136 }
@@ -140,42 +139,67 @@ pub fn sys_mmap(start: usize, len: usize, prot: usize) -> isize {
140139 let page_table_token = current_user_token ( ) ;
141140 let mut page_table = PageTable :: from_token ( page_table_token) ;
142141
143- let mut flags = PTEFlags :: V | PTEFlags :: U ; // 基础标志:有效+用户可见
144- if ( prot & 0x1 ) != 0 { flags |= PTEFlags :: R ; } // prot第0位→读权限
145- if ( prot & 0x2 ) != 0 { flags |= PTEFlags :: W ; } // prot第1位→写权限
146- if ( prot & 0x4 ) != 0 { flags |= PTEFlags :: X ; } // prot第2位→执行权限
142+ // 6. 设置权限标志
143+ let mut flags = PTEFlags :: V | PTEFlags :: U ;
144+ if ( prot & 0x1 ) != 0 { flags |= PTEFlags :: R ; }
145+ if ( prot & 0x2 ) != 0 { flags |= PTEFlags :: W ; }
146+ if ( prot & 0x4 ) != 0 { flags |= PTEFlags :: X ; }
147147
148- // 6 . 检查区间内是否已有映射(如有则返回错误)
148+ // 7 . 检查区间内是否已有映射
149149 let mut va = start;
150150 while va < end {
151- let vpn = VirtAddr :: from ( va) . floor ( ) ; // 虚拟页号(向下取整到页边界)
151+ let vpn = VirtAddr :: from ( va) . floor ( ) ;
152152
153153 if let Some ( pte) = page_table. translate ( vpn) {
154- // 判断页面是否有效(检查PTE的有效位V是否置位)
155154 if pte. is_valid ( ) {
156- return -1 ; // 存在已有效的映射页,冲突返回-1
155+ return -1 ; // 已存在有效映射
157156 }
158157 }
159-
160158 va += PAGE_SIZE ;
161159 }
162160
163- // 7. 建立映射,处理内存分配失败
161+ // 8. 建立映射并验证
164162 let mut va = start;
165- let mut mapped_pages = Vec :: new ( ) ; // 记录已成功映射的页面,用于错误回滚
163+ let mut mapped_pages = Vec :: new ( ) ;
166164
167165 while va < end {
168166 let vpn = VirtAddr :: from ( va) . floor ( ) ;
169167
170- // 分配物理页(处理内存不足情况)
168+ // 分配物理页
171169 if let Some ( frame) = frame_alloc ( ) {
172170 let ppn = frame. ppn ;
173171
174- // 建立虚拟页→物理页的映射
172+ // 建立映射
175173 page_table. map ( vpn, ppn, flags) ;
176- mapped_pages. push ( vpn) ; // 记录成功映射的页面
174+
175+ // 验证映射是否成功
176+ if let Some ( pte) = page_table. translate ( vpn) {
177+ if pte. is_valid ( ) && pte. ppn ( ) == ppn {
178+ // 映射成功,检查标志位
179+ let actual_flags = pte. flags ( ) ;
180+ if actual_flags. contains ( flags) {
181+ mapped_pages. push ( vpn) ;
182+ } else {
183+ // 标志位不匹配,回滚
184+ println ! ( "标志位不匹配: 期望 {:?}, 实际 {:?}" , flags, actual_flags) ;
185+ page_table. unmap ( vpn) ;
186+ break ;
187+ }
188+ } else {
189+ // 映射失败,回滚
190+ println ! ( "映射失败: VPN {:#x}" , vpn. 0 ) ;
191+ page_table. unmap ( vpn) ;
192+ break ;
193+ }
194+ } else {
195+ // 无法翻译,映射失败
196+ println ! ( "无法翻译 VPN: {:#x}" , vpn. 0 ) ;
197+ frame_dealloc ( ppn) ;
198+ break ;
199+ }
177200 } else {
178- // 内存不足,回滚已建立的映射
201+ // 内存不足
202+ println ! ( "内存不足,回滚已建立的映射" ) ;
179203 for mapped_vpn in mapped_pages {
180204 page_table. unmap ( mapped_vpn) ;
181205 }
@@ -185,53 +209,78 @@ pub fn sys_mmap(start: usize, len: usize, prot: usize) -> isize {
185209 va += PAGE_SIZE ;
186210 }
187211
212+ // 9. 检查是否所有页面都成功映射
213+ if mapped_pages. len ( ) * PAGE_SIZE < len {
214+ // 部分映射失败,回滚所有
215+ println ! ( "部分映射失败,回滚所有" ) ;
216+ for mapped_vpn in mapped_pages {
217+ page_table. unmap ( mapped_vpn) ;
218+ }
219+ return -1 ;
220+ }
221+
188222 0 // 成功返回0
189223}
190224
191225pub fn sys_munmap ( start : usize , len : usize ) -> isize {
192226 trace ! ( "kernel: sys_munmap" ) ;
193227
194- // 1. 校验start按页对齐(虚拟内存最小单位是页)
228+ // 1. 校验start按页对齐
195229 if start % PAGE_SIZE != 0 {
196230 return -1 ;
197231 }
198232
199- // 2. len=0时无实际操作,直接返回成功
233+ // 2. len=0时无实际操作
200234 if len == 0 {
201235 return 0 ;
202236 }
203237
204- // 3. 计算映射区间[start, end)
238+ // 3. 计算映射区间
205239 let end = start. checked_add ( len) . unwrap_or ( usize:: MAX ) ;
206- // 校验区间:不超出用户空间
207- if start > end || end > USER_SPACE_END {
240+ if end > USER_SPACE_END {
208241 return -1 ;
209242 }
210243
211244 // 4. 获取当前进程的页表
212245 let page_table_token = current_user_token ( ) ;
213246 let mut page_table = PageTable :: from_token ( page_table_token) ;
214247
215- // 5. 首先检查整个区域是否都是已映射的
216- // 如果任何一页没有有效映射,则返回错误
217- let mut va = start;
248+ let mut va = start;
218249 while va < end {
219250 let vpn = VirtAddr :: from ( va) . floor ( ) ;
220251
221- // 检查页面是否有效映射
252+ // 检查页面是否存在有效映射
222253 if let Some ( pte) = page_table. translate ( vpn) {
223- if !pte . is_valid ( ) || !pte . user_visible ( ) {
224- // 页面无效,返回错误
254+ // 只检查页面是否有效,不检查用户可见性
255+ if !pte . is_valid ( ) {
225256 return -1 ;
226- } else {
227- page_table. unmap ( vpn) ;
228257 }
229- }
258+ // 如果页面无效,静默跳过
259+ }
260+ // 如果页面没有映射(translate返回None),也静默跳过
261+
230262 va += PAGE_SIZE ;
231263 }
232264
265+ // 5. 遍历区域,只取消已存在的有效映射
266+ let mut va = start;
267+ while va < end {
268+ let vpn = VirtAddr :: from ( va) . floor ( ) ;
269+
270+ // 检查页面是否存在有效映射
271+ if let Some ( pte) = page_table. translate ( vpn) {
272+ // 只检查页面是否有效,不检查用户可见性
273+ if pte. is_valid ( ) {
274+ page_table. unmap ( vpn) ;
275+ }
276+ // 如果页面无效,静默跳过
277+ }
278+ // 如果页面没有映射(translate返回None),也静默跳过
279+
280+ va += PAGE_SIZE ;
281+ }
233282
234- // 7 . 刷新TLB:确保CPU立即丢弃旧映射
283+ // 6 . 刷新TLB
235284 unsafe {
236285 core:: arch:: asm!( "sfence.vma" ) ;
237286 }
0 commit comments