Skip to content

Commit d56c75f

Browse files
committed
update
1 parent fc216b4 commit d56c75f

File tree

2 files changed

+86
-37
lines changed

2 files changed

+86
-37
lines changed

os/src/mm/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ mod page_table;
1414

1515
pub use address::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum};
1616
use address::{StepByOne, VPNRange};
17-
pub use frame_allocator::{frame_alloc, FrameTracker};
17+
pub use frame_allocator::{frame_alloc, FrameTracker, frame_dealloc};
1818
pub use memory_set::remap_test;
1919
pub use memory_set::{kernel_stack_position, MapPermission, MemorySet, KERNEL_SPACE};
2020
pub use page_table::{translated_byte_buffer, PageTableEntry,translated_and_write};

os/src/syscall/process.rs

Lines changed: 85 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Process management syscalls
22
use crate::task::{change_program_brk, exit_current_and_run_next, suspend_current_and_run_next,current_user_token,get_current_syscall_stats};
33
use 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};
55
use crate::config::{PAGE_SIZE,USER_SPACE_END};
66
use alloc::vec::Vec;
77

@@ -114,24 +114,23 @@ pub fn sys_trace(trace_request: usize, id: usize, data: usize) -> isize {
114114
pub 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

191225
pub 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

Comments
 (0)