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
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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&);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue