summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c473
1 files changed, 473 insertions, 0 deletions
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.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/VariableLock.h>
+#include <Guid/CapsuleReport.h>
+#include <Guid/FmpCapsule.h>
+#include <Guid/CapsuleVendor.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/PrintLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/CapsuleLib.h>
+
+#include <IndustryStandard/WindowsUxCapsule.h>
+
+/**
+ 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.
+ //
+}