添加系统调用
本指南介绍如何为 OpenOS 添加新的系统调用。
添加系统调用步骤
Section titled “添加系统调用步骤”1. 定义系统调用号
Section titled “1. 定义系统调用号”/// 系统调用号#[derive(Debug, Clone, Copy, PartialEq, Eq)]#[repr(u64)]pub enum SyscallNumber { // 现有系统调用 Write = 1, Read = 2, Exit = 3, Yield = 4, PortCreate = 5, Send = 6, Receive = 7,
// 新系统调用 MyNewSyscall = 8,}2. 实现处理函数
Section titled “2. 实现处理函数”pub fn handle_syscall( number: u64, arg1: u64, arg2: u64, arg3: u64,) -> i64 { match number { 1 => sys_write(arg1, arg2), 2 => sys_read(arg1, arg2), 3 => sys_exit(arg1), 4 => sys_yield(), 5 => sys_port_create(), 6 => sys_send(arg1, arg2, arg3), 7 => sys_receive(arg1, arg2, arg3),
// 新系统调用 8 => sys_my_new_syscall(arg1, arg2, arg3),
_ => -1, // ENOSYS }}
fn sys_my_new_syscall(arg1: u64, arg2: u64, arg3: u64) -> i64 { if arg1 == 0 { return -1; // EINVAL }
let result = do_something(arg1, arg2, arg3); result as i64}3. 验证用户态指针
Section titled “3. 验证用户态指针”fn validate_user_ptr(ptr: *const u8, len: usize) -> Result<(), Error> { if ptr as usize >= 0x800000000000 { return Err(Error::InvalidPointer); }
if len > MAX_BUFFER_SIZE { return Err(Error::BufferTooLarge); }
if ptr as usize % core::mem::align_of::<u8>() != 0 { return Err(Error::UnalignedPointer); }
Ok(())}
fn read_user_data(ptr: *const u8, len: usize) -> Result<&[u8], Error> { validate_user_ptr(ptr, len)?; let data = unsafe { core::slice::from_raw_parts(ptr, len) }; Ok(data)}4. 更新系统调用表
Section titled “4. 更新系统调用表”pub const SYSCALL_COUNT: usize = 9;
pub const SYSCALL_NAMES: [&str; SYSCALL_COUNT] = [ "reserved", "write", "read", "exit", "yield", "port_create", "send", "receive", "my_new_syscall",];5. 添加用户态包装器
Section titled “5. 添加用户态包装器”; user/syscall.asm
section .text
; my_new_syscall(arg1, arg2, arg3)global openos_my_new_syscallopenos_my_new_syscall: mov rax, 8 ; 系统调用号 syscall ret6. 添加 C 头文件
Section titled “6. 添加 C 头文件”#ifndef OPENOS_SYSCALL_H#define OPENOS_SYSCALL_H
#include <stdint.h>
#define SYS_WRITE 1#define SYS_READ 2#define SYS_EXIT 3#define SYS_YIELD 4#define SYS_PORT_CREATE 5#define SYS_SEND 6#define SYS_RECEIVE 7#define SYS_MY_NEW_SYSCALL 8
static inline int64_t syscall3(int64_t num, int64_t arg1, int64_t arg2, int64_t arg3) { int64_t ret; asm volatile ("syscall" : "=a"(ret) : "a"(num), "D"(arg1), "S"(arg2), "d"(arg3) : "rcx", "r11", "memory"); return ret;}
static inline int64_t sys_my_new_syscall(uint64_t arg1, uint64_t arg2, uint64_t arg3) { return syscall3(SYS_MY_NEW_SYSCALL, arg1, arg2, arg3);}
#endif系统调用约定
Section titled “系统调用约定”| 寄存器 | 用途 |
|---|---|
| RAX | 系统调用号 |
| RDI | 参数 1 |
| RSI | 参数 2 |
| RDX | 参数 3 |
| R10 | 参数 4(保留) |
- 成功:返回正值
- 错误:返回负值(高位为 1)
pub const EINVAL: i64 = -1; // 无效参数pub const ENOENT: i64 = -2; // 未找到pub const EPERM: i64 = -3; // 权限不足pub const ENOMEM: i64 = -4; // 内存不足pub const EBUSY: i64 = -5; // 资源忙pub const EPIPE: i64 = -6; // 管道已关闭pub const EAGAIN: i64 = -7; // 会阻塞pub const ETIME: i64 = -8; // 超时pub const EFAULT: i64 = -9; // 错误指针pub const ENOSYS: i64 = -10; // 未知系统调用fn validate_syscall_args( number: u64, arg1: u64, arg2: u64, arg3: u64,) -> Result<(), Error> { if number >= SYSCALL_COUNT as u64 { return Err(Error::InvalidSyscall); }
if needs_pointer_validation(number, 1) { validate_user_ptr(arg1 as *const u8, arg2 as usize)?; }
Ok(())}调试系统调用
Section titled “调试系统调用”pub fn handle_syscall(number: u64, arg1: u64, arg2: u64, arg3: u64) -> i64 { serial_println!( "[SYSCALL] {}({:#x}, {:#x}, {:#x})", SYSCALL_NAMES.get(number as usize).unwrap_or(&"unknown"), arg1, arg2, arg3 );
let result = match number { // ... };
serial_println!("[SYSCALL] → {}", result);
result}