| /** @file | |
| Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> | |
| Copyright (c) 2011, ARM Limited. All rights reserved. | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "CpuDxe.h" | |
| #include <Guid/IdleLoopEvent.h> | |
| /** | |
| This function flushes the range of addresses from Start to Start+Length | |
| from the processor's data cache. If Start is not aligned to a cache line | |
| boundary, then the bytes before Start to the preceding cache line boundary | |
| are also flushed. If Start+Length is not aligned to a cache line boundary, | |
| then the bytes past Start+Length to the end of the next cache line boundary | |
| are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be | |
| supported. If the data cache is fully coherent with all DMA operations, then | |
| this function can just return EFI_SUCCESS. If the processor does not support | |
| flushing a range of the data cache, then the entire data cache can be flushed. | |
| @param This The EFI_CPU_ARCH_PROTOCOL instance. | |
| @param Start The beginning physical address to flush from the processor's data | |
| cache. | |
| @param Length The number of bytes to flush from the processor's data cache. This | |
| function may flush more bytes than Length specifies depending upon | |
| the granularity of the flush operation that the processor supports. | |
| @param FlushType Specifies the type of flush operation to perform. | |
| @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from | |
| the processor's data cache. | |
| @retval EFI_UNSUPPORTED The processor does not support the cache flush type specified | |
| by FlushType. | |
| @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed | |
| from the processor's data cache. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| CpuFlushCpuDataCache ( | |
| IN EFI_CPU_ARCH_PROTOCOL *This, | |
| IN EFI_PHYSICAL_ADDRESS Start, | |
| IN UINT64 Length, | |
| IN EFI_CPU_FLUSH_TYPE FlushType | |
| ) | |
| { | |
| switch (FlushType) { | |
| case EfiCpuFlushTypeWriteBack: | |
| WriteBackDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length); | |
| break; | |
| case EfiCpuFlushTypeInvalidate: | |
| InvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length); | |
| break; | |
| case EfiCpuFlushTypeWriteBackInvalidate: | |
| WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length); | |
| break; | |
| default: | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function enables interrupt processing by the processor. | |
| @param This The EFI_CPU_ARCH_PROTOCOL instance. | |
| @retval EFI_SUCCESS Interrupts are enabled on the processor. | |
| @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| CpuEnableInterrupt ( | |
| IN EFI_CPU_ARCH_PROTOCOL *This | |
| ) | |
| { | |
| ArmEnableInterrupts (); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function disables interrupt processing by the processor. | |
| @param This The EFI_CPU_ARCH_PROTOCOL instance. | |
| @retval EFI_SUCCESS Interrupts are disabled on the processor. | |
| @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| CpuDisableInterrupt ( | |
| IN EFI_CPU_ARCH_PROTOCOL *This | |
| ) | |
| { | |
| ArmDisableInterrupts (); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function retrieves the processor's current interrupt state a returns it in | |
| State. If interrupts are currently enabled, then TRUE is returned. If interrupts | |
| are currently disabled, then FALSE is returned. | |
| @param This The EFI_CPU_ARCH_PROTOCOL instance. | |
| @param State A pointer to the processor's current interrupt state. Set to TRUE if | |
| interrupts are enabled and FALSE if interrupts are disabled. | |
| @retval EFI_SUCCESS The processor's current interrupt state was returned in State. | |
| @retval EFI_INVALID_PARAMETER State is NULL. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| CpuGetInterruptState ( | |
| IN EFI_CPU_ARCH_PROTOCOL *This, | |
| OUT BOOLEAN *State | |
| ) | |
| { | |
| if (State == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| *State = ArmGetInterruptState(); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function generates an INIT on the processor. If this function succeeds, then the | |
| processor will be reset, and control will not be returned to the caller. If InitType is | |
| not supported by this processor, or the processor cannot programmatically generate an | |
| INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error | |
| occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned. | |
| @param This The EFI_CPU_ARCH_PROTOCOL instance. | |
| @param InitType The type of processor INIT to perform. | |
| @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen. | |
| @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported | |
| by this processor. | |
| @retval EFI_DEVICE_ERROR The processor INIT failed. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| CpuInit ( | |
| IN EFI_CPU_ARCH_PROTOCOL *This, | |
| IN EFI_CPU_INIT_TYPE InitType | |
| ) | |
| { | |
| return EFI_UNSUPPORTED; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| CpuRegisterInterruptHandler ( | |
| IN EFI_CPU_ARCH_PROTOCOL *This, | |
| IN EFI_EXCEPTION_TYPE InterruptType, | |
| IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler | |
| ) | |
| { | |
| return RegisterInterruptHandler (InterruptType, InterruptHandler); | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| CpuGetTimerValue ( | |
| IN EFI_CPU_ARCH_PROTOCOL *This, | |
| IN UINT32 TimerIndex, | |
| OUT UINT64 *TimerValue, | |
| OUT UINT64 *TimerPeriod OPTIONAL | |
| ) | |
| { | |
| return EFI_UNSUPPORTED; | |
| } | |
| /** | |
| Callback function for idle events. | |
| @param Event Event whose notification function is being invoked. | |
| @param Context The pointer to the notification function's context, | |
| which is implementation-dependent. | |
| **/ | |
| VOID | |
| EFIAPI | |
| IdleLoopEventCallback ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| CpuSleep (); | |
| } | |
| // | |
| // Globals used to initialize the protocol | |
| // | |
| EFI_HANDLE mCpuHandle = NULL; | |
| EFI_CPU_ARCH_PROTOCOL mCpu = { | |
| CpuFlushCpuDataCache, | |
| CpuEnableInterrupt, | |
| CpuDisableInterrupt, | |
| CpuGetInterruptState, | |
| CpuInit, | |
| CpuRegisterInterruptHandler, | |
| CpuGetTimerValue, | |
| CpuSetMemoryAttributes, | |
| 0, // NumberOfTimers | |
| 2048, // DmaBufferAlignment | |
| }; | |
| STATIC | |
| VOID | |
| InitializeDma ( | |
| IN OUT EFI_CPU_ARCH_PROTOCOL *CpuArchProtocol | |
| ) | |
| { | |
| CpuArchProtocol->DmaBufferAlignment = ArmCacheWritebackGranule (); | |
| } | |
| EFI_STATUS | |
| CpuDxeInitialize ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_EVENT IdleLoopEvent; | |
| InitializeExceptions (&mCpu); | |
| InitializeDma (&mCpu); | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &mCpuHandle, | |
| &gEfiCpuArchProtocolGuid, &mCpu, | |
| &gVirtualUncachedPagesProtocolGuid, &gVirtualUncachedPages, | |
| NULL | |
| ); | |
| // | |
| // Make sure GCD and MMU settings match. This API calls gDS->SetMemorySpaceAttributes () | |
| // and that calls EFI_CPU_ARCH_PROTOCOL.SetMemoryAttributes, so this code needs to go | |
| // after the protocol is installed | |
| // | |
| SyncCacheConfig (&mCpu); | |
| // If the platform is a MPCore system then install the Configuration Table describing the | |
| // secondary core states | |
| if (ArmIsMpCore()) { | |
| PublishArmProcessorTable(); | |
| } | |
| // | |
| // Setup a callback for idle events | |
| // | |
| Status = gBS->CreateEventEx ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_NOTIFY, | |
| IdleLoopEventCallback, | |
| NULL, | |
| &gIdleLoopEventGuid, | |
| &IdleLoopEvent | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } |