/** C Interrupt Handler called in the interrupt context when Source interrupt is active. @param Source Source of the interrupt. Hardware routing off a specific platform defines what source means. @param SystemContext Pointer to system register context. Mostly used by debuggers and will update the system context after the return from the interrupt if modified. Don't change these values unless you know what you are doing **/ VOID EFIAPI TimerInterruptHandler ( IN HARDWARE_INTERRUPT_SOURCE Source, IN EFI_SYSTEM_CONTEXT SystemContext ) { EFI_TPL OriginalTPL; // // DXE core uses this callback for the EFI timer tick. The DXE core uses locks // that raise to TPL_HIGH and then restore back to current level. Thus we need // to make sure TPL level is set to TPL_HIGH while we are handling the timer tick. // OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL); // Check if the timer interrupt is active if ((ArmArchTimerGetTimerCtrlReg () ) & ARM_ARCH_TIMER_ISTATUS) { // Signal end of interrupt early to help avoid losing subsequent ticks from long duration handlers gInterrupt->EndOfInterrupt (gInterrupt, Source); if (mTimerNotifyFunction) { mTimerNotifyFunction (mTimerPeriod); } // Reload the Timer TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod)); } // Enable timer interrupts gInterrupt->EnableInterruptSource (gInterrupt, Source); gBS->RestoreTPL (OriginalTPL); }
/** Initialize the state information for the Timer Architectural Protocol and the Timer Debug support protocol that allows the debugger to break into a running program. @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 EFIAPI TimerInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_HANDLE Handle = NULL; EFI_STATUS Status; UINTN TimerCtrlReg; if (ArmIsArchTimerImplemented () == 0) { DEBUG ((EFI_D_ERROR, "ARM Architectural Timer is not available in the CPU, hence cann't use this Driver \n")); ASSERT (0); } // Find the interrupt controller protocol. ASSERT if not found. Status = gBS->LocateProtocol (&gHardwareInterruptProtocolGuid, NULL, (VOID **)&gInterrupt); ASSERT_EFI_ERROR (Status); // Disable the timer TimerCtrlReg = ArmArchTimerGetTimerCtrlReg (); TimerCtrlReg |= ARM_ARCH_TIMER_IMASK; TimerCtrlReg &= ~ARM_ARCH_TIMER_ENABLE; ArmArchTimerSetTimerCtrlReg (TimerCtrlReg); Status = TimerDriverSetTimerPeriod (&gTimer, 0); ASSERT_EFI_ERROR (Status); // Install secure and Non-secure interrupt handlers // Note: Because it is not possible to determine the security state of the // CPU dynamically, we just install interrupt handler for both sec and non-sec // timer PPI Status = gInterrupt->RegisterInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerSecIntrNum), TimerInterruptHandler); ASSERT_EFI_ERROR (Status); Status = gInterrupt->RegisterInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerIntrNum), TimerInterruptHandler); ASSERT_EFI_ERROR (Status); // Set up default timer Status = TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod)); // TIMER_DEFAULT_PERIOD ASSERT_EFI_ERROR (Status); // Install the Timer Architectural Protocol onto a new handle Status = gBS->InstallMultipleProtocolInterfaces( &Handle, &gEfiTimerArchProtocolGuid, &gTimer, NULL ); ASSERT_EFI_ERROR(Status); // Everything is ready, unmask and enable timer interrupts TimerCtrlReg = ARM_ARCH_TIMER_ENABLE; ArmArchTimerSetTimerCtrlReg (TimerCtrlReg); // Register for an ExitBootServicesEvent Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent); ASSERT_EFI_ERROR (Status); return Status; }