From: Duke Zhai <Duke.Zhai@amd.com>
BZ #:4640
In V2: Improve coding style.
1.Remove the leading underscore and use double underscore at trailing in C header files.
2.Remove old tianocore licenses and redundant license description.
3.Improve coding style. For example: remove space between @param.
In V1:
Chachani board supports "Capsule on Disk (CoD)" feature defined in UEFI
Spec chapter 8.5.5 "Delivery of Capsules via file on Mass Storage Device".
The BIOS capsule image is saved in hard disk as default setting.
Signed-off-by: Ken Yao <ken.yao@amd.com>
Cc: Duke Zhai <duke.zhai@amd.com>
Cc: Eric Xing <eric.xing@amd.com>
Cc: Igniculus Fu <igniculus.fu@amd.com>
Cc: Abner Chang <abner.chang@amd.com>
---
.../SystemFirmwareDescriptor.aslc | 85 ++
.../SystemFirmwareDescriptor.inf | 39 +
.../SystemFirmwareDescriptorPei.c | 64 +
.../Include/Library/CapsuleHookLib.h | 40 +
.../Capsule/CapsuleHookLib/CapsuleHookLib.c | 1153 +++++++++++++++++
.../Capsule/CapsuleHookLib/CapsuleHookLib.inf | 56 +
.../PlatformBootManager.c | 794 ++++++++++++
.../PlatformBootManager.h | 150 +++
.../PlatformBootManagerLib.inf | 89 ++
.../PlatformBootManagerLib/PlatformConsole.c | 495 +++++++
.../PlatformBootManagerLib/PlatformConsole.h | 69 +
.../PlatformBootManagerLib/PlatformData.c | 39 +
.../CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf | 122 ++
.../CapsuleRuntimeDxe/CapsuleService.c | 461 +++++++
.../CapsuleRuntimeDxe/CapsuleService.h | 73 ++
15 files changed, 3729 insertions(+)
create mode 100644 Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Capsule/SystemFirmwareDescriptor/SystemFirmwareDescriptor.aslc
create mode 100644 Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Capsule/SystemFirmwareDescriptor/SystemFirmwareDescriptor.inf
create mode 100644 Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Capsule/SystemFirmwareDescriptor/SystemFirmwareDescriptorPei.c
create mode 100644 Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Include/Library/CapsuleHookLib.h
create mode 100644 Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/CapsuleHookLib/CapsuleHookLib.c
create mode 100644 Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/CapsuleHookLib/CapsuleHookLib.inf
create mode 100644 Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformBootManager.c
create mode 100644 Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformBootManager.h
create mode 100644 Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformBootManagerLib.inf
create mode 100644 Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformConsole.c
create mode 100644 Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformConsole.h
create mode 100644 Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformData.c
create mode 100644 Platform/AMD/VanGoghBoard/Override/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
create mode 100644 Platform/AMD/VanGoghBoard/Override/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c
create mode 100644 Platform/AMD/VanGoghBoard/Override/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.h
diff --git a/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Capsule/SystemFirmwareDescriptor/SystemFirmwareDescriptor.aslc b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Capsule/SystemFirmwareDescriptor/SystemFirmwareDescriptor.aslc
new file mode 100644
index 0000000000..2e05a523c7
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Capsule/SystemFirmwareDescriptor/SystemFirmwareDescriptor.aslc
@@ -0,0 +1,85 @@
+/** @file
+ System firmware Descriptor file
+ System Firmware descriptor.
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Guid/EdkiiSystemFmpCapsule.h>
+
+#define PACKAGE_VERSION 0xFFFFFFFF
+#define PACKAGE_VERSION_STRING L"Unknown"
+
+#define CURRENT_FIRMWARE_VERSION 0x00003818
+#define CURRENT_FIRMWARE_VERSION_STRING L"00003818"
+#define LOWEST_SUPPORTED_FIRMWARE_VERSION 0x00000001
+
+#define IMAGE_ID SIGNATURE_64('C', 'H', 'A', 'C', 'H', 'A','N','I')
+#define IMAGE_ID_STRING L"ChachaniFD"
+
+// PcdSystemFmpCapsuleImageTypeIdGuid
+#define IMAGE_TYPE_ID_GUID { 0x38663fe6, 0x934f, 0x42a1, { 0xbc, 0xb0, 0xf7, 0x9e, 0x62, 0xec, 0xbe, 0x80 } }
+
+typedef struct {
+ EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR Descriptor;
+ // real string data
+ CHAR16 ImageIdNameStr[sizeof(IMAGE_ID_STRING)/sizeof(CHAR16)];
+ CHAR16 VersionNameStr[sizeof(CURRENT_FIRMWARE_VERSION_STRING)/sizeof(CHAR16)];
+ CHAR16 PackageVersionNameStr[sizeof(PACKAGE_VERSION_STRING)/sizeof(CHAR16)];
+} IMAGE_DESCRIPTOR;
+
+IMAGE_DESCRIPTOR mImageDescriptor =
+{
+ {
+ EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR_SIGNATURE,
+ sizeof(EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR),
+ sizeof(IMAGE_DESCRIPTOR),
+ PACKAGE_VERSION, // PackageVersion
+ OFFSET_OF (IMAGE_DESCRIPTOR, PackageVersionNameStr), // PackageVersionName
+ 1, // ImageIndex;
+ {0x0}, // Reserved
+ IMAGE_TYPE_ID_GUID, // ImageTypeId;
+ IMAGE_ID, // ImageId;
+ OFFSET_OF (IMAGE_DESCRIPTOR, ImageIdNameStr), // ImageIdName;
+ CURRENT_FIRMWARE_VERSION, // Version;
+ OFFSET_OF (IMAGE_DESCRIPTOR, VersionNameStr), // VersionName;
+ {0x0}, // Reserved2
+ FixedPcdGet32(PcdFlashAreaSize), // Size;
+ IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
+ IMAGE_ATTRIBUTE_RESET_REQUIRED |
+ IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED |
+ IMAGE_ATTRIBUTE_IN_USE, // AttributesSupported;
+ IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
+ IMAGE_ATTRIBUTE_RESET_REQUIRED |
+ IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED |
+ IMAGE_ATTRIBUTE_IN_USE, // AttributesSetting;
+ 0x0, // Compatibilities;
+ LOWEST_SUPPORTED_FIRMWARE_VERSION, // LowestSupportedImageVersion;
+ 0x00000000, // LastAttemptVersion;
+ 0, // LastAttemptStatus;
+ {0x0}, // Reserved3
+ 0, // HardwareInstance;
+ },
+ // real string data
+ {IMAGE_ID_STRING},
+ {CURRENT_FIRMWARE_VERSION_STRING},
+ {PACKAGE_VERSION_STRING},
+};
+
+
+VOID*
+ReferenceAcpiTable (
+ VOID
+ )
+{
+ //
+ // Reference the table being generated to prevent the optimizer from
+ // removing the data structure from the executable
+ //
+ return (VOID*)&mImageDescriptor;
+}
diff --git a/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Capsule/SystemFirmwareDescriptor/SystemFirmwareDescriptor.inf b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Capsule/SystemFirmwareDescriptor/SystemFirmwareDescriptor.inf
new file mode 100644
index 0000000000..50f2b8c1a2
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Capsule/SystemFirmwareDescriptor/SystemFirmwareDescriptor.inf
@@ -0,0 +1,39 @@
+## @file
+# System Firmware descriptor.
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SystemFirmwareDescriptor
+ FILE_GUID = 90B2B846-CA6D-4D6E-A8D3-C140A8E110AC
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SystemFirmwareDescriptorPeimEntry
+
+[Sources]
+ SystemFirmwareDescriptorPei.c
+ SystemFirmwareDescriptor.aslc
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SignedCapsulePkg/SignedCapsulePkg.dec
+ ChachaniBoardPkg/Project.dec
+
+[LibraryClasses]
+ PcdLib
+ PeiServicesLib
+ DebugLib
+ PeimEntryPoint
+
+[Pcd]
+ gEfiSignedCapsulePkgTokenSpaceGuid.PcdEdkiiSystemFirmwareImageDescriptor
+ gPlatformPkgTokenSpaceGuid.PcdFlashAreaSize
+
+[Depex]
+ TRUE
diff --git a/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Capsule/SystemFirmwareDescriptor/SystemFirmwareDescriptorPei.c b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Capsule/SystemFirmwareDescriptor/SystemFirmwareDescriptorPei.c
new file mode 100644
index 0000000000..7f0c4421e3
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Capsule/SystemFirmwareDescriptor/SystemFirmwareDescriptorPei.c
@@ -0,0 +1,64 @@
+/** @file
+ Implements SystemFirmwareDescriptorPei.c
+ System Firmware descriptor producer.
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/DebugLib.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Guid/EdkiiSystemFmpCapsule.h>
+
+/**
+ Entrypoint for SystemFirmwareDescriptor PEIM.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS PPI successfully installed.
+**/
+EFI_STATUS
+EFIAPI
+SystemFirmwareDescriptorPeimEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR *Descriptor;
+ UINTN Size;
+ UINTN Index;
+ UINT32 AuthenticationStatus;
+
+ //
+ // Search RAW section.
+ //
+ Index = 0;
+ while (TRUE) {
+ Status = PeiServicesFfsFindSectionData3 (EFI_SECTION_RAW, Index, FileHandle, (VOID **)&Descriptor, &AuthenticationStatus);
+ if (EFI_ERROR (Status)) {
+ // Should not happen, must something wrong in FDF.
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+ }
+
+ if (Descriptor->Signature == EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR_SIGNATURE) {
+ break;
+ }
+
+ Index++;
+ }
+
+ DEBUG ((DEBUG_INFO, "EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR size - 0x%x\n", Descriptor->Length));
+
+ Size = Descriptor->Length;
+ PcdSetPtrS (PcdEdkiiSystemFirmwareImageDescriptor, &Size, Descriptor);
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Include/Library/CapsuleHookLib.h b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Include/Library/CapsuleHookLib.h
new file mode 100644
index 0000000000..584adfaee9
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Include/Library/CapsuleHookLib.h
@@ -0,0 +1,40 @@
+/** @file
+ Implements CapsuleHookLib.h
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CAPSULE_HOOK_LIB_H__
+#define CAPSULE_HOOK_LIB_H__
+
+/**
+ Detect Capsule file from ESP partition and update capsule.
+
+ @retval EFI_SUCCESS. Opertion is successful.
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate.
+ @retval EFI_ERROR Internal error when update Capsule.
+
+**/
+EFI_STATUS
+EFIAPI
+CapsuleUpdateViaFileHook (
+ VOID
+ );
+
+/**
+ Detect Capsule file from ESP partition and update capsule.
+
+ @retval EFI_SUCCESS. Opertion is successful.
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate.
+ @retval EFI_ERROR Internal error when update Capsule.
+
+**/
+EFI_STATUS
+EFIAPI
+CapsuleUpdateViaFileLib (
+ VOID
+ );
+
+#endif
diff --git a/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/CapsuleHookLib/CapsuleHookLib.c b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/CapsuleHookLib/CapsuleHookLib.c
new file mode 100644
index 0000000000..b4513514b8
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/CapsuleHookLib/CapsuleHookLib.c
@@ -0,0 +1,1153 @@
+/** @file
+ Implements CapsuleHookLib.c
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <PiDxe.h>
+#include <Guid/Gpt.h>
+#include <Guid/FileSystemInfo.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/BlockIo.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/FileHandleLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/CapsuleHookLib.h>
+#include <OtaCapsuleUpdate.h>
+
+#define CAP_FILE_NAME (CHAR16 *) FixedPcdGetPtr (PcdOtaCapsuleName)
+#define CAP_PARTITION (CHAR16 *) FixedPcdGetPtr (PcdOtaCapsulePartitionName)
+CHAR16 mPartitionName[36];
+STATIC CONST CHAR16 *mSlotSuffixes[2] = { L"_a", L"_b" };
+EFI_DEVICE_PATH_PROTOCOL *mBootDevicePath;
+
+#define FLASH_DEVICE_PATH_SIZE(DevPath) (GetDevicePathSize (DevPath) - sizeof (EFI_DEVICE_PATH_PROTOCOL))
+
+// Hidden (Not exported) function from DxeCapsuleReportLib.
+extern
+EFI_STATUS
+// Not EFIAPI!
+RecordCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus
+ );
+
+/**
+ Read GPT partition entries.
+
+ @param[in] BlockIo The BlockIo of device.
+ @param[out] PartitionEntries The output buffer of partition entry.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadPartitionEntries (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ OUT EFI_PARTITION_ENTRY **PartitionEntries
+ )
+{
+ EFI_STATUS Status;
+ UINTN EntrySize;
+ UINTN NumEntries;
+ UINTN BufferSize;
+ UINT32 MediaId;
+ EFI_PARTITION_TABLE_HEADER *GptHeader;
+
+ MediaId = BlockIo->Media->MediaId;
+
+ //
+ // Read size of Partition entry and number of entries from GPT header
+ //
+ GptHeader = AllocatePool (BlockIo->Media->BlockSize);
+ if (GptHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ MediaId,
+ PRIMARY_PART_HEADER_LBA,
+ BlockIo->Media->BlockSize,
+ (VOID *)GptHeader
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (GptHeader);
+ return Status;
+ }
+
+ //
+ // Check there is a GPT on the media
+ //
+ if ((GptHeader->Header.Signature != EFI_PTAB_HEADER_ID) || (GptHeader->MyLBA != PRIMARY_PART_HEADER_LBA)) {
+ DEBUG ((DEBUG_ERROR, "No valid GPT found!\n"));
+ FreePool (GptHeader);
+ return EFI_DEVICE_ERROR;
+ }
+
+ EntrySize = GptHeader->SizeOfPartitionEntry;
+ NumEntries = GptHeader->NumberOfPartitionEntries;
+ if ((EntrySize == 0) || (NumEntries == 0)) {
+ DEBUG ((DEBUG_ERROR, "Invalid Entry size or number.\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ FreePool (GptHeader);
+
+ BufferSize = ALIGN_VALUE (EntrySize * NumEntries, BlockIo->Media->BlockSize);
+ *PartitionEntries = AllocatePool (BufferSize);
+ if (PartitionEntries == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ MediaId,
+ 2,
+ BufferSize,
+ (VOID *)*PartitionEntries
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (*PartitionEntries);
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ Get capsule partition device path by partition name.
+
+ @param[in] BootDevicePath Pointer to the Device Path Protocol from variable.
+ @param[in] PartitionName The given partition name.
+ @param[out] PartitionDevicePath Pointer to the Device Path Protocol of capsule partition.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDevicePathByName (
+ IN EFI_DEVICE_PATH_PROTOCOL *BootDevicePath,
+ IN CONST CHAR16 *PartitionName,
+ OUT EFI_DEVICE_PATH_PROTOCOL **PartitionDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DEVICE_PATH_PROTOCOL *NextNode;
+ HARDDRIVE_DEVICE_PATH *PartitionNode;
+ EFI_PARTITION_ENTRY *PartitionEntries;
+ UINTN NumHandles;
+ UINTN LoopIndex;
+ EFI_HANDLE *AllHandles;
+ EFI_HANDLE Handle;
+
+ //
+ // Get all BlockIo handles in system
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ &NumHandles,
+ &AllHandles
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Couldn't locate BlockIo protocol: %r\n", Status));
+ return Status;
+ }
+
+ for (LoopIndex = 0; LoopIndex < NumHandles; LoopIndex++) {
+ Status = gBS->OpenProtocol (
+ AllHandles[LoopIndex],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&DevicePath,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Couldn't locate DevicePath protocol: %r\n", Status));
+ return Status;
+ }
+
+ if (!CompareMem (DevicePath, BootDevicePath, FLASH_DEVICE_PATH_SIZE (BootDevicePath))) {
+ BootDevicePath = DevicePath;
+ break;
+ }
+ }
+
+ DevicePath = BootDevicePath;
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePath, &Handle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Couldn't locate device status: %r\n", Status));
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlockIo,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to get BlockIo: %r\n", Status));
+ return Status;
+ }
+
+ Status = ReadPartitionEntries (BlockIo, &PartitionEntries);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to read partitions from disk device: %r\n", Status));
+ return Status;
+ }
+
+ for (LoopIndex = 0; LoopIndex < NumHandles; LoopIndex++) {
+ Status = gBS->OpenProtocol (
+ AllHandles[LoopIndex],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&DevicePath,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Couldn't locate DevicePath protocol: %r\n", Status));
+ return Status;
+ }
+
+ if (!CompareMem (DevicePath, BootDevicePath, FLASH_DEVICE_PATH_SIZE (BootDevicePath))) {
+ NextNode = NextDevicePathNode (DevicePath);
+
+ while (!IsDevicePathEndType (NextNode)) {
+ if ((NextNode->Type == MEDIA_DEVICE_PATH) &&
+ (NextNode->SubType == MEDIA_HARDDRIVE_DP))
+ {
+ break;
+ }
+
+ NextNode = NextDevicePathNode (NextNode);
+ }
+
+ if (IsDevicePathEndType (NextNode)) {
+ continue;
+ }
+
+ PartitionNode = (HARDDRIVE_DEVICE_PATH *)NextNode;
+
+ if (PartitionNode->PartitionNumber == 0) {
+ continue;
+ }
+
+ if (0 == StrCmp (PartitionEntries[PartitionNode->PartitionNumber - 1].PartitionName, PartitionName)) {
+ break;
+ }
+ }
+ }
+
+ if (LoopIndex >= NumHandles) {
+ return EFI_LOAD_ERROR;
+ }
+
+ *PartitionDevicePath = DevicePath;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get capsule paritioin information.
+
+ @param[in] VOID
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+CapsulePartitionInfo (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN VarSize;
+ OTA_CAPSULE_UPDATE OtaCapsuleUpdateVal;
+ CHAR16 BootPath[512];
+
+ //
+ // Get Capsule A/B partition.
+ //
+ ZeroMem (&OtaCapsuleUpdateVal, sizeof (OTA_CAPSULE_UPDATE));
+ VarSize = sizeof (OTA_CAPSULE_UPDATE);
+ Status = gRT->GetVariable (
+ OTA_CAPSULE_VAR_NAME,
+ &gOtaCapsuleUpdateGuid,
+ NULL,
+ &VarSize,
+ (VOID *)&OtaCapsuleUpdateVal
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "CapsulePartitionInfo: GetVariable failed: %r\n", Status));
+ return Status;
+ }
+
+ ZeroMem (mPartitionName, sizeof (mPartitionName));
+ StrCpyS (mPartitionName, sizeof (mPartitionName), CAP_PARTITION);
+ StrCatS (mPartitionName, sizeof (mPartitionName), mSlotSuffixes[OtaCapsuleUpdateVal.UpdateSlot]);
+ DEBUG ((DEBUG_INFO, "CapsulePartitionInfo from partition: %s\n", mPartitionName));
+
+ //
+ // Get Boot device path
+ //
+ VarSize = 512;
+ Status = gRT->GetVariable (
+ L"AndroidBootDevice",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &VarSize,
+ BootPath
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "CapsulePartitionInfo: Get BootDevice variable failed: %r\n", Status));
+ return Status;
+ }
+
+ mBootDevicePath = ConvertTextToDevicePath (BootPath);
+ if (mBootDevicePath == NULL) {
+ DEBUG ((DEBUG_ERROR, "mBootDevicePath is NULL\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read Capsule file information from FAT partiton.
+
+ @param[in] FileName File name of Capsule binary
+ @param[out] Buffer Return buffer pointer of Capsule binary
+ @param[out] BufferSize Capsule binary size
+
+ @retval EFI_SUCCESS Read Capsule information successfully
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_NOT_FOUND Fail to read Capsule information
+ @retval Others Internal error when read Capsule information
+
+**/
+EFI_STATUS
+EFIAPI
+ReadCapsuleInfo (
+ IN CHAR16 *FileName,
+ OUT VOID **Buffer,
+ OUT UINTN *BufferSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+ EFI_FILE *Root;
+ EFI_FILE *FileHandle;
+ UINT8 *FileBuffer;
+ UINTN FileSize;
+ EFI_HANDLE Handle;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DEVICE_PATH_PROTOCOL *BootPartitionPath;
+
+ FileBuffer = NULL;
+ FileSize = 0;
+
+ DEBUG ((DEBUG_INFO, "ReadCapsuleInfo()...\n"));
+
+ Status = GetDevicePathByName (mBootDevicePath, mPartitionName, &BootPartitionPath);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetDevicePathByName failed: %r\n", Status));
+ return Status;
+ }
+
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &BootPartitionPath, &Handle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: Locate DevicePath failed: %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Get Capsule file
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (BlockIo->Media->RemovableMedia) {
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Fs->OpenVolume (Fs, &Root);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Root->Open (Root, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (FileHandle == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = FileHandleGetSize (FileHandle, (UINT64 *)&FileSize);
+ if (EFI_ERROR (Status)) {
+ FileHandleClose (FileHandle);
+ return Status;
+ }
+
+ FileBuffer = AllocateZeroPool (FileSize);
+ if (FileBuffer == NULL) {
+ FileHandleClose (FileHandle);
+ return Status;
+ }
+
+ Status = FileHandleRead (FileHandle, &FileSize, FileBuffer);
+ if (EFI_ERROR (Status)) {
+ FileHandleClose (FileHandle);
+ FreePool (FileBuffer);
+ return Status;
+ }
+
+ Status = FileHandleClose (FileHandle);
+ if (EFI_ERROR (Status)) {
+ FreePool (FileBuffer);
+ return Status;
+ }
+
+ *Buffer = FileBuffer;
+ *BufferSize = FileSize;
+
+ DEBUG ((DEBUG_INFO, "Capsule size: 0x%x\n", *BufferSize));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remove capsule file from FAT partitions.
+
+ @param[in] FileName File name of Capsule binary
+
+ @retval EFI_SUCCESS Delete capsule succesfully
+ @retval Others Internal error of delete capsule function
+
+**/
+EFI_STATUS
+EFIAPI
+RemoveCapsuleFile (
+ IN CHAR16 *FileName
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+ EFI_FILE *Root;
+ EFI_FILE *FileHandle;
+ EFI_HANDLE Handle;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DEVICE_PATH_PROTOCOL *BootPartitionPath;
+
+ DEBUG ((DEBUG_INFO, "RemoveCapsuleFile()...\n"));
+
+ Status = GetDevicePathByName (mBootDevicePath, mPartitionName, &BootPartitionPath);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetDevicePathByName failed: %r\n", Status));
+ return Status;
+ }
+
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &BootPartitionPath, &Handle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: Locate DevicePath failed: %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Remove Capsule file
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (BlockIo->Media->RemovableMedia) {
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Fs->OpenVolume (Fs, &Root);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Root->Open (Root, &FileHandle, FileName, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (FileHandle == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = FileHandleDelete (FileHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Passes and processes the capsule file.
+
+ @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules
+ being passed into update capsule.
+ @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in CaspuleHeaderArray.
+
+ @retval EFI_SUCCESS Valid capsule was passed.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateCapsule (
+ IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
+ IN UINTN CapsuleCount
+ )
+{
+ UINTN ArrayNumber;
+ EFI_STATUS Status;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+
+ //
+ // Capsule Count can't be less than one.
+ //
+ if (CapsuleCount < 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CapsuleHeader = NULL;
+
+ for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
+ //
+ // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have
+ // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
+ //
+ CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have
+ // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
+ //
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // FIXME: The CoD Image CANNOT BE RELOADED as Memory capsule.
+ //
+ // Check FMP capsule flag
+ //
+ if ( CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)
+ && ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check Capsule image without populate flag by firmware support capsule function
+ //
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
+ Status = SupportCapsuleImage (CapsuleHeader);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ //
+ // Walk through all capsules, record whether there is a capsule needs reset
+ // or initiate reset. And then process capsules which has no reset flag directly.
+ //
+ for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
+ CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
+ //
+ // Here should be in the boot-time for non-reset capsule image
+ // Platform specific update for the non-reset capsule image.
+ //
+
+ // FIXME: The CoD Image CANNOT BE RELOADED as Memory capsule.
+ if (((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) || TRUE) {
+ Status = ProcessCapsuleImage (CapsuleHeader);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Detect Capsule file from ESP partition and update capsule.
+
+ @retval EFI_SUCCESS Opertion is successful.
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate.
+ @retval EFI_ERROR Internal error when update Capsule.
+
+**/
+EFI_STATUS
+EFIAPI
+CapsuleUpdateViaFileHook (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *CapsuleBuffer;
+ UINTN CapsuleSize;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ UINTN CapsuleNum;
+
+ CapsuleBuffer = NULL;
+ CapsuleSize = 0;
+
+ DEBUG ((DEBUG_INFO, "CapsuleUpdateViaFileHook() Entry Point...\n"));
+
+ Status = CapsulePartitionInfo ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "CapsulePartitionInfo failed: %r\n", Status));
+ return Status;
+ }
+
+ Status = ReadCapsuleInfo (CAP_FILE_NAME, (VOID **)&CapsuleBuffer, &CapsuleSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Read Capsule file failed. Status: %r\n", Status));
+ if (CapsuleBuffer != NULL) {
+ FreePool (CapsuleBuffer);
+ }
+
+ return Status;
+ }
+
+ CapsuleHeader = (EFI_CAPSULE_HEADER *)CapsuleBuffer;
+ CapsuleNum = 1;
+
+ Status = UpdateCapsule (&CapsuleHeader, CapsuleNum);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to update capsule. Status: %r\n", Status));
+ }
+
+ if (CapsuleBuffer != NULL) {
+ FreePool (CapsuleBuffer);
+ }
+
+ DEBUG ((DEBUG_INFO, "Capsule update via file completed, reset system...\n"));
+
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get capsule partition device path by partition name.
+
+ @param[in] BootDevicePath Pointer to the Device Path Protocol from variable.
+ @param[in] PartitionName The given partition name.
+ @param[out] PartitionDevicePath Pointer to the Device Path Protocol of capsule partition.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDevicePathByBoot (
+ IN EFI_DEVICE_PATH_PROTOCOL *BootDevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **PartitionDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DEVICE_PATH_PROTOCOL *NextNode;
+ UINTN NumHandles;
+ UINTN LoopIndex;
+ EFI_HANDLE *AllHandles;
+ EFI_HANDLE Handle;
+
+ //
+ // Get all BlockIo handles in system
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ &NumHandles,
+ &AllHandles
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Couldn't locate BlockIo protocol: %r\n", Status));
+ return Status;
+ }
+
+ for (LoopIndex = 0; LoopIndex < NumHandles; LoopIndex++) {
+ Status = gBS->OpenProtocol (
+ AllHandles[LoopIndex],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&DevicePath,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Couldn't locate DevicePath protocol: %r\n", Status));
+ return Status;
+ }
+
+ if (!CompareMem (DevicePath, BootDevicePath, FLASH_DEVICE_PATH_SIZE (BootDevicePath))) {
+ BootDevicePath = DevicePath;
+ break;
+ }
+ }
+
+ DevicePath = BootDevicePath;
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePath, &Handle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Couldn't locate device status: %r\n", Status));
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlockIo,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to get BlockIo: %r\n", Status));
+ return Status;
+ }
+
+ for (LoopIndex = 0; LoopIndex < NumHandles; LoopIndex++) {
+ Status = gBS->OpenProtocol (
+ AllHandles[LoopIndex],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&DevicePath,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Couldn't locate DevicePath protocol: %r\n", Status));
+ return Status;
+ }
+
+ if (!CompareMem (DevicePath, BootDevicePath, FLASH_DEVICE_PATH_SIZE (BootDevicePath))) {
+ NextNode = NextDevicePathNode (DevicePath);
+
+ while (!IsDevicePathEndType (NextNode)) {
+ if ((NextNode->Type == MEDIA_DEVICE_PATH) &&
+ (NextNode->SubType == MEDIA_HARDDRIVE_DP))
+ {
+ break;
+ }
+
+ NextNode = NextDevicePathNode (NextNode);
+ }
+
+ if (IsDevicePathEndType (NextNode)) {
+ continue;
+ }
+
+ break;
+ }
+ }
+
+ if (LoopIndex >= NumHandles) {
+ return EFI_LOAD_ERROR;
+ }
+
+ *PartitionDevicePath = DevicePath;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get capsule paritioin information.
+
+ @param[in] VOID
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+CapsulePathInfo (
+ VOID
+ )
+{
+ mBootDevicePath = ConvertTextToDevicePath ((CHAR16 *)PcdGetPtr (PcdNVMeDevicePath));
+
+ if (mBootDevicePath == NULL) {
+ DEBUG ((DEBUG_ERROR, "mBootDevicePath is NULL\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read Capsule file information from FAT partiton.
+
+ @param[in] FileName File name of Capsule binary
+ @param[out] Buffer Return buffer pointer of Capsule binary
+ @param[out] BufferSize Capsule binary size
+
+ @retval EFI_SUCCESS Read Capsule information successfully
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_NOT_FOUND Fail to read Capsule information
+ @retval Others Internal error when read Capsule information
+
+**/
+EFI_STATUS
+EFIAPI
+IterateAllCapsulesFromDisk (
+ IN CHAR16 *FileBaseName,
+ OUT VOID **Buffer,
+ OUT UINTN *BufferSize,
+ OUT BOOLEAN *NoNextFile
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+ EFI_FILE *Root;
+ EFI_FILE *DirHandle;
+ EFI_FILE *FileHandle;
+ EFI_FILE_INFO *FileInfo;
+ UINT8 *FileBuffer;
+ EFI_HANDLE Handle;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DEVICE_PATH_PROTOCOL *BootPartitionPath;
+ BOOLEAN Found = FALSE;
+
+ FileBuffer = NULL;
+
+ DEBUG ((DEBUG_INFO, "ReadCapsuleInfo()...\n"));
+
+ Status = GetDevicePathByBoot (mBootDevicePath, &BootPartitionPath);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetDevicePathByName failed: %r\n", Status));
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "IGpuDevicePath: %S\n", ConvertDevicePathToText (BootPartitionPath, FALSE, FALSE)));
+
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &BootPartitionPath, &Handle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: Locate DevicePath failed: %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Get Capsule file
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: 1Locate DevicePath failed: %r\n", Status));
+ return Status;
+ }
+
+ if (BlockIo->Media->RemovableMedia) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: 2Locate DevicePath failed: %r\n", Status));
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: 3Locate DevicePath failed: %r\n", Status));
+ return Status;
+ }
+
+ Status = Fs->OpenVolume (Fs, &Root);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: 4Locate DevicePath failed: %r\n", Status));
+ return Status;
+ }
+
+ Status = Root->Open (Root, &DirHandle, FileBaseName, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Cannot open %s. Status = %r\n", FileBaseName, Status));
+ return Status;
+ }
+
+ //
+ // Get file count first
+ //
+ Status = FileHandleFindFirstFile (DirHandle, &FileInfo);
+ while (!*NoNextFile && !Found) {
+ // . & ..
+ Status = FileHandleFindNextFile (DirHandle, FileInfo, NoNextFile);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (FileInfo->Attribute & EFI_FILE_DIRECTORY) {
+ continue;
+ }
+
+ Found = TRUE;
+ }
+
+ if (!Found) {
+ *NoNextFile = TRUE;
+ return EFI_NOT_FOUND;
+ }
+
+ DEBUG ((DEBUG_INFO, "Processing Capsule %s\n", FileInfo->FileName));
+ FileBuffer = AllocateZeroPool (FileInfo->FileSize);
+ if (FileBuffer == NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ Status = DirHandle->Open (DirHandle, &FileHandle, FileInfo->FileName, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo Cannot open file %s: %r\n", FileInfo->FileName, Status));
+ FreePool (FileBuffer);
+ return Status;
+ }
+
+ Status = FileHandleRead (FileHandle, &FileInfo->FileSize, FileBuffer);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: 7Locate DevicePath failed: %r\n", Status));
+ FileHandleClose (FileHandle);
+ FreePool (FileBuffer);
+ return Status;
+ }
+
+ if (!*NoNextFile) {
+ Status = FileHandleClose (DirHandle);
+ }
+
+ Status = FileHandleClose (FileHandle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: 8Locate DevicePath failed: %r\n", Status));
+ FreePool (FileBuffer);
+ return Status;
+ }
+
+ *Buffer = FileBuffer;
+ *BufferSize = FileInfo->FileSize;
+
+ DEBUG ((DEBUG_INFO, "Capsule size: 0x%x\n", *BufferSize));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read Capsule file information from FAT partiton.
+
+ @param[in] FileBaseName File name of Capsule binary
+
+ @retval EFI_SUCCESS Delete first capsule successfully
+ @retval EFI_NOT_FOUND Fail to found Capsule information
+
+**/
+EFI_STATUS
+EFIAPI
+DeleteFirstCapsule (
+ CHAR16 *FileBaseName
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *BootPartitionPath;
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_FILE_PROTOCOL *Root;
+ EFI_FILE_HANDLE DirHandle;
+ BOOLEAN NoNextFile = FALSE;
+ EFI_FILE_INFO *FileInfo;
+ BOOLEAN Found = FALSE;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+ EFI_FILE_HANDLE FileHandle;
+
+ Status = GetDevicePathByBoot (mBootDevicePath, &BootPartitionPath);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetDevicePathByName failed: %r\n", Status));
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "IGpuDevicePath: %S\n", ConvertDevicePathToText (BootPartitionPath, FALSE, FALSE)));
+
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &BootPartitionPath, &Handle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: Locate DevicePath failed: %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Get Capsule file
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: 1Locate DevicePath failed: %r\n", Status));
+ return Status;
+ }
+
+ if (BlockIo->Media->RemovableMedia) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: 2Locate DevicePath failed: %r\n", Status));
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: 3Locate DevicePath failed: %r\n", Status));
+ return Status;
+ }
+
+ Status = Fs->OpenVolume (Fs, &Root);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadCapsuleInfo: 4Locate DevicePath failed: %r\n", Status));
+ return Status;
+ }
+
+ Status = Root->Open (Root, &DirHandle, FileBaseName, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Cannot open %s. Status = %r\n", FileBaseName, Status));
+ return Status;
+ }
+
+ Status = FileHandleFindFirstFile (DirHandle, &FileInfo);
+ while (!NoNextFile && !Found) {
+ // . & ..
+ FileHandleFindNextFile (DirHandle, FileInfo, &NoNextFile);
+ if (FileInfo->Attribute & EFI_FILE_DIRECTORY) {
+ continue;
+ }
+
+ Found = TRUE;
+ }
+
+ if (!Found) {
+ return EFI_NOT_FOUND;
+ }
+
+ DEBUG ((DEBUG_INFO, "Deleting Capsule %s\n", FileInfo->FileName));
+ Status = DirHandle->Open (DirHandle, &FileHandle, FileInfo->FileName, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
+ if (!EFI_ERROR (Status)) {
+ Status = FileHandle->Delete (FileHandle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "Cannot delete Capsule %s:%r\n", FileInfo->FileName, Status));
+ }
+
+ DirHandle->Close (DirHandle);
+ Root->Close (Root);
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Detect Capsule file from ESP partition and update capsule.
+
+ @retval EFI_SUCCESS Opertion is successful.
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate.
+ @retval EFI_ERROR Internal error when update Capsule.
+
+**/
+EFI_STATUS
+EFIAPI
+CapsuleUpdateViaFileLib (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *CapsuleBuffer;
+ UINTN CapsuleSize;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ UINTN CapsuleNum;
+ UINTN CurrentCapsuleFileNo = 0;
+ BOOLEAN NoNextFile = FALSE;
+
+ CapsuleBuffer = NULL;
+ CapsuleSize = 0;
+
+ DEBUG ((DEBUG_INFO, "CapsuleUpdateViaFileHook() Entry Point...\n"));
+
+ Status = CapsulePathInfo ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "CapsulePathInfo failed: %r\n", Status));
+ return Status;
+ }
+
+ while (!NoNextFile) {
+ Status = IterateAllCapsulesFromDisk (EFI_CAPSULE_FILE_DIRECTORY, (VOID **)&CapsuleBuffer, &CapsuleSize, &NoNextFile);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to update capsule:%r\n", Status));
+ break;
+ }
+
+ CapsuleHeader = (EFI_CAPSULE_HEADER *)CapsuleBuffer;
+ CapsuleNum = 1;
+ Status = UpdateCapsule (&CapsuleHeader, CapsuleNum);
+ RecordCapsuleStatusVariable (CapsuleHeader, Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to update capsule.\n"));
+ break;
+ }
+
+ Status = DeleteFirstCapsule (EFI_CAPSULE_FILE_DIRECTORY);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Cannot delete Capsule.\n"));
+ break;
+ }
+ }
+
+ if (CapsuleBuffer != NULL) {
+ FreePool (CapsuleBuffer);
+ }
+
+ if (!CurrentCapsuleFileNo && (Status == EFI_NOT_FOUND)) {
+ Status = EFI_SUCCESS;
+ }
+
+ DEBUG ((DEBUG_INFO, "Capsule update via file completed, Status=%r\n", Status));
+ // RecordFmpCapsuleStatus();
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+
+ // Unreachable.
+ return EFI_SUCCESS;
+}
diff --git a/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/CapsuleHookLib/CapsuleHookLib.inf b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/CapsuleHookLib/CapsuleHookLib.inf
new file mode 100644
index 0000000000..c3e910007a
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/CapsuleHookLib/CapsuleHookLib.inf
@@ -0,0 +1,56 @@
+## @file
+# Capsule Hook Lib Module
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CapsuleHookLib
+ FILE_GUID = 22BC4D9A-C78A-4038-8071-865765C4C019
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CapsuleHookLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ CapsuleHookLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ VanGoghCommonPkg/AmdCommonPkg.dec
+ ChachaniBoardPkg/Project.dec
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ UefiLib
+ FileHandleLib
+ DxeServicesLib
+ CapsuleLib
+
+[Protocols]
+ gEfiBlockIoProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+
+[Pcd]
+ gAmdCommonPkgTokenSpaceGuid.PcdOtaCapsuleName
+ gAmdCommonPkgTokenSpaceGuid.PcdOtaCapsulePartitionName
+ gPlatformPkgTokenSpaceGuid.PcdNVMeDevicePath
+
+[Guids]
+ gEfiFmpCapsuleGuid
+ gEfiGlobalVariableGuid
+ gOtaCapsuleUpdateGuid
diff --git a/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformBootManager.c b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformBootManager.c
new file mode 100644
index 0000000000..94f4f8207a
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformBootManager.c
@@ -0,0 +1,794 @@
+/** @file
+ This file include all platform action which can be customized
+ by IBV/OEM.
+
+Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+//
+// PCI Vendor ID and Device ID
+//
+#define VENDOR_ID 0x1002
+#define DEVICE_ID 0x163F
+#define DEVICE_ID2 0x1435
+
+#include "PlatformBootManager.h"
+#include "PlatformConsole.h"
+#include <Protocol/PlatformBootManagerOverride.h>
+#include <Guid/BootManagerMenu.h>
+#include <Library/HobLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/CapsuleHookLib.h>
+#include <Library/CapsuleLib.h>
+
+//
+// Predefined platform root bridge
+//
+PLATFORM_ROOT_BRIDGE_DEVICE_PATH gPlatformRootBridge0 = {
+ gPciRootBridge,
+ gEndEntire
+};
+
+EFI_DEVICE_PATH_PROTOCOL *gPlatformRootBridges[] = {
+ (EFI_DEVICE_PATH_PROTOCOL *)&gPlatformRootBridge0,
+ NULL
+};
+
+extern EFI_GUID gEfiEventReadyToBootGuid;
+UNIVERSAL_PAYLOAD_PLATFORM_BOOT_MANAGER_OVERRIDE_PROTOCOL *mUniversalPayloadPlatformBootManagerOverrideInstance = NULL;
+
+EFI_STATUS
+GetGopDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
+ );
+
+/**
+ Signal EndOfDxe event and install SMM Ready to lock protocol.
+
+**/
+VOID
+InstallReadyToLock (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;
+
+ DEBUG ((DEBUG_INFO, "InstallReadyToLock entering......\n"));
+ //
+ // Inform the SMM infrastructure that we're entering BDS and may run 3rd party code hereafter
+ // Since PI1.2.1, we need signal EndOfDxe as ExitPmAuth
+ //
+ EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
+ DEBUG ((DEBUG_INFO, "All EndOfDxe callbacks have returned successfully\n"));
+
+ //
+ // Install DxeSmmReadyToLock protocol in order to lock SMM
+ //
+ Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);
+ if (!EFI_ERROR (Status)) {
+ Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ DEBUG ((DEBUG_INFO, "InstallReadyToLock end\n"));
+ return;
+}
+
+/**
+ Return the index of the load option in the load option array.
+
+ The function consider two load options are equal when the
+ OptionType, Attributes, Description, FilePath and OptionalData are equal.
+
+ @param Key Pointer to the load option to be found.
+ @param Array Pointer to the array of load options to be found.
+ @param Count Number of entries in the Array.
+
+ @retval -1 Key wasn't found in the Array.
+ @retval 0 ~ Count-1 The index of the Key in the Array.
+**/
+INTN
+PlatformFindLoadOption (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
+ IN UINTN Count
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Count; Index++) {
+ if ((Key->OptionType == Array[Index].OptionType) &&
+ (Key->Attributes == Array[Index].Attributes) &&
+ (StrCmp (Key->Description, Array[Index].Description) == 0) &&
+ (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
+ (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
+ (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0))
+ {
+ return (INTN)Index;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ Register a boot option using a file GUID in the FV.
+
+ @param FileGuid The file GUID name in FV.
+ @param Description The boot option description.
+ @param Attributes The attributes used for the boot option loading.
+**/
+VOID
+PlatformRegisterFvBootOption (
+ EFI_GUID *FileGuid,
+ CHAR16 *Description,
+ UINT32 Attributes
+ )
+{
+ EFI_STATUS Status;
+ UINTN OptionIndex;
+ EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage);
+ ASSERT_EFI_ERROR (Status);
+
+ EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
+ DevicePath = AppendDevicePathNode (
+ DevicePathFromHandle (LoadedImage->DeviceHandle),
+ (EFI_DEVICE_PATH_PROTOCOL *)&FileNode
+ );
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &NewOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ Attributes,
+ Description,
+ DevicePath,
+ NULL,
+ 0
+ );
+ if (!EFI_ERROR (Status)) {
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+
+ OptionIndex = PlatformFindLoadOption (&NewOption, BootOptions, BootOptionCount);
+
+ if (OptionIndex == -1) {
+ Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN)-1);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ EfiBootManagerFreeLoadOption (&NewOption);
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+ }
+}
+
+/**
+ Get device path of one IGPU and one DGPU.
+
+ @param IGpuDevicePath Return the IGPU devide path, if no, return NULL.
+ @param DGpuDevicePath Return the DGPU devide path, if no, return NULL.
+
+ @retval EFI_SUCCSS Get all platform active video device path.
+ @retval EFI_STATUS Return the status of gBS->LocateDevicePath (),
+ gBS->ConnectController (),
+ and gBS->LocateHandleBuffer ().
+**/
+EFI_STATUS
+GetVgaDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **IGpuDevicePath,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DGpuDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE RootHandle;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ DEBUG ((DEBUG_INFO, "GetVgaDevicePath enter\n"));
+
+ HandleCount = 0;
+ DevicePath = NULL;
+ HandleBuffer = NULL;
+ *IGpuDevicePath = NULL;
+ *DGpuDevicePath = NULL;
+
+ DEBUG ((DEBUG_INFO, "VENDOR_ID = 0x%x\n", VENDOR_ID));
+ DEBUG ((DEBUG_INFO, "DEVICE_ID = 0x%x\n", DEVICE_ID));
+
+ //
+ // Make all the PCI_IO protocols on PCI Seg 0 show up
+ //
+ EfiBootManagerConnectDevicePath (gPlatformRootBridges[0], NULL);
+
+ Status = gBS->LocateDevicePath (
+ &gEfiDevicePathProtocolGuid,
+ &gPlatformRootBridges[0],
+ &RootHandle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->ConnectController (
+ RootHandle,
+ NULL,
+ NULL,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Start to check all the pci io to find all possible VGA device
+ //
+ HandleCount = 0;
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Check for all VGA device
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Here we decide which VGA device to enable in PCI bus
+ //
+ // The first plugin PCI VGA card device will be present as PCI VGA
+ // The onchip AGP or AGP card will be present as AGP VGA
+ //
+ if (!IS_PCI_DISPLAY (&Pci)) {
+ // if (!IS_PCI_VGA (&Pci)) {
+ continue;
+ }
+
+ //
+ // Set the device as the possible console out device,
+ //
+ // Below code will make every VGA device to be one
+ // of the possibe console out device
+ //
+ gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&DevicePath
+ );
+ DEBUG ((DEBUG_INFO, "DevicePath: %S\n", ConvertDevicePathToText (DevicePath, FALSE, FALSE)));
+
+ if ((Pci.Hdr.VendorId == VENDOR_ID) && ((Pci.Hdr.DeviceId == DEVICE_ID) || (Pci.Hdr.DeviceId == DEVICE_ID2))) {
+ // IGPU
+ *IGpuDevicePath = DevicePath;
+ } else {
+ // DGPU
+ *DGpuDevicePath = DevicePath;
+ }
+
+ if ((*IGpuDevicePath != NULL) && (*DGpuDevicePath != NULL)) {
+ DEBUG ((DEBUG_INFO, "IGpuDevicePath and DGpuDevicePath are not NULL\n"));
+ break;
+ }
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "IGpuDevicePath: %S\n", ConvertDevicePathToText (*IGpuDevicePath, FALSE, FALSE)));
+ DEBUG ((DEBUG_INFO, "DGpuDevicePath: %S\n", ConvertDevicePathToText (*DGpuDevicePath, FALSE, FALSE)));
+ FreePool (HandleBuffer);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Find the platform active vga, and base on the policy to enable the vga as
+ the console out device. The policy is active dGPU, if no dGPU active iGPU.
+
+ None.
+
+ @param EFI_UNSUPPORTED There is no active vga device
+
+ @retval EFI_STATUS Return the status of BdsLibGetVariableAndSize ()
+
+**/
+EFI_STATUS
+PlatformBdsForceActiveVga (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathFirst;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathSecond;
+ EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *IGpuDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DGpuDevicePath;
+
+ DEBUG ((DEBUG_INFO, "PlatformBdsForceActiveVga enter\n"));
+
+ Status = EFI_SUCCESS;
+ DevicePathFirst = NULL;
+ DevicePathSecond = NULL;
+ GopDevicePath = NULL;
+ IGpuDevicePath = NULL;
+ DGpuDevicePath = NULL;
+
+ //
+ // Get device path of one IGPU and one DGPU
+ //
+ Status = GetVgaDevicePath (&IGpuDevicePath, &DGpuDevicePath);
+ ASSERT_EFI_ERROR (Status);
+
+ if ((IGpuDevicePath == NULL) && (DGpuDevicePath == NULL)) {
+ DEBUG ((DEBUG_INFO, "No valid IGPU and DGPU\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((IGpuDevicePath != NULL) && (DGpuDevicePath == NULL)) {
+ DEBUG ((DEBUG_INFO, "Only IGPU is valid\n"));
+ // DEBUG ((DEBUG_INFO,"Only IGPU is valid, Update IGPU ...\n"));
+ DevicePathFirst = IGpuDevicePath;
+ DevicePathSecond = DGpuDevicePath;
+ goto UpdateConOut;
+ } else if ((IGpuDevicePath == NULL) && (DGpuDevicePath != NULL)) {
+ DEBUG ((DEBUG_INFO, "Only DGPU is valid\n"));
+ // DEBUG ((DEBUG_INFO,"Only DGPU is valid, Update DGPU ...\n"));
+ DevicePathFirst = DGpuDevicePath;
+ DevicePathSecond = IGpuDevicePath;
+ goto UpdateConOut;
+ } else if ((IGpuDevicePath != NULL) && (DGpuDevicePath != NULL)) {
+ DEBUG ((DEBUG_INFO, "DGPU and IGPU are valid, active DGPU\n"));
+ // DEBUG ((DEBUG_INFO,"Only DGPU is valid, Update DGPU ...\n"));
+ DevicePathFirst = DGpuDevicePath;
+ DevicePathSecond = IGpuDevicePath;
+ goto UpdateConOut;
+ }
+
+UpdateConOut:
+ DEBUG ((DEBUG_INFO, "Before GetGopDevicePath: ConOutDevicePath is %S\n", ConvertDevicePathToText (DevicePathFirst, FALSE, FALSE)));
+ GetGopDevicePath (DevicePathFirst, &GopDevicePath);
+ DevicePathFirst = GopDevicePath;
+ DEBUG ((DEBUG_INFO, "After GetGopDevicePath: ConOutDevicePath is %S\n", ConvertDevicePathToText (DevicePathFirst, FALSE, FALSE)));
+ DEBUG ((DEBUG_INFO, "Exclusive device path is %S\n", ConvertDevicePathToText (DevicePathSecond, FALSE, FALSE)));
+
+ Status = EfiBootManagerUpdateConsoleVariable (
+ ConOut,
+ DevicePathFirst,
+ DevicePathSecond
+ );
+ // TODO: Specify iGPU/dGPU.
+ EfiBootManagerConnectVideoController (NULL);
+ return Status;
+}
+
+/**
+ Do the platform specific action before the console is connected.
+
+ Such as:
+ Update console variable;
+ Register new Driver#### or Boot####;
+ Signal ReadyToLock event.
+**/
+VOID
+EFIAPI
+PlatformBootManagerBeforeConsole (
+ VOID
+ )
+{
+ EFI_INPUT_KEY Enter;
+ EFI_INPUT_KEY CustomKey;
+ EFI_INPUT_KEY Down;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+ EFI_STATUS Status;
+ UINT64 OsIndication;
+ UINTN DataSize;
+ UINT32 Attributes;
+ BOOLEAN CapsuleUpdateonDisk;
+
+ Status = gBS->LocateProtocol (&gUniversalPayloadPlatformBootManagerOverrideProtocolGuid, NULL, (VOID **)&mUniversalPayloadPlatformBootManagerOverrideInstance);
+ if (EFI_ERROR (Status)) {
+ mUniversalPayloadPlatformBootManagerOverrideInstance = NULL;
+ }
+
+ Status = gRT->GetVariable (
+ L"OsIndications",
+ &gEfiGlobalVariableGuid,
+ &Attributes,
+ &DataSize,
+ &OsIndication
+ );
+ if (mUniversalPayloadPlatformBootManagerOverrideInstance != NULL) {
+ mUniversalPayloadPlatformBootManagerOverrideInstance->BeforeConsole ();
+ return;
+ }
+
+ //
+ // Register ENTER as CONTINUE key
+ //
+ Enter.ScanCode = SCAN_NULL;
+ Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
+ EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
+
+ if (FixedPcdGetBool (PcdBootManagerEscape)) {
+ //
+ // Map Esc to Boot Manager Menu
+ //
+ CustomKey.ScanCode = SCAN_ESC;
+ CustomKey.UnicodeChar = CHAR_NULL;
+ } else {
+ //
+ // Map Esc to Boot Manager Menu
+ //
+ CustomKey.ScanCode = SCAN_F2;
+ CustomKey.UnicodeChar = CHAR_NULL;
+ }
+
+ EfiBootManagerGetBootManagerMenu (&BootOption);
+ EfiBootManagerAddKeyOptionVariable (NULL, (UINT16)BootOption.OptionNumber, 0, &CustomKey, NULL);
+
+ //
+ // Also add Down key to Boot Manager Menu since some serial terminals don't support F2 key.
+ //
+ Down.ScanCode = SCAN_DOWN;
+ Down.UnicodeChar = CHAR_NULL;
+ EfiBootManagerGetBootManagerMenu (&BootOption);
+ EfiBootManagerAddKeyOptionVariable (NULL, (UINT16)BootOption.OptionNumber, 0, &Down, NULL);
+ CapsuleUpdateonDisk = (BOOLEAN)((OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0);
+ // Process Capsule in Memory first, before EndOfDxe.
+ if ((GetBootModeHob () == BOOT_ON_FLASH_UPDATE) || CapsuleUpdateonDisk) {
+ PlatformBdsForceActiveVga (); // Force enable VGA on Capsule Update.
+ ASSERT_EFI_ERROR (BootLogoEnableLogo ());
+ Print (
+ L"\n"
+ L" Updating system BIOS.....\n"
+ L"\n"
+ );
+ if (CapsuleUpdateonDisk) {
+ EfiBootManagerConnectAll (); // Get BlockIo
+ CapsuleUpdateViaFileLib ();
+ } else {
+ ProcessCapsules ();
+ }
+ }
+
+ //
+ // Install ready to lock.
+ // This needs to be done before option rom dispatched.
+ //
+ InstallReadyToLock ();
+
+ //
+ // Dispatch deferred images after EndOfDxe event and ReadyToLock installation.
+ //
+ EfiBootManagerDispatchDeferredImages ();
+
+ PlatformConsoleInit ();
+}
+
+/**
+ Do the platform specific action after the console is connected.
+
+ Such as:
+ Dynamically switch output mode;
+ Signal console ready platform customized event;
+ Run diagnostics like memory testing;
+ Connect certain devices;
+ Dispatch additional option roms.
+**/
+VOID
+EFIAPI
+PlatformBootManagerAfterConsole (
+ VOID
+ )
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Black;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL White;
+ EDKII_PLATFORM_LOGO_PROTOCOL *PlatformLogo;
+ EFI_STATUS Status;
+ UINT64 OsIndication;
+ UINTN DataSize;
+ UINT32 Attributes;
+
+ if (mUniversalPayloadPlatformBootManagerOverrideInstance != NULL) {
+ mUniversalPayloadPlatformBootManagerOverrideInstance->AfterConsole ();
+ return;
+ }
+
+ Black.Blue = Black.Green = Black.Red = Black.Reserved = 0;
+ White.Blue = White.Green = White.Red = White.Reserved = 0xFF;
+
+ Status = gBS->LocateProtocol (&gEdkiiPlatformLogoProtocolGuid, NULL, (VOID **)&PlatformLogo);
+
+ if (!EFI_ERROR (Status)) {
+ gST->ConOut->ClearScreen (gST->ConOut);
+ BootLogoEnableLogo ();
+ }
+
+ EfiBootManagerConnectAll ();
+ EfiBootManagerRefreshAllBootOption ();
+
+ // Process Capsule in Memory again, after EndOfDxe.
+ if (GetBootModeHob () == BOOT_ON_FLASH_UPDATE) {
+ ProcessCapsules ();
+ }
+
+ OsIndication = 0;
+ Attributes = 0;
+ DataSize = sizeof (UINT64);
+ Status = gRT->GetVariable (
+ EFI_OS_INDICATIONS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ &Attributes,
+ &DataSize,
+ &OsIndication
+ );
+ if (EFI_ERROR (Status)) {
+ OsIndication = 0;
+ }
+
+ //
+ // Register UEFI Shell
+ //
+ PlatformRegisterFvBootOption (PcdGetPtr (PcdShellFile), L"UEFI Shell", LOAD_OPTION_ACTIVE);
+
+ {
+ if (FixedPcdGetBool (PcdBootManagerEscape)) {
+ Print (
+ L"\n"
+ L" Esc or Down to enter Boot Manager Menu.\n"
+ L" ENTER to boot directly.\n"
+ L"\n"
+ );
+ } else {
+ Print (
+ L"\n"
+ L" F2 or Down to enter Boot Manager Menu.\n"
+ L" ENTER to boot directly.\n"
+ L"\n"
+ );
+ }
+ }
+}
+
+/**
+ This function is called each second during the boot manager waits the timeout.
+
+ @param TimeoutRemain The remaining timeout.
+**/
+VOID
+EFIAPI
+PlatformBootManagerWaitCallback (
+ UINT16 TimeoutRemain
+ )
+{
+ if (mUniversalPayloadPlatformBootManagerOverrideInstance != NULL) {
+ mUniversalPayloadPlatformBootManagerOverrideInstance->WaitCallback (TimeoutRemain);
+ }
+
+ return;
+}
+
+/**
+ The function is called when no boot option could be launched,
+ including platform recovery options and options pointing to applications
+ built into firmware volumes.
+
+ If this function returns, BDS attempts to enter an infinite loop.
+**/
+VOID
+EFIAPI
+PlatformBootManagerUnableToBoot (
+ VOID
+ )
+{
+ if (mUniversalPayloadPlatformBootManagerOverrideInstance != NULL) {
+ mUniversalPayloadPlatformBootManagerOverrideInstance->UnableToBoot ();
+ }
+
+ return;
+}
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+ UINT64 Length;
+ UINT64 Capabilities;
+} NONTESTED_MEMORY_RANGE;
+
+//
+// This structure records every nontested memory range parsed through GCD
+// service.
+//
+#define EFI_NONTESTED_MEMORY_RANGE_SIGNATURE SIGNATURE_32 ('N', 'T', 'M', 'E')
+
+//
+// attributes for reserved memory before it is promoted to system memory
+//
+#define EFI_MEMORY_PRESENT 0x0100000000000000ULL
+#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
+#define EFI_MEMORY_TESTED 0x0400000000000000ULL
+
+/**
+ Callback function for event group EFI_EVENT_GROUP_READY_TO_BOOT.
+ This is used to expose the 4G above memory into system memory table.
+
+ @param[in] Event The Event that is being processed.
+ @param[in] Context The Event Context.
+
+**/
+VOID
+EFIAPI
+ExposeOver4GMemoryEventCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ NONTESTED_MEMORY_RANGE *Range;
+ BOOLEAN NoFound;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN Index;
+ LIST_ENTRY *TmpLink;
+ LIST_ENTRY NonTestedMemRanList;
+
+ DEBUG ((DEBUG_INFO, "ExposeOver4GMemoryEventCallback\n"));
+
+ TmpLink = NULL;
+ NoFound = TRUE;
+
+ InitializeListHead (&NonTestedMemRanList);
+
+ gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved) &&
+ ((MemorySpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED))
+ )
+ {
+ NoFound = FALSE;
+
+ gBS->AllocatePool (EfiBootServicesData, sizeof (NONTESTED_MEMORY_RANGE), (VOID **)&Range);
+
+ Range->Signature = EFI_NONTESTED_MEMORY_RANGE_SIGNATURE;
+ Range->StartAddress = MemorySpaceMap[Index].BaseAddress;
+ Range->Length = MemorySpaceMap[Index].Length;
+ Range->Capabilities = MemorySpaceMap[Index].Capabilities;
+
+ InsertTailList (&NonTestedMemRanList, &Range->Link);
+ }
+ }
+
+ if (!NoFound) {
+ TmpLink = NonTestedMemRanList.ForwardLink;
+
+ while (TmpLink != &NonTestedMemRanList) {
+ Range = CR (TmpLink, NONTESTED_MEMORY_RANGE, Link, EFI_NONTESTED_MEMORY_RANGE_SIGNATURE);
+ gDS->RemoveMemorySpace (Range->StartAddress, Range->Length);
+ gDS->AddMemorySpace (
+ EfiGcdMemoryTypeSystemMemory,
+ Range->StartAddress,
+ Range->Length,
+ Range->Capabilities &~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+ );
+
+ TmpLink = TmpLink->ForwardLink;
+ }
+ }
+
+ //
+ // Make sure the hook ONLY called once.
+ //
+ if (Event != NULL) {
+ gBS->CloseEvent (Event);
+ }
+}
+
+/**
+ Get/update PcdBootManagerMenuFile from GUID HOB which will be assigned in bootloader.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformBootManagerLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ VOID *GuidHob;
+ UNIVERSAL_PAYLOAD_GENERIC_HEADER *GenericHeader;
+ UNIVERSAL_PAYLOAD_BOOT_MANAGER_MENU *BootManagerMenuFile;
+
+ EFI_EVENT ExposeOver4GMemoryEvent;
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ ExposeOver4GMemoryEventCallback,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &ExposeOver4GMemoryEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ GuidHob = GetFirstGuidHob (&gEdkiiBootManagerMenuFileGuid);
+
+ if (GuidHob == NULL) {
+ //
+ // If the HOB is not create, the default value of PcdBootManagerMenuFile will be used.
+ //
+ return EFI_SUCCESS;
+ }
+
+ GenericHeader = (UNIVERSAL_PAYLOAD_GENERIC_HEADER *)GET_GUID_HOB_DATA (GuidHob);
+ if ((sizeof (UNIVERSAL_PAYLOAD_GENERIC_HEADER) > GET_GUID_HOB_DATA_SIZE (GuidHob)) || (GenericHeader->Length > GET_GUID_HOB_DATA_SIZE (GuidHob))) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (GenericHeader->Revision == UNIVERSAL_PAYLOAD_BOOT_MANAGER_MENU_REVISION) {
+ BootManagerMenuFile = (UNIVERSAL_PAYLOAD_BOOT_MANAGER_MENU *)GET_GUID_HOB_DATA (GuidHob);
+ if (BootManagerMenuFile->Header.Length < UNIVERSAL_PAYLOAD_SIZEOF_THROUGH_FIELD (UNIVERSAL_PAYLOAD_BOOT_MANAGER_MENU, FileName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Size = sizeof (BootManagerMenuFile->FileName);
+ Status = PcdSetPtrS (PcdBootManagerMenuFile, &Size, &BootManagerMenuFile->FileName);
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformBootManager.h b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformBootManager.h
new file mode 100644
index 0000000000..15891f9471
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformBootManager.h
@@ -0,0 +1,150 @@
+/** @file
+ Head file for BDS Platform specific code
+
+Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef PLATFORM_BOOT_MANAGER_H_
+#define PLATFORM_BOOT_MANAGER_H_
+
+#include <PiDxe.h>
+#include <Protocol/LoadedImage.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/BootLogoLib.h>
+#include <Protocol/SmmAccess2.h>
+#include <Guid/GlobalVariable.h>
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN ConnectType;
+} PLATFORM_CONSOLE_CONNECT_ENTRY;
+
+extern PLATFORM_CONSOLE_CONNECT_ENTRY gPlatformConsole[];
+
+#define gEndEntire \
+ { \
+ END_DEVICE_PATH_TYPE,\
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,\
+ { END_DEVICE_PATH_LENGTH, 0 },\
+ }
+
+#define CONSOLE_OUT BIT0
+#define CONSOLE_IN BIT1
+#define STD_ERROR BIT2
+
+#define CLASS_HID 3
+#define SUBCLASS_BOOT 1
+#define PROTOCOL_KEYBOARD 1
+
+#define PNPID_DEVICE_PATH_NODE(PnpId) \
+ { \
+ { \
+ ACPI_DEVICE_PATH, \
+ ACPI_DP, \
+ { \
+ (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \
+ (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \
+ }, \
+ }, \
+ EISA_PNP_ID((PnpId)), \
+ 0 \
+ }
+
+#define gPciRootBridge \
+ PNPID_DEVICE_PATH_NODE(0x0A03)
+
+typedef struct {
+ USB_CLASS_DEVICE_PATH UsbClass;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} USB_CLASS_FORMAT_DEVICE_PATH;
+
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ UINT32 Instance;
+} WIN_NT_VENDOR_DEVICE_PATH_NODE;
+
+//
+// Below is the platform console device path
+//
+typedef struct {
+ VENDOR_DEVICE_PATH NtBus;
+ WIN_NT_VENDOR_DEVICE_PATH_NODE SerialDevice;
+ UART_DEVICE_PATH Uart;
+ VENDOR_DEVICE_PATH TerminalType;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} NT_ISA_SERIAL_DEVICE_PATH;
+
+typedef struct {
+ VENDOR_DEVICE_PATH NtBus;
+ WIN_NT_VENDOR_DEVICE_PATH_NODE NtGopDevice;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} NT_PLATFORM_GOP_DEVICE_PATH;
+
+extern USB_CLASS_FORMAT_DEVICE_PATH gUsbClassKeyboardDevicePath;
+
+/**
+ Use SystemTable Conout to stop video based Simple Text Out consoles from going
+ to the video device. Put up LogoFile on every video device that is a console.
+
+ @param[in] LogoFile File name of logo to display on the center of the screen.
+
+ @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed.
+ @retval EFI_UNSUPPORTED Logo not found
+
+**/
+EFI_STATUS
+PlatformBootManagerEnableQuietBoot (
+ IN EFI_GUID *LogoFile
+ );
+
+/**
+ Use SystemTable Conout to turn on video based Simple Text Out consoles. The
+ Simple Text Out screens will now be synced up with all non video output devices
+
+ @retval EFI_SUCCESS UGA devices are back in text mode and synced up.
+
+**/
+EFI_STATUS
+PlatformBootManagerDisableQuietBoot (
+ VOID
+ );
+
+/**
+ Show progress bar with title above it. It only works in Graphics mode.
+
+ @param TitleForeground Foreground color for Title.
+ @param TitleBackground Background color for Title.
+ @param Title Title above progress bar.
+ @param ProgressColor Progress bar color.
+ @param Progress Progress (0-100)
+ @param PreviousValue The previous value of the progress.
+
+ @retval EFI_STATUS Success update the progress bar
+
+**/
+EFI_STATUS
+PlatformBootManagerShowProgress (
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,
+ IN CHAR16 *Title,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,
+ IN UINTN Progress,
+ IN UINTN PreviousValue
+ );
+
+#endif // _PLATFORM_BOOT_MANAGER_H
diff --git a/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformBootManagerLib.inf
new file mode 100644
index 0000000000..fc9251d3fd
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformBootManagerLib.inf
@@ -0,0 +1,89 @@
+## @file
+# Include all platform action which can be customized by IBV/OEM.
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (c) 2012 - 2021, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformBootManagerLib
+ FILE_GUID = 9455F0BD-2037-488A-8899-56CB72A44A03
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformBootManagerLib|DXE_DRIVER
+ CONSTRUCTOR = PlatformBootManagerLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ PlatformData.c
+ PlatformConsole.c
+ PlatformConsole.h
+ PlatformBootManager.c
+ PlatformBootManager.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiPayloadPkg/UefiPayloadPkg.dec
+ AgesaPublic/AgesaPublic.dec
+ VanGoghCommonPkg/AmdCommonPkg.dec
+ ChachaniBoardPkg/Project.dec
+
+[LibraryClasses]
+ BaseLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiLib
+ UefiBootManagerLib
+ BootLogoLib
+ PcdLib
+ DxeServicesLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ DevicePathLib
+ HiiLib
+ PrintLib
+ PlatformHookLib
+ HobLib
+ DebugLib
+ CapsuleLib
+ CapsuleHookLib
+
+[Guids]
+ gEfiEndOfDxeEventGroupGuid
+ gEdkiiBootManagerMenuFileGuid
+ gEfiEventReadyToBootGuid
+
+[Protocols]
+ gEfiGenericMemTestProtocolGuid ## CONSUMES
+ gEfiGraphicsOutputProtocolGuid ## CONSUMES
+ gEfiUgaDrawProtocolGuid ## CONSUMES
+ gEfiBootLogoProtocolGuid ## CONSUMES
+ gEfiDxeSmmReadyToLockProtocolGuid
+ gEfiSmmAccess2ProtocolGuid
+ gUniversalPayloadPlatformBootManagerOverrideProtocolGuid
+ gEfiSerialIoProtocolGuid
+ gEfiPciRootBridgeIoProtocolGuid
+ gAmdCpmAllPciIoProtocolsInstalledProtocolGuid
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
+ gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConInConnectOnDemand
+ gUefiPayloadPkgTokenSpaceGuid.PcdShellFile
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile
+ gUefiPayloadPkgTokenSpaceGuid.PcdBootManagerEscape
diff --git a/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformConsole.c b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformConsole.c
new file mode 100644
index 0000000000..4849770ff6
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformConsole.c
@@ -0,0 +1,495 @@
+/** @file
+This file include all platform action which can be customized by IBV/OEM.
+
+Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PlatformBootManager.h"
+#include "PlatformConsole.h"
+#include <Guid/SerialPortLibVendor.h>
+
+#define PCI_DEVICE_PATH_NODE(Func, Dev) \
+ { \
+ { \
+ HARDWARE_DEVICE_PATH, \
+ HW_PCI_DP, \
+ { \
+ (UINT8) (sizeof (PCI_DEVICE_PATH)), \
+ (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) \
+ } \
+ }, \
+ (Func), \
+ (Dev) \
+ }
+
+#define PNPID_DEVICE_PATH_NODE(PnpId) \
+ { \
+ { \
+ ACPI_DEVICE_PATH, \
+ ACPI_DP, \
+ { \
+ (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \
+ (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \
+ }, \
+ }, \
+ EISA_PNP_ID((PnpId)), \
+ 0 \
+ }
+
+#define gPnp16550ComPort \
+ PNPID_DEVICE_PATH_NODE(0x0501)
+
+#define gPnpPs2Keyboard \
+ PNPID_DEVICE_PATH_NODE(0x0303)
+
+#define gPcAnsiTerminal \
+ { \
+ { \
+ MESSAGING_DEVICE_PATH, \
+ MSG_VENDOR_DP, \
+ { \
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)), \
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) \
+ } \
+ }, \
+ DEVICE_PATH_MESSAGING_PC_ANSI \
+ }
+
+ACPI_HID_DEVICE_PATH gPnpPs2KeyboardDeviceNode = gPnpPs2Keyboard;
+ACPI_HID_DEVICE_PATH gPnp16550ComPortDeviceNode = gPnp16550ComPort;
+VENDOR_DEVICE_PATH gTerminalTypeDeviceNode = gPcAnsiTerminal;
+
+BOOLEAN mDetectDisplayOnly;
+
+/**
+ Add IsaKeyboard to ConIn.
+
+ @param[in] DeviceHandle Handle of the LPC Bridge device.
+
+ @retval EFI_SUCCESS IsaKeyboard on the LPC bridge have been added to ConIn.
+ @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
+ from DeviceHandle.
+**/
+EFI_STATUS
+PrepareLpcBridgeDevicePath (
+ IN EFI_HANDLE DeviceHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ DevicePath = NULL;
+ Status = gBS->HandleProtocol (
+ DeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID *)&DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Register Keyboard
+ //
+ DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
+ EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the GOP device path in the platform.
+
+ @param[in] PciDevicePath - Device path for the PCI graphics device.
+ @param[out] GopDevicePath - Return the device path with GOP installed.
+
+ @retval EFI_SUCCESS - PCI VGA is added to ConOut.
+ @retval EFI_INVALID_PARAMETER - The device path parameter is invalid.
+ @retval EFI_STATUS - No GOP device found.
+**/
+EFI_STATUS
+GetGopDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_HANDLE PciDeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;
+ UINTN GopHandleCount;
+ EFI_HANDLE *GopHandleBuffer;
+
+ if ((PciDevicePath == NULL) || (GopDevicePath == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize the GopDevicePath to be PciDevicePath
+ //
+ *GopDevicePath = PciDevicePath;
+ TempPciDevicePath = PciDevicePath;
+
+ Status = gBS->LocateDevicePath (
+ &gEfiDevicePathProtocolGuid,
+ &TempPciDevicePath,
+ &PciDeviceHandle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiGraphicsOutputProtocolGuid,
+ NULL,
+ &GopHandleCount,
+ &GopHandleBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Add all the child handles as possible Console Device
+ //
+ for (Index = 0; Index < GopHandleCount; Index++) {
+ Status = gBS->HandleProtocol (GopHandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *)&TempDevicePath);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (CompareMem (
+ PciDevicePath,
+ TempDevicePath,
+ GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
+ ) == 0)
+ {
+ //
+ // In current implementation, we only enable one of the child handles
+ // as console device, i.e. sotre one of the child handle's device
+ // path to variable "ConOut"
+ // In future, we could select all child handles to be console device
+ //
+ *GopDevicePath = TempDevicePath;
+
+ //
+ // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
+ // Add the integrity GOP device path.
+ //
+ EfiBootManagerUpdateConsoleVariable (ConOut, NULL, PciDevicePath);
+ EfiBootManagerUpdateConsoleVariable (ConOut, TempDevicePath, NULL);
+ }
+ }
+
+ gBS->FreePool (GopHandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add PCI VGA to ConOut, ConIn, ErrOut.
+
+ @param[in] DeviceHandle - Handle of PciIo protocol.
+
+ @retval EFI_SUCCESS - PCI VGA is added to ConOut.
+ @retval EFI_STATUS - No PCI VGA device is added.
+
+**/
+EFI_STATUS
+PreparePciVgaDevicePath (
+ IN EFI_HANDLE DeviceHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
+
+ DevicePath = NULL;
+ Status = gBS->HandleProtocol (
+ DeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID *)&DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ GetGopDevicePath (DevicePath, &GopDevicePath);
+ DevicePath = GopDevicePath;
+
+ EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ For every PCI instance execute a callback function.
+
+ @param[in] Id - The protocol GUID for callback
+ @param[in] CallBackFunction - The callback function
+
+ @retval EFI_STATUS - Callback function failed.
+
+**/
+EFI_STATUS
+EFIAPI
+VisitAllInstancesOfProtocol (
+ IN EFI_GUID *Id,
+ IN SIMPLE_PROTOCOL_INSTANCE_CALLBACK CallBackFunction
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ VOID *Instance;
+
+ //
+ // Start to check all the PciIo to find all possible device
+ //
+ HandleCount = 0;
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ Id,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = (*CallBackFunction)(
+ HandleBuffer[Index],
+ Instance
+ );
+ }
+
+ gBS->FreePool (HandleBuffer);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Do platform specific PCI Device check and add them to
+ ConOut, ConIn, ErrOut.
+
+ @param[in] Handle - Handle of PCI device instance
+ @param[in] Instance - The instance of PCI device
+
+ @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
+ @retval EFI_STATUS - PCI Device check or Console variable update fail.
+
+**/
+EFI_STATUS
+EFIAPI
+DetectAndPreparePlatformPciDevicePath (
+ IN EFI_HANDLE Handle,
+ IN VOID *Instance
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ EFI_HANDLE CPMHandle;
+
+ PciIo = (EFI_PCI_IO_PROTOCOL *)Instance;
+
+ //
+ // Check for all PCI device
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (!mDetectDisplayOnly) {
+ //
+ // Here we decide whether it is LPC Bridge
+ //
+ if ((IS_PCI_LPC (&Pci)) ||
+ ((IS_PCI_ISA_PDECODE (&Pci)) &&
+ (Pci.Hdr.VendorId == 0x8086)
+ )
+ )
+ {
+ //
+ // Add IsaKeyboard to ConIn,
+ // add IsaSerial to ConOut, ConIn, ErrOut
+ //
+ DEBUG ((DEBUG_INFO, "Found LPC Bridge device\n"));
+ PrepareLpcBridgeDevicePath (Handle);
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Enable all display devices
+ //
+ if (IS_PCI_DISPLAY (&Pci)) {
+ //
+ // Add them to ConOut.
+ //
+ DEBUG ((DEBUG_INFO, "Found PCI Display device\n"));
+ EfiBootManagerConnectVideoController (Handle);
+ //
+ // At this point, all the PCI_IO protocols are installed completely.
+ // Install gAmdCpmAllPciIoProtocolsInstalledProtocolGuid protocol for AmdCpmDisplayFeature DXE driver.
+ //
+ CPMHandle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &CPMHandle,
+ &gAmdCpmAllPciIoProtocolsInstalledProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((DEBUG_INFO, "InstallProtocolInterface gAmdCpmAllPciIoProtocolsInstalledProtocolGuid %r\n", Status));
+ return EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ For every Serial Io instance, add it to ConOut, ConIn, ErrOut.
+
+ @param[in] Handle - The Serial Io device handle
+ @param[in] Instance - The instance of the SerialIo protocol
+
+ @retval EFI_STATUS - Callback function failed.
+
+**/
+EFI_STATUS
+EFIAPI
+AddDevicePathForOneSerialIoInstance (
+ IN EFI_HANDLE Handle,
+ IN VOID *Instance
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ DevicePath = NULL;
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID *)&DevicePath
+ );
+ DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
+
+ EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+ EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
+ EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
+ return Status;
+}
+
+/**
+ Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
+
+ @param[in] DetectDisplayOnly - Only detect display device if it's TRUE.
+
+ @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
+ @retval EFI_STATUS - PCI Device check or Console variable update fail.
+
+**/
+EFI_STATUS
+DetectAndPreparePlatformPciDevicePaths (
+ BOOLEAN DetectDisplayOnly
+ )
+{
+ EFI_STATUS Status;
+
+ mDetectDisplayOnly = DetectDisplayOnly;
+
+ EfiBootManagerUpdateConsoleVariable (
+ ConIn,
+ (EFI_DEVICE_PATH_PROTOCOL *)&gUsbClassKeyboardDevicePath,
+ NULL
+ );
+
+ VisitAllInstancesOfProtocol (
+ &gEfiSerialIoProtocolGuid,
+ AddDevicePathForOneSerialIoInstance
+ );
+
+ Status = VisitAllInstancesOfProtocol (
+ &gEfiPciIoProtocolGuid,
+ DetectAndPreparePlatformPciDevicePath
+ );
+ return Status;
+}
+
+/**
+ The function will connect one root bridge
+
+ @param[in] Handle - The root bridge handle
+ @param[in] Instance - The instance of the root bridge
+
+ @return EFI_SUCCESS Connect RootBridge successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+ConnectOneRootBridge (
+ IN EFI_HANDLE Handle,
+ IN VOID *Instance
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->ConnectController (Handle, NULL, NULL, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Platform console init. Include the platform firmware vendor, revision
+ and so crc check.
+
+**/
+VOID
+EFIAPI
+PlatformConsoleInit (
+ VOID
+ )
+{
+ VisitAllInstancesOfProtocol (
+ &gEfiPciRootBridgeIoProtocolGuid,
+ ConnectOneRootBridge
+ );
+
+ //
+ // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
+ //
+ DetectAndPreparePlatformPciDevicePaths (FALSE);
+}
diff --git a/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformConsole.h b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformConsole.h
new file mode 100644
index 0000000000..dc66db7ced
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformConsole.h
@@ -0,0 +1,69 @@
+/** @file
+Head file for BDS Platform specific code
+
+Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef PLATFORM_CONSOLE_H_
+#define PLATFORM_CONSOLE_H_
+
+#include <PiDxe.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Protocol/PciIo.h>
+
+#define IS_PCI_ISA_PDECODE(_p) IS_CLASS3 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_ISA_PDECODE, 0)
+
+//
+// Type definitions
+//
+
+//
+// Platform Root Bridge
+//
+typedef struct {
+ ACPI_HID_DEVICE_PATH PciRootBridge;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_ROOT_BRIDGE_DEVICE_PATH;
+
+typedef
+EFI_STATUS
+(EFIAPI *SIMPLE_PROTOCOL_INSTANCE_CALLBACK)(
+ IN EFI_HANDLE Handle,
+ IN VOID *Instance
+ );
+
+/**
+ @param[in] Handle - Handle of PCI device instance
+ @param[in] PciIo - PCI IO protocol instance
+ @param[in] Pci - PCI Header register block
+**/
+typedef
+EFI_STATUS
+(EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(
+ IN EFI_HANDLE Handle,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN PCI_TYPE00 *Pci
+ );
+
+/**
+ Platform console init. Include the platform firmware vendor, revision
+ and so crc check.
+
+**/
+VOID
+EFIAPI
+PlatformConsoleInit (
+ VOID
+ );
+
+#endif
diff --git a/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformData.c b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformData.c
new file mode 100644
index 0000000000..d8871a4bd5
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/ChachaniBoardPkg/Library/Capsule/PlatformBootManagerLib/PlatformData.c
@@ -0,0 +1,39 @@
+/** @file
+ Defined the platform specific device path which will be filled to
+ ConIn/ConOut variables.
+
+Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "PlatformBootManager.h"
+
+///
+/// Predefined platform default console device path
+///
+GLOBAL_REMOVE_IF_UNREFERENCED PLATFORM_CONSOLE_CONNECT_ENTRY gPlatformConsole[] = {
+ {
+ NULL,
+ 0
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED USB_CLASS_FORMAT_DEVICE_PATH gUsbClassKeyboardDevicePath = {
+ {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_USB_CLASS_DP,
+ {
+ (UINT8)(sizeof (USB_CLASS_DEVICE_PATH)),
+ (UINT8)((sizeof (USB_CLASS_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0xffff, // VendorId
+ 0xffff, // ProductId
+ CLASS_HID, // DeviceClass
+ SUBCLASS_BOOT, // DeviceSubClass
+ PROTOCOL_KEYBOARD // DeviceProtocol
+ },
+ gEndEntire
+};
diff --git a/Platform/AMD/VanGoghBoard/Override/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf b/Platform/AMD/VanGoghBoard/Override/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
new file mode 100644
index 0000000000..c99dd4cd47
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/Override/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
@@ -0,0 +1,122 @@
+## @file
+# Capsule Runtime DXE Module INF file
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+## @file
+# Capsule Runtime Driver produces two UEFI capsule runtime services: (UpdateCapsule, QueryCapsuleCapabilities).
+#
+# It installs the Capsule Architectural Protocol defined in PI1.0a to signify
+# the capsule runtime services are ready.
+#
+# Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CapsuleRuntimeDxe
+ MODULE_UNI_FILE = CapsuleRuntimeDxe.uni
+ FILE_GUID = 42857F0A-13F2-4B21-8A23-53D3F714B840
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = CapsuleServiceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64 RISCV64
+#
+
+[Sources]
+ CapsuleService.c
+ CapsuleService.h
+
+[Sources.Ia32, Sources.EBC, Sources.ARM, Sources.AARCH64, Sources.RISCV64]
+ SaveLongModeContext.c
+
+[Sources.Ia32, Sources.X64, Sources.ARM, Sources.AARCH64, Sources.RISCV64]
+ CapsuleCache.c
+
+[Sources.Ia32, Sources.X64, Sources.EBC, Sources.RISCV64]
+ CapsuleReset.c
+
+[Sources.ARM, Sources.AARCH64]
+ Arm/CapsuleReset.c
+
+[Sources.EBC]
+ CapsuleCacheNull.c
+
+[Sources.X64]
+ X64/SaveLongModeContext.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ VanGoghCommonPkg/AmdCommonPkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ PcdLib
+ DebugLib
+ UefiRuntimeServicesTableLib
+ UefiDriverEntryPoint
+ CapsuleLib
+ UefiRuntimeLib
+ BaseLib
+ PrintLib
+ BaseMemoryLib
+ CacheMaintenanceLib
+ IoLib
+
+[LibraryClasses.X64]
+ UefiLib
+ BaseMemoryLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"CapsuleUpdateData" # (Process across reset capsule image) for capsule updated data
+ ## SOMETIMES_PRODUCES ## Variable:L"CapsuleLongModeBuffer" # The long mode buffer used by IA32 Capsule PEIM to call X64 CapsuleCoalesce code to handle >4GB capsule blocks
+ gEfiCapsuleVendorGuid
+ gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID # FMP capsule GUID
+ gAmdSetCapsuleS3FlagGuid ## SOMETIMES_CONSUMES
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES
+
+[Protocols]
+ gEfiCapsuleArchProtocolGuid ## PRODUCES
+ gEfiMmCommunication2ProtocolGuid ## CONSUMES
+
+[Protocols.X64]
+ ## UNDEFINED ## NOTIFY
+ ## SOMETIMES_CONSUMES
+ gEdkiiVariableLockProtocolGuid
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSupportProcessCapsuleAtRuntime ## CONSUMES
+
+[FeaturePcd.X64]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizeNonPopulateCapsule ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizePopulateCapsule ## SOMETIMES_CONSUMES # Populate Image requires reset support.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleInRamSupport ## CONSUMES
+
+[Pcd.X64]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsulePeiLongModeStackSize ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiVariableWriteArchProtocolGuid AND # Depends on variable write functionality to produce capsule data variable
+ gEfiMmCommunication2ProtocolGuid # Perform AMD Specific flags settings
+
+# [Hob.X64]
+# UNDEFINED ## SOMETIMES_CONSUMES # CPU
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ CapsuleRuntimeDxeExtra.uni
diff --git a/Platform/AMD/VanGoghBoard/Override/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c b/Platform/AMD/VanGoghBoard/Override/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c
new file mode 100644
index 0000000000..6915c054dd
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/Override/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c
@@ -0,0 +1,461 @@
+/** @file
+ Capsule Runtime Driver produces two UEFI capsule runtime services.
+ (UpdateCapsule, QueryCapsuleCapabilities)
+ It installs the Capsule Architectural Protocol defined in PI1.0a to signify
+ the capsule runtime services are ready.
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CapsuleService.h"
+
+#include <Library/IoLib.h>
+
+//
+// Handle for the installation of Capsule Architecture Protocol.
+//
+EFI_HANDLE mNewHandle = NULL;
+
+//
+// The times of calling UpdateCapsule ()
+//
+UINTN mTimes = 0;
+
+UINT32 mMaxSizePopulateCapsule = 0;
+UINT32 mMaxSizeNonPopulateCapsule = 0;
+
+// Cached MM Communication protocol.
+EFI_MM_COMMUNICATION2_PROTOCOL *mMmCommunication2 = NULL;
+
+// For MM Communication purpose.
+EFI_MM_COMMUNICATE_HEADER *mCommunicationBuffer = NULL;
+EFI_MM_COMMUNICATE_HEADER *mCommunicationBufferPhysical = NULL;
+EFI_EVENT mVirtualAddressChangeEvent = NULL;
+extern EFI_GUID gAmdSetCapsuleS3FlagGuid;
+
+/**
+ Passes capsules to the firmware with both virtual and physical mapping. Depending on the intended
+ consumption, the firmware may process the capsule immediately. If the payload should persist
+ across a system reset, the reset value returned from EFI_QueryCapsuleCapabilities must
+ be passed into ResetSystem() and will cause the capsule to be processed by the firmware as
+ part of the reset process.
+
+ @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules
+ being passed into update capsule.
+ @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in
+ CaspuleHeaderArray.
+ @param ScatterGatherList Physical pointer to a set of
+ EFI_CAPSULE_BLOCK_DESCRIPTOR that describes the
+ location in physical memory of a set of capsules.
+
+ @retval EFI_SUCCESS Valid capsule was passed. If
+ CAPSULE_FLAGS_PERSIT_ACROSS_RESET is not set, the
+ capsule has been successfully processed by the firmware.
+ @retval EFI_DEVICE_ERROR The capsule update was started, but failed due to a device error.
+ @retval EFI_INVALID_PARAMETER CapsuleSize is NULL, or an incompatible set of flags were
+ set in the capsule header.
+ @retval EFI_INVALID_PARAMETER CapsuleCount is Zero.
+ @retval EFI_INVALID_PARAMETER For across reset capsule image, ScatterGatherList is NULL.
+ @retval EFI_UNSUPPORTED CapsuleImage is not recognized by the firmware.
+ @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has been previously called this error indicates the capsule
+ is compatible with this platform but is not capable of being submitted or processed
+ in runtime. The caller may resubmit the capsule prior to ExitBootServices().
+ @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has not been previously called then this error indicates
+ the capsule is compatible with this platform but there are insufficient resources to process.
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateCapsule (
+ IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
+ IN UINTN CapsuleCount,
+ IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL
+ )
+{
+ UINTN ArrayNumber;
+ EFI_STATUS Status;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ BOOLEAN NeedReset;
+ BOOLEAN InitiateReset;
+ CHAR16 CapsuleVarName[30];
+ CHAR16 *TempVarName;
+
+ //
+ // Check if platform support Capsule In RAM or not.
+ // Platform could choose to drop CapsulePei/CapsuleX64 and do not support Capsule In RAM.
+ //
+ if (!PcdGetBool (PcdCapsuleInRamSupport)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Capsule Count can't be less than one.
+ //
+ if (CapsuleCount < 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NeedReset = FALSE;
+ InitiateReset = FALSE;
+ CapsuleHeader = NULL;
+ CapsuleVarName[0] = 0;
+
+ for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
+ //
+ // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have
+ // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
+ //
+ CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have
+ // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
+ //
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check FMP capsule flag
+ //
+ if ( CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)
+ && ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check Capsule image without populate flag by firmware support capsule function
+ //
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
+ Status = SupportCapsuleImage (CapsuleHeader);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ //
+ // Walk through all capsules, record whether there is a capsule needs reset
+ // or initiate reset. And then process capsules which has no reset flag directly.
+ //
+ for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
+ CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
+ //
+ // Here should be in the boot-time for non-reset capsule image
+ // Platform specific update for the non-reset capsule image.
+ //
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) {
+ if (EfiAtRuntime () && !FeaturePcdGet (PcdSupportProcessCapsuleAtRuntime)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ Status = ProcessCapsuleImage (CapsuleHeader);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ NeedReset = TRUE;
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_INITIATE_RESET) != 0) {
+ InitiateReset = TRUE;
+ }
+ }
+ }
+
+ //
+ // After launching all capsules who has no reset flag, if no more capsules claims
+ // for a system reset just return.
+ //
+ if (!NeedReset) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // ScatterGatherList is only referenced if the capsules are defined to persist across
+ // system reset.
+ //
+ if (ScatterGatherList == (EFI_PHYSICAL_ADDRESS)(UINTN)NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if the platform supports update capsule across a system reset
+ //
+ if (!IsPersistAcrossResetCapsuleSupported ()) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CapsuleCacheWriteBack (ScatterGatherList);
+
+ //
+ // Construct variable name CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
+ // if user calls UpdateCapsule multiple times.
+ //
+ StrCpyS (CapsuleVarName, sizeof (CapsuleVarName)/sizeof (CHAR16), EFI_CAPSULE_VARIABLE_NAME);
+ TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
+ if (mTimes > 0) {
+ UnicodeValueToStringS (
+ TempVarName,
+ sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),
+ 0,
+ mTimes,
+ 0
+ );
+ }
+
+ //
+ // ScatterGatherList is only referenced if the capsules are defined to persist across
+ // system reset. Set its value into NV storage to let pre-boot driver to pick it up
+ // after coming through a system reset.
+ //
+ Status = EfiSetVariable (
+ CapsuleVarName,
+ &gEfiCapsuleVendorGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (UINTN),
+ (VOID *)&ScatterGatherList
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Variable has been set successfully, increase variable index.
+ //
+ mTimes++;
+ if (InitiateReset) {
+ //
+ // Firmware that encounters a capsule which has the CAPSULE_FLAGS_INITIATE_RESET Flag set in its header
+ // will initiate a reset of the platform which is compatible with the passed-in capsule request and will
+ // not return back to the caller.
+ //
+ // EfiResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ // Invoke AMD Specific S3.
+ DEBUG ((DEBUG_INFO, "Setting AMD Specific S3 Flag.\n"));
+ Status = mMmCommunication2->Communicate (
+ mMmCommunication2,
+ mCommunicationBufferPhysical,
+ mCommunicationBuffer,
+ NULL
+ );
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Returns if the capsule can be supported via UpdateCapsule().
+ Notice: When PcdCapsuleInRamSupport is unsupported, even this routine returns a valid answer,
+ the capsule still is unsupported via UpdateCapsule().
+
+ @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules
+ being passed into update capsule.
+ @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in
+ CaspuleHeaderArray.
+ @param MaxiumCapsuleSize On output the maximum size that UpdateCapsule() can
+ support as an argument to UpdateCapsule() via
+ CapsuleHeaderArray and ScatterGatherList.
+ @param ResetType Returns the type of reset required for the capsule update.
+
+ @retval EFI_SUCCESS Valid answer returned.
+ @retval EFI_UNSUPPORTED The capsule image is not supported on this platform, and
+ MaximumCapsuleSize and ResetType are undefined.
+ @retval EFI_INVALID_PARAMETER MaximumCapsuleSize is NULL, or ResetTyep is NULL,
+ Or CapsuleCount is Zero, or CapsuleImage is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+QueryCapsuleCapabilities (
+ IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
+ IN UINTN CapsuleCount,
+ OUT UINT64 *MaxiumCapsuleSize,
+ OUT EFI_RESET_TYPE *ResetType
+ )
+{
+ EFI_STATUS Status;
+ UINTN ArrayNumber;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ BOOLEAN NeedReset;
+
+ //
+ // Capsule Count can't be less than one.
+ //
+ if (CapsuleCount < 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether input parameter is valid
+ //
+ if ((MaxiumCapsuleSize == NULL) || (ResetType == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CapsuleHeader = NULL;
+ NeedReset = FALSE;
+
+ for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
+ CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
+ //
+ // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have
+ // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
+ //
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have
+ // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
+ //
+ if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check FMP capsule flag
+ //
+ if ( CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)
+ && ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check Capsule image without populate flag is supported by firmware
+ //
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
+ Status = SupportCapsuleImage (CapsuleHeader);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ //
+ // Find out whether there is any capsule defined to persist across system reset.
+ //
+ for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
+ CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
+ NeedReset = TRUE;
+ break;
+ }
+ }
+
+ if (NeedReset) {
+ //
+ // Check if the platform supports update capsule across a system reset
+ //
+ if (!IsPersistAcrossResetCapsuleSupported ()) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *ResetType = EfiResetWarm;
+ *MaxiumCapsuleSize = (UINT64)mMaxSizePopulateCapsule;
+ } else {
+ //
+ // For non-reset capsule image.
+ //
+ *ResetType = EfiResetCold;
+ *MaxiumCapsuleSize = (UINT64)mMaxSizeNonPopulateCapsule;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ Here it converts the SMM Communicate buffer address into virtual.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+VariableAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EfiConvertPointer (0x0, (VOID **)&mCommunicationBuffer);
+ EfiConvertPointer (0x0, (VOID **)&mMmCommunication2);
+}
+
+/**
+
+ This code installs UEFI capsule runtime service.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS UEFI Capsule Runtime Services are installed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+CapsuleServiceInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mMaxSizePopulateCapsule = PcdGet32 (PcdMaxSizePopulateCapsule);
+ mMaxSizeNonPopulateCapsule = PcdGet32 (PcdMaxSizeNonPopulateCapsule);
+
+ //
+ // When PEI phase is IA32, DXE phase is X64, it is possible that capsule data are
+ // put above 4GB, so capsule PEI will transfer to long mode to get capsule data.
+ // The page table and stack is used to transfer processor mode from IA32 to long mode.
+ // Create the base address of page table and stack, and save them into variable.
+ // This is not needed when capsule with reset type is not supported.
+ //
+ SaveLongModeContext ();
+
+ //
+ // Install capsule runtime services into UEFI runtime service tables.
+ //
+ gRT->UpdateCapsule = UpdateCapsule;
+ gRT->QueryCapsuleCapabilities = QueryCapsuleCapabilities;
+
+ //
+ // Install the Capsule Architectural Protocol on a new handle
+ // to signify the capsule runtime services are ready.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mNewHandle,
+ &gEfiCapsuleArchProtocolGuid,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiMmCommunication2ProtocolGuid, NULL, (VOID **)&mMmCommunication2);
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->AllocatePool (EfiRuntimeServicesData, sizeof (EFI_MM_COMMUNICATE_HEADER), (VOID **)&mCommunicationBufferPhysical);
+ ASSERT_EFI_ERROR (Status);
+ CopyGuid (&(mCommunicationBufferPhysical->HeaderGuid), &gAmdSetCapsuleS3FlagGuid);
+ mCommunicationBufferPhysical->MessageLength = 0;
+ mCommunicationBuffer = mCommunicationBufferPhysical;
+
+ // Create an event to update SMM pointers.
+ gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ VariableAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mVirtualAddressChangeEvent
+ );
+
+ return Status;
+}
diff --git a/Platform/AMD/VanGoghBoard/Override/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.h b/Platform/AMD/VanGoghBoard/Override/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.h
new file mode 100644
index 0000000000..fc6d831663
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/Override/edk2/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.h
@@ -0,0 +1,73 @@
+/** @file
+ Capsule Runtime Driver produces two UEFI capsule runtime services.
+ (UpdateCapsule, QueryCapsuleCapabilities)
+ It installs the Capsule Architectural Protocol defined in PI1.0a to signify
+ the capsule runtime services are ready.
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CAPSULE_SERVICE_H__
+#define CAPSULE_SERVICE_H__
+
+#include <Uefi.h>
+
+#include <Protocol/Capsule.h>
+#include <Protocol/MmCommunication2.h>
+#include <Guid/CapsuleVendor.h>
+#include <Guid/FmpCapsule.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PrintLib.h>
+#include <Library/BaseMemoryLib.h>
+
+/**
+ Create the variable to save the base address of page table and stack
+ for transferring into long mode in IA32 PEI.
+**/
+VOID
+SaveLongModeContext (
+ VOID
+ );
+
+/**
+ Whether the platform supports capsules that persist across reset. Note that
+ some platforms only support such capsules at boot time.
+
+ @return TRUE if a PersistAcrossReset capsule may be passed to UpdateCapsule()
+ at this time
+ FALSE otherwise
+**/
+BOOLEAN
+IsPersistAcrossResetCapsuleSupported (
+ VOID
+ );
+
+/**
+ Writes Back a range of data cache lines covering a set of capsules in memory.
+
+ Writes Back the data cache lines specified by ScatterGatherList.
+
+ @param ScatterGatherList Physical address of the data structure that
+ describes a set of capsules in memory
+
+**/
+VOID
+CapsuleCacheWriteBack (
+ IN EFI_PHYSICAL_ADDRESS ScatterGatherList
+ );
+
+#endif
--
2.31.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#114497): https://edk2.groups.io/g/devel/message/114497
Mute This Topic: https://groups.io/mt/103971394/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
© 2016 - 2024 Red Hat, Inc.