alder_lake_bios/Intel/AlderLake/AlderLakeChipsetPkg/ExtendPeiTimer/ExtendPeiTimer.c

276 lines
7.5 KiB
C

/** @file
Maintain PEI Timer Interrupt in DXE phase.
;******************************************************************************
;* Copyright (c) 2015 - 2020, Insyde Software Corporation. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include <ExtendPeiTimer.h>
EFI_LEGACY_8259_PROTOCOL *mLegacy8259 = NULL;
EFI_EVENT mTimerEvent = NULL;
UINT32 mPeiService;
UINT32 mFunctionPoint;
UINT32 mPeiServicesPoint;
ALIGN_16BYTE_BOUNDRY IA32_DESCRIPTOR mIdtr;
/**
Migrate IDT table and Save PEI Service Table Pointer.
The PEI Services Table pointer is stored in the 4 bytes
immediately preceding the Interrupt Descriptor Table (IDT) in memory.
@param None.
**/
VOID
MigrateIdtTable (
VOID
)
{
EFI_STATUS Status;
X64_IDT_TABLE *IdtTable;
EFI_PHYSICAL_ADDRESS PageAddress;
IdtTable = NULL;
//
// Allocate New IDT table
//
AsmReadIdtr (&mIdtr);
Status = gBS->AllocatePages (
AllocateAnyPages,
EfiBootServicesData,
EFI_SIZE_TO_PAGES(mIdtr.Limit + 1 + sizeof (UINT32) * 2),
&PageAddress
);
ASSERT (Status == EFI_SUCCESS);
if (!EFI_ERROR(Status)) {
//
// Copy IDT Table and save PeiServicePointer
//
IdtTable = (X64_IDT_TABLE*)(UINTN)PageAddress;
IdtTable->Reserved = 0;
IdtTable->PeiService = mPeiService;
CopyMem ((VOID*)&IdtTable->IdtTable, (VOID*)mIdtr.Base, mIdtr.Limit + 1);
mIdtr.Base = (UINTN)&IdtTable->IdtTable;
AsmWriteIdtr (&mIdtr);
}
}
/**
Legacy8259Protocol installed callback function.
Open IRQ0 interrupt again.
@param[in] Event Wait Event
@param[in] Context Passed parameter to event handler
**/
VOID
Legacy8259CallbackFunction (
IN EFI_EVENT Event,
IN VOID *Context
)
{
DEBUG ((DEBUG_INFO, "PeiTimer: Legacy8259 Callback\n"));
gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID**)&mLegacy8259);
//
// Open the IRQ0 interrupt
//
mLegacy8259->EnableIrq (mLegacy8259, Efi8259Irq0, FALSE);
}
/**
CpuArchProtocol installed callback function.
Clear pending interrupt.
@param[in] Event Wait Event
@param[in] Context Passed parameter to event handler
**/
VOID
CpuCallbackFunction (
IN EFI_EVENT Event,
IN VOID *Context
)
{
DEBUG ((DEBUG_INFO, "PeiTimer: CpuArchDxe Callback\n"));
if (mLegacy8259 != NULL) {
//
// Disabled IRQ0 interrupts
//
mLegacy8259->DisableIrq (mLegacy8259, Efi8259Irq0);
//
// Clear pending interrupt
//
mLegacy8259->EndOfInterrupt (mLegacy8259, Efi8259Irq0);
}
MigrateIdtTable ();
}
/**
Change cpu mode to IA-32 and execution PEI function.
@param[in] Event Wait Event
@param[in] Context Passed parameter to event handler
**/
VOID
TimerCallbackFunction (
IN EFI_EVENT Event,
IN VOID *Context
)
{
DEBUG ((DEBUG_INFO, "PeiTimer: Dxe Timer Event Callback\n"));
if (mFunctionPoint != 0) {
Thunk64To32 (mPeiServicesPoint, mFunctionPoint);
}
ASSERT (mFunctionPoint != 0);
}
/**
CpuArchProtocol installed callback function.
@param[in] Event A pointer to the Event that triggered the callback.
@param[in] Handle Checkpoint handle.
**/
VOID
EnterBdsCallbackFunction (
IN EFI_EVENT Event,
IN H2O_CP_HANDLE Handle
)
{
DEBUG ((DEBUG_INFO, "PeiTimer: EnterBdsCallback\n"));
if (mTimerEvent != NULL) {
gBS->CloseEvent (mTimerEvent);
}
ASSERT (mTimerEvent != NULL);
}
/**
ExtendPeiTimer driver entry point function.
@param[in] ImageHandle Image handle for this driver image
@param[in] SystemTable Pointer to the EFI System Table
@retval EFI_SUCCESS The driver installed/initialized correctly.
**/
EFI_STATUS
ExtendPeiTimerEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_EVENT Event8259;
EFI_EVENT EventCpu;
VOID *Registration8259;
VOID *RegistrationCpu;
EFI_HOB_GUID_TYPE *GuidHob;
H2O_PEI_TIMER_DATA_HOB *DataInHob;
H2O_CP_HANDLE CpHandle;
//
// Get Thunk Entry point and Pei Services Point.
//
GuidHob = NULL;
mFunctionPoint = 0;
mPeiServicesPoint = 0;
GuidHob = GetFirstGuidHob (&gH2OPeiTimerDataHobGuid);
ASSERT (GuidHob != NULL);
if (GuidHob != NULL) {
DataInHob = GET_GUID_HOB_DATA (GuidHob);
mFunctionPoint = DataInHob->CallBackFunction;
mPeiServicesPoint = DataInHob->PeiServicesPoint;
DEBUG ((DEBUG_INFO, "PeiTimer: Get H2OPeiTimerDataHob\n"));
DEBUG ((DEBUG_INFO, " FunctionPoint = 0x%X\n",mFunctionPoint));
DEBUG ((DEBUG_INFO, " PeiServicesPoint = 0x%X\n",mPeiServicesPoint));
}
//
// Save the PeiServicePointer
//
AsmReadIdtr (&mIdtr);
mPeiService = (UINT32)*(UINT32*)(mIdtr.Base - PEI_POINTER_SIZE);
//
// Register Event for Monitor gEfiLegacy8259ProtocolGuid is installed.
//
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
Legacy8259CallbackFunction,
NULL,
&Event8259
);
if(!EFI_ERROR(Status)) {
Status = gBS->RegisterProtocolNotify (
&gEfiLegacy8259ProtocolGuid,
Event8259,
&Registration8259
);
}
//
// Register Event for Monitor gEfiCpuArchProtocolGuid is installed.
//
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
CpuCallbackFunction,
NULL,
&EventCpu
);
if(!EFI_ERROR(Status)) {
Status = gBS->RegisterProtocolNotify (
&gEfiCpuArchProtocolGuid,
EventCpu,
&RegistrationCpu
);
}
if (FeaturePcdGet (PcdH2OBdsCpInitSupported)) {
Status = H2OCpRegisterHandler (
&gH2OBdsCpInitGuid,
EnterBdsCallbackFunction,
H2O_CP_MEDIUM,
&CpHandle
);
if (EFI_ERROR (Status)) {
DEBUG_CP ((DEBUG_ERROR, "Checkpoint Register Fail: %g (%r)\n", &gH2OBdsCpInitGuid, Status));
return Status;
}
DEBUG_CP ((DEBUG_INFO, "Checkpoint Registered: %g (%r)\n", &gH2OBdsCpInitGuid, Status));
}
//
// Register Timer Event for do thunk.
//
Status = gBS->CreateEvent (
EVT_TIMER | EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
TimerCallbackFunction,
NULL,
&mTimerEvent
);
if(!EFI_ERROR(Status)) {
Status = gBS->SetTimer (
mTimerEvent,
TimerPeriodic,
DEFAULT_TIMER_TICK_DURATION
);
}
return Status;
}