Kernel: We can create basic userspace processes

These are still allocated on the kernel memory
This commit is contained in:
Bananymous 2023-04-12 17:51:36 +03:00
parent 6be53668b9
commit 8637959289
10 changed files with 121 additions and 82 deletions

View File

@ -26,3 +26,22 @@ continue_thread:
movl 4(%esp), %esp movl 4(%esp), %esp
movl $0, %eax movl $0, %eax
jmp *%ecx 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

View File

@ -24,3 +24,13 @@ continue_thread:
movq %rdi, %rsp movq %rdi, %rsp
movq $0, %rax movq $0, %rax
jmp *%rsi 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

View File

@ -23,9 +23,10 @@ namespace Kernel
public: public:
static BAN::ErrorOr<BAN::RefPtr<Process>> create_kernel(entry_t, void*); static BAN::ErrorOr<BAN::RefPtr<Process>> create_kernel(entry_t, void*);
static BAN::ErrorOr<BAN::RefPtr<Process>> create_userspace(void(*)());
~Process(); ~Process();
void exit(); [[noreturn]] void exit();
BAN::ErrorOr<Thread*> add_thread(entry_t, void*); BAN::ErrorOr<Thread*> add_thread(entry_t, void*);
void on_thread_exit(Thread&); void on_thread_exit(Thread&);

View File

@ -1,4 +1,20 @@
#pragma once #pragma once
#define SYS_TEST 0 #define SYS_EXIT 1
#define SYS_PUTC 1 #define SYS_READ 2
#define SYS_WRITE 3
#include <stdint.h>
namespace Kernel
{
template<typename T1 = void*, typename T2 = void*, typename T3 = void*>
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;
}
}

View File

@ -29,6 +29,8 @@ namespace Kernel
static BAN::ErrorOr<Thread*> create(entry_t, void* = nullptr, BAN::RefPtr<Process> = nullptr); static BAN::ErrorOr<Thread*> create(entry_t, void* = nullptr, BAN::RefPtr<Process> = nullptr);
~Thread(); ~Thread();
void jump_userspace(uintptr_t rip);
pid_t tid() const { return m_tid; } pid_t tid() const { return m_tid; }
void set_rsp(uintptr_t rsp) { m_rsp = rsp; } void set_rsp(uintptr_t rsp) { m_rsp = rsp; }

View File

@ -2,6 +2,7 @@
#include <kernel/CriticalScope.h> #include <kernel/CriticalScope.h>
#include <kernel/FS/VirtualFileSystem.h> #include <kernel/FS/VirtualFileSystem.h>
#include <kernel/LockGuard.h> #include <kernel/LockGuard.h>
#include <kernel/MMU.h>
#include <kernel/Process.h> #include <kernel/Process.h>
#include <kernel/Scheduler.h> #include <kernel/Scheduler.h>
@ -20,6 +21,25 @@ namespace Kernel
return process; return process;
} }
BAN::ErrorOr<BAN::RefPtr<Process>> Process::create_userspace(void(*entry)())
{
auto process = TRY(BAN::RefPtr<Process>::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) Process::Process(pid_t pid)
: m_pid(pid) : m_pid(pid)
, m_tty(TTY::current()) , m_tty(TTY::current())

View File

@ -1,19 +1,28 @@
#include <kernel/Debug.h> #include <kernel/Debug.h>
#include <kernel/kprint.h> #include <kernel/Process.h>
#include <kernel/Syscall.h> #include <kernel/Syscall.h>
namespace Kernel 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; 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; return 0;
} }
@ -23,14 +32,17 @@ namespace Kernel
(void)arg2; (void)arg2;
(void)arg3; (void)arg3;
int ret; int ret = 0;
switch (syscall) switch (syscall)
{ {
case SYS_TEST: case SYS_EXIT:
ret = sys_test(); sys_exit();
break; break;
case SYS_PUTC: case SYS_READ:
ret = sys_putc(arg1); 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; break;
default: default:
ret = -1; ret = -1;

View File

@ -10,6 +10,7 @@
namespace Kernel namespace Kernel
{ {
extern "C" void thread_jump_userspace(uintptr_t rsp, uintptr_t rip);
template<size_t size, typename T> template<size_t size, typename T>
static void write_to_stack(uintptr_t& rsp, const T& value) static void write_to_stack(uintptr_t& rsp, const T& value)
@ -63,6 +64,11 @@ namespace Kernel
kfree(m_stack_base); kfree(m_stack_base);
} }
void Thread::jump_userspace(uintptr_t rip)
{
thread_jump_userspace(rsp(), rip);
}
void Thread::on_exit() void Thread::on_exit()
{ {
if (m_process) if (m_process)

View File

@ -103,6 +103,7 @@ extern "C" uintptr_t g_userspace_start;
extern "C" uintptr_t g_userspace_end; extern "C" uintptr_t g_userspace_end;
extern void userspace_entry(); extern void userspace_entry();
static void jump_userspace();
static void init2(void*); static void init2(void*);
@ -154,54 +155,10 @@ extern "C" void kernel_main()
MUST(Scheduler::initialize()); MUST(Scheduler::initialize());
Scheduler& scheduler = Scheduler::get(); 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)))); MUST(scheduler.add_thread(MUST(Thread::create(init2, terminal_driver))));
#endif
scheduler.start(); scheduler.start();
ASSERT(false);
ASSERT_NOT_REACHED();
} }
static void init2(void* terminal_driver) static void init2(void* terminal_driver)
@ -220,6 +177,8 @@ static void init2(void* terminal_driver)
ASSERT(tty1); ASSERT(tty1);
DeviceManager::get().add_device(tty1); DeviceManager::get().add_device(tty1);
return jump_userspace();
MUST(Process::create_kernel( MUST(Process::create_kernel(
[](void*) [](void*)
{ {
@ -230,3 +189,13 @@ static void init2(void* terminal_driver)
}, nullptr }, nullptr
)); ));
} }
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));
}

View File

@ -1,28 +1,12 @@
#include <BAN/Formatter.h> #include <BAN/Formatter.h>
#include <kernel/Syscall.h> #include <kernel/Syscall.h>
#include <unistd.h>
#define USERSPACE __attribute__((section(".userspace"))) #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() USERSPACE void userspace_entry()
{ {
BAN::Formatter::println(user_putc, "Hello {}!", "World"); Kernel::syscall(SYS_WRITE, STDOUT_FILENO, "Hello World!", 12);
for (;;); Kernel::syscall(SYS_EXIT);
} }