Allocate Mailboxes from special non-cacheable memory

This commit is contained in:
Berkus Decker 2019-03-10 15:17:09 +02:00
parent 006abc39dd
commit 7ea82d90d7
6 changed files with 168 additions and 21 deletions

View File

@ -0,0 +1,100 @@
/*
* MIT License
*
* Copyright (c) 2019 Andre Richter <andre.o.richter@gmail.com>
*
* 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<NonNull<u8>, 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<u8>, _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::<T>();
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) })
}
}

View File

@ -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;

View File

@ -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
/*

View File

@ -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<devices::Console> = 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<memory::BumpAllocator> =
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

View File

@ -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<Mailbox<'a>, ()> {
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<Mailbox<'a>, ()> {
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<()> {

View File

@ -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<Display> {
// Use property channel
let mut mbox = Mailbox::new();
let mut mbox = Mailbox::default();
/*
* * All tags in the request are processed in one operation.