diff --git a/kernel/Makefile b/kernel/Makefile index e6cc174f5e..74cbfc133e 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -26,11 +26,11 @@ CFLAGS:=$(CFLAGS) $(KERNEL_ARCH_CFLAGS) CPPFLAGS:=$(CPPFLAGS) $(KERNEL_ARCH_CPPFLAGS) LDFLAGS:=$(LDFLAGS) $(KERNEL_ARCH_LDFLAGS) LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS) - + ifeq ($(UBSAN), 1) CFLAGS:=$(CFLAGS) -fsanitize=undefined endif - + BUILDDIR=$(abspath build) KERNEL_OBJS= \ @@ -58,9 +58,11 @@ kernel/SpinLock.o \ kernel/SSP.o \ kernel/Storage/ATAController.o \ kernel/Storage/StorageDevice.o \ +kernel/Syscall.o \ kernel/Thread.o \ kernel/TTY.o \ kernel/VesaTerminalDriver.o \ +userspace/userspace.o \ icxxabi.o \ ubsan.o \ @@ -109,6 +111,7 @@ always: mkdir -p $(BUILDDIR)/kernel mkdir -p $(BUILDDIR)/kernel/FS mkdir -p $(BUILDDIR)/kernel/Storage + mkdir -p $(BUILDDIR)/userspace mkdir -p $(BUILDDIR)/font clean: diff --git a/kernel/arch/i386/IDT.cpp b/kernel/arch/i386/IDT.cpp index a1fe841d1f..3efd51024e 100644 --- a/kernel/arch/i386/IDT.cpp +++ b/kernel/arch/i386/IDT.cpp @@ -151,6 +151,29 @@ found: "popa;" "iret;" ); + + extern "C" void syscall_asm(); + asm( + ".global syscall_asm;" + "syscall_asm:" + "pusha;" + "pushw %ds;" + "pushw %es;" + "pushw %ss;" + "pushw %ss;" + "popw %ds;" + "popw %es;" + "pushl %edx;" + "pushl %ecx;" + "pushl %ebx;" + "pushl %eax;" + "call cpp_syscall_handler;" + "addl $16, %esp;" + "popw %es;" + "popw %ds;" + "popa;" + "iret;" + ); static void flush_idt() { @@ -175,6 +198,12 @@ found: flush_idt(); } + void register_syscall_handler(uint8_t offset, void(*handler)()) + { + register_interrupt_handler(offset, handler); + s_idt[offset].DPL = 3; + } + void initialize() { constexpr size_t idt_size = 0x100 * sizeof(GateDescriptor); @@ -219,6 +248,8 @@ found: REGISTER_HANDLER(0x1E); REGISTER_HANDLER(0x1F); + register_syscall_handler(0x80, syscall_asm); + flush_idt(); } diff --git a/kernel/arch/i386/linker.ld b/kernel/arch/i386/linker.ld index 2fb0064756..75e730376f 100644 --- a/kernel/arch/i386/linker.ld +++ b/kernel/arch/i386/linker.ld @@ -11,7 +11,9 @@ SECTIONS } .rodata BLOCK(4K) : ALIGN(4K) { - *(.rodata) + g_rodata_start = .; + *(.rodata.*) + g_rodata_end = .; } .data BLOCK(4K) : ALIGN(4K) { @@ -24,4 +26,13 @@ SECTIONS } g_kernel_end = .; + + . = 0x00A00000; + + g_userspace_start = .; + .userspace BLOCK(4K) : ALIGN(4K) + { + *(.userspace) + } + g_userspace_end = .; } \ No newline at end of file diff --git a/kernel/arch/x86_64/IDT.cpp b/kernel/arch/x86_64/IDT.cpp index 484b3ccaeb..5fa5005422 100644 --- a/kernel/arch/x86_64/IDT.cpp +++ b/kernel/arch/x86_64/IDT.cpp @@ -148,6 +148,12 @@ namespace IDT descriptor.flags = 0x8E; } + static void register_syscall_handler(uint8_t index, void(*handler)()) + { + register_interrupt_handler(index, handler); + s_idt[index].flags = 0xEE; + } + void register_irq_handler(uint8_t irq, void(*handler)()) { s_irq_handlers[irq] = handler; @@ -203,6 +209,8 @@ namespace IDT extern "C" void irq14(); extern "C" void irq15(); + extern "C" void syscall_asm(); + void initialize() { s_idt = (GateDescriptor*)kmalloc(0x100 * sizeof(GateDescriptor)); @@ -262,6 +270,8 @@ namespace IDT REGISTER_IRQ_HANDLER(14); REGISTER_IRQ_HANDLER(15); + register_syscall_handler(0x80, syscall_asm); + flush_idt(); } diff --git a/kernel/arch/x86_64/interrupts.S b/kernel/arch/x86_64/interrupts.S index c650991ef4..b7f61b27e1 100644 --- a/kernel/arch/x86_64/interrupts.S +++ b/kernel/arch/x86_64/interrupts.S @@ -34,6 +34,23 @@ popq %rax .endm +.macro popaq_no_rax + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rsi + popq %rdi + popq %rbp + popq %rdx + popq %rcx + popq %rbx +.endm + isr_stub: pushaq @@ -138,3 +155,15 @@ irq 12 irq 13 irq 14 irq 15 + +.global syscall_asm +syscall_asm: + cli + pushaq + movq %rax, %rdi + movq %rbx, %rsi + xchgq %rcx, %rdx + call cpp_syscall_handler + popaq_no_rax + addq $8, %rsp + iretq \ No newline at end of file diff --git a/kernel/arch/x86_64/linker.ld b/kernel/arch/x86_64/linker.ld index 2fb0064756..ad62aa8e2c 100644 --- a/kernel/arch/x86_64/linker.ld +++ b/kernel/arch/x86_64/linker.ld @@ -11,7 +11,9 @@ SECTIONS } .rodata BLOCK(4K) : ALIGN(4K) { - *(.rodata) + g_rodata_start = .; + *(.rodata.*) + g_rodata_end = .; } .data BLOCK(4K) : ALIGN(4K) { @@ -22,6 +24,15 @@ SECTIONS *(COMMON) *(.bss) } - g_kernel_end = .; + + . = 0x00A00000; + + g_userspace_start = .; + .userspace BLOCK(4K) : ALIGN(4K) + { + *(.userspace) + } + g_userspace_end = .; + } \ No newline at end of file diff --git a/kernel/include/kernel/Syscall.h b/kernel/include/kernel/Syscall.h new file mode 100644 index 0000000000..f35269208a --- /dev/null +++ b/kernel/include/kernel/Syscall.h @@ -0,0 +1,4 @@ +#pragma once + +#define SYS_TEST 0 +#define SYS_PUTC 1 \ No newline at end of file diff --git a/kernel/kernel/Syscall.cpp b/kernel/kernel/Syscall.cpp new file mode 100644 index 0000000000..6e08b353a4 --- /dev/null +++ b/kernel/kernel/Syscall.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +namespace Kernel +{ + + int sys_test() + { + dprintln("hello"); + return 0; + } + + int sys_putc(void* ch) + { + kprint("{}", (char)(uintptr_t)ch); + return 0; + } + + extern "C" int cpp_syscall_handler(int syscall, void* arg1, void* arg2, void* arg3) + { + (void)arg1; + (void)arg2; + (void)arg3; + + int ret; + switch (syscall) + { + case SYS_TEST: + ret = sys_test(); + break; + case SYS_PUTC: + ret = sys_putc(arg1); + break; + default: + ret = -1; + dprintln("Unknown syscall"); + break; + } + + return ret; + } + +} \ No newline at end of file diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index 54306332a6..3c5cfdf347 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #include #include @@ -75,6 +77,14 @@ namespace BAN::Formatter } +extern "C" uintptr_t g_rodata_start; +extern "C" uintptr_t g_rodata_end; + +extern "C" uintptr_t g_userspace_start; +extern "C" uintptr_t g_userspace_end; + +extern void userspace_entry(); + extern "C" void kernel_main() { using namespace Kernel; @@ -124,6 +134,50 @@ extern "C" void kernel_main() MUST(Scheduler::initialize()); Scheduler& scheduler = Scheduler::get(); +#if 1 + MUST(scheduler.add_thread(MUST(Thread::create( + [] (void*) + { + MMU::get().allocate_range((uintptr_t)&g_userspace_start, (uintptr_t)&g_userspace_end - (uintptr_t)&g_userspace_start, MMU::Flags::UserSupervisor | MMU::Flags::Present); + MMU::get().allocate_range((uintptr_t)&g_rodata_start, (uintptr_t)&g_rodata_end - (uintptr_t)&g_rodata_start, MMU::Flags::UserSupervisor | MMU::Flags::Present); + + void* userspace_stack = kmalloc(4096, 4096); + ASSERT(userspace_stack); + MMU::get().allocate_page((uintptr_t)userspace_stack, MMU::Flags::UserSupervisor | MMU::Flags::ReadWrite | MMU::Flags::Present); + + BOCHS_BREAK(); + +#if ARCH(x86_64) + asm volatile( + "pushq %0;" + "pushq %1;" + "pushfq;" + "pushq %2;" + "pushq %3;" + "iretq;" + :: "r"((uintptr_t)0x20 | 3), "r"((uintptr_t)userspace_stack + 4096), "r"((uintptr_t)0x18 | 3), "r"(userspace_entry) + ); +#else + asm volatile( + "movl %0, %%eax;" + "movw %%ax, %%ds;" + "movw %%ax, %%es;" + "movw %%ax, %%fs;" + "movw %%ax, %%gs;" + + "movl %1, %%esp;" + "pushl %0;" + "pushl %1;" + "pushfl;" + "pushl %2;" + "pushl %3;" + "iret;" + :: "r"((uintptr_t)0x20 | 3), "r"((uintptr_t)userspace_stack + 4096), "r"((uintptr_t)0x18 | 3), "r"(userspace_entry) + ); +#endif + } + )))); +#else MUST(scheduler.add_thread(MUST(Thread::create( [](void* terminal_driver) { @@ -144,6 +198,7 @@ extern "C" void kernel_main() shell->run(); }, tty1 )))); +#endif scheduler.start(); ASSERT(false); } \ No newline at end of file diff --git a/kernel/userspace/userspace.cpp b/kernel/userspace/userspace.cpp new file mode 100644 index 0000000000..a152a64569 --- /dev/null +++ b/kernel/userspace/userspace.cpp @@ -0,0 +1,28 @@ +#include +#include + +#define USERSPACE __attribute__((section(".userspace"))) + +USERSPACE int syscall(int syscall, void* arg1 = nullptr, void* arg2 = nullptr, void* arg3 = nullptr) +{ + int ret; + asm volatile("int $0x80" : "=a"(ret) : "a"(syscall), "b"(arg1), "c"(arg2), "d"(arg3) : "memory"); + return ret; +} + +USERSPACE void user_putc(char ch) +{ + syscall(SYS_PUTC, (void*)(uintptr_t)ch); +} + +USERSPACE void print(const char* str) +{ + while (*str) + user_putc(*str++); +} + +USERSPACE void userspace_entry() +{ + BAN::Formatter::println(user_putc, "Hello {}!", "World"); + for (;;); +}