/** @file Provide functions for WMI SMM Service ;****************************************************************************** ;* Copyright (c) 2018, 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 "WmiSetupUnderOsSmm.h" BOOLEAN mAlreadyInitWmiSetupUnderOs = FALSE; BOOLEAN mSystemBusy = FALSE; EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL; EFI_L05_GLOBAL_NVS_AREA *mL05GlobalNVSArea = NULL; L05_WMI_SETUP_ITEM mL05WmiSetupItem; CHAR8 *mBootOrderStr = NULL; BOOLEAN mIsSgxFeatureCtrlSet = FALSE; /** Set WMI status to buffer for return ASL used. @param WmiStatus IdeaPad BIOS setup WMI Return type. @retval EFI_SUCCESS This function execute successfully. @retval Others An unexpected error occurred. **/ EFI_STATUS SetWmiStatusToBuffer ( IN UINT8 WmiStatus ) { EFI_STATUS Status; // // Initialization // Status = EFI_UNSUPPORTED; // // WMI status report L05_WMI_ACCESS_DENIED // mL05GlobalNVSArea->L05WmiStatus = WmiStatus; // // Clean WMI buffer // ZeroMem (mL05GlobalNVSArea->L05WmiBuffer, L05_WMI_BUFFER_MAX_SIZE); // // Report status // switch (WmiStatus) { case L05_WMI_SUCCESS: Status = EFI_SUCCESS; break; case L05_WMI_NOT_SUPPORTED: Status = EFI_UNSUPPORTED; break; case L05_WMI_INVALID_PARAMETER: Status = EFI_INVALID_PARAMETER; break; case L05_WMI_ACCESS_DENIED: // // Put Access Denied status to WMI Buffer // AsciiStrCpyS (mL05GlobalNVSArea->L05WmiBuffer, L05_WMI_BUFFER_MAX_SIZE, WMI_BIOS_SETTING_RETURN_ACCESS_DENIED_STR); Status = EFI_ACCESS_DENIED; break; case L05_WMI_SYSTEM_BUSY: // // Put System Busy to WMI Buffer // AsciiStrCpyS (mL05GlobalNVSArea->L05WmiBuffer, L05_WMI_BUFFER_MAX_SIZE, WMI_BIOS_SETTING_RETURN_SYSTEM_BUSY_STR); Status = EFI_UNSUPPORTED; break; default: Status = EFI_UNSUPPORTED; break; } // // Set WMI buffer length // mL05GlobalNVSArea->L05WmiBufferLen = (UINT16) AsciiStrLen (mL05GlobalNVSArea->L05WmiBuffer); return EFI_SUCCESS; } /** Analyze WMI check password input buffer. @param PasswordStr Assign a pointer to the password string. @param PasswordEncodingStr Assign a pointer to the password encoding string. @param PasswordLanguageStr Assign a pointer to the password keyboard language string. @retval EFI_SUCCESS This function execute successfully. @retval Others An unexpected error occurred. **/ EFI_STATUS AnalyzeWmiCheckPasswordInputBuffer ( OUT CHAR8 **PasswordStr, OUT CHAR8 **PasswordEncodingStr, OUT CHAR8 **PasswordLanguageStr ) { EFI_STATUS Status; UINTN BufferOffset; UINTN TempBufferOffset; UINTN SectionCount; // // Initialization // Status = EFI_INVALID_PARAMETER; BufferOffset = 0; // // Part section // SectionCount = 0; TempBufferOffset = 0; for (BufferOffset = 0; BufferOffset < mL05GlobalNVSArea->L05WmiBufferLen; BufferOffset++) { if ((mL05GlobalNVSArea->L05WmiBuffer[BufferOffset] != ',') &&(mL05GlobalNVSArea->L05WmiBuffer[BufferOffset] != ';')) { continue; } mL05GlobalNVSArea->L05WmiBuffer[BufferOffset] = 0; switch (SectionCount) { case CheckPassword: *PasswordStr = &mL05GlobalNVSArea->L05WmiBuffer[TempBufferOffset]; break; case CheckPasswordEncoding: *PasswordEncodingStr = &mL05GlobalNVSArea->L05WmiBuffer[TempBufferOffset]; break; case CheckPasswordLanguage: *PasswordLanguageStr = &mL05GlobalNVSArea->L05WmiBuffer[TempBufferOffset]; break; } TempBufferOffset = BufferOffset; TempBufferOffset++; SectionCount++; } // // Check section number is valid // if (SectionCount == CheckPasswordMaxSection) { Status = EFI_SUCCESS; } return Status; } /** Analyze WMI input buffer. @param SelectStr A pointer to the select string. @param SelectStrLen A pointer to the Length of the select string. @param SelectItemIndex A pointer to the select item index. @param SelectStrListIndex A pointer to the select string list index. @retval EFI_SUCCESS This function execute successfully. @retval Others An unexpected error occurred. **/ EFI_STATUS AnalyzeWmiInputBuffer ( OUT CHAR8 *SelectStr, OUT UINT16 *SelectStrLen, OUT UINT8 *SelectItemIndex, OUT UINTN *SelectStrListIndex ) { EFI_STATUS Status; UINTN Index; BOOLEAN SelectStrFilter; // // Initialization // Status = EFI_SUCCESS; SelectStrFilter = FALSE; *SelectStrListIndex = (UINTN) -1; *SelectItemIndex = (UINT8) -1; *SelectStrLen = mL05GlobalNVSArea->L05WmiBufferLen; ZeroMem (SelectStr, L05_WMI_BUFFER_MAX_SIZE); // // Check if terminator (';', or '*') exist // if (mL05GlobalNVSArea->L05WmiBuffer[*SelectStrLen - 1] == ';' || mL05GlobalNVSArea->L05WmiBuffer[*SelectStrLen - 1] == '*') { // // Remove terminator // AsciiStrnCpyS (SelectStr, L05_WMI_BUFFER_MAX_SIZE, mL05GlobalNVSArea->L05WmiBuffer, (UINTN) (*SelectStrLen - 1)); } else { AsciiStrCpyS (SelectStr, L05_WMI_BUFFER_MAX_SIZE , mL05GlobalNVSArea->L05WmiBuffer); } // // Check if ',' exist, only get String before ',' // for (Index = 0; Index < AsciiStrLen (SelectStr); Index++) { if (SelectStr[Index] == ',') { SelectStrFilter = TRUE; } if (SelectStrFilter) { SelectStr[Index] = 0; } } // // Get selection string item index // for (Index = 0; Index < mWmiBiosConfigEnumMapListCount; Index++) { if (AsciiStrCmp (SelectStr, mWmiBiosConfigEnumMap[Index].BiosConfigItemName) == 0) { *SelectItemIndex = (UINT8) Index; break; } } // // Not have get selection string item index // if (*SelectItemIndex >= mWmiBiosConfigEnumMapListCount) { Status = EFI_OUT_OF_RESOURCES; return Status; } if (mWmiBiosConfigEnumMap[mL05GlobalNVSArea->L05WmiItem].ConfigDataType < SwitchConfigTypeMax) { // // Switch config type to get select String list index // for (Index = 0; Index < mWmiSelectStrListMapListCount; Index++) { if (mWmiBiosConfigEnumMap[*SelectItemIndex].ConfigDataType == mWmiSelectStrListMap[Index].ConfigDataType) { *SelectStrListIndex = Index; break; } } // // Not have get select String list index // if (Index >= mWmiSelectStrListMapListCount) { Status = EFI_OUT_OF_RESOURCES; return Status; } } return Status; } /** Get boot order string. @param BootOrder A pointer to boot order buffer. @param BootOrderCount Count of boot order. @param L05WmiBootDescription A pointer to the L05 WMI boot description. @param DelimiterChar Char of delimiter. @return Boot order string. **/ CHAR8 * GetBootOrderStr ( IN UINT16 *BootOrder, IN UINT16 BootOrderCount, IN L05_WMI_BOOT_DESCRIPTION *L05WmiBootDescription, IN CHAR8 DelimiterChar ) { CHAR8 *BootOrderStr; UINTN Index; UINTN BootOrderIndex; L05_WMI_BOOT_DESCRIPTION *TempL05WmiBootDescription; BOOLEAN NeedSortingBootDescription; UINTN BuferSize; UINTN BufferOffset; CHAR8 BootOptionTempStr[10]; CHAR8 *Ipv4NetworkStr = WMI_L05_PXE_IPV4_STRING; CHAR8 *Ipv6NetworkStr = WMI_L05_PXE_IPV6_STRING; CHAR8 *NewNetworkStr = WMI_L05_PXE_NETWROK_STRING; UINTN NewNetworkOptionCount; BOOLEAN ChangeNewNetworkStr; // // Initialization // BootOrderStr = NULL; TempL05WmiBootDescription = NULL; NeedSortingBootDescription = FALSE; NewNetworkOptionCount = 0; ChangeNewNetworkStr = FALSE; // // Count Boot Order str size // BuferSize = 0; for (Index = 0; Index < BootOrderCount; Index++) { BuferSize += AsciiStrSize ("00[]"); BuferSize += AsciiStrSize (L05WmiBootDescription[Index].BootDescription); } // // Allocate Boot Order str buffer // if (BootOrderStr == NULL) { BootOrderStr = AllocateRuntimeZeroPool (BuferSize); } if (BootOrderStr == NULL) { return BootOrderStr; } // // When Boot Order sequence is different with Boot Description will need sorting Boot Description // for (BootOrderIndex = 0; BootOrderIndex < BootOrderCount; BootOrderIndex++) { if (BootOrder[BootOrderIndex] != L05WmiBootDescription[BootOrderIndex].BootOption) { NeedSortingBootDescription = TRUE; // // Allocate resources // TempL05WmiBootDescription = AllocateRuntimeZeroPool (sizeof (L05_WMI_BOOT_DESCRIPTION) * BootOrderCount); if (TempL05WmiBootDescription == NULL) { return NULL; } break; } } if (NeedSortingBootDescription) { for (BootOrderIndex = 0; BootOrderIndex < BootOrderCount; BootOrderIndex++) { for (Index = 0; Index < BootOrderCount; Index++) { if (BootOrder[BootOrderIndex] == L05WmiBootDescription[Index].BootOption) { break; } } CopyMem (&TempL05WmiBootDescription[BootOrderIndex], &mL05WmiSetupItem.L05WmiEfiBootDescription[Index], sizeof (L05_WMI_BOOT_DESCRIPTION)); } CopyMem (mL05WmiSetupItem.L05WmiEfiBootDescription, TempL05WmiBootDescription, (sizeof (L05_WMI_BOOT_DESCRIPTION) * BootOrderCount)); FreePool (TempL05WmiBootDescription); } // // Set Boot Order string // BufferOffset = 0; BootOrderIndex = 0; for (Index = 0; Index < BootOrderCount; Index++) { // // Merge IPv4 & IPv6 string to EFI PXE NETWORK // if ((CompareMem (Ipv4NetworkStr, L05WmiBootDescription[Index].BootDescription, AsciiStrSize (Ipv4NetworkStr) - sizeof (CHAR8)) == 0x0) || (CompareMem (Ipv6NetworkStr, L05WmiBootDescription[Index].BootDescription, AsciiStrSize (Ipv6NetworkStr) - sizeof (CHAR8)) == 0x0)) { if (NewNetworkOptionCount > 0) { continue; } ChangeNewNetworkStr = TRUE; NewNetworkOptionCount++; } // // Set boot option index to boot order string // ZeroMem (BootOptionTempStr, sizeof (BootOptionTempStr)); AsciiSPrint (BootOptionTempStr, sizeof (BootOptionTempStr), "%02d", (BootOrderIndex + 1)); AsciiStrCpyS (&BootOrderStr[BufferOffset], BuferSize - (BufferOffset * sizeof (CHAR8)), BootOptionTempStr); BufferOffset += AsciiStrLen (BootOptionTempStr); // // When delimiter is ',' need set [boot description] for possible settings // if (DelimiterChar == ',') { BootOrderStr[BufferOffset] = '['; BufferOffset++; if (ChangeNewNetworkStr) { AsciiStrCpyS (&BootOrderStr[BufferOffset], BuferSize - (BufferOffset * sizeof (CHAR8)) , NewNetworkStr); BufferOffset += AsciiStrLen (NewNetworkStr); } else { AsciiStrCpyS (&BootOrderStr[BufferOffset], BuferSize - (BufferOffset * sizeof (CHAR8)), L05WmiBootDescription[Index].BootDescription); BufferOffset += AsciiStrLen (L05WmiBootDescription[Index].BootDescription); } BootOrderStr[BufferOffset] = ']'; BufferOffset++; } // // last Boot Order string not need add delimiter char // if (Index < BootOrderCount - (ChangeNewNetworkStr ? (UINTN) 2 : (UINTN) 1)) { BootOrderStr[BufferOffset] = DelimiterChar; BufferOffset++; } else { BootOrderStr[BufferOffset] = 0; BufferOffset++; } ChangeNewNetworkStr = FALSE; BootOrderIndex++; } return BootOrderStr; } /** Initialize for configuration data. @param None @retval EFI_SUCCESS This function execute successfully. @retval Others An unexpected error occurred. **/ EFI_STATUS ConfigurationDataInit ( IN BOOLEAN IsAlreadyInit ) { // // [Lenovo China Minimum BIOS Spec Version 1.38] // [3.11.2 Configuration menu] // USB legacy[Enable/Disable] // Default setting: enable, When boot mode is UEFI mode,this item must be hidden // if (mL05WmiSetupItem.L05BootMode == L05_WMI_BOOT_MODE_UEFI) { mL05WmiSetupItem.L05UsbLegacyValid = FALSE; } // // [Lenovo BIOS Setup Design Guide V2.3] // [Configuration] // Charge in Battery Mode - The item should be hidden while "Always on USB" set as "Disabled". // if (mL05WmiSetupItem.L05AlwaysOnUsb == L05_WMI_SETUP_ITEM_DISABLE) { mL05WmiSetupItem.L05ChargeInBatteryModeValid = FALSE; } return EFI_SUCCESS; } /** Initialize for security data. @param None @retval EFI_SUCCESS This function execute successfully. @retval Others An unexpected error occurred. **/ EFI_STATUS SecurityDataInit ( IN BOOLEAN IsAlreadyInit ) { if (!IsAlreadyInit) { // // Check password exist // mAdminPasswordExist = WmiIsAdminPasswordExist (); mUserPasswordExist = WmiIsUserPasswordExist (); mHddPasswordExist = WmiIsHddPasswordExist (); // // Clean password error count // mPasswordErrorCount = 0; // // Clean password check data // ZeroMem (&mPasswordCheckData, sizeof (WMI_PASSWORD_DATA_MAP)); } // // [Lenovo China Minimum BIOS Spec Version 1.37] // [3.4.1 Rules for BIOS CMOS password] // When the administrator password set, additional two submenus appeared in security menu. // Password on boot[Enable/Disable] (default disabled) // if (mAdminPasswordExist) { mL05WmiSetupItem.L05PowerOnPasswordValid = TRUE; } else { mL05WmiSetupItem.L05PowerOnPasswordValid = FALSE; } // // [Lenovo China Minimum BIOS Spec Version 1.37] // [3.4.1 Rules for BIOS CMOS password] // When the user password set, there is an additional submenu added. // - Clear User Password // if (mUserPasswordExist) { mL05WmiSetupItem.L05ClearUserPasswordValid = TRUE; } else { mL05WmiSetupItem.L05ClearUserPasswordValid = FALSE; } // // [Lenovo China Minimum BIOS Spec Version 1.38] // [3.11.3 Security menu] // Clear Intel PTT Key // Hidden if Intel PTT disabled // if (mL05WmiSetupItem.L05IntelPtt == L05_WMI_SETUP_ITEM_DISABLE) { mL05WmiSetupItem.L05ClearIntelPttKeyValid = FALSE; } // // [Lenovo China Minimum BIOS Spec Version 1.38] // [3.11.3 Security menu] // Clear AMD PSP Key // Hidden if AMD PSP disabled // if (mL05WmiSetupItem.L05AmdPsp == L05_WMI_SETUP_ITEM_DISABLE) { mL05WmiSetupItem.L05ClearAmdPspKeyValid = FALSE; } if (mL05WmiSetupItem.L05SecurityChip == L05_WMI_SETUP_ITEM_DISABLE) { mL05WmiSetupItem.L05ClearSecurityChipKeyValid = FALSE; } // // [Lenovo China Minimum BIOS Spec Version 1.38] // [10.1 Secure boot] // When boot mode set to legacy support, the Secure boot option must be disabled and hidden // if (mL05WmiSetupItem.L05BootMode == L05_WMI_BOOT_MODE_LEGACY_SUPPORT) { mL05WmiSetupItem.L05SecureBootValid = FALSE; mL05WmiSetupItem.L05SecureBoot = L05_WMI_SETUP_ITEM_DISABLE; } // // [Lenovo BIOS SetupSpec Version 2.0] // [Security] // Secure Boot Status, Hidden if [Boot Mode] = [Legacy Support]. // Platform Mode, Hidden if [Boot Mode] = [Legacy Support]. // Secure Boot Mode, Hidden if [Boot Mode] = [Legacy Support]. // Reset to Setup Mode, Hidden if [Boot Mode] = [Legacy Support]. // Restore Factory Keys, Hidden if [Boot Mode] = [Legacy Support]. // if (mL05WmiSetupItem.L05BootMode == L05_WMI_BOOT_MODE_LEGACY_SUPPORT) { mL05WmiSetupItem.L05SecureBootStatusValid = FALSE; mL05WmiSetupItem.L05PlatformModeValid = FALSE; mL05WmiSetupItem.L05SecureBootModeValid = FALSE; mL05WmiSetupItem.L05ResetToSetupModeValid = FALSE; mL05WmiSetupItem.L05RestoreFactoryKeysValid = FALSE; } return EFI_SUCCESS; } /** Initialize for boot data. @param None @retval EFI_SUCCESS This function execute successfully. @retval Others An unexpected error occurred. **/ EFI_STATUS BootDataInit ( IN BOOLEAN IsAlreadyInit ) { // // [Lenovo BIOS Setup Design Guide V2.3] // [Boot] // Hidden if [Boot Mode] = [UEFI]. // if (mL05WmiSetupItem.L05BootMode == L05_WMI_BOOT_MODE_UEFI) { mL05WmiSetupItem.L05BootPriorityValid = FALSE; } // // [Lenovo BIOS SetupSpec Version 2.0] // [Boot] // IPV4 PXE First, Hidden if PXE boot to LAN disabled. // if (mL05WmiSetupItem.L05PxeBootToLan == L05_WMI_SETUP_ITEM_DISABLE) { mL05WmiSetupItem.L05PxeIpv4FirstValid = FALSE; } return EFI_SUCCESS; } /** Initialize for WMI Setup under OS. @param None @retval EFI_SUCCESS This function execute successfully. @retval Others An unexpected error occurred. **/ EFI_STATUS InitWmiSetupUnderOs ( VOID ) { EFI_STATUS Status; if (!mAlreadyInitWmiSetupUnderOs) { // // Initialization // mBootOrderStr = NULL; // // Clean mL05WmiSetupItem // ZeroMem (&mL05WmiSetupItem, sizeof (L05_WMI_SETUP_ITEM)); // // Init mL05WmiSetupItem data // Status = L05WmiSetupItemFunc (mSmmVariable, L05WmiSetupItemInit, &mL05WmiSetupItem); } // // Init configuration data // Status = ConfigurationDataInit (mAlreadyInitWmiSetupUnderOs); // // Init security data // Status = SecurityDataInit (mAlreadyInitWmiSetupUnderOs); // // Init boot data // Status = BootDataInit (mAlreadyInitWmiSetupUnderOs); mAlreadyInitWmiSetupUnderOs = TRUE; return Status; } /** A callback function for WMI Setup Under OS. @param DispatchHandle Unused. @param DispatchContext Unused. @param CommBuffer Unused. @param CommBufferSize Unused. @retval EFI_SUCCESS This function execute successfully. @retval EFI_UNSUPPORTED The feature is not supported. @retval EFI_INVALID_PARAMETER The parameter used for operation is not valid. @retval EFI_ACCESS_DENIED The operation needs password and the password is not correct. @retval EFI_UNSUPPORTED An unexpected error occurred. **/ EFI_STATUS EFIAPI L05SmmWmiSetupUnderOsCallback ( IN EFI_HANDLE DispatchHandle, IN CONST VOID *DispatchContext, IN OUT VOID *CommBuffer, IN OUT UINTN *CommBufferSize ) { EFI_STATUS Status; // // Initialization // Status = EFI_UNSUPPORTED; // // [Lenovo China Minimum BIOS Spec Version 1.37] // [3.4 BIOS Security Passwords] // BIOS should lock the system after three invalid password attempts for // each password at the password prompt. // if (mPasswordErrorCount >= (EFI_L05_SYSTEM_PASSWORD_MAX_RETRY * 2)) { Status = SetWmiStatusToBuffer (L05_WMI_ACCESS_DENIED); return Status; } // // [Lenovo BIOS Setup using WMI Deployment Guide - Third Edition (February 2016)] // Limitations and Notes: // 1. BIOS settings cannot be changed at the same boot as power-on passwords (POP) and hard disk passwords // (HDP). If you want to change BIOS settings and POP or HDP, you must reboot the system after changing // one of them. // if (mPasswordChange) { if ((mL05GlobalNVSArea->L05WmiObjectId == L05_SET_BIOS_PASSWORD_A6)) { // // Avoid WMI call twice have return error // if (WmiInputPasswordIsRepeat ()) { Status = SetWmiStatusToBuffer (L05_WMI_SUCCESS); return Status; } } // // Clean password check data // ZeroMem (&mPasswordCheckData, sizeof (WMI_PASSWORD_DATA_MAP)); Status = SetWmiStatusToBuffer (L05_WMI_SYSTEM_BUSY); return Status; } // // When System Busy [BIOS changed have already been made that need to be committed, reboot system and try again]. // WMI status report L05_WMI_SYSTEM_BUSY & Put "System Busy" into WMI buffer. // if (mSystemBusy) { if ((mL05GlobalNVSArea->L05WmiObjectId != L05_SAVE_BIOS_SETTINGS_A2) &&(mL05GlobalNVSArea->L05WmiObjectId != L05_LOAD_DEFAULT_SETTINGS_A4)) { Status = SetWmiStatusToBuffer (L05_WMI_SYSTEM_BUSY); return Status; } } // // Init WMI setup under OS // Status = InitWmiSetupUnderOs (); if (EFI_ERROR (Status)) { return Status; } // // Call object's function // switch (mL05GlobalNVSArea->L05WmiObjectId) { case L05_BIOS_SETTING_A0: Status = WmiBiosSettingA0 (); break; case L05_SET_BIOS_SETTING_A1: Status = WmiSetBiosSettingA1 (); break; case L05_SAVE_BIOS_SETTINGS_A2: Status = WmiSaveBiosSettingsA2 (); break; case L05_DISCARD_BIOS_SETTINGS_A3: Status = WmiDiscardBiosSettingsA3 (); break; case L05_LOAD_DEFAULT_SETTINGS_A4: Status = WmiLoadDefaultSettingsA4 (); if (!EFI_ERROR (Status)) { // // After load default settings will set System Busy // mSystemBusy = TRUE; } break; case L05_BIOS_PASSWORD_SETTINGS_A5: Status = WmiBiosPasswordSettingsA5 (); break; case L05_SET_BIOS_PASSWORD_A6: Status = WmiSetBiosPasswordA6 (); break; case L05_GET_BIOS_SELECTIONS_A7: Status = WmiGetBiosSelectionsA7 (); break; default: break; } // // Report WMI status // switch (Status) { case EFI_SUCCESS: mL05GlobalNVSArea->L05WmiStatus = L05_WMI_SUCCESS; break; case EFI_UNSUPPORTED: mL05GlobalNVSArea->L05WmiStatus = L05_WMI_NOT_SUPPORTED; break; case EFI_INVALID_PARAMETER: mL05GlobalNVSArea->L05WmiStatus = L05_WMI_INVALID_PARAMETER; break; case EFI_ACCESS_DENIED: mL05GlobalNVSArea->L05WmiStatus = L05_WMI_ACCESS_DENIED; break; default: mL05GlobalNVSArea->L05WmiStatus = L05_WMI_NOT_SUPPORTED; } return Status; } /** Find the operation region in WMI ACPI table by given Name and Size, and initialize it if the region is found. @param Table The WMI item in ACPI table. @param Name The name string to find in WMI table. @param Size The size of the region to find. @param Address The allocated address for the found region. @retval EFI_SUCCESS The function completed successfully. **/ EFI_STATUS AssignOpRegion ( IN OUT EFI_ACPI_DESCRIPTION_HEADER *Table, IN UINT32 Name, IN UINT16 Size, IN OUT VOID** Address OPTIONAL ) { EFI_STATUS Status; AML_OP_REGION_32_32 *OpRegion; EFI_PHYSICAL_ADDRESS MemoryAddress; Status = EFI_NOT_FOUND; MemoryAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) *Address; // // Patch some pointers for the ASL code before loading the SSDT. // for (OpRegion = (AML_OP_REGION_32_32 *) (Table + 1); OpRegion <= (AML_OP_REGION_32_32 *) ((UINT8 *) Table + Table->Length); OpRegion = (AML_OP_REGION_32_32 *) ((UINT8 *) OpRegion + 1)) { if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) && (OpRegion->NameString == Name) && (OpRegion->OffsetPrefix == AML_DWORD_PREFIX) && (OpRegion->LenPrefix == AML_DWORD_PREFIX)) { if (MemoryAddress == 0) { MemoryAddress = SIZE_4GB - 1; Status = gBS->AllocatePages (AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress); if (EFI_ERROR (Status)) { return Status; } ZeroMem ((VOID *) (UINTN) MemoryAddress, Size); } OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress; OpRegion->RegionLen = (UINT32) Size; Status = EFI_SUCCESS; break; } } *Address = (VOID *) (UINTN) MemoryAddress; return Status; } /** Get AML Buffer (Declare Buffer Object) by Name. Search the Buffer Name in ACPI Table and get the Buffer & Buffer Length. @param Table A pointer to the ACPI Table. @param Name Buffer Name. @param NameBuffer A pointer to the Buffer for the Name. @param NameBufferLength A pointer to the Buffer Length for the Name. @retval EFI_SUCCESS The operation completed successfully. @retval Others An unexpected error occurred. **/ EFI_STATUS GetAmlNameBuffer ( IN EFI_ACPI_DESCRIPTION_HEADER *Table, IN UINT32 Name, OUT UINT8 **NameBuffer, OUT UINT64 *NameBufferLength ) { EFI_STATUS Status; AML_NAME_BUFFER_HEADER *NameBufferHeader; UINT8 *Operation; UINT8 PkgLeadByte; UINT64 PkgLength; UINT64 TempLength; UINT8 Index; UINT8 DataConst; UINT8 DataConstLength; Status = EFI_NOT_FOUND; NameBufferHeader = NULL; Operation = NULL; PkgLeadByte = 0; PkgLength = 0; TempLength = 0; Index = 0; DataConst = 0; DataConstLength = 0; // // Patch some pointers for the ASL code before loading the SSDT. // for (NameBufferHeader = (AML_NAME_BUFFER_HEADER *) (Table + 1); NameBufferHeader < (AML_NAME_BUFFER_HEADER *) ((UINT8 *) Table + Table->Length); NameBufferHeader = (AML_NAME_BUFFER_HEADER *) ((UINT8 *) NameBufferHeader + 1)) { if ((NameBufferHeader->NameOp == AML_NAME_OP) && (NameBufferHeader->NameString == Name) && (NameBufferHeader->BufferOp == AML_BUFFER_OP)) { Operation = (UINT8 *)(NameBufferHeader + 1); PkgLeadByte = ((*Operation) >> 6) + 1; // , // // If the multiple bytes encoding is used, bits 0-3 of the PkgLeadByte become the least significant 4 bits // of the resulting package length value. The next ByteData will become the next least significant 8 bits // of the resulting value and so on, up to 3 ByteData bytes. Thus, the maximum package length is 2**28. // if (PkgLeadByte > 1) { PkgLength = (PkgLength) & 0x0F; } for (Index = 1; Index < PkgLeadByte; Index++) { TempLength = Operation[Index]; TempLength = LShiftU64(TempLength, ((Index * 8) - 4)); PkgLength += TempLength; } DataConst = *(Operation + PkgLeadByte); switch (DataConst) { case AML_BYTE_PREFIX: DataConstLength = sizeof (UINT8) + sizeof (UINT8); // BytePrefix + ByteData break; case AML_WORD_PREFIX: DataConstLength = sizeof (UINT8) + sizeof (UINT16); // WordPrefix + WordData break; case AML_DWORD_PREFIX: DataConstLength = sizeof (UINT8) + sizeof (UINT32); // DWordPrefix + DWordData break; case AML_QWORD_PREFIX: DataConstLength = sizeof (UINT8) + sizeof (UINT64); // QWordPrefix + QWordData break; case AML_STRING_PREFIX: DataConstLength = sizeof (UINT8); // StringPrefix break; } *NameBuffer = Operation + PkgLeadByte + DataConstLength; *NameBufferLength = PkgLength - PkgLeadByte - DataConstLength; Status = EFI_SUCCESS; break; } } return Status; } /** Update the Instance Count of BIOS Setting A0 at _WDG. Automatic count the Instance Count for BIOS Setting A0. @param Table A pointer to the ACPI Table. @retval EFI_SUCCESS The operation completed successfully. @retval Others An unexpected error occurred. **/ EFI_STATUS UpdateWdgBiosSettingA0InstanceCount ( IN OUT EFI_ACPI_DESCRIPTION_HEADER *Table ) { EFI_STATUS Status; UINT8 *NameBuffer; UINT64 NameBufferLength; AML_WDG_TABLE *WdgTable; UINT64 WdgTableLength; EFI_GUID WdgBiosSettingA0Guid = WDG_BIOS_SETTING_A0_GUID; NameBuffer = NULL; NameBufferLength = 0; WdgTable = NULL; WdgTableLength = 0; Status = GetAmlNameBuffer (Table, SIGNATURE_32 ('_', 'W', 'D', 'G'), &NameBuffer, &NameBufferLength); if (EFI_ERROR (Status)) { return Status; } Status = EFI_NOT_FOUND; WdgTable = (AML_WDG_TABLE *) NameBuffer; WdgTableLength = NameBufferLength; for (WdgTable; WdgTable < (AML_WDG_TABLE *) ((UINT8 *) WdgTable + WdgTableLength); WdgTable++) { if (CompareGuid (&WdgTable->InstanceGuid, &WdgBiosSettingA0Guid)) { WdgTable->InstanceCount = (UINT8) mWmiBiosConfigEnumMapListCount; Status = EFI_SUCCESS; break; } } return Status; } /** Initialize and publish WMI items in ACPI table. @param None @retval EFI_SUCCESS The WMI ACPI table is published successfully. @retval Others The WMI ACPI table is not published. **/ EFI_STATUS PublishAcpiTable ( 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); if (EFI_ERROR (Status)) { return Status; } ASSERT (Table->OemTableId == SIGNATURE_64 ('W', 'm', 'i', 'T', 'a', 'b', 'l', 'e')); Status = AssignOpRegion (Table, SIGNATURE_32 ('L', 'N', 'V', 'S'), (UINT16) sizeof (EFI_L05_GLOBAL_NVS_AREA), (VOID **) &mL05GlobalNVSArea); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } // // Update WDG_BIOS_SETTING_A0 Instance Count in WmiTable // UpdateWdgBiosSettingA0InstanceCount (Table); // // Publish the WMI ACPI table // Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } TableKey = 0; Status = AcpiTable->InstallAcpiTable ( AcpiTable, Table, TableSize, &TableKey ); ASSERT_EFI_ERROR (Status); return Status; } /** WMI Setup under OS SMM entry @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 L05WmiSetupUnderOsSmmEntry ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status = EFI_SUCCESS; EFI_HANDLE SwHandle; EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; EFI_SMM_SW_REGISTER_CONTEXT SwContext; if (!InSmm ()) { return EFI_SUCCESS; } // // Publish ACPI table // Status = PublishAcpiTable (); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } // // Initialize global variables // Status = gSmst->SmmLocateProtocol ( &gEfiSmmVariableProtocolGuid, NULL, &mSmmVariable ); if (EFI_ERROR (Status)) { return Status; } // // Get the Sw dispatch protocol // Status = gSmst->SmmLocateProtocol ( &gEfiSmmSwDispatch2ProtocolGuid, NULL, &SwDispatch ); if (EFI_ERROR (Status)) { return Status; } // // Register Software SMI function // SwContext.SwSmiInputValue = EFI_L05_WMI_SETUP_UNDER_OS_CALLBACK; Status = SwDispatch->Register ( SwDispatch, L05SmmWmiSetupUnderOsCallback, &SwContext, &SwHandle ); if (EFI_ERROR (Status)) { return Status; } // // Get setting for SGX in feature control. // mIsSgxFeatureCtrlSet = L05WmiIsSgxFeatureCtrlSet (); return Status; }