/* * This function configures the all interrupts to be Non-secure. * */ VOID EFIAPI ArmGicSetupNonSecure ( IN UINTN MpId, IN INTN GicDistributorBase, IN INTN GicInterruptInterfaceBase ) { UINTN InterruptId; UINTN CachedPriorityMask; UINTN Index; CachedPriorityMask = MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR); // Set priority Mask so that no interrupts get through to CPU MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0); InterruptId = MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIAR); // Only try to clear valid interrupts. Ignore spurious interrupts. while ((InterruptId & 0x3FF) < ArmGicGetMaxNumInterrupts (GicDistributorBase)) { // Some of the SGI's are still pending, read Ack register and send End of Interrupt Signal MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCEIOR, InterruptId); // Next InterruptId = MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIAR); } // Only the primary core should set the Non Secure bit to the SPIs (Shared Peripheral Interrupt). if (ArmPlatformIsPrimaryCore (MpId)) { // Ensure all GIC interrupts are Non-Secure for (Index = 0; Index < (ArmGicGetMaxNumInterrupts (GicDistributorBase) / 32); Index++) { MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISR + (Index * 4), 0xffffffff); } } else { // The secondary cores only set the Non Secure bit to their banked PPIs MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISR, 0xffffffff); } // Ensure all interrupts can get through the priority mask MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR, CachedPriorityMask); }
/* * This function configures the interrupts set by the mask to be secure. * */ VOID EFIAPI ArmGicSetSecureInterrupts ( IN UINTN GicDistributorBase, IN UINTN* GicSecureInterruptMask, IN UINTN GicSecureInterruptMaskSize ) { UINTN Index; UINT32 InterruptStatus; // We must not have more interrupts defined by the mask than the number of available interrupts ASSERT(GicSecureInterruptMaskSize <= (ArmGicGetMaxNumInterrupts (GicDistributorBase) / 32)); // Set all the interrupts defined by the mask as Secure for (Index = 0; Index < GicSecureInterruptMaskSize; Index++) { InterruptStatus = MmioRead32 (GicDistributorBase + ARM_GIC_ICDISR + (Index * 4)); MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISR + (Index * 4), InterruptStatus & (~GicSecureInterruptMask[Index])); } }
/* * This function configures the all interrupts to be Non-secure. * */ VOID EFIAPI ArmGicSetupNonSecure ( IN UINTN MpId, IN INTN GicDistributorBase, IN INTN GicInterruptInterfaceBase ) { UINTN InterruptId; UINTN CachedPriorityMask; UINTN Index; CachedPriorityMask = MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR); // Set priority Mask so that no interrupts get through to CPU MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0); // Check if there are any pending interrupts //TODO: could be extended to take Peripheral interrupts into consideration, but at the moment only SGI's are taken into consideration. while(0 != (MmioRead32 (GicDistributorBase + ARM_GIC_ICDICPR) & 0xF)) { // Some of the SGI's are still pending, read Ack register and send End of Interrupt Signal InterruptId = MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIAR); // Write to End of interrupt signal MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCEIOR, InterruptId); } // Only the primary core should set the Non Secure bit to the SPIs (Shared Peripheral Interrupt). if (IS_PRIMARY_CORE(MpId)) { // Ensure all GIC interrupts are Non-Secure for (Index = 0; Index < (ArmGicGetMaxNumInterrupts (GicDistributorBase) / 32); Index++) { MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISR + (Index * 4), 0xffffffff); } } else { // The secondary cores only set the Non Secure bit to their banked PPIs MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISR, 0xffffffff); } // Ensure all interrupts can get through the priority mask MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR, CachedPriorityMask); }
/** Initialize the state information for the CPU Architectural Protocol @param ImageHandle of the loaded driver @param SystemTable Pointer to the System Table @retval EFI_SUCCESS Protocol registered @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure @retval EFI_DEVICE_ERROR Hardware problems **/ EFI_STATUS GicV2DxeInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINTN Index; UINT32 RegOffset; UINTN RegShift; UINT32 CpuTarget; // Make sure the Interrupt Controller Protocol is not already installed in the system. ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid); mGicInterruptInterfaceBase = PcdGet32 (PcdGicInterruptInterfaceBase); mGicDistributorBase = PcdGet32 (PcdGicDistributorBase); mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase); for (Index = 0; Index < mGicNumInterrupts; Index++) { GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index); // Set Priority RegOffset = Index / 4; RegShift = (Index % 4) * 8; MmioAndThenOr32 ( mGicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset), ~(0xff << RegShift), ARM_GIC_DEFAULT_PRIORITY << RegShift ); } // // Targets the interrupts to the Primary Cpu // // Only Primary CPU will run this code. We can identify our GIC CPU ID by reading // the GIC Distributor Target register. The 8 first GICD_ITARGETSRn are banked to each // connected CPU. These 8 registers hold the CPU targets fields for interrupts 0-31. // More Info in the GIC Specification about "Interrupt Processor Targets Registers" // // Read the first Interrupt Processor Targets Register (that corresponds to the 4 // first SGIs) CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR); // The CPU target is a bit field mapping each CPU to a GIC CPU Interface. This value // is 0 when we run on a uniprocessor platform. if (CpuTarget != 0) { // The 8 first Interrupt Processor Targets Registers are read-only for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) { MmioWrite32 (mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4), CpuTarget); } } // Set binary point reg to 0x7 (no preemption) MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCBPR, 0x7); // Set priority mask reg to 0xff to allow all priorities through MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0xff); // Enable gic cpu interface ArmGicEnableInterruptInterface (mGicInterruptInterfaceBase); // Enable gic distributor ArmGicEnableDistributor (mGicDistributorBase); Status = InstallAndRegisterInterruptService ( &gHardwareInterruptV2Protocol, GicV2IrqInterruptHandler, GicV2ExitBootServicesEvent); return Status; }
/* * This is the main function for secondary cores. They loop around until a non Null value is written to * SYS_FLAGS register.The SYS_FLAGS register is platform specific. * Note:The secondary cores, while executing secondary_main, assumes that: * : SGI 0 is configured as Non-secure interrupt * : Priority Mask is configured to allow SGI 0 * : Interrupt Distributor and CPU interfaces are enabled * */ VOID EFIAPI SecondaryMain ( IN UINTN MpId ) { EFI_STATUS Status; UINTN PpiListSize; UINTN PpiListCount; EFI_PEI_PPI_DESCRIPTOR *PpiList; ARM_MP_CORE_INFO_PPI *ArmMpCoreInfoPpi; UINTN Index; UINTN ArmCoreCount; ARM_CORE_INFO *ArmCoreInfoTable; UINT32 ClusterId; UINT32 CoreId; VOID (*SecondaryStart)(VOID); UINTN SecondaryEntryAddr; UINTN AcknowledgeInterrupt; UINTN InterruptId; ClusterId = GET_CLUSTER_ID(MpId); CoreId = GET_CORE_ID(MpId); // Get the gArmMpCoreInfoPpiGuid PpiListSize = 0; ArmPlatformGetPlatformPpiList (&PpiListSize, &PpiList); PpiListCount = PpiListSize / sizeof(EFI_PEI_PPI_DESCRIPTOR); for (Index = 0; Index < PpiListCount; Index++, PpiList++) { if (CompareGuid (PpiList->Guid, &gArmMpCoreInfoPpiGuid) == TRUE) { break; } } // On MP Core Platform we must implement the ARM MP Core Info PPI ASSERT (Index != PpiListCount); ArmMpCoreInfoPpi = PpiList->Ppi; ArmCoreCount = 0; Status = ArmMpCoreInfoPpi->GetMpCoreInfo (&ArmCoreCount, &ArmCoreInfoTable); ASSERT_EFI_ERROR (Status); // Find the core in the ArmCoreTable for (Index = 0; Index < ArmCoreCount; Index++) { if ((ArmCoreInfoTable[Index].ClusterId == ClusterId) && (ArmCoreInfoTable[Index].CoreId == CoreId)) { break; } } // The ARM Core Info Table must define every core ASSERT (Index != ArmCoreCount); // Clear Secondary cores MailBox MmioWrite32 (ArmCoreInfoTable[Index].MailboxClearAddress, ArmCoreInfoTable[Index].MailboxClearValue); do { ArmCallWFI (); // Read the Mailbox SecondaryEntryAddr = MmioRead32 (ArmCoreInfoTable[Index].MailboxGetAddress); // Acknowledge the interrupt and send End of Interrupt signal. AcknowledgeInterrupt = ArmGicAcknowledgeInterrupt (PcdGet32 (PcdGicInterruptInterfaceBase), &InterruptId); // Check if it is a valid interrupt ID if (InterruptId < ArmGicGetMaxNumInterrupts (PcdGet32 (PcdGicDistributorBase))) { // Got a valid SGI number hence signal End of Interrupt ArmGicEndOfInterrupt (PcdGet32 (PcdGicInterruptInterfaceBase), AcknowledgeInterrupt); } } while (SecondaryEntryAddr == 0); // Jump to secondary core entry point. SecondaryStart = (VOID (*)())SecondaryEntryAddr; SecondaryStart(); // The secondaries shouldn't reach here ASSERT(FALSE); }
/** Initialize the state information for the CPU Architectural Protocol @param ImageHandle of the loaded driver @param SystemTable Pointer to the System Table @retval EFI_SUCCESS Protocol registered @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure @retval EFI_DEVICE_ERROR Hardware problems **/ EFI_STATUS InterruptDxeInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINTN Index; UINT32 RegOffset; UINTN RegShift; EFI_CPU_ARCH_PROTOCOL *Cpu; // Make sure the Interrupt Controller Protocol is not already installed in the system. ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid); mGicNumInterrupts = ArmGicGetMaxNumInterrupts (PcdGet32(PcdGicDistributorBase)); for (Index = 0; Index < mGicNumInterrupts; Index++) { DisableInterruptSource (&gHardwareInterruptProtocol, Index); // Set Priority RegOffset = Index / 4; RegShift = (Index % 4) * 8; MmioAndThenOr32 ( PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDIPR + (4*RegOffset), ~(0xff << RegShift), ARM_GIC_DEFAULT_PRIORITY << RegShift ); } // Configure interrupts for cpu 0 for (Index = 0; Index < (mGicNumInterrupts / 4); Index++) { MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDIPTR + (Index*4), 0x01010101); } // Set binary point reg to 0x7 (no preemption) MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCBPR, 0x7); // Set priority mask reg to 0xff to allow all priorities through MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCPMR, 0xff); // Enable gic cpu interface MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCICR, 0x1); // Enable gic distributor MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDDCR, 0x1); // Initialize the array for the Interrupt Handlers gRegisteredInterruptHandlers = (HARDWARE_INTERRUPT_HANDLER*)AllocateZeroPool (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts); Status = gBS->InstallMultipleProtocolInterfaces ( &gHardwareInterruptHandle, &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol, NULL ); ASSERT_EFI_ERROR (Status); // // Get the CPU protocol that this driver requires. // Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu); ASSERT_EFI_ERROR(Status); // // Unregister the default exception handler. // Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, NULL); ASSERT_EFI_ERROR(Status); // // Register to receive interrupts // Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler); ASSERT_EFI_ERROR(Status); // Register for an ExitBootServicesEvent Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent); ASSERT_EFI_ERROR (Status); return Status; }
/** Initialize the state information for the CPU Architectural Protocol @param ImageHandle of the loaded driver @param SystemTable Pointer to the System Table @retval EFI_SUCCESS Protocol registered @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure @retval EFI_DEVICE_ERROR Hardware problems **/ EFI_STATUS GicV3DxeInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINTN Index; UINT32 RegOffset; UINTN RegShift; UINT64 CpuTarget; UINT64 MpId; // Make sure the Interrupt Controller Protocol is not already installed in the system. ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid); mGicDistributorBase = PcdGet32 (PcdGicDistributorBase); mGicRedistributorsBase = PcdGet32 (PcdGicRedistributorsBase); mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase); // // We will be driving this GIC in native v3 mode, i.e., with Affinity // Routing enabled. So ensure that the ARE bit is set. // if (!FeaturePcdGet (PcdArmGicV3WithV2Legacy)) { MmioOr32 (mGicDistributorBase + ARM_GIC_ICDDCR, ARM_GIC_ICDDCR_ARE); } for (Index = 0; Index < mGicNumInterrupts; Index++) { GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index); // Set Priority RegOffset = Index / 4; RegShift = (Index % 4) * 8; MmioAndThenOr32 ( mGicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset), ~(0xff << RegShift), ARM_GIC_DEFAULT_PRIORITY << RegShift ); } // // Targets the interrupts to the Primary Cpu // if (FeaturePcdGet (PcdArmGicV3WithV2Legacy)) { // Only Primary CPU will run this code. We can identify our GIC CPU ID by reading // the GIC Distributor Target register. The 8 first GICD_ITARGETSRn are banked to each // connected CPU. These 8 registers hold the CPU targets fields for interrupts 0-31. // More Info in the GIC Specification about "Interrupt Processor Targets Registers" // // Read the first Interrupt Processor Targets Register (that corresponds to the 4 // first SGIs) CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR); // The CPU target is a bit field mapping each CPU to a GIC CPU Interface. This value // is 0 when we run on a uniprocessor platform. if (CpuTarget != 0) { // The 8 first Interrupt Processor Targets Registers are read-only for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) { MmioWrite32 (mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4), CpuTarget); } } } else { MpId = ArmReadMpidr (); CpuTarget = MpId & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2 | ARM_CORE_AFF3); if ((MmioRead32 (mGicDistributorBase + ARM_GIC_ICDDCR) & ARM_GIC_ICDDCR_DS) != 0) { // // If the Disable Security (DS) control bit is set, we are dealing with a // GIC that has only one security state. In this case, let's assume we are // executing in non-secure state (which is appropriate for DXE modules) // and that no other firmware has performed any configuration on the GIC. // This means we need to reconfigure all interrupts to non-secure Group 1 // first. // MmioWrite32 (mGicRedistributorsBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDISR, 0xffffffff); for (Index = 32; Index < mGicNumInterrupts; Index += 32) { MmioWrite32 (mGicDistributorBase + ARM_GIC_ICDISR + Index / 8, 0xffffffff); } } // Route the SPIs to the primary CPU. SPIs start at the INTID 32 for (Index = 0; Index < (mGicNumInterrupts - 32); Index++) { MmioWrite32 (mGicDistributorBase + ARM_GICD_IROUTER + (Index * 8), CpuTarget | ARM_GICD_IROUTER_IRM); } } // Set binary point reg to 0x7 (no preemption) ArmGicV3SetBinaryPointer (0x7); // Set priority mask reg to 0xff to allow all priorities through ArmGicV3SetPriorityMask (0xff); // Enable gic cpu interface ArmGicV3EnableInterruptInterface (); // Enable gic distributor ArmGicEnableDistributor (mGicDistributorBase); Status = InstallAndRegisterInterruptService ( &gHardwareInterruptV3Protocol, GicV3IrqInterruptHandler, GicV3ExitBootServicesEvent); return Status; }
/** Initialize the state information for the CPU Architectural Protocol @param ImageHandle of the loaded driver @param SystemTable Pointer to the System Table @retval EFI_SUCCESS Protocol registered @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure @retval EFI_DEVICE_ERROR Hardware problems **/ EFI_STATUS InterruptDxeInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINTN Index; UINT32 RegOffset; UINTN RegShift; EFI_CPU_ARCH_PROTOCOL *Cpu; UINT32 CpuTarget; // Check PcdGicPrimaryCoreId has been set in case the Primary Core is not the core 0 of Cluster 0 DEBUG_CODE_BEGIN(); if ((PcdGet32(PcdArmPrimaryCore) != 0) && (PcdGet32 (PcdGicPrimaryCoreId) == 0)) { DEBUG((EFI_D_WARN,"Warning: the PCD PcdGicPrimaryCoreId does not seem to be set up for the configuration.\n")); } DEBUG_CODE_END(); // Make sure the Interrupt Controller Protocol is not already installed in the system. ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid); mGicNumInterrupts = ArmGicGetMaxNumInterrupts (PcdGet32(PcdGicDistributorBase)); mGicNumInterrupts /=8; for (Index = 0; Index < mGicNumInterrupts; Index++) { (VOID)DisableInterruptSource (&gHardwareInterruptProtocol, Index); // Set Priority RegOffset = Index / 4; RegShift = (Index % 4) * 8; MmioAndThenOr32 ( PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDIPR + (4*RegOffset), ~(UINT32)(0xff << RegShift), ARM_GIC_DEFAULT_PRIORITY << RegShift ); } // Configure interrupts for Primary Cpu CpuTarget = (1 << PcdGet32 (PcdGicPrimaryCoreId)); CpuTarget |= CpuTarget << 16; for (Index = 0; Index < (mGicNumInterrupts / 2); Index++) { MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDIPTR + (Index*4), CpuTarget); } //end_d00183345, 2012-11-17 // Set binary point reg to 0x7 (no preemption) MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCBPR, 0x3); // Set priority mask reg to 0xff to allow all priorities through MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCPMR, 0xff); // Enable gic cpu interface MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCICR, 0x1); // Enable gic distributor MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDDCR, 0x7); MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDISR, ~0); //MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDISR, ~0); // Initialize the array for the Interrupt Handlers gRegisteredInterruptHandlers = (HARDWARE_INTERRUPT_HANDLER*)AllocateZeroPool (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts); Status = gBS->InstallMultipleProtocolInterfaces ( &gHardwareInterruptHandle, &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol, NULL ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { //for fortify return Status; } // // Get the CPU protocol that this driver requires. // Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu); ASSERT_EFI_ERROR(Status); if (EFI_ERROR (Status)) { //for fortify return Status; } // // Unregister the default exception handler. // Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_AARCH64_IRQ, NULL); ASSERT_EFI_ERROR(Status); if (EFI_ERROR (Status)) { //for fortify return Status; } // // Register to receive interrupts // Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_AARCH64_IRQ, IrqInterruptHandler); ASSERT_EFI_ERROR(Status); if (EFI_ERROR (Status)) { //for fortify return Status; } // Register for an ExitBootServicesEvent Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { //for fortify return Status; } return Status; }