From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c | 473 +++++++++++++++++++++ 1 file changed, 473 insertions(+) create mode 100644 src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c') diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c new file mode 100644 index 00000000..bfefd652 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c @@ -0,0 +1,473 @@ +/** @file + DXE capsule report related function. + + Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/** + This routine is called to clear CapsuleOnDisk Relocation Info variable. + Total Capsule On Disk length is recorded in this variable + + @retval EFI_SUCCESS Capsule On Disk flags are cleared + +**/ +EFI_STATUS +CoDClearCapsuleRelocationInfo( + VOID + ); + +/** + Get current capsule last variable index. + + @return Current capsule last variable index. + @retval -1 No current capsule last variable. +**/ +INTN +GetCurrentCapsuleLastIndex ( + VOID + ) +{ + UINTN Size; + CHAR16 CapsuleLastStr[sizeof("Capsule####")]; + EFI_STATUS Status; + UINT16 CurrentIndex; + + Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator + Status = gRT->GetVariable( + L"CapsuleLast", + &gEfiCapsuleReportGuid, + NULL, + &Size, + CapsuleLastStr + ); + if (EFI_ERROR(Status)) { + return -1; + } + CurrentIndex = (UINT16)StrHexToUintn(&CapsuleLastStr[sizeof("Capsule") - 1]); + return CurrentIndex; +} + +/** + Get a new capsule status variable index. + + @return A new capsule status variable index. + @retval 0 No new capsule status variable index. Rolling over. +**/ +INTN +GetNewCapsuleResultIndex ( + VOID + ) +{ + INTN CurrentIndex; + + CurrentIndex = GetCurrentCapsuleLastIndex(); + if (CurrentIndex >= PcdGet16(PcdCapsuleMax)) { + DEBUG((DEBUG_INFO, " CapsuleResult variable Rolling Over!\n")); + return 0; + } + + return CurrentIndex + 1; +} + +/** + Write a new capsule status variable. + + @param[in] CapsuleResult The capsule status variable + @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes + + @retval EFI_SUCCESS The capsule status variable is recorded. + @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable. +**/ +EFI_STATUS +WriteNewCapsuleResultVariable ( + IN VOID *CapsuleResult, + IN UINTN CapsuleResultSize + ) +{ + INTN CapsuleResultIndex; + CHAR16 CapsuleResultStr[sizeof("Capsule####")]; + UINTN Size; + EFI_STATUS Status; + + CapsuleResultIndex = GetNewCapsuleResultIndex(); + DEBUG((DEBUG_INFO, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex)); + + UnicodeSPrint( + CapsuleResultStr, + sizeof(CapsuleResultStr), + L"Capsule%04x", + CapsuleResultIndex + ); + + Status = gRT->SetVariable( + CapsuleResultStr, + &gEfiCapsuleReportGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + CapsuleResultSize, + CapsuleResult + ); + if (!EFI_ERROR(Status)) { + Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator + DEBUG((DEBUG_INFO, "Set CapsuleLast - %s\n", CapsuleResultStr)); + Status = gRT->SetVariable( + L"CapsuleLast", + &gEfiCapsuleReportGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + Size, + CapsuleResultStr + ); + } + + return Status; +} + +/** + Record capsule status variable and to local cache. + + @param[in] CapsuleHeader The capsule image header + @param[in] CapsuleStatus The capsule process stauts + + @retval EFI_SUCCESS The capsule status variable is recorded. + @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable. +**/ +EFI_STATUS +RecordCapsuleStatusVariable ( + IN EFI_CAPSULE_HEADER *CapsuleHeader, + IN EFI_STATUS CapsuleStatus + ) +{ + EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable; + EFI_STATUS Status; + + CapsuleResultVariable.VariableTotalSize = sizeof(CapsuleResultVariable); + CapsuleResultVariable.Reserved = 0; + CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid); + ZeroMem(&CapsuleResultVariable.CapsuleProcessed, sizeof(CapsuleResultVariable.CapsuleProcessed)); + gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL); + CapsuleResultVariable.CapsuleStatus = CapsuleStatus; + + Status = EFI_SUCCESS; + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) { + Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable)); + } + return Status; +} + +/** + Record FMP capsule status variable and to local cache. + + @param[in] CapsuleHeader The capsule image header + @param[in] CapsuleStatus The capsule process stauts + @param[in] PayloadIndex FMP payload index + @param[in] ImageHeader FMP image header + @param[in] FmpDevicePath DevicePath associated with the FMP producer + @param[in] CapFileName Capsule file name + + @retval EFI_SUCCESS The capsule status variable is recorded. + @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable. +**/ +EFI_STATUS +RecordFmpCapsuleStatusVariable ( + IN EFI_CAPSULE_HEADER *CapsuleHeader, + IN EFI_STATUS CapsuleStatus, + IN UINTN PayloadIndex, + IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader, + IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath, OPTIONAL + IN CHAR16 *CapFileName OPTIONAL + ) +{ + EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResultVariableHeader; + EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultVariableFmp; + EFI_STATUS Status; + UINT8 *CapsuleResultVariable; + UINTN CapsuleResultVariableSize; + CHAR16 *DevicePathStr; + UINTN DevicePathStrSize; + UINTN CapFileNameSize; + + DevicePathStr = NULL; + CapFileNameSize = sizeof(CHAR16); + + if (FmpDevicePath != NULL) { + DevicePathStr = ConvertDevicePathToText (FmpDevicePath, FALSE, FALSE); + } + if (DevicePathStr != NULL) { + DevicePathStrSize = StrSize(DevicePathStr); + } else { + DevicePathStrSize = sizeof(CHAR16); + } + + if (CapFileName != NULL) { + CapFileNameSize = StrSize(CapFileName); + } + + // + // Allocate room for CapsuleFileName. + // + CapsuleResultVariableSize = sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize + DevicePathStrSize; + + CapsuleResultVariable = AllocateZeroPool (CapsuleResultVariableSize); + if (CapsuleResultVariable == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CapsuleResultVariableHeader = (VOID *)CapsuleResultVariable; + CapsuleResultVariableHeader->VariableTotalSize = (UINT32)CapsuleResultVariableSize; + CapsuleResultVariableHeader->Reserved = 0; + CopyGuid(&CapsuleResultVariableHeader->CapsuleGuid, &CapsuleHeader->CapsuleGuid); + ZeroMem(&CapsuleResultVariableHeader->CapsuleProcessed, sizeof(CapsuleResultVariableHeader->CapsuleProcessed)); + gRT->GetTime(&CapsuleResultVariableHeader->CapsuleProcessed, NULL); + CapsuleResultVariableHeader->CapsuleStatus = CapsuleStatus; + + CapsuleResultVariableFmp = (VOID *)(CapsuleResultVariable + sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)); + CapsuleResultVariableFmp->Version = 0x1; + CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex; + CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader->UpdateImageIndex; + CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId); + + if (CapFileName != NULL) { + CopyMem((UINT8 *)CapsuleResultVariableFmp + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP), CapFileName, CapFileNameSize); + } + + if (DevicePathStr != NULL) { + CopyMem ((UINT8 *)CapsuleResultVariableFmp + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize, DevicePathStr, DevicePathStrSize); + FreePool (DevicePathStr); + DevicePathStr = NULL; + } + + Status = EFI_SUCCESS; + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) { + Status = WriteNewCapsuleResultVariable(CapsuleResultVariable, CapsuleResultVariableSize); + } + FreePool (CapsuleResultVariable); + return Status; +} + +/** + Initialize CapsuleMax variables. +**/ +VOID +InitCapsuleMaxVariable ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Size; + CHAR16 CapsuleMaxStr[sizeof("Capsule####")]; + EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; + + UnicodeSPrint( + CapsuleMaxStr, + sizeof(CapsuleMaxStr), + L"Capsule%04x", + PcdGet16(PcdCapsuleMax) + ); + + Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator + Status = gRT->SetVariable( + L"CapsuleMax", + &gEfiCapsuleReportGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + Size, + CapsuleMaxStr + ); + if (!EFI_ERROR(Status)) { + // Lock it per UEFI spec. + Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock); + if (!EFI_ERROR(Status)) { + Status = VariableLock->RequestToLock(VariableLock, L"CapsuleMax", &gEfiCapsuleReportGuid); + ASSERT_EFI_ERROR(Status); + } + } +} + +/** + Initialize CapsuleLast variables. +**/ +VOID +InitCapsuleLastVariable ( + VOID + ) +{ + EFI_STATUS Status; + EFI_BOOT_MODE BootMode; + EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; + VOID *CapsuleResult; + UINTN Size; + CHAR16 CapsuleLastStr[sizeof("Capsule####")]; + + BootMode = GetBootModeHob(); + if (BootMode == BOOT_ON_FLASH_UPDATE) { + Status = gRT->SetVariable( + L"CapsuleLast", + &gEfiCapsuleReportGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + 0, + NULL + ); + // Do not lock it because it will be updated later. + } else { + // + // Check if OS/APP cleared L"Capsule####" + // + ZeroMem(CapsuleLastStr, sizeof(CapsuleLastStr)); + Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator + Status = gRT->GetVariable( + L"CapsuleLast", + &gEfiCapsuleReportGuid, + NULL, + &Size, + CapsuleLastStr + ); + if (!EFI_ERROR(Status)) { + // + // L"CapsuleLast" is got, check if data is there. + // + Status = GetVariable2 ( + CapsuleLastStr, + &gEfiCapsuleReportGuid, + (VOID **) &CapsuleResult, + NULL + ); + if (EFI_ERROR(Status)) { + // + // If no data, delete L"CapsuleLast" + // + Status = gRT->SetVariable( + L"CapsuleLast", + &gEfiCapsuleReportGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + 0, + NULL + ); + } else { + if (CapsuleResult != NULL) { + FreePool (CapsuleResult); + } + } + } + + // Lock it in normal boot path per UEFI spec. + Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock); + if (!EFI_ERROR(Status)) { + Status = VariableLock->RequestToLock(VariableLock, L"CapsuleLast", &gEfiCapsuleReportGuid); + ASSERT_EFI_ERROR(Status); + } + } +} + +/** + Initialize capsule update variables. +**/ +VOID +InitCapsuleUpdateVariable ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Index; + CHAR16 CapsuleVarName[30]; + CHAR16 *TempVarName; + + // + // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2... + // as early as possible which will avoid the next time boot after the capsule update + // will still into the capsule loop + // + StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), EFI_CAPSULE_VARIABLE_NAME); + TempVarName = CapsuleVarName + StrLen (CapsuleVarName); + Index = 0; + while (TRUE) { + if (Index > 0) { + UnicodeValueToStringS ( + TempVarName, + sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName), + 0, + Index, + 0 + ); + } + Status = gRT->SetVariable ( + CapsuleVarName, + &gEfiCapsuleVendorGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, + 0, + (VOID *)NULL + ); + if (EFI_ERROR (Status)) { + // + // There is no capsule variables, quit + // + break; + } + Index++; + } +} + +/** + Initialize capsule relocation info variable. +**/ +VOID +InitCapsuleRelocationInfo ( + VOID + ) +{ + EFI_STATUS Status; + EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; + + CoDClearCapsuleRelocationInfo(); + + // + // Unlock Capsule On Disk relocation Info variable only when Capsule On Disk flag is enabled + // + if (!CoDCheckCapsuleOnDiskFlag()) { + Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock); + if (!EFI_ERROR (Status)) { + Status = VariableLock->RequestToLock (VariableLock, COD_RELOCATION_INFO_VAR_NAME, &gEfiCapsuleVendorGuid); + ASSERT_EFI_ERROR (Status); + } + } +} + +/** + Initialize capsule related variables. +**/ +VOID +InitCapsuleVariable ( + VOID + ) +{ + InitCapsuleUpdateVariable(); + InitCapsuleMaxVariable(); + InitCapsuleLastVariable(); + InitCapsuleRelocationInfo(); + + // + // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast" + // to check status and delete them. + // +} -- cgit v1.2.3