//***************************************************************************** // // // 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 #include #include #include 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; }