Skip to content

Commit 12dd82c

Browse files
committed
aarch64: Restrict address mappings in loader.rs
Limit the 1:1 address mapping in the loader to cover only the necessary blocks using level-2 translation tables and with 2MB blocks. Don't map device memory at all, therefore, printf must not be used in the elfloader after the MMU is enabled. This prevents speculative accesses to device or secure memory which otherwise would cause faults or unwanted side-effects. Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
1 parent c83d507 commit 12dd82c

4 files changed

Lines changed: 55 additions & 4 deletions

File tree

loader/aarch64.ld

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ SECTIONS
1212
{
1313
. = LINK_ADDRESS;
1414

15+
_loader_start = .;
16+
1517
.text :
1618
{
1719
_text = .;
@@ -36,4 +38,6 @@ SECTIONS
3638
. = ALIGN(4);
3739
_bss_end = .;
3840
} :all
41+
42+
_loader_end = .;
3943
}

loader/src/aarch64/mmu.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ uint64_t boot_lvl2_upper[1 << 9] ALIGN(1 << 12);
2323
/* Paging structures for identity mapping */
2424
uint64_t boot_lvl0_lower[1 << 9] ALIGN(1 << 12);
2525
uint64_t boot_lvl1_lower[1 << 9] ALIGN(1 << 12);
26+
uint64_t boot_lvl2_lower[1 << 9] ALIGN(1 << 12);
2627

2728
int arch_mmu_enable(int logical_cpu)
2829
{

loader/src/uart.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ void putc(uint8_t ch)
205205
#error Board not defined
206206
#endif
207207

208+
uint32_t *uart_addr = (uint32_t *)UART_BASE;
209+
208210
void puts(const char *s)
209211
{
210212
while (*s) {

tool/microkit/src/loader.rs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -485,20 +485,63 @@ impl<'a> Loader<'a> {
485485
let (boot_lvl0_upper_addr, boot_lvl0_upper_size) = elf
486486
.find_symbol("boot_lvl0_upper")
487487
.expect("Could not find 'boot_lvl0_upper' symbol");
488+
let (boot_lvl2_lower_addr, boot_lvl2_lower_size) = elf
489+
.find_symbol("boot_lvl2_lower")
490+
.expect("Could not find 'boot_lvl2_lower' symbol");
491+
let (start_addr, _) = elf
492+
.find_symbol("_loader_start")
493+
.expect("Could not find 'loader_start' symbol");
494+
let (end_addr, _) = elf
495+
.find_symbol("_loader_end")
496+
.expect("Could not find 'loader_end' symbol");
497+
498+
if Aarch64::lvl1_index(start_addr) != Aarch64::lvl1_index(end_addr) {
499+
panic!("We only map 1GiB, but elfloader paddr range covers multiple GiB");
500+
}
488501

489502
let mut boot_lvl0_lower: [u8; PAGE_TABLE_SIZE] = [0; PAGE_TABLE_SIZE];
490503
boot_lvl0_lower[..8].copy_from_slice(&(boot_lvl1_lower_addr | 3).to_le_bytes());
491504

492505
let mut boot_lvl1_lower: [u8; PAGE_TABLE_SIZE] = [0; PAGE_TABLE_SIZE];
493-
for i in 0..512 {
506+
507+
// map optional UART MMIO in l1 1GB page, only available if CONFIG_PRINTING
508+
if let Ok((uart_addr, _)) = elf.find_symbol("uart_addr") {
509+
let data = elf
510+
.get_data(uart_addr, 8)
511+
.expect("uart_addr not initialized");
512+
let uart_base = u64::from_le_bytes(data[0..8].try_into().unwrap());
513+
514+
let lvl1_idx = Aarch64::lvl1_index(uart_base);
494515
#[allow(clippy::identity_op)] // keep the (0 << 2) for clarity
495-
let pt_entry: u64 = ((i as u64) << AARCH64_1GB_BLOCK_BITS) |
516+
let pt_entry: u64 = ((lvl1_idx as u64) << AARCH64_1GB_BLOCK_BITS) |
496517
(1 << 10) | // access flag
497518
(0 << 2) | // strongly ordered memory
498-
(1); // 1G block
519+
(1 << 0); // 1G block
520+
let start = 8 * lvl1_idx;
521+
let end = 8 * (lvl1_idx + 1);
522+
boot_lvl1_lower[start..end].copy_from_slice(&pt_entry.to_le_bytes());
523+
}
524+
525+
let mut boot_lvl2_lower: [u8; PAGE_TABLE_SIZE] = [0; PAGE_TABLE_SIZE];
526+
527+
let pt_entry = (boot_lvl2_lower_addr | 3).to_le_bytes();
528+
let lvl1_idx = Aarch64::lvl1_index(start_addr);
529+
let start = 8 * lvl1_idx;
530+
let end = 8 * (lvl1_idx + 1);
531+
boot_lvl1_lower[start..end].copy_from_slice(&pt_entry);
532+
533+
// map the loader 1:1 access into 2MB blocks
534+
let lvl2_idx = Aarch64::lvl2_index(start_addr);
535+
for i in lvl2_idx ..= Aarch64::lvl2_index(end_addr) {
536+
let entry_idx = (i - Aarch64::lvl2_index(start_addr)) << AARCH64_2MB_BLOCK_BITS;
537+
let pt_entry: u64 = (entry_idx as u64 + start_addr) |
538+
(1 << 10) | // Access flag
539+
(3 << 8) | // Sharable
540+
(3 << 2) | // MT_NORMAL memory
541+
(1 << 0); // 2M block
499542
let start = 8 * i;
500543
let end = 8 * (i + 1);
501-
boot_lvl1_lower[start..end].copy_from_slice(&pt_entry.to_le_bytes());
544+
boot_lvl2_lower[start..end].copy_from_slice(&pt_entry.to_le_bytes());
502545
}
503546

504547
let boot_lvl0_upper: [u8; PAGE_TABLE_SIZE] = [0; PAGE_TABLE_SIZE];
@@ -536,6 +579,7 @@ impl<'a> Loader<'a> {
536579
(boot_lvl0_upper_addr, boot_lvl0_upper_size, boot_lvl0_upper),
537580
(boot_lvl1_upper_addr, boot_lvl1_upper_size, boot_lvl1_upper),
538581
(boot_lvl2_upper_addr, boot_lvl2_upper_size, boot_lvl2_upper),
582+
(boot_lvl2_lower_addr, boot_lvl2_lower_size, boot_lvl2_lower),
539583
]
540584
}
541585
}

0 commit comments

Comments
 (0)