Kernel/Userspace: Start initial work on userspace and syscalls

This commit is contained in:
Bananymous 2023-03-13 15:32:46 +02:00
parent af854ec9e1
commit 8b8e3cbbf0
10 changed files with 231 additions and 5 deletions

View File

@ -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:

View File

@ -152,6 +152,29 @@ found:
"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()
{
asm volatile("lidt %0"::"m"(s_idtr));
@ -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();
}

View File

@ -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 = .;
}

View File

@ -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();
}

View File

@ -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

View File

@ -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 = .;
}

View File

@ -0,0 +1,4 @@
#pragma once
#define SYS_TEST 0
#define SYS_PUTC 1

44
kernel/kernel/Syscall.cpp Normal file
View File

@ -0,0 +1,44 @@
#include <kernel/Debug.h>
#include <kernel/kprint.h>
#include <kernel/Syscall.h>
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;
}
}

View File

@ -1,3 +1,4 @@
#include <kernel/Arch.h>
#include <kernel/Debug.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/GDT.h>
@ -14,6 +15,7 @@
#include <kernel/Scheduler.h>
#include <kernel/Serial.h>
#include <kernel/Shell.h>
#include <kernel/Syscall.h>
#include <kernel/TTY.h>
#include <kernel/VesaTerminalDriver.h>
@ -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);
}

View File

@ -0,0 +1,28 @@
#include <BAN/Formatter.h>
#include <kernel/Syscall.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 (;;);
}