diff --git a/src/arch/aarch64/memory/bump_allocator.rs b/src/arch/aarch64/memory/bump_allocator.rs new file mode 100644 index 0000000..0bab412 --- /dev/null +++ b/src/arch/aarch64/memory/bump_allocator.rs @@ -0,0 +1,100 @@ +/* + * MIT License + * + * Copyright (c) 2019 Andre Richter + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +use crate::println; +use core::alloc::{Alloc, AllocErr, Layout}; +use core::mem; +use core::ptr::NonNull; +use core::slice; + +pub struct BumpAllocator { + next: usize, + pool_end: usize, + name: &'static str, +} + +unsafe impl Alloc for BumpAllocator { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + let start = crate::memory::aligned_addr_unchecked(self.next, layout.align()); + let end = start + layout.size(); + + if end <= self.pool_end { + self.next = end; + + println!( + "[i] {}:\n Allocated Addr {:#010X} Size {:#X}", + self.name, + start, + layout.size() + ); + + Ok(NonNull::new_unchecked(start as *mut u8)) + } else { + Err(AllocErr) + } + } + + // A bump allocator doesn't care + unsafe fn dealloc(&mut self, _ptr: NonNull, _layout: Layout) {} +} + +impl BumpAllocator { + pub const fn new(pool_start: usize, pool_end: usize, name: &'static str) -> Self { + Self { + next: pool_start, + pool_end, + name, + } + } + + /// Allocate a zeroed slice + pub fn alloc_slice_zeroed<'a, T>( + &mut self, + count_of_items: usize, + alignment: usize, + ) -> Result<&'a mut [T], ()> { + let l; + let size_in_byte = count_of_items * mem::size_of::(); + match Layout::from_size_align(size_in_byte, alignment) { + Ok(layout) => l = layout, + + Err(_) => { + println!("[e] Layout Error!"); + return Err(()); + } + } + + let ptr; + match unsafe { self.alloc_zeroed(l) } { + Ok(i) => ptr = i.as_ptr(), + + Err(_) => { + println!("[e] Layout Error!"); + return Err(()); + } + } + + Ok(unsafe { slice::from_raw_parts_mut(ptr as *mut T, count_of_items) }) + } +} diff --git a/src/arch/aarch64/memory/mod.rs b/src/arch/aarch64/memory/mod.rs index ac10ab7..43dd7e6 100644 --- a/src/arch/aarch64/memory/mod.rs +++ b/src/arch/aarch64/memory/mod.rs @@ -5,6 +5,9 @@ // pub use self::area_frame_allocator::AreaFrameAllocator; +mod bump_allocator; +pub use bump_allocator::BumpAllocator; + pub type PhysicalAddress = usize; pub type VirtualAddress = usize; diff --git a/src/arch/aarch64/mmu.rs b/src/arch/aarch64/mmu.rs index a68cb54..a2793bd 100644 --- a/src/arch/aarch64/mmu.rs +++ b/src/arch/aarch64/mmu.rs @@ -260,11 +260,7 @@ pub unsafe fn init() { barrier::isb(barrier::SY); // Enable the MMU and turn on data and instruction caching. - SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::NonCacheable + SCTLR_EL1::I::Cacheable); - - // @todo potentially disable both caches here for testing? - // Figured: data caching causes these mailbox misreads - // Need to allocate mailbox in non-cached memory perhaps for proper hw i/o + SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable); // Force MMU init to complete before next instruction /* diff --git a/src/main.rs b/src/main.rs index 732f2cf..1606a25 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ #![feature(core_intrinsics)] #![feature(range_contains)] #![feature(underscore_const_names)] +#![feature(allocator_api)] #![doc(html_root_url = "https://docs.metta.systems/")] #![allow(dead_code)] #![allow(unused_assignments)] @@ -54,6 +55,24 @@ use platform::{ /// The global console. Output of the print! and println! macros. static CONSOLE: sync::NullLock = sync::NullLock::new(devices::Console::new()); +/// The global allocator for DMA-able memory. That is, memory which is tagged +/// non-cacheable in the page tables. +static DMA_ALLOCATOR: sync::NullLock = + sync::NullLock::new(memory::BumpAllocator::new( + memory::map::virt::DMA_HEAP_START as usize, + memory::map::virt::DMA_HEAP_END as usize, + "Global DMA Allocator", + // Try the following arguments instead to see all mailbox operations + // fail. It will cause the allocator to use memory that are marked + // cacheable and therefore not DMA-safe. The answer from the VideoCore + // won't be received by the CPU because it reads an old cached value + // that resembles an error case instead. + + // 0x00600000 as usize, + // 0x007FFFFF as usize, + // "Global Non-DMA Allocator", + )); + fn init_jlink_rtt() { CONSOLE.lock(|c| { c.replace_with(Output::new().into()); @@ -77,7 +96,7 @@ fn init_uart_serial() { let uart = platform::PL011Uart::new_default(); - let mut mbox = platform::mailbox::Mailbox::new(); + let mut mbox = platform::mailbox::Mailbox::default(); // uart.init() will reconfigure the GPIO, which causes a race against // the MiniUart that is still putting out characters on the physical diff --git a/src/platform/mailbox.rs b/src/platform/mailbox.rs index ab78add..094a250 100644 --- a/src/platform/mailbox.rs +++ b/src/platform/mailbox.rs @@ -11,12 +11,14 @@ use register::mmio::*; // The address for the buffer needs to be 16-byte aligned // so that the VideoCore can handle it properly. // The reason is that lowest 4 bits of the address will contain the channel number. -#[repr(C)] -#[repr(align(16))] -pub struct Mailbox { - pub buffer: [u32; 36], +pub struct Mailbox<'a> { + pub buffer: &'a mut [u32], + base_addr: u32, } +const MAILBOX_ALIGNMENT: usize = 16; +const MAILBOX_ITEMS_COUNT: usize = 36; + // Identity mapped first 1Gb by u-boot const MAILBOX_BASE: u32 = BcmHost::get_peripheral_address() + 0xb880; // Lowest 4-bits are channel ID. @@ -292,15 +294,15 @@ fn read(regs: &RegisterBlock, expected: u32, channel: u32) -> Result<()> { /// ``` /// unsafe { (*Mbox::ptr()).STATUS.read() } /// ``` -impl Deref for Mailbox { +impl<'a> Deref for Mailbox<'a> { type Target = RegisterBlock; fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } + unsafe { &*self.ptr() } } } -impl core::fmt::Display for Mailbox { +impl<'a> core::fmt::Display for Mailbox<'a> { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { let count = self.buffer[0] / 4; assert_eq!(self.buffer[0], count * 4); @@ -312,20 +314,47 @@ impl core::fmt::Display for Mailbox { } } -impl Default for Mailbox { +impl<'a> Default for Mailbox<'a> { fn default() -> Self { - Self::new() + Self::new_default().expect("Couldn't allocate a mailbox") } } -impl Mailbox { - pub fn new() -> Mailbox { - Mailbox { buffer: [0; 36] } +impl<'a> Mailbox<'a> { + pub fn new_default() -> ::core::result::Result, ()> { + let ret = crate::DMA_ALLOCATOR + .lock(|d| d.alloc_slice_zeroed(MAILBOX_ITEMS_COUNT, MAILBOX_ALIGNMENT)); + + if ret.is_err() { + return Err(()); + } + + Ok(Mailbox { + base_addr: MAILBOX_BASE, + buffer: ret.unwrap(), + }) + } + + pub fn new(base_addr: usize) -> ::core::result::Result, ()> { + let ret = crate::DMA_ALLOCATOR + .lock(|d| d.alloc_slice_zeroed(MAILBOX_ITEMS_COUNT, MAILBOX_ALIGNMENT)); + + if ret.is_err() { + return Err(()); + } + + use core::convert::TryFrom; + let base_addr = u32::try_from(base_addr).unwrap(); + + Ok(Mailbox { + base_addr, + buffer: ret.unwrap(), + }) } /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - MAILBOX_BASE as *const _ + fn ptr(&self) -> *const RegisterBlock { + self.base_addr as *const _ } pub fn write(&self, channel: u32) -> Result<()> { diff --git a/src/platform/vc.rs b/src/platform/vc.rs index 762ed15..f7f3142 100644 --- a/src/platform/vc.rs +++ b/src/platform/vc.rs @@ -15,7 +15,7 @@ impl VC { // https://www.raspberrypi.org/forums/viewtopic.php?f=72&t=185116 pub fn init_fb(size: Size2d, depth: u32) -> Option { // Use property channel - let mut mbox = Mailbox::new(); + let mut mbox = Mailbox::default(); /* * * All tags in the request are processed in one operation.