AArch64: Allow GICv2 initialization on uniprocessor systems

Treat a zero GICD_ITARGETSR target mask as valid during BSP
initialization because GICv2 target registers may be RAZ/WI on
uniprocessor implementations, while retaining fail-closed SMP
behavior by requiring a valid target mask before starting secondary
CPUs and after each AP initializes its local GIC interface.

Signed-off-by: Luiz Fernando Becher de Araujo <luiz.becher.araujo@gmail.com>
This commit is contained in:
Luiz Fernando Becher de Araujo
2026-08-23 19:37:08 +00:00
parent ac99077220
commit 9d0de645a1
3 changed files with 22 additions and 5 deletions
+4
View File
@@ -478,6 +478,10 @@ pub(super) fn start_secondaries() {
);
return;
}
if crate::arch::device::irqchip::current_cpu_target_mask().is_none() {
error!("CPU activation unavailable: BSP has no directed-SGI target mask");
return;
}
if !crate::arch::device::generic_timer::ready() {
error!("CPU activation unavailable: architected timer is not initialized");
return;
+10 -4
View File
@@ -55,6 +55,14 @@ pub(crate) fn cpu_capacity() -> Option<usize> {
(count != 0).then_some(count)
}
pub(crate) fn current_cpu_target_mask() -> Option<u8> {
let target_mask = crate::percpu::PercpuBlock::current()
.misc_arch_info
.gic_target_mask
.load(Ordering::Acquire);
(target_mask != 0).then_some(target_mask)
}
pub(crate) fn init_current_cpu() -> Result<()> {
let dist = GICD_BASE.load(Ordering::Acquire);
let cpu = GICC_BASE.load(Ordering::Acquire);
@@ -79,11 +87,9 @@ pub(crate) fn init_current_cpu() -> Result<()> {
write32(cpu, GICC_CTLR, 1);
// ITARGETSR0 is banked for SGIs/PPIs and exposes the target bit assigned
// to the current GICv2 CPU interface.
// to the current GICv2 CPU interface. On a uniprocessor GIC the target
// registers are RAZ/WI, so zero is valid until directed SGIs are needed.
let target_mask = (read32(dist, GICD_ITARGETSR) & 0xff) as u8;
if target_mask == 0 {
return Err(Error::new(EINVAL));
}
crate::percpu::PercpuBlock::current()
.misc_arch_info
.gic_target_mask
+8 -1
View File
@@ -42,7 +42,10 @@ pub(crate) fn ic_for_chip(fdt: &Fdt, node: &FdtNode) -> Option<usize> {
pub(crate) fn init_ap() -> syscall::Result<()> {
if gic::active() {
gic::init_current_cpu()
gic::init_current_cpu()?;
gic::current_cpu_target_mask()
.map(|_| ())
.ok_or_else(|| syscall::Error::new(syscall::error::EINVAL))
} else {
Err(syscall::Error::new(syscall::error::ENODEV))
}
@@ -52,6 +55,10 @@ pub(crate) fn cpu_capacity() -> Option<usize> {
gic::cpu_capacity()
}
pub(crate) fn current_cpu_target_mask() -> Option<u8> {
gic::active().then(gic::current_cpu_target_mask).flatten()
}
pub(crate) fn enable_local_irq(hwirq: u32) -> syscall::Result<()> {
if gic::active() {
gic::enable_local_irq(hwirq)