diff --git a/loader/aarch64.ld b/loader/aarch64.ld index 6a583113d..977ccc574 100644 --- a/loader/aarch64.ld +++ b/loader/aarch64.ld @@ -12,6 +12,8 @@ SECTIONS { . = LINK_ADDRESS; + _loader_start = .; + .text : { _text = .; @@ -36,4 +38,6 @@ SECTIONS . = ALIGN(4); _bss_end = .; } :all + + _loader_end = .; } diff --git a/loader/src/aarch64/mmu.c b/loader/src/aarch64/mmu.c index 37a9030c4..8ef6427ce 100644 --- a/loader/src/aarch64/mmu.c +++ b/loader/src/aarch64/mmu.c @@ -23,6 +23,7 @@ uint64_t boot_lvl2_upper[1 << 9] ALIGN(1 << 12); /* Paging structures for identity mapping */ uint64_t boot_lvl0_lower[1 << 9] ALIGN(1 << 12); uint64_t boot_lvl1_lower[1 << 9] ALIGN(1 << 12); +uint64_t boot_lvl2_lower[1 << 9] ALIGN(1 << 12); int arch_mmu_enable(int logical_cpu) { diff --git a/loader/src/uart.c b/loader/src/uart.c index 54b182100..ad04f23ee 100644 --- a/loader/src/uart.c +++ b/loader/src/uart.c @@ -205,6 +205,10 @@ void putc(uint8_t ch) #error Board not defined #endif +#ifdef UART_BASE +uint32_t *uart_addr = (uint32_t *)UART_BASE; +#endif + void puts(const char *s) { while (*s) { diff --git a/tool/microkit/src/loader.rs b/tool/microkit/src/loader.rs index 37f63f65d..237bbd040 100644 --- a/tool/microkit/src/loader.rs +++ b/tool/microkit/src/loader.rs @@ -485,20 +485,64 @@ impl<'a> Loader<'a> { let (boot_lvl0_upper_addr, boot_lvl0_upper_size) = elf .find_symbol("boot_lvl0_upper") .expect("Could not find 'boot_lvl0_upper' symbol"); + let (boot_lvl2_lower_addr, boot_lvl2_lower_size) = elf + .find_symbol("boot_lvl2_lower") + .expect("Could not find 'boot_lvl2_lower' symbol"); + let (start_addr, _) = elf + .find_symbol("_loader_start") + .expect("Could not find 'loader_start' symbol"); + let (end_addr, _) = elf + .find_symbol("_loader_end") + .expect("Could not find 'loader_end' symbol"); + + if Aarch64::lvl1_index(start_addr) != Aarch64::lvl1_index(end_addr) { + panic!("We only map 1GiB, but elfloader paddr range covers multiple GiB"); + } let mut boot_lvl0_lower: [u8; PAGE_TABLE_SIZE] = [0; PAGE_TABLE_SIZE]; boot_lvl0_lower[..8].copy_from_slice(&(boot_lvl1_lower_addr | 3).to_le_bytes()); let mut boot_lvl1_lower: [u8; PAGE_TABLE_SIZE] = [0; PAGE_TABLE_SIZE]; - for i in 0..512 { + + // map optional UART MMIO in l1 1GB page, only available if CONFIG_PRINTING + if let Ok((uart_addr, _)) = elf.find_symbol("uart_addr") { + let data = elf + .get_data(uart_addr, 8) + .expect("uart_addr not initialized"); + let uart_base = u64::from_le_bytes(data[0..8].try_into().unwrap()); + + let lvl1_idx = Aarch64::lvl1_index(uart_base); #[allow(clippy::identity_op)] // keep the (0 << 2) for clarity - let pt_entry: u64 = ((i as u64) << AARCH64_1GB_BLOCK_BITS) | + let pt_entry: u64 = ((lvl1_idx as u64) << AARCH64_1GB_BLOCK_BITS) | (1 << 10) | // access flag (0 << 2) | // strongly ordered memory - (1); // 1G block + (1 << 0); // 1G block + let start = 8 * lvl1_idx; + let end = 8 * (lvl1_idx + 1); + boot_lvl1_lower[start..end].copy_from_slice(&pt_entry.to_le_bytes()); + } + + let mut boot_lvl2_lower: [u8; PAGE_TABLE_SIZE] = [0; PAGE_TABLE_SIZE]; + + // 1GB lvl1 Table entry + let pt_entry = (boot_lvl2_lower_addr | 3).to_le_bytes(); + let lvl1_idx = Aarch64::lvl1_index(start_addr); + let start = 8 * lvl1_idx; + let end = 8 * (lvl1_idx + 1); + boot_lvl1_lower[start..end].copy_from_slice(&pt_entry); + + // map the loader 1:1 access into 2MB lvl2 Block entries for a 4KB granule + let lvl2_idx = Aarch64::lvl2_index(start_addr); + for i in lvl2_idx ..= Aarch64::lvl2_index(end_addr) { + let entry_idx = (i - Aarch64::lvl2_index(start_addr)) << AARCH64_2MB_BLOCK_BITS; + let pt_entry: u64 = (entry_idx as u64 + start_addr) | + (1 << 10) | // Access flag + (3 << 8) | // Sharable + (3 << 2) | // MT_NORMAL memory + (1 << 0); // 2M block let start = 8 * i; let end = 8 * (i + 1); - boot_lvl1_lower[start..end].copy_from_slice(&pt_entry.to_le_bytes()); + boot_lvl2_lower[start..end].copy_from_slice(&pt_entry.to_le_bytes()); } let boot_lvl0_upper: [u8; PAGE_TABLE_SIZE] = [0; PAGE_TABLE_SIZE]; @@ -536,6 +580,7 @@ impl<'a> Loader<'a> { (boot_lvl0_upper_addr, boot_lvl0_upper_size, boot_lvl0_upper), (boot_lvl1_upper_addr, boot_lvl1_upper_size, boot_lvl1_upper), (boot_lvl2_upper_addr, boot_lvl2_upper_size, boot_lvl2_upper), + (boot_lvl2_lower_addr, boot_lvl2_lower_size, boot_lvl2_lower), ] } }