diff --git a/arch/x86/include/arch/atom.h b/arch/x86/include/arch/atom.h index 143e62e..74a0a98 100644 --- a/arch/x86/include/arch/atom.h +++ b/arch/x86/include/arch/atom.h @@ -6,19 +6,6 @@ #include #include -static __always_inline void __spin_loop(void) -{ - /* - * Intel says you're supposed to put this in tight spin loops as a - * workaround for their buggy memory order violation prediction or - * something. They also claim that it significantly reduces power - * consumption, whatever, i don't care. - */ - __asm__ volatile("pause" ::: "memory"); -} -/** @brief Use this macro to build spin-wait loops. */ -#define spin_loop for (;; __spin_loop()) - /** * @brief Read an atom's current value. * You usually shouldn't need this function because all the other atomic diff --git a/arch/x86/include/arch/cpufunc.h b/arch/x86/include/arch/cpufunc.h new file mode 100644 index 0000000..5122014 --- /dev/null +++ b/arch/x86/include/arch/cpufunc.h @@ -0,0 +1,91 @@ +/* See the end of this file for copyright and license terms. */ + +#pragma once + +#include +#include + +static __always_inline void enable_intr(void) +{ + __asm__ volatile("sti"); +} + +static __always_inline void disable_intr(void) +{ + __asm__ volatile("cli" ::: "memory"); +} + +static inline register_t read_flags(void) +{ + register_t flags; + +#ifdef __x86_64__ + __asm__( +" pushfq \n" +" popq %0 \n" + : "=r"(flags) + ); +#else + __asm__( +" pushfl \n" +" popl %0 \n" + : "=r"(flags) + ); +#endif + + return flags; +} + +/** + * @brief Temporarily disable interrupts. + * + * It should be noted that yes, there is also `disable_intr()`, which does the + * exact same thing except it has no return value. This is yet another instance + * of me finding it funny to cause unnecessary confusion, but this time it's + * also because FreeBSD uses the same unfortunate naming scheme. + * + * @return The contents of the status register before disabling interrupts. + * This should be passed to `intr_restore()` after the atomic operation + * is complete so that the interrupt enable flag can be restored to what + * it was before. + */ +static inline register_t intr_disable(void) +{ + register_t eflags = read_flags(); + disable_intr(); + return eflags; +} + +static inline void intr_restore(register_t flags) +{ + /* bit 9 is IF (Interrupt Enable Flag) */ + if (flags & (1 << 9)) + enable_intr(); +} + +static __always_inline void halt(void) +{ + __asm__ volatile("hlt"); +} + +static __always_inline void x86_pause(void) +{ + __asm__ volatile("pause"); +} + +/** @brief Use this macro to build spin-wait loops. */ +#define spin_loop for (;; x86_pause()) + +/* + * 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/arch/x86/include/arch/interrupt.h b/arch/x86/include/arch/interrupt.h index bf4ddb0..29e843b 100644 --- a/arch/x86/include/arch/interrupt.h +++ b/arch/x86/include/arch/interrupt.h @@ -6,8 +6,8 @@ #define X86_INTR_COUNT 256 /* - * These are all reserved interrupt/exception vector numbers for x86 Protected Mode. - * Taken from the Intel Architecture Software Developer's Manual, vol. 3, table 6-1. + * These are all reserved interrupt/exception vector numbers for x86 Protected + * and Long Mode. Taken from the Intel SDM vol 3, sec 6.3.1, tbl 6-1. */ /** @brief Divide Error */ @@ -66,16 +66,6 @@ #include #include -static __always_inline void enable_intr(void) -{ - __asm__ volatile("sti"); -} - -static __always_inline void disable_intr(void) -{ - __asm__ volatile("cli" ::: "memory"); -} - /** * @brief A single entry in the Interrupt Descriptor Table as laid out in hardware. * Luckily, this is not quite as deranged as the GDT layout. diff --git a/arch/x86/sys/interrupt.c b/arch/x86/sys/interrupt.c index 8a5816a..244a734 100644 --- a/arch/x86/sys/interrupt.c +++ b/arch/x86/sys/interrupt.c @@ -1,5 +1,6 @@ /* See the end of this file for copyright and license terms. */ +#include #include #include #include diff --git a/arch/x86/sys/irq.c b/arch/x86/sys/irq.c index 2f0dcf5..0090b41 100644 --- a/arch/x86/sys/irq.c +++ b/arch/x86/sys/irq.c @@ -5,6 +5,7 @@ * */ +#include #include #include #include diff --git a/include/gay/cdefs.h b/include/gay/cdefs.h index dfaf073..23322cb 100644 --- a/include/gay/cdefs.h +++ b/include/gay/cdefs.h @@ -41,6 +41,8 @@ */ #define __alloc_size(argn) __attribute__(( alloc_size(argn) )) +#define __noreturn __attribute__(( noreturn )) + /** * @brief Hint that the returned pointer will be able to hold at least as much * bytes as the product of the arguments `argn1` and `argn2` (counting from 1). diff --git a/include/gay/sched.h b/include/gay/sched.h index ff38b2e..a1f0b0b 100644 --- a/include/gay/sched.h +++ b/include/gay/sched.h @@ -3,6 +3,7 @@ #pragma once #include +#include #include #include @@ -38,15 +39,16 @@ struct task { * For the same reason, don't assign values to this directly, and use * `set_current()` instead. */ -extern struct task *current; +extern struct task *current_array[CFG_MAX_CPU]; +#define current (current_array[smp_cpuid()]) /** * @brief Update the `current` task. * You will almost never need this because `switch_to()` does it automatically. */ -__always_inline void set_current(struct task *task) +static inline void set_current(struct task *task) { - current = task; + current_array[smp_cpuid()] = task; } extern struct task kernel_task; diff --git a/include/gay/util.h b/include/gay/util.h index 98f1078..447adff 100644 --- a/include/gay/util.h +++ b/include/gay/util.h @@ -5,6 +5,8 @@ #include #include +void panic(const char *fmt, ...) __noreturn; + /** * @brief Get the number of elements in a statically allocated array. * diff --git a/kernel/mutex.c b/kernel/mutex.c index 3dd0818..717edbb 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -1,6 +1,7 @@ /* See the end of this file for copyright and license terms. */ #include +#include #include #include diff --git a/kernel/sched.c b/kernel/sched.c index 230edaf..0057146 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1,6 +1,6 @@ /* See the end of this file for copyright and license terms. */ -#include +#include #include #include @@ -13,7 +13,9 @@ struct task kernel_task = { .state = TASK_READY, }; -struct task *current = &kernel_task; +struct task *current_array[CFG_MAX_CPU] = { + &kernel_task, +}; /* * Two run queues, one active and one inactive. The scheduler takes tasks out diff --git a/kernel/util.c b/kernel/util.c index d1b2dfc..8228654 100644 --- a/kernel/util.c +++ b/kernel/util.c @@ -1,8 +1,35 @@ /* See the end of this file for copyright and license terms. */ +#include + +#include #include #include +#include + +void panic(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + disable_intr(); + + kprintf("Kernel panic: "); + if (fmt == nil) + kprintf("(nil)\n"); + else + kvprintf(fmt, args); + + kprintf("\nSystem halted"); + + /* no need for va_end() here i guess */ + while (1) { + halt(); + disable_intr(); + } +} + void *ptr_align(void *ptr, int log) { uintptr_t shifted = 1 << abs(log);