diff --git a/CMakeLists.txt b/CMakeLists.txt index 15dfb0b..ebd3cd0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,9 @@ configure_file( include("arch/${ARCH}/config/toolchain.cmake") +# Used by the KASSERT macro for printing the filename relative to the source root +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__FILENAME__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pipe -nostdinc -ffreestanding -fno-stack-protector") set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -pipe -D_ASM_SOURCE") if(DEBUG) diff --git a/include/gay/cdefs.h b/include/gay/cdefs.h index 23322cb..6eaeb1c 100644 --- a/include/gay/cdefs.h +++ b/include/gay/cdefs.h @@ -55,6 +55,9 @@ */ #define __packed __attribute__(( packed )) +#define __printflike(fmt_argn, firstva_argn) \ + __attribute__(( format(printf, fmt_argn, firstva_argn) )) + /** * @brief Function does not have any side effects or internal state. * Subsequent calls with the same parameters always return the same result. diff --git a/include/gay/kprintf.h b/include/gay/kprintf.h index 848cc62..6b334cf 100644 --- a/include/gay/kprintf.h +++ b/include/gay/kprintf.h @@ -18,8 +18,7 @@ * @returns The amount of bytes written, * or a negative number from `errno.h` on failure */ -__attribute__(( format(printf, 1, 2) )) -int kprintf(const char *__restrict fmt, ...); +int kprintf(const char *__restrict fmt, ...) __printflike(1, 2); /** * @brief Print to the kernel log. @@ -29,7 +28,7 @@ int kprintf(const char *__restrict fmt, ...); * @returns The amount of bytes written, * or a negative number from `errno.h` on failure */ -int kvprintf(const char *__restrict fmt, va_list args); +int kvprintf(const char *__restrict fmt, va_list args) __printflike(1, 0); /** * @brief Printing functions that `kprintf()` and friends call for writing. diff --git a/include/gay/sched.h b/include/gay/sched.h index a1f0b0b..78aad42 100644 --- a/include/gay/sched.h +++ b/include/gay/sched.h @@ -25,6 +25,11 @@ struct task { tcb_t tcb; struct task *parent; pid_t pid; + /** + * @brief 0 = interruptable, > 0 = uninterruptible, < 0 = we messed up. + * Increment/decrement using `critical_enter()`/`critical_leave()`. + */ + volatile int critnest; enum task_state state; }; diff --git a/include/gay/systm.h b/include/gay/systm.h new file mode 100644 index 0000000..1600948 --- /dev/null +++ b/include/gay/systm.h @@ -0,0 +1,64 @@ +/* See the end of this file for copyright and license terms. */ + +#pragma once + +#include +#include +#include + +/** + * @brief Print an error message and halt the system immediately. + * + * @param fmt printf style format string + */ +void panic(const char *fmt, ...) __noreturn __printflike(1, 2); + +#ifdef DEBUG +/** + * @brief Assert that statement `x` is true. + * If it is not and debugging is enabled, the kernel panics. + */ +#define KASSERT(x) do { \ + if ( __predict_false(!(x)) ) { \ + panic("Assertion \"%s\" failed!\n" \ + " in function %s()\n" \ + " in file %s, line %u\n", \ + #x, __func__, __FILENAME__, __LINE__); \ + } \ +} while (0) +#else +#define KASSERT(x) do { } while (0) +#endif + +static inline void critical_enter(void) +{ + struct task *tsk = current; + tsk->critnest++; +} + +static inline void critical_leave(void) +{ + struct task *tsk = current; + tsk->critnest--; + + KASSERT(tsk->critnest >= 0); +} + +static inline bool in_critical(void) +{ + return current->critnest > 0; +} + +/* + * This file is part of GayBSD. + * Copyright (c) 2021 fef . + * + * GayBSD is nonviolent software: you may only use, redistribute, and/or + * modify it under the terms of the Cooperative Nonviolent Public License + * (CNPL) as found in the LICENSE file in the source code root directory + * or at ; either version 7 + * of the license, or (at your option) any later version. + * + * GayBSD comes with ABSOLUTELY NO WARRANTY, to the extent + * permitted by applicable law. See the CNPL for details. + */ diff --git a/include/gay/util.h b/include/gay/util.h index 447adff..096c774 100644 --- a/include/gay/util.h +++ b/include/gay/util.h @@ -5,8 +5,6 @@ #include #include -void panic(const char *fmt, ...) __noreturn; - /** * @brief Get the number of elements in a statically allocated array. * @@ -49,20 +47,20 @@ static __always_inline bool sus_nil(const void *ptr) return ptr < (void *)0x1000; } -/** - * @brief Align `ptr` such that `ptr % n == 0`. - * - * @param ptr Pointer to align - * @param log The log2 of the alignment. If negative, the pointer will be - * aligned to the next lower address, otherwise to the next higher one. - * @returns The aligned pointer - */ -void *ptr_align(void *ptr, int log); +static __always_inline uintptr_t _align_floor(uintptr_t ptr, usize size) +{ + return ptr - ptr % size; +} +#define align_floor(ptr, size) ( (typeof(ptr))_align_floor((uintptr_t)(ptr), size) ) -static __always_inline uintptr_t uintptr_align(uintptr_t ptr, int log) +static __always_inline uintptr_t _align_ceil(uintptr_t ptr, usize size) { - return (uintptr_t)ptr_align((void *)ptr, log); + uintptr_t aligned = ptr - ptr % size; + if (aligned < ptr) + aligned += size; + return aligned; } +#define align_ceil(ptr, size) ( (typeof(ptr))_align_ceil((uintptr_t)(ptr), size) ) /* * This file is part of GayBSD. diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 1d4cb61..8baf616 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -13,8 +13,8 @@ target_sources(gay_kernel PRIVATE kprintf.c main.c mutex.c + panic.c sched.c - util.c ) add_subdirectory(mm) diff --git a/kernel/mm/kmalloc.c b/kernel/mm/kmalloc.c index 9dc1e0e..147d2c2 100644 --- a/kernel/mm/kmalloc.c +++ b/kernel/mm/kmalloc.c @@ -38,7 +38,7 @@ int kmalloc_init(uintptr_t _phys_start, uintptr_t _phys_end) phys_start = image_end_phys; } - phys_start = uintptr_align(phys_start, +HUGEPAGE_SHIFT); + phys_start = align_ceil(phys_start, HUGEPAGE_SIZE); /* * This is intentionally not aligned to hugepages, because __early_get_page() * shrinks it in single PAGE_SIZE steps whenever it is called anyway. @@ -48,7 +48,7 @@ int kmalloc_init(uintptr_t _phys_start, uintptr_t _phys_end) * be able to allocate pages before the page frame allocator is set up * in the first place). */ - phys_end = uintptr_align(phys_end, -PAGE_SHIFT); + phys_end = align_floor(phys_end, PAGE_SIZE); int err = pages_init(); if (err) diff --git a/kernel/util.c b/kernel/panic.c similarity index 76% rename from kernel/util.c rename to kernel/panic.c index 8228654..810731f 100644 --- a/kernel/util.c +++ b/kernel/panic.c @@ -2,12 +2,13 @@ #include +#include +#include #include -#include -#include #include +__noreturn void panic(const char *fmt, ...) { va_list args; @@ -21,7 +22,7 @@ void panic(const char *fmt, ...) else kvprintf(fmt, args); - kprintf("\nSystem halted"); + kprintf("\nKernel version: %s\nSystem halted", GAY_VERSION_STR); /* no need for va_end() here i guess */ while (1) { @@ -30,17 +31,6 @@ void panic(const char *fmt, ...) } } -void *ptr_align(void *ptr, int log) -{ - uintptr_t shifted = 1 << abs(log); - uintptr_t aligned = (uintptr_t)ptr & ~(shifted - 1); - - if (log > 0 && aligned != (uintptr_t)ptr) - aligned += shifted; - - return (void *)aligned; -} - /* * This file is part of GayBSD. * Copyright (c) 2021 fef . diff --git a/kernel/sched.c b/kernel/sched.c index 0057146..8f3e3cf 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -11,6 +11,7 @@ struct task kernel_task = { .parent = nil, .pid = 0, .state = TASK_READY, + .critnest = 0, }; struct task *current_array[CFG_MAX_CPU] = { @@ -40,6 +41,9 @@ void schedule(void) struct task *old = current; struct task *new = nil; + if (old->critnest) + return; + clist_add(inactive_queue, &old->run_queue); /* Dijkstra would be so mad if he saw this */