Hi Nickle,

Please see my comments inline...

P/s: I just realized that I can not test this protocol without IPMI SSIF to be compatible with ManageabilityPkg framework.

On 5/15/2024 10:06 PM, Nickle Wang wrote:
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4773

This change implements the blob transfer protocol used in OpenBmc
documented here: https://github.com/openbmc/phosphor-ipmi-blobs

Signed-off-by: Nick Ramirez <nrami...@nvidia.com>
Co-authored-by: Nickle Wang <nick...@nvidia.com>
Cc: Abner Chang <abner.ch...@amd.com>
Cc: Abdul Lateef Attar <abdullateef.at...@amd.com>
Cc: Tinh Nguyen <tinhngu...@amperemail.onmicrosoft.com>
Cc: Nhi Pham <n...@os.amperecomputing.com>
Cc: Thang Nguyen OS <th...@amperemail.onmicrosoft.com>
Cc: Mike Maslenkin <mike.maslen...@gmail.com>
---
  .../ManageabilityPkg/ManageabilityPkg.dec     |    3 +
  .../Include/Manageability.dsc                 |    2 +
  .../IpmiBlobTransferDxe.inf                   |   39 +
  .../IpmiBlobTransferTestUnitTestsHost.inf     |   40 +
  .../Include/Protocol/IpmiBlobTransfer.h       |  253 ++++
  .../InternalIpmiBlobTransfer.h                |  407 ++++++
  .../IpmiBlobTransferDxe/IpmiBlobTransferDxe.c |  872 +++++++++++++
  .../UnitTest/IpmiBlobTransferTestUnitTests.c  | 1113 +++++++++++++++++
  .../Universal/IpmiBlobTransferDxe/Readme.md   |   24 +
  9 files changed, 2753 insertions(+)
  create mode 100644 
Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
  create mode 100644 
Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
  create mode 100644 
Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
  create mode 100644 
Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
  create mode 100644 
Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
  create mode 100644 
Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
  create mode 100644 
Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md

diff --git a/Features/ManageabilityPkg/ManageabilityPkg.dec 
b/Features/ManageabilityPkg/ManageabilityPkg.dec
index eb0ee67cba..dc1d00162c 100644
--- a/Features/ManageabilityPkg/ManageabilityPkg.dec
+++ b/Features/ManageabilityPkg/ManageabilityPkg.dec
@@ -4,6 +4,7 @@
  # those are related to the platform management.
  #
  # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  # SPDX-License-Identifier: BSD-2-Clause-Patent
  #
  ##
@@ -58,6 +59,8 @@
    gEdkiiPldmProtocolGuid                = { 0x60997616, 0xDB70, 0x4B5F, { 
0x86, 0xA4, 0x09, 0x58, 0xA3, 0x71, 0x47, 0xB4 } }
    gEdkiiPldmSmbiosTransferProtocolGuid  = { 0xFA431C3C, 0x816B, 0x4B32, { 
0xA3, 0xE0, 0xAD, 0x9B, 0x7F, 0x64, 0x27, 0x2E } }
    gEdkiiMctpProtocolGuid                = { 0xE93465C1, 0x9A31, 0x4C96, { 
0x92, 0x56, 0x22, 0x0A, 0xE1, 0x80, 0xB4, 0x1B } }
+  ## Include/Protocol/IpmiBlobTransfer.h
+  gEdkiiIpmiBlobTransferProtocolGuid    = { 0x05837c75, 0x1d65, 0x468b, { 
0xb1, 0xc2, 0x81, 0xaf, 0x9a, 0x31, 0x5b, 0x2c } }
[PcdsFixedAtBuild]
    ## This value is the MCTP Interface source and destination endpoint ID for 
transmiting MCTP message.
diff --git a/Features/ManageabilityPkg/Include/Manageability.dsc 
b/Features/ManageabilityPkg/Include/Manageability.dsc
index 2e410df9ba..aae343a733 100644
--- a/Features/ManageabilityPkg/Include/Manageability.dsc
+++ b/Features/ManageabilityPkg/Include/Manageability.dsc
@@ -2,6 +2,7 @@
  # Common libraries for Manageabilty Package
  #
  # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  # SPDX-License-Identifier: BSD-2-Clause-Patent
  #
  ##
@@ -37,6 +38,7 @@
  [Components.X64, Components.AARCH64]
  !if gManageabilityPkgTokenSpaceGuid.PcdManageabilityDxeIpmiEnable == TRUE
    ManageabilityPkg/Universal/IpmiProtocol/Dxe/IpmiProtocolDxe.inf
+  ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
  !endif
[Components.X64]
diff --git 
a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
 
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
new file mode 100644
index 0000000000..108f4bb5f8
--- /dev/null
+++ 
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
@@ -0,0 +1,39 @@
+## @file
+# IPMI Blob Transfer Protocol DXE Driver.
+#
+#  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights 
reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = IpmiBlobTransferDxe
+  FILE_GUID                      = 6357c804-78bb-4b0c-abdf-c75df942f319
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = IpmiBlobTransferDxeDriverEntryPoint
+
+[Sources.common]
+  IpmiBlobTransferDxe.c
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  IpmiLib
+  MemoryAllocationLib
+  PcdLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  ManageabilityPkg/ManageabilityPkg.dec
+
+[Protocols]
+  gEdkiiIpmiBlobTransferProtocolGuid
+
+[Depex]
+  TRUE
diff --git 
a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
 
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
new file mode 100644
index 0000000000..dab6858f09
--- /dev/null
+++ 
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
@@ -0,0 +1,40 @@
+## @file
+# Unit tests of the Ipmi blob transfer driver that are run from a host 
environment.
+#
+# Copyright (c) 2020-2024, NVIDIA CORPORATION & AFFILIATES. All rights 
reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010006
+  BASE_NAME                      = IpmiBlobTransferDxeUnitTestsHost
+  FILE_GUID                      = 1f5d4095-ea52-432c-b078-86097fef6004
+  MODULE_TYPE                    = HOST_APPLICATION
+  VERSION_STRING                 = 1.0
+
+#
+# The following information is for reference only
+# and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = X64
+#
+
+[Sources]
+  IpmiBlobTransferTestUnitTests.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  ManageabilityPkg/ManageabilityPkg.dec
+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  UnitTestLib
+  IpmiLib
+
+[Protocols]
+  gEdkiiIpmiBlobTransferProtocolGuid
diff --git a/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h 
b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
new file mode 100644
index 0000000000..14b5294314
--- /dev/null
+++ b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
@@ -0,0 +1,253 @@
+/** @file
+
+  IPMI Blob Transfer driver
+
+  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights 
reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @Par: https://github.com/openbmc/phosphor-ipmi-blobs/blob/master/README.md
+**/

Lack of header guard
#ifndef IPMI_BLOB_TRANSFER_H_

+#include <Library/IpmiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <IndustryStandard/Ipmi.h>
+#include <IndustryStandard/IpmiNetFnOem.h>
+
+#define IPMI_OEM_BLOB_TRANSFER_CMD  0x80
+
+#define BLOB_TRANSFER_STAT_OPEN_R        BIT0
+#define BLOB_TRANSFER_STAT_OPEN_W        BIT1
+#define BLOB_TRANSFER_STAT_COMMITING     BIT2
+#define BLOB_TRANSFER_STAT_COMMITTED     BIT3
+#define BLOB_TRANSFER_STAT_COMMIT_ERROR  BIT4
+// Bits 5-7 are reserved
+// Bits 8-15 are blob-specific definitions
+
+//
+// OpenBMC OEN code in little endian format
+//
+const UINT8  OpenBmcOen[] = { 0xCF, 0xC2, 0x00 };

const -> CONST

Should we add a PCD for the OEN to be configured by platform specific BMC? Or this protocol is only to support OpenBMC.

+
+//
+//  Blob Transfer Function Prototypes
+//
+
+/**
+  This function retrieves the count of blob transfers available through the 
IPMI.
+
+  @param[out]        Count       The number of active blobs
+
+  @retval EFI_SUCCESS            Successfully retrieved the number of active 
blobs.
+  @retval Other                  An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)(
+  OUT UINT32 *Count
+  );
+
+/**
+  This function enumerates blob transfers available through the IPMI.
+
+  @param[in]         BlobIndex       The 0-based Index of the blob to enumerate
+  @param[out]        BlobId          The ID of the blob
+
+  @retval EFI_SUCCESS                Successfully enumerated the blob.
+  @retval Other                      An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)(
+  IN  UINT32  BlobIndex,
+  OUT CHAR8   *BlobId
+  );
+
+/**
+  This function is designed to open a session for a specific blob
+  identified by its ID, using the IPMI.
+
+  @param[in]         BlobId          The ID of the blob to open
+  @param[in]         Flags           Flags to control how the blob is opened
+  @param[out]        SessionId       A unique session identifier
+
+  @retval EFI_SUCCESS                Successfully opened the blob.
+  @retval Other                      An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)(
+  IN  CHAR8  *BlobId,
+  IN  UINT16 Flags,
+  OUT UINT16 *SessionId
+  );
+
+/**
+  This function reads data from a blob over the IPMI.
+
+  @param[in]         SessionId       The session ID returned from a call to 
BlobOpen
+  @param[in]         Offset          The offset of the blob from which to 
start reading
+  @param[in]         RequestedSize   The length of data to read
+  @param[out]        Data            Data read from the blob
+
+  @retval EFI_SUCCESS                Successfully read from the blob.
+  @retval Other                      An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_READ)(
+  IN  UINT16      SessionId,
+  IN  UINT32      Offset,
+  IN  UINT32      RequestedSize,
+  OUT UINT8       *Data
+  );
+
+/**
+  This function writes data to a blob over the IPMI.
+
+  @param[in]         SessionId       The session ID returned from a call to 
BlobOpen
+  @param[in]         Offset          The offset of the blob from which to 
start writing
+  @param[in]         Data            A pointer to the data to write
+  @param[in]         WriteLength     The length to write
+
+  @retval EFI_SUCCESS                Successfully wrote to the blob.
+  @retval Other                      An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE)(
+  IN  UINT16      SessionId,
+  IN  UINT32      Offset,
+  IN  UINT8       *Data,
+  IN  UINT32      WriteLength
+  );
+
+/**
+  This function commits data to a blob over the IPMI.
+
+  @param[in]         SessionId        The session ID returned from a call to 
BlobOpen
+  @param[in]         CommitDataLength The length of data to commit to the blob
+  @param[in]         CommitData       A pointer to the data to commit
+
+  @retval EFI_SUCCESS                Successful commit to the blob.
+  @retval Other                      An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)(
+  IN  UINT16      SessionId,
+  IN  UINT8       CommitDataLength,
+  IN  UINT8       *CommitData
+  );
+
+/**
+  This function close a session associated with a blob transfer over the IPMI.
+
+  @param[in]         SessionId       The session ID returned from a call to 
BlobOpen
+
+  @retval EFI_SUCCESS                The blob was closed.
+  @retval Other                      An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)(
+  IN  UINT16      SessionId
+  );
+
+/**
+  This function deletes a specific blob identified by its ID over the IPMI.
+
+  @param[in]         BlobId          The BlobId to be deleted
+
+  @retval EFI_SUCCESS                The blob was deleted.
+  @retval Other                      An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)(
+  IN  CHAR8 *BlobId
+  );
+
+/**
+  This function retrieve the status of a specific blob identified by BlobId 
from an IPMI.
+
+  @param[in]         BlobId          The Blob ID to gather statistics for
+  @param[out]        BlobState       The current state of the blob
+  @param[out]        Size            Size in bytes of the blob
+  @param[out]        MetadataLength  Length of the optional metadata
+  @param[out]        Metadata        Optional blob-specific metadata
+
+  @retval EFI_SUCCESS                The blob statistics were successfully 
gathered.
+  @retval Other                      An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_STAT)(
+  IN  CHAR8  *BlobId,
+  OUT UINT16 *BlobState,
+  OUT UINT32 *Size,
+  OUT UINT8  *MetadataLength,
+  OUT UINT8  *Metadata
+  );
+
+/**
+  This function query the status of a blob transfer session in an IPMI.
+
+  @param[in]         SessionId       The ID of the session to gather 
statistics for
+  @param[out]        BlobState       The current state of the blob
+  @param[out]        Size            Size in bytes of the blob
+  @param[out]        MetadataLength  Length of the optional metadata
+  @param[out]        Metadata        Optional blob-specific metadata
+
+  @retval EFI_SUCCESS                The blob statistics were successfully 
gathered.
+  @retval Other                      An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT)(
+  IN  UINT16 SessionId,
+  OUT UINT16 *BlobState,
+  OUT UINT32 *Size,
+  OUT UINT8  *MetadataLength,
+  OUT UINT8  *Metadata
+  );
+
+/**
+  This function writes metadata to a blob associated with a session in an IPMI.
+
+  @param[in]         SessionId       The ID of the session to write metadata 
for
+  @param[in]         Offset          The offset of the metadata to write to
+  @param[in]         Data            The data to write to the metadata
+  @param[in]         WriteLength     The length to write
+
+  @retval EFI_SUCCESS                The blob metadata was successfully 
written.
+  @retval Other                      An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)(
+  IN  UINT16      SessionId,
+  IN  UINT32      Offset,
+  IN  UINT8       *Data,
+  IN  UINT32      WriteLength
+  );
+
+//
+// Structure of EDKII_IPMI_BLOB_TRANSFER_PROTOCOL
+//
+struct _EDKII_IPMI_BLOB_TRANSFER_PROTOCOL {
+  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT       BlobGetCount;
+  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE       BlobEnumerate;
+  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_OPEN            BlobOpen;
+  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_READ            BlobRead;
+  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE           BlobWrite;
+  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT          BlobCommit;
+  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE           BlobClose;
+  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_DELETE          BlobDelete;
+  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_STAT            BlobStat;
+  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT    BlobSessionStat;
+  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META      BlobWriteMeta;
+};
+
+typedef struct _EDKII_IPMI_BLOB_TRANSFER_PROTOCOL 
EDKII_IPMI_BLOB_TRANSFER_PROTOCOL;
+
+extern EFI_GUID  gEdkiiIpmiBlobTransferProtocolGuid;
diff --git 
a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
 
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
new file mode 100644
index 0000000000..3e90dc6871
--- /dev/null
+++ 
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
@@ -0,0 +1,407 @@
+/** @file
+
+  Headers for IPMI Blob Transfer driver
+
+  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights 
reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+

Lack of header guard
#ifndef INTERNAL_IPMI_BLOB_TRANSFER_H_

+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IpmiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+
+#define PROTOCOL_RESPONSE_OVERHEAD  (4 * sizeof(UINT8))       // 1 byte 
completion code + 3 bytes OEN

Nit: Add a space after sizeof

+#define BLOB_MAX_DATA_PER_PACKET    64

Should it be moved to Include/Protocol/IpmiBlobTransfer.h? The caller could need to be aware the max length of the package.

+
+// Subcommands for this protocol
+typedef enum {
+  IpmiBlobTransferSubcommandGetCount = 0,
+  IpmiBlobTransferSubcommandEnumerate,
+  IpmiBlobTransferSubcommandOpen,
+  IpmiBlobTransferSubcommandRead,
+  IpmiBlobTransferSubcommandWrite,
+  IpmiBlobTransferSubcommandCommit,
+  IpmiBlobTransferSubcommandClose,
+  IpmiBlobTransferSubcommandDelete,
+  IpmiBlobTransferSubcommandStat,
+  IpmiBlobTransferSubcommandSessionStat,
+  IpmiBlobTransferSubcommandWriteMeta,
+} IPMI_BLOB_TRANSFER_SUBCOMMANDS;
+
+#pragma pack(1)
+
+typedef struct {
+  UINT8    OEN[3];
+  UINT8    SubCommand;
+} IPMI_BLOB_TRANSFER_HEADER;
+
+//
+// Command 0 - BmcBlobGetCount
+// The BmcBlobGetCount command expects to receive an empty body.
+// The BMC will return the number of enumerable blobs
+//
+typedef struct {
+  UINT32    BlobCount;
+} IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE;
+
+//
+// Command 1 - BmcBlobEnumerate
+// The BmcBlobEnumerate command expects to receive a body of:
+//
+typedef struct {
+  UINT32    BlobIndex; // 0-based index of blob to receive
+} IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA;
+
+typedef struct {
+  CHAR8    BlobId[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_RESPONSE;
+
+//
+// Command 2 - BmcBlobOpen
+// The BmcBlobOpen command expects to receive a body of:
+//
+typedef struct {
+  UINT16    Flags;
+  CHAR8     BlobId[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA;
+
+#define BLOB_OPEN_FLAG_READ   0
+#define BLOB_OPEN_FLAG_WRITE  1
+// Bits 2-7 are reserved
+// Bits 8-15 are blob-specific definitions
+
+typedef struct {
+  UINT16    SessionId;
+} IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE;
+
+//
+// Command 3 - BmcBlobRead
+// The BmcBlobRead command expects to receive a body of:
+//
+typedef struct {
+  UINT16    SessionId; // Returned from BlobOpen
+  UINT32    Offset;
+  UINT32    RequestedSize;
+} IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA;
+
+typedef struct {
+  UINT8    Data[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_READ_RESPONSE;
+
+//
+// Command 4 - BmcBlobWrite
+// The BmcBlobWrite command expects to receive a body of:
+//
+typedef struct {
+  UINT16    SessionId; // Returned from BlobOpen
+  UINT32    Offset;
+  UINT8     Data[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA;
+
+//
+// Command 5 - BmcBlobCommit
+// The BmcBlobCommit command expects to receive a body of:
+//
+typedef struct {
+  UINT16    SessionId; // Returned from BlobOpen
+  UINT8     CommitDataLength;
+  UINT8     CommitData[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA;
+
+//
+// Command 6 - BmcBlobClose
+// The BmcBlobClose command expects to receive a body of:
+//
+typedef struct {
+  UINT16    SessionId; // Returned from BlobOpen
+} IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA;
+
+//
+// Command 7 - BmcBlobDelete
+// NOTE: This command will fail if there are open sessions for this blob
+// The BmcBlobDelete command expects to receive a body of:
+//
+typedef struct {
+  CHAR8    BlobId[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA;
+
+//
+// Command 8 - BmcBlobStat
+// This command returns statistics about a blob.
+// This command expects to receive a body of:
+//
+typedef struct {
+  CHAR8    BlobId[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA;
+
+typedef struct {
+  UINT16    BlobState;
+  UINT32    Size; // Size in bytes of the blob
+  UINT8     MetaDataLen;
+  UINT8     MetaData[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE;
+
+//
+// Command 9 - BmcBlobSessionStat
+// Returns same data as BmcBlobState expect for a session, not a blob
+// This command expects to receive a body of:
+//
+typedef struct {
+  UINT16    SessionId;
+} IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA;
+
+typedef struct {
+  UINT16    BlobState;
+  UINT32    Size; // Size in bytes of the blob
+  UINT8     MetaDataLen;
+  UINT8     MetaData[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE;
+
+//
+// Command 10 - BmcBlobWriteMeta
+// The BmcBlobWriteMeta command expects to receive a body of:
+//
+typedef struct {
+  UINT16    SessionId;
+  UINT32    Offset;
+  UINT8     Data[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_WRITE_META_SEND_DATA;
+
+#define IPMI_BLOB_TRANSFER_BLOB_WRITE_META_RESPONSE  NULL
+
+#pragma pack()
+
+/**
+  Calculate CRC-16-CCITT with poly of 0x1021
+
+  @param[in]  Data              The target data.
+  @param[in]  DataSize          The target data size.
+
+  @return UINT16     The CRC16 value.
+
+**/
+UINT16
+CalculateCrc16Ccitt (
+  IN UINT8  *Data,
+  IN UINTN  DataSize
+  );
+
+/**
+  This function does blob transfer over IPMI command.
+
+  @param[in]  SubCommand        The specific sub-command to be executed as 
part of
+                                the blob transfer operation.
+  @param[in]  SendData          A pointer to the data buffer that contains the 
data to be sent.
+  @param[in]  SendDataSize      The size of the data to be sent, in bytes.
+  @param[out] ResponseData      A pointer to the buffer where the response 
data will be stored.
+  @param[out] ResponseDataSize  A pointer to a variable that will hold the 
size of the response
+                                data received.
+
+  @retval EFI_SUCCESS            Successfully sends blob data.
+  @retval EFI_OUT_OF_RESOURCES   Memory allocation fails.
+  @retval EFI_PROTOCOL_ERROR     Communication errors.
+  @retval EFI_CRC_ERROR          Data integrity checks fail.
+  @retval Other                  An error occurred
+
+**/
+EFI_STATUS
+IpmiBlobTransferSendIpmi (
+  IN  UINT8   SubCommand,
+  IN  UINT8   *SendData,
+  IN  UINT32  SendDataSize,
+  OUT UINT8   *ResponseData,
+  OUT UINT32  *ResponseDataSize
+  );
+
+/**
+  This function retrieves the count of blob transfers available through the 
IPMI.
+
+  @param[out]        Count       The number of active blobs
+
+  @retval EFI_SUCCESS            Successfully retrieved the number of active 
blobs.
+  @retval Other                  An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferGetCount (
+  OUT UINT32  *Count
+  );
+
+/**
+  This function enumerates blob transfers available through the IPMI.
+
+  @param[in]         BlobIndex       The 0-based Index of the blob to enumerate
+  @param[out]        BlobId          The ID of the blob
+
+  @retval EFI_SUCCESS                Successfully enumerated the blob.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferEnumerate (
+  IN  UINT32  BlobIndex,
+  OUT CHAR8   *BlobId
+  );
+
+/**
+  This function is designed to open a session for a specific blob
+  identified by its ID, using the IPMI.
+
+  @param[in]         BlobId          The ID of the blob to open
+  @param[in]         Flags           Flags to control how the blob is opened
+  @param[out]        SessionId       A unique session identifier
+
+  @retval EFI_SUCCESS                Successfully opened the blob.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferOpen (
+  IN  CHAR8   *BlobId,
+  IN  UINT16  Flags,
+  OUT UINT16  *SessionId
+  );
+
+/**
+  This function reads data from a blob over the IPMI.
+
+  @param[in]         SessionId       The session ID returned from a call to 
BlobOpen
+  @param[in]         Offset          The offset of the blob from which to 
start reading
+  @param[in]         RequestedSize   The length of data to read
+  @param[out]        Data            Data read from the blob
+
+  @retval EFI_SUCCESS                Successfully read from the blob.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferRead (
+  IN  UINT16  SessionId,
+  IN  UINT32  Offset,
+  IN  UINT32  RequestedSize,
+  OUT UINT8   *Data
+  );
+
+/**
+  This function writes data to a blob over the IPMI.
+
+  @param[in]         SessionId       The session ID returned from a call to 
BlobOpen
+  @param[in]         Offset          The offset of the blob from which to 
start writing
+  @param[in]         Data            A pointer to the data to write
+  @param[in]         WriteLength     The length to write
+
+  @retval EFI_SUCCESS                Successfully wrote to the blob.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferWrite (
+  IN  UINT16  SessionId,
+  IN  UINT32  Offset,
+  IN  UINT8   *Data,
+  IN  UINT32  WriteLength
+  );
+
+/**
+  This function commits data to a blob over the IPMI.
+
+  @param[in]         SessionId        The session ID returned from a call to 
BlobOpen
+  @param[in]         CommitDataLength The length of data to commit to the blob
+  @param[in]         CommitData       A pointer to the data to commit
+
+  @retval EFI_SUCCESS                Successful commit to the blob.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferCommit (
+  IN  UINT16  SessionId,
+  IN  UINT8   CommitDataLength,
+  IN  UINT8   *CommitData
+  );
+
+/**
+  This function close a session associated with a blob transfer over the IPMI.
+
+  @param[in]         SessionId       The session ID returned from a call to 
BlobOpen
+
+  @retval EFI_SUCCESS                The blob was closed.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferClose (
+  IN  UINT16  SessionId
+  );
+
+/**
+  This function deletes a specific blob identified by its ID over the IPMI.
+
+  @param[in]         BlobId          The BlobId to be deleted
+
+  @retval EFI_SUCCESS                The blob was deleted.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferDelete (
+  IN  CHAR8  *BlobId
+  );
+
+/**
+  This function retrieve the status of a specific blob identified by BlobId 
from an IPMI.
+
+  @param[in]         BlobId          The Blob ID to gather statistics for
+  @param[out]        BlobState       The current state of the blob
+  @param[out]        Size            Size in bytes of the blob
+  @param[out]        MetadataLength  Length of the optional metadata
+  @param[out]        Metadata        Optional blob-specific metadata
+
+  @retval EFI_SUCCESS                The blob statistics were successfully 
gathered.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferStat (
+  IN  CHAR8   *BlobId,
+  OUT UINT16  *BlobState,
+  OUT UINT32  *Size,
+  OUT UINT8   *MetadataLength,
+  OUT UINT8   *Metadata
+  );
+
+/**
+  This function query the status of a blob transfer session in an IPMI.
+
+  @param[in]         SessionId       The ID of the session to gather 
statistics for
+  @param[out]        BlobState       The current state of the blob
+  @param[out]        Size            Size in bytes of the blob
+  @param[out]        MetadataLength  Length of the optional metadata
+  @param[out]        Metadata        Optional blob-specific metadata
+
+  @retval EFI_SUCCESS                The blob statistics were successfully 
gathered.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferSessionStat (
+  IN  UINT16  SessionId,
+  OUT UINT16  *BlobState,
+  OUT UINT32  *Size,
+  OUT UINT8   *MetadataLength,
+  OUT UINT8   *Metadata
+  );
+
+/**
+  This function writes metadata to a blob associated with a session in an IPMI.
+
+  @param[in]         SessionId       The ID of the session to write metadata 
for
+  @param[in]         Offset          The offset of the metadata to write to
+  @param[in]         Data            The data to write to the metadata
+  @param[in]         WriteLength     The length to write
+
+  @retval EFI_SUCCESS                The blob metadata was successfully 
written.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferWriteMeta (
+  IN  UINT16  SessionId,
+  IN  UINT32  Offset,
+  IN  UINT8   *Data,
+  IN  UINT32  WriteLength
+  );
diff --git 
a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c 
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
new file mode 100644
index 0000000000..b8a2db193b
--- /dev/null
+++ 
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
@@ -0,0 +1,872 @@
+/** @file
+
+  IPMI Blob Transfer driver
+
+  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights 
reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Protocol/IpmiBlobTransfer.h>
+
+#include "InternalIpmiBlobTransfer.h"
+
+#define BLOB_TRANSFER_DEBUG  DEBUG_MANAGEABILITY
+
+STATIC CONST EDKII_IPMI_BLOB_TRANSFER_PROTOCOL  mIpmiBlobTransfer = {
+  (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)*IpmiBlobTransferGetCount,
+  (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnumerate,
+  (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)*IpmiBlobTransferOpen,
+  (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_READ)*IpmiBlobTransferRead,
+  (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE)*IpmiBlobTransferWrite,
+  (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)*IpmiBlobTransferCommit,
+  (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)*IpmiBlobTransferClose,
+  (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)*IpmiBlobTransferDelete,
+  (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_STAT)*IpmiBlobTransferStat,
+  (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT)*IpmiBlobTransferSessionStat,
+  (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWriteMeta
+};
+
+/**
+  Calculate CRC-16-CCITT with poly of 0x1021
+
+  @param[in]  Data              The target data.
+  @param[in]  DataSize          The target data size.
+
+  @return UINT16     The CRC16 value.
+
+**/
+UINT16
+CalculateCrc16Ccitt (
+  IN UINT8  *Data,
+  IN UINTN  DataSize
+  )
+{
+  UINTN    Index;
+  UINTN    BitIndex;
+  UINT16   Crc;
+  UINT16   Poly;
+  BOOLEAN  XorFlag;
+
+  Crc     = 0xFFFF;
+  Poly    = 0x1021;
+  XorFlag = FALSE;
+
+  for (Index = 0; Index < (DataSize + 2); ++Index) {
+    for (BitIndex = 0; BitIndex < 8; ++BitIndex) {
+      XorFlag = (Crc & 0x8000) ? TRUE : FALSE;
+      Crc   <<= 1;
+      if ((Index < DataSize) && (Data[Index] & (1 << (7 - BitIndex)))) {
+        Crc++;
+      }
+
+      if (XorFlag == TRUE) {
+        Crc ^= Poly;
+      }
+    }
+  }
+
+  DEBUG ((BLOB_TRANSFER_DEBUG, "%a: CRC-16-CCITT %x\n", __func__, Crc));
+
+  return Crc;
+}
+
+/**
+  This function does blob transfer over IPMI command.
+
+  @param[in]  SubCommand        The specific sub-command to be executed as 
part of
+                                the blob transfer operation.
+  @param[in]  SendData          A pointer to the data buffer that contains the 
data to be sent.
+  @param[in]  SendDataSize      The size of the data to be sent, in bytes.
+  @param[out] ResponseData      A pointer to the buffer where the response 
data will be stored.
+  @param[out] ResponseDataSize  A pointer to a variable that will hold the 
size of the response
+                                data received.
+
+  @retval EFI_SUCCESS            Successfully sends blob data.
+  @retval EFI_OUT_OF_RESOURCES   Memory allocation fails.
+  @retval EFI_PROTOCOL_ERROR     Communication errors.
+  @retval EFI_CRC_ERROR          Data integrity checks fail.
+  @retval Other                  An error occurred
+
+**/
+EFI_STATUS
+IpmiBlobTransferSendIpmi (
+  IN  UINT8   SubCommand,
+  IN  UINT8   *SendData,
+  IN  UINT32  SendDataSize,

Should describe SendData and SendDataSize as OPTIONAL

+  OUT UINT8   *ResponseData,
+  OUT UINT32  *ResponseDataSize
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      CompletionCode;
+  UINT16                     Crc;
+  UINT8                      Oen[3];
+  UINT8                      *IpmiSendData;
+  UINT32                     IpmiSendDataSize;
+  UINT8                      *IpmiResponseData;
+  UINT8                      *ModifiedResponseData;
+  UINT32                     IpmiResponseDataSize;
+  IPMI_BLOB_TRANSFER_HEADER  Header;
+

Should validate the pointer of input arguments: SendData, ResponseData, ResponseDataSize.

+  Crc = 0;
+
+  //
+  // Prepend the proper header to the SendData
+  //
+  IpmiSendDataSize = (sizeof (IPMI_BLOB_TRANSFER_HEADER));
+  if (SendDataSize) {
+    IpmiSendDataSize += sizeof (Crc) + (sizeof (UINT8) * SendDataSize);
+  }
+
+  IpmiSendData = AllocateZeroPool (IpmiSendDataSize);
+  if (IpmiSendData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Header.OEN[0]     = OpenBmcOen[0];
+  Header.OEN[1]     = OpenBmcOen[1];
+  Header.OEN[2]     = OpenBmcOen[2];
+  Header.SubCommand = SubCommand;
+  CopyMem (IpmiSendData, &Header, sizeof (IPMI_BLOB_TRANSFER_HEADER));
+  if (SendDataSize) {

if (SendDataSize != 0)

+    //
+    // Calculate the Crc of the send data
+    //
+    Crc = CalculateCrc16Ccitt (SendData, SendDataSize);
+    CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER), &Crc, sizeof 
(UINT16));
+    CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER) + sizeof 
(UINT16), SendData, SendDataSize);
+  }
+
+  DEBUG_CODE_BEGIN ();
+  DEBUG ((BLOB_TRANSFER_DEBUG, "%a: Inputs:\n", __func__));
+  DEBUG ((BLOB_TRANSFER_DEBUG, "%a: SendDataSize: %02x\nData: ", __func__, 
SendDataSize));
+  UINT8  i;
+
+  for (i = 0; i < SendDataSize; i++) {
+    DEBUG ((BLOB_TRANSFER_DEBUG, "%02x", *((UINT8 *)SendData + i)));
+  }
+
+  DEBUG ((BLOB_TRANSFER_DEBUG, "\n"));
+  DEBUG ((BLOB_TRANSFER_DEBUG, "%a: IpmiSendDataSize: %02x\nData: ", __func__, 
IpmiSendDataSize));
+  for (i = 0; i < IpmiSendDataSize; i++) {
+    DEBUG ((BLOB_TRANSFER_DEBUG, "%02x", *((UINT8 *)IpmiSendData + i)));
+  }
+
+  DEBUG ((BLOB_TRANSFER_DEBUG, "\n"));
+  DEBUG_CODE_END ();
+
+  IpmiResponseDataSize = (*ResponseDataSize + PROTOCOL_RESPONSE_OVERHEAD);
+  //
+  // If expecting data to be returned, we have to also account for the 16 bit 
CRC
+  //
+  if (*ResponseDataSize) {

if (*ResponseDataSize != 0)

+    IpmiResponseDataSize += sizeof (Crc);
+  }
+
+  IpmiResponseData = AllocateZeroPool (IpmiResponseDataSize);
+  if (IpmiResponseData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = IpmiSubmitCommand (
+             IPMI_NETFN_OEM,
+             IPMI_OEM_BLOB_TRANSFER_CMD,
+             (VOID *)IpmiSendData,
+             IpmiSendDataSize,
+             (VOID *)IpmiResponseData,
+             &IpmiResponseDataSize
+             );
+
+  FreePool (IpmiSendData);
+  ModifiedResponseData = IpmiResponseData;
+
+  DEBUG_CODE_BEGIN ();
+  DEBUG ((BLOB_TRANSFER_DEBUG, "%a: IPMI Response:\n", __func__));
+  DEBUG ((BLOB_TRANSFER_DEBUG, "%a: ResponseDataSize: %02x\nData: ", __func__, 
IpmiResponseDataSize));
+  UINT8  i;
+
+  for (i = 0; i < IpmiResponseDataSize; i++) {
+    DEBUG ((BLOB_TRANSFER_DEBUG, "%02x", *(ModifiedResponseData + i)));
+  }
+
+  DEBUG ((BLOB_TRANSFER_DEBUG, "\n"));
+  DEBUG_CODE_END ();
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CompletionCode = *ModifiedResponseData;
+  if (CompletionCode != IPMI_COMP_CODE_NORMAL) {
+    DEBUG ((DEBUG_ERROR, "%a: Returning because CompletionCode = 0x%x\n", 
__func__, CompletionCode));
+    FreePool (IpmiResponseData);
+    return EFI_PROTOCOL_ERROR;
+  }
+
+  // Strip completion code, we are done with it
+  ModifiedResponseData  = ModifiedResponseData + sizeof (CompletionCode);
+  IpmiResponseDataSize -= sizeof (CompletionCode);
+
+  // Check OEN code and verify it matches the OpenBMC OEN
+  CopyMem (Oen, ModifiedResponseData, sizeof (OpenBmcOen));
+  if (CompareMem (Oen, OpenBmcOen, sizeof (OpenBmcOen)) != 0) {
+    FreePool (IpmiResponseData);
+    return EFI_PROTOCOL_ERROR;
+  }
+
+  if (IpmiResponseDataSize == sizeof (OpenBmcOen)) {
+    //
+    // In this case, there was no response data sent. This is not an error.
+    // Some messages do not require a response.
+    //
+    *ResponseDataSize = 0;
+    FreePool (IpmiResponseData);
+    return Status;
+    // Now we need to validate the CRC then send the Response body back
+  } else {
+    // Strip the OEN, we are done with it now
+    ModifiedResponseData  = ModifiedResponseData + sizeof (Oen);
+    IpmiResponseDataSize -= sizeof (Oen);
+    // Then validate the Crc
+    CopyMem (&Crc, ModifiedResponseData, sizeof (Crc));
+    ModifiedResponseData  = ModifiedResponseData + sizeof (Crc);
+    IpmiResponseDataSize -= sizeof (Crc);
+
+    if (Crc == CalculateCrc16Ccitt (ModifiedResponseData, 
IpmiResponseDataSize)) {
+      CopyMem (ResponseData, ModifiedResponseData, IpmiResponseDataSize);
+      CopyMem (ResponseDataSize, &IpmiResponseDataSize, sizeof 
(IpmiResponseDataSize));
+      FreePool (IpmiResponseData);
+      return EFI_SUCCESS;
+    } else {
+      FreePool (IpmiResponseData);
+      return EFI_CRC_ERROR;
+    }
+  }
+}
+
+/**
+  This function retrieves the count of blob transfers available through the 
IPMI.
+
+  @param[out]        Count       The number of active blobs
+
+  @retval EFI_SUCCESS            Successfully retrieved the number of active 
blobs.
+  @retval Other                  An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferGetCount (
+  OUT UINT32  *Count
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *ResponseData;
+  UINT32      ResponseDataSize;
+
+  if (Count == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE);
+  ResponseData     = AllocateZeroPool (ResponseDataSize);
+  if (ResponseData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount, NULL, 0, 
(UINT8 *)ResponseData, &ResponseDataSize);
+  if (!EFI_ERROR (Status)) {
+    *Count = ((IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE 
*)ResponseData)->BlobCount;
+  }
+
+  FreePool (ResponseData);
+  return Status;
+}
+
+/**
+  This function enumerates blob transfers available through the IPMI.
+
+  @param[in]         BlobIndex       The 0-based Index of the blob to enumerate
+  @param[out]        BlobId          The ID of the blob
+
+  @retval EFI_SUCCESS                Successfully enumerated the blob.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferEnumerate (
+  IN  UINT32  BlobIndex,
+  OUT CHAR8   *BlobId
+  )
+{
+  EFI_STATUS  Status;
+
+  UINT8   *SendData;
+  UINT8   *ResponseData;
+  UINT32  SendDataSize;
+  UINT32  ResponseDataSize;
+
+  if (BlobId == NULL) {
+    ASSERT (FALSE);
+    return EFI_ABORTED;

Should return EFI_INVALID_PARAMETER for input validation?

+  }
+
+  ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_RESPONSE);
+  ResponseData     = AllocateZeroPool (ResponseDataSize);
+  if (ResponseData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Format send data
+  //
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA);
+  SendData     = AllocateZeroPool (SendDataSize);
+  if (SendData == NULL) {

FreePool (ResponseData);

+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ((IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA *)SendData)->BlobIndex = 
BlobIndex;
+
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandEnumerate, 
SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);
+  if (!EFI_ERROR (Status)) {
+    AsciiStrCpyS (BlobId, ResponseDataSize, (CHAR8 *)ResponseData);
+  }
+
+  FreePool (ResponseData);
+  return Status;
+}
+
+/**
+  This function is designed to open a session for a specific blob
+  identified by its ID, using the IPMI.
+
+  @param[in]         BlobId          The ID of the blob to open
+  @param[in]         Flags           Flags to control how the blob is opened

It would be good if we can list out all flag definitions here. Actually, I don't know how to input for this argument.

Are they BLOB_OPEN_FLAG_READ and BLOB_OPEN_FLAG_WRITE in the private include header?

+  @param[out]        SessionId       A unique session identifier
+
+  @retval EFI_SUCCESS                Successfully opened the blob.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferOpen (
+  IN  CHAR8   *BlobId,
+  IN  UINT16  Flags,
+  OUT UINT16  *SessionId
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *SendData;
+  UINT8       *ResponseData;
+  UINT32      SendDataSize;
+  UINT32      ResponseDataSize;
+  CHAR8       *BlobSearch;
+  UINT32      NumBlobs;
+  UINT16      Index;
+  BOOLEAN     BlobFound;
+
+  if ((BlobId == NULL) || (SessionId == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Before opening a blob, need to check if it exists

I'm thinking the caller sequence here. Typically, the caller might check the presence of a blob by calling GetCount () and Enumerate () before opening a blob session. This check here could waste time. Or, do we call open direction the blob session without pre-checking?

+  //
+  Status = IpmiBlobTransferGetCount (&NumBlobs);
+  if (EFI_ERROR (Status) || (NumBlobs == 0)) {
+    if (Status == EFI_UNSUPPORTED) {
+      return Status;
+    }
+
+    DEBUG ((DEBUG_ERROR, "%a: Could not find any blobs: %r\n", __func__, 
Status));
+    return EFI_NOT_FOUND;
+  }
+
+  BlobSearch = AllocateZeroPool (sizeof (CHAR8) * BLOB_MAX_DATA_PER_PACKET);
+  if (BlobSearch == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  BlobFound = FALSE;
+  for (Index = 0; Index < NumBlobs; Index++) {
+    Status = IpmiBlobTransferEnumerate (Index, BlobSearch);
+    if ((!EFI_ERROR (Status)) && (AsciiStrCmp (BlobSearch, BlobId) == 0)) {
+      BlobFound = TRUE;
+      break;
+    } else {
+      continue;
+    }
+  }
+
+  if (!BlobFound) {
+    DEBUG ((DEBUG_ERROR, "%a: Could not find a blob that matches %a\n", 
__func__, BlobId));
+    FreePool (BlobSearch);
+    return EFI_NOT_FOUND;
+  }
+
+  ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE);
+  ResponseData     = AllocateZeroPool (ResponseDataSize);
+  if (ResponseData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Format send data
+  //
+  SendDataSize = sizeof (((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA 
*)SendData)->Flags) + ((AsciiStrLen (BlobId)) * sizeof (CHAR8)) + sizeof 
(CHAR8);
+  SendData     = AllocateZeroPool (SendDataSize);
+  if (SendData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA *)SendData)->BlobId, 
AsciiStrSize (BlobId) / sizeof (CHAR8), BlobId);
+  ((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA *)SendData)->Flags = Flags;
+  // append null char to SendData
+  SendData[SendDataSize-1] = 0;

Nit: add spaces around minus (-) for readability.

+
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandOpen, SendData, 
SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);
+  if (!EFI_ERROR (Status)) {
+    *SessionId = ((IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE 
*)ResponseData)->SessionId;
+  }
+
+  FreePool (ResponseData);
+  FreePool (SendData);
+  FreePool (BlobSearch);
+  return Status;
+}
+
+/**
+  This function reads data from a blob over the IPMI.
+
+  @param[in]         SessionId       The session ID returned from a call to 
BlobOpen
+  @param[in]         Offset          The offset of the blob from which to 
start reading
+  @param[in]         RequestedSize   The length of data to read
+  @param[out]        Data            Data read from the blob
+
+  @retval EFI_SUCCESS                Successfully read from the blob.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferRead (
+  IN  UINT16  SessionId,

There might be developer mistake when executing the transfer before opening the session. How do we handle this failure path? Do we need to maintain a state machine for that?

This comment applies to other functions as well.

+  IN  UINT32  Offset,
+  IN  UINT32  RequestedSize,
+  OUT UINT8   *Data
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *SendData;
+  UINT8       *ResponseData;
+  UINT32      SendDataSize;
+  UINT32      ResponseDataSize;
+
+  if (Data == NULL) {
+    ASSERT (FALSE);
+    return EFI_ABORTED;

Should return EFI_INVALID_PARAMETER?

+  }
+
+  ResponseDataSize = RequestedSize * sizeof (UINT8);

Should check the RequestedSize against BLOB_MAX_DATA_PER_PACKET?

+  ResponseData     = AllocateZeroPool (ResponseDataSize);
+  if (ResponseData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Format send data
+  //
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA);
+  SendData     = AllocateZeroPool (SendDataSize);
+  if (SendData == NULL) {

FreePool (ResponseData);

+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)->SessionId     = 
SessionId;
+  ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)->Offset        = Offset;
+  ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)->RequestedSize = 
RequestedSize;
+
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandRead, SendData, 
SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);
+  if (!EFI_ERROR (Status)) {
+    CopyMem (Data, ((IPMI_BLOB_TRANSFER_BLOB_READ_RESPONSE 
*)ResponseData)->Data, ResponseDataSize * sizeof (UINT8));
+  }
+
+  FreePool (ResponseData);
+  FreePool (SendData);
+  return Status;
+}
+
+/**
+  This function writes data to a blob over the IPMI.
+
+  @param[in]         SessionId       The session ID returned from a call to 
BlobOpen
+  @param[in]         Offset          The offset of the blob from which to 
start writing
+  @param[in]         Data            A pointer to the data to write
+  @param[in]         WriteLength     The length to write
+
+  @retval EFI_SUCCESS                Successfully wrote to the blob.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferWrite (
+  IN  UINT16  SessionId,
+  IN  UINT32  Offset,
+  IN  UINT8   *Data,
+  IN  UINT32  WriteLength
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *SendData;
+  UINT32      SendDataSize;
+  UINT32      ResponseDataSize;
+
+  if (Data == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Format send data
+  //
+  SendDataSize = sizeof (SessionId) + sizeof (Offset) + WriteLength;

Should we check whether or not the WriteLength is equal to or less than BLOB_MAX_DATA_PER_PACKET?

+  SendData     = AllocateZeroPool (SendDataSize);
+  if (SendData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->SessionId = SessionId;
+  ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset    = Offset;
+  CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Data, Data, 
sizeof (UINT8) * WriteLength);
+
+  ResponseDataSize = 0;
+  Status           = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandWrite, 
SendData, SendDataSize, NULL, &ResponseDataSize);
+
+  FreePool (SendData);
+  return Status;
+}
+
+/**
+  This function commits data to a blob over the IPMI.
+
+  @param[in]         SessionId        The session ID returned from a call to 
BlobOpen
+  @param[in]         CommitDataLength The length of data to commit to the blob
+  @param[in]         CommitData       A pointer to the data to commit
+
+  @retval EFI_SUCCESS                Successful commit to the blob.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferCommit (
+  IN  UINT16  SessionId,
+  IN  UINT8   CommitDataLength,
+  IN  UINT8   *CommitData
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *SendData;
+  UINT32      SendDataSize;
+  UINT32      ResponseDataSize;
+
+  if (CommitData == NULL) {

According to the spec https://github.com/openbmc/phosphor-ipmi-blobs, the commit data is block-specific optional.

For instance, the commit data is optional for SMBIOS blob transfer. Look at https://github.com/openbmc/smbios-mdr

+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Format send data
+  //
+  SendDataSize = sizeof (SessionId) + sizeof (CommitDataLength) + 
CommitDataLength;
+  SendData     = AllocateZeroPool (SendDataSize);
+  if (SendData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)->SessionId        = 
SessionId;
+  ((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)->CommitDataLength = 
CommitDataLength;
+  CopyMem (((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)->CommitData, 
CommitData, sizeof (UINT8) * CommitDataLength);
+
+  ResponseDataSize = 0;
+
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandCommit, SendData, 
SendDataSize, NULL, &ResponseDataSize);
+
+  FreePool (SendData);
+  return Status;
+}
+
+/**
+  This function close a session associated with a blob transfer over the IPMI.
+
+  @param[in]         SessionId       The session ID returned from a call to 
BlobOpen
+
+  @retval EFI_SUCCESS                The blob was closed.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferClose (
+  IN  UINT16  SessionId
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *SendData;
+  UINT32      SendDataSize;
+  UINT32      ResponseDataSize;
+
+  //
+  // Format send data
+  //
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA);
+  SendData     = AllocateZeroPool (SendDataSize);
+  if (SendData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ((IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA *)SendData)->SessionId = SessionId;
+
+  ResponseDataSize = 0;
+
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandClose, SendData, 
SendDataSize, NULL, &ResponseDataSize);
+
+  FreePool (SendData);
+  return Status;
+}
+
+/**
+  This function deletes a specific blob identified by its ID over the IPMI.
+
+  @param[in]         BlobId          The BlobId to be deleted
+
+  @retval EFI_SUCCESS                The blob was deleted.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferDelete (
+  IN  CHAR8  *BlobId
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *SendData;
+  UINT32      SendDataSize;
+  UINT32      ResponseDataSize;
+
+  if (BlobId == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Format send data
+  //
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA);
+  SendData     = AllocateZeroPool (SendDataSize);
+  if (SendData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA 
*)SendData)->BlobId, AsciiStrLen (BlobId), BlobId);
+
+  ResponseDataSize = 0;
+
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandDelete, SendData, 
SendDataSize, NULL, &ResponseDataSize);
+
+  FreePool (SendData);
+  return Status;
+}
+
+/**
+  This function retrieve the status of a specific blob identified by BlobId 
from an IPMI.
+
+  @param[in]         BlobId          The Blob ID to gather statistics for
+  @param[out]        BlobState       The current state of the blob
+  @param[out]        Size            Size in bytes of the blob
+  @param[out]        MetadataLength  Length of the optional metadata
+  @param[out]        Metadata        Optional blob-specific metadata
+
+  @retval EFI_SUCCESS                The blob statistics were successfully 
gathered.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferStat (
+  IN  CHAR8   *BlobId,
+  OUT UINT16  *BlobState,
+  OUT UINT32  *Size,
+  OUT UINT8   *MetadataLength,
+  OUT UINT8   *Metadata
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *SendData;
+  UINT8       *ResponseData;
+  UINT32      SendDataSize;
+  UINT32      ResponseDataSize;
+
+  if ((BlobId == NULL) || (BlobState == NULL) || (Size == NULL) || 
(MetadataLength == NULL)) {

Could we make Metadata **per spec**, MetadataLength, and Size optional? We could not care them rather than BlobState.

This comment applies to IpmiBlobTransferSessionStat () as well.

+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Metadata == NULL) {
+    ASSERT (FALSE);
+    return EFI_ABORTED;
+  }
+
+  ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE);
+  ResponseData     = AllocateZeroPool (ResponseDataSize);
+  if (ResponseData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Format send data
+  //
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA);
+  SendData     = AllocateZeroPool (SendDataSize);
+  if (SendData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA *)SendData)->BlobId, 
BLOB_MAX_DATA_PER_PACKET, BlobId);
+
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandStat, SendData, 
SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);
+  if (!EFI_ERROR (Status)) {
+    *BlobState      = ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE 
*)ResponseData)->BlobState;
+    *Size           = ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE 
*)ResponseData)->Size;
+    *MetadataLength = ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE 
*)ResponseData)->MetaDataLen;
+
+    CopyMem (&Metadata, &((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE 
*)ResponseData)->MetaData, sizeof (((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE 
*)ResponseData)->MetaData));
+  }
+
+  FreePool (ResponseData);
+  FreePool (SendData);
+  return Status;
+}
+
+/**
+  This function query the status of a blob transfer session in an IPMI.
+
+  @param[in]         SessionId       The ID of the session to gather 
statistics for
+  @param[out]        BlobState       The current state of the blob
+  @param[out]        Size            Size in bytes of the blob
+  @param[out]        MetadataLength  Length of the optional metadata
+  @param[out]        Metadata        Optional blob-specific metadata
+
+  @retval EFI_SUCCESS                The blob statistics were successfully 
gathered.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferSessionStat (
+  IN  UINT16  SessionId,
+  OUT UINT16  *BlobState,
+  OUT UINT32  *Size,
+  OUT UINT8   *MetadataLength,
+  OUT UINT8   *Metadata
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *SendData;
+  UINT8       *ResponseData;
+  UINT32      SendDataSize;
+  UINT32      ResponseDataSize;
+
+  if ((BlobState == NULL) || (Size == NULL) || (MetadataLength == NULL) || 
(Metadata == NULL)) {
+    ASSERT (FALSE);
+    return EFI_ABORTED;
+  }
+
+  ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE);
+  ResponseData     = AllocateZeroPool (ResponseDataSize);
+  if (ResponseData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Format send data
+  //
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA);
+  SendData     = AllocateZeroPool (SendDataSize);
+  if (SendData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA *)SendData)->SessionId = 
SessionId;
+
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandSessionStat, 
SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);
+
+  if (!EFI_ERROR (Status)) {
+    *BlobState      = ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE 
*)ResponseData)->BlobState;
+    *Size           = ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE 
*)ResponseData)->Size;
+    *MetadataLength = ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE 
*)ResponseData)->MetaDataLen;
+
+    CopyMem (&Metadata, &((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE 
*)ResponseData)->MetaData, sizeof (((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE 
*)ResponseData)->MetaData));
+  }
+
+  FreePool (ResponseData);
+  FreePool (SendData);
+  return Status;
+}
+
+/**
+  This function writes metadata to a blob associated with a session in an IPMI.
+
+  @param[in]         SessionId       The ID of the session to write metadata 
for
+  @param[in]         Offset          The offset of the metadata to write to
+  @param[in]         Data            The data to write to the metadata
+  @param[in]         WriteLength     The length to write
+
+  @retval EFI_SUCCESS                The blob metadata was successfully 
written.
+  @retval Other                      An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferWriteMeta (
+  IN  UINT16  SessionId,
+  IN  UINT32  Offset,
+  IN  UINT8   *Data,

How do callers know the data format of metadata for writing correctly?

+  IN  UINT32  WriteLength

Should check with BLOB_MAX_DATA_PER_PACKET

+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *SendData;
+  UINT32      SendDataSize;
+  UINT32      ResponseDataSize;
+
+  if (Data == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Format send data
+  //
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA);
+  SendData     = AllocateZeroPool (SendDataSize);
+  if (SendData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->SessionId = SessionId;
+  ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset    = Offset;
+  CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Data, Data, 
sizeof (UINT8) * WriteLength);
+
+  ResponseDataSize = 0;
+
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandWriteMeta, 
SendData, SendDataSize, NULL, &ResponseDataSize);
+
+  FreePool (SendData);
+  return Status;
+}
+
+/**
+  This is the declaration of an EFI image entry point. This entry point is
+  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
+  both device drivers and bus drivers.
+
+  @param[in]  ImageHandle       The firmware allocated handle for the UEFI 
image.
+  @param[in]  SystemTable       A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval Others                An unexpected error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+IpmiBlobTransferDxeDriverEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  return gBS->InstallMultipleProtocolInterfaces (
+                &ImageHandle,

Nit: Typically, we could also use gImageHandle instead.

+                &gEdkiiIpmiBlobTransferProtocolGuid,
+                (VOID *)&mIpmiBlobTransfer,
+                NULL
+                );
+}
diff --git 
a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
 
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
new file mode 100644
index 0000000000..0f728527b8
--- /dev/null
+++ 
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
@@ -0,0 +1,1113 @@
+/** @file
+*
+*  Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
+*
+*  SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & 
AFFILIATES
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdint.h>
+#include <cmocka.h>
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HostBasedTestStubLib/IpmiStubLib.h>
+
+#include <Library/UnitTestLib.h>
+#include <Protocol/IpmiBlobTransfer.h>
+#include "../InternalIpmiBlobTransfer.h"
+
+#define UNIT_TEST_NAME     "IPMI Blob Transfer Unit Tests"
+#define UNIT_TEST_VERSION  "1.0"
+
+UINT8  InvalidCompletion[] = {
+  0xC0,             // CompletionCode
+  0xCF, 0xC2, 0x00, // OpenBMC OEN
+};
+#define INVALID_COMPLETION_SIZE  4 * sizeof(UINT8)
+
+UINT8  NoDataResponse[] = {
+  0x00,             // CompletionCode
+  0xCF, 0xC2, 0x00, // OpenBMC OEN
+};
+#define NO_DATA_RESPONSE_SIZE  4 * sizeof(UINT8)
+
+UINT8  BadOenResponse[] = {
+  0x00,             // CompletionCode
+  0xFF, 0xC2, 0x00, // Wrong OEN
+};
+#define BAD_OEN_RESPONSE_SIZE  4 * sizeof(UINT8)
+
+UINT8  BadCrcResponse[] = {
+  0x00,                   // CompletionCode
+  0xCF, 0xC2, 0x00,       // OpenBMC OEN
+  0x00, 0x00,             // CRC
+  0x01, 0x00, 0x00, 0x00, // Data
+};
+#define BAD_CRC_RESPONSE_SIZE  10 * sizeof(UINT8)
+
+UINT8  ValidNoDataResponse[] = {
+  0x00,             // CompletionCode
+  0xCF, 0xC2, 0x00, // OpenBMC OEN
+};
+
+#define VALID_NODATA_RESPONSE_SIZE  4 * sizeof(UINT8)
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+GoodCrc (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  UINT8   Data[5] = { 0x12, 0x34, 0x56, 0x78, 0x90 };
+  UINTN   DataSize;
+  UINT16  Crc;
+
+  DataSize = sizeof (Data);
+
+  Crc = CalculateCrc16Ccitt (Data, DataSize);
+
+  UT_ASSERT_EQUAL (Crc, 0xB928);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+BadCrc (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  UINT8   Data[5] = { 0x12, 0x34, 0x56, 0x78, 0x90 };
+  UINTN   DataSize;
+  UINT16  Crc;
+
+  DataSize = sizeof (Data);
+
+  Crc = CalculateCrc16Ccitt (Data, DataSize);
+
+  UT_ASSERT_NOT_EQUAL (Crc, 0x3409);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SendIpmiBadCompletion (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  VOID        *ResponseData;
+  UINT32      *ResponseDataSize;
+  EFI_STATUS  Status;
+  VOID        *MockResponseResults = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (INVALID_COMPLETION_SIZE);
+  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
+  CopyMem (MockResponseResults, &InvalidCompletion, INVALID_COMPLETION_SIZE);
+
+  MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
INVALID_COMPLETION_SIZE, EFI_SUCCESS);
+
+  ResponseData = (UINT8 *)AllocateZeroPool (*ResponseDataSize);
+  Status       = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount, 
NULL, 0, ResponseData, ResponseDataSize);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_PROTOCOL_ERROR);
+  FreePool (MockResponseResults);
+  FreePool (ResponseDataSize);
+  FreePool (ResponseData);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SendIpmiNoDataResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  VOID        *ResponseData;
+  UINT32      *ResponseDataSize;
+  EFI_STATUS  Status;
+  VOID        *MockResponseResults = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (NO_DATA_RESPONSE_SIZE);
+  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
+  CopyMem (MockResponseResults, &NoDataResponse, NO_DATA_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
NO_DATA_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  ResponseData = (UINT8 *)AllocateZeroPool (sizeof (NoDataResponse));
+  Status       = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount, 
NULL, 0, ResponseData, ResponseDataSize);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+  UT_ASSERT_EQUAL (*ResponseDataSize, 0);
+  FreePool (MockResponseResults);
+  FreePool (ResponseDataSize);
+  FreePool (ResponseData);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SendIpmiBadOenResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  VOID        *ResponseData;
+  UINT32      *ResponseDataSize;
+  EFI_STATUS  Status;
+  VOID        *MockResponseResults = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (BAD_OEN_RESPONSE_SIZE);
+  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
+  CopyMem (MockResponseResults, &BadOenResponse, BAD_OEN_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
BAD_OEN_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  ResponseData = (UINT8 *)AllocateZeroPool (sizeof (BadOenResponse));
+  Status       = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount, 
NULL, 0, ResponseData, ResponseDataSize);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_PROTOCOL_ERROR);
+  FreePool (MockResponseResults);
+  FreePool (ResponseDataSize);
+  FreePool (ResponseData);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SendIpmiBadCrcResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  VOID        *ResponseData;
+  UINT32      *ResponseDataSize;
+  EFI_STATUS  Status;
+  VOID        *MockResponseResults = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(BAD_CRC_RESPONSE_SIZE));
+  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
+  CopyMem (MockResponseResults, &BadCrcResponse, BAD_CRC_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
BAD_CRC_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  ResponseData = (UINT8 *)AllocateZeroPool (sizeof (BadCrcResponse));
+  Status       = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount, 
NULL, 0, ResponseData, ResponseDataSize);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_CRC_ERROR);
+  FreePool (MockResponseResults);
+  FreePool (ResponseDataSize);
+  FreePool (ResponseData);
+  return UNIT_TEST_PASSED;
+}
+
+UINT8  ValidGetCountResponse[] = {
+  0x00,                   // CompletionCode
+  0xCF, 0xC2, 0x00,       // OpenBMC OEN
+  0xA4, 0x78,             // CRC
+  0x01, 0x00, 0x00, 0x00, // Data
+};
+#define VALID_GET_COUNT_RESPONSE_SIZE  10 * sizeof(UINT8)
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SendIpmiValidCountResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  UINT8       *ResponseData;
+  UINT32      *ResponseDataSize;
+  EFI_STATUS  Status;
+  VOID        *MockResponseResults = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_GET_COUNT_RESPONSE_SIZE));
+  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
+  CopyMem (MockResponseResults, &ValidGetCountResponse, 
VALID_GET_COUNT_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  ResponseData = AllocateZeroPool (sizeof (ValidGetCountResponse));
+  Status       = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount, 
NULL, 0, ResponseData, ResponseDataSize);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+  FreePool (MockResponseResults);
+  FreePool (ResponseDataSize);
+  FreePool (ResponseData);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+GetCountValidCountResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      Count;
+  VOID        *MockResponseResults = NULL;
+
+  Count = 0;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_GET_COUNT_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidGetCountResponse, 
VALID_GET_COUNT_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  Status = IpmiBlobTransferGetCount (&Count);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+  UT_ASSERT_EQUAL (Count, 1);
+  FreePool (MockResponseResults);
+  return UNIT_TEST_PASSED;
+}
+
+UINT8  ValidEnumerateResponse[] = {
+  0x00,                   // CompletionCode
+  0xCF, 0xC2, 0x00,       // OpenBMC OEN
+  0x81, 0x13,             // CRC
+  0x2F, 0x73, 0x6D, 0x62, // Data = "/smbios"
+  0x69, 0x6F, 0x73, 0x00,
+};
+#define VALID_ENUMERATE_RESPONSE_SIZE  14 * sizeof(UINT8)
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+EnumerateValidResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS  Status;
+  CHAR8       *BlobId;
+  VOID        *MockResponseResults = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_ENUMERATE_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidEnumerateResponse, 
VALID_ENUMERATE_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  BlobId = AllocateZeroPool (sizeof (CHAR8) * BLOB_MAX_DATA_PER_PACKET);
+
+  Status = IpmiBlobTransferEnumerate (0, BlobId);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+  UT_ASSERT_MEM_EQUAL (BlobId, "/smbios", 7);
+  FreePool (MockResponseResults);
+  FreePool (BlobId);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+EnumerateInvalidBuffer (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  CHAR8       *BlobId;
+  EFI_STATUS  Status;
+  VOID        *MockResponseResults = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_ENUMERATE_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidEnumerateResponse, 
VALID_ENUMERATE_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  BlobId = NULL;
+
+  UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferEnumerate (0, BlobId), NULL);
+
+  FreePool (MockResponseResults);
+  return UNIT_TEST_PASSED;
+}
+
+UINT8  ValidOpenResponse[] = {
+  0x00,             // CompletionCode
+  0xCF, 0xC2, 0x00, // OpenBMC OEN
+  0x93, 0xD1,       // CRC
+  0x03, 0x00,       // SessionId = 3
+};
+#define VALID_OPEN_RESPONSE_SIZE  8 * sizeof(UINT8)
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+OpenValidResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS  Status;
+  CHAR8       *BlobId;
+  UINT16      Flags;
+  UINT16      SessionId;
+  VOID        *MockResponseResults  = NULL;
+  VOID        *MockResponseResults2 = NULL;
+  VOID        *MockResponseResults3 = NULL;
+
+  Flags = BLOB_TRANSFER_STAT_OPEN_W;
+
+  //
+  // An open call effectively leads to three IPMI commands
+  // 1. GetCount of blobs
+  // 2. Enumerate the requested blob
+  // 3. Open the requested blob
+  //
+  // So we'll push three Ipmi responses in this case
+  //
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_OPEN_RESPONSE_SIZE));
+
+  CopyMem (MockResponseResults, &ValidOpenResponse, VALID_OPEN_RESPONSE_SIZE);
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_OPEN_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  MockResponseResults2 = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_ENUMERATE_RESPONSE_SIZE));
+  CopyMem (MockResponseResults2, &ValidEnumerateResponse, 
VALID_ENUMERATE_RESPONSE_SIZE);
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults2, 
VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  MockResponseResults3 = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_GET_COUNT_RESPONSE_SIZE));
+  CopyMem (MockResponseResults3, &ValidGetCountResponse, 
VALID_GET_COUNT_RESPONSE_SIZE);
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults3, 
VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  BlobId = "/smbios";
+
+  Status = IpmiBlobTransferOpen (BlobId, Flags, &SessionId);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+  UT_ASSERT_EQUAL (SessionId, 3);
+  FreePool (MockResponseResults);
+  return UNIT_TEST_PASSED;
+}
+
+UINT8  ValidReadResponse[] = {
+  0x00,                   // CompletionCode
+  0xCF, 0xC2, 0x00,       // OpenBMC OEN
+  0x21, 0x6F,             // CRC
+  0x00, 0x01, 0x02, 0x03, // Data to read
+};
+
+#define VALID_READ_RESPONSE_SIZE  10 * sizeof(UINT8)
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+ReadValidResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *ResponseData;
+  UINT8       ExpectedDataResponse[4] = { 0x00, 0x01, 0x02, 0x03 };
+  VOID        *MockResponseResults    = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_READ_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidReadResponse, VALID_READ_RESPONSE_SIZE);
+  ResponseData = AllocateZeroPool (sizeof (ValidReadResponse));
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_READ_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  Status = IpmiBlobTransferRead (0, 0, 4, ResponseData);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+  UT_ASSERT_MEM_EQUAL (ResponseData, ExpectedDataResponse, 4);
+  FreePool (MockResponseResults);
+  FreePool (ResponseData);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+ReadInvalidBuffer (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  UINT8       *ResponseData;
+  EFI_STATUS  Status;
+  VOID        *MockResponseResults = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_READ_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidReadResponse, VALID_READ_RESPONSE_SIZE);
+  ResponseData = NULL;
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_READ_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferRead (0, 0, 4, ResponseData), 
NULL);
+
+  FreePool (MockResponseResults);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+WriteValidResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       SendData[4]          = { 0x00, 0x01, 0x02, 0x03 };
+  VOID        *MockResponseResults = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_NODATA_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidNoDataResponse, 
VALID_NODATA_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  Status = IpmiBlobTransferWrite (0, 0, SendData, 4);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+  FreePool (MockResponseResults);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+CommitValidResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       SendData[4]          = { 0x00, 0x01, 0x02, 0x03 };
+  VOID        *MockResponseResults = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_NODATA_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidNoDataResponse, 
VALID_NODATA_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  Status = IpmiBlobTransferCommit (0, 4, SendData);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+  FreePool (MockResponseResults);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+CloseValidResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *MockResponseResults = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_NODATA_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidNoDataResponse, 
VALID_NODATA_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  Status = IpmiBlobTransferClose (1);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+  FreePool (MockResponseResults);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+DeleteValidResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *MockResponseResults = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_NODATA_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidNoDataResponse, 
VALID_NODATA_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  Status = IpmiBlobTransferDelete ("/smbios");
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+  FreePool (MockResponseResults);
+  return UNIT_TEST_PASSED;
+}
+
+UINT8  ValidBlobStatResponse[] = {
+  0x00,                   // CompletionCode
+  0xCF, 0xC2, 0x00,       // OpenBMC OEN
+  0x1F, 0x4F,             // Crc
+  0x01, 0x00,             // BlobState
+  0x02, 0x03, 0x04, 0x05, // BlobSize
+  0x04,                   // MetaDataLen
+  0x06, 0x07, 0x08, 0x09, // MetaData
+};
+
+#define VALID_BLOB_STAT_RESPONSE_SIZE  17 * sizeof(UINT8)
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+BlobStatValidResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS  Status;
+  UINT16      *BlobState;
+  UINT32      *Size;
+  UINT8       *MetadataLength;
+  UINT8       *Metadata;
+  UINT8       *ExpectedMetadata;
+  CHAR8       *BlobId;
+  VOID        *MockResponseResults = NULL;
+
+  BlobState        = AllocateZeroPool (sizeof (UINT16));
+  Size             = AllocateZeroPool (sizeof (UINT32));
+  BlobId           = "BlobId";
+  MetadataLength   = AllocateZeroPool (sizeof (UINT8));
+  Metadata         = AllocateZeroPool (4 * sizeof (UINT8));
+  ExpectedMetadata = AllocateZeroPool (4 * sizeof (UINT8));
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_BLOB_STAT_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidBlobStatResponse, 
VALID_BLOB_STAT_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  Status = IpmiBlobTransferStat (BlobId, BlobState, Size, MetadataLength, 
Metadata);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+  UT_ASSERT_EQUAL (*BlobState, 1);
+  UT_ASSERT_EQUAL (*Size, 0x05040302);
+  UT_ASSERT_EQUAL (*MetadataLength, 4);
+  UT_ASSERT_MEM_EQUAL (Metadata, ExpectedMetadata, 4);
+  FreePool (MockResponseResults);
+  FreePool (BlobState);
+  FreePool (Size);
+  FreePool (MetadataLength);
+  FreePool (Metadata);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+BlobStatInvalidBuffer (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  UINT8       *Metadata;
+  EFI_STATUS  Status;
+  VOID        *MockResponseResults = NULL;
+
+  Metadata = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_BLOB_STAT_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidBlobStatResponse, 
VALID_BLOB_STAT_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferStat (NULL, 0, 0, 0, Metadata), 
NULL);
+
+  FreePool (MockResponseResults);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SessionStatValidResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS  Status;
+  UINT16      *BlobState;
+  UINT32      *Size;
+  UINT8       *MetadataLength;
+  UINT8       *Metadata;
+  UINT8       *ExpectedMetadata;
+  VOID        *MockResponseResults = NULL;
+
+  BlobState        = AllocateZeroPool (sizeof (UINT16));
+  Size             = AllocateZeroPool (sizeof (UINT32));
+  MetadataLength   = AllocateZeroPool (sizeof (UINT8));
+  Metadata         = AllocateZeroPool (4 * sizeof (UINT8));
+  ExpectedMetadata = AllocateZeroPool (4 * sizeof (UINT8));
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_BLOB_STAT_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidBlobStatResponse, 
VALID_BLOB_STAT_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  Status = IpmiBlobTransferSessionStat (0, BlobState, Size, MetadataLength, 
Metadata);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+  UT_ASSERT_EQUAL (*BlobState, 1);
+  UT_ASSERT_EQUAL (*Size, 0x05040302);
+  UT_ASSERT_EQUAL (*MetadataLength, 4);
+  UT_ASSERT_MEM_EQUAL (Metadata, ExpectedMetadata, 4);
+  FreePool (MockResponseResults);
+  FreePool (BlobState);
+  FreePool (Size);
+  FreePool (MetadataLength);
+  FreePool (Metadata);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SessionStatInvalidBuffer (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  UINT8       *Metadata;
+  EFI_STATUS  Status;
+  VOID        *MockResponseResults = NULL;
+
+  Metadata = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_BLOB_STAT_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidBlobStatResponse, 
VALID_BLOB_STAT_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferSessionStat (0, 0, 0, 0, 
Metadata), NULL);
+
+  FreePool (MockResponseResults);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  @param[in]  Context    [Optional] An optional parameter that enables:
+                         1) test-case reuse with varied parameters and
+                         2) test-case re-entry for Target tests that need a
+                         reboot.  This parameter is a VOID* and it is the
+                         responsibility of the test author to ensure that the
+                         contents are well understood by all test cases that 
may
+                         consume it.
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the 
test
+                                        case was successful.
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+WriteMetaValidResponse (
+  IN UNIT_TEST_CONTEXT  Context
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *MockResponseResults = NULL;
+
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof 
(VALID_NODATA_RESPONSE_SIZE));
+  CopyMem (MockResponseResults, &ValidNoDataResponse, 
VALID_NODATA_RESPONSE_SIZE);
+
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, 
VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
+  if (EFI_ERROR (Status)) {
+    return UNIT_TEST_ERROR_TEST_FAILED;
+  }
+
+  Status = IpmiBlobTransferWriteMeta (0, 0, NULL, 0);
+
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+  FreePool (MockResponseResults);
+  return UNIT_TEST_PASSED;
+}
+
+/**
+  Initialize the unit test framework, suite, and unit tests for the
+  sample unit tests and run the unit tests.
+  @retval  EFI_SUCCESS           All test cases were dispatched.
+  @retval  EFI_OUT_OF_RESOURCES  There are not enough resources available to
+                                 initialize the unit tests.
+**/
+EFI_STATUS
+EFIAPI
+SetupAndRunUnitTests (
+  VOID
+  )
+{
+  EFI_STATUS                  Status;
+  UNIT_TEST_FRAMEWORK_HANDLE  Framework;
+  UNIT_TEST_SUITE_HANDLE      IpmiBlobTransfer;
+
+  Framework = NULL;
+  DEBUG ((DEBUG_INFO, "%a: v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION));
+
+  Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, 
gEfiCallerBaseName, UNIT_TEST_VERSION);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to setup Test Framework. Exiting with status = 
%r\n", Status));
+    ASSERT (FALSE);
+    return Status;
+  }
+
+  //
+  // Populate the Unit Test Suite.
+  //
+  Status = CreateUnitTestSuite (&IpmiBlobTransfer, Framework, "IPMI Blob Transfer 
Tests", "UnitTest.IpmiBlobTransferCB", NULL, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for IPMI Blob Transfer 
Tests\n"));
+    Status = EFI_OUT_OF_RESOURCES;
+    return Status;
+  }
+
+  // CalculateCrc16Ccitt
+  Status = AddTestCase (IpmiBlobTransfer, "Test CRC Calculation", "GoodCrc", 
GoodCrc, NULL, NULL, NULL);
+  Status = AddTestCase (IpmiBlobTransfer, "Test Bad CRC Calculation", 
"BadCrc", BadCrc, NULL, NULL, NULL);
+  // IpmiBlobTransferSendIpmi
+  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns bad completion", 
"SendIpmiBadCompletion", SendIpmiBadCompletion, NULL, NULL, NULL);
+  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfully with no data", 
"SendIpmiNoDataResponse", SendIpmiNoDataResponse, NULL, NULL, NULL);
+  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfully with bad OEN", 
"SendIpmiBadOenResponse", SendIpmiBadOenResponse, NULL, NULL, NULL);
+  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfully with bad CRC", 
"SendIpmiBadCrcResponse", SendIpmiBadCrcResponse, NULL, NULL, NULL);
+  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns with valid GetCount data", 
"SendIpmiValidCountResponse", SendIpmiValidCountResponse, NULL, NULL, NULL);
+  // IpmiBlobTransferGetCount
+  Status = AddTestCase (IpmiBlobTransfer, "GetCount call with valid data", 
"GetCountValidCountResponse", GetCountValidCountResponse, NULL, NULL, NULL);
+  // IpmiBlobTransferEnumerate
+  Status = AddTestCase (IpmiBlobTransfer, "Enumerate call with valid data", 
"EnumerateValidResponse", EnumerateValidResponse, NULL, NULL, NULL);
+  Status = AddTestCase (IpmiBlobTransfer, "Enumerate call with invalid output buffer", 
"EnumerateInvalidBuffer", EnumerateInvalidBuffer, NULL, NULL, NULL);
+  // IpmiBlobTransferOpen
+  Status = AddTestCase (IpmiBlobTransfer, "Open call with valid data", 
"OpenValidResponse", OpenValidResponse, NULL, NULL, NULL);
+  // IpmiBlobTransferRead
+  Status = AddTestCase (IpmiBlobTransfer, "Read call with valid data", 
"ReadValidResponse", ReadValidResponse, NULL, NULL, NULL);
+  Status = AddTestCase (IpmiBlobTransfer, "Read call with invalid buffer", 
"ReadInvalidBuffer", ReadInvalidBuffer, NULL, NULL, NULL);
+  // IpmiBlobTransferWrite
+  Status = AddTestCase (IpmiBlobTransfer, "Write call with valid data", 
"WriteValidResponse", WriteValidResponse, NULL, NULL, NULL);
+  // IpmiBlobTransferCommit
+  Status = AddTestCase (IpmiBlobTransfer, "Commit call with valid data", 
"CommitValidResponse", CommitValidResponse, NULL, NULL, NULL);
+  // IpmiBlobTransferClose
+  Status = AddTestCase (IpmiBlobTransfer, "Close call with valid data", 
"CloseValidResponse", CloseValidResponse, NULL, NULL, NULL);
+  // IpmiBlobTransferDelete
+  Status = AddTestCase (IpmiBlobTransfer, "Delete call with valid data", 
"DeleteValidResponse", DeleteValidResponse, NULL, NULL, NULL);
+  // IpmiBlobTransferStat
+  Status = AddTestCase (IpmiBlobTransfer, "Blob Stat call with valid data", 
"BlobStatValidResponse", BlobStatValidResponse, NULL, NULL, NULL);
+  Status = AddTestCase (IpmiBlobTransfer, "Blob Stat call with invalid buffer", 
"BlobStatInvalidBuffer", BlobStatInvalidBuffer, NULL, NULL, NULL);
+  // IpmiBlobTransferSessionStat
+  Status = AddTestCase (IpmiBlobTransfer, "Session Stat call with valid data", 
"SessionStatValidResponse", SessionStatValidResponse, NULL, NULL, NULL);
+  Status = AddTestCase (IpmiBlobTransfer, "Session Stat call with invalid buffer", 
"SessionStatInvalidBuffer", SessionStatInvalidBuffer, NULL, NULL, NULL);
+  // IpmiBlobTransferWriteMeta
+  Status = AddTestCase (IpmiBlobTransfer, "WriteMeta call with valid data", 
"WriteMetaValidResponse", WriteMetaValidResponse, NULL, NULL, NULL);
+
+  // Execute the tests.
+  Status = RunAllTestSuites (Framework);
+  return Status;
+}
+
+/**
+  Standard UEFI entry point for target based
+  unit test execution from UEFI Shell.
+**/
+EFI_STATUS
+EFIAPI
+BaseLibUnitTestAppEntry (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  return SetupAndRunUnitTests ();
+}
+
+/**
+  Standard POSIX C entry point for host based unit test execution.
+**/
+int
+main (
+  int   argc,
+  char  *argv[]
+  )
+{
+  return SetupAndRunUnitTests ();
+}
diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md 
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md
new file mode 100644
index 0000000000..9eed5d3728
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md
@@ -0,0 +1,24 @@
+# IPMI Blob Transfer Interface Driver
+
+This DXE module is a UEFI implementation of the Phorphor Blob Transfer 
Interface defined in OpenBMC
+https://github.com/openbmc/phosphor-ipmi-blobs
+
+## OpenBMC implements this interface as a protocol, allowing UEFI and BMC to 
transfer blobs over IPMI.
+
+### Usage:
+Any DXE module that wishes to use this protocol should do the following:
+1) The module should have a dependency on gEdkiiIpmiBlobTransferProtocolGuid in its inf 
"Depex" section
+2) The module should list gEdkiiIpmiBlobTransferProtocolGuid in its inf 
"Protocol" section
+3) The module's entry point should do a LocateProtocol on 
gEdkiiIpmiBlobTransferProtocolGuid
+
+### A sample flow of protocol usage is as follows:
+1) A call to IpmiBlobTransferOpen ()
+2) Iterative calls to IpmiBlobTransferWrite
+3) A call to IpmiBlobTransferClose ()
+
+### Unit Tests:
+IpmiBlobTransferDxe/UnitTest/ contains host based unit tests of this 
implementation.
+Any changes to IpmiBlobTransferDxe should include proof of successful unit 
tests.
+
+### Debugging
+To assist in debugging any issues, change BLOB_TRANSFER_DEBUG to desired debug 
level, such as DEBUG_ERROR or DEBUG_INFO.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118993): https://edk2.groups.io/g/devel/message/118993
Mute This Topic: https://groups.io/mt/106115743/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to