434 lines
12 KiB
C
434 lines
12 KiB
C
/** @file
|
|
This driver is for providing the Legacy To Efi Services routines.
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2018, 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 "LegacyToEfiDxe.h"
|
|
|
|
EFI_LEGACY_BIOS_SHADOW_ALL_LEGACY_OPROMS mOrgShadowAllLegacyOproms;
|
|
|
|
/**
|
|
Erase L"LegacyToEfi" Variable during Ready To Boot Event
|
|
|
|
@param Event ReadyToBootEvent
|
|
@param Context Context
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
EraseLegacyToEfiVariable (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 LegacyToEfi;
|
|
UINTN BufferSize;
|
|
|
|
Status = EFI_SUCCESS;
|
|
LegacyToEfi = 0;
|
|
BufferSize = sizeof (UINT8);
|
|
|
|
Status = gRT->GetVariable (
|
|
L"LegacyToEfi",
|
|
&gEfiGenericVariableGuid,
|
|
NULL,
|
|
&BufferSize,
|
|
&LegacyToEfi
|
|
);
|
|
|
|
if (!EFI_ERROR (Status) && LegacyToEfi == 1) {
|
|
|
|
//
|
|
// Clear the "LegacyToEfi" variable first
|
|
//
|
|
Status = gRT->SetVariable (
|
|
L"LegacyToEfi",
|
|
&gEfiGenericVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Replace the LegacyBios->ShadowAllLegacyOproms function to hook Int10 that make sure No any display during LegacyToEfi boot
|
|
|
|
@param This Points to Legacy BIOS protocol
|
|
@param Context Context
|
|
|
|
@retval EFI_SUCCESS Dispatch LegacyRom success
|
|
@retval EFI_LOAD_ERROR Dispatch LegacyRom failure
|
|
**/
|
|
EFI_STATUS
|
|
BypassInt10 (
|
|
IN EFI_LEGACY_BIOS_PROTOCOL *This
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
|
|
UINT8 *DummyRetOpCode;
|
|
UINT8 OpCode;
|
|
UINT32 *IdtArray;
|
|
UINT32 OrgInt10;
|
|
|
|
Status = EFI_LOAD_ERROR;
|
|
|
|
//
|
|
// Locate LegacyBios Protocol
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, &LegacyBios);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
Status = LegacyBios->GetLegacyRegion (
|
|
LegacyBios,
|
|
1,
|
|
0,
|
|
1,
|
|
&DummyRetOpCode
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Fill in machine code for iret
|
|
//
|
|
OpCode = 0x0cf;
|
|
Status = LegacyBios->CopyLegacyRegion (
|
|
LegacyBios,
|
|
1,
|
|
DummyRetOpCode,
|
|
&OpCode
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
IdtArray = (UINT32 *) 0;
|
|
OrgInt10 = IdtArray[0x10];
|
|
|
|
//
|
|
// Hook Int10h
|
|
//
|
|
IdtArray[0x10] = (EFI_SEGMENT ((UINTN) DummyRetOpCode) << 16) | EFI_OFFSET ((UINTN) DummyRetOpCode);
|
|
|
|
Status = mOrgShadowAllLegacyOproms (LegacyBios);
|
|
|
|
LegacyBios->ShadowAllLegacyOproms = mOrgShadowAllLegacyOproms;
|
|
|
|
//
|
|
// Restore Int10h
|
|
//
|
|
IdtArray[0x10] = OrgInt10;
|
|
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function is invoked when gEfiLegacyBiosProtocolGuid is installed
|
|
|
|
@retval EFI_SUCCESS Shadow All Legac OpRoms success
|
|
@retval Others An unexpected error occurred after locating gEfiLegacyBiosProtocolGuid Protocol
|
|
**/
|
|
EFI_STATUS
|
|
ShadowAllLegacyOpRomsCore (
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
|
|
|
|
Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, &LegacyBios);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
//
|
|
// Replace the LegacyBios->ShadowAllLegacyOproms function
|
|
//
|
|
mOrgShadowAllLegacyOproms = LegacyBios->ShadowAllLegacyOproms;
|
|
LegacyBios->ShadowAllLegacyOproms = BypassInt10;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function is invoked when gEfiLegacyBiosProtocolGuid is installed
|
|
|
|
@param Event The triggered event.
|
|
@param Context Context for this event.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
HookShadowAllLegacyOproms (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = ShadowAllLegacyOpRomsCore ();
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
gBS->CloseEvent (Event);
|
|
}
|
|
}
|
|
|
|
/**
|
|
This function is invoked when gH2OBdsCpReadyToBootBeforeGuid is triggered
|
|
|
|
@param Event A pointer to the Event that triggered the callback.
|
|
@param Handle Checkpoint handle.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
LegacyToEfiCpHandler (
|
|
IN EFI_EVENT Event,
|
|
IN H2O_CP_HANDLE Handle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
|
|
BBS_TABLE *LocalBbsTable;
|
|
EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
|
|
UINT8 SmmCommBuffer[SMM_COMMUNICATE_HEADER_SIZE + sizeof (UINTN)];
|
|
EFI_SMM_COMMUNICATE_HEADER *SmmCommHeader;
|
|
UINTN *LegacyToEfiSmmData;
|
|
UINTN CommBufferSize;
|
|
|
|
LegacyBios = NULL;
|
|
LocalBbsTable = NULL;
|
|
SmmCommunication = NULL;
|
|
SmmCommHeader = NULL;
|
|
LegacyToEfiSmmData = NULL;
|
|
CommBufferSize = 0;
|
|
|
|
H2OCpUnregisterHandler (Handle);
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiLegacyBiosProtocolGuid,
|
|
NULL,
|
|
&LegacyBios
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
LegacyBios->GetBbsInfo (
|
|
LegacyBios,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&LocalBbsTable
|
|
);
|
|
|
|
//
|
|
// Trigger SMI for pass data to SMM instance
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiSmmCommunicationProtocolGuid,
|
|
NULL,
|
|
(VOID **)&SmmCommunication
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
SmmCommHeader = (EFI_SMM_COMMUNICATE_HEADER *) SmmCommBuffer;
|
|
CommBufferSize = SMM_COMMUNICATE_HEADER_SIZE + sizeof (UINTN);
|
|
ZeroMem (SmmCommHeader, CommBufferSize);
|
|
|
|
CopyGuid (&SmmCommHeader->HeaderGuid , &gEfiL05LegacyToEfiCommunicationGuid);
|
|
|
|
LegacyToEfiSmmData = (UINTN *) SmmCommHeader->Data;
|
|
*LegacyToEfiSmmData = (UINTN) LocalBbsTable;
|
|
|
|
Status = SmmCommunication->Communicate (
|
|
SmmCommunication,
|
|
SmmCommHeader,
|
|
&CommBufferSize
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
This is the declaration of an EFI image entry point. This entry point is
|
|
the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
|
|
both device drivers and bus drivers.
|
|
|
|
@param ImageHandle The firmware allocated handle for the UEFI image.
|
|
@param SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The operation completed successfully.
|
|
@retval Others An unexpected error occurred.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
LegacyToEfiDxeEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 LegacyToEfi;
|
|
UINTN BufferSize;
|
|
VOID *HobPtr;
|
|
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
|
|
EFI_EVENT LegacyBiosEvent;
|
|
VOID *Registration;
|
|
EFI_EVENT ReadyToBootEvent;
|
|
BOOLEAN IsLegacyToEfi;
|
|
H2O_CP_HANDLE CpHandle;
|
|
|
|
Registration = NULL;
|
|
IsLegacyToEfi = TRUE;
|
|
HobPtr = NULL;
|
|
LegacyBios = NULL;
|
|
CpHandle = NULL;
|
|
|
|
//
|
|
// Get Current Status of Legacy To EFI function
|
|
//
|
|
BufferSize = sizeof (UINT8);
|
|
|
|
Status = gRT->GetVariable (
|
|
L"LegacyToEfi",
|
|
&gEfiGenericVariableGuid,
|
|
NULL,
|
|
&BufferSize,
|
|
&LegacyToEfi
|
|
);
|
|
|
|
if (EFI_ERROR (Status) || LegacyToEfi != 1) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Stop process of Legacy To EFI by Project decide in PEI or DXE phase
|
|
// Project neeed check System not Wake from cold boot(ex: power button, WOL, RTC wake..., etc).
|
|
//
|
|
HobPtr = GetNextGuidHob ((CONST EFI_GUID *) &gL05StopLegacyToEfiProcessGuid, GetHobList ());
|
|
Status = OemSvcStopLegacyToEfiProcess ();
|
|
|
|
if (HobPtr != NULL || Status == EFI_MEDIA_CHANGED) {
|
|
|
|
//
|
|
// Delete L"LegacyToEfi" & L"BootNext" variable to stop process of Legacy To EFI
|
|
//
|
|
Status = gRT->SetVariable (
|
|
L"LegacyToEfi",
|
|
&gEfiGenericVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
|
|
Status = gRT->SetVariable (
|
|
L"BootNext",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Replace the ShadowAllLegacyOproms function
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiLegacyBiosProtocolGuid,
|
|
NULL,
|
|
(VOID **) &LegacyBios
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
ShadowAllLegacyOpRomsCore ();
|
|
|
|
} else {
|
|
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
HookShadowAllLegacyOproms,
|
|
NULL,
|
|
&LegacyBiosEvent
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gBS->RegisterProtocolNotify (
|
|
&gEfiLegacyBiosProtocolGuid,
|
|
LegacyBiosEvent,
|
|
&Registration
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create ReadyToBoot to make sure the "LegacyToEfi" variable be erase
|
|
//
|
|
Status = EfiCreateEventReadyToBootEx (
|
|
TPL_CALLBACK,
|
|
EraseLegacyToEfiVariable,
|
|
NULL,
|
|
&ReadyToBootEvent
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Register notification on H2O_CP_LOW of gH2OBdsCpReadyToBootBeforeGuid event for pass BbsTable pointer to SMM instance
|
|
//
|
|
Status = H2OCpRegisterHandler (
|
|
&gH2OBdsCpReadyToBootBeforeGuid,
|
|
LegacyToEfiCpHandler,
|
|
H2O_CP_MEDIUM,
|
|
&CpHandle
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// For HddPassword and OemBadgingSupportDxe module to check status of Legacy To EFI function
|
|
//
|
|
Status = gRT->SetVariable (
|
|
L"IsLegacyToEfi",
|
|
&gEfiGenericVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (IsLegacyToEfi),
|
|
&IsLegacyToEfi
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|