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}