From 8a12f23b6946bea1c8a7925b0747e44ee0ec4a6a Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Tue, 2 Sep 2025 23:51:14 +0200 Subject: [PATCH] Implement syscalls, hello world from userspace --- kernel/Makefile | 1 + kernel/compiler/attr.h | 7 ++-- kernel/errors.h | 19 +++++---- kernel/hal/x86_64/cpu.c | 20 +++++++-- kernel/hal/x86_64/cpu.h | 25 +++++++++++ kernel/hal/x86_64/hal.c | 2 + kernel/hal/x86_64/intr.c | 13 +++--- kernel/hal/x86_64/intr.h | 1 + kernel/hal/x86_64/intr0.S | 1 - kernel/hal/x86_64/regs.S | 2 + kernel/hal/x86_64/syscall.c | 43 +++++++++++++++++++ kernel/hal/x86_64/syscall.h | 6 +++ kernel/hal/x86_64/syscall0.S | 48 +++++++++++++++++++++ kernel/kprintf.h | 7 ---- kernel/proc/proc.c | 24 ++++++----- kernel/proc/proc.h | 7 ++++ kernel/syscall/syscall.c | 27 ++++++++++++ kernel/syscall/syscall.h | 81 ++++++++++++++++++++++++++++++++++++ kernel/term/term.c | 1 - kernel/term/term.h | 1 - run/qemu-x86_64.sh | 2 +- user/arch/x86_64/link.ld | 1 - user/hello/Makefile | 2 +- user/hello/hello.s | 16 ++++++- 24 files changed, 313 insertions(+), 44 deletions(-) create mode 100644 kernel/hal/x86_64/syscall.c create mode 100644 kernel/hal/x86_64/syscall.h create mode 100644 kernel/hal/x86_64/syscall0.S create mode 100644 kernel/syscall/syscall.c create mode 100644 kernel/syscall/syscall.h diff --git a/kernel/Makefile b/kernel/Makefile index 1e24e9c..b7173bc 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -57,6 +57,7 @@ SRCFILES += $(call GRABSRC, \ std \ flanterm/src \ flanterm/src/flanterm_backends \ + syscall \ ) ifeq ($(ARCH),x86_64) diff --git a/kernel/compiler/attr.h b/kernel/compiler/attr.h index b8ae016..6621587 100644 --- a/kernel/compiler/attr.h +++ b/kernel/compiler/attr.h @@ -1,8 +1,9 @@ #ifndef COMPILER_ATTR_H_ #define COMPILER_ATTR_H_ -#define PACKED __attribute__((packed)) -#define ALIGNED(x) __attribute__((aligned((x)))) -#define NORETURN __attribute__((noreturn)) +#define PACKED __attribute__((packed)) +#define ALIGNED(x) __attribute__((aligned((x)))) +#define NORETURN __attribute__((noreturn)) +#define UNUSED __attribute__((unused)) #endif // COMPILER_ATTR_H_ diff --git a/kernel/errors.h b/kernel/errors.h index e08f860..da810c6 100644 --- a/kernel/errors.h +++ b/kernel/errors.h @@ -1,13 +1,16 @@ #ifndef ERRORS_H_ #define ERRORS_H_ -#define E_OK 0 -#define E_NOMEMORY -1 -#define E_UNKNOWN_FSTYPE -2 -#define E_NOENTRY -3 -#define E_OUTOFBOUNDS -4 -#define E_UNKNOWN_SDTYPE -5 -#define E_TODO -6 -#define E_BADIO -7 +enum { + E_OK = 0, + E_NOMEMORY = -1, + E_UNKNOWN_FSTYPE = -2, + E_NOENTRY = -3, + E_OUTOFBOUNDS = -4, + E_UNKNOWN_SDTYPE = -5, + E_TODO = -6, + E_BADIO = -7, + E_BADSYSCALL = -8, +}; #endif // ERRORS_H_ diff --git a/kernel/hal/x86_64/cpu.c b/kernel/hal/x86_64/cpu.c index 264a0ca..29b1425 100644 --- a/kernel/hal/x86_64/cpu.c +++ b/kernel/hal/x86_64/cpu.c @@ -1,14 +1,28 @@ #include #include +#include "cpu.h" +#include "vmm.h" +#include "pmm/pmm.h" +#include "hal/hal.h" +#include "bootinfo/bootinfo.h" + +LocalCpuData HAL_CPUS[HAL_CPUS_MAX]; uint64_t hal_cpu_rdmsr(uint32_t id) { uint32_t lo, hi; - asm volatile("rdmsr" : "=m"(lo), "=d"(hi) : "c"(id)); + asm volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(id)); return ((uint64_t)lo) | ((uint64_t)hi << 32); } uint64_t hal_cpu_wrmsr(uint32_t id, uint64_t val) { - uint32_t lo = val & 0xffffffff, hi = (val >> 32) & 0xffffffff; - asm volatile("wrmsr" :: "a"(lo), "d"(hi), "c"(id) : "memory"); + uint32_t lo = val & 0xFFFFFFFF; + uint32_t hi = val >> 32; + asm volatile("wrmsr" :: "c"(id), "a"(lo), "d"(hi)); return val; } + +void hal_cpu_init(uint32_t cpu) { + void *addr = pmm_alloc(16) + (16 * HAL_PAGE_SIZE); + HAL_CPUS[cpu].syscall_kstack = (uint64_t *)VIRT(addr); + HAL_CPUS[cpu].kcr3 = hal_vmm_current_cr3(); +} diff --git a/kernel/hal/x86_64/cpu.h b/kernel/hal/x86_64/cpu.h index a546fae..efb7504 100644 --- a/kernel/hal/x86_64/cpu.h +++ b/kernel/hal/x86_64/cpu.h @@ -1,11 +1,36 @@ #ifndef HAL_CPU_H_ #define HAL_CPU_H_ +#include +#include "compiler/attr.h" +#include "vmm.h" +#include "intr.h" + +#define HAL_CPUS_MAX 0xff + +#define HAL_CPU_EFER 0xC0000080 + +#define HAL_CPU_STAR 0xC0000081 +#define HAL_CPU_LSTAR 0xC0000082 +#define HAL_CPU_CSTAR 0xC0000083 +#define HAL_CPU_SFMASK 0xC0000084 + #define HAL_CPU_FSBASE 0xC0000100 #define HAL_CPU_GSBASE 0xC0000101 #define HAL_CPU_KGSBASE 0xC0000102 +typedef struct { + uint64_t *syscall_kstack; + uint64_t *syscall_ustack; + PgTable *kcr3; + PgTable *pcr3; + IntrStackFrame *frame; +} PACKED LocalCpuData; + uint64_t hal_cpu_rdmsr(uint32_t id); uint64_t hal_cpu_wrmsr(uint32_t id, uint64_t val); +void hal_cpu_init(uint32_t cpu); + +extern LocalCpuData HAL_CPUS[HAL_CPUS_MAX]; #endif // HAL_CPU_H_ diff --git a/kernel/hal/x86_64/hal.c b/kernel/hal/x86_64/hal.c index 76503a0..45c028a 100644 --- a/kernel/hal/x86_64/hal.c +++ b/kernel/hal/x86_64/hal.c @@ -9,6 +9,7 @@ #include "pic.h" #include "apic.h" #include "pit.h" +#include "syscall.h" void hal_init(void) { if (!serial_init()) { @@ -32,6 +33,7 @@ void hal_init_withmalloc(void) { pit_init(); ioapic_setentry(IOAPIC, acpi_remapirq(0x00), INTR_TIMER); hal_intr_disable(); + hal_syscall_init(); } void hal_wait(uint32_t ms) { diff --git a/kernel/hal/x86_64/intr.c b/kernel/hal/x86_64/intr.c index ea50ec9..f60e45e 100644 --- a/kernel/hal/x86_64/intr.c +++ b/kernel/hal/x86_64/intr.c @@ -133,7 +133,7 @@ void intr_dumpframe(IntrStackFrame *frame) { asm volatile("mov %%cr3, %0" : "=r"(cr3)); uint64_t cr4; asm volatile("mov %%cr4, %0" : "=r"(cr4)); - kprintf_unsafe("rax=%016lx rcx=%016lx rdx=%016lx\n" + kprintf("rax=%016lx rcx=%016lx rdx=%016lx\n" "rsi=%016lx rdi=%016lx r8 =%016lx\n" "r9 =%016lx r10=%016lx r11=%016lx\n" "rip=%016lx rfl=%016lx rsp=%016lx\n" @@ -150,11 +150,14 @@ void intr_dumpframe(IntrStackFrame *frame) { } void intr_handleintr(IntrStackFrame *frame) { - if (frame->trapnum >= 0 && frame->trapnum <= 31) { - // EXCEPTION - kprintf_unsafe("ERROR %s, 0x%lX\n", exceptions[frame->trapnum], frame->errnum); + if (frame->trapnum <= 31) { + if (frame->trapnum == 14 && frame->errnum & 0x4) { + proc_killself(); + proc_sched((void *)frame); + } + kprintf("ERROR %s, 0x%lX\n", exceptions[frame->trapnum], frame->errnum); intr_dumpframe(frame); - hal_hang(); + hal_hang(); } else if (frame->trapnum >= 32 && frame->trapnum <= 47) { if (frame->trapnum == INTR_TIMER) { io_out8(PIC2_CMD, 0x20); diff --git a/kernel/hal/x86_64/intr.h b/kernel/hal/x86_64/intr.h index 5c7ca3c..a1179e9 100644 --- a/kernel/hal/x86_64/intr.h +++ b/kernel/hal/x86_64/intr.h @@ -17,6 +17,7 @@ typedef struct { uint64_t r10; uint64_t r9; uint64_t r8; + uint64_t rbp; uint64_t rdi; uint64_t rsi; uint64_t rdx; diff --git a/kernel/hal/x86_64/intr0.S b/kernel/hal/x86_64/intr0.S index c905969..2b98fcc 100644 --- a/kernel/hal/x86_64/intr0.S +++ b/kernel/hal/x86_64/intr0.S @@ -215,4 +215,3 @@ intr_vec46: intr_vec47: _vecintr_plain_save 47 _vecintr_bodygen - diff --git a/kernel/hal/x86_64/regs.S b/kernel/hal/x86_64/regs.S index 862af16..c921d14 100644 --- a/kernel/hal/x86_64/regs.S +++ b/kernel/hal/x86_64/regs.S @@ -4,6 +4,7 @@ push %rdx push %rsi push %rdi + push %rbp push %r8 push %r9 push %r10 @@ -23,6 +24,7 @@ pop %r10 pop %r9 pop %r8 + pop %rbp pop %rdi pop %rsi pop %rdx diff --git a/kernel/hal/x86_64/syscall.c b/kernel/hal/x86_64/syscall.c new file mode 100644 index 0000000..7a18f62 --- /dev/null +++ b/kernel/hal/x86_64/syscall.c @@ -0,0 +1,43 @@ +#include +#include "syscall.h" +#include "cpu.h" +#include "intr.h" +#include "syscall/syscall.h" +#include "proc/proc.h" +#include "kprintf.h" +#include "errors.h" + +extern void hal_enable_syscallentry(void); +extern void hal_syscallentry(void); + +void hal_syscalldispatch(IntrStackFrame *frame) { + uint64_t sysnum = frame->regs.rax; + if (sysnum < SYSCALLS_MAX) { + SyscallFn fn = SYSCALL_TABLE[sysnum]; + if (fn == NULL) { + frame->regs.rax = E_BADSYSCALL; + return; + } + int32_t ret = fn(frame->regs.rdi, frame->regs.rsi, frame->regs.rdx, + frame->regs.r10, frame->regs.r8, frame->regs.r9); + + if (sysnum == SYS_QUITPROC) { + proc_sched((void *)frame); + } + frame->regs.rax = *(uint64_t *)&ret; + } +} + +void hal_syscall_init(void) { + hal_cpu_init(0); + LocalCpuData *lcd = &HAL_CPUS[0]; + + hal_cpu_wrmsr(HAL_CPU_EFER, hal_cpu_rdmsr(HAL_CPU_EFER) | 0x1); + hal_enable_syscallentry(); + + hal_cpu_wrmsr(HAL_CPU_GSBASE, (uint64_t)lcd); + hal_cpu_wrmsr(HAL_CPU_KGSBASE, (uint64_t)lcd); + hal_cpu_wrmsr(HAL_CPU_SFMASK, (uint64_t)0); + + hal_cpu_wrmsr(HAL_CPU_LSTAR, (uint64_t)&hal_syscallentry); +} diff --git a/kernel/hal/x86_64/syscall.h b/kernel/hal/x86_64/syscall.h new file mode 100644 index 0000000..d408203 --- /dev/null +++ b/kernel/hal/x86_64/syscall.h @@ -0,0 +1,6 @@ +#ifndef HAL_SYSCALL_H_ +#define HAL_SYSCALL_H_ + +void hal_syscall_init(void); + +#endif // HAL_SYSCALL_H_ diff --git a/kernel/hal/x86_64/syscall0.S b/kernel/hal/x86_64/syscall0.S new file mode 100644 index 0000000..8c44aad --- /dev/null +++ b/kernel/hal/x86_64/syscall0.S @@ -0,0 +1,48 @@ +#include "regs.S" + +.extern hal_syscalldispatch + +.global hal_enable_syscallentry +hal_enable_syscallentry: + movq $0xC0000080, %rcx + rdmsr + or $0x1, %eax + wrmsr + movq $0xC0000081, %rcx + rdmsr + movl $0x180008, %edx + wrmsr + ret + +.global hal_syscallentry +hal_syscallentry: + cli + swapgs + + movq %rsp, %gs:0x8 + movq %gs:0x0, %rsp + + pushq $0x23 + pushq %gs:0x8 + + swapgs + + pushq %r11 + pushq $0x1b + pushq %rcx + + _push_regs + + mov %rsp, %rdi + mov $0x0, %rbp + + call hal_syscalldispatch + cli + + _pop_regs + + popq %rcx + add $0x8, %rsp + popq %r11 + popq %rsp + sysret diff --git a/kernel/kprintf.h b/kernel/kprintf.h index 551fa20..bc9f395 100644 --- a/kernel/kprintf.h +++ b/kernel/kprintf.h @@ -6,13 +6,6 @@ #include "spinlock/spinlock.h" #define kprintf(fmt, ...) \ - do { \ - spinlock_acquire(&TERM.spinlock); \ - printf_(fmt, ##__VA_ARGS__); \ - spinlock_release(&TERM.spinlock); \ - } while(0) - -#define kprintf_unsafe(fmt, ...) \ do { \ printf_(fmt, ##__VA_ARGS__); \ } while(0) diff --git a/kernel/proc/proc.c b/kernel/proc/proc.c index bc6ebdd..f1a97ff 100644 --- a/kernel/proc/proc.c +++ b/kernel/proc/proc.c @@ -15,12 +15,6 @@ #define PROC_REAPER_FREQ 30 -#define PROC_DIE() \ - do { \ - proc_killself(); \ - for(;;); \ - } while(0) - uint64_t pids = 0; uint64_t sched_ticks = 0; @@ -161,8 +155,16 @@ void proc_register(Proc *proc) { } Proc *proc_nextready(void) { - Proc *next = PROCS.current->next; - Proc *proc = next == NULL ? PROCS.procs : next; + Proc *proc = PROCS.current->next; + for (;;) { + if (proc == NULL) { + proc = PROCS.procs; + } + if (proc->state != PROC_ZOMBIE) { + return proc; + } + proc = proc->next; + } return proc; } @@ -183,7 +185,7 @@ void proc_reaper(void) { while (vashead) { VasRange *tmp = vashead; vashead = vashead->next; - hal_vmm_unmap_range(zombie->platformdata.cr3, tmp->virtstart, tmp->physstart, tmp->size); + hal_vmm_unmap_range(VIRT(zombie->platformdata.cr3), tmp->virtstart, tmp->physstart, tmp->size); // first pmm mapping is for the elf itself if (i == 0) { pmm_free((uintptr_t)tmp->physstart, tmp->size / HAL_PAGE_SIZE); @@ -218,6 +220,7 @@ void proc_sched(void *cpustate) { PROCS.current->state = PROC_RUNNING; hal_cpu_wrmsr(HAL_CPU_FSBASE, PROCS.current->platformdata.fsbase); + HAL_CPUS[0].syscall_kstack = VIRT(PROCS.current->platformdata.kstack); hal_switchproc(&PROCS.current->platformdata.trapframe, (void *)PROCS.current->platformdata.cr3); } @@ -239,11 +242,12 @@ void proc_idle(void) { } void proc_status(void) { + static const char *statuses[] = {"ready", "running", "zombie", "waiting"}; for (;;) { spinlock_acquire(&PROCS.spinlock); Proc *head = PROCS.procs; while (head) { - kprintf("%s %s\n", head->kern ? "kern" : "user", head->name); + kprintf("%s %s %s\n", head->kern ? "kern" : "user", statuses[head->state], head->name); head = head->next; } kprintf("\n\n"); diff --git a/kernel/proc/proc.h b/kernel/proc/proc.h index 339fe63..4b54d19 100644 --- a/kernel/proc/proc.h +++ b/kernel/proc/proc.h @@ -50,5 +50,12 @@ void proc_register(Proc *proc); Proc *proc_spawnkern(void (*ent)(void), char *name); Proc *proc_spawnuser(char *mountpoint, char *path); void proc_sched(void *cpustate); +void proc_killself(void); + +#define PROC_DIE() \ + do { \ + proc_killself(); \ + for(;;); \ + } while(0) #endif // PROC_PROC_H_ diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c new file mode 100644 index 0000000..5501298 --- /dev/null +++ b/kernel/syscall/syscall.c @@ -0,0 +1,27 @@ +#include +#include "syscall.h" +#include "errors.h" +#include "dlmalloc/malloc.h" +#include "kprintf.h" +#include "proc/proc.h" + +int32_t SYSCALL2(sys_debugprint, string1, len) { + char *buf = dlmalloc(len); + if (buf == NULL) { + return E_NOMEMORY; + } + ksnprintf(buf, len, "%s", string1); + kprintf("%s\n", buf); + dlfree(buf); + return E_OK; +} + +int32_t SYSCALL0(sys_quitproc) { + proc_killself(); + return E_OK; +} + +SyscallFn SYSCALL_TABLE[SYSCALLS_MAX] = { + [SYS_DEBUGPRINT] = &sys_debugprint, + [SYS_QUITPROC] = &sys_quitproc, +}; diff --git a/kernel/syscall/syscall.h b/kernel/syscall/syscall.h new file mode 100644 index 0000000..2079533 --- /dev/null +++ b/kernel/syscall/syscall.h @@ -0,0 +1,81 @@ +#ifndef SYSCALL_SYSCALL_H_ +#define SYSCALL_SYSCALL_H_ + +#include +#include "compiler/attr.h" + +#define SYSCALLS_MAX 0xff + +#define SYSCALL0(name) \ + name(UNUSED uint64_t _1, \ + UNUSED uint64_t _2, \ + UNUSED uint64_t _3, \ + UNUSED uint64_t _4, \ + UNUSED uint64_t _5, \ + UNUSED uint64_t _6 \ + ) + +#define SYSCALL1(name, arg1) \ + name(uint64_t arg1, \ + UNUSED uint64_t _2, \ + UNUSED uint64_t _3, \ + UNUSED uint64_t _4, \ + UNUSED uint64_t _5, \ + UNUSED uint64_t _6 \ + ) + +#define SYSCALL2(name, arg1, arg2) \ + name(uint64_t arg1, \ + uint64_t arg2, \ + UNUSED uint64_t _3, \ + UNUSED uint64_t _4, \ + UNUSED uint64_t _5, \ + UNUSED uint64_t _6 \ + ) + +#define SYSCALL3(name, arg1, arg2, arg3) \ + name(uint64_t arg1, \ + uint64_t arg2, \ + uint64_t arg3, \ + UNUSED uint64_t _4, \ + UNUSED uint64_t _5, \ + UNUSED uint64_t _6 \ + ) + +#define SYSCALL4(name, arg1, arg2, arg3, arg4) \ + name(uint64_t arg1, \ + uint64_t arg2, \ + uint64_t arg3, \ + uint64_t arg4, \ + UNUSED uint64_t _5, \ + UNUSED uint64_t _6 \ + ) + +#define SYSCALL5(name, arg1, arg2, arg3, arg4, arg5) \ + name(uint64_t arg1, \ + uint64_t arg2, \ + uint64_t arg3, \ + uint64_t arg4, \ + uint64_t arg5, \ + UNUSED uint64_t _6 \ + ) + +#define SYSCALL6(name, arg1, arg2, arg3, arg4, arg5, arg6) \ + name(uint64_t arg1, \ + uint64_t arg2, \ + uint64_t arg3, \ + uint64_t arg4, \ + uint64_t arg5, \ + uint64_t arg6 \ + ) + +enum { + SYS_DEBUGPRINT = 1, + SYS_QUITPROC = 2, +}; + +typedef int32_t (*SyscallFn)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); + +extern SyscallFn SYSCALL_TABLE[SYSCALLS_MAX]; + +#endif // SYSCALL_SYSCALL_H_ diff --git a/kernel/term/term.c b/kernel/term/term.c index ebd000d..5ec9065 100644 --- a/kernel/term/term.c +++ b/kernel/term/term.c @@ -31,7 +31,6 @@ void term_doinit(void *addr) { } void term_init(void *addr) { - spinlock_init(&TERM.spinlock); term_doinit(addr); } diff --git a/kernel/term/term.h b/kernel/term/term.h index fe91fe2..cf1d5c3 100644 --- a/kernel/term/term.h +++ b/kernel/term/term.h @@ -7,7 +7,6 @@ typedef struct { struct flanterm_context *ftctx; - SpinLock spinlock; } Term; extern Term TERM; diff --git a/run/qemu-x86_64.sh b/run/qemu-x86_64.sh index 84a6b0e..4560355 100755 --- a/run/qemu-x86_64.sh +++ b/run/qemu-x86_64.sh @@ -2,4 +2,4 @@ set -x -qemu-system-x86_64 -cpu qemu64,+pdpe1gb -m 4G -cdrom mop2.iso -boot d -serial stdio $@ +qemu-system-x86_64 -cpu IvyBridge -m 4G -cdrom mop2.iso -boot d -serial stdio $@ diff --git a/user/arch/x86_64/link.ld b/user/arch/x86_64/link.ld index e846459..a8e5fff 100644 --- a/user/arch/x86_64/link.ld +++ b/user/arch/x86_64/link.ld @@ -1,7 +1,6 @@ ENTRY(_start) SECTIONS { - /* . = 0xffff000000000000; */ . = 0x0000000000000000; .rodata ALIGN(4K): diff --git a/user/hello/Makefile b/user/hello/Makefile index b6da720..ccd4b6d 100644 --- a/user/hello/Makefile +++ b/user/hello/Makefile @@ -16,7 +16,7 @@ all: $(TARGET) hello: $(OBJ) $(LD) $^ $(LDFLAGS) -o $@ - echo $(realpath $@) >> $(FILES) + echo $(realpath hello) >> $(FILES) clean: rm -f $(OBJ) $(TARGET) diff --git a/user/hello/hello.s b/user/hello/hello.s index bf780c3..0abbbc5 100644 --- a/user/hello/hello.s +++ b/user/hello/hello.s @@ -1,6 +1,18 @@ +.section .data +STRING: + .string "Hello World from userspace" +STRING_LEN: + .quad . - STRING + +.section .text .global _start _start: -.spin: - jmp .spin + movq $1, %rax + lea STRING(%rip), %rdi + lea STRING_LEN(%rip), %rsi + syscall + + movq $2, %rax + syscall