在内核中实现系统调用
上一节中描述的Hello World应用程序会发出两个系统调用请求,我们的 OS 当然也就需要实现这两个系统调用:
- 在屏幕上输出一个字符
- 结束运行,退出当前线程
改进中断服务例程
这些功能其实我们的内核都已经实现完毕,因此重点是将系统调用这条调用链建立起来。
1. // src/interrupt.rs
3. #[no_mangle]
4. pub fn rust_trap(tf: &mut TrapFrame) {
5. match tf.scause.cause() {
6. ...
7. Trap::Exception(Exception::UserEnvCall) => syscall(tf),
8. ...
9. }
10. }
首先是发现中断原因是在用户态执行 ecall 指令时,说明用户程序向我们请求服务,我们转入 syscall 函数。
1. // src/interrupt.rs
3. fn syscall(tf: &mut TrapFrame) {
4. // 返回后跳转到 ecall 下一条指令
5. tf.sepc += 4;
6. let ret = crate::syscall::syscall(
7. tf.x[17],
8. [tf.x[10], tf.x[11], tf.x[12]],
9. tf
10. );
11. tf.x[10] = ret as usize;
12. }
我们从中断帧中取出中断之前的寄存器

的值,分别表示 syscall id 以及传入的参数。这是通过用户态的内联汇编 ecall 传给我们的。
添加 syscall 处理
我们将系统调用单开一个模块来实现:
1. // src/syscall.rs
3. use crate::context::TrapFrame;
4. use crate::process;
6. pub const SYS_WRITE: usize = 64;
7. pub const SYS_EXIT: usize = 93;
9. pub fn syscall(id: usize, args: [usize; 3], tf: &mut TrapFrame) -> isize {
10. match id {
11. SYS_WRITE => {
12. print!("{}", args[0] as u8 as char);
13. 0
14. },
15. SYS_EXIT => {
16. sys_exit(args[0]);
17. 0
18. },
19. _ => {
20. panic!("unknown syscall id {}", id);
21. },
22. }
23. }
25. fn sys_exit(code: usize) {
26. process::exit(code);
27. }
不必花太多功夫,我们就在内核中支持了两个系统调用!
