Skip to content

Commit fc216b4

Browse files
committed
update
1 parent 353990c commit fc216b4

File tree

1 file changed

+49
-57
lines changed

1 file changed

+49
-57
lines changed

os/src/syscall/process.rs

Lines changed: 49 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::task::{change_program_brk, exit_current_and_run_next, suspend_current
33
use crate::timer::get_time_us;
44
use crate::mm::{PageTable,translated_and_write,VirtAddr,frame_alloc,PTEFlags};
55
use crate::config::{PAGE_SIZE,USER_SPACE_END};
6+
use alloc::vec::Vec;
67

78
#[repr(C)]
89
#[derive(Debug)]
@@ -110,9 +111,8 @@ pub fn sys_trace(trace_request: usize, id: usize, data: usize) -> isize {
110111
}
111112
}
112113

113-
// YOUR JOB: Implement mmap.
114114
pub fn sys_mmap(start: usize, len: usize, prot: usize) -> isize {
115-
trace!("kernel: sys_mmap NOT IMPLEMENTED YET!");
115+
trace!("kernel: sys_mmap");
116116

117117
// 1. 校验start按页对齐(页大小为PAGE_SIZE,4KB为4096)
118118
if start % PAGE_SIZE != 0 {
@@ -125,7 +125,7 @@ pub fn sys_mmap(start: usize, len: usize, prot: usize) -> isize {
125125
}
126126

127127
// 3. 计算映射区间[start, end),处理len=0的特殊情况
128-
let end = start + len ;
128+
let end = start.checked_add(len).unwrap_or(usize::MAX);
129129
// 校验区间不超出用户空间(避免映射内核地址)
130130
if start >= USER_SPACE_END || end > USER_SPACE_END {
131131
return -1;
@@ -135,8 +135,8 @@ pub fn sys_mmap(start: usize, len: usize, prot: usize) -> isize {
135135
if len == 0 {
136136
return 0;
137137
}
138-
// println!("kernel: sys_mmap from {:#x} to {:#x}", start, end);
139-
// 5. 获取当前进程的页表(加锁保护,避免并发修改)
138+
139+
// 5. 获取当前进程的页表
140140
let page_table_token = current_user_token();
141141
let mut page_table = PageTable::from_token(page_table_token);
142142

@@ -145,51 +145,49 @@ pub fn sys_mmap(start: usize, len: usize, prot: usize) -> isize {
145145
if (prot & 0x2) != 0 { flags |= PTEFlags::W; } // prot第1位→写权限
146146
if (prot & 0x4) != 0 { flags |= PTEFlags::X; } // prot第2位→执行权限
147147

148-
149148
// 6. 检查区间内是否已有映射(如有则返回错误)
150149
let mut va = start;
151150
while va < end {
152151
let vpn = VirtAddr::from(va).floor(); // 虚拟页号(向下取整到页边界)
153-
println!("kernel: sys_mmap mapping vpn {:#x}", vpn.0);
154152

155153
if let Some(pte) = page_table.translate(vpn) {
156-
// 核心修改:判断页面是否有效(检查PTE的有效位V是否置位)
157-
if pte.is_valid() { // 关键:判断“页面是否valid”
154+
// 判断页面是否有效(检查PTE的有效位V是否置位)
155+
if pte.is_valid() {
158156
return -1; // 存在已有效的映射页,冲突返回-1
159-
}else {
160-
// 页表项存在但无效,继续下一页检查
161-
println!("kernel: PTE_flage = {:?}", pte.flags());
162157
}
163-
}else {
164-
// 页表项不存在,继续下一页检查
165-
println!("kernel: PTE_flage = None");
166158
}
167159

168-
// 分配物理页(alloc_frame返回None表示内存不足)
169-
let ppn = frame_alloc().unwrap().ppn;
170-
171-
// 建立虚拟页→物理页的映射(写入页表)
172-
page_table.map(vpn, ppn, flags);
160+
va += PAGE_SIZE;
161+
}
173162

174-
if let Some(pte1) = page_table.translate(vpn) {
175-
// 检查mmap之后标志位是否设置正常
176-
println!("kernel: mmap_PTE_flage = {:#?}", pte1.flags());
177-
}else {
178-
// 页表项存在但无效,继续下一页检查
179-
println!("kernel: mmap_PTE_flage = None");
163+
// 7. 建立映射,处理内存分配失败
164+
let mut va = start;
165+
let mut mapped_pages = Vec::new(); // 记录已成功映射的页面,用于错误回滚
166+
167+
while va < end {
168+
let vpn = VirtAddr::from(va).floor();
169+
170+
// 分配物理页(处理内存不足情况)
171+
if let Some(frame) = frame_alloc() {
172+
let ppn = frame.ppn;
173+
174+
// 建立虚拟页→物理页的映射
175+
page_table.map(vpn, ppn, flags);
176+
mapped_pages.push(vpn); // 记录成功映射的页面
177+
} else {
178+
// 内存不足,回滚已建立的映射
179+
for mapped_vpn in mapped_pages {
180+
page_table.unmap(mapped_vpn);
181+
}
182+
return -1;
180183
}
181184

182185
va += PAGE_SIZE;
183-
184-
println!("kernel: va = {:#x}", va);
185-
println!("kernel: end = {:#x}", end);
186-
187186
}
188187

189188
0 // 成功返回0
190189
}
191190

192-
// YOUR JOB: Implement munmap.
193191
pub fn sys_munmap(start: usize, len: usize) -> isize {
194192
trace!("kernel: sys_munmap");
195193

@@ -203,46 +201,40 @@ pub fn sys_munmap(start: usize, len: usize) -> isize {
203201
return 0;
204202
}
205203

206-
// 3. 计算映射区间[start, end),处理len=0的特殊情况
207-
let end = start + len ;
208-
// 校验区间:不超出用户空间,且start <= end(避免无效区间)
204+
// 3. 计算映射区间[start, end)
205+
let end = start.checked_add(len).unwrap_or(usize::MAX);
206+
// 校验区间:不超出用户空间
209207
if start > end || end > USER_SPACE_END {
210208
return -1;
211209
}
212210

213-
// 4. 获取当前进程的页表(加锁保护,避免并发修改页表导致数据竞争)
211+
// 4. 获取当前进程的页表
214212
let page_table_token = current_user_token();
215213
let mut page_table = PageTable::from_token(page_table_token);
216214

215+
// 5. 首先检查整个区域是否都是已映射的
216+
// 如果任何一页没有有效映射,则返回错误
217217
let mut va = start;
218-
// 合并「校验+回收+取消映射」为一次遍历(优化性能,减少冗余)
219-
220-
while va < end {
221-
let vpn = VirtAddr::from(va).floor(); // 虚拟页号(向下对齐到页边界)
218+
while va < end {
219+
let vpn = VirtAddr::from(va).floor();
222220

223-
// 关键修改:仅处理已映射的页,未映射页直接跳过(不返回错误)
221+
// 检查页面是否有效映射
224222
if let Some(pte) = page_table.translate(vpn) {
225-
// 校验页合法性:必须是有效且用户可见的页
226-
if !pte.user_visible() {
227-
return -1; // 有效但非用户页,属于错误,返回-1
223+
if !pte.is_valid() || !pte.user_visible() {
224+
// 页面无效,返回错误
225+
return -1;
226+
}else {
227+
page_table.unmap(vpn);
228228
}
229-
230-
// 取消页表映射(清除PTE的V位)
231-
page_table.unmap(vpn);
232-
233-
}
234-
235-
va += PAGE_SIZE; // 按页步长遍历下一页
236-
229+
}
230+
va += PAGE_SIZE;
237231
}
238232

239-
// 5. 刷新TLB:确保CPU立即丢弃旧映射(避免访问已回收的物理页)
240-
// 注意:sfence.vma 需确保操作的是当前进程的页表(通过current_user_token保证)
241-
// unsafe {
242-
// core::arch::asm!("sfence.vma");
243-
// // a0=0 表示刷新所有虚拟地址,a1=0 表示使用当前页表(ASID=0,简化场景)
244-
// }
245233

234+
// 7. 刷新TLB:确保CPU立即丢弃旧映射
235+
unsafe {
236+
core::arch::asm!("sfence.vma");
237+
}
246238

247239
0 // 成功返回0
248240
}

0 commit comments

Comments
 (0)