feat: Switch mailboxes to correct DMA-backed storage by default

Allocate DmaBackedMailboxStorage out of DMA_ALLOCATOR.
Replace DMA bump_allocator with buddy_alloc.
This commit is contained in:
Berkus Decker 2022-05-05 22:01:49 +03:00
parent 07df330b62
commit ddf6d09136
4 changed files with 100 additions and 23 deletions

7
Cargo.lock generated
View File

@ -67,6 +67,11 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "buddy-alloc"
version = "0.5.0"
source = "git+https://github.com/metta-systems/buddy-alloc?branch=feature/allocator-api#70c17c858100282252754981f13e9442b86e07e0"
[[package]]
name = "bytes"
version = "1.1.0"
@ -385,8 +390,10 @@ version = "0.0.1"
dependencies = [
"bit_field",
"bitflags",
"buddy-alloc",
"cfg-if",
"cortex-a",
"once_cell",
"qemu-exit",
"r0",
"snafu",

View File

@ -38,3 +38,5 @@ bit_field = "0.10"
bitflags = "1.3"
cfg-if = "1.0"
snafu = { version = "0.7", default-features = false }
buddy-alloc = { git = "https://github.com/metta-systems/buddy-alloc", version = "0.5.0", branch = "feature/allocator-api" }
once_cell = { version = "1.10.0", default-features = false, features = ["unstable"] }

View File

@ -5,6 +5,7 @@
#![feature(format_args_nl)]
#![feature(core_intrinsics)]
#![feature(stmt_expr_attributes)]
#![feature(slice_ptr_get)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(custom_test_frameworks)]
#![test_runner(crate::tests::test_runner)]
@ -18,6 +19,12 @@
#[cfg(not(target_arch = "aarch64"))]
use architecture_not_supported_sorry;
use {
buddy_alloc::{BuddyAlloc, BuddyAllocParam},
once_cell::unsync::Lazy,
platform::memory::map::virt::{DMA_HEAP_END, DMA_HEAP_START},
};
/// Architecture-specific code.
#[macro_use]
pub mod arch;
@ -41,19 +48,20 @@ pub static CONSOLE: sync::NullLock<devices::Console> = sync::NullLock::new(devic
/// The global allocator for DMA-able memory. That is, memory which is tagged
/// non-cacheable in the page tables.
#[allow(dead_code)]
static DMA_ALLOCATOR: sync::NullLock<mm::BumpAllocator> =
sync::NullLock::new(mm::BumpAllocator::new(
// @todo Init this after we loaded boot memory map
platform::memory::map::virt::DMA_HEAP_START as usize,
platform::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.
static DMA_ALLOCATOR: sync::NullLock<Lazy<BuddyAlloc>> =
sync::NullLock::new(Lazy::new(|| unsafe {
BuddyAlloc::new(BuddyAllocParam::new(
// @todo Init this after we loaded boot memory map
DMA_HEAP_START as *const u8,
DMA_HEAP_END - DMA_HEAP_START,
64,
))
}));
// 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",
));
// 0x00600000 as usize,
// 0x007FFFFF as usize,

View File

@ -13,8 +13,11 @@
use {
super::BcmHost,
crate::{platform::MMIODerefWrapper, println},
crate::{platform::MMIODerefWrapper, println, DMA_ALLOCATOR},
core::{
alloc::{AllocError, Allocator, Layout},
mem,
ptr::NonNull,
result::Result as CoreResult,
sync::atomic::{compiler_fence, Ordering},
},
@ -31,14 +34,14 @@ use {
/// 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.
pub struct Mailbox<const N_SLOTS: usize, Storage = LocalMailboxStorage<N_SLOTS>> {
pub struct Mailbox<const N_SLOTS: usize, Storage = DmaBackedMailboxStorage<N_SLOTS>> {
registers: Registers,
pub buffer: Storage,
}
/// Mailbox that is ready to be called.
/// This prevents invalid use of the mailbox until it is fully prepared.
pub struct PreparedMailbox<const N_SLOTS: usize, Storage = LocalMailboxStorage<N_SLOTS>>(
pub struct PreparedMailbox<const N_SLOTS: usize, Storage = DmaBackedMailboxStorage<N_SLOTS>>(
Mailbox<N_SLOTS, Storage>,
);
@ -96,6 +99,8 @@ pub enum MailboxError {
Unknown,
#[snafu(display("Timeout"))]
Timeout,
#[snafu(display("AllocError"))]
Alloc,
}
pub type Result<T> = CoreResult<T, MailboxError>;
@ -111,7 +116,9 @@ pub trait MailboxOps {
}
pub trait MailboxStorage {
fn new() -> Self;
fn new() -> Result<Self>
where
Self: Sized;
}
pub trait MailboxStorageRef {
@ -127,11 +134,45 @@ pub struct LocalMailboxStorage<const N_SLOTS: usize> {
pub storage: [u32; N_SLOTS],
}
pub struct DmaBackedMailboxStorage<const N_SLOTS: usize> {
pub storage: *mut u32,
}
impl<const N_SLOTS: usize> MailboxStorage for LocalMailboxStorage<N_SLOTS> {
fn new() -> Self {
Self {
fn new() -> Result<Self> {
Ok(Self {
storage: [0u32; N_SLOTS],
}
})
}
}
impl<const N_SLOTS: usize> MailboxStorage for DmaBackedMailboxStorage<N_SLOTS> {
fn new() -> Result<Self> {
Ok(Self {
storage: DMA_ALLOCATOR
.lock(|a| {
a.allocate(
Layout::from_size_align(N_SLOTS * mem::size_of::<u32>(), 16)
.map_err(|_| AllocError)?,
)
})
.map_err(|_| MailboxError::Alloc)?
.as_mut_ptr() as *mut u32,
})
}
}
impl<const N_SLOTS: usize> Drop for DmaBackedMailboxStorage<N_SLOTS> {
fn drop(&mut self) {
DMA_ALLOCATOR
.lock::<_, Result<()>>(|a| unsafe {
Ok(a.deallocate(
NonNull::new_unchecked(self.storage as *mut u8),
Layout::from_size_align(N_SLOTS * mem::size_of::<u32>(), 16)
.map_err(|_| MailboxError::Alloc)?,
))
})
.unwrap_or(())
}
}
@ -154,6 +195,25 @@ impl<const N_SLOTS: usize> MailboxStorageRef for LocalMailboxStorage<N_SLOTS> {
}
}
impl<const N_SLOTS: usize> MailboxStorageRef for DmaBackedMailboxStorage<N_SLOTS> {
fn as_ref(&self) -> &[u32] {
unsafe { core::slice::from_raw_parts(self.storage.cast(), N_SLOTS) }
}
fn as_mut(&mut self) -> &mut [u32] {
unsafe { core::slice::from_raw_parts_mut(self.storage.cast(), N_SLOTS) }
}
fn as_ptr(&self) -> *const u32 {
self.storage.cast()
}
// @todo Probably need a ResultMailbox for accessing data after call()?
fn value_at(&self, index: usize) -> u32 {
self.as_ref()[index]
}
}
/*
* Source https://elinux.org/RPi_Framebuffer
* Source for channels 8 and 9: https://github.com/raspberrypi/firmware/wiki/Mailboxes
@ -315,7 +375,7 @@ impl<const N_SLOTS: usize, Storage: MailboxStorage + MailboxStorageRef> Mailbox<
pub unsafe fn new(base_addr: usize) -> Result<Mailbox<N_SLOTS, Storage>> {
Ok(Mailbox {
registers: Registers::new(base_addr),
buffer: Storage::new(),
buffer: Storage::new()?,
})
}