diff --git a/Makefile b/Makefile index f8cc863..5de848b 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ OBJS = \ # riscv64-unknown-elf- or riscv64-linux-gnu- # perhaps in /opt/riscv/bin -#TOOLPREFIX = +#TOOLPREFIX = # Try to infer the correct TOOLPREFIX if not set ifndef TOOLPREFIX @@ -73,8 +73,6 @@ endif LDFLAGS = -z max-page-size=4096 -all: kernel world fs - $K/kernel: $(OBJS) $K/kernel.ld $U/initcode $(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS) $(OBJDUMP) -S $K/kernel > $K/kernel.asm @@ -141,7 +139,7 @@ fs.img: mkfs/mkfs README.md $(UPROGS) -include kernel/*.d user/*.d -clean: +clean: rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \ */*.o */*.d */*.asm */*.sym \ $U/initcode $U/initcode.out $K/kernel fs.img \ diff --git a/kernel/file.c b/kernel/file.c index 24c6ec6..72cca61 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -3,10 +3,12 @@ // #include "types.h" +#include "riscv.h" #include "defs.h" #include "param.h" #include "fs.h" #include "spinlock.h" +#include "sleeplock.h" #include "file.h" #include "stat.h" #include "proc.h" diff --git a/kernel/main.c b/kernel/main.c index 24fe214..2aeca75 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -1,3 +1,7 @@ +#include "types.h" +#include "param.h" +#include "memlayout.h" +#include "riscv.h" #include "defs.h" volatile static int started = 0; diff --git a/kernel/proc.h b/kernel/proc.h index 01bb57c..d48fd3f 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -5,7 +5,7 @@ #include "riscv.h" #include "spinlock.h" -/** Saved registers for kernel context switches. */ +// Saved registers for kernel context switches. struct context { u64 ra; u64 sp; @@ -25,7 +25,7 @@ struct context { u64 s11; }; -/** Per-CPU state. */ +// Per-CPU state. struct cpu { struct proc *proc; // The process running on this cpu, or null. struct context context; // swtch() here to enter scheduler(). @@ -88,7 +88,7 @@ struct trapframe { enum procstate { UNUSED, USED, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; -/** Per-process state */ +// Per-process state struct proc { struct spinlock lock; diff --git a/kernel/sleeplock.c b/kernel/sleeplock.c index 2aaf93e..e0f05a9 100644 --- a/kernel/sleeplock.c +++ b/kernel/sleeplock.c @@ -1,6 +1,11 @@ // Sleeping locks +#include "types.h" +#include "riscv.h" #include "defs.h" +#include "param.h" +#include "memlayout.h" +#include "spinlock.h" #include "proc.h" #include "sleeplock.h" diff --git a/kernel/spinlock.c b/kernel/spinlock.c index 29d02db..9840302 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c @@ -1,44 +1,13 @@ -/** - * Mutual exclusion spin locks. - * (Not mutexes as these are spinning locks). - */ +// Mutual exclusion spin locks. +#include "types.h" +#include "param.h" +#include "memlayout.h" #include "spinlock.h" #include "riscv.h" #include "proc.h" #include "defs.h" -/** - * The aquire() and release() functions control ownership of the lock. - * To perform these operations, modern CPU's provide atomic instructions - * that prevent the cores from stepping on each other's toes, otherwise known - * as a deadlock. - * - * GCC provides a set of built-in functions that allow you to use atomic - * instructions in an architecture-independent way. These functions are - * defined in the GCC manual: - * - * See: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html - * See: https://en.wikipedia.org/wiki/Memory_barrier - * - * On RISC-V, sync_lock_test_and_set turns into an atomic swap: - * a5 = 1 - * s1 = &lk->locked - * amoswap.w.aq a5, a5, (s1) - * - * On RISC-V, sync_lock_release turns into an atomic swap: - * s1 = &lk->locked - * amoswap.w zero, zero, (s1) - * - * __sync_synchronize(); - * - * This function tells the C compiler and the processor to not move loads or stores - * past this point, to ensure that the critical section's memory - * references happen strictly after the lock is acquired/locked. - * On RISC-V, this emits a fence instruction. - */ - -/** Initialize spinlock */ void initlock(struct spinlock *lk, char *name) { @@ -47,41 +16,57 @@ initlock(struct spinlock *lk, char *name) lk->cpu = 0; } -/** - * Acquire the lock. - * Loops (spins) until the lock is acquired. - * Panics if the lock is already held by this cpu. - */ +// Acquire the lock. +// Loops (spins) until the lock is acquired. void acquire(struct spinlock *lk) { push_off(); // disable interrupts to avoid deadlock. - - if(holding(lk)) // If the lock is already held, panic. + if(holding(lk)) panic("acquire"); - // See file header for details + // On RISC-V, sync_lock_test_and_set turns into an atomic swap: + // a5 = 1 + // s1 = &lk->locked + // amoswap.w.aq a5, a5, (s1) while(__sync_lock_test_and_set(&lk->locked, 1) != 0) ; - __sync_synchronize(); // No loads/stores after this point + + // Tell the C compiler and the processor to not move loads or stores + // past this point, to ensure that the critical section's memory + // references happen strictly after the lock is acquired. + // On RISC-V, this emits a fence instruction. + __sync_synchronize(); // Record info about lock acquisition for holding() and debugging. lk->cpu = mycpu(); } -/** - * Release the lock. - * Panics if the lock is not held. - */ +// Release the lock. void release(struct spinlock *lk) { - if(!holding(lk)) // If the lock is not held, panic. + if(!holding(lk)) panic("release"); - lk->cpu = 0; // 0 means unheld - __sync_synchronize(); // No loads/stores after this point - __sync_lock_release(&lk->locked); // Essentially lk->locked = 0 + lk->cpu = 0; + + // Tell the C compiler and the CPU to not move loads or stores + // past this point, to ensure that all the stores in the critical + // section are visible to other CPUs before the lock is released, + // and that loads in the critical section occur strictly before + // the lock is released. + // On RISC-V, this emits a fence instruction. + __sync_synchronize(); + + // Release the lock, equivalent to lk->locked = 0. + // This code doesn't use a C assignment, since the C standard + // implies that an assignment might be implemented with + // multiple store instructions. + // On RISC-V, sync_lock_release turns into an atomic swap: + // s1 = &lk->locked + // amoswap.w zero, zero, (s1) + __sync_lock_release(&lk->locked); pop_off(); } diff --git a/kernel/spinlock.h b/kernel/spinlock.h index 779d918..dc21dd7 100644 --- a/kernel/spinlock.h +++ b/kernel/spinlock.h @@ -2,7 +2,7 @@ #include "types.h" -/** Mutual exclusion spin lock */ +// Mutual exclusion lock. struct spinlock { u32 locked; // Is the lock held? diff --git a/user/umalloc.c b/user/umalloc.c index 99107b2..4398225 100644 --- a/user/umalloc.c +++ b/user/umalloc.c @@ -1,5 +1,7 @@ #include "kernel/types.h" +#include "kernel/stat.h" #include "user/user.h" +#include "kernel/param.h" // Memory allocator by Kernighan and Ritchie, // The C programming Language, 2nd ed. Section 8.7. diff --git a/user/usertests.c b/user/usertests.c index d078540..d4fb6be 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -1,8 +1,10 @@ #include "kernel/param.h" #include "kernel/types.h" +#include "kernel/stat.h" #include "user/user.h" #include "kernel/fs.h" #include "kernel/fcntl.h" +#include "kernel/syscall.h" #include "kernel/memlayout.h" #include "kernel/riscv.h" diff --git a/user/wc.c b/user/wc.c index 77dae22..7719650 100644 --- a/user/wc.c +++ b/user/wc.c @@ -1,3 +1,5 @@ +#include "kernel/types.h" +#include "kernel/stat.h" #include "user/user.h" char buf[512];