summaryrefslogtreecommitdiff
path: root/Kernel/Arch/x86_64/SyscallEntry.cpp
blob: 45e7c339fdaed894db0041855192e9db75aade7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*
 * Copyright (c) 2021, Owen Smith <yeeetari@gmail.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <Kernel/API/Syscall.h>
#include <Kernel/Arch/TrapFrame.h>
#include <Kernel/Arch/x86_64/DescriptorTable.h>
#include <Kernel/Arch/x86_64/Processor.h>
#include <Kernel/Assertions.h>
#include <Kernel/Panic.h>
#include <Kernel/Tasks/Process.h>
#include <Kernel/Tasks/Scheduler.h>
#include <Kernel/Tasks/Thread.h>
#include <Kernel/Tasks/ThreadTracer.h>

using namespace Kernel;

extern "C" void syscall_entry();
extern "C" [[gnu::naked]] void syscall_entry()
{
    // clang-format off
    asm(
        // Store the user stack, then switch to the kernel stack.
        "    movq %%rsp, %%gs:%c[user_stack] \n"
        "    movq %%gs:%c[kernel_stack], %%rsp \n"

        // Build RegisterState.
        "    pushq $0x1b \n" // User ss
        "    pushq %%gs:%c[user_stack] \n" // User rsp
        "    sti \n" // It's now safe to enable interrupts, but we can't index into gs after this point
        "    pushq %%r11 \n" // The CPU preserves the user rflags in r11
        "    pushq $0x23 \n" // User cs
        "    pushq %%rcx \n" // The CPU preserves the user IP in rcx
        "    pushq $0 \n"
        "    pushq %%r15 \n"
        "    pushq %%r14 \n"
        "    pushq %%r13 \n"
        "    pushq %%r12 \n"
        "    pushq %%r11 \n"
        "    pushq %%r10 \n"
        "    pushq %%r9 \n"
        "    pushq %%r8 \n"
        "    pushq %%rax \n"
        "    pushq %%rcx \n"
        "    pushq %%rdx \n"
        "    pushq %%rbx \n"
        "    pushq %%rsp \n"
        "    pushq %%rbp \n"
        "    pushq %%rsi \n"
        "    pushq %%rdi \n"

        "    pushq %%rsp \n" // TrapFrame::regs
        "    subq $" __STRINGIFY(TRAP_FRAME_SIZE - 8) ", %%rsp \n"
        "    movq %%rsp, %%rdi \n"
        "    call enter_trap_no_irq \n"
        "    movq %%rsp, %%rdi \n"
        "    call syscall_handler \n"
        "    movq %%rsp, %%rdi \n"
        "    call exit_trap \n"
        "    addq $" __STRINGIFY(TRAP_FRAME_SIZE) ", %%rsp \n" // Pop TrapFrame

        "    popq %%rdi \n"
        "    popq %%rsi \n"
        "    popq %%rbp \n"
        "    addq $8, %%rsp \n" // Skip restoring kernel rsp
        "    popq %%rbx \n"
        "    popq %%rdx \n"
        "    popq %%rcx \n"
        "    popq %%rax \n"
        "    popq %%r8 \n"
        "    popq %%r9 \n"
        "    popq %%r10 \n"
        "    popq %%r11 \n"
        "    popq %%r12 \n"
        "    popq %%r13 \n"
        "    popq %%r14 \n"
        "    popq %%r15 \n"
        "    addq $8, %%rsp \n"
        "    popq %%rcx \n"
        "    addq $16, %%rsp \n"

        // Disable interrupts before we restore the user stack pointer. sysret will re-enable interrupts when it restores
        // rflags.
        "    cli \n"
        "    popq %%rsp \n"
        "    sysretq \n"
    :: [user_stack] "i"(Kernel::Processor::user_stack_offset()), [kernel_stack] "i"(Kernel::Processor::kernel_stack_offset()));
    // clang-format on
}