diff --git a/Makefile b/Makefile index e99f2a0..b3e8f6c 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ all: kern/kernel.elf main: main.o -kern/kernel.elf: kern/entry.o kern/start.o kern/libkern/string.o kern/libkern/proc.o kern/libkern/uart.o kern/libkern/panic.o kern/kalloc.o kern/libkern/memory.o kern/libkern/spinlock.o kern/libkern/string.o kern/libkern/mini-printf.o +kern/kernel.elf: kern/entry.o kern/start.o kern/libkern/string.o kern/libkern/proc.o kern/libkern/uart.o kern/libkern/panic.o kern/kalloc.o kern/libkern/memory.o kern/ispinlock.o kern/libkern/spinlock.o kern/libkern/string.o kern/libkern/mini-printf.o @echo LD $@ @$(LD) $(LDFLAGS) -o $@ $^ diff --git a/kern/ispinlock.c b/kern/ispinlock.c new file mode 100644 index 0000000..01965f8 --- /dev/null +++ b/kern/ispinlock.c @@ -0,0 +1,45 @@ +#include "ispinlock.h" + +void spinlock_init(spinlock_t *l) { + l->v = 0; +} + +__attribute__((warn_unused_result)) bool spin_trylock(spinlock_t *l) { + uint32_t old; + // old = xchg_acquire(&l->v, 1) using AMO + __asm__ volatile("amoswap.w.aq %0, %2, (%1)\n" : "=&r"(old) : "r"(&l->v), "r"(1u) : "memory"); + return old == 0; +} + +void spin_unlock(spinlock_t *l) { + // Release: store 0 with .rl ordering. + uint32_t dummy; + __asm__ volatile("amoswap.w.rl %0, %2, (%1)\n" : "=&r"(dummy) : "r"(&l->v), "r"(0u) : "memory"); +} + +// Optional: tiny pause/backoff (works even if Zihintpause isn't present). +// See: https://github.com/riscv/riscv-isa-manual/blob/main/src/zihintpause.adoc +static inline void cpu_relax(void) { +#if defined(__riscv_zihintpause) + __asm__ volatile("pause"); +#else + __asm__ volatile("nop"); +#endif +} + +// Test-and-test-and-set acquire with polite spinning + exponential backoff. +void spin_lock(spinlock_t *l) { + unsigned backoff = 1; + for (;;) { + if (spin_trylock(l)) + return; + + // Contended: spin on plain loads (no AMO) until it looks free. + while (__atomic_load_n(&l->v, __ATOMIC_RELAXED) != 0) { + for (unsigned i = 0; i < backoff; ++i) cpu_relax(); + if (backoff < 1u << 12) + backoff <<= 1; + } + // Try again; loop. + } +} diff --git a/kern/ispinlock.h b/kern/ispinlock.h new file mode 100644 index 0000000..e30d4b6 --- /dev/null +++ b/kern/ispinlock.h @@ -0,0 +1,11 @@ +#pragma once +#include + +typedef struct { + volatile uint32_t v; // 0 = unlocked, 1 = locked +} spinlock_t; + +void spinlock_init(spinlock_t *l); +bool spin_trylock(spinlock_t *l); +void spin_unlock(spinlock_t *l); +void spin_lock(spinlock_t *l); diff --git a/kern/kalloc.c b/kern/kalloc.c index b0f89a0..0adbdc9 100644 --- a/kern/kalloc.c +++ b/kern/kalloc.c @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/kern/libkern/spinlock.c b/kern/libkern/spinlock.c index f3b194a..6b1d89f 100644 --- a/kern/libkern/spinlock.c +++ b/kern/libkern/spinlock.c @@ -122,47 +122,3 @@ void pop_off(void) { if (c->noff == 0 && c->intena) intr_on(); } - -void spinlock_init(spinlock_t *l) { - l->v = 0; -} - -__attribute__((warn_unused_result)) bool spin_trylock(spinlock_t *l) { - uint32_t old; - // old = xchg_acquire(&l->v, 1) using AMO - __asm__ volatile("amoswap.w.aq %0, %2, (%1)\n" : "=&r"(old) : "r"(&l->v), "r"(1u) : "memory"); - return old == 0; -} - -void spin_unlock(spinlock_t *l) { - // Release: store 0 with .rl ordering. - uint32_t dummy; - __asm__ volatile("amoswap.w.rl %0, %2, (%1)\n" : "=&r"(dummy) : "r"(&l->v), "r"(0u) : "memory"); -} - -// Optional: tiny pause/backoff (works even if Zihintpause isn't present). -// See: https://github.com/riscv/riscv-isa-manual/blob/main/src/zihintpause.adoc -static inline void cpu_relax(void) { -#if defined(__riscv_zihintpause) - __asm__ volatile("pause"); -#else - __asm__ volatile("nop"); -#endif -} - -// Test-and-test-and-set acquire with polite spinning + exponential backoff. -void spin_lock(spinlock_t *l) { - unsigned backoff = 1; - for (;;) { - if (spin_trylock(l)) - return; - - // Contended: spin on plain loads (no AMO) until it looks free. - while (__atomic_load_n(&l->v, __ATOMIC_RELAXED) != 0) { - for (unsigned i = 0; i < backoff; ++i) cpu_relax(); - if (backoff < 1u << 12) - backoff <<= 1; - } - // Try again; loop. - } -} diff --git a/kern/libkern/spinlock.h b/kern/libkern/spinlock.h index 5561b98..9629e60 100644 --- a/kern/libkern/spinlock.h +++ b/kern/libkern/spinlock.h @@ -48,13 +48,4 @@ void push_off(void); /** @copydoc pop_off */ void pop_off(void); -typedef struct { - volatile uint32_t v; // 0 = unlocked, 1 = locked -} spinlock_t; - -void spinlock_init(spinlock_t *l); -bool spin_trylock(spinlock_t *l); -void spin_unlock(spinlock_t *l); -void spin_lock(spinlock_t *l); - #endif diff --git a/kern/libkern/stdint.h b/kern/libkern/stdint.h index 69e74d4..37c912f 100644 --- a/kern/libkern/stdint.h +++ b/kern/libkern/stdint.h @@ -13,4 +13,4 @@ typedef uint64_t size_t; typedef uint64_t uintptr_t; -typedef u8 bool; +// typedef u8 bool; diff --git a/kern/start.c b/kern/start.c index 0a34508..10503d1 100644 --- a/kern/start.c +++ b/kern/start.c @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include