diff options
Diffstat (limited to 'src/lib/libc')
-rw-r--r-- | src/lib/libc/debug.c | 18 | ||||
-rw-r--r-- | src/lib/libc/malloc.c | 70 | ||||
-rw-r--r-- | src/lib/libc/start.c | 17 | ||||
-rw-r--r-- | src/lib/libc/stdio.c | 63 | ||||
-rw-r--r-- | src/lib/libc/syscall.c | 204 | ||||
-rw-r--r-- | src/lib/libc/unistd.c | 66 |
6 files changed, 438 insertions, 0 deletions
diff --git a/src/lib/libc/debug.c b/src/lib/libc/debug.c new file mode 100644 index 0000000..dc04fd3 --- /dev/null +++ b/src/lib/libc/debug.c @@ -0,0 +1,18 @@ +#include <stdbool.h> + +#include <kogata/debug.h> +#include <kogata/syscall.h> + +void sys_panic(const char* msg, const char* file, int line) { + dbg_printf("PANIC in user process\n %s\n at %s:%d\n", msg, file, line); + exit(-1); + while(true); +} + +void sys_panic_assert(const char* assert, const char* file, int line) { + dbg_printf("ASSERT FAILED in user process\n %s\n at %s:%d\n", assert, file, line); + exit(-1); + while(true); +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/libc/malloc.c b/src/lib/libc/malloc.c new file mode 100644 index 0000000..cb983fd --- /dev/null +++ b/src/lib/libc/malloc.c @@ -0,0 +1,70 @@ +#include <kogata/malloc.h> +#include <kogata/slab_alloc.h> + +#include <kogata/syscall.h> +#include <kogata/region_alloc.h> + +#include <string.h> + +static void* heap_alloc_pages(size_t s) { + void* addr = region_alloc(s, "Heap"); + if (addr == 0) return 0; + + bool map_ok = mmap(addr, s, FM_READ | FM_WRITE); + if (!map_ok) { + region_free(addr); + return 0; + } + + return addr; +} + +static void heap_free_pages(void* addr) { + munmap(addr); + region_free(addr); +} + +static mem_allocator_t *mem_allocator; +static slab_type_t slab_sizes[] = { + { "8B malloc objects", 8, 2 }, + { "16B malloc objects", 16, 2 }, + { "32B malloc objects", 32, 2 }, + { "64B malloc objects", 64, 4 }, + { "128B malloc objects", 128, 4 }, + { "256B malloc objects", 256, 4 }, + { "512B malloc objects", 512, 8 }, + { "1KB malloc objects", 1024, 8 }, + { "2KB malloc objects", 2048, 16 }, + { "4KB malloc objects", 4096, 16 }, + { 0, 0, 0 } +}; + +bool mmap_single_page(void* addr) { + return mmap(addr, PAGE_SIZE, MM_READ | MM_WRITE); +} + +void malloc_setup() { + region_allocator_init((void*)0x40000000, (void*)0x40000000, (void*)0xB0000000, mmap_single_page); + + mem_allocator = create_slab_allocator(slab_sizes, heap_alloc_pages, heap_free_pages); + + ASSERT(mem_allocator != 0); +} + +void* malloc(size_t size) { + if (size == 0) return 0; + + return slab_alloc(mem_allocator, size); +} + +void* calloc(size_t nmemb, size_t sz) { + void* r = malloc(nmemb * sz); + if (r != 0) memset(r, 0, nmemb * sz); + return r; +} + +void free(void* ptr) { + slab_free(mem_allocator, ptr); +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/libc/start.c b/src/lib/libc/start.c new file mode 100644 index 0000000..49a6ca1 --- /dev/null +++ b/src/lib/libc/start.c @@ -0,0 +1,17 @@ +#include <kogata/syscall.h> + +void malloc_setup(); + +int main(int, char**); + +void __libkogata_start() { + malloc_setup(); + + // TODO : more setup ? + + int ret = main(0, 0); + + exit(ret); +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/libc/stdio.c b/src/lib/libc/stdio.c new file mode 100644 index 0000000..22be78e --- /dev/null +++ b/src/lib/libc/stdio.c @@ -0,0 +1,63 @@ +#include <string.h> +#include <stdio.h> + +#include <kogata/syscall.h> +#include <kogata/printf.h> + + +fd_t stdio = 1; + +int getchar() { + char chr; + size_t sz = read(stdio, 0, 1, &chr); + ASSERT(sz == 1); + return chr; +} + + +int putchar(int c) { + char chr = c; + write(stdio, 0, 1, &chr); + return 0; //TODO what? +} + +int puts(const char* s) { + // TODO return EOF on error + return write(stdio, 0, strlen(s), s); +} + +void getline(char* buf, size_t l) { + size_t i = 0; + while (true) { + int c = getchar(); + if (c == '\n') { + putchar('\n'); + buf[i] = 0; + break; + } else if (c == '\b') { + if (i > 0) { + i--; + putchar('\b'); + } + } else if (c >= ' ') { + buf[i] = c; + if (i < l-1) { + i++; + putchar(c); + } + } + } +} + +int printf(const char* fmt, ...) { + va_list ap; + char buffer[256]; + + va_start(ap, fmt); + vsnprintf(buffer, 256, fmt, ap); + va_end(ap); + + return puts(buffer); +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/libc/syscall.c b/src/lib/libc/syscall.c new file mode 100644 index 0000000..61b3471 --- /dev/null +++ b/src/lib/libc/syscall.c @@ -0,0 +1,204 @@ +#include <kogata/debug.h> +#include <kogata/syscall.h> + +#include <kogata/printf.h> + +#include <string.h> + +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) + :"a"(a),"b"(b),"c"(c),"d"(d),"S"(ss),"D"(dd)); + return ret; +} + +void dbg_print(const char* str) { + call(SC_DBG_PRINT, (uint32_t)str, strlen(str), 0, 0, 0); +} + +void dbg_printf(const char* fmt, ...) { + va_list ap; + char buffer[256]; + + va_start(ap, fmt); + vsnprintf(buffer, 256, fmt, ap); + va_end(ap); + + dbg_print(buffer); +} + +void yield() { + call(SC_YIELD, 0, 0, 0, 0, 0); +} + +void exit(int code) { + call(SC_EXIT, code, 0, 0, 0, 0); +} + +void usleep(int usecs) { + call(SC_USLEEP, usecs, 0, 0, 0, 0); +} + +bool sys_new_thread(void* eip, void* esp) { + return call(SC_NEW_THREAD, (uint32_t)eip, (uint32_t)esp, 0, 0, 0); +} + +void exit_thread() { + call(SC_EXIT_THREAD, 0, 0, 0, 0, 0); +} + +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); +} +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); +} + +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, size_t ent_no, dirent_t *d) { + return call(SC_READDIR, file, ent_no, (uint32_t)d, 0, 0); +} +bool stat_open(fd_t file, stat_t *s) { + return call(SC_STAT_OPEN, file, (uint32_t)s, 0, 0, 0); +} +int ioctl(fd_t file, int command, void* data) { + return call(SC_IOCTL, file, command, (uint32_t)data, 0, 0); +} +int fctl(fd_t file, int command, void *data) { + return call(SC_FCTL, file, command, (uint32_t)data, 0, 0); +} +bool select(sel_fd_t* fds, size_t nfds, int timeout) { + return call(SC_SELECT, (uint32_t)fds, nfds, timeout, 0, 0); +} + +fd_pair_t make_channel(bool blocking) { + fd_pair_t ret; + call(SC_MK_CHANNEL, blocking, (uint32_t)&ret, 0, 0, 0); + return ret; +} +fd_t make_shm(size_t s) { + return call(SC_MK_SHM, s, 0, 0, 0, 0); +} +bool gen_token(fd_t file, token_t *tok) { + return call(SC_GEN_TOKEN, file, (uint32_t)tok, 0, 0, 0); +} +fd_t use_token(token_t *tok) { + return call(SC_USE_TOKEN, (uint32_t)tok, 0, 0, 0, 0); +} + +bool make_fs(const char* name, const char* driver, fd_t source, const char* options) { + volatile sc_make_fs_args_t args = { + .driver = driver, + .driver_strlen = strlen(driver), + .fs_name = name, + .fs_name_strlen = strlen(name), + .source_fd = source, + .opts = options, + .opts_strlen = strlen(options), + .bind_to_pid = 0, + }; + return call(SC_MAKE_FS, (uint32_t)&args, 0, 0, 0, 0); +} +bool fs_add_source(const char* fs, fd_t source, const char* options) { + return call(SC_FS_ADD_SRC, (uint32_t)fs, strlen(fs), source, (uint32_t)options, strlen(options)); +} +bool fs_subfs(const char* name, const char* orig_fs, const char* root, int ok_modes) { + volatile sc_subfs_args_t args = { + .new_name = name, + .new_name_strlen = strlen(name), + .from_fs = orig_fs, + .from_fs_strlen = strlen(orig_fs), + .root = root, + .root_strlen = strlen(root), + .ok_modes = ok_modes, + .bind_to_pid = 0 + }; + return call(SC_SUBFS, (uint32_t)(&args), 0, 0, 0, 0); +} +void fs_remove(const char* name) { + call(SC_RM_FS, (uint32_t)name, strlen(name), 0, 0, 0); +} + +pid_t new_proc() { + return call(SC_NEW_PROC, 0, 0, 0, 0, 0); +} +bool bind_fs(pid_t pid, const char* new_name, const char* fs) { + return call(SC_BIND_FS, pid, (uint32_t)new_name, strlen(new_name), (uint32_t)fs, strlen(fs)); +} +bool bind_subfs(pid_t pid, const char* new_name, const char* orig_fs, const char* root, int ok_modes) { + sc_subfs_args_t args = { + .new_name = new_name, + .new_name_strlen = strlen(new_name), + .from_fs = orig_fs, + .from_fs_strlen = strlen(orig_fs), + .root = root, + .root_strlen = strlen(root), + .ok_modes = ok_modes, + .bind_to_pid = pid + }; + return call(SC_BIND_SUBFS, (uint32_t)&args, 0, 0, 0, 0); +} +bool bind_make_fs(pid_t pid, const char* name, const char* driver, fd_t source, const char* options) { + sc_make_fs_args_t args = { + .driver = driver, + .driver_strlen = strlen(driver), + .fs_name = name, + .fs_name_strlen = strlen(name), + .source_fd = source, + .opts = options, + .opts_strlen = strlen(options), + .bind_to_pid = pid, + }; + return call(SC_BIND_MAKE_FS, (uint32_t)&args, 0, 0, 0, 0); +} +bool bind_fd(pid_t pid, fd_t new_fd, fd_t fd) { + return call(SC_BIND_FD, pid, new_fd, fd, 0, 0); +} +bool proc_exec(pid_t pid, const char* file) { + return call(SC_PROC_EXEC, pid, (uint32_t)file, strlen(file), 0, 0); +} +bool proc_status(pid_t pid, proc_status_t *s) { + return call(SC_PROC_STATUS, pid, (uint32_t)s, 0, 0, 0); +} +bool proc_kill(pid_t pid, proc_status_t *s) { + return call(SC_PROC_KILL, pid, (uint32_t)s, 0, 0, 0); +} +void proc_wait(pid_t pid, bool block, proc_status_t *s) { + call(SC_PROC_WAIT, pid, block, (uint32_t)s, 0, 0); +} + + + + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/libc/unistd.c b/src/lib/libc/unistd.c new file mode 100644 index 0000000..5ae1735 --- /dev/null +++ b/src/lib/libc/unistd.c @@ -0,0 +1,66 @@ +#include <string.h> +#include <unistd.h> + +#include <kogata/syscall.h> + + +char cwd_buf[256]; + +char* getcwd(char* buf, size_t buf_len) { + if (buf_len > strlen(cwd_buf)) { + strcpy(buf, cwd_buf); + return buf; + } else { + return 0; + } +} + +int chdir(const char* path) { + char cwd_buf2[256]; + strcpy(cwd_buf2, cwd_buf); + + if (!pathncat(cwd_buf2, path, 256)) return -1; + + stat_t st; + if (!stat(cwd_buf2, &st)) return -1; + if (!(st.type & FT_DIR)) return -1; + + strcpy(cwd_buf, cwd_buf2); + return 0; +} + +char* pathncat(char* buf, const char* add, size_t buf_len) { + if (strchr(add, ':')) { + if (strlen(add) < buf_len) { + strcpy(buf, add); + return buf; + } else { + return 0; + } + } else { + char* sep_init = strchr(buf, ':'); + if (add[0] == '/') { + if (strlen(add) + (sep_init + 1 - buf) < buf_len) { + strcpy(sep_init + 1, add); + return buf; + } else { + return 0; + } + } else { + //TODO: simplify '..' + char* end = buf + strlen(buf) - 1; + if (*end != '/') end++; + if (end + 1 - buf + strlen(add) < buf_len) { + *end = '/'; + strcpy(end + 1, add); + return buf; + } else { + return 0; + } + } + return 0; + } +} + + +/* vim: set ts=4 sw=4 tw=0 noet :*/ |