diff --git a/TODO b/TODO index a9d5dee..83f6358 100644 --- a/TODO +++ b/TODO @@ -18,7 +18,8 @@ TODO [x] PIT [ ] RTC [ ] HPET -[ ] System calls +[x] System calls +[ ] Separate syscall sources into individual files [ ] Userspace [x] Processes/Tasks [x] Scheduler diff --git a/docs/syscalls.txt b/docs/syscalls.txt index bf21ded..5110aaf 100644 --- a/docs/syscalls.txt +++ b/docs/syscalls.txt @@ -1,6 +1,21 @@ System Calls ============ +System calls are a way of interfacing with the kernel from userspace. + +Calling +------- +System calls are called via interrupt 0x80. Arguments can be passed through +registers in this order with EAX containing the system call number (see [Table](#Table)) +and arguments in EBX, ECX, EDX, ESI, EDI and EBP respectively. + +Table +----- + + +Syscalls +-------- + pid_t fork(void); Creates a child process. diff --git a/kernel/include/isr.h b/kernel/include/isr.h index 98f6b86..1e693fc 100644 --- a/kernel/include/isr.h +++ b/kernel/include/isr.h @@ -17,7 +17,7 @@ typedef void (*isr_handler_ptr)(struct isr_int_frame* iframe); int isr_init(void); void isr_register(uint8_t i, isr_handler_ptr handler); -int isr_handle_interrupt(struct isr_int_frame iframe); +void isr_handle_interrupt(struct isr_int_frame iframe); // Assembly definitions (isr.s) extern void isr_return(void); diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h index 3f5819c..e060c53 100644 --- a/kernel/include/syscall.h +++ b/kernel/include/syscall.h @@ -1,8 +1,15 @@ #ifndef _SYSCALL_H #define _SYSCALL_H +#include #include -int syscall_handler(struct isr_int_frame* iframe) { (void)iframe; return 1; } +#define SYSCALL_MAX 2 +#define SYS_EXIT 0 +#define SYS_TEST 1 + +int syscall_init(void); +void syscall_register(size_t idx, void* handler); +void syscall_handler(struct isr_int_frame* iframe); #endif diff --git a/kernel/src/bootloader.c b/kernel/src/bootloader.c index 8ac5615..bbc45e8 100644 --- a/kernel/src/bootloader.c +++ b/kernel/src/bootloader.c @@ -79,6 +79,8 @@ int boot_init_mb1(void* ptr, uint32_t magic) { // TODO: APM table // TODO: VBE table // TODO: Framebuffer + + debugf("[boot] Initiated with MultiBoot 1\n"); return 0; } diff --git a/kernel/src/isr.c b/kernel/src/isr.c index 4255ec2..0f1eb3b 100644 --- a/kernel/src/isr.c +++ b/kernel/src/isr.c @@ -85,7 +85,7 @@ void isr_send_eoi(uint8_t irq) { } // TODO: Write fault handlers and make this more robust -int isr_handle_interrupt(struct isr_int_frame iframe) { +void isr_handle_interrupt(struct isr_int_frame iframe) { if (iframe.interrupt < 32) { // ISRs 0-31 - Exceptions if (iframe.error) debugf("[kernel] Error code: 0x%08x\n", iframe.error); @@ -97,9 +97,7 @@ int isr_handle_interrupt(struct isr_int_frame iframe) { if (irq_handlers[irq]) irq_handlers[irq](&iframe); } else if (iframe.interrupt == 128) { // ISR 128 - System call - return syscall_handler(&iframe); + syscall_handler(&iframe); } - - return 0; } diff --git a/kernel/src/kernel.c b/kernel/src/kernel.c index 6f15683..b29b1b4 100644 --- a/kernel/src/kernel.c +++ b/kernel/src/kernel.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -10,20 +11,16 @@ #include #include -void test(void); - __noreturn void kmain(void* ptr, uint32_t magic) { - if (boot_init_mb1(ptr, magic) != 0) panic("Unsupported bootloader."); - // Serial console for debugging if (serial_init(COM1) != 0) panic("Failed to initialize Serial driver."); - debugf("\x1b[H\x1b[J\x1b[0mkern. \x1b[36m(serial console)\x1b[0m\n\n"); + + // Load structures from bootloader + if (boot_init_mb1(ptr, magic) != 0) panic("Unsupported bootloader."); // System init if (gdt_init() != 0) panic("Failed to initalize GDT."); - debugf("[gdt] Segment selectors: NULL: 0x%04x, KCODE: 0x%04x, KDATA: 0x%04x, UCODE: 0x%04x, UDATA: 0x%04x, TSS: 0x%04x\n", - GDT_NULL, GDT_KERNEL_CODE, GDT_KERNEL_DATA, GDT_USER_CODE, GDT_USER_DATA, GDT_TSS); if (isr_init() != 0) panic("Failed to initalize ISRs."); if (pag_init() != 0) panic("Failed to initalize Paging."); @@ -36,38 +33,16 @@ void kmain(void* ptr, uint32_t magic) { tty_puts("kern.\n\n"); if (timer_init() != 0) panic("Failed to initialize timer."); + if (syscall_init() != 0) panic("Failed to initialize syscalls."); if (task_init() != 0) panic("Failed to initialize tasking."); - // Create a temporary test task - task_create(task_create_id(), (uint32_t)test, 1, pag_get_pagedir(), 0, NULL); + char* s = "Hello, World!"; + __asm__ volatile("int $0x80" :: "a"(SYS_TEST), "b"(s)); - size_t delay = 0; - while (1) { - delay++; - - if (delay < 0x1FFFFFF) continue; - delay = 0; - - tty_puts("[kernel] Hello!\n"); - } - - // TODO: Syscalls // TODO: Interprocess communication // TODO: Load & run /sbin/init - panic("kmain() reached end."); -} - -// An imaginary second task -void test(void) { - size_t delay = 0; - while (1) { - delay++; - - if (delay < 0x2FFFFFF) continue; - delay = 0; - - tty_puts("[test] Hello!\n"); - } + // We don't want to halt + while (1); } diff --git a/kernel/src/serial.c b/kernel/src/serial.c index a199d79..a377f6a 100644 --- a/kernel/src/serial.c +++ b/kernel/src/serial.c @@ -17,6 +17,8 @@ int serial_init(int dev) { if (inb(dev + 0) != 0xAE) return 1; outb(dev + 4, 0x0F); // non-loopback, IRQs enabled, OUT#1 and OUT#2 bits enabled + debugf("\x1b[H\x1b[JSerial display initiated!\n\n"); + return 0; } diff --git a/kernel/src/syscall.c b/kernel/src/syscall.c new file mode 100644 index 0000000..0a29dd4 --- /dev/null +++ b/kernel/src/syscall.c @@ -0,0 +1,66 @@ +#include +#include +#include + +#include + +// Syscall table +void* syscalls[SYSCALL_MAX] = { 0 }; + +void sys_exit(int code) { + debugf("[syscall] Task #%d exited with code %d.\n", task_current->id, code); + task_kill(task_current->id); +} + +void sys_test(char* msg) { + debugf("[syscall] Test: %s\n", msg); +} + +int syscall_init(void) { + syscall_register(SYS_EXIT, (void*)sys_exit); + syscall_register(SYS_TEST, (void*)sys_test); + + debugf("[syscall] Initiated syscalls!\n"); + + return 0; +} + +void syscall_register(size_t idx, void* handler) { + if (idx > SYSCALL_MAX) { + debugf("[syscall] Failed to register syscall #%d.\n", idx); + return; + } + + syscalls[idx] = handler; +} + +void syscall_handler(struct isr_int_frame* iframe) { + size_t nr = iframe->eax; + if (nr > SYSCALL_MAX || !syscalls[nr]) { + iframe->eax = -1; + debugf("[syscall] Tried to call syscall #%d which doesn't exist.\n", nr); + return; + } + + void* handler = syscalls[nr]; + + int ret; + debugf("0x%08x\n", &ret); + __asm__ volatile( + "push %1\n" + "push %2\n" + "push %3\n" + "push %4\n" + "push %5\n" + "push %6\n" + "call *%7\n" + "add $24, %%esp\n" + "mov %%eax, %0\n" + : "=a"(ret) + : "g"(iframe->ebp), "g"(iframe->edi), "g"(iframe->esi), + "g"(iframe->edx), "g"(iframe->ecx), "g"(iframe->ebx), + "g"(handler) + ); + iframe->eax = ret; +} + diff --git a/kernel/src/timer.c b/kernel/src/timer.c index 0689301..7c24bbd 100644 --- a/kernel/src/timer.c +++ b/kernel/src/timer.c @@ -34,7 +34,7 @@ void pit_phase(uint8_t ch, uint8_t mode, uint32_t hz) { uint32_t div = PIT_DIV / hz; outb(PIT_CH0 + ch, div & 0xFF); outb(PIT_CH0 + ch, div >> 8); - debugf("[PIT] Set PIT divisor to %d (%d Hz).\n", div, hz); + debugf("[pit] Set PIT divisor to %d (%d Hz).\n", div, hz); sti(); } diff --git a/kernel/src/tty.c b/kernel/src/tty.c index 0ea14f9..0dbc619 100644 --- a/kernel/src/tty.c +++ b/kernel/src/tty.c @@ -28,6 +28,8 @@ int tty_init(void) { tty_ctx.buf = (uint8_t*)KERNEL_FRAMEBUF; tty_clear(); + debugf("[tty] Initiated %dx%d VGA display to TTY.\n", VGA_WIDTH, VGA_HEIGHT); + return 0; }