Skip to content

Commit

Permalink
Syscalls working
Browse files Browse the repository at this point in the history
  • Loading branch information
Twometer committed Jan 17, 2021
1 parent 7fe39a7 commit 5f089f8
Show file tree
Hide file tree
Showing 15 changed files with 208 additions and 29 deletions.
6 changes: 4 additions & 2 deletions Nekofile
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
; Constants
CCFLAGS = -std=gnu++11 -ffreestanding -mno-red-zone -fno-exceptions -nostdlib -Wall -Wextra -fno-pie -fno-rtti -O2 -mgeneral-regs-only

; Tools
; Assembler
[asm, multi]:
nasm -f {format=bin} {input} -o {output}

; Kernel compiler
[kcc, single]:
neko-gcc {input} -o {output} -T kernel.ld {CCFLAGS} {include}
neko-gcc {input} -o {output} -D __KERNEL -T kernel.ld {CCFLAGS} {include}

; Userspace compiler (TODO)
[cc, single]:
neko-gcc -c {input} -o {output} {CCFLAGS} {include}

Expand Down
16 changes: 10 additions & 6 deletions kernel/arch/interrupts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#define TYPE_INTERRUPT_GATE 0x8e
#define TYPE_TRAP_GATE 0x8f
#define TYPE_USER_INTERRUPT (TYPE_INTERRUPT_GATE | 0b01100000)

using namespace Kernel;

Expand Down Expand Up @@ -256,7 +257,7 @@ void Interrupts::SetupIdt()
SetIdtEntry(45, TYPE_INTERRUPT_GATE, (unsigned long)irq13);
SetIdtEntry(46, TYPE_INTERRUPT_GATE, (unsigned long)irq14);
SetIdtEntry(47, TYPE_INTERRUPT_GATE, (unsigned long)irq15);
SetIdtEntry(128, TYPE_INTERRUPT_GATE, (unsigned long)irq128);
SetIdtEntry(128, TYPE_INTERRUPT_GATE | TYPE_USER_INTERRUPT, (unsigned long)irq128);

// build idt descriptor
unsigned long idt_ptr[2];
Expand All @@ -268,14 +269,20 @@ void Interrupts::SetupIdt()
load_idt(idt_ptr);
}

void Interrupts::WaitForInt()
{
asm volatile("sti");
asm volatile("hlt");
}

void Interrupts::Enable()
{
asm("sti");
asm volatile("sti");
}

void Interrupts::Disable()
{
asm("cli");
asm volatile("cli");
}

void Interrupts::SetIdtEntry(unsigned int interrupt, unsigned char type, unsigned long address)
Expand All @@ -295,9 +302,6 @@ void Interrupts::HandleException(unsigned int vector, struct interrupt_frame *fr

void Interrupts::HandleInterrupt(unsigned int interrupt)
{
if (interrupt == 0x80)
printf("SYSCALL!\n");

RegisterStates *states = &register_states;
for (size_t i = 0; i < entries.Size(); i++)
{
Expand Down
2 changes: 1 addition & 1 deletion kernel/device/cpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
void Device::CPU::Halt()
{
for (;;)
asm("hlt");
asm volatile("hlt");
}
2 changes: 2 additions & 0 deletions kernel/include/kernel/interrupts.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ namespace Kernel

static void Disable();

static void WaitForInt();

static void HandleException(unsigned int vector, struct interrupt_frame *frame);

static void SetIdtEntry(unsigned int interrupt, unsigned char type, unsigned long address);
Expand Down
4 changes: 3 additions & 1 deletion kernel/include/kernel/stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ namespace Kernel
public:
Stack(void *stack_bottom, size_t size);

~Stack();
Stack(void *stack_ptr);

void Push(uint32_t data);

uint32_t Pop();

void *GetStackPtr();
};

Expand Down
30 changes: 30 additions & 0 deletions kernel/include/kernel/syscallhandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef _SYSCALLHANDLER_H
#define _SYSCALLHANDLER_H

#include <nk/singleton.h>
#include <nk/vector.h>
#include <sys/syscall.h>
#include <kernel/interrupts.h>

namespace Kernel
{
typedef uint32_t (*syscall_t)(void *);

class SyscallHandler : public InterruptHandler
{
DECLARE_SINGLETON(SyscallHandler)
private:
nk::Vector<syscall_t> syscalls;

public:
void Register();

private:
void HandleInterrupt(unsigned int interrupt, RegisterStates *regs) override;

void AddSyscall(uint32_t number, syscall_t call);
};

}; // namespace Kernel

#endif
19 changes: 11 additions & 8 deletions kernel/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
#include <kernel/panic.h>
#include <kernel/interrupts.h>
#include <kernel/timemanager.h>
#include <kernel/syscallhandler.h>
#include <device/devicemanager.h>
#include <device/pit.h>
#include <memory/memorymap.h>
#include <memory/pagemanager.h>
#include <memory/pagedirectory.h>
#include <sys/syscall.h>
#include <tasks/scheduler.h>
#include <stdio.h>

Expand Down Expand Up @@ -43,10 +45,11 @@ void testExitingThread()

void ring3Thread()
{
for (;;)
{
;
}
const char *data = "Hello from userspace :3\n";
syscall(SYS_PRINT, data);

uint32_t exit_code = 0;
syscall(SYS_TEXIT, &exit_code);
}

extern "C"
Expand Down Expand Up @@ -148,6 +151,7 @@ extern "C"

printf("Setting up interrupts\n");
Interrupts::SetupIdt();
SyscallHandler::GetInstance()->Register();

printf("Setting up devices\n");
DeviceManager::Initialize();
Expand All @@ -160,13 +164,13 @@ extern "C"
printf("Current time and date: %d.%d.%d %d:%d:%d\n", time.day, time.month, time.year, time.hour, time.minute, time.second);

// map a new page for testing
vaddress_t test_addr = (vaddress_t)0xA0000000;
/*vaddress_t test_addr = (vaddress_t)0xA0000000;
auto *pageframe = pagemanager.AllocPageframe();
pageDir.MapPage(pageframe, test_addr, PAGE_BIT_READ_WRITE);
*test_addr = 0xAF;
printf("reading from %x: %x\n", test_addr, *test_addr);
printf("reading from %x: %x\n", test_addr, *test_addr);*/

/*PageDirectory test_dir(pageDir);
printf("now we have our own page directory :o\n");
Expand Down Expand Up @@ -205,8 +209,7 @@ extern "C"

// Kernel initialized, let the scheduler take over
printf("System boot complete\n");
Interrupts::Enable();
asm("hlt");
Interrupts::WaitForInt();

// If we got back here, something went *seriously* wrong
Kernel::Panic("kernel_main", "Kernel has exited, this should not happen.");
Expand Down
16 changes: 15 additions & 1 deletion kernel/stack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,35 @@

namespace Kernel
{

Stack::Stack(void *stack_bottom, size_t size)
{
this->stack_bottom = (uint8_t *)stack_bottom;
this->stack_top = this->stack_bottom + size;
this->stack_ptr = this->stack_top;
}

Stack::Stack(void *stack_ptr)
{
this->stack_bottom = nullptr;
this->stack_top = nullptr;
this->stack_ptr = (uint8_t *)stack_ptr;
}

void Stack::Push(uint32_t data)
{
size_t data_size = sizeof(data);
stack_ptr -= data_size;
memcpy(stack_ptr, &data, data_size);
}

uint32_t Stack::Pop()
{
uint32_t *ptr = (uint32_t *)stack_ptr;
stack_ptr += sizeof(uint32_t);
return *ptr;
}

void *Stack::GetStackPtr()
{
return stack_ptr;
Expand Down
71 changes: 71 additions & 0 deletions kernel/syscallhandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include <kernel/syscallhandler.h>
#include <kernel/stack.h>
#include <tasks/thread.h>

namespace Kernel
{
DEFINE_SINGLETON(SyscallHandler)

uint32_t syscall_print(void *param)
{
printf("%s", param);
return 0;
}

uint32_t syscall_texit(void *param)
{
uint32_t exit_code = *(uint32_t *)(param);
printf("UserThread %d exited with exit code %d\n", Thread::current->id, exit_code);
Thread::current->Kill();
return 0;
}

SyscallHandler::SyscallHandler()
{
}

void SyscallHandler::Register()
{
AddSyscall(SYS_TEXIT, syscall_texit);
AddSyscall(SYS_PRINT, syscall_print);
Interrupts::AddHandler(0x80, this);
}

void SyscallHandler::HandleInterrupt(unsigned int, RegisterStates *regs)
{
// When the interrupt is called, ESP is saved to the regs state.
// At that point however, it is already the kernel's ESP0. The
// user-mode stack pointer was pushed to the stack by the CPU.
// The value at ESP+12 therefore gets us the address of where
// the user thread's stack is located. There, the syscall params
// are stored.
auto user_stack_ptr = *(uint32_t *)(regs->esp + 12);

// For easy access to the struct, we create ourselves a "virtual"
// stack
Stack stack((void *)user_stack_ptr);
stack.Pop(); // The return pointer - we don't need that
uint32_t syscall_num = stack.Pop(); // Syscall number
void *param_ptr = (void *)stack.Pop(); // Pointer to the param struct
uint32_t *retval = (uint32_t *)stack.GetStackPtr(); // Stack now points at the retval ptr

auto syscall_ptr = syscalls.At(syscall_num);
if (syscall_ptr == nullptr)
{
*retval = -1;
printf("warn: Thread %d attempted invalid syscall %x\n", Thread::current->id, syscall_num);
return;
}
else
{
*retval = syscall_ptr(param_ptr);
}
}

void SyscallHandler::AddSyscall(uint32_t number, syscall_t call)
{
syscalls.Reserve(number);
syscalls.At(number) = call;
}

} // namespace Kernel
16 changes: 7 additions & 9 deletions kernel/tasks/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <tasks/thread.h>
#include <tasks/scheduler.h>
#include <memory/pagemanager.h>
#include <sys/syscall.h>

using namespace Memory;

Expand All @@ -16,18 +17,15 @@ namespace Kernel
static void thread_exit_func_krnl()
{
auto curThread = Thread::current;
printf("Thread %x died\n", curThread->id);
printf("KernelThread %x died\n", curThread->id);
curThread->threadState = ThreadState::Dead;
asm("hlt"); // wait for the scheduler to get us out of here
Interrupts::WaitForInt(); // wait for the scheduler to get us out of here
}

static void thread_exit_func_user()
{
// TODO replace with syscall to signal thread exit
auto curThread = Thread::current;
printf("Usermode Thread %x died\n", curThread->id);
curThread->threadState = ThreadState::Dead;
asm("hlt");
uint32_t exit_code = 0;
syscall(SYS_TEXIT, &exit_code);
}

Thread::Thread(ThreadMain entryPoint, Ring ring)
Expand Down Expand Up @@ -96,14 +94,14 @@ namespace Kernel
{
// TODO: don't wait for the interrupt, but yield instantly...?
threadState = ThreadState::Yielded;
asm("hlt");
Interrupts::WaitForInt();
}

void Thread::Kill()
{
// just set our state to dead and wait for the scheduler to annihilate us
threadState = ThreadState::Dead;
asm("hlt");
Interrupts::WaitForInt();
}

uint32_t Thread::GetRuntime()
Expand Down
1 change: 1 addition & 0 deletions libc/include/stdlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extern "C"
#endif

__attribute__((__noreturn__)) void abort(void);
__attribute__((__noreturn__)) void exit(int retval);
void *malloc(size_t size);
void free(void *ptr);

Expand Down
28 changes: 28 additions & 0 deletions libc/include/sys/syscall.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef _SYS_SYSCALL_H
#define _SYS_SYSCALL_H

#include <stdint.h>

#define SYS_INVAL 0
#define SYS_TEXIT 1
#define SYS_PRINT 2

#ifdef __cplusplus
extern "C"
{
#endif

typedef struct syscall_invoke
{
uint32_t number;
const void *params;
uint32_t retval;
} syscall_invoke_t;

uint32_t syscall(uint32_t number, const void *params);

#ifdef __cplusplus
}
#endif

#endif
Loading

0 comments on commit 5f089f8

Please sign in to comment.