diff --git a/kernel/Makefile b/kernel/Makefile index acca445..ae79794 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -77,6 +77,7 @@ endif ld := $(prefix)ld objdump := $(prefix)objdump cc := $(prefix)gcc +CC := $(cc) as := $(prefix)as .PHONY: all clean run build asm doc justrun kernel diff --git a/kernel/build.rs b/kernel/build.rs index af15f66..0cd473a 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -12,6 +12,12 @@ fn main() { // .compile("cobj"); gen_vector_asm().unwrap(); } + if std::env::var("TARGET").unwrap().find("riscv32").is_some() { + cc::Build::new() + .file("src/arch/riscv32/compiler_rt.c") + .flag("-march=rv32ima") + .compile("atomic_rt"); + } } fn gen_vector_asm() -> Result<()> { diff --git a/kernel/src/arch/riscv32/compiler_rt.c b/kernel/src/arch/riscv32/compiler_rt.c new file mode 100644 index 0000000..8aa0e99 --- /dev/null +++ b/kernel/src/arch/riscv32/compiler_rt.c @@ -0,0 +1,57 @@ + + +// fn __atomic_load_1_workaround(src: *const u8) -> u8; +// fn __atomic_load_2_workaround(src: *const u16) -> u16; +// fn __atomic_load_4_workaround(src: *const u32) -> u32; +// fn __atomic_store_1_workaround(dst: *mut u8, val: u8); +// fn __atomic_store_4_workaround(dst: *mut u32, val: u32); +// fn __atomic_compare_exchange_1_workaround(dst: *mut u8, expected: *mut u8, desired: u8) -> bool; +// fn __atomic_compare_exchange_4_workaround(dst: *mut u32, expected: *mut u32, desired: u32) -> bool; + +char __atomic_load_1_workaround(char *src) { + char res = 0; + __asm__ __volatile__("amoadd.w.rl %0, zero, (%1)" : "=r"(res) : "r"(src) : "memory"); + return res; +} + +short __atomic_load_2_workaround(short *src) { + short res = 0; + __asm__ __volatile__("amoadd.w.rl %0, zero, (%1)" : "=r"(res) : "r"(src) : "memory"); + return res; +} + +int __atomic_load_4_workaround(int *src) { + int res = 0; + __asm__ __volatile__("amoadd.w.rl %0, zero, (%1)" : "=r"(res) : "r"(src) : "memory"); + return res; +} + +char __atomic_store_1_workaround(char *dst, char val) { + __asm__ __volatile__("amoswap.w.aq zero, %0, (%1)" :: "r"(val), "r"(dst) : "memory"); +} + +int __atomic_store_4_workaround(int *dst, int val) { + __asm__ __volatile__("amoswap.w.aq zero, %0, (%1)" :: "r"(val), "r"(dst) : "memory"); +} + +char __atomic_compare_exchange_1_workaround(char* dst, char* expected, char desired) { + char val = 0; + __asm__ __volatile__("lr.w %0, (%1)" : "=r"(val) : "r"(dst) : "memory"); + if (val == *expected) { + int sc_ret = 0; + __asm__ __volatile__("sc.w %0, %1, (%2)" : "=r"(sc_ret) : "r"(desired), "r"(dst) : "memory"); + return sc_ret == 0; + } + return 0; +} + +char __atomic_compare_exchange_4_workaround(int* dst, int* expected, int desired) { + int val = 0; + __asm__ __volatile__("lr.w %0, (%1)" : "=r"(val) : "r"(dst) : "memory"); + if (val == *expected) { + int sc_ret = 0; + __asm__ __volatile__("sc.w %0, %1, (%2)" : "=r"(sc_ret) : "r"(desired), "r"(dst) : "memory"); + return sc_ret == 0; + } + return 0; +} \ No newline at end of file diff --git a/kernel/src/arch/riscv32/compiler_rt.rs b/kernel/src/arch/riscv32/compiler_rt.rs index 8b0a685..bb94eb0 100644 --- a/kernel/src/arch/riscv32/compiler_rt.rs +++ b/kernel/src/arch/riscv32/compiler_rt.rs @@ -2,6 +2,17 @@ //! //! [atomic](http://llvm.org/docs/Atomics.html#libcalls-atomic) +#[link(name = "atomic_rt")] +extern { + fn __atomic_load_1_workaround(src: *const u8) -> u8; + fn __atomic_load_2_workaround(src: *const u16) -> u16; + fn __atomic_load_4_workaround(src: *const u32) -> u32; + fn __atomic_store_1_workaround(dst: *mut u8, val: u8); + fn __atomic_store_4_workaround(dst: *mut u32, val: u32); + fn __atomic_compare_exchange_1_workaround(dst: *mut u8, expected: *mut u8, desired: u8) -> bool; + fn __atomic_compare_exchange_4_workaround(dst: *mut u32, expected: *mut u32, desired: u32) -> bool; +} + /// Copy from: /// https://github.com/rust-lang-nursery/compiler-builtins/blob/master/src/riscv32.rs #[no_mangle] @@ -28,59 +39,53 @@ use core::ptr::{read, write}; #[no_mangle] pub unsafe extern fn __atomic_load_1(src: *const u8) -> u8 { - let mut res: u8 = 0; - asm!("amoadd.w.rl $0, zero, ($1)" : "=r"(res) : "r"(src) : "memory" : "volatile"); - res + __atomic_load_1_workaround(src) } #[no_mangle] pub unsafe extern fn __atomic_load_2(src: *const u16) -> u16 { - let mut res: u16 = 0; - asm!("amoadd.w.rl $0, zero, ($1)" : "=r"(res) : "r"(src) : "memory" : "volatile"); - res + __atomic_load_2_workaround(src) } #[no_mangle] pub unsafe extern fn __atomic_load_4(src: *const u32) -> u32 { - let mut res: u32 = 0; - asm!("amoadd.w.rl $0, zero, ($1)" : "=r"(res) : "r"(src) : "memory" : "volatile"); - res + __atomic_load_4_workaround(src) } #[no_mangle] pub unsafe extern fn __atomic_store_1(dst: *mut u8, val: u8) { - asm!("amoswap.w.aq zero, $0, ($1)" :: "r"(val), "r"(dst) : "memory" : "volatile"); + __atomic_store_1_workaround(dst, val); } #[no_mangle] pub unsafe extern fn __atomic_store_4(dst: *mut u32, val: u32) { - asm!("amoswap.w.aq zero, $0, ($1)" :: "r"(val), "r"(dst) : "memory" : "volatile"); + __atomic_store_4_workaround(dst, val); } -unsafe fn __atomic_compare_exchange(dst: *mut T, expected: *mut T, desired: T) -> bool { - // use super::interrupt; - // let flags = interrupt::disable_and_store(); - // let val = read(dst); - // let success = val == read(expected); - // write(dst, if success {desired} else {val}); - // interrupt::restore(flags); - // success - let mut val: T; - asm!("lr.w $0, ($1)" : "=r"(val) : "r"(dst) : "memory" : "volatile"); - if val == *expected { - let mut sc_ret = 0; - asm!("sc.w $0, $1, ($2)" : "=r"(sc_ret) : "r"(desired), "r"(dst) : "memory" : "volatile"); - return sc_ret == 0 - } - false -} +// unsafe fn __atomic_compare_exchange(dst: *mut T, expected: *mut T, desired: T) -> bool { +// // use super::interrupt; +// // let flags = interrupt::disable_and_store(); +// // let val = read(dst); +// // let success = val == read(expected); +// // write(dst, if success {desired} else {val}); +// // interrupt::restore(flags); +// // success +// // let mut val: T; +// // asm!("lr.w $0, ($1)" : "=r"(val) : "r"(dst) : "memory" : "volatile"); +// // if val == *expected { +// // let mut sc_ret = 0; +// // asm!("sc.w $0, $1, ($2)" : "=r"(sc_ret) : "r"(desired), "r"(dst) : "memory" : "volatile"); +// // return sc_ret == 0 +// // } +// false +// } #[no_mangle] pub unsafe extern fn __atomic_compare_exchange_1(dst: *mut u8, expected: *mut u8, desired: u8) -> bool { - __atomic_compare_exchange(dst, expected, desired) + __atomic_compare_exchange_1_workaround(dst, expected, desired) } #[no_mangle] pub unsafe extern fn __atomic_compare_exchange_4(dst: *mut u32, expected: *mut u32, desired: u32) -> bool { - __atomic_compare_exchange(dst, expected, desired) + __atomic_compare_exchange_4_workaround(dst, expected, desired) } \ No newline at end of file diff --git a/kernel/src/logging.rs b/kernel/src/logging.rs index 0aeb89a..c1f2241 100644 --- a/kernel/src/logging.rs +++ b/kernel/src/logging.rs @@ -1,8 +1,10 @@ use core::fmt; use log::{self, Level, LevelFilter, Log, Metadata, Record}; -use spin::Mutex; +use sync::SpinLock as Mutex; -static log_mutex: Mutex<()> = Mutex::new(()); +lazy_static! { + static ref log_mutex: Mutex<()> = Mutex::new(()); +} pub fn init() { static LOGGER: SimpleLogger = SimpleLogger; diff --git a/kernel/src/sync/arch/riscv32/atomic_lock.rs b/kernel/src/sync/arch/riscv32/atomic_lock.rs new file mode 100644 index 0000000..0ee4c91 --- /dev/null +++ b/kernel/src/sync/arch/riscv32/atomic_lock.rs @@ -0,0 +1,40 @@ +//! RISCV atomic is not currently supported by Rust. +//! This is a ugly workaround. + + +use arch::compiler_rt::{__atomic_compare_exchange_4, __atomic_store_4, __atomic_load_4}; +use core::cell::UnsafeCell; + +pub struct AtomicLock +{ + lock: UnsafeCell +} + +impl AtomicLock +{ + pub fn new() -> Self { + AtomicLock { + lock: UnsafeCell::new(0) + } + } + + /// Returns 1 if lock is acquired + pub fn try_lock(&self) -> bool { + let mut expected: u32 = 0; + unsafe { + __atomic_compare_exchange_4(self.lock.get(), &mut expected as *mut u32, 1) + } + } + + pub fn load(&self) -> bool { + unsafe { + __atomic_load_4(self.lock.get()) == 1 + } + } + + pub fn store(&self) { + unsafe { + __atomic_store_4(self.lock.get(), 0); + } + } +} diff --git a/kernel/src/sync/arch/x86_64/atomic_lock.rs b/kernel/src/sync/arch/x86_64/atomic_lock.rs new file mode 100644 index 0000000..ddd4b23 --- /dev/null +++ b/kernel/src/sync/arch/x86_64/atomic_lock.rs @@ -0,0 +1,30 @@ + +pub struct AtomicLock +{ + lock: usize +} + +impl AtomicLock +{ + pub fn new() -> AtomicLock { + AtomicLock { + lock: ATOMIC_BOOL_INIT + } + } + + pub fn try_lock(&self) -> bool { + self.lock.compare_and_swap(false, true, Ordering::Acquire) == false + } + + pub fn load(&self) -> bool { + self.lock.load(Ordering::Relaxed) + } + + pub fn store(&self) { + self.lock.store(false, Ordering::Release); + } +} + +pub const ATOMIC_LOCK_INIT: AtomicLock = AtomicLock { + lock: ATOMIC_BOOL_INIT +}; \ No newline at end of file diff --git a/kernel/src/sync/mod.rs b/kernel/src/sync/mod.rs index cfa5071..c2bae78 100644 --- a/kernel/src/sync/mod.rs +++ b/kernel/src/sync/mod.rs @@ -53,6 +53,15 @@ pub use self::condvar::*; pub use self::mutex::*; pub use self::semaphore::*; +#[allow(dead_code)] +#[cfg(target_arch = "x86_64")] +#[path = "arch/x86_64/atomic_lock.rs"] +pub mod atomic_lock; + +#[cfg(target_arch = "riscv32")] +#[path = "arch/riscv32/atomic_lock.rs"] +pub mod atomic_lock; + mod mutex; mod condvar; mod semaphore; diff --git a/kernel/src/sync/mutex.rs b/kernel/src/sync/mutex.rs index c8e62ea..d542e76 100644 --- a/kernel/src/sync/mutex.rs +++ b/kernel/src/sync/mutex.rs @@ -30,8 +30,8 @@ use arch::interrupt; use core::cell::UnsafeCell; use core::fmt; use core::ops::{Deref, DerefMut}; -use core::sync::atomic::{ATOMIC_BOOL_INIT, AtomicBool, Ordering}; use super::Condvar; +use super::atomic_lock::AtomicLock; pub type SpinLock = Mutex; pub type SpinNoIrqLock = Mutex; @@ -39,7 +39,7 @@ pub type ThreadLock = Mutex; pub struct Mutex { - lock: AtomicBool, + lock: AtomicLock, support: S, data: UnsafeCell, } @@ -78,7 +78,7 @@ impl Mutex /// ``` pub fn new(user_data: T) -> Mutex { Mutex { - lock: ATOMIC_BOOL_INIT, + lock: AtomicLock::new(), data: UnsafeCell::new(user_data), support: S::new(), } @@ -96,9 +96,9 @@ impl Mutex impl Mutex { fn obtain_lock(&self) { - while self.lock.compare_and_swap(false, true, Ordering::Acquire) != false { + while !self.lock.try_lock() { // Wait until the lock looks unlocked before retrying - while self.lock.load(Ordering::Relaxed) { + while self.lock.load() { self.support.cpu_relax(); } } @@ -137,14 +137,14 @@ impl Mutex /// /// If the lock isn't held, this is a no-op. pub unsafe fn force_unlock(&self) { - self.lock.store(false, Ordering::Release); + self.lock.store(); } /// Tries to lock the mutex. If it is already locked, it will return None. Otherwise it returns /// a guard within Some. pub fn try_lock(&self) -> Option> { let support_guard = S::before_lock(); - if self.lock.compare_and_swap(false, true, Ordering::Acquire) == false { + if self.lock.try_lock() { Some(MutexGuard { mutex: self, support_guard, @@ -186,7 +186,7 @@ impl<'a, T: ?Sized, S: MutexSupport> Drop for MutexGuard<'a, T, S> { /// The dropping of the MutexGuard will release the lock it was created from. fn drop(&mut self) { - self.mutex.lock.store(false, Ordering::Release); + self.mutex.lock.store(); self.mutex.support.after_unlock(); } }