333 lines
11 KiB
C
333 lines
11 KiB
C
//*****************************************************************************
|
|
//
|
|
//
|
|
// Copyright (c) 2012 - 2021, Hefei LCFC Information Technology Co.Ltd.
|
|
// And/or its affiliates. All rights reserved.
|
|
// Hefei LCFC Information Technology Co.Ltd. PROPRIETARY/CONFIDENTIAL.
|
|
// Use is subject to license terms.
|
|
//
|
|
//******************************************************************************
|
|
/*++
|
|
Abstract:
|
|
This driver is used LFC WMI Service, it will public BIOS WMI SSDT table, register
|
|
software SMI handler for dealing with the request by APP.
|
|
|
|
History:
|
|
Date Name Version Change Notes
|
|
2021.02.23 Steven Wang v1.00 Initial release
|
|
|
|
Module Name:
|
|
LfcWmiServiceSmm.c
|
|
--*/
|
|
|
|
#include "LfcWmiServiceSmm.h"
|
|
#include <Library/PcdLib.h>
|
|
#include <Protocol/SmmVariable.h>
|
|
#include <Library/LfcLib.h>
|
|
#include <Protocol/LenovoVariable.h>
|
|
static LFC_WMI_NVS *mLfcWmiNvs;
|
|
|
|
/**
|
|
Default LFC WMI Service Handler
|
|
**/
|
|
EFI_STATUS
|
|
DefaultLfcWmiHandler (
|
|
IN OUT LFC_WMI_NVS* LfcWmiNvs
|
|
)
|
|
{
|
|
LfcWmiNvs->ReturnCode = WMI_UNSUPPORTED;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Snap BIOS setup LFC WMI Service Handler
|
|
**/
|
|
EFI_STATUS
|
|
LfcSnapServiceHandler (
|
|
IN OUT LFC_WMI_NVS* LfcWmiNvs
|
|
)
|
|
{
|
|
/* //--temp solution, for build error
|
|
UINT32 Attributes;
|
|
IpData LfcIpDataBuffer;
|
|
EFI_STATUS Status;
|
|
EFI_SMM_VARIABLE_PROTOCOL *SmmVariable;
|
|
Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_RUNTIME_ACCESS;
|
|
Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, &SmmVariable);
|
|
ASSERT_EFI_ERROR (Status);
|
|
LfcIpDataBuffer.HostIp[0] = (UINT8)(LfcWmiNvs->Data1>>24);
|
|
LfcIpDataBuffer.HostIp[1] = (UINT8)(LfcWmiNvs->Data1>>16);
|
|
LfcIpDataBuffer.HostIp[2] = (UINT8)(LfcWmiNvs->Data1>>8);
|
|
LfcIpDataBuffer.HostIp[3] = (UINT8)(LfcWmiNvs->Data1);
|
|
|
|
LfcIpDataBuffer.ClientIp[0] = (UINT8)(LfcWmiNvs->Data2>>24);
|
|
LfcIpDataBuffer.ClientIp[1] = (UINT8)(LfcWmiNvs->Data2>>16);
|
|
LfcIpDataBuffer.ClientIp[2] = (UINT8)(LfcWmiNvs->Data2>>8);
|
|
LfcIpDataBuffer.ClientIp[3] = (UINT8)(LfcWmiNvs->Data2);
|
|
|
|
|
|
LfcIpDataBuffer.LocalMask[0] = (UINT8)(LfcWmiNvs->Data3>>24);
|
|
LfcIpDataBuffer.LocalMask[1] = (UINT8)(LfcWmiNvs->Data3>>16);
|
|
LfcIpDataBuffer.LocalMask[2] = (UINT8)(LfcWmiNvs->Data3>>8);
|
|
LfcIpDataBuffer.LocalMask[3] = (UINT8)(LfcWmiNvs->Data3);
|
|
|
|
|
|
LfcIpDataBuffer.GateWay[0] = (UINT8)(LfcWmiNvs->Data4>>24);
|
|
LfcIpDataBuffer.GateWay[1] = (UINT8)(LfcWmiNvs->Data4>>16);
|
|
LfcIpDataBuffer.GateWay[2] = (UINT8)(LfcWmiNvs->Data4>>8);
|
|
LfcIpDataBuffer.GateWay[3] = (UINT8)(LfcWmiNvs->Data4);
|
|
|
|
LfcIpDataBuffer.Port =( (UINT32)(LfcWmiNvs->BlockData[3])<<24)|( (UINT32)(LfcWmiNvs->BlockData[2])<<16)|( (UINT32)(LfcWmiNvs->BlockData[1])<<8)|(UINT32)(LfcWmiNvs->BlockData[0]);
|
|
|
|
DEBUG ((DEBUG_INFO, "BlockData3 Status =%d \n",LfcWmiNvs->BlockData[3]));
|
|
DEBUG ((DEBUG_INFO, "BlockData2 Status =%d \n",LfcWmiNvs->BlockData[2]));
|
|
DEBUG ((DEBUG_INFO, "BlockData1 Status =%d \n",LfcWmiNvs->BlockData[1]));
|
|
DEBUG ((DEBUG_INFO, "BlockData0 Status =%d \n",LfcWmiNvs->BlockData[0]));
|
|
|
|
Status = SmmVariable->SmmSetVariable (
|
|
LCFC_VARIABLE_IP_VARIABLE_NAME,
|
|
&gLfcIpVariableGuid,
|
|
Attributes,
|
|
sizeof(IpData),
|
|
&LfcIpDataBuffer
|
|
);
|
|
|
|
|
|
LfcWmiNvs->ReturnCode = LfcIpDataBuffer.Port;
|
|
*/
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
LfcsetBIOSVariableHandler (
|
|
IN OUT LFC_WMI_NVS* LfcWmiNvs
|
|
)
|
|
{
|
|
/*
|
|
EFI_STATUS Status;
|
|
UINT32 DataLength = sizeof(UINT8);
|
|
UINT8 TestData;
|
|
EFI_GUID gEfigettestGuid;
|
|
LENOVO_VARIABLE_PROTOCOL *LenovoVariable = NULL;
|
|
|
|
Status = gSmst->SmmLocateProtocol (&gLenovoVariableProtocolGuid, NULL, &LenovoVariable);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
gEfigettestGuid.Data1 = LfcWmiNvs->Data1;
|
|
gEfigettestGuid.Data2 = (UINT16)((LfcWmiNvs->Data2)>>16);
|
|
gEfigettestGuid.Data3 = (UINT16)((LfcWmiNvs->Data2)&0x0000FFFF);
|
|
gEfigettestGuid.Data4[0] =(UINT8)((LfcWmiNvs->Data3) >> 24);
|
|
gEfigettestGuid.Data4[1] =(UINT8)((LfcWmiNvs->Data3) >> 16);
|
|
gEfigettestGuid.Data4[2] =(UINT8)((LfcWmiNvs->Data3) >> 8);
|
|
gEfigettestGuid.Data4[3] =(UINT8)(LfcWmiNvs->Data3);
|
|
gEfigettestGuid.Data4[4] =(UINT8)((LfcWmiNvs->Data4) >> 24);
|
|
gEfigettestGuid.Data4[5] =(UINT8)((LfcWmiNvs->Data4) >> 16);
|
|
gEfigettestGuid.Data4[6] =(UINT8)((LfcWmiNvs->Data4) >> 8);
|
|
gEfigettestGuid.Data4[7] =(UINT8)(LfcWmiNvs->Data4);
|
|
//set lenovo variable
|
|
//TestData = (LfcWmiNvs->BlockData[3]<<24) + (LfcWmiNvs->BlockData[2]<<16) + (LfcWmiNvs->BlockData[1]<<8) + (LfcWmiNvs->BlockData[0]);
|
|
TestData = LfcWmiNvs->BlockData[0];
|
|
Status = LenovoVariable->SetVariable (
|
|
LenovoVariable,
|
|
&gEfigettestGuid,
|
|
DataLength,
|
|
&TestData);
|
|
|
|
//get lenovo variable , read the value and return
|
|
Status = LenovoVariable->GetVariable (
|
|
LenovoVariable,
|
|
&gEfigettestGuid,
|
|
&DataLength,
|
|
&TestData
|
|
);
|
|
LfcWmiNvs->ReturnCode= TestData;
|
|
*/
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// LFC WMI SMI interface table
|
|
//
|
|
static LFC_WMI_SMI_HANDLER mLfcCommonWmiSmiHandlers[] = {
|
|
DefaultLfcWmiHandler,
|
|
LfcWmiEcServiceHandler, // 01: WMI Tools Service
|
|
LfcSnapServiceHandler, // 02: MBV WMI Snap Service
|
|
LfcsetBIOSVariableHandler // 03: Set BIOS variable
|
|
};
|
|
|
|
/**
|
|
Software SMI callback for handle the request from BIOS WMI ASL.
|
|
|
|
Caution: This function may receive untrusted input.
|
|
Variable and ACPINvs are external input, so this function will validate
|
|
its data structure to be valid value.
|
|
|
|
@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 interrupt was handled successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
LfcWmiServiceCallback (
|
|
IN EFI_HANDLE DispatchHandle,
|
|
IN CONST VOID *Context,
|
|
IN OUT VOID *CommBuffer,
|
|
IN OUT UINTN *CommBufferSize
|
|
)
|
|
{
|
|
// Clear return code
|
|
mLfcWmiNvs->ReturnCode = WMI_SUCCESS;
|
|
|
|
//
|
|
// Dispatch LFC WMI handler.
|
|
//
|
|
if (mLfcWmiNvs->Cmd < sizeof(mLfcCommonWmiSmiHandlers)/sizeof(LFC_WMI_SMI_HANDLER)) {
|
|
return mLfcCommonWmiSmiHandlers[mLfcWmiNvs->Cmd].Function (mLfcWmiNvs);
|
|
}
|
|
|
|
mLfcWmiNvs->ReturnCode = WMI_UNSUPPORTED;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Find the operation region in BIOS WMI ACPI table by given Name and Size,
|
|
and initialize it if the region is found.
|
|
|
|
@param[in, out] Table The BIOS WMI item in ACPI table.
|
|
@param[in] Name The name string to find in BIOS WMI table.
|
|
@param[in] Size The size of the region to find.
|
|
|
|
@return The allocated address for the found region.
|
|
|
|
**/
|
|
VOID *
|
|
AssignOpRegion (
|
|
EFI_ACPI_DESCRIPTION_HEADER *Table,
|
|
UINT32 Name,
|
|
UINT16 Size
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
AML_OP_REGION_32_16 *OpRegion;
|
|
EFI_PHYSICAL_ADDRESS MemoryAddress;
|
|
|
|
MemoryAddress = SIZE_4GB - 1;
|
|
|
|
//
|
|
// Patch some pointers for the ASL code before loading the SSDT.
|
|
//
|
|
for (OpRegion = (AML_OP_REGION_32_16 *) (Table + 1);
|
|
OpRegion <= (AML_OP_REGION_32_16 *) ((UINT8 *) Table + Table->Length);
|
|
OpRegion = (AML_OP_REGION_32_16 *) ((UINT8 *) OpRegion + 1)) {
|
|
if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) &&
|
|
(OpRegion->NameString == Name) &&
|
|
(OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&
|
|
(OpRegion->BytePrefix == AML_WORD_PREFIX)) {
|
|
|
|
Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);
|
|
ASSERT_EFI_ERROR (Status);
|
|
ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);
|
|
OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;
|
|
OpRegion->RegionLen = Size;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (VOID *) (UINTN) MemoryAddress;
|
|
}
|
|
|
|
/**
|
|
Initialize and publish BIOS WMI SSDT table in ACPI table.
|
|
|
|
@retval EFI_SUCCESS BIOS WMI SSDT table is published successfully.
|
|
@retval Others BIOS WMI SSDT table is not published.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
PublishLfcWmiAcpiTable (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
|
|
UINTN TableKey;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Table;
|
|
UINTN TableSize;
|
|
|
|
Status = GetSectionFromFv (
|
|
&gEfiCallerIdGuid,
|
|
EFI_SECTION_RAW,
|
|
0,
|
|
(VOID **) &Table,
|
|
&TableSize
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
ASSERT (Table->OemTableId == SIGNATURE_64 ('W', 'm', 'i', 'T', 'a', 'b', 'l', 'e'));
|
|
CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );
|
|
|
|
mLfcWmiNvs = AssignOpRegion (Table, SIGNATURE_32 ('L', 'N', 'V', 'S'), (UINT16) sizeof (LFC_WMI_NVS));
|
|
ASSERT (mLfcWmiNvs != NULL);
|
|
mLfcWmiNvs->Signature = SIGNATURE_32 ('_', 'L', 'F', 'C');
|
|
|
|
//
|
|
// Publish the BIOS WMI ACPI table
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
TableKey = 0;
|
|
Status = AcpiTable->InstallAcpiTable (
|
|
AcpiTable,
|
|
Table,
|
|
TableSize,
|
|
&TableKey
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
The driver's entry point.
|
|
|
|
It install software SMI callbacks for communication between WMI asl and Smm c code.
|
|
|
|
@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
|
|
LfcWmiServiceSmmEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
|
|
EFI_SMM_SW_REGISTER_CONTEXT SwContext;
|
|
EFI_HANDLE SwHandle;
|
|
|
|
Status = PublishLfcWmiAcpiTable ();
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Get the Sw dispatch protocol and register SMI callback functions.
|
|
//
|
|
Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);
|
|
if (!EFI_ERROR(Status)) {
|
|
SwContext.SwSmiInputValue = SMM_LFC_WMI_SERVICE_SMI;
|
|
Status = SwDispatch->Register (SwDispatch, (EFI_SMM_HANDLER_ENTRY_POINT2) LfcWmiServiceCallback, &SwContext, &SwHandle);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|