good_os_framework/user/
syscall.rs

1use core::arch::asm;
2use spin::Mutex;
3use x86_64::registers::model_specific::{Efer, EferFlags};
4use x86_64::registers::model_specific::{LStar, SFMask, Star};
5use x86_64::registers::rflags::RFlags;
6use x86_64::VirtAddr;
7
8use crate::arch::gdt::Selectors;
9
10pub fn init() {
11    let handler_addr = syscall_handler as *const () as u64;
12
13    SFMask::write(RFlags::INTERRUPT_FLAG);
14    LStar::write(VirtAddr::new(handler_addr as u64));
15
16    let (code_selector, data_selector) = Selectors::get_kernel_segments();
17    let (user_code_selector, user_data_selector) = Selectors::get_user_segments();
18
19    Star::write(
20        user_code_selector,
21        user_data_selector,
22        code_selector,
23        data_selector,
24    )
25    .unwrap();
26
27    unsafe {
28        Efer::write(Efer::read() | EferFlags::SYSTEM_CALL_EXTENSIONS);
29    }
30}
31
32#[naked]
33extern "C" fn syscall_handler() {
34    unsafe {
35        asm!(
36            "push rcx",
37            "push r11",
38            "push rbp",
39            "push rbx",
40            "push r12",
41            "push r13",
42            "push r14",
43            "push r15",
44
45            // Move the 4th argument in r10 to rcx to fit the C ABI
46            "mov rcx, r10",
47            "call {syscall_handle_fn}",
48
49            "pop r15",
50            "pop r14",
51            "pop r13",
52            "pop r12",
53            "pop rbx",
54            "pop rbp",
55            "pop r11",
56            "pop rcx",
57            "sysretq",
58            syscall_handle_fn = sym syscall_handle_fn,
59            options(noreturn)
60        );
61    }
62}
63
64#[allow(unused_variables)]
65pub extern "C" fn syscall_handle_fn(
66    arg1: usize,
67    arg2: usize,
68    arg3: usize,
69    arg4: usize,
70    arg5: usize,
71    arg6: usize,
72) -> usize {
73    let syscall_number_raw: usize;
74    unsafe { asm!("mov {0}, rax", out(reg) syscall_number_raw) };
75
76    SYSCALL_HANDLER.lock()(syscall_number_raw, arg1, arg2, arg3, arg4, arg5, arg6)
77}
78
79fn tmp_syscall_handler(
80    _idx: usize,
81    _arg1: usize,
82    _arg2: usize,
83    _arg3: usize,
84    _arg4: usize,
85    _arg5: usize,
86    _arg6: usize,
87) -> usize {
88    0
89}
90
91/// The syscall handler type
92pub type SyscallHandlerFn = fn(
93    idx: usize,
94    arg1: usize,
95    arg2: usize,
96    arg3: usize,
97    arg4: usize,
98    arg5: usize,
99    arg6: usize,
100) -> usize;
101
102static SYSCALL_HANDLER: Mutex<SyscallHandlerFn> = Mutex::new(tmp_syscall_handler);
103
104/// Sets the syscall handler.
105pub fn regist_syscall_handler(handler: SyscallHandlerFn) {
106    *SYSCALL_HANDLER.lock() = handler;
107}