821 lines
24 KiB
C
821 lines
24 KiB
C
/** @file
|
|
Smm Int15 Service Driver
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2020, 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 "Int15ServiceSmm.h"
|
|
|
|
UINT16 mInt15Count = 0;
|
|
EFI_SMM_SYSTEM_TABLE2 *mSmst;
|
|
INT15_SERVICE_INSTANCE *mInt15ServiceInstance = NULL;
|
|
EFI_SMM_CPU_PROTOCOL *mSmmCpu = NULL;
|
|
INT15_PRIVATE_DATA *mInt15PrivateData;
|
|
/**
|
|
Install Int15 OpRom to shadow ram
|
|
|
|
@retval EFI_SUCCESS Install Int15 OpRom successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InstallInt15OpRom (
|
|
);
|
|
|
|
/**
|
|
Install SmmInt15service Protocol
|
|
|
|
@retval EFI_SUCCESS Install SmmInt15service Protocol successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InstallSmmInt15ServiceProtocol (
|
|
);
|
|
|
|
/**
|
|
This function is invoked when gEfiLegacyBiosProtocolGuid is installed
|
|
|
|
@param[in] Event The triggered event.
|
|
@param[in] Context Context for this event.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
InstallInt15ServiceNotifyFunction (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
);
|
|
|
|
/**
|
|
INT15 SW SMI callback
|
|
|
|
@param Handle The unique handle assigned to this handler by SmiHandlerRegister().
|
|
@param Context Points to an optional handler context which was specified when the
|
|
handler was registered.
|
|
@param CommBuffer A pointer to a collection of data in memory that will
|
|
be conveyed from a non-SMM environment into an SMM environment.
|
|
@param CommBufferSize The size of the CommBuffer.
|
|
|
|
@retval EFI_SUCCESS The callabck was handled successfully.
|
|
@retval EFI_NOT_FOUND Cannot determine the source of SMI.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
INT15SwSmiCallback (
|
|
IN EFI_HANDLE Handle,
|
|
IN CONST VOID *Context,
|
|
IN OUT VOID *CommBuffer,
|
|
IN OUT UINTN *CommBufferSize
|
|
);
|
|
|
|
/**
|
|
INT15 Smm Callback of EFI_INT15_SERVICE_PROTOCOL
|
|
|
|
@param[in] CpuRegisters Point to Cpu registers.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
SmmInt15CallBack (
|
|
IN OUT EFI_IA32_REGISTER_SET *CpuRegisters
|
|
);
|
|
|
|
/**
|
|
Initializes the INT15 SMM Dispatcher
|
|
|
|
@param[in] ImageHandle Pointer to the loaded image protocol for this driver.
|
|
@param[in] SystemTable Pointer to the EFI System Table
|
|
|
|
@retval EFI_SUCCESS The call returned successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Int15ServiceDriverEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN InSmm;
|
|
EFI_SMM_BASE2_PROTOCOL *SmmBase;
|
|
EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
|
|
EFI_SMM_SW_REGISTER_CONTEXT SwContext;
|
|
EFI_HANDLE SwHandle;
|
|
INT15_DATA_PACKET *Int15DataPacketDummy;
|
|
EFI_OEM_INT15_CALLBACK *OemInt15Callback;
|
|
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
|
|
EFI_EVENT LegacyBiosEvent;
|
|
VOID *Registration;
|
|
|
|
OemInt15Callback = NULL;
|
|
InSmm = FALSE;
|
|
|
|
Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID **)&SmmBase);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
SmmBase->InSmm (SmmBase, &InSmm);
|
|
if (!InSmm) {
|
|
//
|
|
// Locate LegacyBios Protocol
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **)&LegacyBios);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
InstallInt15ServiceNotifyFunction (NULL, NULL);
|
|
} else {
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
InstallInt15ServiceNotifyFunction,
|
|
NULL,
|
|
&LegacyBiosEvent
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
Status = gBS->RegisterProtocolNotify (
|
|
&gEfiLegacyBiosProtocolGuid,
|
|
LegacyBiosEvent,
|
|
&Registration
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// Great! We're now in SMM!
|
|
// Initialize global variables
|
|
//
|
|
Status = SmmBase->GetSmstLocation (SmmBase, &mSmst);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = mSmst->SmmLocateProtocol (
|
|
&gEfiSmmSwDispatch2ProtocolGuid,
|
|
NULL,
|
|
(VOID **)&SwDispatch
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Register SwSmi for ATA Legacy services
|
|
//
|
|
SwContext.SwSmiInputValue = COMMON_INT15_SMI;
|
|
|
|
Status = SwDispatch->Register (
|
|
SwDispatch,
|
|
INT15SwSmiCallback,
|
|
&SwContext,
|
|
&SwHandle
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Initialize INT15DataPacketDummy
|
|
//
|
|
Int15DataPacketDummy = AllocatePool (sizeof (INT15_DATA_PACKET));
|
|
if (Int15DataPacketDummy == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
ZeroMem (Int15DataPacketDummy, sizeof (INT15_DATA_PACKET));
|
|
|
|
Int15DataPacketDummy->Signature = INT15_DATA_SIGNATURE;
|
|
InitializeListHead (&Int15DataPacketDummy->FunctionLinkList);
|
|
|
|
//
|
|
// Initialize OemInt15Callback
|
|
//
|
|
OemInt15Callback = AllocatePool (sizeof (EFI_OEM_INT15_CALLBACK));
|
|
if (OemInt15Callback == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
ZeroMem (OemInt15Callback, sizeof (EFI_OEM_INT15_CALLBACK));
|
|
|
|
//
|
|
// Initialize Int15ServiceInstance
|
|
//
|
|
mInt15ServiceInstance = AllocatePool (sizeof (INT15_SERVICE_INSTANCE));
|
|
if (mInt15ServiceInstance == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
ZeroMem (mInt15ServiceInstance, sizeof (INT15_SERVICE_INSTANCE));
|
|
|
|
mInt15ServiceInstance->Int15DataPacketDummy = Int15DataPacketDummy;
|
|
mInt15ServiceInstance->OemInt15Callback = OemInt15Callback;
|
|
Status = gBS->LocateProtocol(
|
|
&gInt15PrivateDataGuid,
|
|
NULL,
|
|
(VOID **)&mInt15PrivateData
|
|
);
|
|
Status = InstallSmmInt15ServiceProtocol ();
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Install SmmInt15service Protocol
|
|
|
|
@retval EFI_SUCCESS Install SmmInt15service Protocol successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InstallSmmInt15ServiceProtocol (
|
|
)
|
|
{
|
|
INT15_PRIVATE_INFO *Int15PrivateInfo;
|
|
EFI_HANDLE Handle;
|
|
EFI_STATUS Status;
|
|
|
|
if (mInt15PrivateData != NULL) {
|
|
|
|
Int15PrivateInfo = (INT15_PRIVATE_INFO*)((UINTN)((UINTN)mInt15PrivateData->CpuRegistersSegment << 4));
|
|
|
|
Int15PrivateInfo->SmmInt15CallbackPtr = (UINTN)SmmInt15CallBack;
|
|
|
|
mInt15ServiceInstance->Signature = INT15_SERVICE_INSTANCE_SIGNATURE;
|
|
mInt15ServiceInstance->FunctionListSegment = mInt15PrivateData->FunctionListSegment;
|
|
mInt15ServiceInstance->CpuRegistersSegment = mInt15PrivateData->CpuRegistersSegment;
|
|
mInt15ServiceInstance->Int15Service.InstallInt15ProtocolInterface = InstallInt15ProtocolInterface;
|
|
mInt15ServiceInstance->Int15Service.ReinstallInt15ProtocolInterface = ReinstallInt15ProtocolInterface;
|
|
//
|
|
// Install SmmInt15Service in SMM
|
|
//
|
|
Handle = NULL;
|
|
Status = mSmst->SmmInstallProtocolInterface (
|
|
&Handle,
|
|
&gEfiSmmInt15ServiceProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&mInt15ServiceInstance->Int15Service
|
|
);
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is invoked when gEfiLegacyBiosProtocolGuid is installed
|
|
|
|
@param[in] Event The triggered event.
|
|
@param[in] Context Context for this event.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
InstallInt15ServiceNotifyFunction (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_HANDLE Handle;
|
|
EFI_STATUS Status;
|
|
EFI_SMM_INT15_SERVICE_PROTOCOL *SmmInt15Service;
|
|
|
|
if (Event != NULL) {
|
|
gBS->CloseEvent (Event);
|
|
}
|
|
|
|
//
|
|
// Install common Int15 OpRom
|
|
//
|
|
InstallInt15OpRom ();
|
|
|
|
//
|
|
// Install gEfiSmmInt15ServiceProtocolGuid in DXE for dependency
|
|
//
|
|
Handle = NULL;
|
|
Status = gBS->InstallProtocolInterface (
|
|
&Handle,
|
|
&gEfiSmmInt15ServiceProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Check the gEfiSmmInt15ServiceProtocolGuid in DXE whether installed or not
|
|
//
|
|
SmmInt15Service = NULL;
|
|
Status = gBS->LocateProtocol (&gEfiSmmInt15ServiceProtocolGuid, NULL, (VOID **)&SmmInt15Service);
|
|
if (!EFI_ERROR(Status)) {
|
|
IoWrite8 (SW_SMI_PORT, COMMON_INT15_SMI);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Install Int15 OpRom to shadow ram
|
|
|
|
@retval EFI_SUCCESS Install Int15 OpRom successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InstallInt15OpRom (
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *FvHandles;
|
|
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
|
|
EFI_LEGACY_REGION2_PROTOCOL *LegacyRegion;
|
|
EFI_IA32_REGISTER_SET Regs;
|
|
EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
|
|
UINTN Index;
|
|
UINTN HandlesCounter;
|
|
BOOLEAN ImageFound;
|
|
VOID *Table;
|
|
UINTN TableSize;
|
|
UINTN TablePtr;
|
|
UINT16 MaxOemInt15FuListSize;
|
|
UINT16 CpuRegistersSize;
|
|
UINT8 *Ptr;
|
|
EFI_COMPATIBILITY16_TABLE *EfiTable;
|
|
INT15_PRIVATE_DATA *Int15PrivateData;
|
|
EFI_HANDLE Handle;
|
|
UINT32 FileAuthenticationStatus;
|
|
|
|
Table = NULL;
|
|
TableSize = 0;
|
|
EfiTable = NULL;
|
|
ImageFound = FALSE;
|
|
//
|
|
// Get Int15 OpRom image
|
|
//
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
NULL,
|
|
&HandlesCounter,
|
|
&FvHandles
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
for (Index = 0; Index < HandlesCounter; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
*(FvHandles + Index),
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
(VOID **)&FwVol
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
Status = FwVol->ReadSection (
|
|
FwVol,
|
|
PcdGetPtr (PcdInt15ServiceSmmRomFile),
|
|
EFI_SECTION_RAW,
|
|
0,
|
|
&Table,
|
|
&TableSize,
|
|
&FileAuthenticationStatus
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
ImageFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Locate LegacyBios Protocol
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiLegacyBiosProtocolGuid,
|
|
NULL,
|
|
(VOID **)&LegacyBios
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Locate LegacyRegion Protocol
|
|
//
|
|
Status = gBS->LocateProtocol(
|
|
&gEfiLegacyRegion2ProtocolGuid,
|
|
NULL,
|
|
(VOID **)&LegacyRegion
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Get EFI table from F segment
|
|
//
|
|
for (Ptr = (UINT8 *)((UINTN)0xFE000); Ptr < (UINT8 *) ((UINTN) 0x100000); Ptr = (UINT8 *) ((UINTN) Ptr + 0x10)) {
|
|
if (*(UINT32 *) Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) {
|
|
EfiTable = (EFI_COMPATIBILITY16_TABLE *) Ptr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (EfiTable == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "No Legacy16 table found\n"));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Status = LegacyRegion->UnLock (LegacyRegion, 0xE0000, 0x20000, NULL);
|
|
//
|
|
// 16 bytes boundary alignment
|
|
//
|
|
MaxOemInt15FuListSize = (MAX_OEM_INT15_FN_COUNT * 2) + ((0x10 - ((MAX_OEM_INT15_FN_COUNT * 2) % 0x10)) & ~0x10);
|
|
|
|
CpuRegistersSize = sizeof (INT15_PRIVATE_INFO) + ((0x10 - (sizeof (INT15_PRIVATE_INFO) % 0x10)) & ~0x10);
|
|
|
|
//
|
|
// Allocate shadow ram for INT15 OpRom and private data(Function list / Cpu registers)
|
|
//
|
|
ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
|
|
Regs.X.AX = Legacy16GetTableAddress;
|
|
Regs.X.BX = 0x02;//E0000Region;
|
|
Regs.X.CX = (UINT16) TableSize + MaxOemInt15FuListSize + CpuRegistersSize;
|
|
Regs.X.DX = 1;
|
|
Status = LegacyBios->FarCall86 (
|
|
LegacyBios,
|
|
EfiTable->Compatibility16CallSegment,
|
|
EfiTable->Compatibility16CallOffset,
|
|
&Regs,
|
|
NULL,
|
|
0
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
TablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
|
|
|
|
//
|
|
// Initialize Int15PrivateData
|
|
//
|
|
Int15PrivateData = AllocateReservedPool (sizeof (INT15_PRIVATE_DATA));
|
|
|
|
if (Int15PrivateData == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "AllocatePool failed\n"));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ZeroMem (Int15PrivateData, sizeof (INT15_PRIVATE_DATA));
|
|
|
|
Int15PrivateData->FunctionListSegment = (UINT16)(TablePtr >> 4);
|
|
|
|
Int15PrivateData->CpuRegistersSegment = Int15PrivateData->FunctionListSegment + (MaxOemInt15FuListSize >> 4);
|
|
|
|
//
|
|
// Initialize the OEM Int15 function list and CPU registers
|
|
//
|
|
ZeroMem ((VOID *)TablePtr, MaxOemInt15FuListSize + CpuRegistersSize);
|
|
|
|
TablePtr = TablePtr + MaxOemInt15FuListSize + CpuRegistersSize;
|
|
|
|
//
|
|
// To copy the Int15 image to shadow memory
|
|
//
|
|
CopyMem((UINT8 *)TablePtr, (UINT8 *)Table, TableSize);
|
|
|
|
//
|
|
// call into our BIN file for change the INT15
|
|
//
|
|
ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
|
|
Regs.X.AX = COMMON_INT15_SMI;
|
|
Regs.X.CX = MAX_OEM_INT15_FN_COUNT;
|
|
Regs.X.DX = SW_SMI_PORT;
|
|
Regs.X.DS = Int15PrivateData->FunctionListSegment;
|
|
Regs.X.ES = Int15PrivateData->CpuRegistersSegment;
|
|
Status = LegacyBios->FarCall86 (
|
|
LegacyBios,
|
|
(UINT16)(TablePtr >> 4),
|
|
0x03,
|
|
&Regs,
|
|
NULL,
|
|
0
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = LegacyRegion->Lock (LegacyRegion, 0xE0000, 0x20000, NULL);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "LegacyRegion Lock(%r)\n", Status));
|
|
}
|
|
//
|
|
// Install gInt15PrivateDataGuid for Smm Int15ServiceInstance
|
|
//
|
|
Handle = NULL;
|
|
Status = gBS->InstallProtocolInterface (
|
|
&Handle,
|
|
&gInt15PrivateDataGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
Int15PrivateData
|
|
);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Install Int15 function interface
|
|
|
|
@param[in] This Point to EFI_INT15_SERVICE_PROTOCOL.
|
|
@param[in] FunctionNum Oem Int15 function number
|
|
@param[in] FunctionPtr Oem Int15 function point
|
|
@param[in] Context Oem Int15 Context point
|
|
|
|
@retval EFI_SUCCESS The call returned successfully.
|
|
@retval EFI_ALREADY_STARTED The same as INT15 function number
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter
|
|
@retval EFI_OUT_OF_RESOURCES The Int15 function count is greater than MAX_OEM_INT15_FN_COUNT
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InstallInt15ProtocolInterface (
|
|
IN EFI_SMM_INT15_SERVICE_PROTOCOL *This,
|
|
IN UINT16 FunctionNum,
|
|
IN EFI_OEM_INT15_CALLBACK_FUNCTION FunctionPtr,
|
|
IN VOID *Context OPTIONAL
|
|
)
|
|
{
|
|
INT15_DATA_PACKET *Int15DataPacket;
|
|
INT15_DATA_PACKET *Int15DataPacketDummy;
|
|
LIST_ENTRY *Link;
|
|
UINT16 *FunctionListAddress;
|
|
|
|
if (FunctionNum == 0 || FunctionPtr == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (mInt15Count >= MAX_OEM_INT15_FN_COUNT) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Int15DataPacketDummy = mInt15ServiceInstance->Int15DataPacketDummy;
|
|
|
|
//
|
|
// Check the same as INT15 function number
|
|
//
|
|
for (Link = Int15DataPacketDummy->FunctionLinkList.ForwardLink;
|
|
Link != &Int15DataPacketDummy->FunctionLinkList;
|
|
Link = Link->ForwardLink) {
|
|
|
|
Int15DataPacket = CR(Link, INT15_DATA_PACKET, FunctionLinkList, INT15_DATA_SIGNATURE);
|
|
|
|
if (Int15DataPacket->FunctionNum == FunctionNum) {
|
|
//
|
|
// Already install the Int15 function
|
|
//
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
}
|
|
|
|
//
|
|
// allocate new Int15 Data Packet
|
|
//
|
|
Int15DataPacket = AllocatePool (sizeof (INT15_DATA_PACKET));
|
|
if (Int15DataPacket == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ZeroMem (Int15DataPacket, sizeof (INT15_DATA_PACKET));
|
|
//
|
|
// Initialize new INT15 data structure
|
|
//
|
|
Int15DataPacket->Signature = INT15_DATA_SIGNATURE;
|
|
InsertTailList (&Int15DataPacketDummy->FunctionLinkList, &Int15DataPacket->FunctionLinkList);
|
|
|
|
Int15DataPacket->FunctionNum = FunctionNum;
|
|
Int15DataPacket->FunctionPtr = (UINTN)FunctionPtr;
|
|
if (Context != NULL) Int15DataPacket->ContextPtr = (UINTN)Context;
|
|
|
|
//
|
|
// Save INT15 function number for INT15 OpRom
|
|
//
|
|
FunctionListAddress = (UINT16 *)(UINTN)((mInt15ServiceInstance->FunctionListSegment << 4) + mInt15Count * 2);
|
|
*FunctionListAddress = FunctionNum;
|
|
|
|
mInt15Count++;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Re-Install Int15 function interface
|
|
|
|
@param[in] This Point to EFI_INT15_SERVICE_PROTOCOL.
|
|
@param[in] FunctionNum Oem Int15 function number
|
|
@param[in] FunctionPtr Oem Int15 function point
|
|
@param[in] Context Oem Int15 Context point
|
|
|
|
@retval EFI_SUCCESS The call returned successfully.
|
|
@retval EFI_NOT_FOUND Can't find the Int15 function number
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ReinstallInt15ProtocolInterface (
|
|
IN EFI_SMM_INT15_SERVICE_PROTOCOL *This,
|
|
IN UINT16 FunctionNum,
|
|
IN EFI_OEM_INT15_CALLBACK_FUNCTION FunctionPtr,
|
|
IN VOID *Context OPTIONAL
|
|
)
|
|
{
|
|
INT15_DATA_PACKET *Int15DataPacket;
|
|
LIST_ENTRY *Link;
|
|
INT15_DATA_PACKET *Int15DataPacketDummy;
|
|
|
|
if (FunctionNum == 0 || FunctionPtr == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Int15DataPacketDummy = mInt15ServiceInstance->Int15DataPacketDummy;
|
|
|
|
//
|
|
// Reinstall INT15 function
|
|
//
|
|
for (Link = Int15DataPacketDummy->FunctionLinkList.ForwardLink;
|
|
Link != &Int15DataPacketDummy->FunctionLinkList;
|
|
Link = Link->ForwardLink) {
|
|
|
|
Int15DataPacket = CR(Link, INT15_DATA_PACKET, FunctionLinkList, INT15_DATA_SIGNATURE);
|
|
|
|
if (Int15DataPacket->FunctionNum == FunctionNum) {
|
|
//
|
|
// Already install the Int15 function
|
|
//
|
|
Int15DataPacket->FunctionPtr = (UINTN)FunctionPtr;
|
|
if (Context != NULL) Int15DataPacket->ContextPtr = (UINTN)Context;
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
INT15 Smm Callback of EFI_INT15_SERVICE_PROTOCOL
|
|
|
|
@param[in] CpuRegisters Point to Cpu registers.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
SmmInt15CallBack (
|
|
IN OUT EFI_IA32_REGISTER_SET *CpuRegisters
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
INT15_DATA_PACKET *Int15DataPacket;
|
|
INT15_DATA_PACKET *Int15DataPacketDummy;
|
|
EFI_OEM_INT15_CALLBACK *OemInt15Callback;
|
|
VOID *OemContext;
|
|
|
|
OemInt15Callback = NULL;
|
|
OemContext = NULL;
|
|
Int15DataPacketDummy = mInt15ServiceInstance->Int15DataPacketDummy;
|
|
|
|
//
|
|
// Search the INT15 function number
|
|
//
|
|
for (Link = Int15DataPacketDummy->FunctionLinkList.ForwardLink;
|
|
Link != &Int15DataPacketDummy->FunctionLinkList;
|
|
Link = Link->ForwardLink) {
|
|
|
|
Int15DataPacket = CR(Link, INT15_DATA_PACKET, FunctionLinkList, INT15_DATA_SIGNATURE);
|
|
|
|
if (Int15DataPacket->FunctionNum == CpuRegisters->X.AX) {
|
|
//
|
|
// Find the INT15 function
|
|
//
|
|
OemInt15Callback = mInt15ServiceInstance->OemInt15Callback;
|
|
OemInt15Callback->Funcs = (EFI_OEM_INT15_CALLBACK_FUNCTION)(UINTN)Int15DataPacket->FunctionPtr;
|
|
if (Int15DataPacket->ContextPtr) {
|
|
OemContext = (VOID *)(UINTN)Int15DataPacket->ContextPtr;
|
|
}
|
|
//
|
|
// Oem Int15 callback function
|
|
//
|
|
OemInt15Callback->Funcs (CpuRegisters, OemContext);
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
INT15 SW SMI callback
|
|
|
|
@param Handle The unique handle assigned to this handler by SmiHandlerRegister().
|
|
@param Context Points to an optional handler context which was specified when the
|
|
handler was registered.
|
|
@param CommBuffer A pointer to a collection of data in memory that will
|
|
be conveyed from a non-SMM environment into an SMM environment.
|
|
@param CommBufferSize The size of the CommBuffer.
|
|
|
|
@retval EFI_SUCCESS The callabck was handled successfully.
|
|
@retval EFI_NOT_FOUND Cannot determine the source of SMI.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
INT15SwSmiCallback (
|
|
IN EFI_HANDLE Handle,
|
|
IN CONST VOID *Context,
|
|
IN OUT VOID *CommBuffer,
|
|
IN OUT UINTN *CommBufferSize
|
|
)
|
|
{
|
|
EFI_IA32_REGISTER_SET *CpuRegisters;
|
|
EFI_SMM_CPU_PROTOCOL *SmmCpu;
|
|
UINTN Index;
|
|
EFI_STATUS Status;
|
|
UINT32 Eax;
|
|
UINT32 Edx;
|
|
|
|
CpuRegisters = NULL;
|
|
SmmCpu = NULL;
|
|
Eax = 0;
|
|
Edx = 0;
|
|
|
|
if (mInt15ServiceInstance->CpuRegistersSegment == 0) {
|
|
Status = InstallSmmInt15ServiceProtocol ();
|
|
return Status;
|
|
}
|
|
//
|
|
// Locate Smm Cpu protocol for Cpu save state manipulation
|
|
//
|
|
Status = mSmst->SmmLocateProtocol (
|
|
&gEfiSmmCpuProtocolGuid,
|
|
NULL,
|
|
(VOID **)&SmmCpu
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Find out which CPU triggered the S/W SMI
|
|
//
|
|
for (Index = 0; Index < mSmst->NumberOfCpus; Index++) {
|
|
SmmCpu->ReadSaveState (
|
|
SmmCpu,
|
|
sizeof (UINT32),
|
|
EFI_SMM_SAVE_STATE_REGISTER_RAX,
|
|
Index,
|
|
&Eax
|
|
);
|
|
|
|
SmmCpu->ReadSaveState (
|
|
SmmCpu,
|
|
sizeof (UINT32),
|
|
EFI_SMM_SAVE_STATE_REGISTER_RDX,
|
|
Index,
|
|
&Edx
|
|
);
|
|
|
|
if (((Eax & 0xff) == COMMON_INT15_SMI) && ((Edx & 0xffff) == SW_SMI_PORT)) {
|
|
//
|
|
// CPU found!
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
if (Index == mSmst->NumberOfCpus) {
|
|
//
|
|
// Error out due to CPU not found
|
|
//
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Get Cpu registers of caller
|
|
//
|
|
CpuRegisters = AllocateCopyPool (sizeof (EFI_IA32_REGISTER_SET), (VOID*)((UINTN)((UINTN)mInt15ServiceInstance->CpuRegistersSegment << 4)));
|
|
if (CpuRegisters == NULL) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Call Oem Int15 callback function
|
|
//
|
|
SmmInt15CallBack (CpuRegisters);
|
|
//
|
|
// Restore data from SMRAM to parameter communication buffer.
|
|
//
|
|
CopyMem ((VOID*)((UINTN)((UINTN)mInt15ServiceInstance->CpuRegistersSegment << 4)), CpuRegisters, sizeof (EFI_IA32_REGISTER_SET));
|
|
FreePool (CpuRegisters);
|
|
return EFI_SUCCESS;
|
|
}
|