//***************************************************************************** // // // 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 #include #include #include #include #include #include #include #include #include #include #include #include #include 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; }