/** @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> | |
BOOLEAN mInterruptState = FALSE; | |
/** | |
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_UNSUPPORTEDT 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 (); | |
mInterruptState = TRUE; | |
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 (); | |
mInterruptState = FALSE; | |
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 = mInterruptState; | |
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 | |
4, // DmaBufferAlignment | |
}; | |
EFI_STATUS | |
CpuDxeInitialize ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_EVENT IdleLoopEvent; | |
InitializeExceptions (&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; | |
} |