PatchworkOS  c9fea19
A non-POSIX operating system.
Loading...
Searching...
No Matches
syscall.c
Go to the documentation of this file.
3
4#include <kernel/cpu/cpu.h>
5#include <kernel/cpu/gdt.h>
6#include <kernel/log/log.h>
7#include <kernel/mem/vmm.h>
10
11#include <kernel/defs.h>
12
13#include <assert.h>
14#include <errno.h>
15#include <stdlib.h>
16
17void syscall_ctx_init(syscall_ctx_t* ctx, const stack_pointer_t* syscallStack)
18{
19 ctx->syscallRsp = syscallStack->top;
20 ctx->userRsp = 0;
21 ctx->frame = NULL;
22 ctx->flags = SYSCALL_NORMAL;
23}
24
29
30static int syscall_descriptor_cmp(const void* a, const void* b)
31{
32 const syscall_descriptor_t* sysA = (const syscall_descriptor_t*)a;
33 const syscall_descriptor_t* sysB = (const syscall_descriptor_t*)b;
34 return sysA->number - sysB->number;
35}
36
38{
39 // Syscalls are not inserted into the table by the linker in the correct order so we sort them.
40 const uint64_t syscallsInTable =
42 assert(syscallsInTable == SYS_TOTAL_AMOUNT);
43
44 LOG_INFO("sorting syscall table, total system calls %d\n", SYS_TOTAL_AMOUNT);
46
47 for (uint64_t i = 0; i < syscallsInTable; i++)
48 {
49 assert(_syscallTableStart[i].number == i);
50 }
51}
52
63
65{
66 if (number > SYS_TOTAL_AMOUNT)
67 {
68 return NULL;
69 }
70
71 return &_syscallTableStart[number];
72}
73
75{
77 if (desc == NULL)
78 {
79 LOG_DEBUG("Unknown syscall %u\n", frame->rax);
80 errno = ENOSYS;
81 frame->rax = ERR;
82 return;
83 }
84
85 thread_t* thread = sched_thread();
87
88 thread->syscall.frame = frame;
90
91 // This is safe for any input type and any number of arguments up to 6 as they will simply be ignored.
92 frame->rax = desc->handler(frame->rdi, frame->rsi, frame->rdx, frame->r10, frame->r8, frame->r9);
93
95
97 asm volatile("cli" ::: "memory");
99 {
100 cpu_t* self = cpu_get_unsafe();
101 frame->vector = VECTOR_FAKE;
102 interrupt_fake(frame, self);
103 }
104}
#define assert(expression)
Definition assert.h:29
@ GDT_KERNEL_CODE
Kernel code segment selector.
Definition gdt.h:39
@ GDT_USER_CODE
User code segment selector.
Definition gdt.h:42
@ GDT_RING3
Definition gdt.h:26
_NORETURN void interrupt_fake(interrupt_frame_t *frame, cpu_t *self)
Enter a fake interrupt context as if an interrupt had occurred at the given frame.
@ VECTOR_FAKE
Used to implement interrupt_fake().
Definition interrupt.h:129
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:17
void syscall_table_init(void)
Sort the syscall table and verify that all syscalls are present.
Definition syscall.c:37
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:53
void syscall_handler(interrupt_frame_t *frame)
Main C syscall handler.
Definition syscall.c:74
void syscall_ctx_load(syscall_ctx_t *ctx)
Load the syscall context into the MSR_KERNEL_GS_BASE MSR.
Definition syscall.c:25
void syscall_entry(void)
Assembly entry point for syscalls.
@ SYS_TOTAL_AMOUNT
Definition syscall.h:101
@ SYSCALL_FORCE_FAKE_INTERRUPT
Definition syscall.h:116
@ SYSCALL_NORMAL
Definition syscall.h:110
static cpu_t * cpu_get_unsafe(void)
Gets the current CPU structure without disabling interrupts.
Definition cpu.h:299
void perf_syscall_end(void)
Called at the end of a syscall to update process performance data.
Definition perf.c:234
void perf_syscall_begin(void)
Called at the beginning of a syscall to update process performance data.
Definition perf.c:210
#define LOG_INFO(format,...)
Definition log.h:106
#define LOG_DEBUG(format,...)
Definition log.h:100
bool thread_is_note_pending(thread_t *thread)
Check if a thread has a note pending.
Definition thread.c:151
thread_t * sched_thread(void)
Retrieves the currently running thread.
Definition sched.c:612
#define ENOSYS
Function not implemented.
Definition errno.h:222
#define errno
Error number variable.
Definition errno.h:27
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
#define RFLAGS_INTERRUPT_ENABLE
Definition regs.h:32
#define RFLAGS_NESTED_TASK
Definition regs.h:36
static void msr_write(uint32_t msr, uint64_t value)
Definition regs.h:71
#define MSR_EFER
Definition regs.h:14
#define RFLAGS_DIRECTION
Definition regs.h:33
#define EFER_SYSCALL_ENABLE
Definition regs.h:21
static uint64_t msr_read(uint32_t msr)
Definition regs.h:63
#define RFLAGS_TRAP
Definition regs.h:31
#define MSR_STAR
Definition regs.h:15
#define RFLAGS_IOPL
Definition regs.h:35
#define MSR_SYSCALL_FLAG_MASK
Definition regs.h:17
#define MSR_LSTAR
Definition regs.h:16
#define MSR_KERNEL_GS_BASE
Definition regs.h:19
#define RFLAGS_AUX_CARRY
Definition regs.h:27
static uint64_t rflags_read()
Definition regs.h:78
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *))
Definition qsort.c:47
CPU structure.
Definition cpu.h:122
Trap Frame Structure.
Definition interrupt.h:146
Structure to define a stack in memory.
uintptr_t top
The top of the stack, this address is not inclusive.
Per thread syscall context.
Definition syscall.h:124
uintptr_t userRsp
Used to avoid clobbering registers when switching stacks.
Definition syscall.h:126
interrupt_frame_t * frame
If a fake interrupt is generated, this is the interrupt frame to return to.
Definition syscall.h:127
uintptr_t syscallRsp
The stack pointer to use when handling syscalls.
Definition syscall.h:125
syscall_flags_t flags
Flags for the current syscall.
Definition syscall.h:128
A syscall descriptor.
Definition syscall.h:138
uint64_t(* handler)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t)
Definition syscall.h:140
Thread of execution structure.
Definition thread.h:56
syscall_ctx_t syscall
Definition thread.h:74
const syscall_descriptor_t * syscall_get_descriptor(uint64_t number)
Definition syscall.c:64
static int syscall_descriptor_cmp(const void *a, const void *b)
Definition syscall.c:30