From 71e15e94af794051dacf6495029095998ebd2bad Mon Sep 17 00:00:00 2001 From: apio Date: Sat, 8 Oct 2022 12:06:09 +0200 Subject: [PATCH] Kernel, libc and userspace: Add basic errno support. Kernel: Add an errno.h header with definitions for each header, and return those, negated, from syscalls when there is an error. mmap() returns an invalid address with errno encoded, instead of returning a negated errno; this address is encoded as ffffffffffffffEE where EE is errno in hex. libc: make syscall() return -1 and set errno on error, instead of returning the raw return value of the system call. Also, add mmap() and munmap() wrappers in sys/mman.h :). userspace: make the memeater program show the value of errno when allocating memory fails. Things to improve: add perror() and strerror() to make the errno experience even better! >.< --- apps/src/memeater.c | 4 +++- kernel/include/errno.h | 5 +++++ kernel/src/sys/mem.cpp | 21 +++++++++++++++------ kernel/src/sys/paint.cpp | 5 +++-- kernel/src/sys/version.cpp | 11 +++++++++++ libs/libc/include/bits/error.h | 26 ++++++++++++++++++++++++++ libs/libc/include/bits/macros.h | 4 ++-- libs/libc/include/errno.h | 10 ++++++++++ libs/libc/include/sys/mman.h | 22 ++++++++++++++++++++++ libs/libc/src/bits/bindings.c | 11 ++++------- libs/libc/src/errno.cpp | 3 +++ libs/libc/src/luna.cpp | 4 ++-- libs/libc/src/stdio.cpp | 1 + libs/libc/src/sys/mman.cpp | 17 +++++++++++++++++ libs/libc/src/unistd.cpp | 4 +++- 15 files changed, 127 insertions(+), 21 deletions(-) create mode 100644 kernel/include/errno.h create mode 100644 libs/libc/include/bits/error.h create mode 100644 libs/libc/include/sys/mman.h create mode 100644 libs/libc/src/errno.cpp create mode 100644 libs/libc/src/sys/mman.cpp diff --git a/apps/src/memeater.c b/apps/src/memeater.c index 875d319b..8e683637 100644 --- a/apps/src/memeater.c +++ b/apps/src/memeater.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -13,5 +14,6 @@ int main() printf("Allocating 4 MB of memory... %lx\n", (unsigned long)allocated); sleep(1); } while ((allocated = malloc(CHUNK))); - printf("Out of memory.\n"); + printf("Out of memory. (errno=%d)\n", errno); + printf("Press any key to restart.\n"); } \ No newline at end of file diff --git a/kernel/include/errno.h b/kernel/include/errno.h new file mode 100644 index 00000000..c02a1dcd --- /dev/null +++ b/kernel/include/errno.h @@ -0,0 +1,5 @@ +#pragma once + +#define EPERM 1 +#define ENOMEM 12 +#define EINVAL 22 \ No newline at end of file diff --git a/kernel/src/sys/mem.cpp b/kernel/src/sys/mem.cpp index f87843c6..148bb964 100644 --- a/kernel/src/sys/mem.cpp +++ b/kernel/src/sys/mem.cpp @@ -1,17 +1,20 @@ #define MODULE "mem" +#include "errno.h" #include "interrupts/Context.h" #include "log/Log.h" #include "memory/MemoryManager.h" #include "memory/VMM.h" #include +#define MAP_FAIL(errno) 0xffffffffffffff00 | (unsigned char)(errno) + void sys_mmap(Context* context, void* address, size_t size, int flags) { if (size < 4096) { kdbgln("sys_mmap: size too small"); - context->rax = 0; + context->rax = MAP_FAIL(EINVAL); return; } int real_flags = MAP_USER; @@ -23,7 +26,7 @@ void sys_mmap(Context* context, void* address, size_t size, int flags) if (kernelVMM.getPhysical((uint64_t)address) != (uint64_t)-1) // Address is already used. { kdbgln("attempt to mmap an already mapped address"); - context->rax = 0; + context->rax = MAP_FAIL(ENOMEM); return; } uint64_t offset = (uint64_t)address % 4096; @@ -37,7 +40,7 @@ void sys_mmap(Context* context, void* address, size_t size, int flags) else { kdbgln("mmap failed"); - context->rax = 0; + context->rax = MAP_FAIL(ENOMEM); return; } } @@ -52,7 +55,7 @@ void sys_mmap(Context* context, void* address, size_t size, int flags) else { kdbgln("mmap failed"); - context->rax = 0; + context->rax = MAP_FAIL(ENOMEM); return; } } @@ -60,17 +63,23 @@ void sys_mmap(Context* context, void* address, size_t size, int flags) void sys_munmap(Context* context, void* address, size_t size) { kdbgln("sys_munmap: attempting to unmap %lx", (uint64_t)address); + if (size < 4096) + { + kdbgln("munmap failed: size is too small"); + context->rax = -EINVAL; + return; + } if (!address) { kdbgln("munmap failed: attempted to unmap page 0"); - context->rax = -1; + context->rax = -EINVAL; return; } uint64_t flags = kernelVMM.getFlags((uint64_t)address); if (!(flags & MAP_USER)) { kdbgln("munmap failed: attempted to unmap a kernel page"); - context->rax = -1; + context->rax = -EINVAL; return; } uint64_t offset = (uint64_t)address % 4096; diff --git a/kernel/src/sys/paint.cpp b/kernel/src/sys/paint.cpp index 9a56de2a..daece6cd 100644 --- a/kernel/src/sys/paint.cpp +++ b/kernel/src/sys/paint.cpp @@ -1,4 +1,5 @@ #include "bootboot.h" +#include "errno.h" #include "interrupts/Context.h" #include "render/Framebuffer.h" #include @@ -9,12 +10,12 @@ void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h, { if ((x + w) > bootboot.fb_width) { - context->rax = -1; + context->rax = -EINVAL; return; } if ((y + h) > bootboot.fb_height) { - context->rax = -1; + context->rax = -EINVAL; return; } diff --git a/kernel/src/sys/version.cpp b/kernel/src/sys/version.cpp index 62a53c1c..f8bd51a3 100644 --- a/kernel/src/sys/version.cpp +++ b/kernel/src/sys/version.cpp @@ -1,8 +1,19 @@ #include "config.h" +#include "errno.h" #include "interrupts/Context.h" #include "std/stdio.h" void sys_getversion(Context* context, char* buffer, size_t max) { + if (!max) + { + context->rax = -EINVAL; + return; + } + if (!buffer) + { + context->rax = -EINVAL; + return; + } context->rax = snprintf(buffer, max, "moon %s", moon_version()); } \ No newline at end of file diff --git a/libs/libc/include/bits/error.h b/libs/libc/include/bits/error.h new file mode 100644 index 00000000..607695d8 --- /dev/null +++ b/libs/libc/include/bits/error.h @@ -0,0 +1,26 @@ +#ifndef _BITS_ERROR_H +#define _BITS_ERROR_H + +#include + +#define _RETURN_WITH_ERRNO(rc, type) \ + do { \ + if (rc < 0) \ + { \ + errno = (int)rc; \ + return -1; \ + } \ + return (type)rc; \ + } while (0) + +#define _RETURN_WITH_MEMORY_ERRNO(rc, type) \ + do { \ + if ((unsigned long int)rc > 0xffffffffffffff00) \ + { \ + errno = (int)((rc)&0xff); \ + return (type)-1; \ + } \ + return (type)rc; \ + } while (0) + +#endif \ No newline at end of file diff --git a/libs/libc/include/bits/macros.h b/libs/libc/include/bits/macros.h index 3bc212ec..16ede7b4 100644 --- a/libs/libc/include/bits/macros.h +++ b/libs/libc/include/bits/macros.h @@ -1,5 +1,5 @@ -#ifndef __BITS_MACROS_H -#define __BITS_MACROS_H +#ifndef _BITS_MACROS_H +#define _BITS_MACROS_H #define noreturn __attribute__((noreturn)) #define align(n) __attribute__((aligned(n))) diff --git a/libs/libc/include/errno.h b/libs/libc/include/errno.h index e69de29b..1caae45e 100644 --- a/libs/libc/include/errno.h +++ b/libs/libc/include/errno.h @@ -0,0 +1,10 @@ +#ifndef _ERRNO_H +#define _ERRNO_H + +extern int errno; + +#define EPERM 1 +#define ENOMEM 12 +#define EINVAL 22 + +#endif \ No newline at end of file diff --git a/libs/libc/include/sys/mman.h b/libs/libc/include/sys/mman.h new file mode 100644 index 00000000..3843a85d --- /dev/null +++ b/libs/libc/include/sys/mman.h @@ -0,0 +1,22 @@ +#ifndef _SYS_MMAN_H +#define _SYS_MMAN_H + +#include + +typedef unsigned long off_t; + +#define MAP_FAILED (void*)-1 + +#ifdef __cplusplus +extern "C" +{ +#endif + + void* mmap(void*, size_t, int, int, int, off_t); + int munmap(void* addr, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/libs/libc/src/bits/bindings.c b/libs/libc/src/bits/bindings.c index f8601d34..75b85898 100644 --- a/libs/libc/src/bits/bindings.c +++ b/libs/libc/src/bits/bindings.c @@ -1,6 +1,5 @@ #include -#include -#include +#include int liballoc_lock() { @@ -14,14 +13,12 @@ int liballoc_unlock() void* liballoc_alloc(size_t size) { - unsigned long int result = (unsigned long int)syscall(SYS_mmap, NULL, size * 4096, 1); + void* result = mmap(NULL, size * 4096, 0, 1, 0, 0); + if (result == MAP_FAILED) return 0; return (void*)result; } int liballoc_free(void* address, size_t size) { - int result = (int)syscall(SYS_munmap, address, size * 4096); - if (result < 0) return 1; - else - return 0; + return munmap(address, size * 4096); } \ No newline at end of file diff --git a/libs/libc/src/errno.cpp b/libs/libc/src/errno.cpp new file mode 100644 index 00000000..434ba1ab --- /dev/null +++ b/libs/libc/src/errno.cpp @@ -0,0 +1,3 @@ +#include + +int errno; \ No newline at end of file diff --git a/libs/libc/src/luna.cpp b/libs/libc/src/luna.cpp index abef73a9..eee9f2ae 100644 --- a/libs/libc/src/luna.cpp +++ b/libs/libc/src/luna.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -20,7 +21,6 @@ extern "C" noreturn void __luna_abort(const char* message) { syscall(SYS_write, message, strlen(message)); - syscall(SYS_exit); - __builtin_unreachable(); + abort(); } } \ No newline at end of file diff --git a/libs/libc/src/stdio.cpp b/libs/libc/src/stdio.cpp index d2da8940..eecf7621 100644 --- a/libs/libc/src/stdio.cpp +++ b/libs/libc/src/stdio.cpp @@ -50,6 +50,7 @@ extern "C" int puts(const char* s) { long nwritten = syscall(SYS_write, s, strlen(s)); + if (nwritten < 0) return -1; nwritten += syscall(SYS_write, "\n", 1); return (int)nwritten; } diff --git a/libs/libc/src/sys/mman.cpp b/libs/libc/src/sys/mman.cpp new file mode 100644 index 00000000..7b2a747f --- /dev/null +++ b/libs/libc/src/sys/mman.cpp @@ -0,0 +1,17 @@ +#include +#include +#include + +extern "C" +{ + // FIXME: Implement a POSIX-compliant mmap. + void* mmap(void* addr, size_t len, int, int flags, int, off_t) + { + return (void*)syscall(SYS_mmap, addr, len, flags); + } + + int munmap(void* addr, size_t len) + { + return (int)syscall(SYS_munmap, addr, len); + } +} \ No newline at end of file diff --git a/libs/libc/src/unistd.cpp b/libs/libc/src/unistd.cpp index 2e3e6593..25ef02cb 100644 --- a/libs/libc/src/unistd.cpp +++ b/libs/libc/src/unistd.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -62,7 +63,8 @@ extern "C" default: result = -1; break; } va_end(ap); - return result; + if (number == SYS_mmap) { _RETURN_WITH_MEMORY_ERRNO(result, long int); } + else { _RETURN_WITH_ERRNO(result, long); } } unsigned int sleep(unsigned int seconds)