/** @file ;****************************************************************************** ;* Copyright (c) 2012 - 2016, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ #include "SpecificVariableServiceDxe.h" EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *mSmmFwb = NULL; EFI_STATUS LenovoVariableSyncDataAndBufferWithRom ( IN OUT LENOVO_VARIABLE_PRIVATE_DATA *PrivateData ) { LENOVO_VARIABLE_RIGION_HEADER *FlashRegion1Address; LENOVO_VARIABLE_RIGION_HEADER *FlashRegion2Address; UINT32 L05VariableRegion1Size; UINT32 L05VariableRegion2Size; L05VariableRegion1Size = (UINT32) FdmGetNAtSize (&gL05H2OFlashMapRegionVaribale1Guid, 1); L05VariableRegion2Size = (UINT32) FdmGetNAtSize (&gL05H2OFlashMapRegionVaribale2Guid, 1); FlashRegion1Address = (LENOVO_VARIABLE_RIGION_HEADER *) (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionVaribale1Guid, 1); FlashRegion2Address = (LENOVO_VARIABLE_RIGION_HEADER *) (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionVaribale2Guid, 1); if (FlashRegion1Address->PriorityFlag == 0 && FlashRegion2Address->PriorityFlag == 0) { //Nothing in region PrivateData->Region = LENOVO_VARIABLE_NO_DATA; SetMem (PrivateData->VariableBuffer, L05VariableRegion1Size, 0); CopyMem (PrivateData->VariableBuffer, FlashRegion1Address, sizeof (LENOVO_VARIABLE_RIGION_HEADER)); //Generate RandomNumber { UINT64 TimeStamp; TimeStamp = AsmReadTsc (); while ((UINT8) TimeStamp == 0) { TimeStamp = AsmReadTsc (); } ((LENOVO_VARIABLE_RIGION_HEADER *) PrivateData->VariableBuffer)->RandomNumber = (UINT8) TimeStamp; } } else if (FlashRegion1Address->PriorityFlag > FlashRegion2Address->PriorityFlag) { //Use sub region 1 if (CompareMem (PrivateData->VariableBuffer, FlashRegion1Address, sizeof (LENOVO_VARIABLE_RIGION_HEADER)) == 0 && PrivateData->Region == LENOVO_VARIABLE_USING_REGION_1) { return EFI_SUCCESS; } else { //if not the same, read from ROM to sync PrivateData->Region = LENOVO_VARIABLE_USING_REGION_1; CopyMem (PrivateData->VariableBuffer, FlashRegion1Address, L05VariableRegion1Size); //Verify sub region 1 checksum { UINTN Index; UINT8 *BufferPointer; UINT16 Checksum; Checksum = 0; BufferPointer = PrivateData->VariableBuffer + sizeof (LENOVO_VARIABLE_RIGION_HEADER); for (Index = 0; Index < L05VariableRegion1Size - sizeof (LENOVO_VARIABLE_RIGION_HEADER); Index++) { Checksum += *(BufferPointer + Index); } if (Checksum != FlashRegion1Address->Checksum) { PrivateData->Region = LENOVO_VARIABLE_USING_REGION_2; CopyMem (PrivateData->VariableBuffer, FlashRegion2Address, L05VariableRegion2Size); } } } } else { //Use sub region 2 if (CompareMem (PrivateData->VariableBuffer, FlashRegion2Address, sizeof (LENOVO_VARIABLE_RIGION_HEADER)) == 0 && PrivateData->Region == LENOVO_VARIABLE_USING_REGION_2) { return EFI_SUCCESS; } else { PrivateData->Region = LENOVO_VARIABLE_USING_REGION_2; CopyMem (PrivateData->VariableBuffer, FlashRegion2Address, L05VariableRegion2Size); //Verify sub region 2 checksum { UINTN Index; UINT8 *BufferPointer; UINT16 Checksum; Checksum = 0; BufferPointer = PrivateData->VariableBuffer + sizeof (LENOVO_VARIABLE_RIGION_HEADER); for (Index = 0; Index < L05VariableRegion2Size - sizeof (LENOVO_VARIABLE_RIGION_HEADER); Index++) { Checksum += *(BufferPointer + Index); } if (Checksum != FlashRegion2Address->Checksum) { PrivateData->Region = LENOVO_VARIABLE_USING_REGION_1; CopyMem (PrivateData->VariableBuffer, FlashRegion1Address, L05VariableRegion1Size); } } } } //Decode if (PrivateData->Region != LENOVO_VARIABLE_NO_DATA) { UINT8 *BufferPointer; UINTN Index; BufferPointer = PrivateData->VariableBuffer + sizeof (LENOVO_VARIABLE_RIGION_HEADER); for (Index = 0; Index < L05VariableRegion1Size - 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; } EFI_STATUS LenovoVariableInitRegion ( VOID ) { UINT32 WriteFlashAddress; UINTN WriteFlashSize; UINT8 *BufferAddress; EFI_STATUS Status; UINT32 L05VariableRegion1Size; UINT32 L05VariableRegion2Size; L05VariableRegion1Size = (UINT32) FdmGetNAtSize (&gL05H2OFlashMapRegionVaribale1Guid, 1); L05VariableRegion2Size = (UINT32) FdmGetNAtSize (&gL05H2OFlashMapRegionVaribale2Guid, 1); WriteFlashAddress = (UINT32) FdmGetNAtAddr (&gL05H2OFlashMapRegionVaribale1Guid, 1); WriteFlashSize = L05VariableRegion1Size + L05VariableRegion2Size; BufferAddress = AllocateZeroPool (WriteFlashSize); SetMem (BufferAddress, WriteFlashSize, 0); *(CHAR8 *) (BufferAddress) = 'L'; *(CHAR8 *) (BufferAddress + 1) = 'E'; *(CHAR8 *) (BufferAddress + 2) = 'N'; *(CHAR8 *) (BufferAddress + 3) = 'V'; *(CHAR8 *) (BufferAddress + L05VariableRegion1Size) = 'L'; *(CHAR8 *) (BufferAddress + L05VariableRegion1Size + 1) = 'E'; *(CHAR8 *) (BufferAddress + L05VariableRegion1Size + 2) = 'N'; *(CHAR8 *) (BufferAddress + L05VariableRegion1Size + 3) = 'V'; Status = mSmmFwb->EraseBlocks (mSmmFwb, WriteFlashAddress, &WriteFlashSize); if (!EFI_ERROR (Status)) { Status = mSmmFwb->Write ( mSmmFwb, WriteFlashAddress, &WriteFlashSize, (UINT8 *) BufferAddress ); } FreePool (BufferAddress); return EFI_SUCCESS; } /* Search VariableGuidName from PrivateData->VariableBuffer If found, VariableSizeAddress point to the variable address If not found, VariableSizeAddress = NULL */ VOID LenovoVariableSearchVar ( IN LENOVO_VARIABLE_PRIVATE_DATA *PrivateData, IN EFI_GUID *VariableGuidName, OUT UINT8 **VariableAddress ) { 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; UINTN WriteFlashAddress; UINTN WriteFlashSize; WriteFlashAddress = 0; WriteFlashSize = (UINTN) FdmGetNAtSize (&gL05H2OFlashMapRegionVaribale1Guid, 1); switch (PrivateData->Region) { case LENOVO_VARIABLE_NO_DATA: WriteFlashAddress = (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionVaribale1Guid, 1); break; case LENOVO_VARIABLE_USING_REGION_1: WriteFlashAddress = (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionVaribale2Guid, 1); break; case LENOVO_VARIABLE_USING_REGION_2: WriteFlashAddress = (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionVaribale1Guid, 1); break; default: break; } ((LENOVO_VARIABLE_RIGION_HEADER *) (PrivateData->VariableBuffer))->PriorityFlag++; //Encode { UINT8 *BufferPointer; UINTN Index; BufferPointer = PrivateData->VariableBuffer + sizeof (LENOVO_VARIABLE_RIGION_HEADER); for (Index = 0; Index < WriteFlashSize - 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; Checksum = 0; BufferPointer = PrivateData->VariableBuffer + sizeof (LENOVO_VARIABLE_RIGION_HEADER); for (Index = 0; Index < (UINTN) FdmGetNAtSize (&gL05H2OFlashMapRegionVaribale1Guid, 1) - sizeof (LENOVO_VARIABLE_RIGION_HEADER); Index++) { Checksum += *(BufferPointer + Index); } ((LENOVO_VARIABLE_RIGION_HEADER *) PrivateData->VariableBuffer)->Checksum = Checksum; } //Write buffer to flash Status = mSmmFwb->EraseBlocks (mSmmFwb, WriteFlashAddress, &WriteFlashSize); if (!EFI_ERROR (Status)) { Status = mSmmFwb->Write ( mSmmFwb, 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 { UINT8 *BufferPointer; UINTN Index; BufferPointer = PrivateData->VariableBuffer + sizeof (LENOVO_VARIABLE_RIGION_HEADER); for (Index = 0; Index < WriteFlashSize - sizeof (LENOVO_VARIABLE_RIGION_HEADER); Index++) { *(BufferPointer + Index) = *(BufferPointer + Index) ^ ((LENOVO_VARIABLE_RIGION_HEADER *) PrivateData->VariableBuffer)->RandomNumber; } } return Status; } EFI_STATUS LenovoDeleteVariable ( IN EFI_L05_VARIABLE_PROTOCOL *This, IN EFI_GUID *VariableGuidName ) { EFI_STATUS Status; LENOVO_VARIABLE_PRIVATE_DATA *PrivateData; UINT8 *VariableAddress; UINT8 *ShiftBegin; UINTN ShiftCount; UINTN Index; PrivateData = INSTANCE_FROM_LENV_THIS (This); if (VariableGuidName == NULL) { return EFI_INVALID_PARAMETER; } LenovoVariableSyncDataAndBufferWithRom (PrivateData); 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++; } for (Index = 0; Index < ShiftCount; Index++) { *(ShiftBegin - ShiftCount + Index) = 0; } ((LENOVO_VARIABLE_RIGION_HEADER *) PrivateData->VariableBuffer)->VariableCount--; PrivateData->LastByte -= ShiftCount; Status = LenovoVariableWriteBufferToFlash (PrivateData); return Status; } /*++ Routine Description: Using runtime service GetVariable(DXE) or SMM variable protocol(SMM) to get variable. Variable name always be the same, we only use GUID to distingue variable. Simply return get variable function. --*/ EFI_STATUS L05GetVariable ( IN EFI_L05_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; } LenovoVariableSyncDataAndBufferWithRom (PrivateData); if (PrivateData->Region == LENOVO_VARIABLE_NO_DATA || ((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; } /*++ Routine Description: Using runtime service SetVariable(DXE) or SMM variable protocol(SMM) to set variable. Variable name always be the same, we only use GUID to distingue variable. Simply return set variable function. --*/ EFI_STATUS L05SetVariable ( IN EFI_L05_VARIABLE_PROTOCOL *This, IN EFI_GUID *VariableGuidName, IN UINT32 DataSize, IN VOID *Data ) { EFI_STATUS Status; LENOVO_VARIABLE_PRIVATE_DATA *PrivateData; LENOVO_VARIABLE_RIGION_HEADER *FlashRegion1Address; LENOVO_VARIABLE_RIGION_HEADER *FlashRegion2Address; UINTN L05VariableRegion1Size; UINTN L05VariableRegion2Size; L05VariableRegion1Size = (UINTN) FdmGetNAtSize (&gL05H2OFlashMapRegionVaribale1Guid, 1); L05VariableRegion2Size = (UINTN) FdmGetNAtSize (&gL05H2OFlashMapRegionVaribale2Guid, 1); FlashRegion1Address = (LENOVO_VARIABLE_RIGION_HEADER *) (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionVaribale1Guid, 1); FlashRegion2Address = (LENOVO_VARIABLE_RIGION_HEADER *) (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionVaribale2Guid, 1); PrivateData = INSTANCE_FROM_LENV_THIS (This); if (VariableGuidName == NULL) { return EFI_INVALID_PARAMETER; } LenovoVariableSyncDataAndBufferWithRom (PrivateData); 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) { return LenovoDeleteVariable (This, VariableGuidName); } if (Data == NULL) { return EFI_INVALID_PARAMETER; } //If variable exist, need delete it first Status = LenovoDeleteVariable (This, VariableGuidName); if (Status != EFI_NOT_FOUND && Status != EFI_SUCCESS) { return Status; } //Make sure we have enough space if (PrivateData->Region == LENOVO_VARIABLE_USING_REGION_2) { //Is using region2 if ((UINTN) (PrivateData->LastByte) + sizeof (LENOVO_VARIABLE_VARIABLE) - 1 + DataSize > \ (UINTN) FlashRegion2Address + L05VariableRegion2Size - 1) { return EFI_OUT_OF_RESOURCES; } } else { if ((UINTN) (PrivateData->LastByte) + sizeof (LENOVO_VARIABLE_VARIABLE) - 1 + DataSize > \ (UINTN) FlashRegion1Address + L05VariableRegion1Size - 1) { 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); return Status; } /*++ Routine Description: Not implemented. --*/ EFI_STATUS L05LockVariable ( IN EFI_L05_VARIABLE_PROTOCOL *This, IN EFI_GUID *VariableGuidName ) { LENOVO_VARIABLE_PRIVATE_DATA *PrivateData; UINT8 *VariableAddress; PrivateData = INSTANCE_FROM_LENV_THIS (This); LenovoVariableSyncDataAndBufferWithRom (PrivateData); if (((LENOVO_VARIABLE_RIGION_HEADER *) PrivateData->VariableBuffer)->LockFlag == LENOVO_VARIABLE_REGION_LOCKED) { return EFI_ACCESS_DENIED; } if (PrivateData->Region == LENOVO_VARIABLE_NO_DATA || ((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; return LenovoVariableWriteBufferToFlash (PrivateData); } else { return EFI_NOT_FOUND; } } /*++ Routine Description: Not implemented. --*/ EFI_STATUS L05UnlockVariable ( IN EFI_L05_VARIABLE_PROTOCOL *This, IN EFI_GUID *VariableGuidName, IN CHAR16 *Password ) { LENOVO_VARIABLE_PRIVATE_DATA *PrivateData; UINT8 *VariableAddress; CHAR16 *LenovoVariablePassword = LENOVO_VARIABLE_UNLOCK_PASSWORD; PrivateData = INSTANCE_FROM_LENV_THIS (This); LenovoVariableSyncDataAndBufferWithRom (PrivateData); if (((LENOVO_VARIABLE_RIGION_HEADER *) PrivateData->VariableBuffer)->LockFlag == LENOVO_VARIABLE_REGION_LOCKED) { return EFI_ACCESS_DENIED; } if (PrivateData->Region == LENOVO_VARIABLE_NO_DATA || ((LENOVO_VARIABLE_RIGION_HEADER *) PrivateData->VariableBuffer)->VariableCount == 0) { return EFI_NOT_FOUND; } LenovoVariableSearchVar (PrivateData, VariableGuidName, &VariableAddress); if (VariableAddress != NULL) { //Verify Password if (StrCmp (Password, LenovoVariablePassword) != 0) { return EFI_SECURITY_VIOLATION; } ((LENOVO_VARIABLE_VARIABLE *) VariableAddress)->VariableAttribute &= ~LENOVO_VARIABLE_ATTRIBUTE_LOCKED; return LenovoVariableWriteBufferToFlash (PrivateData); } else { return EFI_NOT_FOUND; } } EFI_STATUS L05VariableServiceDxeEntry ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { LENOVO_VARIABLE_PRIVATE_DATA *PrivateData; EFI_STATUS Status; UINT8 *BufferAddress; LENOVO_VARIABLE_RIGION_HEADER *FlashRegion1Address; LENOVO_VARIABLE_RIGION_HEADER *FlashRegion2Address; Status = EFI_SUCCESS; Status = gBS->LocateProtocol (&gEfiSmmFwBlockServiceProtocolGuid, NULL, (VOID **) &mSmmFwb); if (EFI_ERROR (Status)) { return Status; } FlashRegion1Address = (LENOVO_VARIABLE_RIGION_HEADER *) (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionVaribale1Guid, 1); FlashRegion2Address = (LENOVO_VARIABLE_RIGION_HEADER *) (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionVaribale2Guid, 1); PrivateData = AllocateZeroPool (sizeof (LENOVO_VARIABLE_PRIVATE_DATA)); if (PrivateData == NULL) { return EFI_OUT_OF_RESOURCES; } BufferAddress = AllocateZeroPool ((UINTN) FdmGetNAtSize (&gL05H2OFlashMapRegionVaribale1Guid, 1)); PrivateData->Signature = LENV_SIGNATURE; PrivateData->VariableBuffer = BufferAddress; if (AsciiStrnCmp (FlashRegion1Address->Signature, "LENV", 4) || AsciiStrnCmp (FlashRegion2Address->Signature, "LENV", 4)) { //In case lvar region is unknow data, init it to 'lenv' + all 00 if (EFI_ERROR (LenovoVariableInitRegion ())) { return EFI_UNSUPPORTED; } } LenovoVariableSyncDataAndBufferWithRom (PrivateData); PrivateData->LenovoVariableInstance.GetVariable = L05GetVariable; PrivateData->LenovoVariableInstance.SetVariable = L05SetVariable; PrivateData->LenovoVariableInstance.LockVariable = L05LockVariable; PrivateData->LenovoVariableInstance.UnlockVariable = L05UnlockVariable; Status = gBS->InstallProtocolInterface ( &ImageHandle, &gEfiL05VariableProtocolGuid, EFI_NATIVE_INTERFACE, &(PrivateData->LenovoVariableInstance) ); if (EFI_ERROR (Status)) { return Status; } return Status; }