alder_lake_bios/Oem/L05/FeatureCommon/InsydeL05ModulePkg/VariableServiceSmm/VariableServiceSmm.c

461 lines
13 KiB
C

/** @file
;******************************************************************************
;* Copyright (c) 2012 - 2013, 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 "VariableServiceSmm.h"
EFI_L05_VARIABLE_PROTOCOL *mEfiL05VariablePtr = NULL;
EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;
EFI_SMM_CPU_PROTOCOL *mSmmCpu = NULL;
EFI_PHYSICAL_ADDRESS *mLvarBuffer = NULL;
EFI_STATUS
L05FoundTriggerCpu (
UINT8 *CpuNum
)
{
EFI_STATUS Status;
UINT8 Index;
UINT16 SmiPort;
UINT32 Eax;
UINT32 Edx;
Status = EFI_NOT_FOUND;
SmiPort = PcdGet16 (PcdSoftwareSmiPort);
Eax = 0;
Edx = 0;
//
// Find out which CPU triggered the S/W SMI
//
for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT16), Index, &Eax);
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RDX, sizeof (UINT16), Index, &Edx);
if (((Eax & 0xff) == EFI_L05_VARIABLE_CALLBACK) && ((Edx & 0xffff) == SmiPort)) {
//
// CPU found!
//
break;
}
}
*CpuNum = Index;
if (*CpuNum < gSmst->NumberOfCpus) {
Status = EFI_SUCCESS;
}
return Status;
}
/*++
Routine Description:
Using runtime service GetVariable(DXE) or SMM variable protocol(SMM) to get variable.
Variable name always be the same, we only use GUID to distingue variable.
Simply return get variable function.
--*/
EFI_STATUS
L05SmmGetVariable (
IN EFI_L05_VARIABLE_PROTOCOL *This,
IN EFI_GUID *VariableGuidName,
IN OUT UINT32 *DataSize,
OUT VOID *Data
)
{
EFI_STATUS Status;
UINTN DataSizeUintn;
DataSizeUintn = *DataSize;
Status = mSmmVariable->SmmGetVariable (
EFI_L05_VARIABLE_NAME,
VariableGuidName,
NULL,
&DataSizeUintn,
Data
);
*DataSize = (UINT32) DataSizeUintn;
return Status;
}
/*++
Routine Description:
Using runtime service SetVariable(DXE) or SMM variable protocol(SMM) to set variable.
Variable name always be the same, we only use GUID to distingue variable.
Simply return set variable function.
--*/
EFI_STATUS
L05SmmSetVariable (
IN EFI_L05_VARIABLE_PROTOCOL *This,
IN EFI_GUID *VariableGuidName,
IN UINT32 DataSize,
IN VOID *Data
)
{
UINT32 Attribute;
Attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
return mSmmVariable->SmmSetVariable (
EFI_L05_VARIABLE_NAME,
VariableGuidName,
Attribute,
(UINTN) DataSize,
Data
);
}
/*++
Routine Description:
Not implemented.
--*/
EFI_STATUS
L05SmmLockVariable (
IN EFI_L05_VARIABLE_PROTOCOL *This,
IN EFI_GUID *VariableGuidName
)
{
return EFI_UNSUPPORTED;
}
/*++
Routine Description:
Not implemented.
--*/
EFI_STATUS
L05SmmUnlockVariable (
IN EFI_L05_VARIABLE_PROTOCOL *This,
IN EFI_GUID *VariableGuidName,
IN CHAR16 *Password
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
L05SmmVariableCallback (
IN EFI_HANDLE DispatchHandle,
IN CONST VOID *DispatchContext,
IN OUT VOID *CommBuffer,
IN OUT UINTN *CommBufferSize
)
{
EFI_STATUS Status;
UINT16 FunctionCode;
L05_SMAPI_DATA *SmapiData;
UINT32 Eax;
UINT32 Ecx;
UINT8 CpuNum;
UINT32 LvarBufferAddressH;
UINT32 LvarBufferAddressL;
FunctionCode = 0;
Eax = 0;
Ecx = 0;
LvarBufferAddressH = 0;
LvarBufferAddressL = 0;
Status = L05FoundTriggerCpu (&CpuNum);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT16), CpuNum, &Eax);
if (Eax != EFI_L05_VARIABLE_FUNCTION) {
return EFI_UNSUPPORTED;
}
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RBX, sizeof (UINT16), CpuNum, &FunctionCode);
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RCX, sizeof (UINT32), CpuNum, &Ecx);
SmapiData = (L05_SMAPI_DATA *) (UINTN) Ecx;
//
// Check SmapiData pointer is not NULL.
//
if (SmapiData == NULL) {
return EFI_UNSUPPORTED;
}
//
// Check SmapiData pointer is in mLvarBuffer range.
//
if (((UINTN) SmapiData < (UINTN) mLvarBuffer) || ((UINTN) SmapiData > ((UINTN) mLvarBuffer + LVAR_RESERVED_MEMORY_SIZE - sizeof (L05_SMAPI_DATA)))) {
return EFI_UNSUPPORTED;
}
//
// Check Data of SmapiData is in mLvarBuffer range.
//
if ((UINTN) SmapiData + sizeof (L05_SMAPI_DATA) + SmapiData->DataLength - sizeof (UINT8) > (UINTN) mLvarBuffer + LVAR_RESERVED_MEMORY_SIZE) {
return EFI_UNSUPPORTED;
}
switch (FunctionCode) {
case READ_NVRAM:
Status = L05SmmGetVariable (
mEfiL05VariablePtr,
(EFI_GUID *)(UINTN) &(SmapiData->Guid),
(UINT32 *)(UINTN) &(SmapiData->DataLength),
SmapiData->Data
);
if (EFI_ERROR (Status)) {
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
Eax &= EFI_L05_VARIABLE_EAX_MASK;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
Eax |= EFI_L05_VARIABLE_ERROR;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
return EFI_UNSUPPORTED;
}
break;
case WRITE_NVRAM:
Status = L05SmmSetVariable (
mEfiL05VariablePtr,
(EFI_GUID *)(UINTN) &(SmapiData->Guid),
SmapiData->DataLength,
SmapiData->Data
);
if (EFI_ERROR (Status)) {
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
Eax &= EFI_L05_VARIABLE_EAX_MASK;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
Eax |= EFI_L05_VARIABLE_ERROR;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
return EFI_UNSUPPORTED;
}
break;
case DELETE_NVRAM:
Status = L05SmmSetVariable (
mEfiL05VariablePtr,
(EFI_GUID *)(UINTN) &(SmapiData->Guid),
0,
NULL
);
if (EFI_ERROR (Status)) {
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
Eax &= EFI_L05_VARIABLE_EAX_MASK;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
Eax |= EFI_L05_VARIABLE_ERROR;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
return EFI_UNSUPPORTED;
}
break;
case GET_BUFFER_ADDRESS:
LvarBufferAddressL = (UINT32)(UINTN) mLvarBuffer;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RCX, sizeof (UINT32), CpuNum, &LvarBufferAddressL);
LvarBufferAddressH = (UINT32)((UINTN) mLvarBuffer >> 32);
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RDI, sizeof (UINT32), CpuNum, &LvarBufferAddressH);
Status = EFI_SUCCESS;
break;
default:
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
Eax &= EFI_L05_VARIABLE_EAX_MASK;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
Eax |= EFI_L05_VARIABLE_ERROR;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
return EFI_UNSUPPORTED;
}
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
Eax &= EFI_L05_VARIABLE_EAX_MASK;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
Eax |= EFI_L05_VARIABLE_NO_ERROR;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
return EFI_UNSUPPORTED;
}
EFI_STATUS
L05VariableServiceSmmEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HANDLE SwHandle;
EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
EFI_SMM_SW_REGISTER_CONTEXT SwContext;
Status = EFI_SUCCESS;
//
// Locate Smm Cpu protocol for Cpu save state manipulation
//
Status = gSmst->SmmLocateProtocol (
&gEfiSmmCpuProtocolGuid,
NULL,
&mSmmCpu
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mSmmVariable);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gSmst->SmmAllocatePool (
EfiRuntimeServicesData,
sizeof (EFI_L05_VARIABLE_PROTOCOL),
&mEfiL05VariablePtr
);
if (EFI_ERROR (Status)) {
return Status;
}
ZeroMem ((VOID *) mEfiL05VariablePtr, sizeof (EFI_L05_VARIABLE_PROTOCOL));
mEfiL05VariablePtr->GetVariable = L05SmmGetVariable;
mEfiL05VariablePtr->SetVariable = L05SmmSetVariable;
mEfiL05VariablePtr->LockVariable = L05SmmLockVariable;
mEfiL05VariablePtr->UnlockVariable = L05SmmUnlockVariable;
SwHandle = NULL;
Status = gSmst->SmmInstallProtocolInterface (
&SwHandle,
&gEfiL05VariableProtocolGuid,
EFI_NATIVE_INTERFACE,
mEfiL05VariablePtr
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// According to Lenovo's requirements,
// BIOS needs to reserve 8*4K memory buffer for LVAR tool and memory type should be EfiReservedMemoryType
//
Status = gBS->AllocatePool (
EfiReservedMemoryType,
LVAR_RESERVED_MEMORY_SIZE,
(VOID **) &mLvarBuffer
);
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_VARIABLE_CALLBACK;
Status = SwDispatch->Register (
SwDispatch,
L05SmmVariableCallback,
&SwContext,
&SwHandle
);
return Status;
}
EFI_STATUS
ReadDwordRegister (
IN EFI_SMM_SAVE_STATE_REGISTER RegisterNum,
IN UINTN Width,
IN UINT8 CpuNum,
OUT VOID *RegisterData
)
{
EFI_STATUS Status;
Status = mSmmCpu->ReadSaveState (
mSmmCpu,
Width,
RegisterNum,
CpuNum,
RegisterData
);
return Status;
}
EFI_STATUS
WriteDwordRegister (
IN EFI_SMM_SAVE_STATE_REGISTER RegisterNum,
IN UINTN Width,
IN UINT8 CpuNum,
OUT VOID *RegisterData
)
{
EFI_STATUS Status;
Status = mSmmCpu->WriteSaveState (
mSmmCpu,
Width,
RegisterNum,
CpuNum,
RegisterData
);
return Status;
}