Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 7996

Bare metal, Assembly language • Pi 4/400 MMU activation help?

$
0
0
Hello all;

I've been working with bare-metal Rust for the Pi 400 and have tried for the past week (Maybe two, time has melded together with this project) to enable the MMU and I have made next to no progress. I've dropped down to EL1 successfully, and I have a non-UART binary debugging method in place where, if it works, it hangs, and if it doesn't, it uses the watchdog to reboot. That said, whenever I try to generate the page tables, a synchronous exception is thrown. I'm not exactly sure what exact synchronous exception is thrown, but I've narrowed it down that much. The error is caused when I call a Rust function that generates page tables, specifically when it writes to the L1 table. The relevant code and comments are listed below.

Code:

// Constantsconst UNPRIV_EX_ON: u64 = 0 << 54;const UNPRIV_EX_OFF: u64 = 1 << 54;const PRIV_EX_ON: u64 = 0 << 53;const PRIV_EX_OFF: u64 = 1 << 53;const AF_INIT: u64 = 1 << 10;const SHAREABILITY_INNER: u64 = 0b11 << 8;const SHAREABILITY_OUTER: u64 = 0b10 << 8;const SHAREABILITY_NON: u64 = 0b00 << 8;const DATA_ACCESS_PERMS: u64 = 0b00 << 6;const NOT_SECURE: u64 = 1 << 5;const ATTR_IDX_RAM: u64 = 0b00 << 0;const ATTR_IDX_MMIO: u64 = 0b01 << 0;const IS_BLOCK: u64 = 0 << 1;const IS_TABLE: u64 = 1 << 1;const IS_VALID: u64 = 1 << 0;const TABLE_ADDR_MASK: u64 = 0x0000_FFFF_FFFF_F000;const L2_BLOCK_ADDR_MASK: u64 = 0x0000_FFFF_FFE0_0000;// Create an array of [u64; 512]s that I can use as my page tables.// The section is linked properly, and I can verify it from an objdump of my ELF.#[unsafe(link_section = ".page_tables")]static mut PAGE_TABLES: [[u64; 512]; 4096] = [ [0; 512]; 4096];static mut INDEX: usize = 0;// Generates the block descriptor given its PA and whether or not it's device memory.fn generate_block_descriptor(addr: u64, is_device: bool) -> u64 {    IS_BLOCK |    IS_VALID |    if is_device {UNPRIV_EX_OFF} else {UNPRIV_EX_ON} |    if is_device {PRIV_EX_OFF} else {PRIV_EX_ON} |    (addr & L2_BLOCK_ADDR_MASK) |    AF_INIT |    if is_device {SHAREABILITY_NON} else {SHAREABILITY_INNER} |    DATA_ACCESS_PERMS |    NOT_SECURE |    if is_device {ATTR_IDX_MMIO} else {ATTR_IDX_RAM}}// Generates the table descriptor from the PA of the tablefn generate_table_descriptor(addr: u64) -> u64 {    IS_TABLE |    IS_VALID |    (addr & TABLE_ADDR_MASK)}fn generate_page_tables(level: u8) -> u64 {    match level {        0 => {            let l0 = unsafe { &raw mut PAGE_TABLES[INDEX] };            unsafe {                INDEX = INDEX + 1;                (*l0)[0] = generate_page_tables(1);            }            l0 as u64        }        1 => {            let l1 = unsafe { &raw mut PAGE_TABLES[INDEX] };            for l1_idx in 0..4 {                let l2 = unsafe { &raw mut PAGE_TABLES[INDEX] };                for l2_idx in 0..512 {                    let pa = (l1_idx * 0x4000_0000) + (l2_idx * 0x0020_0000);                    let block_end = pa + 0x0020_0000 - 1;                    let is_device =                        block_end >= MMIO_START &&                        pa <= MMIO_END;                    let block = generate_block_descriptor(pa, is_device);                    unsafe { (*l2)[l2_idx as usize] = block; }      // This code executes just fine                }                let table = generate_table_descriptor(l2 as u64);   // This also executes just fine                unsafe { (*l1)[l1_idx as usize] = table; }          // CPU gets turned into a brick here                if l1_idx == 0 {unsafe{loop{asm!("wfe")}}};         // This code is never reached            }            generate_table_descriptor(l1 as u64)        }        _ => 0    }}
Any advice or assistance would be greatly appreciated. Thank you all in advance!

(P.S. If you need any further code, I would be more than happy to oblige.)

Statistics: Posted by OhOne — Tue Feb 17, 2026 11:23 pm



Viewing all articles
Browse latest Browse all 7996

Trending Articles