PatchworkOS  da8a090
A non-POSIX operating system.
Loading...
Searching...
No Matches
Syscall

System Call Interface. More...

Collaboration diagram for Syscall:

Detailed Description

System Call Interface.

System calls provide a controlled interface for user-space applications to request services from the kernel, such as file operations, process management, and inter-process communication.

SYSCALL Instruction

Historically, system calls were invoked using software interrupts (usually int 0x80), which are relatively slow due to overhead from interrupt handling.

Instead, we use the modern SYSCALL instruction, which allows for a faster transition from user mode to kernel mode, but it is a little more complex to set up.

Stack switching

When a syscall is invoked, the CPU will not automatically switch stacks. We need to manually switch them. To do this, we use the MSR_KERNEL_GS_BASE MSR to store a pointer to the syscall_ctx_t structure for the current thread.

When swapgs is called, the GS segment register will be swapped with the value in MSR_KERNEL_GS_BASE, allowing us to access the syscall context for the current thread.

We now cache the user stack pointer in the syscall context, and load the syscallRsp stack pointer. We then immediately push the user stack pointer onto the new stack and call swapgs again to restore the original GS value. Finally, we can enable interrupts and call the main C syscall handler.

Note
Swapping the GS register back before enabling interrupts is important, as it ensures user space can modify its own GS base without affecting the kernel and that preemptions do not overwrite the MSR_KERNEL_GS_BASE MSR or the GS register.

Calling Convention

The syscall calling convention mostly follows the standard System V ABI for x86_64 architecture, with the exception of the argument registers, and the use of the RAX register for the syscall number.

Arguments are passed to syscalls using the RDI, RSI, RDX, R10, R8, and R9 registers, in that order. The syscall number is passed in the RAX register.

After the registers are setup the syscall instruction should be called, with the return value is being placed in the RAX register.

If the return value is ERR for a system call that returns an integer or NULL for a system call that returns a pointer. Then the SYS_ERRNO syscall can be used to retrieve the associated error code.

See also
SYSCALL instruction
SYSRET instruction

Data Structures

struct  syscall_ctx_t
 Per thread syscall context. More...
 
struct  syscall_descriptor_t
 A syscall descriptor. More...
 

Macros

#define SYSCALL_DEFINE(num, returnType, ...)
 Macro to define a syscall.
 

Enumerations

enum  syscall_number_t {
  SYS_PROCESS_EXIT = 0 , SYS_THREAD_EXIT = 1 , SYS_SPAWN = 2 , SYS_NANOSLEEP = 3 ,
  SYS_ERRNO = 4 , SYS_GETPID = 5 , SYS_GETTID = 6 , SYS_UPTIME = 7 ,
  SYS_UNIX_EPOCH = 8 , SYS_OPEN = 9 , SYS_OPEN2 = 10 , SYS_CLOSE = 11 ,
  SYS_READ = 12 , SYS_WRITE = 13 , SYS_SEEK = 14 , SYS_IOCTL = 15 ,
  SYS_CHDIR = 16 , SYS_POLL = 17 , SYS_STAT = 18 , SYS_MMAP = 19 ,
  SYS_MUNMAP = 20 , SYS_MPROTECT = 21 , SYS_GETDENTS = 22 , SYS_THREAD_CREATE = 23 ,
  SYS_YIELD = 24 , SYS_DUP = 25 , SYS_DUP2 = 26 , SYS_FUTEX = 27 ,
  SYS_REMOVE = 28 , SYS_LINK = 29 , SYS_SHARE = 30 , SYS_CLAIM = 31 ,
  SYS_BIND = 32 , SYS_OPENAT = 33 , SYS_TOTAL_AMOUNT = 34
}
 System Call Numbers. More...
 

Functions

void syscall_ctx_init (syscall_ctx_t *ctx, const stack_pointer_t *syscallStack)
 Initialize a syscall context.
 
void syscall_ctx_load (syscall_ctx_t *ctx)
 Load the syscall context into the MSR_KERNEL_GS_BASE MSR.
 
void syscall_table_init (void)
 Sort the syscall table and verify that all syscalls are present.
 
void syscalls_cpu_init (void)
 Initialize syscalls on the current CPU.
 
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.
 
void syscall_entry (void)
 Assembly entry point for syscalls.
 

Variables

syscall_descriptor_t _syscallTableStart []
 Linker defined start of the syscall table.
 
syscall_descriptor_t _syscallTableEnd []
 Linker defined end of the syscall table.
 

Macro Definition Documentation

◆ SYSCALL_DEFINE

#define SYSCALL_DEFINE (   num,
  returnType,
  ... 
)
Value:
returnType syscall_handler_##num(__VA_ARGS__); \
const syscall_descriptor_t __syscall_##num __attribute__((used, section(".syscall_table"))) = { \
.number = (num), \
.handler = (void*)syscall_handler_##num, \
}; \
returnType syscall_handler_##num(__VA_ARGS__)
A syscall descriptor.
Definition syscall.h:119

Macro to define a syscall.

Uses the .syscall_table linker section to store the syscall descriptor.

Parameters
numThe syscall number, must be unique, check syscall_number_t.
returnTypeThe return type of the syscall handler, must be uint64_t compatible.
...The arguments of the syscall handler, can be no more than 6 arguments (Such that we only use registers to pass them).

Definition at line 144 of file syscall.h.

Enumeration Type Documentation

◆ syscall_number_t

System Call Numbers.

Enumerator
SYS_PROCESS_EXIT 
SYS_THREAD_EXIT 
SYS_SPAWN 
SYS_NANOSLEEP 
SYS_ERRNO 
SYS_GETPID 
SYS_GETTID 
SYS_UPTIME 
SYS_UNIX_EPOCH 
SYS_OPEN 
SYS_OPEN2 
SYS_CLOSE 
SYS_READ 
SYS_WRITE 
SYS_SEEK 
SYS_IOCTL 
SYS_CHDIR 
SYS_POLL 
SYS_STAT 
SYS_MMAP 
SYS_MUNMAP 
SYS_MPROTECT 
SYS_GETDENTS 
SYS_THREAD_CREATE 
SYS_YIELD 
SYS_DUP 
SYS_DUP2 
SYS_FUTEX 
SYS_REMOVE 
SYS_LINK 
SYS_SHARE 
SYS_CLAIM 
SYS_BIND 
SYS_OPENAT 
SYS_TOTAL_AMOUNT 

Definition at line 63 of file syscall.h.

Function Documentation

◆ syscall_ctx_init()

void syscall_ctx_init ( syscall_ctx_t ctx,
const stack_pointer_t syscallStack 
)

Initialize a syscall context.

Parameters
ctxThe syscall context to initialize.
syscallStackThe syscall stack of the thread.

Definition at line 16 of file syscall.c.

Here is the caller graph for this function:

◆ syscall_ctx_load()

void syscall_ctx_load ( syscall_ctx_t ctx)

Load the syscall context into the MSR_KERNEL_GS_BASE MSR.

Parameters
ctxThe syscall context to load.

Definition at line 21 of file syscall.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ syscall_table_init()

void syscall_table_init ( void  )

Sort the syscall table and verify that all syscalls are present.

Definition at line 33 of file syscall.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ syscalls_cpu_init()

void syscalls_cpu_init ( void  )

Initialize syscalls on the current CPU.

Will modify four MSRs:

  • MSR_EFER: Used to enable the SYSCALL instruction.
  • MSR_STAR: Used to set the code segments for kernel and user mode.
  • MSR_LSTAR: Used to set the entry point for the SYSCALL instruction.
  • MSR_SYSCALL_FLAG_MASK: Specifies which rflags to clear when entering kernel mode.

Definition at line 49 of file syscall.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ syscall_handler()

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.

This is called from the assembly syscall_entry() function.

Parameters
arg1First argument.
arg2Second argument.
arg3Third argument.
arg4Fourth argument.
arg5Fifth argument.
arg6Sixth argument.
numberThe syscall number (syscall_number_t).
Returns
The return value of the syscall.

Definition at line 70 of file syscall.c.

Here is the call graph for this function:

◆ syscall_entry()

void syscall_entry ( void  )
extern

Assembly entry point for syscalls.

The logic for saving/restoring registers and switching stacks is done here before calling syscall_handler().

Here is the caller graph for this function:

Variable Documentation

◆ _syscallTableStart

syscall_descriptor_t _syscallTableStart[]
extern

Linker defined start of the syscall table.

◆ _syscallTableEnd

syscall_descriptor_t _syscallTableEnd[]
extern

Linker defined end of the syscall table.