forked from Bananymous/banan-os
Kernel: We can create basic userspace processes
These are still allocated on the kernel memory
This commit is contained in:
parent
6be53668b9
commit
8637959289
|
@ -25,4 +25,23 @@ continue_thread:
|
|||
movl 8(%esp), %ecx
|
||||
movl 4(%esp), %esp
|
||||
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
|
||||
|
|
|
@ -23,4 +23,14 @@ start_thread:
|
|||
continue_thread:
|
||||
movq %rdi, %rsp
|
||||
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
|
||||
|
|
|
@ -23,9 +23,10 @@ namespace Kernel
|
|||
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<Process>> create_kernel(entry_t, void*);
|
||||
static BAN::ErrorOr<BAN::RefPtr<Process>> create_userspace(void(*)());
|
||||
~Process();
|
||||
|
||||
void exit();
|
||||
[[noreturn]] void exit();
|
||||
|
||||
BAN::ErrorOr<Thread*> add_thread(entry_t, void*);
|
||||
void on_thread_exit(Thread&);
|
||||
|
|
|
@ -1,4 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#define SYS_TEST 0
|
||||
#define SYS_PUTC 1
|
||||
#define SYS_EXIT 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@ namespace Kernel
|
|||
static BAN::ErrorOr<Thread*> create(entry_t, void* = nullptr, BAN::RefPtr<Process> = nullptr);
|
||||
~Thread();
|
||||
|
||||
void jump_userspace(uintptr_t rip);
|
||||
|
||||
pid_t tid() const { return m_tid; }
|
||||
|
||||
void set_rsp(uintptr_t rsp) { m_rsp = rsp; }
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <kernel/CriticalScope.h>
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
#include <kernel/LockGuard.h>
|
||||
#include <kernel/MMU.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
|
||||
|
@ -20,6 +21,25 @@ namespace Kernel
|
|||
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)
|
||||
: m_pid(pid)
|
||||
, m_tty(TTY::current())
|
||||
|
|
|
@ -1,19 +1,28 @@
|
|||
#include <kernel/Debug.h>
|
||||
#include <kernel/kprint.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/Syscall.h>
|
||||
|
||||
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;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
extern "C" void thread_jump_userspace(uintptr_t rsp, uintptr_t rip);
|
||||
|
||||
template<size_t size, typename T>
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -1,28 +1,12 @@
|
|||
#include <BAN/Formatter.h>
|
||||
#include <kernel/Syscall.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue