diff --git a/kernel/defs.h b/kernel/defs.h index f98ccc9..ec8fdfd 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -83,7 +83,6 @@ int pipewrite(struct pipe*, uint64, int); // printf.c __attribute__((noreturn)) void panic(char *s); -void printfinit(void); void printstr(char *s); void printint(int n); void printhex(int n); diff --git a/kernel/rustkernel/src/console/mod.rs b/kernel/rustkernel/src/console/mod.rs index 4f2f2d0..1c20fd5 100644 --- a/kernel/rustkernel/src/console/mod.rs +++ b/kernel/rustkernel/src/console/mod.rs @@ -14,7 +14,7 @@ pub mod uart; use crate::{ fs::file::{devsw, CONSOLE}, proc::{killed, myproc, procdump, wakeup}, - sync::spinmutex::SpinMutex, + sync::mutex::Mutex, }; use core::{ffi::c_void, ptr::addr_of_mut}; use uart::UART0; @@ -54,7 +54,7 @@ impl core::fmt::Write for Console { } #[no_mangle] -pub static cons: SpinMutex = SpinMutex::new(Console { +pub static cons: Mutex = Mutex::new(Console { buffer: [0u8; INPUT_BUF_SIZE], read_index: 0, write_index: 0, @@ -108,7 +108,7 @@ pub fn consoleread(user_dst: i32, mut dst: u64, mut n: i32) -> i32 { let mut c; let mut cbuf; - let mut console = cons.lock(); + let mut console = cons.lock_spinning(); while n > 0 { // Wait until interrupt handler has put @@ -172,7 +172,7 @@ pub unsafe fn consoleinit() { /// Do erase/kill processing, then append to cons.buf. /// Wake up consoleread() if a whole line has arrived. pub fn consoleintr(mut c: u8) { - let mut console = cons.lock(); + let mut console = cons.lock_spinning(); if c == ctrl_x(b'P') { // Print process list. diff --git a/kernel/rustkernel/src/console/printf.rs b/kernel/rustkernel/src/console/printf.rs index 4439faa..597b806 100644 --- a/kernel/rustkernel/src/console/printf.rs +++ b/kernel/rustkernel/src/console/printf.rs @@ -1,30 +1,33 @@ -use crate::sync::spinlock::Spinlock; +use crate::sync::lock::Lock; use core::ffi::{c_char, CStr}; pub use crate::panic; -#[no_mangle] -pub static mut PRINT_LOCK: Spinlock = Spinlock::new(); - -#[repr(C)] -pub struct PrintLock { - pub lock: Spinlock, - pub locking: i32, -} +pub static PRINT_LOCK: Lock = Lock::new(); +/// Print out formatted text to the UART. +/// Spins to acquire the lock. macro_rules! print { ($($arg:tt)*) => {{ use core::fmt::Write; - // Still unsafe because static mut. - let _guard = unsafe { $crate::console::printf::PRINT_LOCK.lock() }; + let _guard = $crate::console::printf::PRINT_LOCK.lock_spinning(); + let mut cons = $crate::console::cons.lock_spinning(); - let mut cons = $crate::console::cons.lock(); let _ = core::write!(cons.as_mut(), $($arg)*); }}; } pub(crate) use print; +macro_rules! println { + ($($arg:tt)*) => {{ + use $crate::console::printf::print; + print!($($arg)*); + print!("\n"); + }}; +} +pub(crate) use println; + #[no_mangle] pub extern "C" fn printint(n: i32) { print!("{}", n); @@ -45,8 +48,3 @@ pub unsafe extern "C" fn printstr(s: *const c_char) { let s = CStr::from_ptr(s).to_str().unwrap_or_default(); print!("{}", s); } - -#[no_mangle] -pub unsafe extern "C" fn printfinit() { - PRINT_LOCK = Spinlock::new(); -} diff --git a/kernel/rustkernel/src/lib.rs b/kernel/rustkernel/src/lib.rs index 26d4abc..62dbd4d 100644 --- a/kernel/rustkernel/src/lib.rs +++ b/kernel/rustkernel/src/lib.rs @@ -24,7 +24,7 @@ pub mod trap; use crate::proc::cpuid; use core::ffi::{c_char, CStr}; -pub(crate) use crate::console::printf::print; +pub(crate) use crate::console::printf::{print, println}; pub static mut STARTED: bool = false; pub static mut PANICKED: bool = false; @@ -60,9 +60,8 @@ pub const MAXPATH: usize = 128; pub unsafe extern "C" fn main() -> ! { if cpuid() == 0 { console::consoleinit(); - console::printf::printfinit(); mem::kalloc::kinit(); - print!("\nxv6 kernel is booting\n"); + println!("\nxv6 kernel is booting"); mem::virtual_memory::kvminit(); mem::virtual_memory::kvminithart(); proc::procinit(); @@ -97,21 +96,21 @@ fn panic_wrapper(panic_info: &core::panic::PanicInfo) -> ! { } if let Some(s) = panic_info.message() { - print!("{}\n", s); + println!("{}", s); } else if let Some(s) = panic_info.payload().downcast_ref::<&str>() { - print!("{}\n", s); + println!("{}", s); } else if let Some(s) = panic_info.payload().downcast_ref::<&CStr>() { - print!("{:?}\n", s); + println!("{:?}", s); } else { - print!("could not recover error message\n"); + println!("could not recover error message"); } - print!("███████╗██╗ ██╗ ██████╗██╗ ██╗██╗██╗\n"); - print!("██╔════╝██║ ██║██╔════╝██║ ██╔╝██║██║\n"); - print!("█████╗ ██║ ██║██║ █████╔╝ ██║██║\n"); - print!("██╔══╝ ██║ ██║██║ ██╔═██╗ ╚═╝╚═╝\n"); - print!("██║ ╚██████╔╝╚██████╗██║ ██╗██╗██╗\n"); - print!("╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚═╝╚═╝\n"); + println!("███████╗██╗ ██╗ ██████╗██╗ ██╗██╗██╗"); + println!("██╔════╝██║ ██║██╔════╝██║ ██╔╝██║██║"); + println!("█████╗ ██║ ██║██║ █████╔╝ ██║██║"); + println!("██╔══╝ ██║ ██║██║ ██╔═██╗ ╚═╝╚═╝"); + println!("██║ ╚██████╔╝╚██████╗██║ ██╗██╗██╗"); + println!("╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚═╝╚═╝"); unsafe { crate::PANICKED = true; diff --git a/kernel/rustkernel/src/sync/lock.rs b/kernel/rustkernel/src/sync/lock.rs new file mode 100644 index 0000000..52c50a2 --- /dev/null +++ b/kernel/rustkernel/src/sync/lock.rs @@ -0,0 +1,105 @@ +use super::LockStrategy; +use crate::proc::{myproc, sched, sleep, wakeup, ProcState}; +use core::{ + cell::UnsafeCell, + ops::Drop, + ptr::{addr_of, null_mut}, + sync::atomic::{AtomicBool, Ordering}, +}; + +pub struct Lock { + locked: AtomicBool, + lock_strategy: UnsafeCell, +} +impl Lock { + pub const fn new() -> Lock { + Lock { + locked: AtomicBool::new(false), + lock_strategy: UnsafeCell::new(LockStrategy::Spin), + } + } + pub fn lock_strategy(&self) -> LockStrategy { + unsafe { *self.lock_strategy.get() } + } + + pub unsafe fn lock_unguarded(&self, lock_strategy: LockStrategy) { + // Lock it first, then store the lock strategy. + + match lock_strategy { + LockStrategy::Spin => { + crate::trap::push_intr_off(); + + while self.locked.swap(true, Ordering::Acquire) { + core::hint::spin_loop(); + } + } + LockStrategy::Sleep => { + while self.locked.swap(true, Ordering::Acquire) { + // Put the process to sleep until the mutex gets released. + sleep(addr_of!(*self).cast_mut().cast()); + } + } + }; + + *self.lock_strategy.get() = lock_strategy; + } + pub fn lock(&self, lock_strategy: LockStrategy) -> LockGuard<'_> { + unsafe { + self.lock_unguarded(lock_strategy); + } + LockGuard { lock: self } + } + pub fn lock_spinning(&self) -> LockGuard<'_> { + self.lock(LockStrategy::Spin) + } + pub fn lock_sleeping(&self) -> LockGuard<'_> { + self.lock(LockStrategy::Sleep) + } + pub unsafe fn unlock(&self) { + let lock_strategy = self.lock_strategy(); + self.locked.store(false, Ordering::Release); + + match lock_strategy { + LockStrategy::Spin => { + crate::trap::pop_intr_off(); + } + LockStrategy::Sleep => { + wakeup(addr_of!(*self).cast_mut().cast()); + } + } + } +} +impl Default for Lock { + fn default() -> Lock { + Lock::new() + } +} +unsafe impl Sync for Lock {} + +pub struct LockGuard<'l> { + pub lock: &'l Lock, +} +impl<'l> LockGuard<'l> { + /// Sleep until `wakeup(chan)` is called somewhere + /// else, yielding access to the lock until then. + pub unsafe fn sleep(&self, chan: *mut core::ffi::c_void) { + let p = myproc(); + let _guard = (*p).lock.lock(); + let strategy = self.lock.lock_strategy(); + self.lock.unlock(); + + // Put the process to sleep. + (*p).chan = chan; + (*p).state = ProcState::Sleeping; + sched(); + + // Tidy up and reacquire the lock. + (*p).chan = null_mut(); + self.lock.lock_unguarded(strategy); + } +} +impl<'l> Drop for LockGuard<'l> { + fn drop(&mut self) { + unsafe { self.lock.unlock() } + } +} diff --git a/kernel/rustkernel/src/sync/mod.rs b/kernel/rustkernel/src/sync/mod.rs index 3d543ce..517d951 100644 --- a/kernel/rustkernel/src/sync/mod.rs +++ b/kernel/rustkernel/src/sync/mod.rs @@ -1,3 +1,13 @@ +pub mod lock; +pub mod mutex; + +// These have to stick around until the entire program is in rust =( pub mod sleeplock; pub mod spinlock; -pub mod spinmutex; + +#[derive(Copy, Clone, Debug, Default, PartialEq)] +pub enum LockStrategy { + #[default] + Spin, + Sleep, +} diff --git a/kernel/rustkernel/src/sync/mutex.rs b/kernel/rustkernel/src/sync/mutex.rs new file mode 100644 index 0000000..952f877 --- /dev/null +++ b/kernel/rustkernel/src/sync/mutex.rs @@ -0,0 +1,85 @@ +use super::{ + lock::{Lock, LockGuard}, + LockStrategy, +}; +use core::{ + cell::UnsafeCell, + convert::{AsMut, AsRef}, + ops::{Deref, DerefMut, Drop}, +}; + +pub struct Mutex { + lock: Lock, + inner: UnsafeCell, +} +impl Mutex { + pub const fn new(value: T) -> Mutex { + Mutex { + lock: Lock::new(), + inner: UnsafeCell::new(value), + } + } + pub unsafe fn as_inner(&self) -> *mut T { + self.inner.get() + } + pub unsafe fn lock_unguarded(&self, lock_strategy: LockStrategy) { + self.lock.lock_unguarded(lock_strategy); + } + pub fn lock(&self, lock_strategy: LockStrategy) -> MutexGuard<'_, T> { + unsafe { + self.lock_unguarded(lock_strategy); + } + MutexGuard { mutex: self } + } + pub fn lock_spinning(&self) -> MutexGuard<'_, T> { + self.lock(LockStrategy::Spin) + } + pub fn lock_sleeping(&self) -> MutexGuard<'_, T> { + self.lock(LockStrategy::Sleep) + } + pub unsafe fn unlock(&self) { + self.lock.unlock(); + } +} +unsafe impl Sync for Mutex where T: Send {} + +pub struct MutexGuard<'m, T> { + pub mutex: &'m Mutex, +} +impl<'m, T> MutexGuard<'m, T> { + /// Sleep until `wakeup(chan)` is called somewhere else, yielding access to the mutex until then. + pub unsafe fn sleep(&mut self, chan: *mut core::ffi::c_void) { + let guard = LockGuard { + lock: &self.mutex.lock, + }; + guard.sleep(chan); + core::mem::forget(guard); + } +} +impl<'m, T> Deref for MutexGuard<'m, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.mutex.as_inner() } + } +} +impl<'m, T> DerefMut for MutexGuard<'m, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.mutex.as_inner() } + } +} +impl<'m, T> AsRef for MutexGuard<'m, T> { + fn as_ref(&self) -> &T { + self.deref() + } +} +impl<'m, T> AsMut for MutexGuard<'m, T> { + fn as_mut(&mut self) -> &mut T { + self.deref_mut() + } +} +impl<'m, T> Drop for MutexGuard<'m, T> { + fn drop(&mut self) { + unsafe { self.mutex.unlock() } + } +} diff --git a/kernel/rustkernel/src/sync/spinmutex.rs b/kernel/rustkernel/src/sync/spinmutex.rs deleted file mode 100644 index ec9330e..0000000 --- a/kernel/rustkernel/src/sync/spinmutex.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::{ - proc::{myproc, sched, ProcState}, - sync::spinlock::Spinlock, -}; -use core::{ - cell::UnsafeCell, - convert::{AsMut, AsRef}, - ops::{Deref, DerefMut, Drop}, - ptr::null_mut, -}; - -pub struct SpinMutex { - lock: Spinlock, - inner: UnsafeCell, -} -impl SpinMutex { - pub const fn new(value: T) -> SpinMutex { - SpinMutex { - lock: Spinlock::new(), - inner: UnsafeCell::new(value), - } - } - pub unsafe fn as_inner(&self) -> *mut T { - self.inner.get() - } - pub unsafe fn lock_unguarded(&self) { - self.lock.lock_unguarded(); - } - pub fn lock(&self) -> SpinMutexGuard<'_, T> { - unsafe { - self.lock_unguarded(); - } - SpinMutexGuard { mutex: self } - } - pub unsafe fn unlock(&self) { - self.lock.unlock(); - } -} -unsafe impl Sync for SpinMutex where T: Send {} - -pub struct SpinMutexGuard<'m, T> { - pub mutex: &'m SpinMutex, -} -impl<'m, T> SpinMutexGuard<'m, T> { - /// Sleep until `wakeup(chan)` is called somewhere else, yielding access to the mutex until then. - pub unsafe fn sleep(&mut self, chan: *mut core::ffi::c_void) { - let p = myproc(); - let _guard = (*p).lock.lock(); - self.mutex.unlock(); - - // Put the process to sleep. - (*p).chan = chan; - (*p).state = ProcState::Sleeping; - sched(); - - // Tidy up and reacquire the mutex. - (*p).chan = null_mut(); - self.mutex.lock_unguarded(); - } -} -impl<'m, T> Deref for SpinMutexGuard<'m, T> { - type Target = T; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.mutex.as_inner() } - } -} -impl<'m, T> DerefMut for SpinMutexGuard<'m, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *self.mutex.as_inner() } - } -} -impl<'m, T> AsRef for SpinMutexGuard<'m, T> { - fn as_ref(&self) -> &T { - self.deref() - } -} -impl<'m, T> AsMut for SpinMutexGuard<'m, T> { - fn as_mut(&mut self) -> &mut T { - self.deref_mut() - } -} -impl<'m, T> Drop for SpinMutexGuard<'m, T> { - fn drop(&mut self) { - unsafe { self.mutex.unlock() } - } -} diff --git a/kernel/rustkernel/src/syscall.rs b/kernel/rustkernel/src/syscall.rs index 0c4e10f..833f56f 100644 --- a/kernel/rustkernel/src/syscall.rs +++ b/kernel/rustkernel/src/syscall.rs @@ -1,5 +1,5 @@ use crate::{ - console::printf::print, + println, proc::{self, myproc, sleep_lock}, riscv::{memlayout::QEMU_POWER, Pagetable}, string::strlen, @@ -261,25 +261,11 @@ pub unsafe extern "C" fn syscall() { let p = myproc(); let num = (*(*p).trapframe).a7; - // print!("syscall {}\n", num); - (*(*p).trapframe).a0 = match TryInto::::try_into(num as usize) { Ok(syscall) => syscall.call(), Err(_) => { - print!("{} unknown syscall {}\n", (*p).pid, num); + println!("{} unknown syscall {}", (*p).pid, num); -1i64 as u64 } }; } - -// #[no_mangle] -// pub unsafe extern "C" fn rust_syscall(num: u64) -> u64 { -// match TryInto::::try_into(num as usize) { -// Ok(syscall) => syscall.call(), -// Err(_) => { -// print!("unknown syscall {}\n", num); -// -1i64 as u64 -// } -// } -// } -// diff --git a/kernel/rustkernel/src/trap.rs b/kernel/rustkernel/src/trap.rs index 98f265b..2c234af 100644 --- a/kernel/rustkernel/src/trap.rs +++ b/kernel/rustkernel/src/trap.rs @@ -1,5 +1,5 @@ use crate::{ - console::printf::print, + println, proc::{cpuid, exit, killed, mycpu, myproc, r#yield, setkilled, wakeup, ProcState}, riscv::*, sync::spinlock::Spinlock, @@ -60,7 +60,7 @@ pub unsafe extern "C" fn devintr() -> i32 { } else if irq == VIRTIO0_IRQ { virtio_disk_intr(); } else if irq > 0 { - print!("unexpected interrupt irq={}\n", irq); + println!("unexpected interrupt irq={}", irq); } // The PLIC allows each device to raise at most one @@ -198,7 +198,7 @@ pub unsafe extern "C" fn kerneltrap() { let which_dev = devintr(); if which_dev == 0 { - print!("scause {}\nsepc={} stval={}\n", scause, r_sepc(), r_stval()); + println!("scause {}\nsepc={} stval={}", scause, r_sepc(), r_stval()); panic!("kerneltrap"); } else if which_dev == 2 && !myproc().is_null() && (*myproc()).state == ProcState::Running { // Give up the CPU if this is a timer interrupt. @@ -249,7 +249,7 @@ pub unsafe extern "C" fn usertrap() { let which_dev = devintr(); if r_scause() != 8 && which_dev == 0 { - print!( + println!( "usertrap(): unexpected scause {} {}\n\tsepc={} stval={}", r_scause(), (*p).pid,