From 277b329c5609b8172ad0c142117edfa9a08279da Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Thu, 19 Feb 2015 18:25:29 +0100 Subject: Implement basic syscalls... --- README.md | 13 +-- src/apps/init/main.c | 25 +++++ src/common/include/syscallproto.h | 44 ++++---- src/common/libc/string.c | 2 +- src/kernel/include/process.h | 8 +- src/kernel/user/process.c | 32 +++++- src/kernel/user/syscall.c | 220 ++++++++++++++++++++++++++++++++++++++ src/lib/include/syscall.h | 17 +++ src/lib/libkogata/syscall.c | 43 +++++++- 9 files changed, 371 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 81ca3e4..589c0f9 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,6 @@ I would love to have kogata fit on a 1.44MB floppy and run with a full GUI and some cool apps (remember the QNX demo floppy!). Also, I want to be able to use it on older computers and prove that such machines can still be put to use. -### Plans for the future - -* Module system for extending the kernel -* In userspace, simple Scheme-like scripting language -* The obvious stuff ;-) - ## How to build ### Requirements @@ -104,11 +98,18 @@ running the tests): * Have several threads in a single process * Better handling of errors (rather than panicing) ; userspace apps should not have the possibility of crashing the system +* How does a process transmit information (such as environment or arguments) to its children ? ### Things not sure * VFS thread safety : is the design correct ? (probably) +### Plans for the later future + +* Module system for extending the kernel +* In userspace, simple Scheme-like scripting language +* The obvious stuff ;-) + ## Licence None of the source files have a licence header because it's cumbersome. All the diff --git a/src/apps/init/main.c b/src/apps/init/main.c index 25f08e8..02fd9df 100644 --- a/src/apps/init/main.c +++ b/src/apps/init/main.c @@ -32,6 +32,31 @@ int main(int argc, char **argv) { dbg_printf("malloc test OK.\n"); dbg_print_region_info(); + fd_t f = open("dev:/", FM_READDIR); + dbg_printf("openned /: %d\n", f); + dirent_t x; + while (readdir(f, &x)) { + dbg_printf("- '%s' %p %d\n", x.name, x.st.type, x.st.size); + if (x.st.type == FT_REGULAR) { + char buf[256]; + strcpy(buf, "dev:/"); + strcpy(buf+5, x.name); + dbg_printf("trying to open %s...\n", buf); + fd_t ff = open(buf, FM_READ); + if (ff != 0) { + dbg_printf("ok, open as %d\n", ff); + char* cont = malloc(x.st.size + 1); + read(ff, 0, x.st.size, cont); + cont[x.st.size] = 0; + dbg_printf(" %s\n", cont); + close(ff); + } else { + dbg_printf("Could not open '%s'\n", buf); + } + } + } + close(f); + return 0; } diff --git a/src/common/include/syscallproto.h b/src/common/include/syscallproto.h index bfcd37a..8c86762 100644 --- a/src/common/include/syscallproto.h +++ b/src/common/include/syscallproto.h @@ -3,28 +3,28 @@ #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_DBG_PRINT 0 // args: msg, msg_strlen +#define SC_EXIT 1 // args: code +#define SC_YIELD 2 // args: () + +#define SC_MMAP 10 // args: addr, size, mode +#define SC_MMAP_FILE 11 // args: handle, offset, addr, size, mode +#define SC_MCHMAP 12 // args: addr, new_mode +#define SC_MUNMAP 13 // args: addr + +#define SC_CREATE 20 // args: file, file_strlen, type +#define SC_DELETE 21 // args: file, file_strlen +#define SC_MOVE 22 // args: old_file, old_file_strlen, new_file, new_file_strlen +#define SC_STAT 23 // args: file, file_strlen, out stat_t* data +#define SC_IOCTL 24 // args: file, file_strlen, code, out void* data + +#define SC_OPEN 30 // args: file, file_strlen, mode +#define SC_CLOSE 31 // args: fd +#define SC_READ 32 // args: fd, offset, size, out char* data +#define SC_WRITE 33 // args: fd, offset, size, data +#define SC_READDIR 34 // args: fd, out dirent_t *data +#define SC_STAT_OPEN 35 // args: fd, out stat_t *data -- stat on open file handle +#define SC_GET_MODE 36 // args: fd -- get mode for open file handle #define SC_MAKE_FS 40 #define SC_FS_ADD_SRC 41 diff --git a/src/common/libc/string.c b/src/common/libc/string.c index 7aa155d..dfc93e6 100644 --- a/src/common/libc/string.c +++ b/src/common/libc/string.c @@ -30,7 +30,7 @@ char *strcpy(char *dest, const char *src) { } char *strncpy(char *dest, const char *src, size_t n) { - size_t x = strlen(src + 1); + size_t x = strlen(src); if (n < x) x = n; memcpy(dest, src, x); if (n > x) memset(dest + x, 0, n - x); diff --git a/src/kernel/include/process.h b/src/kernel/include/process.h index 5d9c3bf..07cc14e 100644 --- a/src/kernel/include/process.h +++ b/src/kernel/include/process.h @@ -18,7 +18,6 @@ #include - #define USERSTACK_ADDR 0xB8000000 #define USERSTACK_SIZE 0x00020000 // 32 KB @@ -29,6 +28,8 @@ typedef struct process { btree_t *regions_idx; hashtbl_t *filesystems; + hashtbl_t *files; + int next_fd; thread_t *thread; @@ -47,7 +48,10 @@ bool start_process(process_t *p, proc_entry_t entry); // maps a region for user 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); +void proc_rm_fs(process_t *p, const char* name); +int proc_add_fd(process_t *p, fs_handle_t *f); // on error returns 0, nonzero otherfilesystems = create_hashtbl(str_key_eq_fun, str_hash_fun, free_key); if (proc->filesystems == 0) goto error; + proc->files = create_hashtbl(id_key_eq_fun, id_hash_fun, 0); + if (proc->files == 0) goto error; + proc->regions_idx = create_btree(id_key_cmp_fun, 0); if (proc->regions_idx == 0) goto error; @@ -48,12 +51,14 @@ process_t *new_process(process_t *parent) { proc->thread = 0; proc->pid = (next_pid++); proc->parent = parent; + proc->next_fd = 1; return proc; error: if (proc && proc->regions_idx) delete_btree(proc->regions_idx); if (proc && proc->filesystems) delete_hashtbl(proc->filesystems); + if (proc && proc->files) delete_hashtbl(proc->files); if (proc) free(proc); return 0; } @@ -123,7 +128,32 @@ bool proc_add_fs(process_t *p, fs_t *fs, const char* name) { } fs_t *proc_find_fs(process_t *p, const char* name) { - return hashtbl_find(p->filesystems, name); + return (fs_t*)hashtbl_find(p->filesystems, name); +} + +void proc_remove_fs(process_t *p, const char* name) { + hashtbl_remove(p->filesystems, name); +} + +int proc_add_fd(process_t *p, fs_handle_t *f) { + int fd = p->next_fd++; + + bool add_ok = hashtbl_add(p->files, (void*)fd, f); + if (!add_ok) return 0; + + return fd; +} + +fs_handle_t *proc_read_fd(process_t *p, int fd) { + return (fs_handle_t*)hashtbl_find(p->files, (void*)fd); +} + +void proc_close_fd(process_t *p, int fd) { + fs_handle_t *x = proc_read_fd(p, fd); + if (x != 0) { + unref_file(x); + hashtbl_remove(p->files, (void*)fd); + } } // ============================= // diff --git a/src/kernel/user/syscall.c b/src/kernel/user/syscall.c index ca5a65c..eee65d6 100644 --- a/src/kernel/user/syscall.c +++ b/src/kernel/user/syscall.c @@ -57,6 +57,14 @@ static uint32_t mmap_sc(sc_args_t args) { return mmap(current_process(), (void*)args.a, args.b, args.c); } +static uint32_t mmap_file_sc(sc_args_t args) { + int fd = args.a; + fs_handle_t *h = proc_read_fd(current_process(), fd); + if (h == 0) return false; + + return mmap_file(current_process(), h, args.b, (void*)args.c, args.d, args.e); +} + static uint32_t mchmap_sc(sc_args_t args) { return mchmap(current_process(), (void*)args.a, args.b); } @@ -65,6 +73,203 @@ static uint32_t munmap_sc(sc_args_t args) { return munmap(current_process(), (void*)args.a); } +static uint32_t create_sc(sc_args_t args) { + bool ret = false; + + char* fn = sc_copy_string(args.a, args.b); + if (fn == 0) goto end_create; + + char* sep = strchr(fn, ':'); + if (sep == 0) goto end_create; + + *sep = 0; + char* file = sep + 1; + + fs_t *fs = proc_find_fs(current_process(), fn); + if (fs == 0) goto end_create; + + ret = fs_create(fs, file, args.c); + +end_create: + if (fn) free(fn); + return ret; +} + +static uint32_t delete_sc(sc_args_t args) { + bool ret = false; + + char* fn = sc_copy_string(args.a, args.b); + if (fn == 0) goto end_del; + + char* sep = strchr(fn, ':'); + if (sep == 0) goto end_del; + + *sep = 0; + char* file = sep + 1; + + fs_t *fs = proc_find_fs(current_process(), fn); + if (fs == 0) goto end_del; + + ret = fs_delete(fs, file); + +end_del: + if (fn) free(fn); + return ret; +} + +static uint32_t move_sc(sc_args_t args) { + bool ret = false; + + char *fn_a = sc_copy_string(args.a, args.b), + *fn_b = sc_copy_string(args.c, args.d); + if (fn_a == 0 || fn_b == 0) goto end_move; + + char* sep_a = strchr(fn_a, ':'); + if (sep_a == 0) goto end_move; + *sep_a = 0; + + char* sep_b = strchr(fn_b, ':'); + if (sep_b == 0) goto end_move; + *sep_b = 0; + + if (strcmp(fn_a, fn_b) != 0) goto end_move; // can only move within same FS + + char *file_a = sep_a + 1, *file_b = sep_b + 1; + + fs_t *fs = proc_find_fs(current_process(), fn_a); + if (fs == 0) goto end_move; + + ret = fs_move(fs, file_a, file_b); + +end_move: + if (fn_a) free(fn_a); + if (fn_b) free(fn_b); + return ret; +} + +static uint32_t stat_sc(sc_args_t args) { + bool ret = false; + + char* fn = sc_copy_string(args.a, args.b); + if (fn == 0) goto end_stat; + + char* sep = strchr(fn, ':'); + if (sep == 0) goto end_stat; + + *sep = 0; + char* file = sep + 1; + + fs_t *fs = proc_find_fs(current_process(), fn); + if (fs == 0) goto end_stat; + + probe_for_write((stat_t*)args.c, sizeof(stat_t)); + ret = fs_stat(fs, file, (stat_t*)args.c); + +end_stat: + if (fn) free(fn); + return ret; +} + +static uint32_t ioctl_sc(sc_args_t args) { + int ret = -1; + + char* fn = sc_copy_string(args.a, args.b); + if (fn == 0) goto end_ioctl; + + char* sep = strchr(fn, ':'); + if (sep == 0) goto end_ioctl; + + *sep = 0; + char* file = sep + 1; + + fs_t *fs = proc_find_fs(current_process(), fn); + if (fs == 0) goto end_ioctl; + + void* data = (void*)args.d; + if (data >= (void*)K_HIGHHALF_ADDR) goto end_ioctl; + ret = fs_ioctl(fs, file, args.c, data); + +end_ioctl: + if (fn) free(fn); + return ret; +} + +static uint32_t open_sc(sc_args_t args) { + int ret = 0; + + char* fn = sc_copy_string(args.a, args.b); + if (fn == 0) goto end_open; + + char* sep = strchr(fn, ':'); + if (sep == 0) goto end_open; + + *sep = 0; + char* file = sep + 1; + + fs_t *fs = proc_find_fs(current_process(), fn); + if (fs == 0) goto end_open; + + fs_handle_t *h = fs_open(fs, file, args.c); + if (h == 0) goto end_open; + + ret = proc_add_fd(current_process(), h); + if (ret == 0) unref_file(h); + +end_open: + if (fn) free(fn); + return ret; +} + +static uint32_t close_sc(sc_args_t args) { + proc_close_fd(current_process(), args.a); + return 0; +} + +static uint32_t read_sc(sc_args_t args) { + fs_handle_t *h = proc_read_fd(current_process(), args.a); + if (h == 0) return 0; + + char* data = (char*)args.d; + size_t len = args.c; + probe_for_write(data, len); + return file_read(h, args.b, len, data); +} + +static uint32_t write_sc(sc_args_t args) { + fs_handle_t *h = proc_read_fd(current_process(), args.a); + if (h == 0) return 0; + + char* data = (char*)args.d; + size_t len = args.c; + probe_for_read(data, len); + return file_write(h, args.b, len, data); +} + +static uint32_t readdir_sc(sc_args_t args) { + fs_handle_t *h = proc_read_fd(current_process(), args.a); + if (h == 0) return false; + + dirent_t *o = (dirent_t*)args.b; + probe_for_write(o, sizeof(dirent_t)); + return file_readdir(h, o); +} + +static uint32_t stat_open_sc(sc_args_t args) { + fs_handle_t *h = proc_read_fd(current_process(), args.a); + if (h == 0) return false; + + stat_t *o = (stat_t*)args.b; + probe_for_write(o, sizeof(stat_t)); + return file_stat(h, o); +} + +static uint32_t get_mode_sc(sc_args_t args) { + fs_handle_t *h = proc_read_fd(current_process(), args.a); + if (h == 0) return 0; + + return file_get_mode(h); +} + // ====================== // // SYSCALLS SETUP ROUTINE // // ====================== // @@ -75,8 +280,23 @@ void setup_syscalls() { sc_handlers[SC_DBG_PRINT] = dbg_print_sc; sc_handlers[SC_MMAP] = mmap_sc; + sc_handlers[SC_MMAP_FILE] = mmap_file_sc; sc_handlers[SC_MCHMAP] = mchmap_sc; sc_handlers[SC_MUNMAP] = munmap_sc; + + sc_handlers[SC_CREATE] = create_sc; + sc_handlers[SC_DELETE] = delete_sc; + sc_handlers[SC_MOVE] = move_sc; + sc_handlers[SC_STAT] = stat_sc; + sc_handlers[SC_IOCTL] = ioctl_sc; + + sc_handlers[SC_OPEN] = open_sc; + sc_handlers[SC_CLOSE] = close_sc; + sc_handlers[SC_READ] = read_sc; + sc_handlers[SC_WRITE] = write_sc; + sc_handlers[SC_READDIR] = readdir_sc; + sc_handlers[SC_STAT_OPEN] = stat_open_sc; + sc_handlers[SC_GET_MODE] = get_mode_sc; } void syscall_handler(registers_t *regs) { diff --git a/src/lib/include/syscall.h b/src/lib/include/syscall.h index e0f08eb..3d9fcd5 100644 --- a/src/lib/include/syscall.h +++ b/src/lib/include/syscall.h @@ -10,14 +10,31 @@ #include #include +typedef int fd_t; + void dbg_print(const char* str); void yield(); void exit(int code); bool mmap(void* addr, size_t size, int mode); +bool mmap_file(fd_t file, size_t offset, void* addr, size_t size, int mode); bool mchmap(void* addr, int mode); bool munmap(void* addr); +bool create(const char* name, int type); +bool delete(const char* name); +bool move(const char* oldname, const char* newname); +bool stat(const char* name, stat_t *s); +int ioctl(const char* filename, int command, void* data); + +fd_t open(const char* name, int mode); +void close(fd_t file); +size_t read(fd_t file, size_t offset, size_t len, char *buf); +size_t write(fd_t file, size_t offset, size_t len, const char* buf); +bool readdir(fd_t file, dirent_t *d); +bool stat_open(fd_t file, stat_t *s); +int get_mode(fd_t file); + // more todo /* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/libkogata/syscall.c b/src/lib/libkogata/syscall.c index 8d24628..008a2a9 100644 --- a/src/lib/libkogata/syscall.c +++ b/src/lib/libkogata/syscall.c @@ -4,7 +4,7 @@ #include #include -static uint32_t call(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t ss, uint32_t dd) { +static inline uint32_t call(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t ss, uint32_t dd) { uint32_t ret; asm volatile("int $0x40" :"=a"(ret) @@ -38,6 +38,9 @@ void exit(int code) { bool mmap(void* addr, size_t size, int mode) { return call(SC_MMAP, (uint32_t)addr, size, mode, 0, 0); } +bool mmap_file(fd_t file, size_t offset, void* addr, size_t size, int mode) { + return call(SC_MMAP_FILE, file, offset, (uint32_t)addr, size, mode); +} bool mchmap(void* addr, int mode) { return call(SC_MCHMAP, (uint32_t)addr, mode, 0, 0, 0); } @@ -45,4 +48,42 @@ bool munmap(void* addr) { return call(SC_MUNMAP, (uint32_t)addr, 0, 0, 0, 0); } +bool create(const char* name, int type) { + return call(SC_CREATE, (uint32_t)name, strlen(name), type, 0, 0); +} +bool delete(const char* name) { + return call(SC_CREATE, (uint32_t)name, strlen(name), 0, 0, 0); +} +bool move(const char* oldname, const char* newname) { + return call(SC_MOVE, (uint32_t)oldname, strlen(oldname), (uint32_t)newname, strlen(newname), 0); +} +bool stat(const char* name, stat_t *s) { + return call(SC_STAT, (uint32_t)name, strlen(name), (uint32_t)s, 0, 0); +} +int ioctl(const char* filename, int command, void* data) { + return call(SC_IOCTL, (uint32_t)filename, strlen(filename), command, (uint32_t)data, 0); +} + +fd_t open(const char* name, int mode) { + return call(SC_OPEN, (uint32_t)name, strlen(name), mode, 0, 0); +} +void close(fd_t file) { + call(SC_CLOSE, file, 0, 0, 0, 0); +} +size_t read(fd_t file, size_t offset, size_t len, char *buf) { + return call(SC_READ, file, offset, len, (uint32_t)buf, 0); +} +size_t write(fd_t file, size_t offset, size_t len, const char* buf) { + return call(SC_WRITE, file, offset, len, (uint32_t)buf, 0); +} +bool readdir(fd_t file, dirent_t *d) { + return call(SC_READDIR, file, (uint32_t)d, 0, 0, 0); +} +bool stat_open(fd_t file, stat_t *s) { + return call(SC_STAT_OPEN, file, (uint32_t)s, 0, 0, 0); +} +int get_mode(fd_t file) { + return call(SC_GET_MODE, file, 0, 0, 0, 0); +} + /* vim: set ts=4 sw=4 tw=0 noet :*/ -- cgit v1.2.3