github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/arm/gic/gic.go (about) 1 // ARM Generic Interrupt Controller (GIC) driver 2 // https://github.com/usbarmory/tamago 3 // 4 // IP: ARM Generic Interrupt Controller version 2.0 5 // 6 // Copyright (c) WithSecure Corporation 7 // https://foundry.withsecure.com 8 // 9 // Use of this source code is governed by the license 10 // that can be found in the LICENSE file. 11 12 // Package gic implements a driver for the ARM Generic Interrupt Controller. 13 // 14 // The driver is based on the following reference specifications: 15 // - ARM IHI 0048B.b - ARM Generic Interrupt Controller - Architecture version 2.0 16 // 17 // This package is only meant to be used with `GOOS=tamago GOARCH=arm` as 18 // supported by the TamaGo framework for bare metal Go on ARM SoCs, see 19 // https://github.com/usbarmory/tamago. 20 package gic 21 22 import ( 23 "github.com/usbarmory/tamago/internal/reg" 24 ) 25 26 const ( 27 // GIC offsets in Cortex-A7 28 // (p178, Table 8-1, Cortex-A7 MPCore Technical Reference Manual). 29 GICD_OFF = 0x1000 30 GICC_OFF = 0x2000 31 32 // Distributor register map 33 // (p75, Table 4-1, ARM Generic Interrupt Controller Architecture Specification). 34 GICD_CTLR = 0x000 35 GICD_CTLR_ENABLEGRP1 = 1 36 GICD_CTLR_ENABLEGRP0 = 0 37 38 GICD_TYPER = 0x004 39 GICD_TYPER_ITLINES = 0 40 41 GICD_IGROUPR = 0x080 42 GICD_ISENABLER = 0x100 43 GICD_ICENABLER = 0x180 44 GICD_ICPENDR = 0x280 45 46 // CPU interface register map 47 // (p76, Table 4-2, ARM Generic Interrupt Controller Architecture Specification). 48 GICC_CTLR = 0x0000 49 GICC_CTLR_FIQEN = 3 50 GICC_CTLR_ENABLEGRP1 = 1 51 GICC_CTLR_ENABLEGRP0 = 0 52 53 GICC_PMR = 0x0004 54 GICC_PMR_PRIORITY = 0 55 56 GICC_IAR = 0x000c 57 GICC_IAR_ID = 0 58 59 GICC_EOIR = 0x0010 60 GICC_EOIR_ID = 0 61 62 GICC_AIAR = 0x0020 63 GICC_AIAR_ID = 0 64 65 GICC_AEOIR = 0x0024 66 GICC_AEOIR_ID = 0 67 ) 68 69 // GIC represents the Generic Interrupt Controller instance. 70 type GIC struct { 71 // Base register 72 Base uint32 73 74 // control registers 75 gicd uint32 76 gicc uint32 77 } 78 79 // InitGIC initializes the ARM Generic Interrupt Controller (GIC). 80 func (hw *GIC) Init(secure bool, fiqen bool) { 81 if hw.Base == 0 { 82 panic("invalid GIC instance") 83 } 84 85 hw.gicd = hw.Base + GICD_OFF 86 hw.gicc = hw.Base + GICC_OFF 87 88 // Get the maximum number of external interrupt lines 89 itLinesNum := reg.Get(hw.gicd+GICD_TYPER, GICD_TYPER_ITLINES, 0x1f) 90 91 // Add a line for the 32 internal interrupts 92 itLinesNum += 1 93 94 for n := uint32(0); n < itLinesNum; n++ { 95 // Disable interrupts 96 addr := hw.gicd + GICD_ICENABLER + 4*n 97 reg.Write(addr, 0xffffffff) 98 99 // Clear pending interrupts 100 addr = hw.gicd + GICD_ICPENDR + 4*n 101 reg.Write(addr, 0xffffffff) 102 103 if !secure { 104 addr = hw.gicd + GICD_IGROUPR + 4*n 105 reg.Write(addr, 0xffffffff) 106 } 107 } 108 109 // Set priority mask to allow Non-Secure world to use the lower half 110 // of the priority range. 111 reg.Write(hw.gicc+GICC_PMR, 0x80) 112 113 reg.SetTo(hw.gicc+GICC_CTLR, GICC_CTLR_FIQEN, fiqen) 114 115 reg.Set(hw.gicc+GICC_CTLR, GICC_CTLR_ENABLEGRP1) 116 reg.Set(hw.gicc+GICC_CTLR, GICC_CTLR_ENABLEGRP0) 117 118 reg.Set(hw.gicd+GICD_CTLR, GICD_CTLR_ENABLEGRP1) 119 reg.Set(hw.gicd+GICD_CTLR, GICD_CTLR_ENABLEGRP0) 120 } 121 122 // FIQEn controls whether Group 0 (Secure) interrupts should be signalled as 123 // IRQ or FIQ requests. 124 func (hw *GIC) FIQEn(fiq bool) { 125 if hw.gicc == 0 { 126 return 127 } 128 129 reg.SetTo(hw.gicc+GICC_CTLR, GICC_CTLR_FIQEN, fiq) 130 } 131 132 func irq(gicd uint32, m int, secure bool, enable bool) { 133 if gicd == 0 { 134 return 135 } 136 137 var addr uint32 138 139 n := uint32(m / 32) 140 i := m % 32 141 142 if enable { 143 reg.SetTo(gicd + GICD_IGROUPR + 4*n, i, !secure) 144 addr = gicd + GICD_ISENABLER + 4*n 145 } else { 146 addr = gicd + GICD_ICENABLER + 4*n 147 } 148 149 reg.SetTo(addr, i, true) 150 } 151 152 // EnableInterrupt enables forwarding of the corresponding interrupt to the CPU 153 // and configures its group status (Secure: Group 0, Non-Secure: Group 1). 154 func (hw *GIC) EnableInterrupt(id int, secure bool) { 155 irq(hw.gicd, id, secure, true) 156 } 157 158 // DisableInterrupt disables forwarding of the corresponding interrupt to the 159 // CPU. 160 func (hw *GIC) DisableInterrupt(id int) { 161 irq(hw.gicd, id, false, false) 162 } 163 164 // GetInterrupt obtains and acknowledges a signaled interrupt, the end of its 165 // handling must be signaled by closing the returned channel. 166 func (hw *GIC) GetInterrupt(secure bool) (id int, end chan struct{}) { 167 if hw.gicc == 0 { 168 return 169 } 170 171 var m uint32 172 173 if secure { 174 m = reg.Get(hw.gicc+GICC_IAR, GICC_IAR_ID, 0x3ff) 175 } else { 176 m = reg.Get(hw.gicc+GICC_AIAR, GICC_AIAR_ID, 0x3ff) 177 } 178 179 if m < 1020 { 180 end = make(chan struct{}) 181 182 go func() { 183 <-end 184 185 if secure { 186 reg.SetN(hw.gicc+GICC_EOIR, GICC_EOIR_ID, 0x3ff, m) 187 } else { 188 reg.SetN(hw.gicc+GICC_AEOIR, GICC_AEOIR_ID, 0x3ff, m) 189 } 190 }() 191 } 192 193 id = int(m) 194 195 return 196 }