From b87fc6b140772ba3017de311c7063c259424264c Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 15 Aug 2016 17:11:31 +0200 Subject: First public release. Used by VeraCrypt 1.18. --- Library/CommonLib/EfiVar.c | 228 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 Library/CommonLib/EfiVar.c (limited to 'Library/CommonLib/EfiVar.c') diff --git a/Library/CommonLib/EfiVar.c b/Library/CommonLib/EfiVar.c new file mode 100644 index 0000000..2a6e59e --- /dev/null +++ b/Library/CommonLib/EfiVar.c @@ -0,0 +1,228 @@ +/** @file +EFI firmware variable helpers + +Copyright (c) 2016. Disk Cryptography Services for EFI (DCS), Alex Kolotnikov +Copyright (c) 2016. VeraCrypt, Mounir IDRASSI + +This program and the accompanying materials are licensed and made available +under the terms and conditions of the GNU Lesser General Public License, version 3.0 (LGPL-3.0). + +The full text of the license may be found at +https://opensource.org/licenses/LGPL-3.0 +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +////////////////////////////////////////////////////////////////////////// +// Efi variables +////////////////////////////////////////////////////////////////////////// + +EFI_STATUS +EfiGetVar( + IN CONST CHAR16* varName, + IN EFI_GUID* varGuid, + OUT VOID** varValue, + OUT UINTN* varSize, + OUT UINT32* varAttr + ) { + EFI_STATUS Status; + CHAR8 *varData = NULL; + if (varSize == NULL) return EFI_INVALID_PARAMETER; + *varSize = 0; + if (varGuid == NULL) varGuid = &gEfiDcsVariableGuid; + Status = gST->RuntimeServices->GetVariable((CHAR16*)varName, varGuid, varAttr, varSize, varData); + if (Status == EFI_BUFFER_TOO_SMALL) { + varData = MEM_ALLOC(*varSize); + if (varData == NULL) { + return EFI_BUFFER_TOO_SMALL; + } + Status = gST->RuntimeServices->GetVariable((CHAR16*)varName, varGuid, varAttr, varSize, varData); + *varValue = varData; + } + return Status; +} + + +EFI_STATUS +EfiSetVar( + IN CONST CHAR16* varName, + IN EFI_GUID* varGuid, + IN VOID* varValue, + IN UINTN varSize, + IN UINT32 varAttr + ) { + EFI_STATUS Status; + if (varGuid == NULL) varGuid = &gEfiDcsVariableGuid; + Status = gST->RuntimeServices->SetVariable((CHAR16*)varName, varGuid, varAttr, varSize, varValue); + return Status; +} + +EFI_STATUS +BootOrderInsert( + IN CHAR16 *OrderVarName, + IN UINTN index, + UINT16 value) +{ + EFI_STATUS res = EFI_NOT_READY; + UINT16* varBootOrderNew; + UINT16* varBootOrder; + UINTN varBootOrderSize; + UINT32 varBootOrderAttr; + UINTN BootOrderCount; + UINTN i; + UINTN j; + res = EfiGetVar(OrderVarName, &gEfiGlobalVariableGuid, &varBootOrder, &varBootOrderSize, &varBootOrderAttr); + if (EFI_ERROR(res)) return res; + BootOrderCount = varBootOrderSize / sizeof(UINT16); + varBootOrderNew = MEM_ALLOC((BootOrderCount + 1) * sizeof(UINT16)); + if (BootOrderCount < index) index = BootOrderCount - 1; + for (j = 0, i = 0; i < BootOrderCount; ++i) { + if (j == index) { + varBootOrderNew[j] = value; + j++; + } + if (varBootOrder[i] == value) { + continue; + } + varBootOrderNew[j] = varBootOrder[i]; + ++j; + } + BootOrderCount = j; + + res = EfiSetVar(OrderVarName, &gEfiGlobalVariableGuid, + varBootOrderNew, BootOrderCount * sizeof(UINT16), + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS); + MEM_FREE(varBootOrderNew); + MEM_FREE(varBootOrder); + return res; +} + +EFI_STATUS +BootOrderRemove( + IN CHAR16 *OrderVarName, + UINT16 value) +{ + EFI_STATUS res = EFI_NOT_READY; + UINT16* varBootOrderNew; + UINT16* varBootOrder; + UINTN varBootOrderSize; + UINT32 varBootOrderAttr; + UINTN BootOrderCount; + UINTN i; + UINTN j; + + res = EfiGetVar(OrderVarName, &gEfiGlobalVariableGuid, &varBootOrder, &varBootOrderSize, &varBootOrderAttr); + if (EFI_ERROR(res)) return res; + BootOrderCount = varBootOrderSize / sizeof(UINT16); + varBootOrderNew = MEM_ALLOC((BootOrderCount + 1) * sizeof(UINT16)); + for (j = 0, i = 0; i < BootOrderCount; ++i) { + if (varBootOrder[i] == value) { + continue; + } + varBootOrderNew[j] = varBootOrder[i]; + ++j; + } + BootOrderCount = j; + + res = EfiSetVar(OrderVarName, &gEfiGlobalVariableGuid, + varBootOrderNew, BootOrderCount * sizeof(UINT16), + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS); + + MEM_FREE(varBootOrderNew); + MEM_FREE(varBootOrder); + return res; +} + +EFI_STATUS +BootMenuItemRemove( + IN CHAR16 *VarName + ) +{ + EFI_STATUS res = EFI_NOT_READY; + res = EfiSetVar( + VarName, &gEfiGlobalVariableGuid, + NULL, 0, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS); + return res; +} + +EFI_STATUS +BootMenuItemCreate( + IN CHAR16 *VarName, + IN CHAR16 *Desc, + IN EFI_HANDLE volumeHandle, + IN CHAR16 *Path, + IN BOOLEAN Reduced + ) +{ + EFI_STATUS res = EFI_NOT_READY; + UINT8* varBoot; + UINT8* TempByteBuffer; + UINTN DescSize; + UINTN FilePathSize; + EFI_DEVICE_PATH_PROTOCOL* DevPath; + EFI_DEVICE_PATH_PROTOCOL* DevicePath; + EFI_DEVICE_PATH_PROTOCOL* FileNode; + EFI_DEVICE_PATH_PROTOCOL* FilePath; + + // Prepare + DevicePath = DevicePathFromHandle(volumeHandle); + if (Reduced) { + DevPath = DevicePath; + while (!IsDevicePathEnd(DevPath)) { + if ((DevicePathType(DevPath) == MEDIA_DEVICE_PATH) && + (DevicePathSubType(DevPath) == MEDIA_HARDDRIVE_DP)) { + + // + // If we find it use it instead + // + DevicePath = DevPath; + break; + } + DevPath = NextDevicePathNode(DevPath); + } + } + // + // append the file + // + FileNode = FileDevicePath(NULL, Path); + FilePath = AppendDevicePath(DevicePath, FileNode); + FreePool(FileNode); + // + // Add the option + // + DescSize = StrSize(Desc); + FilePathSize = GetDevicePathSize(FilePath); + + varBoot = MEM_ALLOC(sizeof(UINT32) + sizeof(UINT16) + DescSize + FilePathSize); + if (varBoot != NULL) { + TempByteBuffer = varBoot; + *((UINT32 *)TempByteBuffer) = LOAD_OPTION_ACTIVE; // Attributes + TempByteBuffer += sizeof(UINT32); + + *((UINT16 *)TempByteBuffer) = (UINT16)FilePathSize; // FilePathListLength + TempByteBuffer += sizeof(UINT16); + + CopyMem(TempByteBuffer, Desc, DescSize); + TempByteBuffer += DescSize; + CopyMem(TempByteBuffer, FilePath, FilePathSize); + + res = EfiSetVar(VarName, &gEfiGlobalVariableGuid, + varBoot, sizeof(UINT32) + sizeof(UINT16) + DescSize + FilePathSize, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS); + } + else { + return EFI_BUFFER_TOO_SMALL; + } + + MEM_FREE(varBoot); + return res; +} -- cgit v1.2.3