From 709ec3a50f1d38bf25135224362a2be9b162e621 Mon Sep 17 00:00:00 2001 From: Garen Tyler Date: Sun, 15 Oct 2023 12:51:16 -0600 Subject: [PATCH] Rewrite spinlock.c --- Makefile | 5 +- kernel/defs.h | 2 +- kernel/proc.c | 12 +- kernel/proc.h | 2 + kernel/riscv.c | 30 +++++ kernel/riscv.h | 2 + kernel/rustkernel/Cargo.lock | 9 ++ kernel/rustkernel/Cargo.toml | 1 + kernel/rustkernel/src/kalloc.rs | 28 +++++ kernel/rustkernel/src/lib.rs | 31 +++-- kernel/rustkernel/src/param.rs | 26 ++++ kernel/rustkernel/src/proc.rs | 162 +++++++++++++++++++++++++ kernel/rustkernel/src/riscv.rs | 190 ++++++++++++++++++++++++++++++ kernel/rustkernel/src/spinlock.rs | 110 +++++++++++++++++ kernel/spinlock.c | 110 ----------------- kernel/types.h | 2 + 16 files changed, 596 insertions(+), 126 deletions(-) create mode 100644 kernel/riscv.c create mode 100644 kernel/rustkernel/src/kalloc.rs create mode 100644 kernel/rustkernel/src/param.rs create mode 100644 kernel/rustkernel/src/proc.rs create mode 100644 kernel/rustkernel/src/riscv.rs create mode 100644 kernel/rustkernel/src/spinlock.rs delete mode 100644 kernel/spinlock.c diff --git a/Makefile b/Makefile index 2e28226..fe700e6 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,6 @@ OBJS = \ $K/printf.o \ $K/uart.o \ $K/kalloc.o \ - $K/spinlock.o \ $K/string.o \ $K/main.o \ $K/vm.o \ @@ -30,7 +29,8 @@ OBJS = \ $K/sysfile.o \ $K/kernelvec.o \ $K/plic.o \ - $K/virtio_disk.o + $K/virtio_disk.o \ + $K/riscv.o # riscv64-unknown-elf- or riscv64-linux-gnu- # perhaps in /opt/riscv/bin @@ -78,6 +78,7 @@ LDFLAGS = -z max-page-size=4096 $K/kernel: $(OBJS) $K/kernel.ld $U/initcode $R/src cargo +nightly -Z unstable-options -C $R build + $(OBJDUMP) -S $R/target/$(TARGET_TRIPLE)/debug/librustkernel.a > $R/target/$(TARGET_TRIPLE)/debug/librustkernel.asm $(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS) $R/target/$(TARGET_TRIPLE)/debug/librustkernel.a $(OBJDUMP) -S $K/kernel > $K/kernel.asm $(OBJDUMP) -t $K/kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $K/kernel.sym diff --git a/kernel/defs.h b/kernel/defs.h index a3c962b..6323989 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -110,7 +110,7 @@ void procdump(void); // swtch.S void swtch(struct context*, struct context*); -// spinlock.c +// spinlock.rs void acquire(struct spinlock*); int holding(struct spinlock*); void initlock(struct spinlock*, char*); diff --git a/kernel/proc.c b/kernel/proc.c index 959b778..4d9f501 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -61,12 +61,12 @@ procinit(void) // Must be called with interrupts disabled, // to prevent race with process being moved // to a different CPU. -int -cpuid() -{ - int id = r_tp(); - return id; -} +// int +// cpuid() +// { +// int id = r_tp(); +// return id; +// } // Return this CPU's cpu struct. // Interrupts must be disabled. diff --git a/kernel/proc.h b/kernel/proc.h index d021857..e022685 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -105,3 +105,5 @@ struct proc { struct inode *cwd; // Current directory char name[16]; // Process name (debugging) }; + +int cpuid(); diff --git a/kernel/riscv.c b/kernel/riscv.c new file mode 100644 index 0000000..af351d5 --- /dev/null +++ b/kernel/riscv.c @@ -0,0 +1,30 @@ +#include "kernel/riscv.h" + +unsigned long rv_r_mhartid() { + return r_mhartid(); +} + +unsigned int rv_r_tp() { + return r_tp(); +} + +unsigned long rv_r_sstatus() { + return r_sstatus(); +} + +void rv_w_sstatus(unsigned long x) { + w_sstatus(x); +} + +void rv_intr_on() { + intr_on(); +} + +void rv_intr_off() { + intr_off(); +} + +int rv_intr_get() { + return intr_get(); +} + diff --git a/kernel/riscv.h b/kernel/riscv.h index 20a01db..b68d134 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -1,5 +1,7 @@ #ifndef __ASSEMBLER__ +#include "./types.h" + // which hart (core) is this? static inline uint64 r_mhartid() diff --git a/kernel/rustkernel/Cargo.lock b/kernel/rustkernel/Cargo.lock index 516fd1e..1a24024 100644 --- a/kernel/rustkernel/Cargo.lock +++ b/kernel/rustkernel/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + [[package]] name = "rustkernel" version = "0.1.0" +dependencies = [ + "libc", +] diff --git a/kernel/rustkernel/Cargo.toml b/kernel/rustkernel/Cargo.toml index 25087f9..df72791 100644 --- a/kernel/rustkernel/Cargo.toml +++ b/kernel/rustkernel/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +libc = { version = "0.2.149", default-features = false } [lib] crate-type = ["staticlib"] diff --git a/kernel/rustkernel/src/kalloc.rs b/kernel/rustkernel/src/kalloc.rs new file mode 100644 index 0000000..a4b23bd --- /dev/null +++ b/kernel/rustkernel/src/kalloc.rs @@ -0,0 +1,28 @@ +extern "C" { + fn kalloc() -> *mut u8; + fn kfree(ptr: *mut u8); +} + +use core::alloc::{GlobalAlloc, Layout}; + +struct KernelAllocator; + +unsafe impl GlobalAlloc for KernelAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if layout.size() > 4096 { + panic!("can only allocate one page of memory at a time"); + } + let ptr = kalloc(); + if ptr.is_null() { + panic!("kernel could not allocate memory"); + } + ptr + } + + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { + kfree(ptr); + } +} + +#[global_allocator] +static GLOBAL: KernelAllocator = KernelAllocator; diff --git a/kernel/rustkernel/src/lib.rs b/kernel/rustkernel/src/lib.rs index 60e595b..11e2490 100644 --- a/kernel/rustkernel/src/lib.rs +++ b/kernel/rustkernel/src/lib.rs @@ -1,12 +1,26 @@ -#![no_std] #![no_main] +#![no_std] +#![allow(dead_code)] +#![allow(clippy::missing_safety_doc)] + +extern crate alloc; +extern crate core; + +extern "C" { + fn print(message: *const c_char); + fn panic(panic_message: *const c_char) -> !; +} + +mod kalloc; +pub(crate) mod param; +pub mod proc; +pub(crate) mod riscv; +pub mod spinlock; use core::ffi::{c_char, CStr}; -extern "C" { - pub fn print(message: *const c_char); - fn panic(panic_message: *const c_char) -> !; -} +pub use proc::*; +pub use spinlock::*; #[no_mangle] pub extern "C" fn rust_main() { @@ -19,8 +33,11 @@ pub extern "C" fn rust_main() { } } - #[panic_handler] unsafe fn panic_wrapper(_panic_info: &core::panic::PanicInfo) -> ! { - panic(CStr::from_bytes_with_nul(b"panic from rust\0").unwrap_or_default().as_ptr()) + panic( + CStr::from_bytes_with_nul(b"panic from rust\0") + .unwrap_or_default() + .as_ptr(), + ) } diff --git a/kernel/rustkernel/src/param.rs b/kernel/rustkernel/src/param.rs new file mode 100644 index 0000000..8fc097c --- /dev/null +++ b/kernel/rustkernel/src/param.rs @@ -0,0 +1,26 @@ +/// Maximum number of processes +pub const NPROC: usize = 64; +/// Maximum number of CPUs +pub const NCPU: usize = 8; +/// Maximum number of open files per process +pub const NOFILE: usize = 16; +/// Maximum number of open files per system +pub const NFILE: usize = 100; +/// Maximum number of active inodes +pub const NINODE: usize = 50; +/// Maximum major device number +pub const NDEV: usize = 10; +/// Device number of file system root disk +pub const ROOTDEV: usize = 1; +/// Max exec arguments +pub const MAXARG: usize = 32; +/// Max num of blocks any FS op writes +pub const MAXOPBLOCKS: usize = 10; +/// Max data blocks in on-disk log +pub const LOGSIZE: usize = MAXOPBLOCKS * 3; +/// Size of disk block cache +pub const NBUF: usize = MAXOPBLOCKS * 3; +/// Size of file system in blocks +pub const FSSIZE: usize = 2000; +/// Maximum file path size +pub const MAXPATH: usize = 128; diff --git a/kernel/rustkernel/src/proc.rs b/kernel/rustkernel/src/proc.rs new file mode 100644 index 0000000..08d0e06 --- /dev/null +++ b/kernel/rustkernel/src/proc.rs @@ -0,0 +1,162 @@ +use crate::{ + riscv::{self, Pagetable}, + spinlock::Spinlock, +}; +use core::ffi::c_char; + +/// Saved registers for kernel context switches. +#[repr(C)] +pub struct Context { + pub ra: u64, + pub sp: u64, + + // callee-saved + pub s0: u64, + pub s1: u64, + pub s2: u64, + pub s3: u64, + pub s4: u64, + pub s5: u64, + pub s6: u64, + pub s7: u64, + pub s8: u64, + pub s9: u64, + pub s10: u64, + pub s11: u64, +} + +/// Per-CPU state. +#[repr(C)] +pub struct Cpu { + /// The process running on this cpu, or null. + pub proc: *mut Proc, + /// swtch() here to enter scheduler() + pub context: Context, + /// Depth of push_off() nesting. + pub noff: i32, + /// Were interrupts enabled before push_off()? + pub intena: i32, +} + +/// Per-process data for the trap handling code in trampoline.S. +/// +/// sits in a page by itself just under the trampoline page in the +/// user page table. not specially mapped in the kernel page table. +/// uservec in trampoline.S saves user registers in the trapframe, +/// then initializes registers from the trapframe's +/// kernel_sp, kernel_hartid, kernel_satp, and jumps to kernel_trap. +/// usertrapret() and userret in trampoline.S set up +/// the trapframe's kernel_*, restore user registers from the +/// trapframe, switch to the user page table, and enter user space. +/// the trapframe includes callee-saved user registers like s0-s11 because the +/// return-to-user path via usertrapret() doesn't return through +/// the entire kernel call stack. +#[repr(C)] +pub struct TrapFrame { + /// Kernel page table. + pub kernel_satp: u64, + /// Top of process's kernel stack. + pub kernel_sp: u64, + /// usertrap() + pub kernel_trap: u64, + /// Saved user program counter. + pub epc: u64, + /// Saved kernel tp. + pub kernel_hartid: u64, + pub ra: u64, + pub sp: u64, + pub gp: u64, + pub tp: u64, + pub t0: u64, + pub t1: u64, + pub t2: u64, + pub s0: u64, + pub s1: u64, + pub a0: u64, + pub a1: u64, + pub a2: u64, + pub a3: u64, + pub a4: u64, + pub a5: u64, + pub a6: u64, + pub a7: u64, + pub s2: u64, + pub s3: u64, + pub s4: u64, + pub s5: u64, + pub s6: u64, + pub s7: u64, + pub s8: u64, + pub s9: u64, + pub s10: u64, + pub s11: u64, + pub t3: u64, + pub t4: u64, + pub t5: u64, + pub t6: u64, +} + +#[repr(C)] +pub enum ProcState { + Unused, + Used, + Sleeping, + Runnable, + Running, + Zombie, +} + +/// Per-process state. +#[repr(C)] +pub struct Proc { + pub lock: Spinlock, + + // p->lock must be held when using these: + /// Process state + pub state: ProcState, + /// If non-zero, sleeping on chan + pub chan: *mut u8, + /// If non-zero, have been killed + pub killed: i32, + /// Exit status to be returned to parent's wait + pub xstate: i32, + /// Process ID + pub pid: i32, + + // wait_lock msut be held when using this: + /// Parent process + pub parent: *mut Proc, + + // These are private to the process, so p->lock need not be held. + /// Virtual address of kernel stack + pub kstack: u64, + /// Size of process memory (bytes) + pub sz: u64, + /// User page table + pub pagetable: Pagetable, + /// Data page for trampoline.S + pub trapframe: *mut TrapFrame, + /// swtch() here to run process + pub context: Context, + /// Open files + pub ofile: *mut u8, // TODO: Change u8 ptr to File ptr. + /// Current directory + pub cwd: *mut u8, // TODO: Change u8 ptr to inode ptr. + /// Process name (debugging) + pub name: [c_char; 16], +} + +/// Must be called with interrupts disabled +/// to prevent race with process being moved +/// to a different CPU. +#[no_mangle] +pub unsafe extern "C" fn cpuid() -> i32 { + riscv::r_tp() as i32 +} + +extern "C" { + // pub fn cpuid() -> i32; + /// Return this CPU's cpu struct. + /// Interrupts must be disabled. + pub fn mycpu() -> *mut Cpu; +} diff --git a/kernel/rustkernel/src/riscv.rs b/kernel/rustkernel/src/riscv.rs new file mode 100644 index 0000000..d934fa1 --- /dev/null +++ b/kernel/rustkernel/src/riscv.rs @@ -0,0 +1,190 @@ +use core::arch::asm; + +pub type Pte = u64; +pub type Pagetable = *mut [Pte; 512]; + +/// Previous mode +pub const MSTATUS_MPP_MASK: u64 = 3 << 11; +pub const MSTATUS_MPP_M: u64 = 3 << 11; +pub const MSTATUS_MPP_S: u64 = 1 << 11; +pub const MSTATUS_MPP_U: u64 = 0 << 11; +/// Machine-mode interrupt enable. +pub const MSTATUS_MIE: u64 = 1 << 3; + +/// Previous mode: 1 = Supervisor, 0 = User +pub const SSTATUS_SPP: u64 = 1 << 8; +/// Supervisor Previous Interrupt Enable +pub const SSTATUS_SPIE: u64 = 1 << 5; +/// User Previous Interrupt Enable +pub const SSTATUS_UPIE: u64 = 1 << 4; +/// Supervisor Interrupt Enable +pub const SSTATUS_SIE: u64 = 1 << 1; +/// User Interrupt Enable +pub const SSTATUS_UIE: u64 = 1 << 0; + +/// Supervisor External Interrupt Enable +pub const SIE_SEIE: u64 = 1 << 9; +/// Supervisor Timer Interrupt Enable +pub const SIE_STIE: u64 = 1 << 5; +/// Supervisor Software Interrupt Enable +pub const SIE_SSIE: u64 = 1 << 1; + +/// Machine-mode External Interrupt Enable +pub const MIE_MEIE: u64 = 1 << 11; +/// Machine-mode Timer Interrupt Enable +pub const MIE_MTIE: u64 = 1 << 7; +/// Machine-mode Software Interrupt Enable +pub const MIE_MSIE: u64 = 1 << 3; + +pub const SATP_SV39: u64 = 8 << 60; + +/// Bytes per page +pub const PGSIZE: u64 = 4096; +/// Bits of offset within a page +pub const PGSHIFT: u64 = 12; + +pub const PTE_V: u64 = 1 << 0; +pub const PTE_R: u64 = 1 << 1; +pub const PTE_W: u64 = 1 << 2; +pub const PTE_X: u64 = 1 << 3; +pub const PTE_U: u64 = 1 << 4; + +/// Which hart (core) is this? +#[inline(always)] +pub unsafe fn r_mhartid() -> u64 { + let x: u64; + asm!("csrr {}, mhartid", out(reg) x); + x +} + +#[inline(always)] +pub unsafe fn r_tp() -> u64 { + let x: u64; + asm!("mv {}, tp", out(reg) x); + x +} + +#[inline(always)] +pub unsafe fn w_sstatus(x: u64) { + asm!("csrw sstatus, {}", in(reg) x); +} + +#[inline(always)] +pub unsafe fn r_sstatus() -> u64 { + let x: u64; + asm!("csrr {}, sstatus", out(reg) x); + x +} + +#[inline(always)] +pub unsafe fn intr_on() { + w_sstatus(r_sstatus() | SSTATUS_SIE); +} + +#[inline(always)] +pub unsafe fn intr_off() { + w_sstatus(r_sstatus() & !SSTATUS_SIE); +} + +#[inline(always)] +pub unsafe fn intr_get() -> i32 { + if (r_sstatus() & SSTATUS_SIE) > 0 { + 1 + } else { + 0 + } +} + +extern "C" { + /// Which hart (core) is this? + pub fn rv_r_mhartid() -> u64; + + // Machine Status Register, mstatus + pub fn r_mstatus() -> u64; + pub fn w_mstatus(x: u64); + + // Machine Exception Program Counter + // MEPC holds the instruction address to which a return from exception will go. + pub fn w_mepc(x: u64); + + // Supervisor Status Register, sstatus + pub fn rv_r_sstatus() -> u64; + pub fn rv_w_sstatus(x: u64); + + // Supervisor Interrupt Pending + pub fn r_sip() -> u64; + pub fn w_sip(x: u64); + + // Supervisor Interrupt Enable + pub fn r_sie() -> u64; + pub fn w_sie(x: u64); + + // Machine-mode Interrupt Enable + pub fn r_mie() -> u64; + pub fn w_mie(x: u64); + + // Supervisor Exception Program Counter + // SEPC holds the instruction address to which a return from exception will go. + pub fn r_sepc() -> u64; + pub fn w_sepc(x: u64); + + // Machine Exception Deletgation + pub fn r_medeleg() -> u64; + pub fn w_medeleg(x: u64); + + // Machine Interrupt Deletgation + pub fn r_mideleg() -> u64; + pub fn w_mideleg(x: u64); + + // Supervisor Trap-Vector Base Address + pub fn r_stvec() -> u64; + pub fn w_stvec(x: u64); + + // Machine-mode Interrupt Vector + pub fn w_mtvec(x: u64); + + // Physical Memory Protection + pub fn w_pmpcfg0(x: u64); + pub fn w_pmpaddr0(x: u64); + + // Supervisor Address Translation and Protection + // SATP holds the address of the page table. + pub fn r_satp() -> u64; + pub fn w_satp(x: u64); + + pub fn w_mscratch(x: u64); + + // Supervisor Trap Cause + pub fn r_scause() -> u64; + + // Supervisor Trap Value + pub fn r_stval() -> u64; + + // Machine-mode Counter-Enable + pub fn r_mcounteren() -> u64; + pub fn w_mcounteren(x: u64); + + // Machine-mode cycle counter + pub fn r_time() -> u64; + + // /// Enable device interrupts + // pub fn intr_on(); + + // /// Disable device interrupts + // pub fn intr_off(); + + // // Are device interrupts enabled? + // pub fn intr_get() -> i32; + + pub fn r_sp() -> u64; + + // Read and write TP (thread pointer), which xv6 uses + // to hold this core's hartid, the index into cpus[]. + // pub fn rv_r_tp() -> u64; + pub fn w_tp(x: u64); + + pub fn r_ra() -> u64; + + /// Flush the TLB. + pub fn sfence_vma(); +} diff --git a/kernel/rustkernel/src/spinlock.rs b/kernel/rustkernel/src/spinlock.rs new file mode 100644 index 0000000..fc05a48 --- /dev/null +++ b/kernel/rustkernel/src/spinlock.rs @@ -0,0 +1,110 @@ +use crate::{ + proc::{mycpu, Cpu}, + riscv, +}; +use core::{ + ffi::c_char, + ptr::null_mut, + sync::atomic::{AtomicBool, Ordering}, +}; + +#[repr(C)] +pub struct Spinlock { + pub locked: AtomicBool, + pub name: *mut c_char, + pub cpu: *mut Cpu, +} +impl Spinlock { + /// Initializes a `Spinlock`. + pub fn new(name: *mut c_char) -> Spinlock { + Spinlock { + locked: AtomicBool::new(false), + cpu: null_mut(), + name, + } + } + /// Check whether this cpu is holding the lock. + /// + /// Interrupts must be off. + pub fn held_by_current_cpu(&self) -> bool { + self.cpu == unsafe { mycpu() } && self.locked.load(Ordering::Relaxed) + } + pub unsafe fn lock(&mut self) { + push_off(); + + if self.held_by_current_cpu() { + panic!("Attempt to acquire twice by the same CPU"); + } + + while self.locked.swap(true, Ordering::Acquire) { + core::hint::spin_loop(); + } + + // The lock is now locked and we can write our CPU info. + + self.cpu = mycpu(); + } + pub unsafe fn unlock(&mut self) { + if !self.held_by_current_cpu() { + panic!("Attempt to release lock from different CPU"); + } + + self.cpu = null_mut(); + + self.locked.store(false, Ordering::Release); + + pop_off(); + } +} + +#[no_mangle] +pub unsafe extern "C" fn initlock(lock: *mut Spinlock, name: *mut c_char) { + *lock = Spinlock::new(name); +} + +#[no_mangle] +pub unsafe extern "C" fn holding(lock: *mut Spinlock) -> i32 { + (*lock).held_by_current_cpu().into() +} + +#[no_mangle] +pub unsafe extern "C" fn acquire(lock: *mut Spinlock) { + (*lock).lock(); +} + +#[no_mangle] +pub unsafe extern "C" fn release(lock: *mut Spinlock) { + (*lock).unlock(); +} + +// push_off/pop_off are like intr_off()/intr_on() except that they are matched: +// it takes two pop_off()s to undo two push_off()s. Also, if interrupts +// are initially off, then push_off, pop_off leaves them off. + +#[no_mangle] +pub unsafe extern "C" fn push_off() { + let old = riscv::intr_get(); + let cpu = mycpu(); + + riscv::intr_off(); + if (*cpu).noff == 0 { + (*cpu).intena = old; + } + (*cpu).noff += 1; +} +#[no_mangle] +pub unsafe extern "C" fn pop_off() { + let cpu = mycpu(); + + if riscv::intr_get() == 1 { + panic!("pop_off - interruptible"); + } else if (*cpu).noff < 1 { + panic!("pop_off"); + } + + (*cpu).noff -= 1; + + if (*cpu).noff == 0 && (*cpu).intena == 1 { + riscv::intr_on(); + } +} diff --git a/kernel/spinlock.c b/kernel/spinlock.c deleted file mode 100644 index 9840302..0000000 --- a/kernel/spinlock.c +++ /dev/null @@ -1,110 +0,0 @@ -// 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" - -void -initlock(struct spinlock *lk, char *name) -{ - lk->name = name; - lk->locked = 0; - lk->cpu = 0; -} - -// 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)) - panic("acquire"); - - // 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) - ; - - // 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. -void -release(struct spinlock *lk) -{ - if(!holding(lk)) - panic("release"); - - 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(); -} - -// Check whether this cpu is holding the lock. -// Interrupts must be off. -int -holding(struct spinlock *lk) -{ - int r; - r = (lk->locked && lk->cpu == mycpu()); - return r; -} - -// push_off/pop_off are like intr_off()/intr_on() except that they are matched: -// it takes two pop_off()s to undo two push_off()s. Also, if interrupts -// are initially off, then push_off, pop_off leaves them off. - -void -push_off(void) -{ - int old = intr_get(); - - intr_off(); - if(mycpu()->noff == 0) - mycpu()->intena = old; - mycpu()->noff += 1; -} - -void -pop_off(void) -{ - struct cpu *c = mycpu(); - if(intr_get()) - panic("pop_off - interruptible"); - if(c->noff < 1) - panic("pop_off"); - c->noff -= 1; - if(c->noff == 0 && c->intena) - intr_on(); -} diff --git a/kernel/types.h b/kernel/types.h index ee73164..9bdd99e 100644 --- a/kernel/types.h +++ b/kernel/types.h @@ -1,3 +1,5 @@ +#pragma once + typedef unsigned int uint; typedef unsigned short ushort; typedef unsigned char uchar;