Skip to content

Commit 84b82e2

Browse files
committed
Kernel: Support syscall instruction
1 parent 7bca596 commit 84b82e2

File tree

10 files changed

+152
-17
lines changed

10 files changed

+152
-17
lines changed

Kernel/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ endif()
1717

1818
include_directories(include)
1919
include_directories($ENV{LEMON_BUILDROOT}/Thirdparty/frigg/include)
20+
include_directories($ENV{LEMON_BUILDROOT}/Thirdparty/cxxshim/stage2/include)
2021

2122
if("${LEMON_ARCH}" STREQUAL "x86_64")
2223
include_directories(include/Arch/x86_64)
@@ -135,6 +136,7 @@ set(KERNEL_SRC_x86_64
135136
src/Arch/x86_64/Memcpy.asm
136137
src/Arch/x86_64/SignalTrampoline.asm
137138
src/Arch/x86_64/SMPTrampoline.asm
139+
src/Arch/x86_64/Syscall.asm
138140
src/Arch/x86_64/TSS.asm
139141
)
140142

Kernel/include/Arch/x86_64/CPU.h

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,34 @@ typedef struct {
1919
} __attribute__((packed)) idt_ptr_t;
2020

2121
struct CPU {
22-
CPU* self;
22+
CPU* self; // Pointer to this struct
2323
uint64_t id; // APIC/CPU id
24+
Thread* currentThread = nullptr; // Current executing thread
25+
// Scratch register, it is used by the syscall handler
26+
// as it cannot touch any registers without saving them
27+
uint64_t scratch;
28+
tss_t tss __attribute__((aligned(16)));
29+
2430
void* gdt; // GDT
2531
gdt_ptr_t gdtPtr;
2632
idt_ptr_t idtPtr;
27-
Thread* currentThread = nullptr;
33+
2834
Thread* idleThread = nullptr;
2935
Process* idleProcess;
3036
volatile int runQueueLock = 0;
3137
FastList<Thread*>* runQueue;
32-
tss_t tss __attribute__((aligned(16)));
33-
};
38+
} __attribute__((packed));
39+
40+
#define CPU_LOCAL_SELF 0x0
41+
#define CPU_LOCAL_ID 0x8
42+
#define CPU_LOCAL_THREAD 0x10
43+
#define CPU_LOCAL_SCRATCH 0x18
44+
#define CPU_LOCAL_TSS 0x20
45+
#define CPU_LOCAL_TSS_RSP0 (CPU_LOCAL_TSS + 0x4)
46+
47+
static_assert(offsetof(CPU, tss) == CPU_LOCAL_TSS);
48+
static_assert(offsetof(CPU, tss) + offsetof(tss_t, rsp0) == CPU_LOCAL_TSS_RSP0);
49+
static_assert(offsetof(CPU, currentThread) == CPU_LOCAL_THREAD);
3450

3551
enum {
3652
CPUID_ECX_SSE3 = 1 << 0,
@@ -185,13 +201,11 @@ static ALWAYS_INLINE Thread* GetCurrentThread() {
185201
Thread* ret;
186202
int intEnable = CheckInterrupts();
187203
asm("cli");
188-
asm volatile("swapgs; movq %%gs:48, %0; swapgs;"
204+
asm volatile("swapgs; movq %%gs:16, %0; swapgs;"
189205
: "=r"(ret)); // CPU info is 16-byte aligned as per liballoc alignment
190206
if (intEnable)
191207
asm("sti");
192208
return ret;
193-
194-
static_assert(offsetof(CPU, currentThread) == 48);
195209
}
196210

197211
static ALWAYS_INLINE void DisableInterrupts() {

Kernel/include/Arch/x86_64/Scheduler.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818

1919
#define KERNEL_CS 0x08
2020
#define KERNEL_SS 0x10
21-
#define USER_CS 0x1B
22-
#define USER_SS 0x23
21+
#define USER_SS 0x1B
22+
#define USER_CS 0x23
2323

2424
namespace Scheduler {
2525
class ProcessStateThreadBlocker;

Kernel/include/Arch/x86_64/Thread.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@ struct Thread {
6767
uint32_t ticksSinceBalance = 0; // Ticks since run queue rebalance
6868
uint32_t ticksGivenSinceBalance = 0;
6969
RegisterContext registers; // Registers
70-
RegisterContext lastSyscall; // Last system call
70+
struct {
71+
RegisterContext regs; // Last system call
72+
long result;
73+
} lastSyscall;
7174
void* fxState; // State of the extended registers
7275

7376
int cpu = -1; // CPU the thread is scheduled on

Kernel/src/Arch/x86_64/SMP.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ volatile bool doneInit = false;
3232
extern gdt_ptr_t GDT64Pointer64;
3333
extern idt_ptr_t idtPtr;
3434

35+
void syscall_init();
36+
3537
namespace SMP {
3638
CPU* cpus[256];
3739
unsigned processorCount = 1;
@@ -60,6 +62,8 @@ void SMPEntry(uint16_t id) {
6062

6163
doneInit = true;
6264

65+
syscall_init();
66+
6367
asm("sti");
6468

6569
for (;;)

Kernel/src/Arch/x86_64/SMPTrampoline.asm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ mov cr3, eax
2727
mov ecx, 0xC0000080 ; EFER Model Specific Register
2828
rdmsr ; Read from the MSR
2929
or eax, 1 << 8
30+
or eax, 1 ; syscall enable
3031
wrmsr
3132

3233
mov eax, cr0

Kernel/src/Arch/x86_64/Syscall.asm

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
global syscall_entry
2+
3+
extern SyscallHandler
4+
5+
section .text
6+
7+
USER_SS equ 0x1B
8+
USER_CS equ 0x23
9+
10+
CPU_LOCAL_SELF equ 0x0
11+
CPU_LOCAL_ID equ 0x8
12+
CPU_LOCAL_THREAD equ 0x10
13+
CPU_LOCAL_SCRATCH equ 0x18
14+
CPU_LOCAL_TSS equ 0x20
15+
CPU_LOCAL_TSS_RSP0 equ (CPU_LOCAL_TSS + 0x4)
16+
17+
syscall_entry:
18+
swapgs
19+
mov qword [gs:CPU_LOCAL_SCRATCH], rsp
20+
mov rsp, qword [gs:CPU_LOCAL_TSS_RSP0]
21+
push USER_SS
22+
push qword [gs:CPU_LOCAL_SCRATCH]
23+
swapgs
24+
push r11
25+
push USER_CS
26+
push rcx
27+
push 0
28+
29+
push rax
30+
push rbx
31+
push rcx
32+
push rdx
33+
push rsi
34+
push rdi
35+
push rbp
36+
push r8
37+
push r9
38+
push r10
39+
push r11
40+
push r12
41+
push r13
42+
push r14
43+
push r15
44+
45+
mov rdi, rsp
46+
xor rbp, rbp
47+
call SyscallHandler
48+
49+
pop r15
50+
pop r14
51+
pop r13
52+
pop r12
53+
pop r11
54+
pop r10
55+
pop r9
56+
pop r8
57+
pop rbp
58+
pop rdi
59+
pop rsi
60+
pop rdx
61+
pop rcx
62+
pop rbx
63+
pop rax
64+
65+
add rsp, 8
66+
; Get user RIP
67+
pop rcx
68+
add rsp, 8
69+
; User RFLAGS
70+
pop r11
71+
; Get user RSP
72+
pop rsp
73+
o64 sysret

Kernel/src/Arch/x86_64/Syscalls.cpp

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4036,16 +4036,44 @@ syscall_t syscalls[NUM_SYSCALLS]{
40364036
// clang-format on
40374037

40384038
void DumpLastSyscall(Thread* t) {
4039-
RegisterContext& lastSyscall = t->lastSyscall;
4039+
RegisterContext& lastSyscall = t->lastSyscall.regs;
40404040
Log::Info("Last syscall:\nCall: %d, arg0: %i (%x), arg1: %i (%x), arg2: %i (%x), arg3: %i (%x), arg4: %i (%x), "
4041-
"arg5: %i (%x)",
4041+
"arg5: %i (%x) result: %i (%x)",
40424042
lastSyscall.rax, SC_ARG0(&lastSyscall), SC_ARG0(&lastSyscall), SC_ARG1(&lastSyscall),
40434043
SC_ARG1(&lastSyscall), SC_ARG2(&lastSyscall), SC_ARG2(&lastSyscall), SC_ARG3(&lastSyscall),
40444044
SC_ARG3(&lastSyscall), SC_ARG4(&lastSyscall), SC_ARG4(&lastSyscall), SC_ARG5(&lastSyscall),
4045-
SC_ARG5(&lastSyscall));
4045+
SC_ARG5(&lastSyscall), t->lastSyscall.result, t->lastSyscall.result);
4046+
}
4047+
4048+
#define MSR_STAR 0xC000'0081
4049+
#define MSR_LSTAR 0xC000'0082
4050+
#define MSR_CSTAR 0xC000'0083
4051+
#define MSR_SFMASK 0xC000'0084
4052+
4053+
extern "C" void syscall_entry();
4054+
4055+
void syscall_init() {
4056+
uint64_t low = ((uint64_t)syscall_entry) & 0xFFFFFFFF;
4057+
uint64_t high = ((uint64_t)syscall_entry) >> 32;
4058+
asm volatile("wrmsr" ::"a"(low), "d"(high), "c"(MSR_LSTAR));
4059+
4060+
// User CS selector set to this field + 16, SS this field + 8
4061+
uint32_t sysretSelectors = USER_SS - 8;
4062+
// When syscall is called, CS set to field, SS this field + 8
4063+
uint32_t syscallSelectors = KERNEL_CS;
4064+
asm volatile("wrmsr" ::"a"(0), "d"((sysretSelectors << 16) | syscallSelectors), "c"(MSR_STAR));
4065+
// SFMASK masks flag values
4066+
// mask everything except reserved flags to disable IRQs when syscall is called
4067+
asm volatile("wrmsr" ::"a"(0x3F7FD5U), "d"(0), "c"(MSR_SFMASK));
4068+
4069+
asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(0xC0000080));
4070+
low |= 1; // SCE (syscall enable)
4071+
asm volatile("wrmsr" :: "a"(low), "d"(high), "c"(0xC0000080));
40464072
}
40474073

40484074
extern "C" void SyscallHandler(RegisterContext* regs) {
4075+
assert(!CheckInterrupts());
4076+
40494077
if (__builtin_expect(regs->rax >= NUM_SYSCALLS || !syscalls[regs->rax],
40504078
0)) { // If syscall is non-existant then return
40514079
regs->rax = -ENOSYS;
@@ -4069,15 +4097,21 @@ extern "C" void SyscallHandler(RegisterContext* regs) {
40694097

40704098
#ifdef KERNEL_DEBUG
40714099
if (debugLevelSyscalls >= DebugLevelNormal) {
4072-
thread->lastSyscall = *regs;
4100+
thread->lastSyscall.regs = *regs;
40734101
}
40744102
#endif
40754103

40764104
regs->rax = syscalls[regs->rax](regs); // Call syscall
40774105

4106+
#ifdef KERNEL_DEBUG
4107+
if (debugLevelSyscalls >= DebugLevelNormal) {
4108+
thread->lastSyscall.result = regs->rax;
4109+
}
4110+
#endif
4111+
40784112
IF_DEBUG((debugLevelSyscalls >= DebugLevelVerbose), {
40794113
if (regs->rax < 0)
4080-
Log::Info("Syscall %d exiting with value %d", thread->lastSyscall.rax, regs->rax);
4114+
Log::Info("Syscall %d exiting with value %d", thread->lastSyscall.regs.rax, regs->rax);
40814115
});
40824116

40834117
if (__builtin_expect(thread->pendingSignals & (~thread->EffectiveSignalMask()), 0)) {

Kernel/src/Kernel.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ void IdleProcess() {
4040
}
4141
}
4242

43+
void syscall_init();
44+
4345
void KernelProcess() {
4446
NVMe::Initialize();
4547
USB::XHCIController::Initialize();
@@ -225,6 +227,8 @@ extern "C" [[noreturn]] void kmain() {
225227

226228
Log::Info("OK");
227229

230+
syscall_init();
231+
228232
Log::Info("Initializing Task Scheduler...");
229233
Scheduler::Initialize();
230234
for (;;)

System/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ set(lemonwm_SRC
3636

3737
add_link_options(-llemon)
3838

39-
add_executable(lemond.lef ${lemond_SRC})
39+
add_executable(init.lef ${lemond_SRC})
4040
add_executable(netgov.lef ${netgov_SRC})
4141
add_executable(kmod.lef ${kmod_SRC})
4242

@@ -46,5 +46,5 @@ target_link_options(login.lef PUBLIC -llemongui)
4646
add_executable(lemonwm.lef ${lemonwm_SRC})
4747
target_link_options(lemonwm.lef PUBLIC -llemongui)
4848

49-
install(TARGETS lemond.lef netgov.lef login.lef kmod.lef lemonwm.lef
49+
install(TARGETS init.lef netgov.lef login.lef kmod.lef lemonwm.lef
5050
RUNTIME DESTINATION lemon)

0 commit comments

Comments
 (0)