diff --git a/kernel/src/arch/gdt-helper.asm b/kernel/src/arch/gdt-helper.asm new file mode 100644 index 0000000..df92d08 --- /dev/null +++ b/kernel/src/arch/gdt-helper.asm @@ -0,0 +1,24 @@ +global flush_tss +global jump_user +extern test_user + +flush_tss: + mov ax, 5 * 8 + ltr ax + ret + +; void jump_user(uint64_t addr, uint64_t stack) +jump_user: + mov ax, 0x23 ; Ring 3 data with bottom 2 bits set for ring 3 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax ; SS is handled by iretq + + ; Set up the stack frame iretq expects + push 0x23 ; Data selector + push rsi ; Stack + pushf ; Rflags + push 0x1B ; Code selector (ring 3 code with bottom 2 bits set for ring 3) + push rdi ; Instruction address to return to + iretq \ No newline at end of file diff --git a/kernel/src/arch/gdt.c b/kernel/src/arch/gdt.c index cde0000..510014c 100644 --- a/kernel/src/arch/gdt.c +++ b/kernel/src/arch/gdt.c @@ -1,8 +1,11 @@ /* EMK 1.0 Copyright (c) 2025 Piraterna */ #include +#include +#include -gdt_entry_t gdt[5]; +gdt_entry_t gdt[7]; gdt_ptr_t gdt_ptr; +tss_entry_t tss; void gdt_init() { @@ -18,6 +21,34 @@ void gdt_init() gdt_flush(gdt_ptr); } +void flush_tss(void); +void tss_init(uint64_t stack) +{ + log_early("Initializing TSS with RSP0 = 0x%.16llx", stack); + + memset(&tss, 0, sizeof(tss_entry_t)); + + tss.rsp0 = stack; + tss.io_map_base = sizeof(tss_entry_t); + + uint64_t base = (uint64_t)&tss; + uint32_t limit = sizeof(tss_entry_t) - 1; + gdt_system_entry_t tss_entry = { + .limit_low = limit & 0xFFFF, + .base_low = base & 0xFFFF, + .base_middle = (base >> 16) & 0xFF, + .access = GDT_TSS, + .granularity = (limit >> 16) & 0x0F, + .base_high = (base >> 24) & 0xFF, + .base_upper = base >> 32, + .reserved = 0, + }; + memcpy(&gdt[5], &tss_entry, sizeof(gdt_system_entry_t)); + + gdt_flush(gdt_ptr); + flush_tss(); +} + void gdt_flush(gdt_ptr_t gdt_ptr) { __asm__ volatile( diff --git a/kernel/src/arch/gdt.h b/kernel/src/arch/gdt.h index efcf1f0..62a134d 100644 --- a/kernel/src/arch/gdt.h +++ b/kernel/src/arch/gdt.h @@ -39,6 +39,37 @@ typedef struct gdt_entry uint8_t base_high; } __attribute__((packed)) gdt_entry_t; +typedef struct gdt_system_entry +{ + uint16_t limit_low; + uint16_t base_low; + uint8_t base_middle; + uint8_t access; + uint8_t granularity; + uint8_t base_high; + uint32_t base_upper; + uint32_t reserved; +} __attribute__((packed)) gdt_system_entry_t; + +typedef struct tss_entry +{ + uint32_t reserved0; + uint64_t rsp0; + uint64_t rsp1; + uint64_t rsp2; + uint64_t reserved1; + uint64_t ist1; + uint64_t ist2; + uint64_t ist3; + uint64_t ist4; + uint64_t ist5; + uint64_t ist6; + uint64_t ist7; + uint64_t reserved2; + uint16_t reserved3; + uint16_t io_map_base; +} __attribute__((packed)) tss_entry_t; + typedef struct gdt_ptr { uint16_t limit; @@ -49,5 +80,7 @@ extern gdt_ptr_t gdt_ptr; void gdt_init(); void gdt_flush(gdt_ptr_t gdt_ptr); +void tss_init(uint64_t rsp0); +extern void jump_user(uint64_t addr, uint64_t stack); #endif // GDT_H \ No newline at end of file diff --git a/kernel/src/arch/idt.c b/kernel/src/arch/idt.c index 60a4f30..7f2f32c 100644 --- a/kernel/src/arch/idt.c +++ b/kernel/src/arch/idt.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include struct idt_entry __attribute__((aligned(16))) idt_descriptor[256] = {0}; idt_intr_handler real_handlers[256] = {0}; @@ -20,6 +22,19 @@ struct __attribute__((packed)) idt_ptr struct idt_ptr idt_ptr = {sizeof(idt_descriptor) - 1, (uint64_t)&idt_descriptor}; +void syscall_handler(struct register_ctx *ctx) +{ + log_user("syscall(%lu, 0x%.16lx, 0x%.16lx, 0x%.16lx, 0x%.16lx) from 0x%.16llx @ CPU %d", + ctx->rax, + ctx->rdi, + ctx->rsi, + ctx->rdx, + ctx->rcx, + ctx->rip, get_cpu_local()->cpu_index); + log_user("warning: No systemcall handlers available, dropping syscall..."); + ctx->rax = -1; +} + void idt_default_interrupt_handler(struct register_ctx *ctx) { kpanic(ctx, NULL); @@ -50,6 +65,9 @@ void idt_init() SET_GATE(i, stubs[i], IDT_INTERRUPT_GATE); } + SET_GATE(0x80, stubs[0x80], IDT_INTERRUPT_GATE | GDT_ACCESS_RING3); + real_handlers[0x80] = syscall_handler; + __asm__ volatile( "lidt %0" : : "m"(idt_ptr) : "memory"); diff --git a/kernel/src/arch/smp.c b/kernel/src/arch/smp.c index 3001279..f4487c0 100644 --- a/kernel/src/arch/smp.c +++ b/kernel/src/arch/smp.c @@ -59,6 +59,7 @@ void smp_entry(struct limine_mp_info *smp_info) idt_init(); pmset(kernel_pagemap); lapic_enable(); + tss_init(kstack_top); atomic_fetch_add(&started_cpus, 1); log_early("CPU %d (LAPIC ID %u) is up", cpu->cpu_index, lapic_id); @@ -74,6 +75,7 @@ void smp_init(void) log_early("%u CPUs detected", cpu_count); lapic_enable(); + tss_init(kstack_top); for (uint32_t i = 0; i < cpu_count; i++) { diff --git a/kernel/src/emk.c b/kernel/src/emk.c index d9e6db0..03f36f2 100644 --- a/kernel/src/emk.c +++ b/kernel/src/emk.c @@ -23,6 +23,7 @@ #include #include #include +#include __attribute__((used, section(".limine_requests"))) static volatile LIMINE_BASE_REVISION(3); __attribute__((used, section(".limine_requests"))) static volatile struct limine_memmap_request memmap_request = { @@ -72,6 +73,11 @@ void tick(struct register_ctx *) log_early("tick on CPU %d", get_cpu_local()->cpu_index); } +void user_func() +{ + syscall(69, 69, 420, 420); +} + void emk_entry(void) { __asm__ volatile("movq %%rsp, %0" : "=r"(kstack_top)); @@ -210,7 +216,10 @@ void emk_entry(void) ioapic_init(); /* Setup timer */ - pit_init(tick); + pit_init(NULL); + + /* Call our user space function */ + user_func(); // No good way to run in usermode, yet /* Finished */ log_early("%s", LOG_SEPARATOR); diff --git a/kernel/src/sys/syscall.h b/kernel/src/sys/syscall.h new file mode 100644 index 0000000..8e0440e --- /dev/null +++ b/kernel/src/sys/syscall.h @@ -0,0 +1,20 @@ +/* EMK 1.0 Copyright (c) 2025 Piraterna */ +#ifndef SYSCALL_H +#define SYSCALL_H + +#include + +/* TODO: Implement syscalls */ +static inline long +syscall(uint64_t number, uint64_t arg1, uint64_t arg2, uint64_t arg3) +{ + long ret; + __asm__ volatile( + "int $0x80" + : "=a"(ret) + : "a"(number), "D"(arg1), "S"(arg2), "d"(arg3) + : "memory"); + return ret; +} + +#endif // SYSCALL_H \ No newline at end of file diff --git a/kernel/src/util/log.h b/kernel/src/util/log.h index 378156b..391e472 100644 --- a/kernel/src/util/log.h +++ b/kernel/src/util/log.h @@ -6,5 +6,6 @@ #define log_early(fmt, ...) kprintf("early: " fmt "\n", ##__VA_ARGS__) #define log_panic(fmt, ...) kprintf("panic: " fmt "\n", ##__VA_ARGS__) +#define log_user(fmt, ...) kprintf("user: " fmt "\n", ##__VA_ARGS__) #endif // LOG_H \ No newline at end of file