系统调用
在32位操作系统中,常常使用int 0x80
指令来完成系统调用处理。但是在x64中,引入了syscall
指令,称为快速系统调用,其不触发中断,而是有自己的一套控制流,在用户态使用syscall
指令后,CPU会执行以下动作:
- 从CPU特殊寄存器STAR MSR中加载cs、ss寄存器
- 将当前的rflags存入r11寄存器,从CPU特殊寄存器RFMASK MSR中加载rflags
- 将当前rip存入rcx,从CPU特殊寄存器LSTAR MSR中加载rip
内核系统调用分发
/// 系统调用总控函数
pub fn syscall(syscall_id: usize, args: [usize; 6]) -> (usize, usize) {
let syscall_id = num::FromPrimitive::from_usize(syscall_id).unwrap();
let ret = match syscall_id {
// 调试用
DebugWrite => sys_debug_write(args[0]),
...
// 任务相关
ProcExit => sys_proc_exit(args[0]),
...
// 文件相关
Open => sys_open(args[0], args[1], args[2]),
...
// 同步互斥
MutexCreate => sys_mutex_create(),
...
};
ret
}
用户态syscall
/// 用户态使用系统调用
fn syscall(id: SyscallNum, args: [usize; 6]) -> (usize, usize) {
let mut ret0: usize;
let mut ret1: usize;
unsafe {
core::arch::asm!(
"syscall",
in("rax") id as usize,
in("rdi") args[0],
in("rsi") args[1],
in("rdx") args[2],
in("r10") args[3],
in("r8") args[4],
in("r9") args[5],
out("rcx") _,
out("r11") _,
lateout("rax") ret0,
lateout("rdx") ret1,
);
}
(ret0, ret1)
}
用户态使用内联汇编来实现系统调用,将rax、rdi、rsi、rdx等寄存器作为参数,rax存放系统调用号,最终返回值存放在rax和rdx中。用户态使用不同系统调用的方法如下:
fn sys_proc_exit(exit_code: usize) -> (usize, usize) {
syscall(SyscallNum::ProcExit, [exit_code, 0, 0, 0, 0, 0])
}
fn sys_proc_wait(pid: usize) -> (usize, usize) {
syscall(SyscallNum::ProcWait, [pid, 0, 0, 0, 0, 0])
}
...