跳转到内容

添加系统调用

本指南介绍如何为 OpenOS 添加新的系统调用。

kernel/src/syscall/mod.rs
/// 系统调用号
#[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,
}
kernel/src/syscall/mod.rs
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
}
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)
}
kernel/src/syscall/mod.rs
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",
];
; user/syscall.asm
section .text
; my_new_syscall(arg1, arg2, arg3)
global openos_my_new_syscall
openos_my_new_syscall:
mov rax, 8 ; 系统调用号
syscall
ret
sdk/include/openos/syscall.h
#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
寄存器用途
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(())
}
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
}