From: Duke Zhai <duke.z...@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....@amd.com>
Cc: Duke Zhai <duke.z...@amd.com>
Cc: Eric Xing <eric.x...@amd.com>
Cc: Igniculus Fu <igniculus...@amd.com>
Cc: Abner Chang <abner.ch...@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/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-



Reply via email to