//***************************************************************************** // // // Copyright (c) 2012 - 2020, 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.19 dahai.zhou v1.12 Support AMD platform Fix spell 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.12 feng.gu v1.21 Fix the issue that compare decoded debug datas in ram with encoded debug datas in BIOS ROM 2015.01.15 feng.gu v1.22 Use EncodeOrDecodeBuffer and FlashToBiosRom functions uniformly. 2016.12.28 feng.gu v1.24 Fix the bug that debug region will overflow 2020.03.02 dahai.zhou v1.25 Fix the hang 0x15 issue from TGL platform, variable attibute mismatch 2020.03.02 feng.gu v1.26 Modify lock,unlock and delete action log data and add SMI data port for DXE to SMM. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //[-start-220210-Dongxu0040-Modify]// #include //[-end-220210-Dongxu0040-Modify]// UINT32 Sub1BaseInRom = 0; UINT32 Sub1SizeInRom = 0; UINT32 Sub2BaseInRom = 0; UINT32 Sub2SizeInRom = 0; UINT32 DebugBaseInRom = 0; UINT32 DebugSizeInRom = 0; EFI_PHYSICAL_ADDRESS mApplicationBufferAddress; 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 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; } // Add and save Data about SetVariable, LockVariable, UnlockVariable action to BIOS ROM EFI_STATUS LenovoVariableSmmAddDebugData ( 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 LenovoVariableInitRegionAndBuffer ( IN LENOVO_VARIABLE_PRIVATE_DATA *PrivateData ) { UINTN WriteFlashAddress; UINTN WriteFlashSize; UINT8 *BufferAddress; BufferAddress = (UINT8*)PrivateData->VariableBuffer; SetMem (BufferAddress, Sub1SizeInRom, 0); *(BufferAddress) = 'L'; *(BufferAddress + 1) = 'E'; *(BufferAddress + 2) = 'N'; *(BufferAddress + 3) = 'V'; WriteFlashAddress = Sub1BaseInRom; WriteFlashSize = Sub1SizeInRom; FlashToBiosRom (WriteFlashAddress, WriteFlashSize, BufferAddress); WriteFlashAddress = Sub2BaseInRom; WriteFlashSize = Sub2SizeInRom; FlashToBiosRom (WriteFlashAddress, WriteFlashSize, BufferAddress); return EFI_SUCCESS; } VOID LenovoVariableSearchVar ( 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; } 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 LenovoVariableSmmGetVariable ( 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; 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; } LenovoVariableSearchVar (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 LenovoVariableSmmDeleteVariable ( IN LENOVO_VARIABLE_PROTOCOL *This, IN EFI_GUID *VariableGuidName ) { EFI_STATUS Status; 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; } LenovoVariableSearchVar (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; Status = LenovoVariableWriteBufferToFlash (PrivateData); return Status; } EFI_STATUS LenovoVariableSmmSetVariable ( IN LENOVO_VARIABLE_PROTOCOL *This, IN EFI_GUID *VariableGuidName, IN UINT32 DataSize, IN VOID *Data ) { EFI_STATUS Status; LENOVO_VARIABLE_PRIVATE_DATA *PrivateData; 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 = LenovoVariableSmmDeleteVariable (This, VariableGuidName); LenovoVariableSmmAddDebugData (PrivateData, VariableGuidName, SET_VARIABLE_FUNCTION, DataSize); return Status; } if (Data == NULL) { return EFI_INVALID_PARAMETER; } // If variable exist, need delete it first Status = LenovoVariableSmmDeleteVariable (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++; Status = LenovoVariableWriteBufferToFlash (PrivateData); LenovoVariableSmmAddDebugData (PrivateData, VariableGuidName, SET_VARIABLE_FUNCTION, DataSize); return Status; } EFI_STATUS LenovoVariableSmmLockVariable ( IN LENOVO_VARIABLE_PROTOCOL *This, IN EFI_GUID *VariableGuidName ) { LENOVO_VARIABLE_PRIVATE_DATA *PrivateData; UINT8 *VariableAddress; 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; } LenovoVariableSearchVar (PrivateData, VariableGuidName, &VariableAddress); if (VariableAddress != NULL) { ((LENOVO_VARIABLE_VARIABLE *)VariableAddress)->VariableAttribute |= LENOVO_VARIABLE_ATTRIBUTE_LOCKED; LenovoVariableSmmAddDebugData (PrivateData, VariableGuidName, LOCK_VARIABLE_FUNCTION, 0); return LenovoVariableWriteBufferToFlash (PrivateData); } else { return EFI_NOT_FOUND; } } EFI_STATUS LenovoVariableSmmUnlockVariable ( 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; 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; } LenovoVariableSearchVar (PrivateData, VariableGuidName, &VariableAddress); if (VariableAddress != NULL) { // Verify Password if (FailCount == LENOVO_VARIABLE_UNLOCK_FAIL_MAX) { return EFI_SECURITY_VIOLATION; } if (StrCmp (Password, LenovoVariablePassword) != 0) { FailCount++; return EFI_SECURITY_VIOLATION; } ((LENOVO_VARIABLE_VARIABLE *)VariableAddress)->VariableAttribute &= ~LENOVO_VARIABLE_ATTRIBUTE_LOCKED; LenovoVariableSmmAddDebugData (PrivateData, VariableGuidName, UNLOCK_VARIABLE_FUNCTION, (UINT32)StrLen (Password)); return LenovoVariableWriteBufferToFlash (PrivateData); } else { return EFI_NOT_FOUND; } } EFI_STATUS LenovoLockVariableRegion ( IN LENOVO_VARIABLE_PROTOCOL *This ) { return EFI_UNSUPPORTED; } EFI_STATUS LenovoUnlockVariableRegion ( IN LENOVO_VARIABLE_PROTOCOL *This, IN CHAR16 *Password ) { return EFI_UNSUPPORTED; } EFI_STATUS EFIAPI LenovoVariableDxeToSmm ( VOID ) { EFI_STATUS Status; SMAPI_DATA *DxeSmmDataRt = NULL; UINTN DataSize = sizeof (SMAPI_DATA*); LENOVO_VARIABLE_PROTOCOL *LenovoVariableInstance; EFI_SMM_VARIABLE_PROTOCOL *SmmVariable; UINT32 Attributes; Status = gSmst->SmmLocateProtocol (&gLenovoVariableProtocolGuid, NULL, &LenovoVariableInstance); ASSERT_EFI_ERROR (Status); Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, &SmmVariable); ASSERT_EFI_ERROR (Status); Status = SmmVariable->SmmGetVariable ( LENOVO_VARIABLE_DXE_SMM_DATA_VARIABLE_NAME, &gLfcVariableGuid, &Attributes, &DataSize, &DxeSmmDataRt ); if (!SmmIsBufferOutsideSmmValid ((UINTN) (DxeSmmDataRt),(UINTN)(DataSize))) { DEBUG ((DEBUG_ERROR, "LenovoVariableDxeToSmm: Runtime non-volatile cache buffer in SMRAM or overflow!\n")); return EFI_UNSUPPORTED; } if (EFI_ERROR (Status) || (Attributes != EFI_VARIABLE_BOOTSERVICE_ACCESS)) { return EFI_SUCCESS; } switch (DxeSmmDataRt->FunctionCode) { case GET_VARIABLE_FUNCTION: *((EFI_STATUS *)(DxeSmmDataRt->Name)) = LenovoVariableInstance->GetVariable ( LenovoVariableInstance, &(DxeSmmDataRt->VariableGuidName), &(DxeSmmDataRt->DataLength), DxeSmmDataRt->Data ); break; case SET_VARIABLE_FUNCTION: *((EFI_STATUS *)(DxeSmmDataRt->Name)) = LenovoVariableInstance->SetVariable ( LenovoVariableInstance, &(DxeSmmDataRt->VariableGuidName), DxeSmmDataRt->DataLength, DxeSmmDataRt->Data ); break; case LOCK_VARIABLE_FUNCTION: *((EFI_STATUS *)(DxeSmmDataRt->Name)) = LenovoVariableInstance->LockVariable ( LenovoVariableInstance, &(DxeSmmDataRt->VariableGuidName) ); break; case UNLOCK_VARIABLE_FUNCTION: *((EFI_STATUS *)(DxeSmmDataRt->Name)) = LenovoVariableInstance->UnlockVariable ( LenovoVariableInstance, &(DxeSmmDataRt->VariableGuidName), (CHAR16*)(DxeSmmDataRt->Data) ); break; default: break; } // Delete variable after use Status = SmmVariable->SmmSetVariable ( LENOVO_VARIABLE_DXE_SMM_DATA_VARIABLE_NAME, &gLfcVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL ); return EFI_SUCCESS; } EFI_STATUS EFIAPI LenovoVariableSmiCallback ( IN EFI_HANDLE DispatchHandle, IN CONST VOID *Context OPTIONAL, IN OUT VOID *CommBuffer OPTIONAL, IN OUT UINTN *CommBufferSize OPTIONAL ) /* SW SMI handler. Input: AX = 5380h BX = Function number ECX = Physical memory address (SMAPI_DATA) EDI = Physics address high 32bit of BOOT_DEVICE_DATA Output: AH - C Return status */ { EFI_STATUS Status; UINTN CpuIndex; UINT32 TempValue; SMAPI_DATA *SmiData = NULL; UINTN SmiDataAddressLow32, SmiDataAddressHigh32; LENOVO_VARIABLE_PROTOCOL *LenovoVariableInstance; LENOVO_VARIABLE_PRIVATE_DATA *PrivateData; UINT8 *Head; CHAR16 *LenovoVariablePassword = LENOVO_VARIABLE_DUMP_PASSWORD; static UINTN FailCount = 0; UINT8 SmiFunctionNum; //[-start-220210-Dongxu0040-Modify]// UINT8 ValidTool = 0; //[-end-220210-Dongxu0040-Modify]// Status = IdentifyCpuIndexByEax (LENOVO_VARIABLE_FLAG|LENOVO_VARIABLE_CALLBACK, 0xffff, &CpuIndex); if (EFI_ERROR (Status)) { GetSwSmiSubFunctionNumber (&SmiFunctionNum); if (SmiFunctionNum == LENOVO_VARIABLE_DXE_TO_SMM_FLAG && IdentifyCpuIndexByEax (LENOVO_VARIABLE_CALLBACK, 0xff, &CpuIndex) == EFI_SUCCESS ){ //Clear SMI data port SetSwSmiSubFunctionNumber (0); LenovoVariableDxeToSmm (); return EFI_SUCCESS; } } Status = GetDwordRegisterByCpuIndex (EFI_SMM_SAVE_STATE_REGISTER_RCX, CpuIndex, sizeof (UINT32), &TempValue); ASSERT_EFI_ERROR (Status); SmiDataAddressLow32 = (UINTN)TempValue; Status = GetDwordRegisterByCpuIndex (EFI_SMM_SAVE_STATE_REGISTER_RDI, CpuIndex, sizeof (UINT32), &TempValue); ASSERT_EFI_ERROR (Status); SmiDataAddressHigh32 = (UINTN)(((UINT64)TempValue)<<32); SmiData = (SMAPI_DATA *)(SmiDataAddressLow32 + SmiDataAddressHigh32); Status = gSmst->SmmLocateProtocol (&gLenovoVariableProtocolGuid, NULL, &LenovoVariableInstance); ASSERT_EFI_ERROR (Status); Status = GetDwordRegisterByCpuIndex (EFI_SMM_SAVE_STATE_REGISTER_RBX, CpuIndex, sizeof (UINT16), &TempValue); ASSERT_EFI_ERROR (Status); if (((UINT16)TempValue!=GET_BUFFER_ADDRESS_FUNCTION )&&((UINT16)TempValue!=DUMP_REGION_FUNCTION)){ if (!SmmIsBufferOutsideSmmValid ( (UINTN) (SmiDataAddressLow32 + SmiDataAddressHigh32), (UINTN)(sizeof(SMAPI_DATA) + SmiData->DataLength -1))) { DEBUG ((DEBUG_ERROR, "LenovoVariableSmiCallback: Runtime non-volatile cache buffer in SMRAM or overflow!\n")); return EFI_UNSUPPORTED; } } //[-start-220210-Dongxu0040-Modify]// Status = LfcCheckValidTool(&ValidTool); if(ValidTool != 0X55){ return EFI_UNSUPPORTED; } //[-end-220210-Dongxu0040-Modify]// switch ((UINT16)TempValue) { case GET_VARIABLE_FUNCTION: Status = LenovoVariableInstance->GetVariable ( LenovoVariableInstance, &(SmiData->VariableGuidName), &(SmiData->DataLength), SmiData->Data ); if (!EFI_ERROR(Status)) { TempValue = LVAR_SUCCESS<<8; } else if (Status == EFI_BUFFER_TOO_SMALL) { TempValue = LVAR_BUFFER_TOO_SMALL<<8; } else if (Status == EFI_NOT_FOUND) { TempValue = LVAR_NOT_FOUND<<8; } else { TempValue = LVAR_OTHER_ERROR<<8; } break; case SET_VARIABLE_FUNCTION: Status = LenovoVariableInstance->SetVariable ( LenovoVariableInstance, &(SmiData->VariableGuidName), SmiData->DataLength, SmiData->Data ); if (!EFI_ERROR(Status)) { TempValue = LVAR_SUCCESS<<8; } else if (Status == EFI_ACCESS_DENIED) { TempValue = LVAR_REGIONE_LOCKED<<8; } else if (Status == EFI_NOT_FOUND) { TempValue = LVAR_NOT_FOUND<<8; } else if (Status == EFI_WRITE_PROTECTED) { TempValue = LVAR_VARIABLE_LOCKED<<8; } else { TempValue = LVAR_OTHER_ERROR<<8; } break; // Keep this for old version tool case DELETE_VARIABLE_FUNCTION: Status = LenovoVariableInstance->SetVariable ( LenovoVariableInstance, &(SmiData->VariableGuidName), 0, SmiData->Data ); if (!EFI_ERROR(Status)) { TempValue = LVAR_SUCCESS<<8; } else if (Status == EFI_ACCESS_DENIED) { TempValue = LVAR_REGIONE_LOCKED<<8; } else if (Status == EFI_NOT_FOUND) { TempValue = LVAR_NOT_FOUND<<8; } else if (Status == EFI_WRITE_PROTECTED) { TempValue = LVAR_VARIABLE_LOCKED<<8; } else { TempValue = LVAR_OTHER_ERROR<<8; } break; case LOCK_VARIABLE_FUNCTION: Status = LenovoVariableInstance->LockVariable ( LenovoVariableInstance, &(SmiData->VariableGuidName) ); if (!EFI_ERROR(Status)) { TempValue = LVAR_SUCCESS<<8; } else if (Status == EFI_ACCESS_DENIED) { TempValue = LVAR_REGIONE_LOCKED<<8; } else if (Status == EFI_NOT_FOUND) { TempValue = LVAR_NOT_FOUND<<8; } else { TempValue = LVAR_OTHER_ERROR<<8; } break; case UNLOCK_VARIABLE_FUNCTION: Status = LenovoVariableInstance->UnlockVariable ( LenovoVariableInstance, &(SmiData->VariableGuidName), (CHAR16 *)SmiData->Data ); if (!EFI_ERROR(Status)) { TempValue = LVAR_SUCCESS<<8; } else if (Status == EFI_SECURITY_VIOLATION) { TempValue = LVAR_PASSWORD_WRONG<<8; } else if (Status == EFI_ACCESS_DENIED) { TempValue = LVAR_REGIONE_LOCKED<<8; } else if (Status == EFI_NOT_FOUND) { TempValue = LVAR_NOT_FOUND<<8; } else { TempValue = LVAR_OTHER_ERROR<<8; } break; case DUMP_REGION_FUNCTION: // If SmiData has enough space about 16KB to save data if (SmiData->DataLength == 0x4000) { Head = SmiData->Data; PrivateData = INSTANCE_FROM_LENV_THIS (LenovoVariableInstance); // Check password in SmiData->Data transmited from input of tool if (FailCount == LENOVO_VARIABLE_UNLOCK_FAIL_MAX) { TempValue = LVAR_PASSWORD_WRONG<<8; SetDwordRegisterByCpuIndex (EFI_SMM_SAVE_STATE_REGISTER_RAX, CpuIndex, sizeof (UINT32), &TempValue); return EFI_SUCCESS; } if (StrCmp ((CHAR16 *)Head, LenovoVariablePassword) != 0) { FailCount++; TempValue = LVAR_PASSWORD_WRONG<<8; SetDwordRegisterByCpuIndex (EFI_SMM_SAVE_STATE_REGISTER_RAX, CpuIndex, sizeof (UINT32), &TempValue); return EFI_SUCCESS; } // Copy LenovoVariable region1 and 2 and bedug region to BIOS ROM CopyMem (Head, (VOID *)(UINTN)Sub1BaseInRom, Sub1SizeInRom); EncodeOrDecodeBuffer (Head, Sub1SizeInRom, sizeof (LENOVO_VARIABLE_RIGION_HEADER), ((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->RandomNumber); Head += Sub1SizeInRom; CopyMem (Head, (VOID *)(UINTN)Sub2BaseInRom, Sub2SizeInRom); EncodeOrDecodeBuffer (Head, Sub2SizeInRom, sizeof (LENOVO_VARIABLE_RIGION_HEADER), ((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->RandomNumber); Head += Sub2SizeInRom; CopyMem (Head, (VOID *)(UINTN)DebugBaseInRom, DebugSizeInRom); EncodeOrDecodeBuffer (Head, DebugSizeInRom, sizeof (LENOVO_DEBUG_RIGION_HEADER), ((LENOVO_VARIABLE_RIGION_HEADER*)PrivateData->VariableBuffer)->RandomNumber); } else { TempValue = LVAR_OTHER_ERROR<<8; } break; case GET_BUFFER_ADDRESS_FUNCTION: TempValue = (UINT32)mApplicationBufferAddress; Status = SetDwordRegisterByCpuIndex (EFI_SMM_SAVE_STATE_REGISTER_RCX, CpuIndex, sizeof (UINT32), &TempValue); // Low 32bit TempValue = (UINT32)(mApplicationBufferAddress>>32); Status = SetDwordRegisterByCpuIndex (EFI_SMM_SAVE_STATE_REGISTER_RDI, CpuIndex, sizeof (UINT32), &TempValue); // High 32bit TempValue = LVAR_SUCCESS<<8; break; default: TempValue = LVAR_FUNCTION_NUMBER_WRONG<<8; break; } SetDwordRegisterByCpuIndex (EFI_SMM_SAVE_STATE_REGISTER_RAX, CpuIndex, sizeof (UINT32), &TempValue); return EFI_SUCCESS; } EFI_STATUS EFIAPI LenovoVariableSmmEntry ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) /* This driver will decode the LENOVO_VARIABLE_REGION_SUBREGION_1 or 2 and copy it to memory Which sub region is depend on the PriorityFlag field And install a protocol, later read/write will be in memory */ { EFI_STATUS Status; LENOVO_VARIABLE_PRIVATE_DATA *PrivateData; LENOVO_VARIABLE_PRIVATE_DATA *PrivateDataSmm; EFI_PHYSICAL_ADDRESS BufferAddressSmm; EFI_PHYSICAL_ADDRESS DebugAddressSmm; LENOVO_VARIABLE_PROTOCOL *LenovoVariable = NULL; if (!InSmm ()) { return EFI_UNSUPPORTED; } 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_SMM_ROM_ERROR); return EFI_SUCCESS; } // Prepare buffer for OS application mApplicationBufferAddress = 0xFFFFFFFF; gBS->AllocatePages (AllocateMaxAddress, EfiReservedMemoryType, APP_BUFFER_SIZE_IN_PAGE, &mApplicationBufferAddress); Status = gBS->LocateProtocol (&gLenovoVariableProtocolGuid, NULL, &LenovoVariable); if (EFI_ERROR (Status)) { return EFI_SUCCESS; } PrivateData = INSTANCE_FROM_LENV_THIS (LenovoVariable); // Prepare private data gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof (LENOVO_VARIABLE_PRIVATE_DATA), &PrivateDataSmm); SetMem (PrivateDataSmm, sizeof (LENOVO_VARIABLE_PRIVATE_DATA), 0); // Prepare variable buffer and verify BufferAddressSmm = 0xFFFFFFFF; gSmst->SmmAllocatePages (AllocateMaxAddress, EfiRuntimeServicesData, Sub1SizeInRom / EFI_PAGE_SIZE, &BufferAddressSmm); CopyMem ((VOID *)(UINTN)BufferAddressSmm, PrivateData->VariableBuffer, Sub1SizeInRom); PrivateDataSmm->Signature = LENV_SIGNATURE; PrivateDataSmm->Region = PrivateData->Region; PrivateDataSmm->VariableBuffer = (UINT8 *)(UINTN)BufferAddressSmm; PrivateDataSmm->LastByte = PrivateDataSmm->VariableBuffer + (PrivateData->LastByte - PrivateData->VariableBuffer); // Encode EncodeOrDecodeBuffer (PrivateDataSmm->VariableBuffer, Sub1SizeInRom, sizeof (LENOVO_VARIABLE_RIGION_HEADER), ((LENOVO_VARIABLE_RIGION_HEADER*)PrivateDataSmm->VariableBuffer)->RandomNumber); if ((CompareMem (PrivateDataSmm->VariableBuffer, (VOID *)(UINTN)Sub1BaseInRom, Sub1SizeInRom) != 0) && \ (CompareMem (PrivateDataSmm->VariableBuffer, (VOID *)(UINTN)Sub2BaseInRom, Sub2SizeInRom) != 0)) { // Decode EncodeOrDecodeBuffer (PrivateDataSmm->VariableBuffer, Sub1SizeInRom, sizeof (LENOVO_VARIABLE_RIGION_HEADER), ((LENOVO_VARIABLE_RIGION_HEADER*)PrivateDataSmm->VariableBuffer)->RandomNumber); LenovoVariableWriteBufferToFlash (PrivateDataSmm); } else { // EncodeOrDecode (PrivateDataSmm); EncodeOrDecodeBuffer (PrivateDataSmm->VariableBuffer, Sub1SizeInRom, sizeof (LENOVO_VARIABLE_RIGION_HEADER), ((LENOVO_VARIABLE_RIGION_HEADER*)PrivateDataSmm->VariableBuffer)->RandomNumber); } // Copy debug data from Dxe phase to SMM RAM DebugAddressSmm = 0xFFFFFFFF; gSmst->SmmAllocatePages (AllocateMaxAddress, EfiRuntimeServicesData, DebugSizeInRom / EFI_PAGE_SIZE, &DebugAddressSmm); CopyMem ((VOID *)(UINTN)DebugAddressSmm, PrivateData->DebugBuffer, DebugSizeInRom); PrivateDataSmm->DebugBuffer = (UINT8 *)(UINTN)DebugAddressSmm; // Encode EncodeOrDecodeBuffer (PrivateDataSmm->DebugBuffer, DebugSizeInRom, sizeof (LENOVO_DEBUG_RIGION_HEADER), ((LENOVO_VARIABLE_RIGION_HEADER*)PrivateDataSmm->VariableBuffer)->RandomNumber); // Flash debug data to BIOS ROM when SMM RAM is different from BIOS ROM if (CompareMem (PrivateDataSmm->DebugBuffer, (VOID *)(UINTN)DebugBaseInRom, DebugSizeInRom) != 0) { FlashToBiosRom (DebugBaseInRom, DebugSizeInRom, PrivateDataSmm->DebugBuffer); } // Decode EncodeOrDecodeBuffer (PrivateDataSmm->DebugBuffer, DebugSizeInRom, sizeof (LENOVO_DEBUG_RIGION_HEADER), ((LENOVO_VARIABLE_RIGION_HEADER*)PrivateDataSmm->VariableBuffer)->RandomNumber); // Install protocol { EFI_HANDLE LenovoVariableHandle = NULL; PrivateDataSmm->LenovoVariableInstance.GetVariable = LenovoVariableSmmGetVariable; PrivateDataSmm->LenovoVariableInstance.SetVariable = LenovoVariableSmmSetVariable; PrivateDataSmm->LenovoVariableInstance.LockVariable = LenovoVariableSmmLockVariable; PrivateDataSmm->LenovoVariableInstance.UnlockVariable = LenovoVariableSmmUnlockVariable; Status = gSmst->SmmInstallProtocolInterface ( &LenovoVariableHandle, &gLenovoVariableProtocolGuid, EFI_NATIVE_INTERFACE, &(PrivateDataSmm->LenovoVariableInstance) ); ASSERT_EFI_ERROR (Status); } // Register Software SMI { EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; EFI_SMM_SW_REGISTER_CONTEXT SwContext; EFI_HANDLE SwHandle; Status = gSmst->SmmLocateProtocol ( &gEfiSmmSwDispatch2ProtocolGuid, NULL, &SwDispatch ); ASSERT_EFI_ERROR (Status); SwContext.SwSmiInputValue = LENOVO_VARIABLE_CALLBACK; Status = SwDispatch->Register ( SwDispatch, LenovoVariableSmiCallback, &SwContext, &SwHandle ); ASSERT_EFI_ERROR (Status); } // Tell DXE protocol that SMI is ready { UINT8 Ready = 1; Status = gRT->SetVariable ( LENOVO_VARIABLE_SMI_READY_FLAG_VARIABLE_NAME, &gLfcVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 1, &Ready ); } return EFI_SUCCESS; }