Compare commits

...

3 Commits

Author SHA1 Message Date
Astro 6ffcf7d4a4 ram: lock for concurrent use
this may be reverted if ram allocation shall be more separate.
2019-11-20 17:25:54 +01:00
Astro 4f8a76e29b stdio: lock for use by core1 2019-11-20 17:00:57 +01:00
Astro ff41f4dd2d cortex_a9::mutex: restore and fix powersaving behaviour, doc 2019-11-20 16:30:56 +01:00
4 changed files with 72 additions and 23 deletions

View File

@ -3,9 +3,25 @@ use core::sync::atomic::{AtomicU32, Ordering};
use core::cell::UnsafeCell; use core::cell::UnsafeCell;
use super::asm::*; use super::asm::*;
/// [Power-saving features](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html)
#[inline]
fn wait_for_update() {
wfe();
}
/// [Power-saving features](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html)
#[inline]
fn signal_update() {
dsb();
sev();
}
const LOCKED: u32 = 1; const LOCKED: u32 = 1;
const UNLOCKED: u32 = 0; const UNLOCKED: u32 = 0;
/// Mutex implementation for Cortex-A9
///
/// [ARM Synchronization Primitives Development Article: Implementing a mutex](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html)
pub struct Mutex<T> { pub struct Mutex<T> {
locked: AtomicU32, locked: AtomicU32,
inner: UnsafeCell<T>, inner: UnsafeCell<T>,
@ -15,6 +31,7 @@ unsafe impl<T: Send> Sync for Mutex<T> {}
unsafe impl<T: Send> Send for Mutex<T> {} unsafe impl<T: Send> Send for Mutex<T> {}
impl<T> Mutex<T> { impl<T> Mutex<T> {
/// Constructor, const-fn
pub const fn new(inner: T) -> Self { pub const fn new(inner: T) -> Self {
Mutex{ Mutex{
locked: AtomicU32::new(UNLOCKED), locked: AtomicU32::new(UNLOCKED),
@ -22,8 +39,11 @@ impl<T> Mutex<T> {
} }
} }
/// Lock the Mutex, blocks when already locked
pub fn lock(&self) -> MutexGuard<T> { pub fn lock(&self) -> MutexGuard<T> {
while self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::Acquire) != UNLOCKED {} while self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::Acquire) != UNLOCKED {
wait_for_update();
}
dmb(); dmb();
MutexGuard { mutex: self } MutexGuard { mutex: self }
} }
@ -31,10 +51,13 @@ impl<T> Mutex<T> {
fn unlock(&self) { fn unlock(&self) {
dmb(); dmb();
self.locked.store(UNLOCKED, Ordering::Release); self.locked.store(UNLOCKED, Ordering::Release);
dsb();
signal_update();
} }
} }
/// Returned by `Mutex.lock()`, allows access to data via
/// `Deref`/`DerefMutx`
pub struct MutexGuard<'a, T> { pub struct MutexGuard<'a, T> {
mutex: &'a Mutex<T>, mutex: &'a Mutex<T>,
} }
@ -52,6 +75,7 @@ impl<'a, T> DerefMut for MutexGuard<'a, T> {
} }
} }
/// Automatically `Mutex.unlock()` when this reference is dropped
impl<'a, T> Drop for MutexGuard<'a, T> { impl<'a, T> Drop for MutexGuard<'a, T> {
fn drop(&mut self) { fn drop(&mut self) {
self.mutex.unlock(); self.mutex.unlock();

View File

@ -122,5 +122,6 @@ pub fn main() {
} }
pub fn main_core1() { pub fn main_core1() {
println!("Hello from core1!");
loop {} loop {}
} }

View File

@ -1,36 +1,35 @@
use core::cell::RefCell;
use core::alloc::GlobalAlloc; use core::alloc::GlobalAlloc;
use core::ptr::NonNull; use core::ptr::NonNull;
use alloc::alloc::Layout; use alloc::alloc::Layout;
use linked_list_allocator::Heap; use linked_list_allocator::Heap;
use crate::cortex_a9::mutex::Mutex;
use crate::zynq::ddr::DdrRam; use crate::zynq::ddr::DdrRam;
#[global_allocator] #[global_allocator]
static ALLOCATOR: HeapAlloc = HeapAlloc(RefCell::new(Heap::empty())); static ALLOCATOR: CortexA9Alloc = CortexA9Alloc(Mutex::new(Heap::empty()));
/// LockedHeap doesn't locking properly /// LockedHeap doesn't locking properly
struct HeapAlloc(RefCell<Heap>); struct CortexA9Alloc(Mutex<Heap>);
/// FIXME: unsound; lock properly unsafe impl Sync for CortexA9Alloc {}
unsafe impl Sync for HeapAlloc {}
unsafe impl GlobalAlloc for HeapAlloc { unsafe impl GlobalAlloc for CortexA9Alloc {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
self.0.borrow_mut() self.0.lock()
.allocate_first_fit(layout) .allocate_first_fit(layout)
.ok() .ok()
.map_or(0 as *mut u8, |allocation| allocation.as_ptr()) .map_or(0 as *mut u8, |allocation| allocation.as_ptr())
} }
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
self.0.borrow_mut() self.0.lock()
.deallocate(NonNull::new_unchecked(ptr), layout) .deallocate(NonNull::new_unchecked(ptr), layout)
} }
} }
pub fn init_alloc(ddr: &mut DdrRam) { pub fn init_alloc(ddr: &mut DdrRam) {
unsafe { unsafe {
ALLOCATOR.0.borrow_mut() ALLOCATOR.0.lock()
.init(ddr.ptr::<u8>() as usize, ddr.size()); .init(ddr.ptr::<u8>() as usize, ddr.size());
} }
} }

View File

@ -1,19 +1,44 @@
use core::ops::{Deref, DerefMut};
use crate::cortex_a9::mutex::{Mutex, MutexGuard};
use crate::zynq::uart::Uart; use crate::zynq::uart::Uart;
const UART_RATE: u32 = 115_200; const UART_RATE: u32 = 115_200;
static mut UART: Option<Uart> = None; static mut UART: Mutex<LazyUart> = Mutex::new(LazyUart::Uninitialized);
// TODO: locking for SMP
#[doc(hidden)] #[doc(hidden)]
pub fn get_uart() -> &'static mut Uart { pub fn get_uart<'a>() -> MutexGuard<'a, LazyUart> {
unsafe { unsafe { UART.lock() }
match &mut UART { }
None => {
let uart = Uart::serial(UART_RATE); /// Initializes the UART on first use through `.deref_mut()` for debug
UART = Some(uart); /// output through the `print!` and `println!` macros.
UART.as_mut().unwrap() pub enum LazyUart {
Uninitialized,
Initialized(Uart),
}
impl Deref for LazyUart {
type Target = Uart;
fn deref(&self) -> &Uart {
match self {
LazyUart::Uninitialized =>
panic!("stdio not initialized!"),
LazyUart::Initialized(uart) =>
uart,
} }
Some(uart) => uart, }
}
impl DerefMut for LazyUart {
fn deref_mut(&mut self) -> &mut Uart {
match self {
LazyUart::Uninitialized => {
let uart = Uart::serial(UART_RATE);
*self = LazyUart::Initialized(uart);
self
}
LazyUart::Initialized(uart) =>
uart,
} }
} }
} }
@ -22,7 +47,7 @@ pub fn get_uart() -> &'static mut Uart {
macro_rules! print { macro_rules! print {
($($arg:tt)*) => ({ ($($arg:tt)*) => ({
use core::fmt::Write; use core::fmt::Write;
let uart = crate::stdio::get_uart(); let mut uart = crate::stdio::get_uart();
let _ = write!(uart, $($arg)*); let _ = write!(uart, $($arg)*);
}) })
} }
@ -31,7 +56,7 @@ macro_rules! print {
macro_rules! println { macro_rules! println {
($($arg:tt)*) => ({ ($($arg:tt)*) => ({
use core::fmt::Write; use core::fmt::Write;
let uart = crate::stdio::get_uart(); let mut uart = crate::stdio::get_uart();
let _ = write!(uart, $($arg)*); let _ = write!(uart, $($arg)*);
let _ = write!(uart, "\r\n"); let _ = write!(uart, "\r\n");
while !uart.tx_fifo_empty() {} while !uart.tx_fifo_empty() {}