Skip to content

Commit 7100b83

Browse files
authored
refactor(mm): 修改异常表安全拷贝的错误处理返回值 (#1395)
将copy_with_exception_table和memset_with_exception_table的返回值从错误码改为剩余 未操作字节数 Signed-off-by: longjin <[email protected]>
1 parent 1c53c97 commit 7100b83

File tree

6 files changed

+37
-58
lines changed

6 files changed

+37
-58
lines changed

docs/kernel/memory_management/extable_safe_copy_design.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
│ │ 4. 修改指令指针(RIP) │ │
6262
│ │ ↓ │ │
6363
│ │ 5. 执行修复代码 │ │
64-
│ │ └─ 设置错误码(-1) │ │
64+
│ │ └─ 返回剩余未拷贝字节数 │ │
6565
│ │ ↓ │ │
6666
│ │ 6. 返回EFAULT给用户 │ │
6767
│ └──────────────────────────────┘ │
@@ -99,7 +99,7 @@
9999
100100
101101
102-
修改RIP到修复代码 ──→ 返回错误码
102+
修改RIP到修复代码 ──→ 返回剩余未拷贝字节数
103103
```
104104

105105
## 典型执行场景
@@ -135,7 +135,7 @@
135135
136136
┌────────────────────────────────┐
137137
│ 4. 修改指令指针到修复代码 │
138-
│ └─ 设置返回值为错误码
138+
│ └─ 设置返回值为剩余未拷贝字节数
139139
└────────────────────────────────┘
140140
141141
@@ -149,7 +149,7 @@
149149

150150
**关键点:**
151151
- 无需预检查地址有效性
152-
- 页错误自动转换为错误码
152+
- 页错误自动转换为返回剩余未拷贝字节数
153153
- 内核不会panic,用户程序收到明确的错误信息
154154

155155
## 使用场景分析

kernel/src/arch/x86_64/interrupt/trap.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ Segment Selector Index: {:#x}\n
363363

364364
/// 处理页错误 14 #PF
365365
#[no_mangle]
366-
unsafe extern "C" fn do_page_fault(regs: &'static TrapFrame, error_code: u64) {
366+
unsafe extern "C" fn do_page_fault(regs: &'static mut TrapFrame, error_code: u64) {
367367
// error!(
368368
// "do_page_fault(14), \tError code: {:#x},\trsp: {:#x},\trip: {:#x},\t CPU: {}, \tpid: {:?}, \nFault Address: {:#x}",
369369
// error_code,

kernel/src/arch/x86_64/mm/fault.rs

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,7 @@ impl X86_64MMArch {
6666
false
6767
}
6868

69-
pub fn show_fault_oops(
70-
regs: &'static TrapFrame,
71-
error_code: X86PfErrorCode,
72-
address: VirtAddr,
73-
) {
69+
pub fn show_fault_oops(regs: &TrapFrame, error_code: X86PfErrorCode, address: VirtAddr) {
7470
let mapper =
7571
unsafe { PageMapper::current(crate::mm::PageTableKind::User, LockedFrameAllocator) };
7672
if let Some(entry) = mapper.get_entry(address, 0) {
@@ -131,11 +127,7 @@ impl X86_64MMArch {
131127
);
132128
}
133129

134-
pub fn page_fault_oops(
135-
regs: &'static TrapFrame,
136-
error_code: X86PfErrorCode,
137-
address: VirtAddr,
138-
) {
130+
pub fn page_fault_oops(regs: &TrapFrame, error_code: X86PfErrorCode, address: VirtAddr) {
139131
if regs.is_from_user() {
140132
Self::show_fault_oops(regs, error_code, address);
141133
}
@@ -149,7 +141,7 @@ impl X86_64MMArch {
149141
/// - `error_code`: 错误标志
150142
/// - `address`: 发生缺页异常的虚拟地址
151143
pub fn do_kern_addr_fault(
152-
regs: &'static TrapFrame,
144+
regs: &'static mut TrapFrame,
153145
error_code: X86PfErrorCode,
154146
address: VirtAddr,
155147
) {
@@ -196,7 +188,7 @@ impl X86_64MMArch {
196188
/// - `true`: 成功修复,可以继续执行
197189
/// - `false`: 无法修复,是真正的内核错误
198190
fn try_fixup_exception(
199-
regs: &'static TrapFrame,
191+
regs: &mut TrapFrame,
200192
_error_code: X86PfErrorCode,
201193
address: VirtAddr,
202194
) -> bool {
@@ -215,10 +207,7 @@ impl X86_64MMArch {
215207
);
216208

217209
// 修改trap frame的RIP到修复代码
218-
unsafe {
219-
let regs_mut = regs as *const TrapFrame as *mut TrapFrame;
220-
(*regs_mut).rip = fixup_addr as u64;
221-
}
210+
regs.rip = fixup_addr as u64;
222211

223212
return true;
224213
}
@@ -233,7 +222,7 @@ impl X86_64MMArch {
233222
/// - `error_code`: 错误标志
234223
/// - `address`: 发生缺页异常的虚拟地址
235224
pub unsafe fn do_user_addr_fault(
236-
regs: &'static TrapFrame,
225+
regs: &'static mut TrapFrame,
237226
error_code: X86PfErrorCode,
238227
address: VirtAddr,
239228
) {
@@ -298,17 +287,17 @@ impl X86_64MMArch {
298287
};
299288

300289
// 辅助函数:处理内核访问用户地址失败的情况
301-
let handle_kernel_access_failed = || {
290+
let handle_kernel_access_failed = |r: &mut TrapFrame| {
302291
// 如果是内核代码访问用户地址,尝试异常表修复
303-
if !regs.is_from_user() {
304-
if Self::try_fixup_exception(regs, error_code, address) {
292+
if !r.is_from_user() {
293+
if Self::try_fixup_exception(r, error_code, address) {
305294
return true; // 成功修复
306295
}
307296
// 如果异常表中没有,说明是bug
308297
error!(
309298
"Kernel code at {:#x} illegally accessed user address {:#x} \
310299
without exception table entry",
311-
regs.rip,
300+
r.rip,
312301
address.data()
313302
);
314303
panic!("Illegal user space access from kernel");
@@ -333,7 +322,7 @@ impl X86_64MMArch {
333322
);
334323

335324
// VMA不存在,检查是否需要异常表修复
336-
if handle_kernel_access_failed() {
325+
if handle_kernel_access_failed(regs) {
337326
return; // 已通过异常表修复
338327
}
339328

@@ -358,7 +347,7 @@ impl X86_64MMArch {
358347
);
359348

360349
// 栈溢出,检查是否需要异常表修复
361-
if handle_kernel_access_failed() {
350+
if handle_kernel_access_failed(regs) {
362351
return; // 已通过异常表修复
363352
}
364353

@@ -386,7 +375,7 @@ impl X86_64MMArch {
386375
log::error!("fault rip: {:#x}", regs.rip);
387376

388377
// 地址不在VMA范围内,检查是否需要异常表修复
389-
if handle_kernel_access_failed() {
378+
if handle_kernel_access_failed(regs) {
390379
return; // 已通过异常表修复
391380
}
392381

@@ -403,7 +392,7 @@ impl X86_64MMArch {
403392
);
404393

405394
// VMA权限错误,检查是否需要异常表修复
406-
if handle_kernel_access_failed() {
395+
if handle_kernel_access_failed(regs) {
407396
return; // 已通过异常表修复
408397
}
409398

kernel/src/arch/x86_64/mm/mod.rs

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -395,13 +395,10 @@ impl MemoryManagementArch for X86_64MMArch {
395395
}
396396

397397
/// 带异常表保护的内存拷贝
398-
#[inline(always)]
399-
unsafe fn copy_with_exception_table(dst: *mut u8, src: *const u8, len: usize) -> i32 {
400-
let mut result: i32;
398+
unsafe fn copy_with_exception_table(dst: *mut u8, src: *const u8, len: usize) -> usize {
399+
let mut result: usize;
401400

402401
core::arch::asm!(
403-
// 保存原始值
404-
"xor {result:e}, {result:e}",
405402

406403
// 标记为可能出错的访问点
407404
"2:",
@@ -411,23 +408,21 @@ impl MemoryManagementArch for X86_64MMArch {
411408
// 正常完成,跳过错误处理
412409
"jmp 3f",
413410

414-
// 错误处理: 设置返回值为-1
411+
// 错误处理: 将剩余未拷贝的字节数返回(rcx会输出出去)
415412
"4:",
416-
"mov {result:e}, -1",
417413

418414
"3:",
419415

420416
// 添加异常表条目
421417
".pushsection __ex_table, \"a\"",
422418
".balign 8",
423419
".quad 2b - .",
424-
".quad 4b - .",
420+
".quad 4b - . + 8",
425421
".popsection",
426422

427-
result = out(reg) result,
428423
inout("rdi") dst => _,
429424
inout("rsi") src => _,
430-
inout("rcx") len => _,
425+
inout("rcx") len => result,
431426
options(att_syntax, nostack)
432427
);
433428

@@ -446,13 +441,10 @@ impl MemoryManagementArch for X86_64MMArch {
446441
/// ## 返回值
447442
/// - 0: 成功
448443
/// - -1: 发生页错误
449-
#[inline(always)]
450-
unsafe fn memset_with_exception_table(dst: *mut u8, value: u8, len: usize) -> i32 {
451-
let mut result: i32;
444+
unsafe fn memset_with_exception_table(dst: *mut u8, value: u8, len: usize) -> usize {
445+
let mut result: usize;
452446

453447
core::arch::asm!(
454-
// 初始化返回值为0
455-
"xor {result:e}, {result:e}",
456448

457449
// 标记为可能出错的访问点
458450
"2:",
@@ -463,22 +455,20 @@ impl MemoryManagementArch for X86_64MMArch {
463455
// 正常完成,跳过错误处理
464456
"jmp 3f",
465457

466-
// 错误处理: 设置返回值为-1
458+
// 错误处理: 将剩余未设置的字节数返回
467459
"4:",
468-
"mov {result:e}, -1",
469460

470461
"3:",
471462

472463
// 添加异常表条目
473464
".pushsection __ex_table, \"a\"",
474465
".balign 8",
475466
".quad 2b - .",
476-
".quad 4b - .",
467+
".quad 4b - . + 8",
477468
".popsection",
478469

479-
result = out(reg) result,
480470
inout("rdi") dst => _,
481-
inout("rcx") len => _,
471+
inout("rcx") len => result,
482472
inout("al") value => _,
483473
options(att_syntax, nostack)
484474
);

kernel/src/exception/extable.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,22 @@
66
#[derive(Debug, Clone, Copy)]
77
pub struct ExceptionTableEntry {
88
/// 可能触发异常的指令地址(相对于表项地址的偏移)
9-
pub insn_offset: i32,
9+
pub insn_offset: i64,
1010
/// 修复代码地址(相对于表项地址的偏移)
11-
pub fixup_offset: i32,
11+
pub fixup_offset: i64,
1212
}
1313

1414
impl ExceptionTableEntry {
1515
/// 获取指令的绝对地址
1616
pub fn insn_addr(&self) -> usize {
1717
let self_addr = self as *const Self as usize;
18-
(self_addr as i64 + self.insn_offset as i64) as usize
18+
(self_addr as i64 + self.insn_offset) as usize
1919
}
2020

2121
/// 获取修复代码的绝对地址
2222
pub fn fixup_addr(&self) -> usize {
2323
let self_addr = self as *const Self as usize;
24-
(self_addr as i64 + self.fixup_offset as i64) as usize
24+
(self_addr as i64 + self.fixup_offset) as usize
2525
}
2626
}
2727

kernel/src/mm/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -714,8 +714,8 @@ pub trait MemoryManagementArch: Clone + Copy + Debug {
714714
///
715715
/// ## 返回值
716716
/// - 0: 成功
717-
/// - -1: 发生页错误
718-
unsafe fn copy_with_exception_table(dst: *mut u8, src: *const u8, len: usize) -> i32 {
717+
/// - 其他值: 剩余未拷贝的字节数
718+
unsafe fn copy_with_exception_table(dst: *mut u8, src: *const u8, len: usize) -> usize {
719719
// 对于不支持异常表的架构,直接使用普通的内存拷贝
720720
ptr::copy_nonoverlapping(src, dst, len);
721721
0
@@ -734,8 +734,8 @@ pub trait MemoryManagementArch: Clone + Copy + Debug {
734734
///
735735
/// ## 返回值
736736
/// - 0: 成功
737-
/// - -1: 发生页错误
738-
unsafe fn memset_with_exception_table(dst: *mut u8, value: u8, len: usize) -> i32 {
737+
/// - 其他值: 剩余未设置的字节数
738+
unsafe fn memset_with_exception_table(dst: *mut u8, value: u8, len: usize) -> usize {
739739
// 对于不支持异常表的架构,直接使用普通的内存设置
740740
ptr::write_bytes(dst, value, len);
741741
0

0 commit comments

Comments
 (0)