Files
novaOS/src/pi3/mailbox.rs
Alexander Neuhäuser 34a66ff87a feat: implement first SVC mailbox instruction (#6)
* refactor: organize code

* feat: move EL0 stack to virtual space

* wip

* feat: Enable EL0 basic mailbox access via SVCs

* refactor: move irq interrupts
2026-03-22 12:25:43 +01:00

92 lines
2.8 KiB
Rust

use core::slice;
use crate::{
aarch64::mmu::GRANULARITY, configuration::memory_mapping::MAILBOX_PHYSICAL_ADDRESS,
configuration::memory_mapping::MAILBOX_VIRTUAL_ADDRESS, read_address, write_address,
};
use nova_error::NovaError;
const MBOX_BASE: u32 = 0x3F00_0000 + 0xB880;
// MB0
const MBOX_READ: u32 = MBOX_BASE;
const MBOX_STATUS: u32 = MBOX_BASE + 0x18;
// MB1
const MBOX_WRITE: u32 = MBOX_BASE + 0x20;
// Status
const MAIL_FULL: u32 = 0x80000000;
const MAIL_EMPTY: u32 = 0x40000000;
const HEADER_LENGTH: usize = 4 + 4 + 4 + 4 + 4; // Total Size + Request + Tag + MaxBufferLength + RequestLength
const FOOTER_LENGTH: usize = 4;
macro_rules! max {
($a:expr, $b:expr) => {{
const M: usize = if $a > $b { $a as usize } else { $b as usize };
M
}};
}
#[macro_export]
macro_rules! mailbox_command {
($name:ident, $tag:expr, $request_len:expr,$response_len:expr) => {
/// More information at: <https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface>
pub fn $name(
request_data: [u32; $request_len / 4],
) -> Result<[u32; $response_len / 4], NovaError> {
let mailbox = unsafe {
slice::from_raw_parts_mut(MAILBOX_VIRTUAL_ADDRESS as *mut u32, GRANULARITY / 4)
};
mailbox[0] = (HEADER_LENGTH + max!($request_len, $response_len) + FOOTER_LENGTH) as u32; // Total length in Bytes
mailbox[1] = 0; // Request
mailbox[2] = $tag; // Command Tag
mailbox[3] = max!($request_len, $response_len) as u32; // Max value buffer size
mailbox[4] = $request_len;
mailbox[5..(5 + ($request_len / 4))].copy_from_slice(&request_data);
mailbox[(5 + ($request_len / 4))..].fill(0);
//let addr = core::ptr::addr_of!(mailbox[0]) as u32;
write_mailbox(8, unsafe { MAILBOX_PHYSICAL_ADDRESS.unwrap() } as u32);
let _ = read_mailbox(8);
if mailbox[1] == 0 {
return Err(NovaError::Mailbox);
}
let mut out = [0u32; $response_len / 4];
out.copy_from_slice(&mailbox[5..(5 + $response_len / 4)]);
Ok(out)
}
};
}
mailbox_command!(read_soc_temp, 0x0003_0006, 4, 8);
// Framebuffer
mailbox_command!(get_display_resolution, 0x0004_0003, 0, 8);
pub fn read_mailbox(channel: u32) -> u32 {
// Wait until mailbox is not empty
loop {
while unsafe { read_address(MBOX_STATUS) } & MAIL_EMPTY != 0 {}
let mut data = unsafe { read_address(MBOX_READ) };
let read_channel = data & 0xF;
data >>= 4;
if channel == read_channel {
return data;
}
}
}
pub fn write_mailbox(channel: u32, data: u32) {
while unsafe { read_address(MBOX_STATUS) } & MAIL_FULL != 0 {}
unsafe { write_address(MBOX_WRITE, (data & !0xF) | (channel & 0xF)) };
}