diff --git a/initrd/sbin/init b/initrd/sbin/init index b1e255e7..1d26fa01 100755 Binary files a/initrd/sbin/init and b/initrd/sbin/init differ diff --git a/src/arch/x86_64/Makefile b/src/arch/x86_64/Makefile index ab5fcb69..586e88d5 100644 --- a/src/arch/x86_64/Makefile +++ b/src/arch/x86_64/Makefile @@ -1,4 +1,4 @@ -objects := $(patsubst %.c,%.o,$(wildcard *.c)) israsm.o context.o +objects := $(patsubst %.c,%.o,$(wildcard *.c)) israsm.o context.o syscall.o subdirs=boot OBJPATH=$(OBJDIR)/arch/${TARGET}/ export @@ -19,3 +19,7 @@ context.o: context.asm nasm -f elf64 -o $@ $< mkdir -p $(OBJPATH) cp $@ $(OBJPATH)/$@ +syscall.o: syscall.asm + nasm -f elf64 -o $@ $< + mkdir -p $(OBJPATH) + cp $@ $(OBJPATH)/$@ diff --git a/src/arch/x86_64/context.asm b/src/arch/x86_64/context.asm index bdca70f0..67d3d45a 100644 --- a/src/arch/x86_64/context.asm +++ b/src/arch/x86_64/context.asm @@ -1,15 +1,21 @@ global arch_switchcontext arch_switchcontext: mov rsp,rdi - add rsp, 8 ; cr2 - pop rax - mov gs,rax - pop rax - mov fs,rax - pop rax + add rsp, 24 ; cr2 gs fs + + mov rbx,es + pop rax + cmp rax,rbx + jne .segswap + add rsp,8 ; ds + jmp .genreg + .segswap: + swapgs mov es,rax - pop rax + pop rax mov ds,rax + + .genreg: pop rax pop rbx pop rcx @@ -27,6 +33,4 @@ arch_switchcontext: pop rbp add rsp,8 ; remove error code - swapgs - iretq diff --git a/src/arch/x86_64/cpu.c b/src/arch/x86_64/cpu.c index aecb8171..5780ad61 100644 --- a/src/arch/x86_64/cpu.c +++ b/src/arch/x86_64/cpu.c @@ -8,6 +8,8 @@ // syscall, sse, etc // for the current cpu +extern void asm_syscall_entry(); + void cpu_state_init(){ // syscall @@ -28,7 +30,7 @@ void cpu_state_init(){ star |= (uint64_t)0x28 << 32; wrmsr(MSR_STAR, star); - wrmsr(MSR_LSTAR, 0xDEADBEEF); // FIXME add 64 bit handler here + wrmsr(MSR_LSTAR, asm_syscall_entry); wrmsr(MSR_CSTAR, 0); // no compat mode syscall handler wrmsr(MSR_FMASK, 0x200); // disable interrupts on syscall } diff --git a/src/arch/x86_64/gdt.c b/src/arch/x86_64/gdt.c index 836f5156..2e4814de 100644 --- a/src/arch/x86_64/gdt.c +++ b/src/arch/x86_64/gdt.c @@ -34,8 +34,10 @@ static void reloadgdtr(){ gdtr.offset = &arch_getcls()->gdt; gdtr.size = sizeof(gdt_t) - 1; - asm("lgdt (%%rax)" : : "a"(&gdtr) : "memory"); - asm("ltr %%ax" : : "a"(0x48)); + asm volatile("lgdt (%%rax)" : : "a"(&gdtr) : "memory"); + asm volatile("ltr %%ax" : : "a"(0x48)); + asm volatile("swapgs;mov $0, %%ax;mov %%ax, %%gs;mov %%ax, %%fs;swapgs;" : : : "ax"); + } void gdt_init(){ diff --git a/src/arch/x86_64/include/arch/cls.h b/src/arch/x86_64/include/arch/cls.h index baae9391..04bc33f3 100644 --- a/src/arch/x86_64/include/arch/cls.h +++ b/src/arch/x86_64/include/arch/cls.h @@ -13,6 +13,7 @@ // this will be pointed to by GS and will contain per cpu info typedef struct{ + void* kstack; gdt_t gdt; ist_t ist; int lapicid; diff --git a/src/arch/x86_64/include/arch/regs.h b/src/arch/x86_64/include/arch/regs.h index 8b775c2e..770c2708 100644 --- a/src/arch/x86_64/include/arch/regs.h +++ b/src/arch/x86_64/include/arch/regs.h @@ -4,10 +4,15 @@ #include #include +typedef struct{ + uint64_t gsbase, fsbase; +} arch_extraregs; + typedef struct{ uint64_t cr2,gs,fs,es,ds,rax,rbx,rcx,rdx,r8,r9,r10,r11,r12,r13,r14,r15,rdi,rsi,rbp,error,rip,cs,rflags,rsp,ss; } arch_regs; - +void arch_regs_saveextra(arch_extraregs* regs); +void arch_regs_setupextra(arch_extraregs* regs); void arch_regs_setupkernel(arch_regs* regs, void* ip, void* stack, bool interrupts); void arch_regs_setupuser(arch_regs* regs, void* ip, void* stack, bool interrupts); diff --git a/src/arch/x86_64/isr.asm b/src/arch/x86_64/isr.asm index e2d47100..0331839b 100644 --- a/src/arch/x86_64/isr.asm +++ b/src/arch/x86_64/isr.asm @@ -29,7 +29,7 @@ section .text mov rax, gs push rax - cmp rax,0x30 + cmp rax,0x43 jmp .noswapgs swapgs .noswapgs: @@ -42,22 +42,18 @@ section .text %macro popregs 0 - add rsp, 8 ; cr2 - + add rsp, 24 ; cr2 gs fs + pop rax - cmp rax,0x30 + cmp rax,0x43 je .dontpopsegs - mov gs,rax - pop rax - mov fs,rax - pop rax mov es,rax pop rax mov ds,rax swapgs jmp .poprest .dontpopsegs: - add rsp,24 + add rsp,8 ; ds .poprest: pop rax diff --git a/src/arch/x86_64/kstack.c b/src/arch/x86_64/kstack.c index 2be88f69..e257e322 100644 --- a/src/arch/x86_64/kstack.c +++ b/src/arch/x86_64/kstack.c @@ -5,4 +5,5 @@ void arch_setkernelstack(void* stack){ arch_getcls()->ist.rsp0 = (uint64_t)stack; + arch_getcls()->kstack = stack; } diff --git a/src/arch/x86_64/regs.c b/src/arch/x86_64/regs.c index 93939bd4..767b1815 100644 --- a/src/arch/x86_64/regs.c +++ b/src/arch/x86_64/regs.c @@ -1,4 +1,17 @@ #include +#include + +void arch_regs_saveextra(arch_extraregs* regs){ + // user gs was swapped + regs->gsbase = rdmsr(MSR_KERNELGSBASE); + regs->fsbase = rdmsr(MSR_FSBASE); +} + +void arch_regs_setupextra(arch_extraregs* regs){ + // gs will be swapped later + wrmsr(MSR_KERNELGSBASE, regs->gsbase); + wrmsr(MSR_FSBASE, regs->fsbase); +} void arch_regs_setupkernel(arch_regs* regs, void* ip, void* stack, bool interrupts){ regs->rip = ip; diff --git a/src/arch/x86_64/syscall.asm b/src/arch/x86_64/syscall.asm new file mode 100644 index 00000000..21c85a64 --- /dev/null +++ b/src/arch/x86_64/syscall.asm @@ -0,0 +1,76 @@ +section .rodata + + +extern syscall_libc_log +func_count equ 1 + + +func_table: + dq syscall_libc_log + +section .text +global asm_syscall_entry + +; the registers for the system call are: +; RETURN: +; rax -> ret value +; rdx -> errno +; PARAM: +; rax -> func +; rdi, rsi, rdx, r10, r8, r9 -> parameters +; clobbers: rax, rdx, rcx, r11 + +asm_syscall_entry: + swapgs + + xchg rsp, [gs:0] ; get new stack + push qword [gs:0] ; save old stack + mov [gs:0], rsp ; return back the kernel stack + add qword [gs:0], 8 ; fix it + + push rcx ; old rip + push r11 ; old rflags + + mov r11, 0x30 ; kernel data + mov ds, r11 + mov es, r11 + + ; save C scratch registers + ; rax is not saved because it will be the return value + ; rdx is not saved because it will be the errno value + + push rdi + push rsi + push rcx + push r8 + push r9 + push r10 + + ; system V C abi expects the third param to be in rcx + ; but the param is in rdx because of the syscall instruction + + mov rcx, rdx + + call [func_table + rax * 8] + + ; now restore the scratch registers + + pop r10 + pop r9 + pop r8 + pop rcx + pop rsi + pop rdi + + ; restore entry state + + mov r11, 0x40 ; user data + mov es,r11 + mov ds,r11 + + pop r11 + pop rcx + pop rsp + swapgs + + o64 sysret diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index 3cc16cae..ed8784c2 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -23,6 +23,7 @@ typedef struct _thread_t{ struct _thread_t* prev; struct _proc_t* proc; arch_regs* regs; + arch_extraregs extraregs; state_t state; void* kernelstack; void* kernelstackbase; diff --git a/src/include/kernel/syscalls.h b/src/include/kernel/syscalls.h new file mode 100644 index 00000000..c4726063 --- /dev/null +++ b/src/include/kernel/syscalls.h @@ -0,0 +1,11 @@ +#ifndef _SYSCALLS_H_INCLUDE +#define _SYSCALLS_H_INCLUDE + +typedef struct { + long ret; + long errno; +} syscallret; + +syscallret syscall_libc_log(char* str); + +#endif diff --git a/src/sys/Makefile b/src/sys/Makefile index d8f94e82..b479712e 100644 --- a/src/sys/Makefile +++ b/src/sys/Makefile @@ -1,5 +1,5 @@ objects := $(patsubst %.c,%.o,$(wildcard *.c)) -subdirs := mm sched +subdirs := mm sched syscalls OBJPATH=$(OBJDIR) export diff --git a/src/sys/sched/scheduler.c b/src/sys/sched/scheduler.c index 14186af9..f0efb023 100644 --- a/src/sys/sched/scheduler.c +++ b/src/sys/sched/scheduler.c @@ -162,9 +162,9 @@ void sched_timerhook(arch_regs* regs){ spinlock_release(&running.lock); - + memcpy(current->regs, regs, sizeof(arch_regs)); - + arch_regs_saveextra(¤t->extraregs); spinlock_acquire(¤tqueue->lock); @@ -198,6 +198,8 @@ static void switch_thread(thread_t* thread){ arch_setkernelstack(thread->kernelstack); + arch_regs_setupextra(&thread->extraregs); + arch_switchcontext(thread->regs); __builtin_unreachable(); @@ -291,6 +293,8 @@ void sched_runinit(){ printf("ELF load error: %s\n", strerror(ret)); _panic("Could not load init", 0); } + + thread->extraregs.gsbase = 0xFFFFFFFFDEADBEEF; switch_thread(thread); diff --git a/src/sys/syscalls/Makefile b/src/sys/syscalls/Makefile new file mode 100644 index 00000000..1d6ce393 --- /dev/null +++ b/src/sys/syscalls/Makefile @@ -0,0 +1,12 @@ +objects := $(patsubst %.c,%.o,$(wildcard *.c)) +subdirs := +OBJPATH=$(OBJDIR) +export + +all: $(subdirs) $(objects) + for subdir in $(subdirs) ; do $(MAKE) -C $${subdir} ; done + +%.o: %.c + $(CC) $(CFLAGS) -o $@ $< + mkdir -p $(OBJPATH) + cp $@ $(OBJPATH)/$@ diff --git a/src/sys/syscalls/libclog.c b/src/sys/syscalls/libclog.c new file mode 100644 index 00000000..0251012f --- /dev/null +++ b/src/sys/syscalls/libclog.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include + +syscallret syscall_libc_log(char* str){ + + syscallret ret; + + char* buf = alloc(strlen(str) + 1); + if(!buf){ + ret.errno = ENOMEM; + ret.ret = -1; + return ret; + } + + strcpy(buf, str); + + printf("%s", str); + + ret.errno = 0; + ret.ret = 0; + + free(buf); + + return ret; + +}