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) 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
|
||||
#
|
||||
|
@ -22,7 +23,7 @@
|
|||
MdeModulePkg/MdeModulePkg.dec
|
||||
UefiCpuPkg/UefiCpuPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
[LibraryClasses.common]
|
||||
BaseLib
|
||||
BaseMemoryLib
|
||||
CpuExceptionHandlerLib
|
||||
|
@ -30,9 +31,7 @@
|
|||
DebugLib
|
||||
DxeServicesTableLib
|
||||
HobLib
|
||||
LocalApicLib
|
||||
MemoryAllocationLib
|
||||
MtrrLib
|
||||
MpInitLib
|
||||
PeCoffGetEntryPointLib
|
||||
ReportStatusCodeLib
|
||||
|
@ -41,7 +40,15 @@
|
|||
UefiDriverEntryPoint
|
||||
UefiLib
|
||||
|
||||
[Sources]
|
||||
[LibraryClasses.IA32, LibraryClasses.X64]
|
||||
LocalApicLib
|
||||
MtrrLib
|
||||
|
||||
[LibraryClasses.LoongArch64]
|
||||
CacheMaintenanceLib
|
||||
CpuMmuLib
|
||||
|
||||
[Sources.IA32, Sources.X64]
|
||||
CpuDxe.c
|
||||
CpuDxe.h
|
||||
CpuGdt.c
|
||||
|
@ -59,6 +66,13 @@
|
|||
X64/CpuAsm.nasm
|
||||
X64/PagingAttribute.c
|
||||
|
||||
[Sources.LoongArch64]
|
||||
CpuMp.h
|
||||
LoongArch64/CpuDxe.c
|
||||
LoongArch64/CpuMp.c
|
||||
LoongArch64/Exception.c
|
||||
LoongArch64/CpuDxe.h
|
||||
|
||||
[Protocols]
|
||||
gEfiCpuArchProtocolGuid ## PRODUCES
|
||||
gEfiMpServiceProtocolGuid ## PRODUCES
|
||||
|
@ -81,6 +95,9 @@
|
|||
gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList ## CONSUMES
|
||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize ## CONSUMES
|
||||
|
||||
[Pcd.LoongArch64]
|
||||
gUefiCpuPkgTokenSpaceGuid.PcdLoongArchExceptionVectorBaseAddress ## CONSUMES
|
||||
|
||||
[Depex]
|
||||
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