alder_lake_bios/Oem/L05/FeatureCommon/InsydeL05ModulePkg/WmiSetupUnderOsSmm/WmiSetupUnderOsSmm.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;
}