Rewrite spinlock.c
This commit is contained in:
parent
b30ea849d1
commit
709ec3a50f
5
Makefile
5
Makefile
@ -10,7 +10,6 @@ OBJS = \
|
|||||||
$K/printf.o \
|
$K/printf.o \
|
||||||
$K/uart.o \
|
$K/uart.o \
|
||||||
$K/kalloc.o \
|
$K/kalloc.o \
|
||||||
$K/spinlock.o \
|
|
||||||
$K/string.o \
|
$K/string.o \
|
||||||
$K/main.o \
|
$K/main.o \
|
||||||
$K/vm.o \
|
$K/vm.o \
|
||||||
@ -30,7 +29,8 @@ OBJS = \
|
|||||||
$K/sysfile.o \
|
$K/sysfile.o \
|
||||||
$K/kernelvec.o \
|
$K/kernelvec.o \
|
||||||
$K/plic.o \
|
$K/plic.o \
|
||||||
$K/virtio_disk.o
|
$K/virtio_disk.o \
|
||||||
|
$K/riscv.o
|
||||||
|
|
||||||
# riscv64-unknown-elf- or riscv64-linux-gnu-
|
# riscv64-unknown-elf- or riscv64-linux-gnu-
|
||||||
# perhaps in /opt/riscv/bin
|
# 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
|
$K/kernel: $(OBJS) $K/kernel.ld $U/initcode $R/src
|
||||||
cargo +nightly -Z unstable-options -C $R build
|
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
|
$(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) -S $K/kernel > $K/kernel.asm
|
||||||
$(OBJDUMP) -t $K/kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $K/kernel.sym
|
$(OBJDUMP) -t $K/kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $K/kernel.sym
|
||||||
|
@ -110,7 +110,7 @@ void procdump(void);
|
|||||||
// swtch.S
|
// swtch.S
|
||||||
void swtch(struct context*, struct context*);
|
void swtch(struct context*, struct context*);
|
||||||
|
|
||||||
// spinlock.c
|
// spinlock.rs
|
||||||
void acquire(struct spinlock*);
|
void acquire(struct spinlock*);
|
||||||
int holding(struct spinlock*);
|
int holding(struct spinlock*);
|
||||||
void initlock(struct spinlock*, char*);
|
void initlock(struct spinlock*, char*);
|
||||||
|
@ -61,12 +61,12 @@ procinit(void)
|
|||||||
// Must be called with interrupts disabled,
|
// Must be called with interrupts disabled,
|
||||||
// to prevent race with process being moved
|
// to prevent race with process being moved
|
||||||
// to a different CPU.
|
// to a different CPU.
|
||||||
int
|
// int
|
||||||
cpuid()
|
// cpuid()
|
||||||
{
|
// {
|
||||||
int id = r_tp();
|
// int id = r_tp();
|
||||||
return id;
|
// return id;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Return this CPU's cpu struct.
|
// Return this CPU's cpu struct.
|
||||||
// Interrupts must be disabled.
|
// Interrupts must be disabled.
|
||||||
|
@ -105,3 +105,5 @@ struct proc {
|
|||||||
struct inode *cwd; // Current directory
|
struct inode *cwd; // Current directory
|
||||||
char name[16]; // Process name (debugging)
|
char name[16]; // Process name (debugging)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int cpuid();
|
||||||
|
30
kernel/riscv.c
Normal file
30
kernel/riscv.c
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
|||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
#include "./types.h"
|
||||||
|
|
||||||
// which hart (core) is this?
|
// which hart (core) is this?
|
||||||
static inline uint64
|
static inline uint64
|
||||||
r_mhartid()
|
r_mhartid()
|
||||||
|
9
kernel/rustkernel/Cargo.lock
generated
9
kernel/rustkernel/Cargo.lock
generated
@ -2,6 +2,15 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.149"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustkernel"
|
name = "rustkernel"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
libc = { version = "0.2.149", default-features = false }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["staticlib"]
|
crate-type = ["staticlib"]
|
||||||
|
28
kernel/rustkernel/src/kalloc.rs
Normal file
28
kernel/rustkernel/src/kalloc.rs
Normal file
@ -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;
|
@ -1,12 +1,26 @@
|
|||||||
#![no_std]
|
|
||||||
#![no_main]
|
#![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};
|
use core::ffi::{c_char, CStr};
|
||||||
|
|
||||||
extern "C" {
|
pub use proc::*;
|
||||||
pub fn print(message: *const c_char);
|
pub use spinlock::*;
|
||||||
fn panic(panic_message: *const c_char) -> !;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn rust_main() {
|
pub extern "C" fn rust_main() {
|
||||||
@ -19,8 +33,11 @@ pub extern "C" fn rust_main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
unsafe fn panic_wrapper(_panic_info: &core::panic::PanicInfo) -> ! {
|
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(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
26
kernel/rustkernel/src/param.rs
Normal file
26
kernel/rustkernel/src/param.rs
Normal file
@ -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;
|
162
kernel/rustkernel/src/proc.rs
Normal file
162
kernel/rustkernel/src/proc.rs
Normal file
@ -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;
|
||||||
|
}
|
190
kernel/rustkernel/src/riscv.rs
Normal file
190
kernel/rustkernel/src/riscv.rs
Normal file
@ -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();
|
||||||
|
}
|
110
kernel/rustkernel/src/spinlock.rs
Normal file
110
kernel/rustkernel/src/spinlock.rs
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
|
||||||
}
|
|
@ -1,3 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
typedef unsigned int uint;
|
typedef unsigned int uint;
|
||||||
typedef unsigned short ushort;
|
typedef unsigned short ushort;
|
||||||
typedef unsigned char uchar;
|
typedef unsigned char uchar;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user