From 706c69d40fcc46e7d7f170dab932d3c7fcc7c34e Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Fri, 13 Feb 2015 22:44:10 +0100 Subject: Begin implementation of syscalls. --- Makefile | 4 +-- src/apps/init/Makefile | 2 +- src/apps/init/main.c | 8 ++++-- src/common/include/syscallid.h | 40 ++++++++++++++++++++++++++ src/common/libc/string.c | 2 +- src/kernel/Makefile | 2 +- src/kernel/core/idt.c | 10 +++---- src/kernel/core/interrupt.s | 4 +-- src/kernel/core/kmain.c | 3 ++ src/kernel/include/process.h | 7 +++++ src/kernel/include/syscall.h | 10 +++++++ src/kernel/user/process.c | 26 ++++++++++++++++- src/kernel/user/syscall.c | 64 ++++++++++++++++++++++++++++++++++++++++++ src/lib/include/syscall.h | 6 ++++ src/lib/libkogata/start.c | 8 +++--- src/lib/libkogata/syscall.c | 15 ++++++++-- 16 files changed, 190 insertions(+), 21 deletions(-) create mode 100644 src/common/include/syscallid.h create mode 100644 src/kernel/include/syscall.h create mode 100644 src/kernel/user/syscall.c diff --git a/Makefile b/Makefile index 246024b..d421104 100644 --- a/Makefile +++ b/Makefile @@ -2,12 +2,12 @@ DIRS = src/common/libkogata src/common/libc src/common/libalgo src/kernel src/li all: for dir in $(DIRS); do \ - $(MAKE) -C $$dir; \ + $(MAKE) -C $$dir || exit 1; \ done rebuild: for dir in $(DIRS); do \ - $(MAKE) -C $$dir rebuild; \ + $(MAKE) -C $$dir rebuild || exit 1; \ done clean: diff --git a/src/apps/init/Makefile b/src/apps/init/Makefile index e56d4c0..c54bbfb 100644 --- a/src/apps/init/Makefile +++ b/src/apps/init/Makefile @@ -1,7 +1,7 @@ OBJ = main.o -LIB = ../../lib/libkogata/libkogata.lib +LIB = ../../lib/libkogata/libkogata.lib ../../common/libc/libc.lib CFLAGS = -I ./include -I ../../common/include -I ../../lib/include diff --git a/src/apps/init/main.c b/src/apps/init/main.c index 47d7bba..6a9cd5f 100644 --- a/src/apps/init/main.c +++ b/src/apps/init/main.c @@ -1,9 +1,13 @@ #include +#include + +#include #include int main(int argc, char **argv) { - asm volatile("int $0x40"); - while(true); + dbg_print("Hello, world! from user process.\n"); + + return 0; } diff --git a/src/common/include/syscallid.h b/src/common/include/syscallid.h new file mode 100644 index 0000000..bfcd37a --- /dev/null +++ b/src/common/include/syscallid.h @@ -0,0 +1,40 @@ +#pragma once + + +#define SC_MAX 128 // maximum number of syscalls + +#define SC_DBG_PRINT 0 +#define SC_EXIT 1 +#define SC_YIELD 2 + +#define SC_MMAP 10 +#define SC_MMAP_FILE 11 +#define SC_MCHMAP 12 +#define SC_MUNMAP 13 + +#define SC_CREATE 20 +#define SC_DELETE 21 +#define SC_MOVE 22 +#define SC_STAT 23 +#define SC_IOCTL 24 + +#define SC_OPEN 30 +#define SC_CLOSE 31 +#define SC_READ 32 +#define SC_WRITE 33 +#define SC_READDIR 34 +#define SC_STAT_OPEN 35 // stat on open file handle +#define SC_GET_MODE 36 // get mode for open file handle + +#define SC_MAKE_FS 40 +#define SC_FS_ADD_SRC 41 +#define SC_RM_FS 42 + +#define SC_NEW_PROC 50 +#define SC_BIND_FS 51 // bind FS to children process +#define SC_PROC_EXEC 52 // execute binary in process + +// much more to do + + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/common/libc/string.c b/src/common/libc/string.c index f6c27b4..7aa155d 100644 --- a/src/common/libc/string.c +++ b/src/common/libc/string.c @@ -33,7 +33,7 @@ char *strncpy(char *dest, const char *src, size_t n) { size_t x = strlen(src + 1); if (n < x) x = n; memcpy(dest, src, x); - if (n > x) memset(dest + n, 0, n - x); + if (n > x) memset(dest + x, 0, n - x); return (char*)dest; } diff --git a/src/kernel/Makefile b/src/kernel/Makefile index cfaadc3..a8e1c65 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -2,7 +2,7 @@ OBJ = core/loader.o core/kmain.o core/dbglog.o core/sys.o \ core/gdt.o core/idt.o core/interrupt.o core/context_switch.o core/thread.o \ core/frame.o core/paging.o core/region.o core/kmalloc.o \ - user/vfs.o user/nullfs.o user/process.o user/elf.o + user/vfs.o user/nullfs.o user/process.o user/elf.o user/syscall.o LIB = ../common/libc/libc.lib ../common/libkogata/libkogata.lib ../common/libalgo/libalgo.lib diff --git a/src/kernel/core/idt.c b/src/kernel/core/idt.c index e1862c9..0459a21 100644 --- a/src/kernel/core/idt.c +++ b/src/kernel/core/idt.c @@ -4,6 +4,7 @@ #include #include #include +#include struct idt_entry { uint16_t base_lo; //Low part of address to jump to @@ -89,7 +90,7 @@ static isr_handler_t irq_handlers[16] = {0}; static isr_handler_t ex_handlers[32] = {0}; /* Called in interrupt.s when an exception fires (interrupt 0 to 31) */ -void idt_exHandler(registers_t *regs) { +void idt_ex_handler(registers_t *regs) { if (ex_handlers[regs->int_no] != 0) { ex_handlers[regs->int_no](regs); } else { @@ -105,7 +106,7 @@ void idt_exHandler(registers_t *regs) { } /* Called in interrupt.s when an IRQ fires (interrupt 32 to 47) */ -void idt_irqHandler(registers_t *regs) { +void idt_irq_handler(registers_t *regs) { if (regs->err_code > 7) { outb(0xA0, 0x20); } @@ -117,9 +118,8 @@ void idt_irqHandler(registers_t *regs) { } /* Caled in interrupt.s when a syscall is called */ -void idt_syscallHandler(registers_t *regs) { - dbg_printf("Syscall %i (not implemented yet)\n", regs->int_no); - // do nothing, yet. +void idt_syscall_handler(registers_t *regs) { + syscall_handler(regs); } /* For internal use only. Sets up an entry of the IDT with given parameters. */ diff --git a/src/kernel/core/interrupt.s b/src/kernel/core/interrupt.s index d40fff0..8fb71e8 100644 --- a/src/kernel/core/interrupt.s +++ b/src/kernel/core/interrupt.s @@ -1,7 +1,7 @@ ;************************************************************************************ %macro COMMONSTUB 1 -[EXTERN idt_%1Handler] +[EXTERN idt_%1_handler] %1_common_stub: pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax @@ -19,7 +19,7 @@ ; (passing it directly results in GCC trashing the data when doing optimisations) mov eax, esp push eax - call idt_%1Handler + call idt_%1_handler add esp, 4 pop eax ; reload the original data segment descriptor diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c index 5572ac4..ee6d8b2 100644 --- a/src/kernel/core/kmain.c +++ b/src/kernel/core/kmain.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -270,6 +271,8 @@ void kmain(multiboot_info_t *mbd, int32_t mb_magic) { kmalloc_setup(); kmalloc_test(kernel_data_end); + setup_syscalls(); + // enter multi-threading mode // interrupts are enabled at this moment, so all // code run from now on should be preemtible (ie thread-safe) diff --git a/src/kernel/include/process.h b/src/kernel/include/process.h index 661aaa6..82ba8dd 100644 --- a/src/kernel/include/process.h +++ b/src/kernel/include/process.h @@ -35,15 +35,22 @@ process_t *new_process(process_t *parent); // void delete_process(process_t *p); // TODO define semantics for freeing stuff pagedir_t *proc_pagedir(process_t *p); +int proc_pid(process_t *p); bool start_process(process_t *p, proc_entry_t entry); // maps a region for user stack bool proc_add_fs(process_t *p, fs_t *fs, const char* name); fs_t *proc_find_fs(process_t *p, const char* name); +bool proc_rm_fs(process_t *p, const char* name); bool mmap(process_t *proc, void* addr, size_t size, int mode); // create empty zone bool mmap_file(process_t *proc, fs_handle_t *h, size_t offset, void* addr, size_t size, int mode); bool mchmap(process_t *proc, void* addr, int mode); bool munmap(process_t *proc, void* addr); +// for syscalls : check that process is authorized to do that +// (if not, process exits with a segfault) +void probe_for_read(const void* addr, size_t len); +void probe_for_write(const void* addr, size_t len); + /* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h new file mode 100644 index 0000000..c6c0ed4 --- /dev/null +++ b/src/kernel/include/syscall.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +void setup_syscalls(); + +void syscall_handler(registers_t *regs); + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c index 0f4892d..579c33d 100644 --- a/src/kernel/user/process.c +++ b/src/kernel/user/process.c @@ -118,6 +118,10 @@ pagedir_t *proc_pagedir(process_t *p) { return p->pd; } +int proc_pid(process_t *p) { + return p->pid; +} + // ================================== // // MANAGING FILESYSTEMS FOR PROCESSES // // ================================== // @@ -143,7 +147,7 @@ fs_t *proc_find_fs(process_t *p, const char* name) { // USER MEMORY REGION MANAGEMENT // // ============================= // -static user_region_t *find_user_region(process_t *proc, void* addr) { +static user_region_t *find_user_region(process_t *proc, const void* addr) { for (user_region_t *it = proc->regions; it != 0; it = it->next) { if (addr >= it->addr && addr < it->addr + it->size) return it; } @@ -287,4 +291,24 @@ static void proc_usermem_pf(void* p, registers_t *regs, void* addr) { } } +void probe_for_read(const void* addr, size_t len) { + process_t *proc = current_process(); + user_region_t *r = find_user_region(proc, addr); + if (r == 0 || addr + len > r->addr + r->size || !(r->mode & MM_READ)) { + dbg_printf("Access violation on read at 0x%p len 0x%p in process %d : exiting.\n", + addr, len, proc->pid); + exit(); + } +} + +void probe_for_write(const void* addr, size_t len) { + process_t *proc = current_process(); + user_region_t *r = find_user_region(proc, addr); + if (r == 0 || addr + len > r->addr + r->size || !(r->mode & MM_WRITE)) { + dbg_printf("Access violation on write at 0x%p len 0x%p in process %d : exiting.\n", + addr, len, proc->pid); + exit(); + } +} + /* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/user/syscall.c b/src/kernel/user/syscall.c new file mode 100644 index 0000000..563957c --- /dev/null +++ b/src/kernel/user/syscall.c @@ -0,0 +1,64 @@ +#include +#include +#include + +#include + +typedef uint32_t (*syscall_handler_t)(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); + +static syscall_handler_t sc_handlers[SC_MAX] = { 0 }; + +// ==================== // +// THE SYSCALLS CODE !! // +// ==================== // + +static uint32_t exit_sc(uint32_t code, uint32_t uu1, uint32_t uu2, uint32_t uu3, uint32_t uu4) { + dbg_printf("Proc %d exit with code %d\n", proc_pid(current_process()), code); + // TODO : use code... and process exiting is not supposed to be done this way + + exit(); + return 0; +} + +static uint32_t yield_sc() { + yield(); + return 0; +} + +static uint32_t dbg_print_sc(uint32_t x, uint32_t uu1, uint32_t uu2, uint32_t uu3, uint32_t uu4) { + const char* addr = (const char*)x; + probe_for_read(addr, 256); + + char buf[256]; + memcpy(buf, addr, 256); + buf[255] = 0; + + dbg_print(buf); + + return 0; +} + +// ====================== // +// SYSCALLS SETUP ROUTINE // +// ====================== // + +void setup_syscalls() { + sc_handlers[SC_EXIT] = exit_sc; + sc_handlers[SC_YIELD] = yield_sc; + sc_handlers[SC_DBG_PRINT] = dbg_print_sc; +} + +void syscall_handler(registers_t *regs) { + ASSERT(regs->int_no == 64); + + if (regs->eax < SC_MAX) { + syscall_handler_t h = sc_handlers[regs->eax]; + if (h != 0) { + regs->eax = h(regs->ebx, regs->ecx, regs->edx, regs->esi, regs->edi); + } else { + regs->eax = -1; + } + } +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/include/syscall.h b/src/lib/include/syscall.h index d6df4ec..37d7302 100644 --- a/src/lib/include/syscall.h +++ b/src/lib/include/syscall.h @@ -4,9 +4,15 @@ #include #include +#include + #include #include void dbg_print(const char* str); void yield(); +void exit(int code); + +// more todo +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/libkogata/start.c b/src/lib/libkogata/start.c index 030423c..9ba7edf 100644 --- a/src/lib/libkogata/start.c +++ b/src/lib/libkogata/start.c @@ -1,12 +1,12 @@ -#include -#include -#include +#include extern int main(int, char**); void __libkogata_start() { // TODO : setup - main(0, 0); + int ret = main(0, 0); + + exit(ret); } diff --git a/src/lib/libkogata/syscall.c b/src/lib/libkogata/syscall.c index 234b9ff..dc7e648 100644 --- a/src/lib/libkogata/syscall.c +++ b/src/lib/libkogata/syscall.c @@ -1,10 +1,21 @@ #include #include +#include + void dbg_print(const char* str) { - // TODO + + char buf[256]; + strncpy(buf, str, 256); + buf[255] = 0; + + asm volatile("int $0x40"::"a"(SC_DBG_PRINT),"b"(buf)); } void yield() { - // TODO + asm volatile("int $0x40"::"a"(SC_YIELD)); +} + +void exit(int code) { + asm volatile("int $0x40"::"a"(SC_EXIT),"b"(code)); } -- cgit v1.2.3