alder_lake_bios/Lcfc/LfcPkg/LenovoVariable/LenovoVariableDxe/LenovoVariableDxe.c

859 lines
30 KiB
C

//*****************************************************************************
//
//
// Copyright (c) 2012 - 2016, Hefei LCFC Information Technology Co.Ltd.
// And/or its affiliates. All rights reserved.
// Hefei LCFC Information Technology Co.Ltd. PROPRIETARY/CONFIDENTIAL.
// Use is subject to license terms.
//
//******************************************************************************
/*
Data Name Version Description
2014.08.12 dahai.zhou v1.10 Reconstitution it
2014.08.13 dahai.zhou v1.11 Fix the issue that find enough space wrong
2014.08.20 dahai.zhou v1.12 Support AMD platform
Fix spelling error
2014.09.12 feng.gu v1.20 Record set,lock,unlock LenovoVariable actions into BIOS ROM
Support Lvar Tool dump recorded debug datas into a binary file
2014.09.17 feng.gu v1.21 Modify all the defult values of debug region from 0xFF to 0x00
2015.01.15 feng.gu v1.22 Restore varialbe in BIOS ROM when invoke delete,set,lock and unlock functions.
Restore debug datas in BIOS ROM when invoke set,lock and unlock functions.
2015.02.04 feng.gu v1.23 Use protocol to get platform type and global variable to store smiport.
2016.12.28 feng.gu v1.24 Fix the bug that debug region will overflow.
2020.03.02 feng.gu v1.25 Replace LenovoVariableDxeToSmm for LenovoVariableDxeGet/Set/Lock/UnlockVariableThroughSmi
so that it is simple and can return the data size when the size reserved for get variable is too small.
*/
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/IoLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Protocol/LenovoVariable.h>
#include <Guid/LfcVariableGuid.h>
#include <Library/LfcFlashDeviceLib.h>
#include <Lfc.h>
#include <Library/OemSvcLfcGetLvarAddress.h>
#include <Library/OemSvcLfcGetPlatformType.h>
UINT32 Sub1BaseInRom = 0;
UINT32 Sub1SizeInRom = 0;
UINT32 Sub2BaseInRom = 0;
UINT32 Sub2SizeInRom = 0;
UINT32 DebugBaseInRom = 0;
UINT32 DebugSizeInRom = 0;
// Default value represent Intel platform
UINTN SmiPort = 0xb2;
UINTN SmiDataPort =0xb3;
EFI_STATUS
EncodeOrDecodeBuffer (
IN UINT8 *Buffer,
IN UINTN Size,
IN UINTN Header,
IN UINT8 RamdomNum
)
{
UINT8 *BufferPointer;
UINTN Index;
BufferPointer = Buffer + Header;
for (Index = 0; Index < Size - Header; Index++) {
*(BufferPointer + Index) = *(BufferPointer + Index)^RamdomNum;
}
return EFI_SUCCESS;
}
EFI_STATUS
FlashToBiosRom (
IN UINTN WriteFlashAddress,
IN UINTN WriteFlashSize,
IN UINT8 *Buffer
)
{
EFI_STATUS Status = EFI_SUCCESS;
Status = LfcFdLibBlockErase (WriteFlashAddress, WriteFlashSize);
ASSERT_EFI_ERROR (Status);
Status = LfcFdLibWrite (WriteFlashAddress, &WriteFlashSize, Buffer);
ASSERT_EFI_ERROR (Status);
return Status;
}
EFI_STATUS
LenovoVariableDxeToSmm (
IN UINT16 FunctionCode,
IN EFI_GUID *VariableGuidName,
IN OUT UINT32 *DataSize,
OUT VOID *Data
)
{
EFI_STATUS Status;
SMAPI_DATA *DxeSmmDataRt;
// We prepare MAX_DATA_BUFFER_SIZE for variable data, and clear it to 0
Status = (gBS->AllocatePool) (EfiRuntimeServicesData, sizeof(SMAPI_DATA) + MAX_DATA_BUFFER_SIZE, (VOID **) &DxeSmmDataRt);
SetMem (DxeSmmDataRt->Data, MAX_DATA_BUFFER_SIZE + 1, 0);
DxeSmmDataRt->FunctionCode = FunctionCode;
DxeSmmDataRt->VariableGuidName = *VariableGuidName;
*(EFI_STATUS *)(DxeSmmDataRt->Name) = (EFI_STATUS)~0;// We use the Name to store return status since the Name is not used, and big enough
switch (FunctionCode) {
case GET_VARIABLE_FUNCTION:
DxeSmmDataRt->DataLength = *DataSize;
break;
case SET_VARIABLE_FUNCTION:
DxeSmmDataRt->DataLength = *DataSize;
CopyMem (DxeSmmDataRt->Data, Data, *DataSize);
break;
case LOCK_VARIABLE_FUNCTION:
break;
case UNLOCK_VARIABLE_FUNCTION:
StrCpyS((CHAR16*)DxeSmmDataRt->Data,sizeof((CHAR16*)DxeSmmDataRt->Data) / sizeof (CHAR16),(CHAR16*)Data);
break;
default:
break;
}
Status = gRT->SetVariable (
LENOVO_VARIABLE_DXE_SMM_DATA_VARIABLE_NAME,
&gLfcVariableGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS,
sizeof (DxeSmmDataRt),
(VOID *)(&DxeSmmDataRt)
);
IoWrite8 (SmiDataPort, LENOVO_VARIABLE_DXE_TO_SMM_FLAG);
IoWrite8 (SmiPort, LENOVO_VARIABLE_CALLBACK);
Status = *(EFI_STATUS *)(DxeSmmDataRt->Name);
if (Status == (EFI_STATUS)~0) {
// Fail to triger Smi
Status = EFI_UNSUPPORTED;
} else {
// Return from SMI
switch (FunctionCode) {
case GET_VARIABLE_FUNCTION:
if (Status == EFI_SUCCESS) {
*DataSize = DxeSmmDataRt->DataLength;
CopyMem (Data, DxeSmmDataRt->Data, DxeSmmDataRt->DataLength);
} else if (Status == EFI_BUFFER_TOO_SMALL) {
*DataSize = DxeSmmDataRt->DataLength;
}
break;
case SET_VARIABLE_FUNCTION:
case LOCK_VARIABLE_FUNCTION:
case UNLOCK_VARIABLE_FUNCTION:
default:
break;
}
}
gBS->FreePool (DxeSmmDataRt);
return Status;
}
VOID
LenovoVariableDxeSearchVar (
IN LENOVO_VARIABLE_PRIVATE_DATA *PrivateData,
IN EFI_GUID *VariableGuidName,
OUT UINT8 **VariableAddress
)
/*
Search VariableGuidName from PrivateData->VariableBuffer
If found, VariableSizeAddress point to the variable address
If not found, VariableSizeAddress = NULL
*/
{
UINT8 *BufferPointer;
UINTN Index;
BufferPointer = PrivateData->VariableBuffer + sizeof (LENOVO_VARIABLE_RIGION_HEADER);
for (Index = 0; Index < ((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->VariableCount; Index++) {
if (CompareGuid (VariableGuidName, &(((LENOVO_VARIABLE_VARIABLE *)BufferPointer)->VariableGuidName))) {
*VariableAddress = BufferPointer;
return;
} else {
BufferPointer = BufferPointer + ((LENOVO_VARIABLE_VARIABLE *)BufferPointer)->VariableDataSize;
BufferPointer = BufferPointer + sizeof (LENOVO_VARIABLE_VARIABLE) - 1;
}
}
*VariableAddress = NULL;
return;
}
// SetVariable, LockVariable, UnlockVariable action data
EFI_STATUS
LenovoVariableAddDebugData (
IN LENOVO_VARIABLE_PRIVATE_DATA *PrivateData,
IN EFI_GUID *VariableGuidName,
IN UINT8 ActionItem,
IN UINT32 DataSize
)
{
LENOVO_DEBUG_RIGION_HEADER *DebugAddress;
LENOVO_DEBUG_DATA *Next;
EFI_STATUS Status= EFI_SUCCESS;
UINTN WriteFlashAddress = 0;
UINTN WriteFlashSize = 0;
DebugAddress = (LENOVO_DEBUG_RIGION_HEADER *)(PrivateData->DebugBuffer);
Next = (LENOVO_DEBUG_DATA *)(PrivateData->DebugBuffer + DebugAddress->NextUsable);
// Save action time
IoWrite8 (0x70, 0x09);
*((UINT16 *)(Next->Time)) = 0x2000 + IoRead8 (0x71); // Year
IoWrite8 (0x70, 0x08);
*(Next->Time + 2) = IoRead8 (0x71); // Month
IoWrite8 (0x70, 0x07);
*(Next->Time + 3) = IoRead8 (0x71); // Date
IoWrite8 (0x70, 0x4);
*(Next->Time + 4) = IoRead8 (0x71); // Hour
IoWrite8 (0x70, 0x02);
*(Next->Time + 5) = IoRead8 (0x71); // Minite
IoWrite8 (0x70, 0x00);
*(Next->Time + 6) = IoRead8 (0x71); // Second
// Save action type:set:2,lock:6,unlock:7
Next->Action = ActionItem;
Next->Guid = *VariableGuidName;
Next->DataLength = DataSize;
SetMem (Next->Reserved, sizeof (Next->Reserved), 0);
DebugAddress->NextUsable += sizeof (LENOVO_DEBUG_DATA);
if (DebugAddress->NextUsable >= DebugSizeInRom) {
DebugAddress->NextUsable = sizeof (LENOVO_DEBUG_RIGION_HEADER);
}
// Encode
EncodeOrDecodeBuffer (PrivateData->DebugBuffer,
DebugSizeInRom,
sizeof (LENOVO_DEBUG_RIGION_HEADER),
((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->RandomNumber);
// Write Debug data to flash
WriteFlashAddress = DebugBaseInRom;
WriteFlashSize = DebugSizeInRom;
FlashToBiosRom (WriteFlashAddress, WriteFlashSize, PrivateData->DebugBuffer);
// Decode
EncodeOrDecodeBuffer (PrivateData->DebugBuffer,
DebugSizeInRom,
sizeof (LENOVO_DEBUG_RIGION_HEADER),
((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->RandomNumber);
return Status;
}
EFI_STATUS
LenovoVariableDxeUpdateChecksumAndPriorityFlag (
IN LENOVO_VARIABLE_PRIVATE_DATA *PrivateData
)
{
// Encode
{
UINT8 *BufferPointer;
UINTN Index;
BufferPointer = PrivateData->VariableBuffer + sizeof (LENOVO_VARIABLE_RIGION_HEADER);
for (Index = 0; Index < Sub1SizeInRom - sizeof (LENOVO_VARIABLE_RIGION_HEADER); Index++) {
*(BufferPointer + Index) = *(BufferPointer + Index)^((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->RandomNumber;
}
}
// Update Checksum
{
UINT8 *BufferPointer;
UINTN Index;
UINT16 Checksum = 0;
BufferPointer = PrivateData->VariableBuffer + sizeof (LENOVO_VARIABLE_RIGION_HEADER);
for (Index = 0; Index < Sub1SizeInRom - sizeof (LENOVO_VARIABLE_RIGION_HEADER); Index++) {
Checksum += *(BufferPointer + Index);
}
((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->Checksum = Checksum;
}
// Decode
{
UINT8 *BufferPointer;
UINTN Index;
BufferPointer = PrivateData->VariableBuffer + sizeof (LENOVO_VARIABLE_RIGION_HEADER);
for (Index = 0; Index < Sub1SizeInRom - sizeof (LENOVO_VARIABLE_RIGION_HEADER); Index++) {
*(BufferPointer + Index) = *(BufferPointer + Index)^((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->RandomNumber;
}
}
// Update Priority Flag
((LENOVO_VARIABLE_RIGION_HEADER*)(PrivateData->VariableBuffer))->PriorityFlag++;
return EFI_SUCCESS;
}
EFI_STATUS
LenovoVariableWriteBufferToFlash (
IN LENOVO_VARIABLE_PRIVATE_DATA *PrivateData
)
{
EFI_STATUS Status = EFI_SUCCESS;
UINTN WriteFlashAddress = 0;
UINTN WriteFlashSize;
switch (PrivateData->Region) {
case LENOVO_VARIABLE_NO_DATA:
WriteFlashAddress = Sub1BaseInRom;
break;
case LENOVO_VARIABLE_USING_REGION_1:
WriteFlashAddress = Sub2BaseInRom;
break;
case LENOVO_VARIABLE_USING_REGION_2:
WriteFlashAddress = Sub1BaseInRom;
break;
default:
break;
}
((LENOVO_VARIABLE_RIGION_HEADER*)(PrivateData->VariableBuffer))->PriorityFlag++;
// Encode
EncodeOrDecodeBuffer (PrivateData->VariableBuffer,
Sub1SizeInRom,
sizeof (LENOVO_VARIABLE_RIGION_HEADER),
((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->RandomNumber);
// Update checksum
{
UINT8 *BufferPointer;
UINTN Index;
UINT16 Checksum = 0;
BufferPointer = PrivateData->VariableBuffer + sizeof (LENOVO_VARIABLE_RIGION_HEADER);
for (Index = 0; Index < Sub1SizeInRom - sizeof (LENOVO_VARIABLE_RIGION_HEADER); Index++) {
Checksum += *(BufferPointer + Index);
}
((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->Checksum = Checksum;
}
WriteFlashSize = Sub1SizeInRom;
FlashToBiosRom (WriteFlashAddress, WriteFlashSize, PrivateData->VariableBuffer);
// Update region
if (!EFI_ERROR(Status)) {
PrivateData->Region = (PrivateData->Region == LENOVO_VARIABLE_USING_REGION_1)?LENOVO_VARIABLE_USING_REGION_2:LENOVO_VARIABLE_USING_REGION_1;
}
// Decode
EncodeOrDecodeBuffer (PrivateData->VariableBuffer,
Sub1SizeInRom,
sizeof (LENOVO_VARIABLE_RIGION_HEADER),
((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->RandomNumber);
return Status;
}
EFI_STATUS
LenovoVariableDxeInit (
IN OUT LENOVO_VARIABLE_PRIVATE_DATA *PrivateData
)
{
LENOVO_VARIABLE_RIGION_HEADER *FlashRegion1Address, *FlashRegion2Address;
// Generate RandomNumber
{
UINT64 TimeStamp;
TimeStamp = AsmReadTsc ();
while ((UINT8)TimeStamp == 0) {
TimeStamp = AsmReadTsc ();
}
((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->RandomNumber = (UINT8)TimeStamp;
}
FlashRegion1Address = (LENOVO_VARIABLE_RIGION_HEADER*)(UINTN)Sub1BaseInRom;
FlashRegion2Address = (LENOVO_VARIABLE_RIGION_HEADER*)(UINTN)Sub2BaseInRom;
if (AsciiStrnCmp (FlashRegion1Address->Signature, "LENV", 4) || \
AsciiStrnCmp (FlashRegion2Address->Signature, "LENV", 4) || \
(FlashRegion1Address->PriorityFlag == 0 && FlashRegion2Address->PriorityFlag == 0)) {
// Nothing in region, or data crashed
PrivateData->Region = LENOVO_VARIABLE_NO_DATA;
} else if (FlashRegion1Address->PriorityFlag > FlashRegion2Address->PriorityFlag) {
// Use sub region 1
PrivateData->Region = LENOVO_VARIABLE_USING_REGION_1;
// Verify sub region 1's checksum
{
UINTN Index;
UINT8 *BufferPointer;
UINT16 Checksum = 0;
BufferPointer = (UINT8 *)FlashRegion1Address + sizeof (LENOVO_VARIABLE_RIGION_HEADER);
// Verify checksum of region 1
for (Index = 0, Checksum = 0; Index < Sub1SizeInRom - sizeof (LENOVO_VARIABLE_RIGION_HEADER); Index++) {
Checksum += *(BufferPointer + Index);
}
if (Checksum != FlashRegion1Address->Checksum) {
// If region 1 is crashed, using region 2
PrivateData->Region = LENOVO_VARIABLE_USING_REGION_2;
BufferPointer = (UINT8 *)FlashRegion2Address + sizeof (LENOVO_VARIABLE_RIGION_HEADER);
// Verify checksum of region 2
for (Index = 0, Checksum = 0; Index < Sub2SizeInRom - sizeof (LENOVO_VARIABLE_RIGION_HEADER); Index++) {
Checksum += *(BufferPointer + Index);
}
if (Checksum != FlashRegion2Address->Checksum) {
// If region 1 and region 2 are crashed, using NO_DATA
PrivateData->Region = LENOVO_VARIABLE_NO_DATA;
} else {
// If region 2 OK
CopyMem (PrivateData->VariableBuffer, FlashRegion2Address, Sub2SizeInRom);
}
} else {
// If region 1 OK
CopyMem (PrivateData->VariableBuffer, FlashRegion1Address, Sub1SizeInRom);
}
}
} else {
// Use sub region 2
PrivateData->Region = LENOVO_VARIABLE_USING_REGION_2;
// Verify sub region 2's checksum
{
UINTN Index;
UINT8 *BufferPointer;
UINT16 Checksum = 0;
BufferPointer = (UINT8 *)FlashRegion2Address + sizeof (LENOVO_VARIABLE_RIGION_HEADER);
// Verify checksum of region 2
for (Index = 0, Checksum = 0; Index < Sub2SizeInRom - sizeof (LENOVO_VARIABLE_RIGION_HEADER); Index++) {
Checksum += *(BufferPointer + Index);
}
if (Checksum != FlashRegion2Address->Checksum) {
// If region 2 is crashed, using region 1
PrivateData->Region = LENOVO_VARIABLE_USING_REGION_1;
BufferPointer = (UINT8 *)FlashRegion1Address + sizeof (LENOVO_VARIABLE_RIGION_HEADER);
// Verify checksum of region 1
for (Index = 0, Checksum = 0; Index < Sub1SizeInRom - sizeof (LENOVO_VARIABLE_RIGION_HEADER); Index++) {
Checksum += *(BufferPointer + Index);
}
if (Checksum != FlashRegion1Address->Checksum) {
// If region 2 and region 1 are crashed, using NO_DATA
PrivateData->Region = LENOVO_VARIABLE_NO_DATA;
} else {
// If region 1 OK
CopyMem (PrivateData->VariableBuffer, FlashRegion1Address, Sub1SizeInRom);
}
} else {
// If region 2 OK
CopyMem (PrivateData->VariableBuffer, FlashRegion2Address, Sub2SizeInRom);
}
}
}
// Decode
if (PrivateData->Region != LENOVO_VARIABLE_NO_DATA) {
UINT8 *BufferPointer;
UINTN Index;
BufferPointer = PrivateData->VariableBuffer + sizeof (LENOVO_VARIABLE_RIGION_HEADER);
for (Index = 0; Index < Sub1SizeInRom - sizeof (LENOVO_VARIABLE_RIGION_HEADER); Index++) {
*(BufferPointer + Index) = *(BufferPointer + Index)^((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->RandomNumber;
}
}
// Update LastByte field
{
UINT8 *BufferPointer;
UINTN Index;
BufferPointer = PrivateData->VariableBuffer + sizeof (LENOVO_VARIABLE_RIGION_HEADER);
for (Index = 0; Index < ((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->VariableCount; Index++) {
BufferPointer = BufferPointer + ((LENOVO_VARIABLE_VARIABLE *)BufferPointer)->VariableDataSize;
BufferPointer = BufferPointer + sizeof (LENOVO_VARIABLE_VARIABLE) - 1;
}
BufferPointer--;
PrivateData->LastByte = BufferPointer;
}
return EFI_SUCCESS;
}
/*
Return:
TRUE = SMI ready
FALSE = SMI not ready
*/
BOOLEAN
LenovoVariableDxeSmiReady (
VOID
)
{
EFI_STATUS Status;
UINTN DataSize = sizeof (BOOLEAN);
BOOLEAN Ready;
Status = gRT->GetVariable (
LENOVO_VARIABLE_SMI_READY_FLAG_VARIABLE_NAME,
&gLfcVariableGuid,
NULL,
&DataSize,
&Ready
);
if (!EFI_ERROR (Status)) {
return TRUE;
}
return FALSE;
}
EFI_STATUS
LenovoVariableDxeGetVariable (
IN LENOVO_VARIABLE_PROTOCOL *This,
IN EFI_GUID *VariableGuidName,
IN OUT UINT32 *DataSize,
OUT VOID *Data
)
{
LENOVO_VARIABLE_PRIVATE_DATA *PrivateData;
UINT32 VariableSize;
UINT8 *VariableAddress;
if (LenovoVariableDxeSmiReady ()) {
return LenovoVariableDxeToSmm (GET_VARIABLE_FUNCTION, VariableGuidName, DataSize, Data);
}
PrivateData = INSTANCE_FROM_LENV_THIS (This);
if (VariableGuidName == NULL || DataSize == NULL) {
return EFI_INVALID_PARAMETER;
}
if (((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->VariableCount == 0) {
return EFI_NOT_FOUND;
}
LenovoVariableDxeSearchVar (PrivateData, VariableGuidName, &VariableAddress);
if (VariableAddress != NULL) {
VariableSize = ((LENOVO_VARIABLE_VARIABLE *)VariableAddress)->VariableDataSize;
if (*DataSize < VariableSize) {
*DataSize = VariableSize;
return EFI_BUFFER_TOO_SMALL;
}
if (Data == NULL) {
return EFI_INVALID_PARAMETER;
}
*DataSize = VariableSize;
CopyMem (Data, ((LENOVO_VARIABLE_VARIABLE *)VariableAddress)->VariableData, VariableSize);
return EFI_SUCCESS;
}
return EFI_NOT_FOUND;
}
EFI_STATUS
LenovoVariableDxeDeleteVariable (
IN LENOVO_VARIABLE_PROTOCOL *This,
IN EFI_GUID *VariableGuidName
)
{
LENOVO_VARIABLE_PRIVATE_DATA *PrivateData;
UINT8 *VariableAddress;
UINT8 *ShiftBegin;
UINTN ShiftCount;
PrivateData = INSTANCE_FROM_LENV_THIS (This);
if (VariableGuidName == NULL) {
return EFI_INVALID_PARAMETER;
}
if (((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->LockFlag == LENOVO_VARIABLE_REGION_LOCKED) {
return EFI_ACCESS_DENIED;
}
LenovoVariableDxeSearchVar (PrivateData, VariableGuidName, &VariableAddress);
if (VariableAddress == NULL) {
return EFI_NOT_FOUND;
}
if ((((LENOVO_VARIABLE_VARIABLE *)VariableAddress)->VariableAttribute & LENOVO_VARIABLE_ATTRIBUTE_LOCKED) == LENOVO_VARIABLE_ATTRIBUTE_LOCKED) {
return EFI_WRITE_PROTECTED;
}
ShiftBegin = VariableAddress + ((LENOVO_VARIABLE_VARIABLE *)VariableAddress)->VariableDataSize;
ShiftBegin = ShiftBegin + sizeof (LENOVO_VARIABLE_VARIABLE) - 1;
ShiftCount = 0 + ((LENOVO_VARIABLE_VARIABLE *)VariableAddress)->VariableDataSize;
ShiftCount = ShiftCount + sizeof (LENOVO_VARIABLE_VARIABLE) - 1;
// Begin shift
while (ShiftBegin <= PrivateData->LastByte) {
*(ShiftBegin - ShiftCount) = *ShiftBegin;
ShiftBegin++;
}
SetMem (ShiftBegin - ShiftCount, ShiftCount, 0);
((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->VariableCount--;
PrivateData->LastByte -= ShiftCount;
LenovoVariableWriteBufferToFlash (PrivateData);
return EFI_SUCCESS;
}
EFI_STATUS
LenovoVariableDxeSetVariable (
IN LENOVO_VARIABLE_PROTOCOL *This,
IN EFI_GUID *VariableGuidName,
IN UINT32 DataSize,
IN VOID *Data
)
{
EFI_STATUS Status;
LENOVO_VARIABLE_PRIVATE_DATA *PrivateData;
if (LenovoVariableDxeSmiReady ()) {
return LenovoVariableDxeToSmm (SET_VARIABLE_FUNCTION, VariableGuidName, &DataSize, Data);
}
PrivateData = INSTANCE_FROM_LENV_THIS (This);
if (VariableGuidName == NULL) {
return EFI_INVALID_PARAMETER;
}
if (((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->LockFlag == LENOVO_VARIABLE_REGION_LOCKED) {
return EFI_ACCESS_DENIED;
}
// If DataSize = 0, then delete variable, sync with EFI variable
if (DataSize == 0) {
Status = LenovoVariableDxeDeleteVariable (This, VariableGuidName);
LenovoVariableAddDebugData (PrivateData, VariableGuidName, SET_VARIABLE_FUNCTION, DataSize);
return Status;
}
if (Data == NULL) {
return EFI_INVALID_PARAMETER;
}
// If variable exist, need delete it first
Status = LenovoVariableDxeDeleteVariable (This, VariableGuidName);
if (Status != EFI_NOT_FOUND && Status != EFI_SUCCESS) {
return Status;
}
// Make sure we have enough space
// Last + Need - Base > Size, then error
if ((UINTN)(PrivateData->LastByte) + sizeof (LENOVO_VARIABLE_VARIABLE) + DataSize - (UINTN)(PrivateData->VariableBuffer) > \
Sub2SizeInRom) {
return EFI_OUT_OF_RESOURCES;
}
// Add a variable
{
LENOVO_VARIABLE_VARIABLE Variable;
CopyMem (&(Variable.VariableGuidName), VariableGuidName, sizeof (*VariableGuidName));
Variable.VariableDataSize = DataSize;
Variable.VariableAttribute = 0;
CopyMem ((PrivateData->LastByte) + 1, &Variable, sizeof (Variable) - 1);
CopyMem ((PrivateData->LastByte) + 1 + sizeof (Variable) - 1, Data, DataSize);
PrivateData->LastByte = PrivateData->LastByte + sizeof (Variable) - 1 + DataSize;
}
((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->VariableCount++;
// LenovoVariableDxeUpdateChecksumAndPriorityFlag (PrivateData);
LenovoVariableWriteBufferToFlash (PrivateData);
LenovoVariableAddDebugData (PrivateData, VariableGuidName, SET_VARIABLE_FUNCTION, DataSize);
return EFI_SUCCESS;
}
EFI_STATUS
LenovoVariableDxeLockVariable (
IN LENOVO_VARIABLE_PROTOCOL *This,
IN EFI_GUID *VariableGuidName
)
{
LENOVO_VARIABLE_PRIVATE_DATA *PrivateData;
UINT8 *VariableAddress;
if (LenovoVariableDxeSmiReady ()) {
return LenovoVariableDxeToSmm (LOCK_VARIABLE_FUNCTION, VariableGuidName, NULL, NULL);
}
PrivateData = INSTANCE_FROM_LENV_THIS (This);
if (((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->LockFlag == LENOVO_VARIABLE_REGION_LOCKED) {
return EFI_ACCESS_DENIED;
}
if (((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->VariableCount == 0) {
return EFI_NOT_FOUND;
}
LenovoVariableDxeSearchVar (PrivateData, VariableGuidName, &VariableAddress);
if (VariableAddress == NULL) {
return EFI_NOT_FOUND;
}
// Update variable attribute
((LENOVO_VARIABLE_VARIABLE *)VariableAddress)->VariableAttribute |= LENOVO_VARIABLE_ATTRIBUTE_LOCKED;
// LenovoVariableDxeUpdateChecksumAndPriorityFlag (PrivateData);
LenovoVariableWriteBufferToFlash (PrivateData);
LenovoVariableAddDebugData (PrivateData, VariableGuidName, LOCK_VARIABLE_FUNCTION, ((LENOVO_VARIABLE_VARIABLE *)VariableAddress)->VariableDataSize);
return EFI_SUCCESS;
}
EFI_STATUS
LenovoVariableDxeUnlockVariable (
IN LENOVO_VARIABLE_PROTOCOL *This,
IN EFI_GUID *VariableGuidName,
IN CHAR16 *Password
)
{
LENOVO_VARIABLE_PRIVATE_DATA *PrivateData;
UINT8 *VariableAddress;
CHAR16 *LenovoVariablePassword = LENOVO_VARIABLE_UNLOCK_PASSWORD;
static UINTN FailCount = 0;
if (LenovoVariableDxeSmiReady ()) {
return LenovoVariableDxeToSmm (UNLOCK_VARIABLE_FUNCTION, VariableGuidName, NULL, Password);
}
PrivateData = INSTANCE_FROM_LENV_THIS (This);
if (((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->LockFlag == LENOVO_VARIABLE_REGION_LOCKED) {
return EFI_ACCESS_DENIED;
}
if (((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->VariableCount == 0) {
return EFI_NOT_FOUND;
}
LenovoVariableDxeSearchVar (PrivateData, VariableGuidName, &VariableAddress);
if (VariableAddress == NULL) {
return EFI_NOT_FOUND;
}
// Verify Password
if (FailCount == LENOVO_VARIABLE_UNLOCK_FAIL_MAX) {
return EFI_SECURITY_VIOLATION;
}
if (StrCmp (Password, LenovoVariablePassword) != 0) {
FailCount++;
return EFI_SECURITY_VIOLATION;
}
// Update variable attribute
((LENOVO_VARIABLE_VARIABLE *)VariableAddress)->VariableAttribute &= ~LENOVO_VARIABLE_ATTRIBUTE_LOCKED;
// LenovoVariableDxeUpdateChecksumAndPriorityFlag (PrivateData);
LenovoVariableWriteBufferToFlash (PrivateData);
LenovoVariableAddDebugData (PrivateData, VariableGuidName, UNLOCK_VARIABLE_FUNCTION, ((LENOVO_VARIABLE_VARIABLE *)VariableAddress)->VariableDataSize);
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
LenovoVariableDxeEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
LENOVO_VARIABLE_PRIVATE_DATA *PrivateData;
EFI_PHYSICAL_ADDRESS BufferAddress;
EFI_PHYSICAL_ADDRESS DebugAddress;
UINT8 PlatformType;
Status = OemSvcLfcDxeGetLvarAddress (&Sub1BaseInRom, &Sub1SizeInRom, &Sub2BaseInRom, &Sub2SizeInRom, &DebugBaseInRom, &DebugSizeInRom);
if (Sub1BaseInRom == 0 || Sub1SizeInRom == 0 || Sub2BaseInRom == 0 || Sub2SizeInRom == 0 || DebugBaseInRom == 0 || DebugSizeInRom == 0) {
LfcLibLogError (LFC_LOG_LVAR_DXE_ROM_ERROR);
return EFI_SUCCESS;
}
Status = OemSvcLfcDxeGetPlatformType (&PlatformType);
if (PlatformType == INTEL_PLATFORM ) {
// Intel platform
SmiPort = 0xb2;
} else if (PlatformType == AMD_PLATFORM) {
// AMD platform
SmiPort = 0xb0;
} else {
LfcLibLogError (LFC_LOG_LVAR_GET_PLATFROM_ERROR);
}
// Prepare private data
gBS->AllocatePool (EfiBootServicesData, sizeof (LENOVO_VARIABLE_PRIVATE_DATA), &PrivateData);
SetMem (PrivateData, sizeof (LENOVO_VARIABLE_PRIVATE_DATA), 0);
// Prepare variable buffer and verify
BufferAddress = 0xFFFFFFFF;
gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, Sub1SizeInRom / EFI_PAGE_SIZE, &BufferAddress);
SetMem ((VOID *)(UINTN)BufferAddress, Sub1SizeInRom, 0);
CopyMem ((VOID *)(UINTN)BufferAddress, "LENV", 4);
PrivateData->Signature = LENV_SIGNATURE;
PrivateData->VariableBuffer = (UINT8*)(UINTN)BufferAddress;
LenovoVariableDxeInit (PrivateData);
// Prepare debug buffer
DebugAddress = 0xFFFFFFFF;
gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, DebugSizeInRom / EFI_PAGE_SIZE, &DebugAddress);
PrivateData->DebugBuffer = (UINT8 *)(UINTN)DebugAddress;
// Load BIOS rom debug region to memory
CopyMem (PrivateData->DebugBuffer, (VOID *)(UINTN)DebugBaseInRom, DebugSizeInRom);
// Need to set NextUsable to point to the first one,if it is the first time to boot machine
if (((LENOVO_DEBUG_RIGION_HEADER *)DebugAddress)->NextUsable == 0xffffffff) {
((LENOVO_DEBUG_RIGION_HEADER *)DebugAddress)->NextUsable = sizeof (LENOVO_DEBUG_RIGION_HEADER);
SetMem (PrivateData->DebugBuffer + sizeof(LENOVO_DEBUG_RIGION_HEADER), DebugSizeInRom - sizeof(LENOVO_DEBUG_RIGION_HEADER), 0);
} else {
// Decode
EncodeOrDecodeBuffer (
PrivateData->DebugBuffer,
DebugSizeInRom,
sizeof (LENOVO_DEBUG_RIGION_HEADER),
((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->RandomNumber
);
}
// Install protocol
PrivateData->LenovoVariableInstance.GetVariable = LenovoVariableDxeGetVariable;
PrivateData->LenovoVariableInstance.SetVariable = LenovoVariableDxeSetVariable;
PrivateData->LenovoVariableInstance.LockVariable = LenovoVariableDxeLockVariable;
PrivateData->LenovoVariableInstance.UnlockVariable = LenovoVariableDxeUnlockVariable;
Status = gBS->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gLenovoVariableProtocolGuid,
&(PrivateData->LenovoVariableInstance),
NULL
);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}