diff --git a/init/init.c b/init/init.c index 59c9519..ac1298a 100644 --- a/init/init.c +++ b/init/init.c @@ -1,8 +1,10 @@ +#include +#include int main(int argc, char **argv) { (void) argc; (void) argv; - int i=0; - for(;;)i++; + asm("syscall" :: "a" (0x3FF), "D" ("Hello, world!\n")); + for(;;); return 0; } diff --git a/kernel/boot/kmain.c b/kernel/boot/kmain.c index d3e3ea4..11c4aec 100644 --- a/kernel/boot/kmain.c +++ b/kernel/boot/kmain.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include int kmain(uint64_t multiboot_magic, void *multiboot_data) { @@ -24,6 +26,8 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data) cpu_init(); pit_init(); + debug_info("Syscall enabled:%d\n", CPUID_FEATURE_SYSCALL); + process_t *p1 = process_spawn(0); thread_t *th = exec_elf(p1, mboot_data.init); scheduler_insert(th); diff --git a/kernel/cpu/cpu.c b/kernel/cpu/cpu.c index ea451e8..590275e 100644 --- a/kernel/cpu/cpu.c +++ b/kernel/cpu/cpu.c @@ -7,6 +7,7 @@ #include #include #include +#include cpu_t cpus[MAX_NUMCPU]; unsigned int num_cpu = 0; @@ -38,6 +39,7 @@ void init_cpu() gdt_init(); sse_init(); scheduler_init(); + syscall_init(); } void cpu_init() diff --git a/kernel/include/cpu.h b/kernel/include/cpu.h index ad68aca..11906f0 100644 --- a/kernel/include/cpu.h +++ b/kernel/include/cpu.h @@ -14,6 +14,7 @@ #define GS_OFFSET_CPU 0 #define GS_OFFSET_STATE 40 #define GS_OFFSET_STACK 48 +#define GS_OFFSET_SCTEMP 56 #ifndef __ASSEMBLER__ #include @@ -31,6 +32,7 @@ typedef struct cpu_t uint64_t is_bsp; uint64_t current_state; // 40 void *kernel_stack; // 48 + uint64_t syscall_temp; // 56 thread_t *current_thread; thread_t *last_thread; process_t *current_process; diff --git a/kernel/include/int.h b/kernel/include/int.h index 36c65a0..277b384 100644 --- a/kernel/include/int.h +++ b/kernel/include/int.h @@ -66,6 +66,7 @@ #define INT_APIC_ERROR 0x45 #define INT_APIC_SPUR 0xFF +#define INT_SYSCALL 0x80 #define RFLAGS_IOPL (3<<12) #define RFLAGS_IOPL1 (1<<12) diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h new file mode 100644 index 0000000..2d7f49b --- /dev/null +++ b/kernel/include/syscall.h @@ -0,0 +1,41 @@ +#pragma once + +void syscall_init(); + +typedef long (*syscall_handler_t)(long num, long, long, long, long, long, long); + +#define SYSCALL_DECL(name) \ + long syscall_##name(long, long, long, long, long, long, long) + +#define SYSCALL_DEF(name) \ + long syscall_##name(long num, long _a1, long _a2, long _a3, long _a4, long _a5, long _a6) + +#define _SYSCALL_INIT6(t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6) \ + (void)num; \ + t1 n1 = (t1)_a1; \ + (void)n1; \ + t2 n2 = (t2)_a2; \ + (void)n2; \ + t3 n3 = (t3)_a3; \ + (void)n3; \ + t4 n4 = (t4)_a4; \ + (void)n4; \ + t5 n5 = (t5)_a5; \ + (void)n5; \ + t6 n6 = (t6)_a6; \ + (void)n6; +#define _SYSCALL_INIT5(t1,n1,t2,n2,t3,n3,t4,n4,t5,n5) _SYSCALL_INIT6(t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,long,__a6) +#define _SYSCALL_INIT4(t1,n1,t2,n2,t3,n3,t4,n4) _SYSCALL_INIT6(t1,n1,t2,n2,t3,n3,t4,n4,long,__a5,long,__a6) +#define _SYSCALL_INIT3(t1,n1,t2,n2,t3,n3) _SYSCALL_INIT6(t1,n1,t2,n2,t3,n3,long,__a4,long,__a5,long,__a6) +#define _SYSCALL_INIT2(t1,n1,t2,n2) _SYSCALL_INIT6(t1,n1,t2,n2,long,__a3,long,__a4,long,__a5,long,__a6) +#define _SYSCALL_INIT1(t1,n1) _SYSCALL_INIT6(t1,n1,long,__a2,long,__a3,long,__a4,long,__a5,long,__a6) +#define _SYSCALL_INIT0() _SYSCALL_INIT6(long,__a1,long,__a2,long,__a3,long,__a4,long,__a5,long,__a6) + +#define __SYSCALL_NARGS(a0,b0,a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,n,...) n +#define _SYSCALL_NARGS(...) __SYSCALL_NARGS(__VA_ARGS__,6,6,5,5,4,4,3,3,2,2,1,1,0,0) +#define __SYSCALL_CONCAT(a,b) a##b +#define _SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT(a,b) +#define _SYSCALL_INIT(a,...) _SYSCALL_CONCAT(a, _SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) +#define SYSCALL_INIT(...) _SYSCALL_INIT(_SYSCALL_INIT,__VA_ARGS__) + +#define SYSCALL_REGISTER(name, num) syscall_handlers[num] = syscall_##name diff --git a/kernel/interrupts/isr_common.S b/kernel/interrupts/isr_common.S index 6817713..2a4d872 100644 --- a/kernel/interrupts/isr_common.S +++ b/kernel/interrupts/isr_common.S @@ -64,6 +64,15 @@ isr_return: pop r13 pop r14 pop r15 + + // Jump to syscall_return if we're in a syscall + push rax + mov rax, [rsp + 8] + cmp rax, INT_SYSCALL + .extern syscall_return + jz syscall_return + pop rax + // Pop error code and fault number add rsp, 16 iretq diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c new file mode 100644 index 0000000..904f00a --- /dev/null +++ b/kernel/syscall/syscall.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include + +extern void syscall_entry(); + +syscall_handler_t syscall_handlers[1024]; + +SYSCALL_DECL(debug); + +registers_t *syscall_handler(registers_t *r) +{ + // Syscall number: RAX + // Order of arguments: + // RDI + // RSI + // RDX + // R10 + // R8 + // R9 + // stack + // + // Return value: + // RAX + + if(syscall_handlers[r->rax]) + { + r->rax = syscall_handlers[r->rax](r->rax, r->rdi, r->rsi, r->rdx, r->r10, r->r8, r->r9); + return r; + } + + debug_error("Unknown syscall, No:%d\n", r->rax); + debug("syscall_%d(%x, %x, %x, %x, %x, %x)\n", r->rax, r->rdi, r->rsi, r->rdx, r->r10, r->r8, r->r9); + for(;;); +} + +int syscall_installed = 0; + +void syscall_init() +{ + msr_write(MSR_REG_STAR, (((uint64_t)SEG_KDATA | 0x3)<<48 | ((uint64_t)SEG_KCODE)<<32)); + msr_write(MSR_REG_LSTAR, (uint64_t)syscall_entry); + msr_write(MSR_REG_EFER, msr_read(MSR_REG_EFER)| 1); + msr_write(MSR_REG_FMASK, RFLAGS_IF); + + if(!syscall_installed) + { + register_int_handler(INT_SYSCALL, syscall_handler); + syscall_installed = 1; + memset(syscall_handlers, 0, 1024*sizeof(syscall_handler_t)); + + SYSCALL_REGISTER(debug, 0x3FF); + } + +} + +SYSCALL_DEF(debug) +{ + SYSCALL_INIT(char*, message); + debug_puts(message); + return 0; +} diff --git a/kernel/syscall/syscall_entry.S b/kernel/syscall/syscall_entry.S new file mode 100644 index 0000000..9db8f52 --- /dev/null +++ b/kernel/syscall/syscall_entry.S @@ -0,0 +1,38 @@ +#include +#include +#include +#include +.intel_syntax noprefix + + +.global syscall_entry +.global syscall_return +.extern syscall_handler + +syscall_entry: + + swapgs + mov [gs:GS_OFFSET_SCTEMP], rsp + mov rsp, [gs:GS_OFFSET_STACK] + + // Prepare a fake interrupt stack + pushq SEG_UDATA // SS + push [gs:GS_OFFSET_SCTEMP] // RSP + push r11 // RFLAGS + pushq SEG_UCODE // CS + push rcx // RIP + pushq 0 // Error code + pushq INT_SYSCALL // Interrupt id + swapgs + + jmp isr_common +syscall_return: + + pop rax + add rsp, 16 + pop rcx + add rsp, 8 + pop r11 + pop rsp + + sysretq