PatchworkOS  da8a090
A non-POSIX operating system.
Loading...
Searching...
No Matches
syscall.h
Go to the documentation of this file.
1#pragma once
2
5#include <kernel/mem/space.h>
6
7/**
8 * @brief System Call Interface.
9 * @defgroup kernel_cpu_syscall Syscall
10 * @ingroup kernel_cpu
11 *
12 * System calls provide a controlled interface for user-space applications to request services from the kernel, such as
13 * file operations, process management, and inter-process communication.
14 *
15 * ## SYSCALL Instruction
16 *
17 * Historically, system calls were invoked using software interrupts (usually `int 0x80`), which are relatively slow due
18 * to overhead from interrupt handling.
19 *
20 * Instead, we use the modern `SYSCALL` instruction, which allows for a faster transition from user mode to kernel mode,
21 * but it is a little more complex to set up.
22 *
23 * ## Stack switching
24 *
25 * When a syscall is invoked, the CPU will not automatically switch stacks. We need to manually switch them. To do this,
26 * we use the `MSR_KERNEL_GS_BASE` MSR to store a pointer to the `syscall_ctx_t` structure for the current thread.
27 *
28 * When `swapgs` is called, the `GS` segment register will be swapped with the value in `MSR_KERNEL_GS_BASE`, allowing
29 * us to access the syscall context for the current thread.
30 *
31 * We now cache the user stack pointer in the syscall context, and load the `syscallRsp` stack pointer. We then
32 * immediately push the user stack pointer onto the new stack and call `swapgs` again to restore the original `GS`
33 * value. Finally, we can enable interrupts and call the main C syscall handler.
34 *
35 * @note Swapping the `GS` register back before enabling interrupts is important, as it ensures user space can modify
36 * its own `GS` base without affecting the kernel and that preemptions do not overwrite the `MSR_KERNEL_GS_BASE` MSR or
37 * the `GS` register.
38 *
39 * ## Calling Convention
40 *
41 * The syscall calling convention mostly follows the standard System V ABI for x86_64 architecture, with the exception
42 * of the argument registers, and the use of the `RAX` register for the syscall number.
43 *
44 * Arguments are passed to syscalls using the `RDI`, `RSI`, `RDX`, `R10`, `R8`, and `R9` registers, in that order. The
45 * syscall number is passed in the `RAX` register.
46 *
47 * After the registers are setup the `syscall` instruction should be called, with the return value is being placed in
48 * the `RAX` register.
49 *
50 * If the return value is `ERR` for a system call that returns an integer or `NULL` for a system call that returns a
51 * pointer. Then the `SYS_ERRNO` syscall can be used to retrieve the associated error code.
52 *
53 * @see [SYSCALL instruction](https://www.felixcloutier.com/x86/syscall)
54 * @see [SYSRET instruction](https://www.felixcloutier.com/x86/sysret)
55 *
56 * @{
57 */
58
59/**
60 * @brief System Call Numbers.
61 * @enum syscall_number_t
62 */
101
102/**
103 * @brief Per thread syscall context.
104 * @struct syscall_ctx_t
105 */
106typedef struct
107{
108 uintptr_t syscallRsp; ///< The stack pointer to use when handling syscalls.
109 uintptr_t userRsp; ///< Used to avoid clobbering registers when switching stacks.
111
112/**
113 * @brief A syscall descriptor.
114 * @struct syscall_descriptor_t
115 *
116 * Describes a single syscall, its number and the function pointer to the handler.
117 */
123
124/**
125 * @brief Linker defined start of the syscall table.
126 */
128
129/**
130 * @brief Linker defined end of the syscall table.
131 */
133
134/**
135 * @brief Macro to define a syscall.
136 *
137 * Uses the `.syscall_table` linker section to store the syscall descriptor.
138 *
139 * @param num The syscall number, must be unique, check `syscall_number_t`.
140 * @param returnType The return type of the syscall handler, must be `uint64_t` compatible.
141 * @param ... The arguments of the syscall handler, can be no more than 6 arguments (Such that we only use registers to
142 * pass them).
143 */
144#define SYSCALL_DEFINE(num, returnType, ...) \
145 returnType syscall_handler_##num(__VA_ARGS__); \
146 const syscall_descriptor_t __syscall_##num __attribute__((used, section(".syscall_table"))) = { \
147 .number = (num), \
148 .handler = (void*)syscall_handler_##num, \
149 }; \
150 returnType syscall_handler_##num(__VA_ARGS__)
151
152/**
153 * @brief Initialize a syscall context.
154 *
155 * @param ctx The syscall context to initialize.
156 * @param syscallStack The syscall stack of the thread.
157 */
158void syscall_ctx_init(syscall_ctx_t* ctx, const stack_pointer_t* syscallStack);
159
160/**
161 * @brief Load the syscall context into the `MSR_KERNEL_GS_BASE` MSR.
162 *
163 * @param ctx The syscall context to load.
164 */
166
167/**
168 * @brief Sort the syscall table and verify that all syscalls are present.
169 */
170void syscall_table_init(void);
171
172/**
173 * @brief Initialize syscalls on the current CPU.
174 *
175 * Will modify four MSRs:
176 * - `MSR_EFER`: Used to enable the `SYSCALL` instruction.
177 * - `MSR_STAR`: Used to set the code segments for kernel and user mode.
178 * - `MSR_LSTAR`: Used to set the entry point for the `SYSCALL` instruction.
179 * - `MSR_SYSCALL_FLAG_MASK`: Specifies which rflags to clear when entering kernel mode.
180 */
181void syscalls_cpu_init(void);
182
183/**
184 * @brief Main C syscall handler.
185 *
186 * This is called from the assembly `syscall_entry()` function.
187 *
188 * @param arg1 First argument.
189 * @param arg2 Second argument.
190 * @param arg3 Third argument.
191 * @param arg4 Fourth argument.
192 * @param arg5 Fifth argument.
193 * @param arg6 Sixth argument.
194 * @param number The syscall number (`syscall_number_t`).
195 * @return The return value of the syscall.
196 */
198 uint64_t number);
199
200/**
201 * @brief Assembly entry point for syscalls.
202 *
203 * The logic for saving/restoring registers and switching stacks is done here before calling `syscall_handler()`.
204 *
205 */
206extern void syscall_entry(void);
207
208/** @} */
syscall_descriptor_t _syscallTableEnd[]
Linker defined end of the syscall table.
void syscall_ctx_init(syscall_ctx_t *ctx, const stack_pointer_t *syscallStack)
Initialize a syscall context.
Definition syscall.c:16
void syscall_table_init(void)
Sort the syscall table and verify that all syscalls are present.
Definition syscall.c:33
syscall_number_t
System Call Numbers.
Definition syscall.h:64
syscall_descriptor_t _syscallTableStart[]
Linker defined start of the syscall table.
void syscalls_cpu_init(void)
Initialize syscalls on the current CPU.
Definition syscall.c:49
void syscall_ctx_load(syscall_ctx_t *ctx)
Load the syscall context into the MSR_KERNEL_GS_BASE MSR.
Definition syscall.c:21
void syscall_entry(void)
Assembly entry point for syscalls.
uint64_t syscall_handler(uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t number)
Main C syscall handler.
Definition syscall.c:70
@ SYS_SHARE
Definition syscall.h:95
@ SYS_TOTAL_AMOUNT
Definition syscall.h:99
@ SYS_PROCESS_EXIT
Definition syscall.h:65
@ SYS_MMAP
Definition syscall.h:84
@ SYS_STAT
Definition syscall.h:83
@ SYS_WRITE
Definition syscall.h:78
@ SYS_LINK
Definition syscall.h:94
@ SYS_NANOSLEEP
Definition syscall.h:68
@ SYS_YIELD
Definition syscall.h:89
@ SYS_GETTID
Definition syscall.h:71
@ SYS_THREAD_EXIT
Definition syscall.h:66
@ SYS_READ
Definition syscall.h:77
@ SYS_OPEN2
Definition syscall.h:75
@ SYS_CLOSE
Definition syscall.h:76
@ SYS_POLL
Definition syscall.h:82
@ SYS_ERRNO
Definition syscall.h:69
@ SYS_MUNMAP
Definition syscall.h:85
@ SYS_UNIX_EPOCH
Definition syscall.h:73
@ SYS_OPEN
Definition syscall.h:74
@ SYS_IOCTL
Definition syscall.h:80
@ SYS_OPENAT
Definition syscall.h:98
@ SYS_GETPID
Definition syscall.h:70
@ SYS_GETDENTS
Definition syscall.h:87
@ SYS_BIND
Definition syscall.h:97
@ SYS_THREAD_CREATE
Definition syscall.h:88
@ SYS_DUP
Definition syscall.h:90
@ SYS_CLAIM
Definition syscall.h:96
@ SYS_FUTEX
Definition syscall.h:92
@ SYS_DUP2
Definition syscall.h:91
@ SYS_SPAWN
Definition syscall.h:67
@ SYS_MPROTECT
Definition syscall.h:86
@ SYS_CHDIR
Definition syscall.h:81
@ SYS_REMOVE
Definition syscall.h:93
@ SYS_UPTIME
Definition syscall.h:72
@ SYS_SEEK
Definition syscall.h:79
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINTPTR_TYPE__ uintptr_t
Definition stdint.h:43
Structure to define a stack in memory.
Per thread syscall context.
Definition syscall.h:107
uintptr_t userRsp
Used to avoid clobbering registers when switching stacks.
Definition syscall.h:109
uintptr_t syscallRsp
The stack pointer to use when handling syscalls.
Definition syscall.h:108
A syscall descriptor.
Definition syscall.h:119