From eb51898177011d6b02a995defcc1d1658cfac499 Mon Sep 17 00:00:00 2001 From: Luiz Fernando Becher de Araujo Date: Thu, 16 Jul 2026 21:09:41 -0300 Subject: [PATCH] AArch64: Map diagnostic UART and root GIC MMIO Device memory registration currently stops when /soc or its ranges property is absent and only considers direct /soc children. Some devicetrees place the interrupt controller at the root and the selected UART below nested buses. Register the exact translated range of the diagnostic UART and the register ranges of root interrupt controllers. Use the hierarchical translator when initializing GICv2 and GICv3 registers. This keeps the translation change limited to the selected console and interrupt controllers while preserving the existing behavior for other devices. Signed-off-by: Luiz Fernando Becher de Araujo --- src/arch/aarch64/device/irqchip/gic.rs | 4 +- src/arch/aarch64/device/irqchip/gicv3.rs | 6 +- src/dtb/mod.rs | 111 +++++++++++++++-------- 3 files changed, 80 insertions(+), 41 deletions(-) diff --git a/src/arch/aarch64/device/irqchip/gic.rs b/src/arch/aarch64/device/irqchip/gic.rs index d5aef88c95..d79ed945a2 100644 --- a/src/arch/aarch64/device/irqchip/gic.rs +++ b/src/arch/aarch64/device/irqchip/gic.rs @@ -1,8 +1,8 @@ use super::InterruptController; use crate::{ dtb::{ - get_mmio_address, irqchip::{InterruptHandler, IrqCell, IrqDesc}, + translate_mmio_address, }, sync::CleanLockToken, }; @@ -60,7 +60,7 @@ impl GenericInterruptController { if chunk.size.is_none() { break; } - let addr = get_mmio_address(fdt, node, &chunk).unwrap(); + let addr = translate_mmio_address(fdt, node, &chunk).unwrap(); match idx { 0 => (regs.0, regs.1) = (addr, chunk.size.unwrap()), 2 => (regs.2, regs.3) = (addr, chunk.size.unwrap()), diff --git a/src/arch/aarch64/device/irqchip/gicv3.rs b/src/arch/aarch64/device/irqchip/gicv3.rs index 9d8a0d5211..77d42a35df 100644 --- a/src/arch/aarch64/device/irqchip/gicv3.rs +++ b/src/arch/aarch64/device/irqchip/gicv3.rs @@ -5,8 +5,8 @@ use fdt::{node::NodeProperty, Fdt}; use super::{gic::GicDistIf, InterruptController}; use crate::{ dtb::{ - get_mmio_address, irqchip::{InterruptHandler, IrqCell, IrqDesc}, + translate_mmio_address, }, sync::CleanLockToken, }; @@ -53,7 +53,7 @@ impl GicV3 { // Read registers let mut chunks = node.reg().unwrap(); if let Some(gicd) = chunks.next() - && let Some(addr) = get_mmio_address(fdt, &node, &gicd) + && let Some(addr) = translate_mmio_address(fdt, &node, &gicd) { unsafe { self.gic_dist_if.init(crate::PHYS_OFFSET + addr); @@ -62,7 +62,7 @@ impl GicV3 { for _ in 0..gicrs { if let Some(gicr) = chunks.next() { self.gicrs.push(( - get_mmio_address(fdt, &node, &gicr).unwrap(), + translate_mmio_address(fdt, &node, &gicr).unwrap(), gicr.size.unwrap(), )); } diff --git a/src/dtb/mod.rs b/src/dtb/mod.rs index 22b2aa797e..26a3b292da 100644 --- a/src/dtb/mod.rs +++ b/src/dtb/mod.rs @@ -102,48 +102,87 @@ pub fn register_dev_memory_ranges(dt: &Fdt) { } } - let Some(soc_node) = dt.find_node("/soc") else { - warn!("failed to find /soc in devicetree"); - return; - }; - let Some(reg) = soc_node.ranges() else { - warn!("devicetree /soc has no ranges"); - return; - }; - for chunk in reg { - debug!( - "dev mem 0x{:08x} 0x{:08x} 0x{:08x} 0x{:08x}", - chunk.child_bus_address_hi, - chunk.child_bus_address, - chunk.parent_bus_address, - chunk.size - ); + if let Some(soc_node) = dt.find_node("/soc") { + if let Some(reg) = soc_node.ranges() { + for chunk in reg { + debug!( + "dev mem 0x{:08x} 0x{:08x} 0x{:08x} 0x{:08x}", + chunk.child_bus_address_hi, + chunk.child_bus_address, + chunk.parent_bus_address, + chunk.size + ); - /*TODO: soc memory may contain all free memory! - register_memory_region( - chunk.parent_bus_address, - chunk.size, - BootloaderMemoryKind::Device, - );*/ - } + /*TODO: soc memory may contain all free memory! + register_memory_region( + chunk.parent_bus_address, + chunk.size, + BootloaderMemoryKind::Device, + );*/ + } + } else { + warn!("devicetree /soc has no ranges"); + } - // also add all soc-internal devices because they might not be shown in ranges - // (identity-mapped soc bus may have empty ranges) - for device in soc_node.children() { - if let Some(reg) = device.reg() { - for entry in reg { - if let Some(size) = entry.size { - let addr = entry.starting_address as usize; - if let Some(mapped_addr) = get_mmio_address(dt, &device, &entry) { - debug!( - "soc device {} 0x{:08x} -> 0x{:08x} size 0x{:08x}", - device.name, addr, mapped_addr, size - ); - register_memory_region(mapped_addr, size, BootloaderMemoryKind::Device); + // also add direct /soc children because they might not be shown in + // ranges (an identity-mapped bus may have empty ranges) + for device in soc_node.children() { + if let Some(reg) = device.reg() { + for entry in reg { + if let Some(size) = entry.size { + let addr = entry.starting_address as usize; + if let Some(mapped_addr) = get_mmio_address(dt, &device, &entry) { + debug!( + "soc device {} 0x{:08x} -> 0x{:08x} size 0x{:08x}", + device.name, addr, mapped_addr, size + ); + register_memory_region(mapped_addr, size, BootloaderMemoryKind::Device); + } } } } } + } else { + warn!("failed to find /soc in devicetree"); + } + + // The selected console may be below a nested bus whose own `reg` range + // does not cover all children. Register the exact translated range so it + // remains mapped after the boot-time identity map is replaced. + if let Some((address, size, _, _, _)) = diag_uart_range(dt) { + debug!( + "diagnostic UART 0x{:08x} size 0x{:08x}", + address.data(), + size + ); + register_memory_region(address.data(), size, BootloaderMemoryKind::Device); + } + + // Interrupt controllers are not required to live below /soc. Some + // devicetrees place the primary GIC directly below the root node, so its + // register ranges would otherwise be absent from the kernel physmap. + if let Some(root) = dt.find_node("/") { + for controller in root + .children() + .filter(|node| node.property("interrupt-controller").is_some()) + { + let Some(regions) = controller.reg() else { + continue; + }; + for region in regions { + let Some(size) = region.size else { + continue; + }; + let Some(address) = translate_mmio_address(dt, &controller, ®ion) else { + continue; + }; + debug!( + "root interrupt controller {} 0x{:08x} size 0x{:08x}", + controller.name, address, size + ); + register_memory_region(address, size, BootloaderMemoryKind::Device); + } + } } }