It turns out, as you will see below, all of the public entry points are in the file gicv3_main.c
As a starting point, I search for a call to gicv3_driver_init() and I find it in plat/rockchip/common/rockchip_gicv3.c as:
gicv3_driver_init(&rockchip_gic_data);Calls to functions named plat_rockchip_gic_*() are found in:
plat/rockchip/rk3399/drivers/pmu/pmu.c plat/rockchip/common/sp_min_plat_setup.c plat/rockchip/common/plat_pm.c plat/rockchip/common/bl31_plat_setup.c plat/rockchip/common/rockchip_gicv3.c (the routines themselves)The functions called are:
plat_rockchip_gic_cpuif_enable() plat_rockchip_gic_init() plat_rockchip_gic_driver_init() plat_rockchip_gic_cpuif_disable() plat_rockchip_gic_pcpu_init()
void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
In the ATF gic driver, the register layout is established and manipulated by code in gicv3_private.h. We have these functions to set and clear bits in the enable registers. Notice that these are now in the R (redistributor) rather than the D (distributor).
void gicr_set_isenabler(uintptr_t base, unsigned int id); void gicr_set_icenabler(uintptr_t base, unsigned int id);A pair of routines in gicv3_main.c look like the jackpot:
void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num) void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num)Here "id" is what I call IRQ and we specify the processor that should handle the interrupt.
Here is another handy jackpot in the same file:
void gicv3_raise_sgi(unsigned int sgi_num, gicv3_irq_group_t group, u_register_t target)
The intcon_irqwho() call simply returned the value of the "iack" register in the CPU section of the GIC.
The intcon_irqack(irq) call wrote the IRQ number to the CPU "eoi" register then called "gic_unpend(irq)".
The gic_unpend(irq) call wrote a bit to a "pclear" register in the distributor. This bit corresponded to the bit set by intcon_ena();
Two calls look interesting in gicv3_main.c
unsigned int gicv3_get_pending_interrupt_id(void) unsigned int gicv3_get_pending_interrupt_type(void)The first looks like what I want. It returns the ID of the highest priority pending interrupt at the CPU interface. The second returns the "group" which involves the secure/non-secure grouping. This would very well be relevant for code running at EL3, but probably not for me.
The "unpend" call looks like the following routine in gicv3_main.c
void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num)
What about initialized variables.
The ESR (exception syndrome register) will tell you what kind of synchronous exception took place. The upper 6 bits of this register have the EC (exception class) value and this is what you want.
The values here seem to be a well guarded secret. Some fellow wrote a decoder in rust:
Thus far, this is the only way I have found to find our what the EC values are. They claim you can dig this information out of the ARM Architecture Manual.Look at the file src/esr/mod.rs -- here are some values:
0x15 - SVC in aarch64 state 0x20 - Instruction abort from lower EL 0x21 - Instruction abort from same EL 0x24 - Data abort from lower EL 0x25 - Data abort from same EL
This is also handy and somewhat related:
Tom's electronics pages / tom@mmto.org