859 lines
30 KiB
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;
|
|
}
|