From 8637959289f86b28f88764c626c4c8fc8c9d213b Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 12 Apr 2023 17:51:36 +0300 Subject: [PATCH] Kernel: We can create basic userspace processes These are still allocated on the kernel memory --- kernel/arch/i386/Thread.S | 21 ++++++++++- kernel/arch/x86_64/Thread.S | 12 ++++++- kernel/include/kernel/Process.h | 3 +- kernel/include/kernel/Syscall.h | 20 +++++++++-- kernel/include/kernel/Thread.h | 2 ++ kernel/kernel/Process.cpp | 20 +++++++++++ kernel/kernel/Syscall.cpp | 32 +++++++++++------ kernel/kernel/Thread.cpp | 6 ++++ kernel/kernel/kernel.cpp | 63 +++++++++------------------------ kernel/userspace/userspace.cpp | 24 +++---------- 10 files changed, 121 insertions(+), 82 deletions(-) diff --git a/kernel/arch/i386/Thread.S b/kernel/arch/i386/Thread.S index af2cb91c..0c83770b 100644 --- a/kernel/arch/i386/Thread.S +++ b/kernel/arch/i386/Thread.S @@ -25,4 +25,23 @@ continue_thread: movl 8(%esp), %ecx movl 4(%esp), %esp movl $0, %eax - jmp *%ecx \ No newline at end of file + jmp *%ecx + +# void thread_jump_userspace(uint32_t rsp, uint32_t rip) +.global thread_jump_userspace +thread_jump_userspace: + movl $0x23, %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + movl 8(%esp), %ecx + movl 4(%esp), %esp + + pushl $0x23 + pushl %esp + pushfl + pushl $0x1B + pushl %ecx + iret diff --git a/kernel/arch/x86_64/Thread.S b/kernel/arch/x86_64/Thread.S index 3c72cb17..6f47cfd9 100644 --- a/kernel/arch/x86_64/Thread.S +++ b/kernel/arch/x86_64/Thread.S @@ -23,4 +23,14 @@ start_thread: continue_thread: movq %rdi, %rsp movq $0, %rax - jmp *%rsi \ No newline at end of file + jmp *%rsi + +# void thread_jump_userspace(uint64_t rsp, uint64_t rip) +.global thread_jump_userspace +thread_jump_userspace: + pushq $0x23 + pushq %rdi + pushfq + pushq $0x1B + pushq %rsi + iretq diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 11a45d01..f7bb3486 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -23,9 +23,10 @@ namespace Kernel public: static BAN::ErrorOr> create_kernel(entry_t, void*); + static BAN::ErrorOr> create_userspace(void(*)()); ~Process(); - void exit(); + [[noreturn]] void exit(); BAN::ErrorOr add_thread(entry_t, void*); void on_thread_exit(Thread&); diff --git a/kernel/include/kernel/Syscall.h b/kernel/include/kernel/Syscall.h index f3526920..94e33f5e 100644 --- a/kernel/include/kernel/Syscall.h +++ b/kernel/include/kernel/Syscall.h @@ -1,4 +1,20 @@ #pragma once -#define SYS_TEST 0 -#define SYS_PUTC 1 \ No newline at end of file +#define SYS_EXIT 1 +#define SYS_READ 2 +#define SYS_WRITE 3 + +#include + +namespace Kernel +{ + + template + inline int syscall(int syscall, T1 arg1 = nullptr, T2 arg2 = nullptr, T3 arg3 = nullptr) + { + int ret; + asm volatile("int $0x80" : "=a"(ret) : "a"(syscall), "b"((uintptr_t)arg1), "c"((uintptr_t)arg2), "d"((uintptr_t)arg3) : "memory"); + return ret; + } + +} diff --git a/kernel/include/kernel/Thread.h b/kernel/include/kernel/Thread.h index e2bc306c..dc002135 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -29,6 +29,8 @@ namespace Kernel static BAN::ErrorOr create(entry_t, void* = nullptr, BAN::RefPtr = nullptr); ~Thread(); + void jump_userspace(uintptr_t rip); + pid_t tid() const { return m_tid; } void set_rsp(uintptr_t rsp) { m_rsp = rsp; } diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 206ea7e9..00ef6c12 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,25 @@ namespace Kernel return process; } + BAN::ErrorOr> Process::create_userspace(void(*entry)()) + { + auto process = TRY(BAN::RefPtr::create(s_next_pid++)); + TRY(process->m_working_directory.push_back('/')); + TRY(process->init_stdio()); + + TRY(process->add_thread( + [](void* entry_func) + { + Thread& current = Thread::current(); + MMU::get().allocate_range(current.stack_base(), current.stack_size(), MMU::Flags::UserSupervisor | MMU::Flags::ReadWrite | MMU::Flags::Present); + current.jump_userspace((uintptr_t)entry_func); + ASSERT_NOT_REACHED(); + }, (void*)entry + )); + + return process; + } + Process::Process(pid_t pid) : m_pid(pid) , m_tty(TTY::current()) diff --git a/kernel/kernel/Syscall.cpp b/kernel/kernel/Syscall.cpp index 6e08b353..842e41cb 100644 --- a/kernel/kernel/Syscall.cpp +++ b/kernel/kernel/Syscall.cpp @@ -1,19 +1,28 @@ #include -#include +#include #include namespace Kernel { - int sys_test() + void sys_exit() { - dprintln("hello"); + Process::current()->exit(); + } + + int sys_read(int fd, void* buffer, size_t size) + { + auto res = Process::current()->read(fd, buffer, size); + if (res.is_error()) + return res.error().get_error_code(); return 0; } - int sys_putc(void* ch) + int sys_write(int fd, const void* buffer, size_t size) { - kprint("{}", (char)(uintptr_t)ch); + auto res = Process::current()->write(fd, buffer, size); + if (res.is_error()) + return res.error().get_error_code(); return 0; } @@ -23,14 +32,17 @@ namespace Kernel (void)arg2; (void)arg3; - int ret; + int ret = 0; switch (syscall) { - case SYS_TEST: - ret = sys_test(); + case SYS_EXIT: + sys_exit(); break; - case SYS_PUTC: - ret = sys_putc(arg1); + case SYS_READ: + ret = sys_read((int)(uintptr_t)arg1, arg2, (size_t)(uintptr_t)arg3); + break; + case SYS_WRITE: + ret = sys_write((int)(uintptr_t)arg1, arg2, (size_t)(uintptr_t)arg3); break; default: ret = -1; diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 29502507..9fe1c9f3 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -10,6 +10,7 @@ namespace Kernel { + extern "C" void thread_jump_userspace(uintptr_t rsp, uintptr_t rip); template static void write_to_stack(uintptr_t& rsp, const T& value) @@ -63,6 +64,11 @@ namespace Kernel kfree(m_stack_base); } + void Thread::jump_userspace(uintptr_t rip) + { + thread_jump_userspace(rsp(), rip); + } + void Thread::on_exit() { if (m_process) diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index 07fa574f..6c2ffb2c 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -103,6 +103,7 @@ extern "C" uintptr_t g_userspace_start; extern "C" uintptr_t g_userspace_end; extern void userspace_entry(); +static void jump_userspace(); static void init2(void*); @@ -154,54 +155,10 @@ extern "C" void kernel_main() MUST(Scheduler::initialize()); Scheduler& scheduler = Scheduler::get(); -#if 0 - 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(init2, terminal_driver)))); -#endif scheduler.start(); - ASSERT(false); + + ASSERT_NOT_REACHED(); } static void init2(void* terminal_driver) @@ -220,6 +177,8 @@ static void init2(void* terminal_driver) ASSERT(tty1); DeviceManager::get().add_device(tty1); + return jump_userspace(); + MUST(Process::create_kernel( [](void*) { @@ -229,4 +188,14 @@ static void init2(void* terminal_driver) shell->run(); }, nullptr )); -} \ No newline at end of file +} + +static void jump_userspace() +{ + using namespace Kernel; + + 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); + + MUST(Process::create_userspace(userspace_entry)); +} diff --git a/kernel/userspace/userspace.cpp b/kernel/userspace/userspace.cpp index a152a645..e438640f 100644 --- a/kernel/userspace/userspace.cpp +++ b/kernel/userspace/userspace.cpp @@ -1,28 +1,12 @@ #include #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 (;;); + Kernel::syscall(SYS_WRITE, STDOUT_FILENO, "Hello World!", 12); + Kernel::syscall(SYS_EXIT); }