mirror of https://github.com/acidanthera/audk.git
UefiCpuPkg: Add CpuDxe driver for LoongArch64
Added LoongArch64 CPU driver into CpuDxe. BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4734 Cc: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Chao Li <lichao@loongson.cn> Co-authored-by: Baoqi Zhang <zhangbaoqi@loongson.cn> Co-authored-by: Dongyan Qian <qiandongyan@loongson.cn> Acked-by: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Ray Ni <ray.ni@intel.com>
This commit is contained in:
parent
abaf405ed9
commit
0b2f97c00a
|
@ -3,6 +3,7 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.<BR>
|
# Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.<BR>
|
||||||
# Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
|
# Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
|
||||||
|
# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
#
|
#
|
||||||
|
@ -22,7 +23,7 @@
|
||||||
MdeModulePkg/MdeModulePkg.dec
|
MdeModulePkg/MdeModulePkg.dec
|
||||||
UefiCpuPkg/UefiCpuPkg.dec
|
UefiCpuPkg/UefiCpuPkg.dec
|
||||||
|
|
||||||
[LibraryClasses]
|
[LibraryClasses.common]
|
||||||
BaseLib
|
BaseLib
|
||||||
BaseMemoryLib
|
BaseMemoryLib
|
||||||
CpuExceptionHandlerLib
|
CpuExceptionHandlerLib
|
||||||
|
@ -30,9 +31,7 @@
|
||||||
DebugLib
|
DebugLib
|
||||||
DxeServicesTableLib
|
DxeServicesTableLib
|
||||||
HobLib
|
HobLib
|
||||||
LocalApicLib
|
|
||||||
MemoryAllocationLib
|
MemoryAllocationLib
|
||||||
MtrrLib
|
|
||||||
MpInitLib
|
MpInitLib
|
||||||
PeCoffGetEntryPointLib
|
PeCoffGetEntryPointLib
|
||||||
ReportStatusCodeLib
|
ReportStatusCodeLib
|
||||||
|
@ -41,7 +40,15 @@
|
||||||
UefiDriverEntryPoint
|
UefiDriverEntryPoint
|
||||||
UefiLib
|
UefiLib
|
||||||
|
|
||||||
[Sources]
|
[LibraryClasses.IA32, LibraryClasses.X64]
|
||||||
|
LocalApicLib
|
||||||
|
MtrrLib
|
||||||
|
|
||||||
|
[LibraryClasses.LoongArch64]
|
||||||
|
CacheMaintenanceLib
|
||||||
|
CpuMmuLib
|
||||||
|
|
||||||
|
[Sources.IA32, Sources.X64]
|
||||||
CpuDxe.c
|
CpuDxe.c
|
||||||
CpuDxe.h
|
CpuDxe.h
|
||||||
CpuGdt.c
|
CpuGdt.c
|
||||||
|
@ -59,6 +66,13 @@
|
||||||
X64/CpuAsm.nasm
|
X64/CpuAsm.nasm
|
||||||
X64/PagingAttribute.c
|
X64/PagingAttribute.c
|
||||||
|
|
||||||
|
[Sources.LoongArch64]
|
||||||
|
CpuMp.h
|
||||||
|
LoongArch64/CpuDxe.c
|
||||||
|
LoongArch64/CpuMp.c
|
||||||
|
LoongArch64/Exception.c
|
||||||
|
LoongArch64/CpuDxe.h
|
||||||
|
|
||||||
[Protocols]
|
[Protocols]
|
||||||
gEfiCpuArchProtocolGuid ## PRODUCES
|
gEfiCpuArchProtocolGuid ## PRODUCES
|
||||||
gEfiMpServiceProtocolGuid ## PRODUCES
|
gEfiMpServiceProtocolGuid ## PRODUCES
|
||||||
|
@ -81,6 +95,9 @@
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList ## CONSUMES
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList ## CONSUMES
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize ## CONSUMES
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize ## CONSUMES
|
||||||
|
|
||||||
|
[Pcd.LoongArch64]
|
||||||
|
gUefiCpuPkgTokenSpaceGuid.PcdLoongArchExceptionVectorBaseAddress ## CONSUMES
|
||||||
|
|
||||||
[Depex]
|
[Depex]
|
||||||
TRUE
|
TRUE
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,515 @@
|
||||||
|
/** @file CpuDxe.c
|
||||||
|
|
||||||
|
CPU DXE Module to produce CPU ARCH Protocol.
|
||||||
|
|
||||||
|
Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "CpuDxe.h"
|
||||||
|
#include "CpuMp.h"
|
||||||
|
#include <Guid/IdleLoopEvent.h>
|
||||||
|
#include <Library/CpuMmuLib.h>
|
||||||
|
#include <Library/TimerLib.h>
|
||||||
|
#include <Register/LoongArch64/Csr.h>
|
||||||
|
|
||||||
|
UINT64 mTimerPeriod = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
IPI Interrupt Handler.
|
||||||
|
|
||||||
|
@param InterruptType The type of interrupt that occurred
|
||||||
|
@param SystemContext A pointer to the system context when the interrupt occurred
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
EFIAPI
|
||||||
|
IpiInterruptHandler (
|
||||||
|
IN EFI_EXCEPTION_TYPE InterruptType,
|
||||||
|
IN EFI_SYSTEM_CONTEXT SystemContext
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Globals used to initialize the protocol
|
||||||
|
//
|
||||||
|
EFI_HANDLE mCpuHandle = NULL;
|
||||||
|
EFI_CPU_ARCH_PROTOCOL gCpu = {
|
||||||
|
CpuFlushCpuDataCache,
|
||||||
|
CpuEnableInterrupt,
|
||||||
|
CpuDisableInterrupt,
|
||||||
|
CpuGetInterruptState,
|
||||||
|
CpuInit,
|
||||||
|
CpuRegisterInterruptHandler,
|
||||||
|
CpuGetTimerValue,
|
||||||
|
CpuSetMemoryAttributes,
|
||||||
|
0, // NumberOfTimers
|
||||||
|
4, // DmaBufferAlignment
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
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_INVALID_PARAMETER The processor does not support the cache flush type specified
|
||||||
|
by FlushType.
|
||||||
|
|
||||||
|
**/
|
||||||
|
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
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EnableInterrupts ();
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DisableInterrupts ();
|
||||||
|
|
||||||
|
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 = GetInterruptState ();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Registers a function to be called from the CPU interrupt handler.
|
||||||
|
|
||||||
|
@param This Protocol instance structure
|
||||||
|
@param InterruptType Defines which interrupt to hook. IA-32
|
||||||
|
valid range is 0x00 through 0xFF
|
||||||
|
@param InterruptHandler A pointer to a function of type
|
||||||
|
EFI_CPU_INTERRUPT_HANDLER that is called
|
||||||
|
when a processor interrupt occurs. A null
|
||||||
|
pointer is an error condition.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS If handler installed or uninstalled.
|
||||||
|
@retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler
|
||||||
|
for InterruptType was previously installed.
|
||||||
|
@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for
|
||||||
|
InterruptType was not previously installed.
|
||||||
|
@retval EFI_UNSUPPORTED The interrupt specified by InterruptType
|
||||||
|
is not supported.
|
||||||
|
|
||||||
|
**/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a timer value from one of the CPU's internal timers. There is no
|
||||||
|
inherent time interval between ticks but is a function of the CPU frequency.
|
||||||
|
|
||||||
|
@param This - Protocol instance structure.
|
||||||
|
@param TimerIndex - Specifies which CPU timer is requested.
|
||||||
|
@param TimerValue - Pointer to the returned timer value.
|
||||||
|
@param TimerPeriod - A pointer to the amount of time that passes
|
||||||
|
in femtoseconds (10-15) for each increment
|
||||||
|
of TimerValue. If TimerValue does not
|
||||||
|
increment at a predictable rate, then 0 is
|
||||||
|
returned. The amount of time that has
|
||||||
|
passed between two calls to GetTimerValue()
|
||||||
|
can be calculated with the formula
|
||||||
|
(TimerValue2 - TimerValue1) * TimerPeriod.
|
||||||
|
This parameter is optional and may be NULL.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS - If the CPU timer count was returned.
|
||||||
|
@retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.
|
||||||
|
@retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.
|
||||||
|
@retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
CpuGetTimerValue (
|
||||||
|
IN EFI_CPU_ARCH_PROTOCOL *This,
|
||||||
|
IN UINT32 TimerIndex,
|
||||||
|
OUT UINT64 *TimerValue,
|
||||||
|
OUT UINT64 *TimerPeriod OPTIONAL
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINT64 BeginValue;
|
||||||
|
UINT64 EndValue;
|
||||||
|
|
||||||
|
if (TimerValue == NULL) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TimerIndex != 0) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
*TimerValue = AsmReadStableCounter ();
|
||||||
|
|
||||||
|
if (TimerPeriod != NULL) {
|
||||||
|
if (mTimerPeriod == 0) {
|
||||||
|
//
|
||||||
|
// Read time stamp counter before and after delay of 100 microseconds
|
||||||
|
//
|
||||||
|
BeginValue = AsmReadStableCounter ();
|
||||||
|
MicroSecondDelay (100);
|
||||||
|
EndValue = AsmReadStableCounter ();
|
||||||
|
//
|
||||||
|
// Calculate the actual frequency
|
||||||
|
//
|
||||||
|
mTimerPeriod = DivU64x64Remainder (
|
||||||
|
MultU64x32 (
|
||||||
|
1000 * 1000 * 1000,
|
||||||
|
100
|
||||||
|
),
|
||||||
|
EndValue - BeginValue,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
*TimerPeriod = mTimerPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function modifies the attributes for the memory region specified by BaseAddress and
|
||||||
|
Length from their current attributes to the attributes specified by Attributes.
|
||||||
|
|
||||||
|
@param This The EFI_CPU_ARCH_PROTOCOL instance.
|
||||||
|
@param BaseAddress The physical address that is the start address of a memory region.
|
||||||
|
@param Length The size in bytes of the memory region.
|
||||||
|
@param EfiAttributes The bit mask of attributes to set for the memory region.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The attributes were set for the memory region.
|
||||||
|
@retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
|
||||||
|
BaseAddress and Length cannot be modified.
|
||||||
|
@retval EFI_INVALID_PARAMETER Length is zero.
|
||||||
|
@retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
|
||||||
|
the memory resource range.
|
||||||
|
@retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
|
||||||
|
resource range specified by BaseAddress and Length.
|
||||||
|
The bit mask of attributes is not support for the memory resource
|
||||||
|
range specified by BaseAddress and Length.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
CpuSetMemoryAttributes (
|
||||||
|
IN EFI_CPU_ARCH_PROTOCOL *This,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||||
|
IN UINT64 Length,
|
||||||
|
IN UINT64 EfiAttributes
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
UINTN PageTable;
|
||||||
|
UINT64 PageWalkCfg;
|
||||||
|
|
||||||
|
Status = EFI_SUCCESS;
|
||||||
|
PageTable = CsrRead (LOONGARCH_CSR_PGDL);
|
||||||
|
PageWalkCfg = ((UINT64)CsrRead (LOONGARCH_CSR_PWCTL1)) << 32 | CsrRead (LOONGARCH_CSR_PWCTL0);
|
||||||
|
|
||||||
|
if ((BaseAddress & (EFI_PAGE_SIZE - 1)) != 0) {
|
||||||
|
//
|
||||||
|
// Minimum granularity is SIZE_4KB.
|
||||||
|
//
|
||||||
|
DEBUG ((
|
||||||
|
DEBUG_INFO,
|
||||||
|
"MemoryRegionMap(%lx, %lx, %lx, %lx, %lx): Minimum granularity is SIZE_4KB\n",
|
||||||
|
&PageTable,
|
||||||
|
PageWalkCfg,
|
||||||
|
BaseAddress,
|
||||||
|
Length,
|
||||||
|
EfiAttributes
|
||||||
|
));
|
||||||
|
|
||||||
|
Status = EFI_UNSUPPORTED;
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = MemoryRegionMap (
|
||||||
|
&PageTable,
|
||||||
|
PageWalkCfg,
|
||||||
|
BaseAddress,
|
||||||
|
Length,
|
||||||
|
EfiAttributes,
|
||||||
|
0x0
|
||||||
|
);
|
||||||
|
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
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 ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Refreshes the GCD Memory Space attributes according to Default Config
|
||||||
|
|
||||||
|
This function refreshes the GCD Memory Space attributes according to DefaultConfig
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Refresh GCD success.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
RefreshGcdMemoryAttributes (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
UINT32 Index;
|
||||||
|
UINTN NumberOfDescriptors;
|
||||||
|
EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
|
||||||
|
|
||||||
|
DEBUG ((DEBUG_PAGE, "RefreshGcdMemoryAttributes()\n"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get the memory space map from GCD
|
||||||
|
//
|
||||||
|
MemorySpaceMap = NULL;
|
||||||
|
Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
|
||||||
|
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
DEBUG ((
|
||||||
|
DEBUG_ERROR,
|
||||||
|
"RefreshGcdMemoryAttributes - GetMemorySpaceMap() failed! Status: %r\n",
|
||||||
|
Status
|
||||||
|
));
|
||||||
|
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( Index = 0; Index < NumberOfDescriptors; Index++ ) {
|
||||||
|
//
|
||||||
|
// If this is system memory, not a class resource like MMIO, and the capability
|
||||||
|
// contains a Memory cacheability attributes and the attribute feature is set
|
||||||
|
// to 0, we will set its attribute to the WriteBack memory of the LoongArch
|
||||||
|
// architecture for the first time.
|
||||||
|
//
|
||||||
|
if (((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) &&
|
||||||
|
MemorySpaceMap[Index].Capabilities & EFI_CACHE_ATTRIBUTE_MASK) &&
|
||||||
|
(MemorySpaceMap[Index].Attributes == 0))
|
||||||
|
{
|
||||||
|
if (!(MemorySpaceMap[Index].Capabilities & EFI_MEMORY_WB)) {
|
||||||
|
DEBUG ((
|
||||||
|
DEBUG_WARN,
|
||||||
|
"RefreshGcdMemoryAttributes - SystemMemory Capabilities should support EFI_MEMORY_WB ! \n"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Refresh or Sync Gcd's memory attributes according to Default Paging (CACHE_CC)
|
||||||
|
//
|
||||||
|
gDS->SetMemorySpaceAttributes (
|
||||||
|
MemorySpaceMap[Index].BaseAddress,
|
||||||
|
MemorySpaceMap[Index].Length,
|
||||||
|
(MemorySpaceMap[Index].Attributes & ~EFI_CACHE_ATTRIBUTE_MASK) |
|
||||||
|
(MemorySpaceMap[Index].Capabilities & EFI_MEMORY_WB)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initialize the state information for the CPU Architectural Protocol.
|
||||||
|
|
||||||
|
@param ImageHandle Image handle this driver.
|
||||||
|
@param SystemTable Pointer to the System Table.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Thread can be successfully created
|
||||||
|
@retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
|
||||||
|
@retval EFI_DEVICE_ERROR Cannot create the thread
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
InitializeCpu (
|
||||||
|
IN EFI_HANDLE ImageHandle,
|
||||||
|
IN EFI_SYSTEM_TABLE *SystemTable
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EFI_EVENT IdleLoopEvent;
|
||||||
|
|
||||||
|
InitializeExceptions (&gCpu);
|
||||||
|
|
||||||
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||||
|
&mCpuHandle,
|
||||||
|
&gEfiCpuArchProtocolGuid,
|
||||||
|
&gCpu,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Refresh GCD memory space map according to Default Paging.
|
||||||
|
//
|
||||||
|
RefreshGcdMemoryAttributes ();
|
||||||
|
|
||||||
|
Status = gCpu.RegisterInterruptHandler (
|
||||||
|
&gCpu,
|
||||||
|
EXCEPT_LOONGARCH_INT_IPI,
|
||||||
|
IpiInterruptHandler
|
||||||
|
);
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Setup a callback for idle events
|
||||||
|
//
|
||||||
|
Status = gBS->CreateEventEx (
|
||||||
|
EVT_NOTIFY_SIGNAL,
|
||||||
|
TPL_NOTIFY,
|
||||||
|
IdleLoopEventCallback,
|
||||||
|
NULL,
|
||||||
|
&gIdleLoopEventGuid,
|
||||||
|
&IdleLoopEvent
|
||||||
|
);
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
|
||||||
|
InitializeMpSupport ();
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
|
@ -0,0 +1,288 @@
|
||||||
|
/** @file CpuDxe.c
|
||||||
|
|
||||||
|
CPU DXE Module to produce CPU ARCH Protocol.
|
||||||
|
|
||||||
|
Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef CPU_DXE_H_
|
||||||
|
#define CPU_DXE_H_
|
||||||
|
|
||||||
|
#include <Uefi.h>
|
||||||
|
#include <Library/BaseMemoryLib.h>
|
||||||
|
#include <Library/CacheMaintenanceLib.h>
|
||||||
|
#include <Library/CpuLib.h>
|
||||||
|
#include <Library/DebugLib.h>
|
||||||
|
#include <Library/DxeServicesTableLib.h>
|
||||||
|
#include <Library/MpInitLib.h>
|
||||||
|
#include <Library/PcdLib.h>
|
||||||
|
#include <Library/PeCoffGetEntryPointLib.h>
|
||||||
|
#include <Library/UefiBootServicesTableLib.h>
|
||||||
|
#include <Library/UefiLib.h>
|
||||||
|
|
||||||
|
#include <Guid/DebugImageInfoTable.h>
|
||||||
|
#include <Protocol/Cpu.h>
|
||||||
|
#include <Protocol/DebugSupport.h>
|
||||||
|
#include <Protocol/LoadedImage.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// For coding convenience, define the maximum valid
|
||||||
|
// LoongArch exception.
|
||||||
|
// Since UEFI V2.11, it will be present in DebugSupport.h.
|
||||||
|
//
|
||||||
|
#define MAX_LOONGARCH_EXCEPTION 64
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Registers a function to be called from the CPU interrupt handler.
|
||||||
|
|
||||||
|
@param This Protocol instance structure
|
||||||
|
@param InterruptType Defines which interrupt to hook. IA-32
|
||||||
|
valid range is 0x00 through 0xFF
|
||||||
|
@param InterruptHandler A pointer to a function of type
|
||||||
|
EFI_CPU_INTERRUPT_HANDLER that is called
|
||||||
|
when a processor interrupt occurs. A null
|
||||||
|
pointer is an error condition.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS If handler installed or uninstalled.
|
||||||
|
@retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler
|
||||||
|
for InterruptType was previously installed.
|
||||||
|
@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for
|
||||||
|
InterruptType was not previously installed.
|
||||||
|
@retval EFI_UNSUPPORTED The interrupt specified by InterruptType
|
||||||
|
is not supported.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
CpuRegisterInterruptHandler (
|
||||||
|
IN EFI_CPU_ARCH_PROTOCOL *This,
|
||||||
|
IN EFI_EXCEPTION_TYPE InterruptType,
|
||||||
|
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a timer value from one of the CPU's internal timers. There is no
|
||||||
|
inherent time interval between ticks but is a function of the CPU frequency.
|
||||||
|
|
||||||
|
@param This - Protocol instance structure.
|
||||||
|
@param TimerIndex - Specifies which CPU timer is requested.
|
||||||
|
@param TimerValue - Pointer to the returned timer value.
|
||||||
|
@param TimerPeriod - A pointer to the amount of time that passes
|
||||||
|
in femtoseconds (10-15) for each increment
|
||||||
|
of TimerValue. If TimerValue does not
|
||||||
|
increment at a predictable rate, then 0 is
|
||||||
|
returned. The amount of time that has
|
||||||
|
passed between two calls to GetTimerValue()
|
||||||
|
can be calculated with the formula
|
||||||
|
(TimerValue2 - TimerValue1) * TimerPeriod.
|
||||||
|
This parameter is optional and may be NULL.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS - If the CPU timer count was returned.
|
||||||
|
@retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.
|
||||||
|
@retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.
|
||||||
|
@retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
CpuGetTimerValue (
|
||||||
|
IN EFI_CPU_ARCH_PROTOCOL *This,
|
||||||
|
IN UINT32 TimerIndex,
|
||||||
|
OUT UINT64 *TimerValue,
|
||||||
|
OUT UINT64 *TimerPeriod OPTIONAL
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function registers and enables the handler specified by InterruptHandler for a processor
|
||||||
|
interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
|
||||||
|
handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
|
||||||
|
The installed handler is called once for each processor interrupt or exception.
|
||||||
|
|
||||||
|
@param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
|
||||||
|
are enabled and FALSE if interrupts are disabled.
|
||||||
|
@param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
|
||||||
|
when a processor interrupt occurs. If this parameter is NULL, then the handler
|
||||||
|
will be uninstalled.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
|
||||||
|
@retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
|
||||||
|
previously installed.
|
||||||
|
@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
|
||||||
|
previously installed.
|
||||||
|
@retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
RegisterInterruptHandler (
|
||||||
|
IN EFI_EXCEPTION_TYPE InterruptType,
|
||||||
|
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function modifies the attributes for the memory region specified by BaseAddress and
|
||||||
|
Length from their current attributes to the attributes specified by Attributes.
|
||||||
|
|
||||||
|
@param This The EFI_CPU_ARCH_PROTOCOL instance.
|
||||||
|
@param BaseAddress The physical address that is the start address of a memory region.
|
||||||
|
@param Length The size in bytes of the memory region.
|
||||||
|
@param Attributes The bit mask of attributes to set for the memory region.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The attributes were set for the memory region.
|
||||||
|
@retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
|
||||||
|
BaseAddress and Length cannot be modified.
|
||||||
|
@retval EFI_INVALID_PARAMETER Length is zero.
|
||||||
|
@retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
|
||||||
|
the memory resource range.
|
||||||
|
@retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
|
||||||
|
resource range specified by BaseAddress and Length.
|
||||||
|
The bit mask of attributes is not support for the memory resource
|
||||||
|
range specified by BaseAddress and Length.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
CpuSetMemoryAttributes (
|
||||||
|
IN EFI_CPU_ARCH_PROTOCOL *This,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||||
|
IN UINT64 Length,
|
||||||
|
IN UINT64 Attributes
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initialize interrupt handling for DXE phase.
|
||||||
|
|
||||||
|
@param Cpu A pointer of EFI_CPU_ARCH_PROTOCOL instance.
|
||||||
|
|
||||||
|
@return VOID.
|
||||||
|
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
InitializeExceptions (
|
||||||
|
IN EFI_CPU_ARCH_PROTOCOL *gCpu
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Converts EFI Attributes to corresponding architecture Attributes.
|
||||||
|
|
||||||
|
@param[in] EfiAttributes Efi Attributes.
|
||||||
|
|
||||||
|
@retval Corresponding architecture attributes.
|
||||||
|
**/
|
||||||
|
UINTN
|
||||||
|
EFIAPI
|
||||||
|
EfiAttributeConverse (
|
||||||
|
IN UINTN EfiAttributes
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // CPU_DXE_H_
|
|
@ -0,0 +1,544 @@
|
||||||
|
/** @file
|
||||||
|
CPU DXE Module to produce CPU MP Protocol.
|
||||||
|
|
||||||
|
Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "CpuDxe.h"
|
||||||
|
#include "CpuMp.h"
|
||||||
|
|
||||||
|
EFI_HANDLE mMpServiceHandle = NULL;
|
||||||
|
UINTN mNumberOfProcessors = 1;
|
||||||
|
|
||||||
|
EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = {
|
||||||
|
GetNumberOfProcessors,
|
||||||
|
GetProcessorInfo,
|
||||||
|
StartupAllAPs,
|
||||||
|
StartupThisAP,
|
||||||
|
SwitchBSP,
|
||||||
|
EnableDisableAP,
|
||||||
|
WhoAmI
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
This service retrieves the number of logical processor in the platform
|
||||||
|
and the number of those logical processors that are enabled on this boot.
|
||||||
|
This service may only be called from the BSP.
|
||||||
|
|
||||||
|
This function is used to retrieve the following information:
|
||||||
|
- The number of logical processors that are present in the system.
|
||||||
|
- The number of enabled logical processors in the system at the instant
|
||||||
|
this call is made.
|
||||||
|
|
||||||
|
Because MP Service Protocol provides services to enable and disable processors
|
||||||
|
dynamically, the number of enabled logical processors may vary during the
|
||||||
|
course of a boot session.
|
||||||
|
|
||||||
|
If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
|
||||||
|
If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
|
||||||
|
EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
|
||||||
|
is returned in NumberOfProcessors, the number of currently enabled processor
|
||||||
|
is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
|
||||||
|
|
||||||
|
@param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
|
||||||
|
instance.
|
||||||
|
@param[out] NumberOfProcessors Pointer to the total number of logical
|
||||||
|
processors in the system, including the BSP
|
||||||
|
and disabled APs.
|
||||||
|
@param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
|
||||||
|
processors that exist in system, including
|
||||||
|
the BSP.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The number of logical processors and enabled
|
||||||
|
logical processors was retrieved.
|
||||||
|
@retval EFI_DEVICE_ERROR The calling processor is an AP.
|
||||||
|
@retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
|
||||||
|
@retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
GetNumberOfProcessors (
|
||||||
|
IN EFI_MP_SERVICES_PROTOCOL *This,
|
||||||
|
OUT UINTN *NumberOfProcessors,
|
||||||
|
OUT UINTN *NumberOfEnabledProcessors
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MpInitLibGetNumberOfProcessors (
|
||||||
|
NumberOfProcessors,
|
||||||
|
NumberOfEnabledProcessors
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Gets detailed MP-related information on the requested processor at the
|
||||||
|
instant this call is made. This service may only be called from the BSP.
|
||||||
|
|
||||||
|
This service retrieves detailed MP-related information about any processor
|
||||||
|
on the platform. Note the following:
|
||||||
|
- The processor information may change during the course of a boot session.
|
||||||
|
- The information presented here is entirely MP related.
|
||||||
|
|
||||||
|
Information regarding the number of caches and their sizes, frequency of operation,
|
||||||
|
slot numbers is all considered platform-related information and is not provided
|
||||||
|
by this service.
|
||||||
|
|
||||||
|
@param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
|
||||||
|
instance.
|
||||||
|
@param[in] ProcessorNumber The handle number of processor.
|
||||||
|
@param[out] ProcessorInfoBuffer A pointer to the buffer where information for
|
||||||
|
the requested processor is deposited.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Processor information was returned.
|
||||||
|
@retval EFI_DEVICE_ERROR The calling processor is an AP.
|
||||||
|
@retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
|
||||||
|
@retval EFI_NOT_FOUND The processor with the handle specified by
|
||||||
|
ProcessorNumber does not exist in the platform.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
GetProcessorInfo (
|
||||||
|
IN EFI_MP_SERVICES_PROTOCOL *This,
|
||||||
|
IN UINTN ProcessorNumber,
|
||||||
|
OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return MpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This service executes a caller provided function on all enabled APs. APs can
|
||||||
|
run either simultaneously or one at a time in sequence. This service supports
|
||||||
|
both blocking and non-blocking requests. The non-blocking requests use EFI
|
||||||
|
events so the BSP can detect when the APs have finished. This service may only
|
||||||
|
be called from the BSP.
|
||||||
|
|
||||||
|
This function is used to dispatch all the enabled APs to the function specified
|
||||||
|
by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
|
||||||
|
immediately and Procedure is not started on any AP.
|
||||||
|
|
||||||
|
If SingleThread is TRUE, all the enabled APs execute the function specified by
|
||||||
|
Procedure one by one, in ascending order of processor handle number. Otherwise,
|
||||||
|
all the enabled APs execute the function specified by Procedure simultaneously.
|
||||||
|
|
||||||
|
If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
|
||||||
|
APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in non-blocking
|
||||||
|
mode, and the BSP returns from this service without waiting for APs. If a
|
||||||
|
non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
|
||||||
|
is signaled, then EFI_UNSUPPORTED must be returned.
|
||||||
|
|
||||||
|
If the timeout specified by TimeoutInMicroseconds expires before all APs return
|
||||||
|
from Procedure, then Procedure on the failed APs is terminated. All enabled APs
|
||||||
|
are always available for further calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
|
||||||
|
and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
|
||||||
|
content points to the list of processor handle numbers in which Procedure was
|
||||||
|
terminated.
|
||||||
|
|
||||||
|
Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
|
||||||
|
to make sure that the nature of the code that is executed on the BSP and the
|
||||||
|
dispatched APs is well controlled. The MP Services Protocol does not guarantee
|
||||||
|
that the Procedure function is MP-safe. Hence, the tasks that can be run in
|
||||||
|
parallel are limited to certain independent tasks and well-controlled exclusive
|
||||||
|
code. EFI services and protocols may not be called by APs unless otherwise
|
||||||
|
specified.
|
||||||
|
|
||||||
|
In blocking execution mode, BSP waits until all APs finish or
|
||||||
|
TimeoutInMicroseconds expires.
|
||||||
|
|
||||||
|
In non-blocking execution mode, BSP is freed to return to the caller and then
|
||||||
|
proceed to the next task without having to wait for APs. The following
|
||||||
|
sequence needs to occur in a non-blocking execution mode:
|
||||||
|
|
||||||
|
-# The caller that intends to use this MP Services Protocol in non-blocking
|
||||||
|
mode creates WaitEvent by calling the EFI CreateEvent() service. The caller
|
||||||
|
invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter WaitEvent
|
||||||
|
is not NULL, then StartupAllAPs() executes in non-blocking mode. It requests
|
||||||
|
the function specified by Procedure to be started on all the enabled APs,
|
||||||
|
and releases the BSP to continue with other tasks.
|
||||||
|
-# The caller can use the CheckEvent() and WaitForEvent() services to check
|
||||||
|
the state of the WaitEvent created in step 1.
|
||||||
|
-# When the APs complete their task or TimeoutInMicroSecondss expires, the MP
|
||||||
|
Service signals WaitEvent by calling the EFI SignalEvent() function. If
|
||||||
|
FailedCpuList is not NULL, its content is available when WaitEvent is
|
||||||
|
signaled. If all APs returned from Procedure prior to the timeout, then
|
||||||
|
FailedCpuList is set to NULL. If not all APs return from Procedure before
|
||||||
|
the timeout, then FailedCpuList is filled in with the list of the failed
|
||||||
|
APs. The buffer is allocated by MP Service Protocol using AllocatePool().
|
||||||
|
It is the caller's responsibility to free the buffer with FreePool() service.
|
||||||
|
-# This invocation of SignalEvent() function informs the caller that invoked
|
||||||
|
EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs completed
|
||||||
|
the specified task or a timeout occurred. The contents of FailedCpuList
|
||||||
|
can be examined to determine which APs did not complete the specified task
|
||||||
|
prior to the timeout.
|
||||||
|
|
||||||
|
@param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
|
||||||
|
instance.
|
||||||
|
@param[in] Procedure A pointer to the function to be run on
|
||||||
|
enabled APs of the system. See type
|
||||||
|
EFI_AP_PROCEDURE.
|
||||||
|
@param[in] SingleThread If TRUE, then all the enabled APs execute
|
||||||
|
the function specified by Procedure one by
|
||||||
|
one, in ascending order of processor handle
|
||||||
|
number. If FALSE, then all the enabled APs
|
||||||
|
execute the function specified by Procedure
|
||||||
|
simultaneously.
|
||||||
|
@param[in] WaitEvent The event created by the caller with CreateEvent()
|
||||||
|
service. If it is NULL, then execute in
|
||||||
|
blocking mode. BSP waits until all APs finish
|
||||||
|
or TimeoutInMicroseconds expires. If it's
|
||||||
|
not NULL, then execute in non-blocking mode.
|
||||||
|
BSP requests the function specified by
|
||||||
|
Procedure to be started on all the enabled
|
||||||
|
APs, and go on executing immediately. If
|
||||||
|
all return from Procedure, or TimeoutInMicroseconds
|
||||||
|
expires, this event is signaled. The BSP
|
||||||
|
can use the CheckEvent() or WaitForEvent()
|
||||||
|
services to check the state of event. Type
|
||||||
|
EFI_EVENT is defined in CreateEvent() in
|
||||||
|
the Unified Extensible Firmware Interface
|
||||||
|
Specification.
|
||||||
|
@param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
|
||||||
|
APs to return from Procedure, either for
|
||||||
|
blocking or non-blocking mode. Zero means
|
||||||
|
infinity. If the timeout expires before
|
||||||
|
all APs return from Procedure, then Procedure
|
||||||
|
on the failed APs is terminated. All enabled
|
||||||
|
APs are available for next function assigned
|
||||||
|
by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
|
||||||
|
or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
|
||||||
|
If the timeout expires in blocking mode,
|
||||||
|
BSP returns EFI_TIMEOUT. If the timeout
|
||||||
|
expires in non-blocking mode, WaitEvent
|
||||||
|
is signaled with SignalEvent().
|
||||||
|
@param[in] ProcedureArgument The parameter passed into Procedure for
|
||||||
|
all APs.
|
||||||
|
@param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
|
||||||
|
if all APs finish successfully, then its
|
||||||
|
content is set to NULL. If not all APs
|
||||||
|
finish before timeout expires, then its
|
||||||
|
content is set to address of the buffer
|
||||||
|
holding handle numbers of the failed APs.
|
||||||
|
The buffer is allocated by MP Service Protocol,
|
||||||
|
and it's the caller's responsibility to
|
||||||
|
free the buffer with FreePool() service.
|
||||||
|
In blocking mode, it is ready for consumption
|
||||||
|
when the call returns. In non-blocking mode,
|
||||||
|
it is ready when WaitEvent is signaled. The
|
||||||
|
list of failed CPU is terminated by
|
||||||
|
END_OF_CPU_LIST.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS In blocking mode, all APs have finished before
|
||||||
|
the timeout expired.
|
||||||
|
@retval EFI_SUCCESS In non-blocking mode, function has been dispatched
|
||||||
|
to all enabled APs.
|
||||||
|
@retval EFI_UNSUPPORTED A non-blocking mode request was made after the
|
||||||
|
UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
|
||||||
|
signaled.
|
||||||
|
@retval EFI_DEVICE_ERROR Caller processor is AP.
|
||||||
|
@retval EFI_NOT_STARTED No enabled APs exist in the system.
|
||||||
|
@retval EFI_NOT_READY Any enabled APs are busy.
|
||||||
|
@retval EFI_TIMEOUT In blocking mode, the timeout expired before
|
||||||
|
all enabled APs have finished.
|
||||||
|
@retval EFI_INVALID_PARAMETER Procedure is NULL.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
StartupAllAPs (
|
||||||
|
IN EFI_MP_SERVICES_PROTOCOL *This,
|
||||||
|
IN EFI_AP_PROCEDURE Procedure,
|
||||||
|
IN BOOLEAN SingleThread,
|
||||||
|
IN EFI_EVENT WaitEvent OPTIONAL,
|
||||||
|
IN UINTN TimeoutInMicroseconds,
|
||||||
|
IN VOID *ProcedureArgument OPTIONAL,
|
||||||
|
OUT UINTN **FailedCpuList OPTIONAL
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return MpInitLibStartupAllAPs (
|
||||||
|
Procedure,
|
||||||
|
SingleThread,
|
||||||
|
WaitEvent,
|
||||||
|
TimeoutInMicroseconds,
|
||||||
|
ProcedureArgument,
|
||||||
|
FailedCpuList
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This service lets the caller get one enabled AP to execute a caller-provided
|
||||||
|
function. The caller can request the BSP to either wait for the completion
|
||||||
|
of the AP or just proceed with the next task by using the EFI event mechanism.
|
||||||
|
See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
|
||||||
|
execution support. This service may only be called from the BSP.
|
||||||
|
|
||||||
|
This function is used to dispatch one enabled AP to the function specified by
|
||||||
|
Procedure passing in the argument specified by ProcedureArgument. If WaitEvent
|
||||||
|
is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
|
||||||
|
TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
|
||||||
|
BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
|
||||||
|
is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
|
||||||
|
then EFI_UNSUPPORTED must be returned.
|
||||||
|
|
||||||
|
If the timeout specified by TimeoutInMicroseconds expires before the AP returns
|
||||||
|
from Procedure, then execution of Procedure by the AP is terminated. The AP is
|
||||||
|
available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
|
||||||
|
EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
|
||||||
|
|
||||||
|
@param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
|
||||||
|
instance.
|
||||||
|
@param[in] Procedure A pointer to the function to be run on the
|
||||||
|
designated AP of the system. See type
|
||||||
|
EFI_AP_PROCEDURE.
|
||||||
|
@param[in] ProcessorNumber The handle number of the AP. The range is
|
||||||
|
from 0 to the total number of logical
|
||||||
|
processors minus 1. The total number of
|
||||||
|
logical processors can be retrieved by
|
||||||
|
EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
|
||||||
|
@param[in] WaitEvent The event created by the caller with CreateEvent()
|
||||||
|
service. If it is NULL, then execute in
|
||||||
|
blocking mode. BSP waits until this AP finish
|
||||||
|
or TimeoutInMicroSeconds expires. If it's
|
||||||
|
not NULL, then execute in non-blocking mode.
|
||||||
|
BSP requests the function specified by
|
||||||
|
Procedure to be started on this AP,
|
||||||
|
and go on executing immediately. If this AP
|
||||||
|
return from Procedure or TimeoutInMicroSeconds
|
||||||
|
expires, this event is signaled. The BSP
|
||||||
|
can use the CheckEvent() or WaitForEvent()
|
||||||
|
services to check the state of event. Type
|
||||||
|
EFI_EVENT is defined in CreateEvent() in
|
||||||
|
the Unified Extensible Firmware Interface
|
||||||
|
Specification.
|
||||||
|
@param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
|
||||||
|
this AP to finish this Procedure, either for
|
||||||
|
blocking or non-blocking mode. Zero means
|
||||||
|
infinity. If the timeout expires before
|
||||||
|
this AP returns from Procedure, then Procedure
|
||||||
|
on the AP is terminated. The
|
||||||
|
AP is available for next function assigned
|
||||||
|
by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
|
||||||
|
or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
|
||||||
|
If the timeout expires in blocking mode,
|
||||||
|
BSP returns EFI_TIMEOUT. If the timeout
|
||||||
|
expires in non-blocking mode, WaitEvent
|
||||||
|
is signaled with SignalEvent().
|
||||||
|
@param[in] ProcedureArgument The parameter passed into Procedure on the
|
||||||
|
specified AP.
|
||||||
|
@param[out] Finished If NULL, this parameter is ignored. In
|
||||||
|
blocking mode, this parameter is ignored.
|
||||||
|
In non-blocking mode, if AP returns from
|
||||||
|
Procedure before the timeout expires, its
|
||||||
|
content is set to TRUE. Otherwise, the
|
||||||
|
value is set to FALSE. The caller can
|
||||||
|
determine if the AP returned from Procedure
|
||||||
|
by evaluating this value.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS In blocking mode, specified AP finished before
|
||||||
|
the timeout expires.
|
||||||
|
@retval EFI_SUCCESS In non-blocking mode, the function has been
|
||||||
|
dispatched to specified AP.
|
||||||
|
@retval EFI_UNSUPPORTED A non-blocking mode request was made after the
|
||||||
|
UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
|
||||||
|
signaled.
|
||||||
|
@retval EFI_DEVICE_ERROR The calling processor is an AP.
|
||||||
|
@retval EFI_TIMEOUT In blocking mode, the timeout expired before
|
||||||
|
the specified AP has finished.
|
||||||
|
@retval EFI_NOT_READY The specified AP is busy.
|
||||||
|
@retval EFI_NOT_FOUND The processor with the handle specified by
|
||||||
|
ProcessorNumber does not exist.
|
||||||
|
@retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
|
||||||
|
@retval EFI_INVALID_PARAMETER Procedure is NULL.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
StartupThisAP (
|
||||||
|
IN EFI_MP_SERVICES_PROTOCOL *This,
|
||||||
|
IN EFI_AP_PROCEDURE Procedure,
|
||||||
|
IN UINTN ProcessorNumber,
|
||||||
|
IN EFI_EVENT WaitEvent OPTIONAL,
|
||||||
|
IN UINTN TimeoutInMicroseconds,
|
||||||
|
IN VOID *ProcedureArgument OPTIONAL,
|
||||||
|
OUT BOOLEAN *Finished OPTIONAL
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return MpInitLibStartupThisAP (
|
||||||
|
Procedure,
|
||||||
|
ProcessorNumber,
|
||||||
|
WaitEvent,
|
||||||
|
TimeoutInMicroseconds,
|
||||||
|
ProcedureArgument,
|
||||||
|
Finished
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This service switches the requested AP to be the BSP from that point onward.
|
||||||
|
This service changes the BSP for all purposes. This call can only be performed
|
||||||
|
by the current BSP.
|
||||||
|
|
||||||
|
This service switches the requested AP to be the BSP from that point onward.
|
||||||
|
This service changes the BSP for all purposes. The new BSP can take over the
|
||||||
|
execution of the old BSP and continue seamlessly from where the old one left
|
||||||
|
off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
|
||||||
|
is signaled.
|
||||||
|
|
||||||
|
If the BSP cannot be switched prior to the return from this service, then
|
||||||
|
EFI_UNSUPPORTED must be returned.
|
||||||
|
|
||||||
|
@param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
|
||||||
|
@param[in] ProcessorNumber The handle number of AP that is to become the new
|
||||||
|
BSP. The range is from 0 to the total number of
|
||||||
|
logical processors minus 1. The total number of
|
||||||
|
logical processors can be retrieved by
|
||||||
|
EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
|
||||||
|
@param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
|
||||||
|
enabled AP. Otherwise, it will be disabled.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS BSP successfully switched.
|
||||||
|
@retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
|
||||||
|
this service returning.
|
||||||
|
@retval EFI_UNSUPPORTED Switching the BSP is not supported.
|
||||||
|
@retval EFI_DEVICE_ERROR The calling processor is an AP.
|
||||||
|
@retval EFI_NOT_FOUND The processor with the handle specified by
|
||||||
|
ProcessorNumber does not exist.
|
||||||
|
@retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
|
||||||
|
a disabled AP.
|
||||||
|
@retval EFI_NOT_READY The specified AP is busy.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
SwitchBSP (
|
||||||
|
IN EFI_MP_SERVICES_PROTOCOL *This,
|
||||||
|
IN UINTN ProcessorNumber,
|
||||||
|
IN BOOLEAN EnableOldBSP
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return MpInitLibSwitchBSP (ProcessorNumber, EnableOldBSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This service lets the caller enable or disable an AP from this point onward.
|
||||||
|
This service may only be called from the BSP.
|
||||||
|
|
||||||
|
This service allows the caller enable or disable an AP from this point onward.
|
||||||
|
The caller can optionally specify the health status of the AP by Health. If
|
||||||
|
an AP is being disabled, then the state of the disabled AP is implementation
|
||||||
|
dependent. If an AP is enabled, then the implementation must guarantee that a
|
||||||
|
complete initialization sequence is performed on the AP, so the AP is in a state
|
||||||
|
that is compatible with an MP operating system. This service may not be supported
|
||||||
|
after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
|
||||||
|
|
||||||
|
If the enable or disable AP operation cannot be completed prior to the return
|
||||||
|
from this service, then EFI_UNSUPPORTED must be returned.
|
||||||
|
|
||||||
|
@param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
|
||||||
|
@param[in] ProcessorNumber The handle number of AP.
|
||||||
|
The range is from 0 to the total number of
|
||||||
|
logical processors minus 1. The total number of
|
||||||
|
logical processors can be retrieved by
|
||||||
|
EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
|
||||||
|
@param[in] EnableAP Specifies the new state for the processor for
|
||||||
|
enabled, FALSE for disabled.
|
||||||
|
@param[in] HealthFlag If not NULL, a pointer to a value that specifies
|
||||||
|
the new health status of the AP. This flag
|
||||||
|
corresponds to StatusFlag defined in
|
||||||
|
EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
|
||||||
|
the PROCESSOR_HEALTH_STATUS_BIT is used. All other
|
||||||
|
bits are ignored. If it is NULL, this parameter
|
||||||
|
is ignored.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
|
||||||
|
@retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
|
||||||
|
prior to this service returning.
|
||||||
|
@retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
|
||||||
|
@retval EFI_DEVICE_ERROR The calling processor is an AP.
|
||||||
|
@retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
|
||||||
|
does not exist.
|
||||||
|
@retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
EnableDisableAP (
|
||||||
|
IN EFI_MP_SERVICES_PROTOCOL *This,
|
||||||
|
IN UINTN ProcessorNumber,
|
||||||
|
IN BOOLEAN EnableAP,
|
||||||
|
IN UINT32 *HealthFlag OPTIONAL
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthFlag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This return the handle number for the calling processor. This service may be
|
||||||
|
called from the BSP and APs.
|
||||||
|
|
||||||
|
This service returns the processor handle number for the calling processor.
|
||||||
|
The returned value is in the range from 0 to the total number of logical
|
||||||
|
processors minus 1. The total number of logical processors can be retrieved
|
||||||
|
with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
|
||||||
|
called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
|
||||||
|
is returned. Otherwise, the current processors handle number is returned in
|
||||||
|
ProcessorNumber, and EFI_SUCCESS is returned.
|
||||||
|
|
||||||
|
@param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
|
||||||
|
@param[out] ProcessorNumber Pointer to the handle number of AP.
|
||||||
|
The range is from 0 to the total number of
|
||||||
|
logical processors minus 1. The total number of
|
||||||
|
logical processors can be retrieved by
|
||||||
|
EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The current processor handle number was returned
|
||||||
|
in ProcessorNumber.
|
||||||
|
@retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
WhoAmI (
|
||||||
|
IN EFI_MP_SERVICES_PROTOCOL *This,
|
||||||
|
OUT UINTN *ProcessorNumber
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return MpInitLibWhoAmI (ProcessorNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initialize Multi-processor support.
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
InitializeMpSupport (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
UINTN NumberOfProcessors;
|
||||||
|
UINTN NumberOfEnabledProcessors;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Wakeup APs to do initialization
|
||||||
|
//
|
||||||
|
Status = MpInitLibInitialize ();
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
|
||||||
|
MpInitLibGetNumberOfProcessors (&NumberOfProcessors, &NumberOfEnabledProcessors);
|
||||||
|
mNumberOfProcessors = NumberOfProcessors;
|
||||||
|
DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors));
|
||||||
|
|
||||||
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||||
|
&mMpServiceHandle,
|
||||||
|
&gEfiMpServiceProtocolGuid,
|
||||||
|
&mMpServicesTemplate,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
/** @file Exception.c
|
||||||
|
|
||||||
|
CPU DXE Module initialization exception instance.
|
||||||
|
|
||||||
|
Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "CpuDxe.h"
|
||||||
|
#include <Guid/VectorHandoffTable.h>
|
||||||
|
#include <Library/CpuExceptionHandlerLib.h>
|
||||||
|
#include <Register/LoongArch64/Csr.h>
|
||||||
|
|
||||||
|
VOID
|
||||||
|
ExceptionEntryStart (
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
ExceptionEntryEnd (
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function registers and enables the handler specified by InterruptHandler for a processor
|
||||||
|
interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
|
||||||
|
handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
|
||||||
|
The installed handler is called once for each processor interrupt or exception.
|
||||||
|
|
||||||
|
@param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
|
||||||
|
are enabled and FALSE if interrupts are disabled.
|
||||||
|
@param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
|
||||||
|
when a processor interrupt occurs. If this parameter is NULL, then the handler
|
||||||
|
will be uninstalled.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
|
||||||
|
@retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
|
||||||
|
previously installed.
|
||||||
|
@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
|
||||||
|
previously installed.
|
||||||
|
@retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
RegisterInterruptHandler (
|
||||||
|
IN EFI_EXCEPTION_TYPE InterruptType,
|
||||||
|
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return (EFI_STATUS)RegisterCpuInterruptHandler (InterruptType, InterruptHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Update the exception start entry code.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Update the exception start entry code down.
|
||||||
|
@retval EFI_OUT_OF_RESOURCES The start entry code size out of bounds.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
UpdateExceptionStartEntry (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_PHYSICAL_ADDRESS ExceptionStartEntry;
|
||||||
|
UINTN VectorLength;
|
||||||
|
UINTN MaxLength;
|
||||||
|
UINTN MaxSizeOfVector;
|
||||||
|
|
||||||
|
VectorLength = (UINTN)ExceptionEntryEnd - (UINTN)ExceptionEntryStart;
|
||||||
|
|
||||||
|
//
|
||||||
|
// A vector is up to 512 bytes.
|
||||||
|
//
|
||||||
|
MaxSizeOfVector = 512;
|
||||||
|
MaxLength = (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * MaxSizeOfVector;
|
||||||
|
|
||||||
|
if (VectorLength > MaxLength) {
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExceptionStartEntry = PcdGet64 (PcdLoongArchExceptionVectorBaseAddress);
|
||||||
|
|
||||||
|
InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLength);
|
||||||
|
CopyMem ((VOID *)ExceptionStartEntry, (VOID *)ExceptionEntryStart, VectorLength);
|
||||||
|
InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLength);
|
||||||
|
InvalidateDataCache ();
|
||||||
|
|
||||||
|
//
|
||||||
|
// If PcdLoongArchExceptionVectorBaseAddress is not used during SEC and PEI stages, the exception
|
||||||
|
// base addres is set to PcdLoongArchExceptionVectorBaseAddress.
|
||||||
|
//
|
||||||
|
if (CsrRead (LOONGARCH_CSR_EBASE) != ExceptionStartEntry) {
|
||||||
|
SetExceptionBaseAddress (ExceptionStartEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initialize interrupt handling for DXE phase.
|
||||||
|
|
||||||
|
@param Cpu A pointer of EFI_CPU_ARCH_PROTOCOL instance.
|
||||||
|
|
||||||
|
@return VOID.
|
||||||
|
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
InitializeExceptions (
|
||||||
|
IN EFI_CPU_ARCH_PROTOCOL *Cpu
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EFI_VECTOR_HANDOFF_INFO *VectorInfoList;
|
||||||
|
EFI_VECTOR_HANDOFF_INFO *VectorInfo;
|
||||||
|
BOOLEAN IrqEnabled;
|
||||||
|
|
||||||
|
VectorInfo = (EFI_VECTOR_HANDOFF_INFO *)NULL;
|
||||||
|
Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList);
|
||||||
|
|
||||||
|
if ((Status == EFI_SUCCESS) && (VectorInfoList != NULL)) {
|
||||||
|
VectorInfo = VectorInfoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Disable interrupts
|
||||||
|
//
|
||||||
|
Cpu->GetInterruptState (Cpu, &IrqEnabled);
|
||||||
|
if (IrqEnabled) {
|
||||||
|
Cpu->DisableInterrupt (Cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Update the Exception Start Entry code to point into CpuDxe.
|
||||||
|
//
|
||||||
|
Status = UpdateExceptionStartEntry ();
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
DebugPrint (EFI_D_ERROR, "[%a]: Exception start entry code out of bounds!\n", __func__);
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Intialize the CpuExceptionHandlerLib so we take over the exception vector table from the DXE Core
|
||||||
|
//
|
||||||
|
Status = InitializeCpuExceptionHandlers (VectorInfo);
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Enable interrupts
|
||||||
|
//
|
||||||
|
DebugPrint (EFI_D_INFO, "InitializeExceptions,IrqEnabled = %x\n", IrqEnabled);
|
||||||
|
if (!IrqEnabled) {
|
||||||
|
Status = Cpu->EnableInterrupt (Cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
}
|
Loading…
Reference in New Issue