Allocate Mailboxes from special non-cacheable memory
This commit is contained in:
parent
006abc39dd
commit
7ea82d90d7
|
@ -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) })
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
/*
|
||||
|
|
21
src/main.rs
21
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<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
|
||||
|
|
|
@ -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<()> {
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue