forked from M-Labs/zynq-rs
72 lines
1.9 KiB
Rust
72 lines
1.9 KiB
Rust
/// Mutex for SMP-safe locking
|
|
|
|
use crate::cortex_a9::asm;
|
|
|
|
pub struct Mutex {
|
|
state: u32,
|
|
}
|
|
|
|
const UNLOCKED_MUTEX: u32 = 0;
|
|
const LOCKED_MUTEX: u32 = 1;
|
|
|
|
impl Mutex {
|
|
pub const fn new_unlocked() -> Mutex {
|
|
Mutex { state: UNLOCKED_MUTEX }
|
|
}
|
|
|
|
pub const fn new_locked() -> Mutex {
|
|
Mutex { state: LOCKED_MUTEX }
|
|
}
|
|
|
|
// inlining causes problems with the labels
|
|
#[inline(never)]
|
|
pub fn acquire(&mut self) {
|
|
unsafe {
|
|
// code adapted from an example by ARM at
|
|
// http://infocenter.arm.com (Home > ARM Synchronization
|
|
// Primitives > Practical uses > Implementing a mutex)
|
|
asm!("
|
|
mutex_acquire_label1:
|
|
ldrex r2, [$0];
|
|
cmp r2, $1;
|
|
beq mutex_acquire_label2;
|
|
strexne r2, $1, [$0];
|
|
cmpne r2, 1;
|
|
beq mutex_acquire_label1;
|
|
dmb;
|
|
b mutex_acquire_label3;
|
|
mutex_acquire_label2:
|
|
wfe;
|
|
b mutex_acquire_label1;
|
|
mutex_acquire_label3: ;
|
|
"
|
|
::
|
|
// inputs
|
|
"r" (&mut self.state as *mut _ as u32), "r" (LOCKED_MUTEX)
|
|
:
|
|
// clobbers
|
|
"r2"
|
|
:
|
|
"volatile"
|
|
);
|
|
}
|
|
}
|
|
|
|
pub fn release(&mut self) {
|
|
unsafe {
|
|
asm!("
|
|
dmb;
|
|
str $1, [$0];
|
|
dsb;
|
|
sev;
|
|
"
|
|
::
|
|
// inputs
|
|
"r" (&mut self.state as *mut _ as u32), "r" (UNLOCKED_MUTEX)
|
|
::
|
|
"volatile"
|
|
);
|
|
}
|
|
}
|
|
}
|