Skip to main content

kernel/arch/x86_64/syscall/
entry.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! Syscall entry handler
3//!
4//! Authors: MarioS271
5
6use crate::arch::x86_64::cpu::gs_info::{GS_INFO_KERNEL_STACK_TOP, GS_INFO_USER_RSP};
7use crate::arch::x86_64::syscall::frame::UserFrame;
8use crate::mm::layout::USER_MAX;
9use crate::state::kstate::KSTATE;
10use crate::syscall::args::SyscallArgs;
11use crate::kdebug;
12use core::arch::naked_asm;
13
14/// Syscall entry point
15///
16/// # Safety
17/// This function must never be called from rust, it should only ever be reached via the `syscall`
18/// instruction. Additionally, it requires that [`GsInfo::init`] and [`GsInfo::set_kernel_stack_top`]
19/// have already been called on this CPU
20///
21/// [`GsInfo::init`]: crate::arch::x86_64::cpu::gs_info::GsInfo::init
22/// [`GsInfo::set_kernel_stack_top`]: crate::arch::x86_64::cpu::gs_info::GsInfo::set_kernel_stack_top
23#[unsafe(naked)]
24pub unsafe extern "C" fn syscall_entry() -> ! {
25    naked_asm!(
26        "swapgs",
27        "mov gs:[{user_rsp}], rsp",
28        "mov rsp, gs:[{kernel_stack_top}]",
29
30        "sub rsp, 8",           // _padding
31        "push 0",               // ss
32        "push 0",               // rsp (placeholder)
33        "push r11",             // user rflags
34        "mov r11, gs:[{user_rsp}]",
35        "mov [rsp + 8], r11",   // rsp
36        "push 0",               // cs
37        "push rcx",             // user rip
38        "push rax",             // orig_rax
39        "push rax",             // rax
40        "push rdi",             // rdi
41        "push rsi",             // rsi
42        "push rdx",             // rdx
43        "push r8",              // r8
44        "push r9",              // r9
45        "push r10",             // r10
46        "push rbx",             // rbx
47        "push rbp",             // rbp
48        "push r12",             // r12
49        "push r13",             // r13
50        "push r14",             // r14
51        "push r15",             // r15
52
53        "sti",
54        "mov rdi, rsp",
55        "call {dispatcher}",
56
57        "cli",
58        "pop r15",              // r15
59        "pop r14",              // r14
60        "pop r13",              // r13
61        "pop r12",              // r12
62        "pop rbp",              // rbp
63        "pop rbx",              // rbx
64        "pop r10",              // r10
65        "pop r9",               // r9
66        "pop r8",               // r8
67        "pop rdx",              // rdx
68        "pop rsi",              // rsi
69        "pop rdi",              // rdi
70        "pop rax",              // rax
71        "add rsp, 8",           // orig_rax
72        "pop rcx",              // rip
73        "add rsp, 8",           // cs
74        "mov r11, {user_max}",
75        "cmp rcx, r11",
76        "jae 1f",
77        "pop r11",              // rflags
78        "pop rsp",              // user rsp
79
80        "swapgs",
81        "sysretq",
82
83        "1:",
84        "sub rsp, 16",
85        "xor r11d, r11d",
86        "swapgs",
87        "iretq",
88
89        kernel_stack_top = const GS_INFO_KERNEL_STACK_TOP,
90        user_rsp = const GS_INFO_USER_RSP,
91        dispatcher = sym syscall_dispatch,
92        user_max = const USER_MAX
93    )
94}
95
96/// Dispatches incoming syscalls to the correct handler
97extern "C" fn syscall_dispatch(frame: &mut UserFrame) {
98    let syscall_frame = SyscallArgs {
99        syscall_num: frame.orig_rax,
100        arg1: frame.rdi,
101        arg2: frame.rsi,
102        arg3: frame.rdx,
103        arg4: frame.r10,
104        arg5: frame.r8,
105        arg6: frame.r9,
106    };
107
108    let res = crate::syscall::syscall::Syscall::dispatch(&syscall_frame);
109    match res {
110        Ok(val) => {
111            frame.rax = 0u64;
112            frame.rdx = val;
113        },
114        Err(err) => {
115            kdebug!("Syscall failed with an error code of {}", err as u64);
116
117            // TODO: send EXILL
118            frame.rax = err as u64;
119            frame.rdx = 0u64;
120        }
121    };
122
123    frame.cs = KSTATE.cpu.global_cpu_state().user_code_selector() as u64;
124    frame.ss = KSTATE.cpu.global_cpu_state().user_data_selector() as u64;
125}