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}