mirror of https://github.com/acidanthera/audk.git
367 lines
11 KiB
C
367 lines
11 KiB
C
/** @file
|
|
Implementation of Reset2, ResetFilter and ResetHandler PPIs.
|
|
|
|
Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "ResetSystem.h"
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mResetTypeStr[] = {
|
|
L"Cold", L"Warm", L"Shutdown", L"PlatformSpecific"
|
|
};
|
|
|
|
EFI_PEI_RESET2_PPI mPpiReset2 = {
|
|
ResetSystem2
|
|
};
|
|
|
|
EFI_GUID *mProcessingOrder[] = {
|
|
&gEdkiiPlatformSpecificResetFilterPpiGuid,
|
|
&gEdkiiPlatformSpecificResetNotificationPpiGuid,
|
|
&gEdkiiPlatformSpecificResetHandlerPpiGuid
|
|
};
|
|
|
|
RESET_FILTER_INSTANCE mResetFilter = {
|
|
{
|
|
RegisterResetNotify,
|
|
UnregisterResetNotify
|
|
},
|
|
&gEdkiiPlatformSpecificResetFilterPpiGuid
|
|
};
|
|
|
|
RESET_FILTER_INSTANCE mResetNotification = {
|
|
{
|
|
RegisterResetNotify,
|
|
UnregisterResetNotify
|
|
},
|
|
&gEdkiiPlatformSpecificResetNotificationPpiGuid
|
|
};
|
|
|
|
RESET_FILTER_INSTANCE mResetHandler = {
|
|
{
|
|
RegisterResetNotify,
|
|
UnregisterResetNotify
|
|
},
|
|
&gEdkiiPlatformSpecificResetHandlerPpiGuid
|
|
};
|
|
|
|
EFI_PEI_PPI_DESCRIPTOR mPpiListReset[] = {
|
|
{
|
|
EFI_PEI_PPI_DESCRIPTOR_PPI,
|
|
&gEfiPeiReset2PpiGuid,
|
|
&mPpiReset2
|
|
},
|
|
{
|
|
EFI_PEI_PPI_DESCRIPTOR_PPI,
|
|
&gEdkiiPlatformSpecificResetFilterPpiGuid,
|
|
&mResetFilter.ResetFilter
|
|
},
|
|
{
|
|
EFI_PEI_PPI_DESCRIPTOR_PPI,
|
|
&gEdkiiPlatformSpecificResetNotificationPpiGuid,
|
|
&mResetNotification.ResetFilter
|
|
},
|
|
{
|
|
EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
|
|
&gEdkiiPlatformSpecificResetHandlerPpiGuid,
|
|
&mResetHandler.ResetFilter
|
|
}
|
|
};
|
|
|
|
/**
|
|
Register a notification function to be called when ResetSystem() is called.
|
|
|
|
The RegisterResetNotify() function registers a notification function that is called when
|
|
ResetSystem() is called and prior to completing the reset of the platform.
|
|
The registered functions must not perform a platform reset themselves. These
|
|
notifications are intended only for the notification of components which may need some
|
|
special-purpose maintenance prior to the platform resetting.
|
|
The list of registered reset notification functions are processed if ResetSystem()is called
|
|
before ExitBootServices(). The list of registered reset notification functions is ignored if
|
|
ResetSystem() is called after ExitBootServices().
|
|
|
|
@param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
|
|
@param[in] ResetFunction Points to the function to be called when a ResetSystem() is executed.
|
|
|
|
@retval EFI_SUCCESS The reset notification function was successfully registered.
|
|
@retval EFI_INVALID_PARAMETER ResetFunction is NULL.
|
|
@retval EFI_OUT_OF_RESOURCES There are not enough resources available to register the reset notification function.
|
|
@retval EFI_ALREADY_STARTED The reset notification function specified by ResetFunction has already been registered.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RegisterResetNotify (
|
|
IN EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PPI *This,
|
|
IN EFI_RESET_SYSTEM ResetFunction
|
|
)
|
|
{
|
|
RESET_FILTER_INSTANCE *ResetFilter;
|
|
RESET_FILTER_LIST *List;
|
|
VOID *Hob;
|
|
UINTN Index;
|
|
|
|
if (ResetFunction == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ResetFilter = (RESET_FILTER_INSTANCE *)This;
|
|
ASSERT (
|
|
CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetFilterPpiGuid) ||
|
|
CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetNotificationPpiGuid) ||
|
|
CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetHandlerPpiGuid)
|
|
);
|
|
|
|
Hob = GetFirstGuidHob (ResetFilter->Guid);
|
|
if (Hob == NULL) {
|
|
//
|
|
// When the GUIDed HOB doesn't exist, create it.
|
|
//
|
|
List = (RESET_FILTER_LIST *)BuildGuidHob (
|
|
ResetFilter->Guid,
|
|
sizeof (RESET_FILTER_LIST) + sizeof (EFI_RESET_SYSTEM) * PcdGet32 (PcdMaximumPeiResetNotifies)
|
|
);
|
|
if (List == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
List->Signature = RESET_FILTER_LIST_SIGNATURE;
|
|
List->Count = PcdGet32 (PcdMaximumPeiResetNotifies);
|
|
ZeroMem (List->ResetFilters, sizeof (EFI_RESET_SYSTEM) * List->Count);
|
|
List->ResetFilters[0] = ResetFunction;
|
|
return EFI_SUCCESS;
|
|
} else {
|
|
List = (RESET_FILTER_LIST *)GET_GUID_HOB_DATA (Hob);
|
|
ASSERT (List->Signature == RESET_FILTER_LIST_SIGNATURE);
|
|
//
|
|
// Firstly check whether the ResetFunction is already registerred.
|
|
//
|
|
for (Index = 0; Index < List->Count; Index++) {
|
|
if (List->ResetFilters[Index] == ResetFunction) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Index != List->Count) {
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
//
|
|
// Secondly find the first free slot.
|
|
//
|
|
for (Index = 0; Index < List->Count; Index++) {
|
|
if (List->ResetFilters[Index] == NULL) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Index == List->Count) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
List->ResetFilters[Index] = ResetFunction;
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Unregister a notification function.
|
|
|
|
The UnregisterResetNotify() function removes the previously registered
|
|
notification using RegisterResetNotify().
|
|
|
|
@param[in] This A pointer to the EFI_RESET_NOTIFICATION_PROTOCOL instance.
|
|
@param[in] ResetFunction The pointer to the ResetFunction being unregistered.
|
|
|
|
@retval EFI_SUCCESS The reset notification function was unregistered.
|
|
@retval EFI_INVALID_PARAMETER ResetFunction is NULL.
|
|
@retval EFI_INVALID_PARAMETER The reset notification function specified by ResetFunction was not previously
|
|
registered using RegisterResetNotify().
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnregisterResetNotify (
|
|
IN EDKII_PLATFORM_SPECIFIC_RESET_FILTER_PPI *This,
|
|
IN EFI_RESET_SYSTEM ResetFunction
|
|
)
|
|
{
|
|
RESET_FILTER_INSTANCE *ResetFilter;
|
|
RESET_FILTER_LIST *List;
|
|
VOID *Hob;
|
|
UINTN Index;
|
|
|
|
if (ResetFunction == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ResetFilter = (RESET_FILTER_INSTANCE *)This;
|
|
ASSERT (
|
|
CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetFilterPpiGuid) ||
|
|
CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetNotificationPpiGuid) ||
|
|
CompareGuid (ResetFilter->Guid, &gEdkiiPlatformSpecificResetHandlerPpiGuid)
|
|
);
|
|
|
|
Hob = GetFirstGuidHob (ResetFilter->Guid);
|
|
if (Hob == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
List = (RESET_FILTER_LIST *)GET_GUID_HOB_DATA (Hob);
|
|
ASSERT (List->Signature == RESET_FILTER_LIST_SIGNATURE);
|
|
for (Index = 0; Index < List->Count; Index++) {
|
|
if (List->ResetFilters[Index] == ResetFunction) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Index == List->Count) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
List->ResetFilters[Index] = NULL;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
The PEIM's entry point.
|
|
|
|
It initializes the Reset2, ResetFilter and ResetHandler PPIs.
|
|
|
|
@param[in] FileHandle Handle of the file being invoked.
|
|
@param[in] PeiServices Describes the list of possible PEI Services.
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
@retval EFI_ALREADY_STARTED The Reset2 PPI was already installed.
|
|
@retval others Status code returned from PeiServicesInstallPpi().
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InitializeResetSystem (
|
|
IN EFI_PEI_FILE_HANDLE FileHandle,
|
|
IN CONST EFI_PEI_SERVICES **PeiServices
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *Ppi;
|
|
|
|
Status = PeiServicesLocatePpi (&gEfiPeiReset2PpiGuid, 0, NULL, (VOID **)&Ppi);
|
|
if (Status != EFI_NOT_FOUND) {
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
PeiServicesInstallPpi (mPpiListReset);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Resets the entire platform.
|
|
|
|
@param[in] ResetType The type of reset to perform.
|
|
@param[in] ResetStatus The status code for the reset.
|
|
@param[in] DataSize The size, in bytes, of ResetData.
|
|
@param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
|
|
EfiResetShutdown the data buffer starts with a Null-terminated
|
|
string, optionally followed by additional binary data.
|
|
The string is a description that the caller may use to further
|
|
indicate the reason for the system reset.
|
|
For a ResetType of EfiResetPlatformSpecific the data buffer
|
|
also starts with a Null-terminated string that is followed
|
|
by an EFI_GUID that describes the specific type of reset to perform.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ResetSystem2 (
|
|
IN EFI_RESET_TYPE ResetType,
|
|
IN EFI_STATUS ResetStatus,
|
|
IN UINTN DataSize,
|
|
IN VOID *ResetData OPTIONAL
|
|
)
|
|
{
|
|
VOID *Hob;
|
|
UINTN Index;
|
|
RESET_FILTER_LIST *List;
|
|
UINTN OrderIndex;
|
|
UINT8 RecursionDepth;
|
|
UINT8 *RecursionDepthPointer;
|
|
|
|
//
|
|
// The recursion depth is stored in GUIDed HOB using gEfiCallerIdGuid.
|
|
//
|
|
Hob = GetFirstGuidHob (&gEfiCallerIdGuid);
|
|
if (Hob == NULL) {
|
|
RecursionDepth = 0;
|
|
RecursionDepthPointer = BuildGuidDataHob (&gEfiCallerIdGuid, &RecursionDepth, sizeof (RecursionDepth));
|
|
} else {
|
|
RecursionDepthPointer = (UINT8 *)GET_GUID_HOB_DATA (Hob);
|
|
}
|
|
|
|
//
|
|
// Only do REPORT_STATUS_CODE() on first call to ResetSystem()
|
|
//
|
|
if (*RecursionDepthPointer == 0) {
|
|
//
|
|
// Indicate reset system PEI service is called.
|
|
//
|
|
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_SERVICE | EFI_SW_PS_PC_RESET_SYSTEM));
|
|
}
|
|
|
|
//
|
|
// Increase the call depth
|
|
//
|
|
(*RecursionDepthPointer)++;
|
|
DEBUG ((DEBUG_INFO, "PEI ResetSystem2: Reset call depth = %d.\n", *RecursionDepthPointer));
|
|
|
|
if (*RecursionDepthPointer <= MAX_RESET_NOTIFY_DEPTH) {
|
|
//
|
|
// Iteratively call Reset Filters and Reset Handlers.
|
|
//
|
|
for (OrderIndex = 0; OrderIndex < ARRAY_SIZE (mProcessingOrder); OrderIndex++) {
|
|
Hob = GetFirstGuidHob (mProcessingOrder[OrderIndex]);
|
|
if (Hob != NULL) {
|
|
List = (RESET_FILTER_LIST *)GET_GUID_HOB_DATA (Hob);
|
|
ASSERT (List->Signature == RESET_FILTER_LIST_SIGNATURE);
|
|
|
|
for (Index = 0; Index < List->Count; Index++) {
|
|
if (List->ResetFilters[Index] != NULL) {
|
|
List->ResetFilters[Index](ResetType, ResetStatus, DataSize, ResetData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
ASSERT (ResetType < ARRAY_SIZE (mResetTypeStr));
|
|
DEBUG ((DEBUG_ERROR, "PEI ResetSystem2: Maximum reset call depth is met. Use the current reset type: %s!\n", mResetTypeStr[ResetType]));
|
|
}
|
|
|
|
switch (ResetType) {
|
|
case EfiResetWarm:
|
|
ResetWarm ();
|
|
break;
|
|
|
|
case EfiResetCold:
|
|
ResetCold ();
|
|
break;
|
|
|
|
case EfiResetShutdown:
|
|
ResetShutdown ();
|
|
return;
|
|
|
|
case EfiResetPlatformSpecific:
|
|
ResetPlatformSpecific (DataSize, ResetData);
|
|
return;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Given we should have reset getting here would be bad
|
|
//
|
|
ASSERT (FALSE);
|
|
}
|