1208 lines
34 KiB
C
1208 lines
34 KiB
C
/** @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; // <bit 7-6: ByteData count that follows (0-3)
|
|
PkgLength = (UINT64)(*Operation) & 0x3F; // <bit 5-4: Only used if PkgLength < 63>, <bit 3-0: Least significant package length nybble>
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|