1 /** @file 2 * 3 * Copyright (c) 2011-2016, ARM Limited. All rights reserved. 4 * 5 * This program and the accompanying materials 6 * are licensed and made available under the terms and conditions of the BSD License 7 * which accompanies this distribution. The full text of the license may be found at 8 * http://opensource.org/licenses/bsd-license.php 9 * 10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 * 13 **/ 14 15 #include <Library/ArmGicLib.h> 16 17 #include "ArmGicDxe.h" 18 19 #define ARM_GIC_DEFAULT_PRIORITY 0x80 20 21 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol; 22 23 STATIC UINTN mGicDistributorBase; 24 STATIC UINTN mGicRedistributorsBase; 25 26 /** 27 Enable interrupt source Source. 28 29 @param This Instance pointer for this protocol 30 @param Source Hardware source of the interrupt 31 32 @retval EFI_SUCCESS Source interrupt enabled. 33 @retval EFI_DEVICE_ERROR Hardware could not be programmed. 34 35 **/ 36 EFI_STATUS 37 EFIAPI 38 GicV3EnableInterruptSource ( 39 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, 40 IN HARDWARE_INTERRUPT_SOURCE Source 41 ) 42 { 43 if (Source >= mGicNumInterrupts) { 44 ASSERT(FALSE); 45 return EFI_UNSUPPORTED; 46 } 47 48 ArmGicEnableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source); 49 50 return EFI_SUCCESS; 51 } 52 53 /** 54 Disable interrupt source Source. 55 56 @param This Instance pointer for this protocol 57 @param Source Hardware source of the interrupt 58 59 @retval EFI_SUCCESS Source interrupt disabled. 60 @retval EFI_DEVICE_ERROR Hardware could not be programmed. 61 62 **/ 63 EFI_STATUS 64 EFIAPI 65 GicV3DisableInterruptSource ( 66 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, 67 IN HARDWARE_INTERRUPT_SOURCE Source 68 ) 69 { 70 if (Source >= mGicNumInterrupts) { 71 ASSERT(FALSE); 72 return EFI_UNSUPPORTED; 73 } 74 75 ArmGicDisableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source); 76 77 return EFI_SUCCESS; 78 } 79 80 /** 81 Return current state of interrupt source Source. 82 83 @param This Instance pointer for this protocol 84 @param Source Hardware source of the interrupt 85 @param InterruptState TRUE: source enabled, FALSE: source disabled. 86 87 @retval EFI_SUCCESS InterruptState is valid 88 @retval EFI_DEVICE_ERROR InterruptState is not valid 89 90 **/ 91 EFI_STATUS 92 EFIAPI 93 GicV3GetInterruptSourceState ( 94 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, 95 IN HARDWARE_INTERRUPT_SOURCE Source, 96 IN BOOLEAN *InterruptState 97 ) 98 { 99 if (Source >= mGicNumInterrupts) { 100 ASSERT(FALSE); 101 return EFI_UNSUPPORTED; 102 } 103 104 *InterruptState = ArmGicIsInterruptEnabled (mGicDistributorBase, mGicRedistributorsBase, Source); 105 106 return EFI_SUCCESS; 107 } 108 109 /** 110 Signal to the hardware that the End Of Interrupt state 111 has been reached. 112 113 @param This Instance pointer for this protocol 114 @param Source Hardware source of the interrupt 115 116 @retval EFI_SUCCESS Source interrupt EOI'ed. 117 @retval EFI_DEVICE_ERROR Hardware could not be programmed. 118 119 **/ 120 EFI_STATUS 121 EFIAPI 122 GicV3EndOfInterrupt ( 123 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, 124 IN HARDWARE_INTERRUPT_SOURCE Source 125 ) 126 { 127 if (Source >= mGicNumInterrupts) { 128 ASSERT(FALSE); 129 return EFI_UNSUPPORTED; 130 } 131 132 ArmGicV3EndOfInterrupt (Source); 133 return EFI_SUCCESS; 134 } 135 136 /** 137 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs. 138 139 @param InterruptType Defines the type of interrupt or exception that 140 occurred on the processor.This parameter is processor architecture specific. 141 @param SystemContext A pointer to the processor context when 142 the interrupt occurred on the processor. 143 144 @return None 145 146 **/ 147 VOID 148 EFIAPI 149 GicV3IrqInterruptHandler ( 150 IN EFI_EXCEPTION_TYPE InterruptType, 151 IN EFI_SYSTEM_CONTEXT SystemContext 152 ) 153 { 154 UINT32 GicInterrupt; 155 HARDWARE_INTERRUPT_HANDLER InterruptHandler; 156 157 GicInterrupt = ArmGicV3AcknowledgeInterrupt (); 158 159 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the 160 // number of interrupt (ie: Spurious interrupt). 161 if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) >= mGicNumInterrupts) { 162 // The special interrupt do not need to be acknowledge 163 return; 164 } 165 166 InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt]; 167 if (InterruptHandler != NULL) { 168 // Call the registered interrupt handler. 169 InterruptHandler (GicInterrupt, SystemContext); 170 } else { 171 DEBUG ((EFI_D_ERROR, "Spurious GIC interrupt: 0x%x\n", GicInterrupt)); 172 GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol, GicInterrupt); 173 } 174 } 175 176 // 177 // The protocol instance produced by this driver 178 // 179 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol = { 180 RegisterInterruptSource, 181 GicV3EnableInterruptSource, 182 GicV3DisableInterruptSource, 183 GicV3GetInterruptSourceState, 184 GicV3EndOfInterrupt 185 }; 186 187 /** 188 Shutdown our hardware 189 190 DXE Core will disable interrupts and turn off the timer and disable interrupts 191 after all the event handlers have run. 192 193 @param[in] Event The Event that is being processed 194 @param[in] Context Event Context 195 **/ 196 VOID 197 EFIAPI 198 GicV3ExitBootServicesEvent ( 199 IN EFI_EVENT Event, 200 IN VOID *Context 201 ) 202 { 203 UINTN Index; 204 205 // Acknowledge all pending interrupts 206 for (Index = 0; Index < mGicNumInterrupts; Index++) { 207 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index); 208 } 209 210 for (Index = 0; Index < mGicNumInterrupts; Index++) { 211 GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol, Index); 212 } 213 214 // Disable Gic Interface 215 ArmGicV3DisableInterruptInterface (); 216 217 // Disable Gic Distributor 218 ArmGicDisableDistributor (mGicDistributorBase); 219 } 220 221 /** 222 Initialize the state information for the CPU Architectural Protocol 223 224 @param ImageHandle of the loaded driver 225 @param SystemTable Pointer to the System Table 226 227 @retval EFI_SUCCESS Protocol registered 228 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure 229 @retval EFI_DEVICE_ERROR Hardware problems 230 231 **/ 232 EFI_STATUS 233 GicV3DxeInitialize ( 234 IN EFI_HANDLE ImageHandle, 235 IN EFI_SYSTEM_TABLE *SystemTable 236 ) 237 { 238 EFI_STATUS Status; 239 UINTN Index; 240 UINT32 RegOffset; 241 UINTN RegShift; 242 UINT64 CpuTarget; 243 UINT64 MpId; 244 245 // Make sure the Interrupt Controller Protocol is not already installed in the system. 246 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid); 247 248 mGicDistributorBase = PcdGet64 (PcdGicDistributorBase); 249 mGicRedistributorsBase = PcdGet64 (PcdGicRedistributorsBase); 250 mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase); 251 252 // 253 // We will be driving this GIC in native v3 mode, i.e., with Affinity 254 // Routing enabled. So ensure that the ARE bit is set. 255 // 256 if (!FeaturePcdGet (PcdArmGicV3WithV2Legacy)) { 257 MmioOr32 (mGicDistributorBase + ARM_GIC_ICDDCR, ARM_GIC_ICDDCR_ARE); 258 } 259 260 for (Index = 0; Index < mGicNumInterrupts; Index++) { 261 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index); 262 263 // Set Priority 264 RegOffset = Index / 4; 265 RegShift = (Index % 4) * 8; 266 MmioAndThenOr32 ( 267 mGicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset), 268 ~(0xff << RegShift), 269 ARM_GIC_DEFAULT_PRIORITY << RegShift 270 ); 271 } 272 273 // 274 // Targets the interrupts to the Primary Cpu 275 // 276 277 if (FeaturePcdGet (PcdArmGicV3WithV2Legacy)) { 278 // Only Primary CPU will run this code. We can identify our GIC CPU ID by reading 279 // the GIC Distributor Target register. The 8 first GICD_ITARGETSRn are banked to each 280 // connected CPU. These 8 registers hold the CPU targets fields for interrupts 0-31. 281 // More Info in the GIC Specification about "Interrupt Processor Targets Registers" 282 // 283 // Read the first Interrupt Processor Targets Register (that corresponds to the 4 284 // first SGIs) 285 CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR); 286 287 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface. This value 288 // is 0 when we run on a uniprocessor platform. 289 if (CpuTarget != 0) { 290 // The 8 first Interrupt Processor Targets Registers are read-only 291 for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) { 292 MmioWrite32 (mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4), CpuTarget); 293 } 294 } 295 } else { 296 MpId = ArmReadMpidr (); 297 CpuTarget = MpId & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2 | ARM_CORE_AFF3); 298 299 if ((MmioRead32 (mGicDistributorBase + ARM_GIC_ICDDCR) & ARM_GIC_ICDDCR_DS) != 0) { 300 // 301 // If the Disable Security (DS) control bit is set, we are dealing with a 302 // GIC that has only one security state. In this case, let's assume we are 303 // executing in non-secure state (which is appropriate for DXE modules) 304 // and that no other firmware has performed any configuration on the GIC. 305 // This means we need to reconfigure all interrupts to non-secure Group 1 306 // first. 307 // 308 MmioWrite32 (mGicRedistributorsBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDISR, 0xffffffff); 309 310 for (Index = 32; Index < mGicNumInterrupts; Index += 32) { 311 MmioWrite32 (mGicDistributorBase + ARM_GIC_ICDISR + Index / 8, 0xffffffff); 312 } 313 } 314 315 // Route the SPIs to the primary CPU. SPIs start at the INTID 32 316 for (Index = 0; Index < (mGicNumInterrupts - 32); Index++) { 317 MmioWrite32 (mGicDistributorBase + ARM_GICD_IROUTER + (Index * 8), CpuTarget | ARM_GICD_IROUTER_IRM); 318 } 319 } 320 321 // Set binary point reg to 0x7 (no preemption) 322 ArmGicV3SetBinaryPointer (0x7); 323 324 // Set priority mask reg to 0xff to allow all priorities through 325 ArmGicV3SetPriorityMask (0xff); 326 327 // Enable gic cpu interface 328 ArmGicV3EnableInterruptInterface (); 329 330 // Enable gic distributor 331 ArmGicEnableDistributor (mGicDistributorBase); 332 333 Status = InstallAndRegisterInterruptService ( 334 &gHardwareInterruptV3Protocol, GicV3IrqInterruptHandler, GicV3ExitBootServicesEvent); 335 336 return Status; 337 } 338