255 lines
7.4 KiB
C
255 lines
7.4 KiB
C
/** @file
|
|
It register callbacks for common Sw or Sx(s3/S4).
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2018, Insyde Software Corp. 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 "CommonSmiCallBackSmm.h"
|
|
|
|
BOOLEAN mLegacyBoot = FALSE;
|
|
|
|
/**
|
|
SMM Legacy boot callback to indicate gLegacyBootProtocolGuid event is signaled
|
|
|
|
@retval EFI_SUCCESS: Locate EFI_SMM_SW_DISPATCH2_PROTOCOL success
|
|
@retval Others EFI_SMM_SW_DISPATCH2_PROTOCOL not installed
|
|
**/
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SmmLegacyBootCallback (
|
|
IN CONST EFI_GUID *Protocol,
|
|
IN VOID *Interface,
|
|
IN EFI_HANDLE Handle
|
|
)
|
|
{
|
|
mLegacyBoot = TRUE;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
The driver's entry point.
|
|
|
|
It register callbacks for common Sw or Sx(s3/S4).
|
|
|
|
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
@param[in] SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
@retval Others Some error occurs when executing this entry point.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CommonSmiInitialize (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE WakeOnAcLossHandle;
|
|
EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch2;
|
|
EFI_SMM_SX_REGISTER_CONTEXT EntryDispatchContext2;
|
|
VOID *LegacyBootRegistration;
|
|
|
|
//
|
|
// Get the Sx dispatch2 protocol
|
|
//
|
|
Status = gSmst->SmmLocateProtocol (&gEfiSmmSxDispatch2ProtocolGuid, NULL, (VOID **)&SxDispatch2);
|
|
if (!EFI_ERROR(Status)) {
|
|
EntryDispatchContext2.Type = SxS4;
|
|
EntryDispatchContext2.Phase = SxEntry;
|
|
Status = SxDispatch2->Register (
|
|
SxDispatch2,
|
|
S4SleepEntryCallBack2,
|
|
&EntryDispatchContext2,
|
|
&WakeOnAcLossHandle
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
Status = gSmst->SmmRegisterProtocolNotify (
|
|
&gEdkiiSmmLegacyBootProtocolGuid,
|
|
SmmLegacyBootCallback,
|
|
&LegacyBootRegistration
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Change the BBS index to Boot current when legacy boot
|
|
|
|
@retval 0xff Failed
|
|
@retval Others Boot current value
|
|
|
|
**/
|
|
UINT8
|
|
GetBootCurrent (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN OptionOrderSize;
|
|
UINT16 *OptionOrder;
|
|
UINT16 PriorityIndex;
|
|
CHAR16 BootOption[10];
|
|
UINT8 *Ptr;
|
|
UINT8 *BootOptionVar;
|
|
UINT8 CmosData;
|
|
UINT16 DevPathSize;
|
|
CHAR16 *BootDesc;
|
|
UINT8 BootCurrentValue;
|
|
UINT16 BbsIndex;
|
|
|
|
|
|
OptionOrderSize = 0;
|
|
OptionOrder = NULL;
|
|
CommonGetVariableDataAndSize (
|
|
L"BootOrder",
|
|
&gEfiGlobalVariableGuid,
|
|
&OptionOrderSize,
|
|
(VOID **) &OptionOrder
|
|
);
|
|
if (OptionOrder == NULL) {
|
|
return INVALID;
|
|
}
|
|
|
|
BootCurrentValue = INVALID;
|
|
//
|
|
// Set BBS priority according OptionOrder variable
|
|
//
|
|
for (PriorityIndex = 0; PriorityIndex < OptionOrderSize / sizeof (UINT16); PriorityIndex++) {
|
|
UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionOrder[PriorityIndex]);
|
|
BootOptionVar = CommonGetVariableData (BootOption, &gEfiGlobalVariableGuid);
|
|
if (BootOptionVar == NULL) {
|
|
break;
|
|
}
|
|
//
|
|
// Skip the native boot options(EFI shell...)
|
|
//
|
|
Ptr = BootOptionVar + sizeof(UINT32) + sizeof(UINT16) + StrSize ((CHAR16 *)(BootOptionVar + 6));
|
|
if (*Ptr != BBS_DEVICE_PATH) {
|
|
FreePool (BootOptionVar);
|
|
continue;
|
|
}
|
|
|
|
Ptr = BootOptionVar;
|
|
Ptr += sizeof (UINT32);
|
|
DevPathSize = *((UINT16 *) Ptr);
|
|
Ptr += sizeof (UINT16);
|
|
BootDesc = (CHAR16*) Ptr;
|
|
Ptr += StrSize (BootDesc);
|
|
Ptr += DevPathSize;
|
|
Ptr += sizeof (BBS_TABLE);
|
|
|
|
BbsIndex = *((UINT16 *) Ptr);
|
|
FreePool (BootOptionVar);
|
|
//
|
|
// Change BBS index to boot current
|
|
//
|
|
CmosData = ReadCmos8 (LastBootDevice);
|
|
if (CmosData == (UINT8) BbsIndex) {
|
|
//
|
|
// Save boot current to CMOS
|
|
//
|
|
BootCurrentValue = (UINT8) OptionOrder[PriorityIndex];
|
|
break;
|
|
}
|
|
}
|
|
FreePool (OptionOrder);
|
|
return BootCurrentValue;
|
|
}
|
|
|
|
|
|
/**
|
|
Check whether is Legacy boot
|
|
|
|
@retval VALUE Legacy boot
|
|
@retval 0xFF UEFI boot or invalid's boot option
|
|
**/
|
|
UINT8
|
|
SaveLastBootDevice (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 *BootTablePtr;
|
|
|
|
//
|
|
// If legacy boot event isn't signaled, it indicates system boots from UEFI boot option.
|
|
// In this case, return INVALID directly.
|
|
// This check condition can prevent from accessing EfiConventionalMemory type memory in
|
|
// SMM and cause CPU exception if copper point feature is enabled.
|
|
//
|
|
if (!mLegacyBoot) {
|
|
return INVALID;
|
|
}
|
|
|
|
if ((BDA(BDA_MEMORY_SIZE_OFFSET) == 0xFFFF) || (BDA(BDA_MEMORY_SIZE_OFFSET) == 0)) {
|
|
//
|
|
// Class 3 Bios
|
|
//
|
|
return INVALID;
|
|
}
|
|
//
|
|
// Check whether BDA is valid (BDA offset 0x13(40:13) * 0x400 is equal EBDA address)
|
|
//
|
|
if ((BOOLEAN)((BDA(BDA_MEMORY_SIZE_OFFSET) * 0x400) == (BDA(EXT_DATA_SEG_OFFSET) << 4))) {
|
|
//
|
|
// Check whether Boot table is valid
|
|
//
|
|
if ((EBDA(LEGACY_BOOT_TABLE_OFFSET) != 0xFFFF) &&
|
|
(EBDA(LEGACY_BOOT_TABLE_OFFSET) != 0) &&
|
|
(EBDA(LEGACY_BOOT_TABLE_OFFSET) >= EBDA_DEFAULT_SIZE)) {
|
|
|
|
BootTablePtr = (UINT32 *)(UINTN)((BDA(EXT_DATA_SEG_OFFSET) << 4) + EBDA(LEGACY_BOOT_TABLE_OFFSET));
|
|
|
|
if ((*BootTablePtr != 0xFFFFFFFF) && (*BootTablePtr != 0)) {
|
|
return GetBootCurrent();
|
|
}
|
|
}
|
|
}
|
|
return INVALID;
|
|
}
|
|
|
|
/**
|
|
S4 sleep entry callback for save boot current to CMOS using gEfiSmmSxDispatch2ProtocolGuid
|
|
|
|
@param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
|
|
@param[in] Context Points to an optional handler context which was specified when the
|
|
handler was registered.
|
|
@param[in, out] CommBuffer A pointer to a collection of data in memory that will
|
|
be conveyed from a non-SMM environment into an SMM environment.
|
|
@param[in, out] CommBufferSize The size of the CommBuffer.
|
|
|
|
@retval EFI_SUCCESS The S4 sleep entry callabck was handled successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
S4SleepEntryCallBack2 (
|
|
IN EFI_HANDLE DispatchHandle,
|
|
IN CONST VOID *Context OPTIONAL,
|
|
IN OUT VOID *CommBuffer OPTIONAL,
|
|
IN OUT UINTN *CommBufferSize OPTIONAL
|
|
)
|
|
{
|
|
//
|
|
// Save Boot Current into offset 0x5f of CMOS if Legacy boot,
|
|
// else if UEFI boot then save value to 0xFF(that mean is invalid).
|
|
//
|
|
WriteCmos8 (LastBootDevice, SaveLastBootDevice());
|
|
return EFI_SUCCESS;
|
|
}
|