283 lines
8 KiB
C
283 lines
8 KiB
C
/** @file
|
|
|
|
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
|
|
Copyright (c) 2011, ARM Limited. All rights reserved.
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "CpuDxe.h"
|
|
|
|
#include <Guid/IdleLoopEvent.h>
|
|
|
|
BOOLEAN mIsFlushingGCD;
|
|
|
|
/**
|
|
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,
|
|
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
|
|
//
|
|
mIsFlushingGCD = TRUE;
|
|
SyncCacheConfig (&mCpu);
|
|
mIsFlushingGCD = FALSE;
|
|
|
|
// 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;
|
|
}
|