From 1a739e7866ff7aba0a9924706634335016bc4454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciro=20Santilli=20=E5=85=AD=E5=9B=9B=E4=BA=8B=E4=BB=B6=20?= =?UTF-8?q?=E6=B3=95=E8=BD=AE=E5=8A=9F?= Date: Fri, 7 Jun 2019 00:00:02 +0000 Subject: [PATCH] aarch64 timer: furthen the attempt --- README.adoc | 33 +++- baremetal/arch/aarch64/timer.c | 17 ++ lkmc/board.h | 24 +++ lkmc/gicv3.h | 318 +++++++++++++++++++++++++++++++++ 4 files changed, 391 insertions(+), 1 deletion(-) create mode 100644 lkmc/board.h create mode 100644 lkmc/gicv3.h diff --git a/README.adoc b/README.adoc index b2f729b..82cba3b 100644 --- a/README.adoc +++ b/README.adoc @@ -14083,7 +14083,38 @@ A large part of the code is taken from the awesome educational OS under 2-clause I needed the following minor patches: https://github.com/NienfengYao/armv8-bare-metal/pull/1 -Handles an SVC and setups and handles the timer about once per second, going through the GICv3. +Handles an SVC and setups and handles the timer about once per second. + +The source claims GICv3, however if I try to add `-machine gic_version=3` on their command line with our QEMU v4.0.0, then it blows up at: + +.... +static void init_gicc(void) +{ + uint32_t pending_irq; + + /* Disable CPU interface */ + *REG_GIC_GICC_CTLR = GICC_CTLR_DISABLE; +.... + +which tries to write to 0x8010000 according to GDB. + +Without `-machine`, QEMU's DTB clearly states GICv2, so I'm starting to wonder if Nienfeng just made a mistake there? The QEMU GICv3 dtb contains: + +.... +reg = <0x0 0x8000000 0x0 0x10000 0x0 0x80a0000 0x0 0xf60000>; +.... + +and the GICv2 one: + +.... +reg = <0x0 0x8000000 0x0 0x10000 0x0 0x8010000 0x0 0x10000>; +.... + +which further confirms that the exception is correct: v2 has a register range at 0x8010000 while in v3 it moved to 0x80a0000 and 0x8010000 is empty. + +The original source does not mention GICv3 anywhere, only link:https://github.com/takeharukato/sample-tsk-sw/blob/c7bbc9dce6b14660bcce8d20735f8c6ebb09396b/hal/aarch64/gic-pl390.c[pl390], which is a specific GIC model that predates the GICv2 spec I believe. + +TODO I hacked `#define GIC_GICC_BASE (GIC_BASE + 0xa0000)` and now continuing attempt. ===== tukl-msd/gem5.bare-metal diff --git a/baremetal/arch/aarch64/timer.c b/baremetal/arch/aarch64/timer.c index ec0a8db..d39daae 100644 --- a/baremetal/arch/aarch64/timer.c +++ b/baremetal/arch/aarch64/timer.c @@ -2,6 +2,7 @@ #include #include +#include #define CNTV_CTL_ENABLE (1 << 0) #define CNTV_CTL_IMASK (1 << 1) @@ -20,6 +21,10 @@ void cntv_ctl_el0_enable(void) { lkmc_sysreg_cntv_ctl_el0_write(lkmc_sysreg_cntv_ctl_el0_read() | CNTV_CTL_ENABLE); } + +void lkmc_vector_trap_handler(LkmcVectorExceptionFrame *exception __attribute__((unused))) { +} + int main(void) { /* Initial state. */ printf("cntv_ctl_el0 0x%" PRIx32 "\n", lkmc_sysreg_cntv_ctl_el0_read()); @@ -31,6 +36,18 @@ int main(void) { printf("cntvct_el0 0x%" PRIx64 "\n", lkmc_sysreg_cntvct_el0_read()); printf("cntvct_el0 0x%" PRIx64 "\n", lkmc_sysreg_cntvct_el0_read()); + /*gic_v3_initialize();*/ + { + /*uint64_t ticks, current_cnt;*/ + /*uint32_t cntfrq;*/ + /*cntfrq = raw_read_cntfrq_el0();*/ + /*ticks = cntfrq;*/ + /*current_cnt = raw_read_cntvct_el0();*/ + /*raw_write_cntv_cval_el0(current_cnt + ticks);*/ + /*enable_cntv();*/ + /*enable_irq();*/ + } + #if 0 /* TODO crashes gem5. */ puts("cntfrq_el0 = 1"); diff --git a/lkmc/board.h b/lkmc/board.h new file mode 100644 index 0000000..bf0e3bc --- /dev/null +++ b/lkmc/board.h @@ -0,0 +1,24 @@ +#ifndef LKMC_BOARD_H +#define LKMC_BOARD_H +#if LKMC_GEM5 +#else +# define QEMU_VIRT_GIC_BASE (0x08000000) +# define QEMU_VIRT_GIC_INT_MAX (64) +# define QEMU_VIRT_GIC_PRIO_MAX (16) +/* SGI: Interrupt IDs 0-15 */ +/* PPI: Interrupt IDs 16-31 */ +/* SPI: Interrupt IDs 32-63 */ +# define QEMU_VIRT_GIC_INTNO_SGIO (0) +# define QEMU_VIRT_GIC_INTNO_PPIO (16) +# define QEMU_VIRT_GIC_INTNO_SPIO (32) +# define GIC_BASE (QEMU_VIRT_GIC_BASE) +# define GIC_INT_MAX (QEMU_VIRT_GIC_INT_MAX) +# define GIC_PRIO_MAX (QEMU_VIRT_GIC_PRIO_MAX) +# define GIC_INTNO_SGI0 (QEMU_VIRT_GIC_INTNO_SGIO) +# define GIC_INTNO_PPI0 (QEMU_VIRT_GIC_INTNO_PPIO) +# define GIC_INTNO_SPI0 (QEMU_VIRT_GIC_INTNO_SPIO) +# define GIC_PRI_SHIFT (4) +# define GIC_PRI_MASK (0x0f) +# define TIMER_IRQ (27) /** Timer IRQ */ +#endif +#endif diff --git a/lkmc/gicv3.h b/lkmc/gicv3.h new file mode 100644 index 0000000..ea2f680 --- /dev/null +++ b/lkmc/gicv3.h @@ -0,0 +1,318 @@ +#ifndef LKMC_GICV3_H +#define LKMC_GICV3_H + +#include +#include + +typedef int32_t irq_no; + +#define GIC_GICD_BASE (GIC_BASE) +#define GIC_GICC_BASE (GIC_BASE + 0xa0000) + +#define GIC_GICD_INT_PER_REG (32) +#define GIC_GICD_IPRIORITY_PER_REG (4) +#define GIC_GICD_IPRIORITY_SIZE_PER_REG (8) +#define GIC_GICD_ITARGETSR_CORE0_TARGET_BMAP (0x01010101) +#define GIC_GICD_ITARGETSR_PER_REG (4) +#define GIC_GICD_ITARGETSR_SIZE_PER_REG (8) +#define GIC_GICD_ICFGR_PER_REG (16) +#define GIC_GICD_ICFGR_SIZE_PER_REG (2) +#define GIC_GICD_ICENABLER_PER_REG (32) +#define GIC_GICD_ISENABLER_PER_REG (32) +#define GIC_GICD_ICPENDR_PER_REG (32) +#define GIC_GICD_ISPENDR_PER_REG (32) + +/* 8.12 The GIC CPU interface register map */ +#define GIC_GICC_CTLR (GIC_GICC_BASE + 0x000) /* CPU Interface Control Register */ +#define GIC_GICC_PMR (GIC_GICC_BASE + 0x004) /* Interrupt Priority Mask Register */ +#define GIC_GICC_BPR (GIC_GICC_BASE + 0x008) /* Binary Point Register */ +#define GIC_GICC_IAR (GIC_GICC_BASE + 0x00C) /* Interrupt Acknowledge Register */ +#define GIC_GICC_EOIR (GIC_GICC_BASE + 0x010) /* End of Interrupt Register */ +#define GIC_GICC_RPR (GIC_GICC_BASE + 0x014) /* Running Priority Register */ +#define GIC_GICC_HPIR (GIC_GICC_BASE + 0x018) /* Highest Pending Interrupt Register */ +#define GIC_GICC_ABPR (GIC_GICC_BASE + 0x01C) /* Aliased Binary Point Register */ +#define GIC_GICC_IIDR (GIC_GICC_BASE + 0x0FC) /* CPU Interface Identification Register */ + +/* 8.13.7 GICC_CTLR, CPU Interface Control Register */ +#define GICC_CTLR_ENABLE (0x1) /* Enable GICC */ +#define GICC_CTLR_DISABLE (0x0) /* Disable GICC */ + +/* 8.13.14 GICC_PMR, CPU Interface Priority Mask Register */ +#define GICC_PMR_PRIO_MIN (0xff) /* The lowest level mask */ +#define GICC_PMR_PRIO_HIGH (0x0) /* The highest level mask */ + +/* 8.13.6 GICC_BPR, CPU Interface Binary Point Register */ +/* In systems that support only one Security state, when GICC_CTLR.CBPR == 0, +this register determines only Group 0 interrupt preemption. */ +#define GICC_BPR_NO_GROUP (0x0) /* handle all interrupts */ + +/* 8.13.11 GICC_IAR, CPU Interface Interrupt Acknowledge Register */ +#define GICC_IAR_INTR_IDMASK (0x3ff) /* 0-9 bits means Interrupt ID */ +#define GICC_IAR_SPURIOUS_INTR (0x3ff) /* 1023 means spurious interrupt */ + +/* 8.8 The GIC Distributor register map */ +#define GIC_GICD_CTLR (GIC_GICD_BASE + 0x000) /* Distributor Control Register */ +#define GIC_GICD_TYPER (GIC_GICD_BASE + 0x004) /* Interrupt Controller Type Register */ +#define GIC_GICD_IIDR (GIC_GICD_BASE + 0x008) /* Distributor Implementer Identification Register */ +#define GIC_GICD_IGROUPR(n) (GIC_GICD_BASE + 0x080 + ( (n) * 4 ) ) /* Interrupt Group Registers */ +#define GIC_GICD_ISENABLER(n) (GIC_GICD_BASE + 0x100 + ( (n) * 4 ) ) /* Interrupt Set-Enable Registers */ +#define GIC_GICD_ICENABLER(n) (GIC_GICD_BASE + 0x180 + ( (n) * 4 ) ) /* Interrupt Clear-Enable Registers */ +#define GIC_GICD_ISPENDR(n) (GIC_GICD_BASE + 0x200 + ( (n) * 4 ) ) /* Interrupt Set-Pending Registers */ +#define GIC_GICD_ICPENDR(n) (GIC_GICD_BASE + 0x280 + ( (n) * 4 ) ) /* Interrupt Clear-Pending Registers */ +#define GIC_GICD_ISACTIVER(n) (GIC_GICD_BASE + 0x300 + ( (n) * 4 ) ) /* Interrupt Set-Active Registers */ +#define GIC_GICD_ICACTIVER(n) (GIC_GICD_BASE + 0x380 + ( (n) * 4 ) ) /* Interrupt Clear-Active Registers */ +#define GIC_GICD_IPRIORITYR(n) (GIC_GICD_BASE + 0x400 + ( (n) * 4 ) ) /* Interrupt Priority Registers */ +#define GIC_GICD_ITARGETSR(n) (GIC_GICD_BASE + 0x800 + ( (n) * 4 ) ) /* Interrupt Processor Targets Registers */ +#define GIC_GICD_ICFGR(n) (GIC_GICD_BASE + 0xc00 + ( (n) * 4 ) ) /* Interrupt Configuration Registers */ +#define GIC_GICD_NSCAR(n) (GIC_GICD_BASE + 0xe00 + ( (n) * 4 ) ) /* Non-secure Access Control Registers */ +#define GIC_GICD_SGIR (GIC_GICD_BASE + 0xf00 ) /* Software Generated Interrupt Register */ +#define GIC_GICD_CPENDSGIR(n) (GIC_GICD_BASE + 0xf10 + ( (n) * 4 ) ) /* SGI Clear-Pending Registers */ +#define GIC_GICD_SPENDSGIR(n) (GIC_GICD_BASE + 0xf20 + ( (n) * 4 ) ) /* SGI Set-Pending Registers */ + +/* 8.9.4 GICD_CTLR, Distributor Control Register */ +#define GIC_GICD_CTLR_ENABLE (0x1) /* Enable GICD */ +#define GIC_GICD_CTLR_DISABLE (0x0) /* Disable GICD */ + +/* 8.9.7 GICD_ICFGR, Interrupt Configuration Registers */ +#define GIC_GICD_ICFGR_LEVEL (0x0) /* level-sensitive */ +#define GIC_GICD_ICFGR_EDGE (0x2) /* edge-triggered */ + +/* Register access macros for GICC */ +#define REG_GIC_GICC_CTLR ((volatile uint32_t *)(uintptr_t)GIC_GICC_CTLR) +#define REG_GIC_GICC_PMR ((volatile uint32_t *)(uintptr_t)GIC_GICC_PMR) +#define REG_GIC_GICC_BPR ((volatile uint32_t *)(uintptr_t)GIC_GICC_BPR) +#define REG_GIC_GICC_IAR ((volatile uint32_t *)(uintptr_t)GIC_GICC_IAR) +#define REG_GIC_GICC_EOIR ((volatile uint32_t *)(uintptr_t)GIC_GICC_EOIR) +#define REG_GIC_GICC_RPR ((volatile uint32_t *)(uintptr_t)GIC_GICC_RPR) +#define REG_GIC_GICC_HPIR ((volatile uint32_t *)(uintptr_t)GIC_GICC_HPIR) +#define REG_GIC_GICC_ABPR ((volatile uint32_t *)(uintptr_t)GIC_GICC_ABPR) +#define REG_GIC_GICC_IIDR ((volatile uint32_t *)(uintptr_t)GIC_GICC_IIDR) + +/* Register access macros for GICD */ +#define REG_GIC_GICD_CTLR ((volatile uint32_t *)(uintptr_t)GIC_GICD_CTLR) +#define REG_GIC_GICD_TYPE ((volatile uint32_t *)(uintptr_t)GIC_GICD_TYPE) +#define REG_GIC_GICD_IIDR ((volatile uint32_t *)(uintptr_t)GIC_GICD_IIDR) +#define REG_GIC_GICD_IGROUPR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_IGROUPR(n)) +#define REG_GIC_GICD_ISENABLER(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ISENABLER(n)) +#define REG_GIC_GICD_ICENABLER(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ICENABLER(n)) +#define REG_GIC_GICD_ISPENDR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ISPENDR(n)) +#define REG_GIC_GICD_ICPENDR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ICPENDR(n)) +#define REG_GIC_GICD_ISACTIVER(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ISACTIVER(n)) +#define REG_GIC_GICD_ICACTIVER(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ICACTIVER(n)) +#define REG_GIC_GICD_IPRIORITYR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_IPRIORITYR(n)) +#define REG_GIC_GICD_ITARGETSR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ITARGETSR(n)) +#define REG_GIC_GICD_ICFGR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ICFGR(n)) +#define REG_GIC_GICD_NSCAR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_NSCAR(n)) +#define REG_GIC_GICD_SGIR ((volatile uint32_t *)(uintptr_t)GIC_GICD_SGIR) +#define REG_GIC_GICD_CPENDSGIR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_CPENDSGIR(n)) +#define REG_GIC_GICD_SPENDSGIR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_SPENDSGIR(n)) + +void gic_v3_initialize(void); +void gic_v3_eoi(irq_no irq); +int gic_v3_find_pending_irq( + LkmcVectorExceptionFrame *exc __attribute__((unused)), + irq_no *irqp +); +void gicd_disable_int(irq_no irq); +void gicd_enable_int(irq_no irq); +void gicd_clear_pending(irq_no irq); + +/* Initialize GIC Controller */ +static void init_gicc(void) { + uint32_t pending_irq; + + /* Disable CPU interface */ + *REG_GIC_GICC_CTLR = GICC_CTLR_DISABLE; + + /* Set the priority level as the lowest priority. + * Note: Higher priority corresponds to a lower Priority field value in the GIC_PMR. + * In addition to this, writing 255 to the GICC_PMR always sets it to the + * largest supported priority field value. + */ + *REG_GIC_GICC_PMR = GICC_PMR_PRIO_MIN; + + /* Handle all of interrupts in a single group */ + *REG_GIC_GICC_BPR = GICC_BPR_NO_GROUP; + + /* Clear all of the active interrupts */ + for(pending_irq = ( *REG_GIC_GICC_IAR & GICC_IAR_INTR_IDMASK ); + ( pending_irq != GICC_IAR_SPURIOUS_INTR ); + pending_irq = ( *REG_GIC_GICC_IAR & GICC_IAR_INTR_IDMASK ) ) + *REG_GIC_GICC_EOIR = *REG_GIC_GICC_IAR; + + /* Enable CPU interface */ + *REG_GIC_GICC_CTLR = GICC_CTLR_ENABLE; +} + +static void init_gicd(void) { + int32_t i, regs_nr; + + /* Diable distributor */ + *REG_GIC_GICD_CTLR = GIC_GICD_CTLR_DISABLE; + + /* Disable all IRQs */ + regs_nr = (GIC_INT_MAX + GIC_GICD_INT_PER_REG - 1) / GIC_GICD_INT_PER_REG; + for (i = 0; regs_nr > i; ++i) + *REG_GIC_GICD_ICENABLER(i) = ~((uint32_t)(0)); + + /* Clear all pending IRQs */ + regs_nr = (GIC_INT_MAX + GIC_GICD_INT_PER_REG - 1) / GIC_GICD_INT_PER_REG; + for (i = 0; regs_nr > i; ++i) + *REG_GIC_GICD_ICPENDR(i) = ~((uint32_t)(0)); + + /* Set all of interrupt priorities as the lowest priority */ + regs_nr = ( GIC_INT_MAX + GIC_GICD_IPRIORITY_PER_REG - 1) / + GIC_GICD_IPRIORITY_PER_REG ; + for (i = 0; regs_nr > i; i++) + *REG_GIC_GICD_IPRIORITYR(i) = ~((uint32_t)(0)); + + /* Set target of all of shared peripherals to processor 0 */ + for (i = GIC_INTNO_SPI0 / GIC_GICD_ITARGETSR_PER_REG; + ( (GIC_INT_MAX + (GIC_GICD_ITARGETSR_PER_REG - 1) ) / + GIC_GICD_ITARGETSR_PER_REG ) > i; ++i) + *REG_GIC_GICD_ITARGETSR(i) = + (uint32_t)GIC_GICD_ITARGETSR_CORE0_TARGET_BMAP; + + /* Set trigger type for all peripheral interrupts level triggered */ + for (i = GIC_INTNO_PPI0 / GIC_GICD_ICFGR_PER_REG; + (GIC_INT_MAX + (GIC_GICD_ICFGR_PER_REG - 1)) / GIC_GICD_ICFGR_PER_REG > i; ++i) + *REG_GIC_GICD_ICFGR(i) = GIC_GICD_ICFGR_LEVEL; + + /* Enable distributor */ + *REG_GIC_GICD_CTLR = GIC_GICD_CTLR_ENABLE; +} + +/* Disable IRQ + * @param[in] irq IRQ number + */ +void gicd_disable_int(irq_no irq) { + *REG_GIC_GICD_ICENABLER( (irq / GIC_GICD_ICENABLER_PER_REG) ) = + 1U << ( irq % GIC_GICD_ICENABLER_PER_REG ); +} + +/* Enable IRQ + * @param[in] irq IRQ number + */ +void gicd_enable_int(irq_no irq) { + *REG_GIC_GICD_ISENABLER( (irq / GIC_GICD_ISENABLER_PER_REG) ) = + 1U << ( irq % GIC_GICD_ISENABLER_PER_REG ); +} + +/* Clear a pending interrupt + * @param[in] irq IRQ number + */ +void gicd_clear_pending(irq_no irq) { + *REG_GIC_GICD_ICPENDR( (irq / GIC_GICD_ICPENDR_PER_REG) ) = + 1U << ( irq % GIC_GICD_ICPENDR_PER_REG ); +} + + +/* Probe pending interrupt + * @param[in] irq IRQ number + */ +static int gicd_probe_pending(irq_no irq) { + int is_pending; + + is_pending = ( *REG_GIC_GICD_ISPENDR( (irq / GIC_GICD_ISPENDR_PER_REG) ) & + ( 1U << ( irq % GIC_GICD_ISPENDR_PER_REG ) ) ); + + return ( is_pending != 0 ); +} + +/* Set an interrupt target processor + * @param[in] irq IRQ number + * @param[in] p Target processor mask + * 0x1 processor 0 + * 0x2 processor 1 + * 0x4 processor 2 + * 0x8 processor 3 + */ +static void gicd_set_target(irq_no irq, uint32_t p){ + uint32_t shift; + uint32_t reg; + + shift = (irq % GIC_GICD_ITARGETSR_PER_REG) * GIC_GICD_ITARGETSR_SIZE_PER_REG; + + reg = *REG_GIC_GICD_ITARGETSR(irq / GIC_GICD_ITARGETSR_PER_REG); + reg &= ~( ((uint32_t)(0xff)) << shift); + reg |= (p << shift); + *REG_GIC_GICD_ITARGETSR(irq / GIC_GICD_ITARGETSR_PER_REG) = reg; +} + +/* Set an interrupt priority + * @param[in] irq IRQ number + * @param[in] prio Interrupt priority in Arm specific expression + */ +static void gicd_set_priority(irq_no irq, uint32_t prio){ + uint32_t shift; + uint32_t reg; + + shift = (irq % GIC_GICD_IPRIORITY_PER_REG) * GIC_GICD_IPRIORITY_SIZE_PER_REG; + reg = *REG_GIC_GICD_IPRIORITYR(irq / GIC_GICD_IPRIORITY_PER_REG); + reg &= ~(((uint32_t)(0xff)) << shift); + reg |= (prio << shift); + *REG_GIC_GICD_IPRIORITYR(irq / GIC_GICD_IPRIORITY_PER_REG) = reg; +} + +/* Configure IRQ + * @param[in] irq IRQ number + * @param[in] config Configuration value for GICD_ICFGR + */ +static void gicd_config(irq_no irq, unsigned int config) { + uint32_t shift; + uint32_t reg; + + shift = (irq % GIC_GICD_ICFGR_PER_REG) * GIC_GICD_ICFGR_SIZE_PER_REG; /* GICD_ICFGR has 16 fields, each field has 2bits. */ + reg = *REG_GIC_GICD_ICFGR( irq / GIC_GICD_ICFGR_PER_REG); + reg &= ~( ( (uint32_t)(0x03) ) << shift ); /* Clear the field */ + reg |= ( ( (uint32_t)config ) << shift ); /* Set the value to the field correponding to irq */ + *REG_GIC_GICD_ICFGR( irq / GIC_GICD_ICFGR_PER_REG) = reg; +} + +/* Send End of Interrupt to IRQ line for GIC + * @param[in] ctrlr IRQ controller information + * @param[in] irq IRQ number + */ +void gic_v3_eoi(irq_no irq) { + gicd_clear_pending(irq); +} + +/* Initialize GIC IRQ controller */ +/* RyanYao: 2018/07/20 + * I supppose the current access is security, because GICD_CTLR.DS is 0b0 and + * we can access. + */ +void gic_v3_initialize(void) { + init_gicd(); + init_gicc(); + gicd_config(TIMER_IRQ, GIC_GICD_ICFGR_EDGE); + gicd_set_priority(TIMER_IRQ, 0 << GIC_PRI_SHIFT ); /* Set priority */ + gicd_set_target(TIMER_IRQ, 0x1); /* processor 0 */ + gicd_clear_pending(TIMER_IRQ); + gicd_enable_int(TIMER_IRQ); +} + + +/* Find pending IRQ + * @param[in] exc An exception frame + * @param[in,out] irqp An IRQ number to be processed + */ +int gic_v3_find_pending_irq( + LkmcVectorExceptionFrame *exc __attribute__((unused)), + irq_no *irqp +) { + int rc; + irq_no i; + for( i = 0; GIC_INT_MAX > i; ++i) { + if ( gicd_probe_pending(i) ) { + rc = 1; + *irqp = i; + goto found; + } + } + rc = 0; +found: + return rc; +} + +#endif