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