diff options
| author | Bradley Morgan <brads@mainlining.org> | 2026-10-04 02:24:47 +0000 |
|---|---|---|
| committer | Bradley Morgan <brads@mainlining.org> | 2026-10-04 02:24:47 +0000 |
| commit | be4565f1fe3de7e16a48688ab8da39c433f0fee3 (patch) | |
| tree | e8e8a4bc2ea0861f6e1d6c5e8011ea11b4abaea4 /common/main.c | |
| parent | 871e4d1551ac8c5be4339e4a3129c45014e613b5 (diff) | |
tashaboot: gic init and the devicetree reg walker
The interrupt controller state the kernel inherits is the
bootloader's to define. On real hardware the secure world
owns which interrupts the non-secure kernel will ever see,
and a distributor left with random enables or secure group
bits can fire before the kernel's irqchip driver is up. The
gic goes into the defined state here, distributor off, every
line in the non-secure group, per interrupt enables, pending
and active cleared, cpu interface off. The kernel programs
everything it runs with itself, it starts from zero instead
of from whatever the last stage left.
The controller is found in the devicetree, no hardcoded
address. The new walker locates a node by name at any depth
and decodes the first reg pair with the root cell counts,
the same parse the kernel does. The node's own begin token
starts the walk at depth zero, starting at one skips every
prop in the node, the first version matched nothing.
receipt: gic 8000000 off, root irq handler gic_handle_irq,
smp brought up 1 node 4 cpus, run /init, busybox shell, the
uart console driven by irq 14 through the gic the kernel
reprogrammed over our off state.
Diffstat (limited to 'common/main.c')
| -rw-r--r-- | common/main.c | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/common/main.c b/common/main.c index a8fdf58..a0237af 100644 --- a/common/main.c +++ b/common/main.c @@ -57,6 +57,7 @@ extern char __image_copy_end[]; extern void __NO_RETURN tb_boot_linux(uintptr_t ep, uintptr_t fw_arg); extern uintptr_t tb_dtb_relocate(uintptr_t dtb, void *scratch, size_t scratch_size, size_t grow); +extern int tb_gic_init(uintptr_t gicd, uintptr_t gicc); extern int tb_dtb_add_chosen_prop(uintptr_t dtb, const char *name, const void *val, size_t len); static size_t initrd_size; @@ -165,6 +166,31 @@ void tashaboot_main(uintptr_t fw_arg) } fw_arg = newdtb; + + /* + * the interrupt controller the machine told us + * about, found by name, the reg pair read with the + * root cell counts. the gic goes into the defined + * off state before the kernel brings its own irq + * handling up. + */ + { + extern int tb_dtb_find_reg0(uintptr_t dtb, + const char *name, + uintptr_t *addr, + size_t *size); + uintptr_t gicd = 0; + uintptr_t gicc = 0; + size_t sz = 0; + + if (tb_dtb_find_reg0(fw_arg, "intc", &gicd, &sz) == 0 && + sz >= 0x10000) { + gicc = gicd + 0x10000; + tb_gic_init(gicd, gicc); + dprintf(ALWAYS, "gic: %lx off\n", + (unsigned long)gicd); + } + } } /* |
