#ifndef LKMC_GIC_H #define LKMC_GIC_H #include #if LKMC_QEMU /* info qtree contains: * * dev: arm_gic, id "" * mmio 0000000008000000/0000000000001000 * mmio 0000000008010000/0000000000002000 */ #define GIC_GICD_BASE 0x08000000 #define GIC_GICC_BASE 0x08010000 #define TIMER_IRQ 27 #elif LKMC_GEM5 /* On source at: https://github.com/gem5/gem5/blob/f525028c126af33da532f6703a152d81d900dcf7/src/dev/arm/RealView.py#L952 * * On m5out/config.ini at: * * * system.realview.gic.dist_addr=738201600 * * system.realview.gic.cpu_addr=738205696 * * On auto-generated DTB in m5out/system.dtb after converstion to dts: * * interrupt-controller { * compatible = "gem5,gic", "arm,cortex-a15-gic", "arm,cortex-a9-gic"; * reg = <0x0 0x2c001000 0x0 0x1000 0x0 0x2c002000 0x0 0x1000 0x0 0x2c004000 0x0 0x2000 0x0 0x2c006000 0x0 0x2000>; * */ #define GIC_GICD_BASE 0x2c001000 #define GIC_GICC_BASE 0x2c002000 #define TIMER_IRQ 30 #endif #define GIC_INT_MAX 64 #define GIC_PRIO_MAX 16 #define GIC_INTNO_SGI0 0 #define GIC_INTNO_PPI0 16 #define GIC_INTNO_SPI0 32 #define GIC_PRI_SHIFT 4 #define GIC_PRI_MASK 0x0f typedef int32_t irq_no; #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_initialize(void); void gic_eoi(irq_no irq); int gic_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_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_initialize(void) { init_gicd(); init_gicc(); gicd_config(TIMER_IRQ, GIC_GICD_ICFGR_EDGE); gicd_set_priority(TIMER_IRQ, 0 << GIC_PRI_SHIFT); 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 * @return 0 if found, 1 if not found */ int gic_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 = 0; *irqp = i; goto found; } } rc = 1; found: return rc; } #endif