alder_lake_bios/Lcfc/LfcPkg/LfcWmi/Smm/LfcWmiServiceSmm.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;
}