Compare commits
3 Commits
d89f594ba4
...
6ffcf7d4a4
Author | SHA1 | Date |
---|---|---|
Astro | 6ffcf7d4a4 | |
Astro | 4f8a76e29b | |
Astro | ff41f4dd2d |
|
@ -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();
|
||||||
|
|
|
@ -122,5 +122,6 @@ pub fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main_core1() {
|
pub fn main_core1() {
|
||||||
|
println!("Hello from core1!");
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
17
src/ram.rs
17
src/ram.rs
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
49
src/stdio.rs
49
src/stdio.rs
|
@ -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);
|
|
||||||
UART = Some(uart);
|
|
||||||
UART.as_mut().unwrap()
|
|
||||||
}
|
}
|
||||||
Some(uart) => uart,
|
|
||||||
|
/// Initializes the UART on first use through `.deref_mut()` for debug
|
||||||
|
/// output through the `print!` and `println!` macros.
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {}
|
||||||
|
|
Loading…
Reference in New Issue