[edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol

Chang, Abner via groups.io abner.chang=amd.com at groups.io
Thu Apr 13 04:29:08 UTC 2023


[AMD Official Use Only - General]

Hi Nickle,

Could you please create a BZ ticket for this? Pease also run Uncristify on these files.

Feedback inline, 

> -----Original Message-----
> From: Nickle Wang <nicklew at nvidia.com>
> Sent: Wednesday, April 12, 2023 11:17 AM
> To: devel at edk2.groups.io
> Cc: Chang, Abner <Abner.Chang at amd.com>; Isaac Oram
> <isaac.w.oram at intel.com>; Attar, AbdulLateef (Abdul Lateef)
> <AbdulLateef.Attar at amd.com>; Tinh Nguyen
> <tinhnguyen at amperemail.onmicrosoft.com>
> Subject: [edk2-platforms][PATCH] ManageabilityPkg: add support for the
> phosphor ipmi blob transfer protocol
> 
> Caution: This message originated from an External Source. Use proper
> caution when opening attachments, clicking links, or responding.
> 
> 
> This change implements the blob transfer protocol used in OpenBmc
> documented here: https://github.com/openbmc/phosphor-ipmi-blobs
> 
> Signed-off-by: Nick Ramirez <nramirez at nvidia.com>
> Cc: Abner Chang <abner.chang at amd.com>
> Cc: Isaac Oram <isaac.w.oram at intel.com>
> Cc: Abdul Lateef Attar <AbdulLateef.Attar at amd.com>
> Cc: Nickle Wang <nicklew at nvidia.com>
> Cc: Tinh Nguyen <tinhnguyen at amperemail.onmicrosoft.com>
> ---
>  .../ManageabilityPkg/ManageabilityPkg.dec     |    6 +
>  .../Include/Dsc/Manageability.dsc             |    4 +-
>  .../IpmiBlobTransferDxe.inf                   |   39 +
>  .../IpmiBlobTransferTestUnitTestsHost.inf     |   40 +
>  .../Include/Protocol/IpmiBlobTransfer.h       |  136 ++
>  .../InternalIpmiBlobTransfer.h                |  363 ++++++
>  .../IpmiBlobTransferDxe/IpmiBlobTransferDxe.c |  799 ++++++++++++
>  .../UnitTest/IpmiBlobTransferTestUnitTests.c  | 1113 +++++++++++++++++
>  .../Universal/IpmiBlobTransferDxe/Readme.md   |   24 +
>  9 files changed, 2523 insertions(+), 1 deletion(-)
>  create mode 100644
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
> erDxe.inf
>  create mode 100644
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl
> obTransferTestUnitTestsHost.inf
>  create mode 100644
> Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
>  create mode 100644
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlo
> bTransfer.h
>  create mode 100644
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
> erDxe.c
>  create mode 100644
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl
> obTransferTestUnitTests.c
>  create mode 100644
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md
> 
> diff --git a/Features/ManageabilityPkg/ManageabilityPkg.dec
> b/Features/ManageabilityPkg/ManageabilityPkg.dec
> index 9a930d3e4b..e2d6cccc50 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) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
>  #
>  ##
> @@ -48,3 +49,8 @@
>    gManageabilityProtocolMctpGuid    = { 0x76FED8F1, 0x0BE5, 0x4269, { 0xA3,
> 0x1A, 0x38, 0x0F, 0x54, 0xF1, 0xA1, 0x8A } }
>    # Manageability Protocol PLDM
>    gManageabilityProtocolPldmGuid    = { 0x3958090D, 0x69DD, 0x4868, { 0x9C,
> 0x41, 0xC9, 0xAC, 0x31, 0xB5, 0x25, 0xC5 } }
> +
> +[Protocols]
> +
> +  ## Include/Protocol/IpmiBlobTransfer.h
> +  gEdkiiIpmiBlobTransferProtocolGuid = { 0x05837c75, 0x1d65, 0x468b, { 0xb1,
> 0xc2, 0x81, 0xaf, 0x9a, 0x31, 0x5b, 0x2c } }
> diff --git a/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc
> b/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc
> index 0d868fdf4a..111d6b91dc 100644
> --- a/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc
> +++ b/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc
> @@ -2,11 +2,13 @@
>  # Common libraries for Manageabilty Package
>  #
>  # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
> +# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
>  #
>  ##
>  [LibraryClasses]
> 
> ManageabilityTransportHelperLib|ManageabilityPkg/Library/BaseManageabi
> lityTransportHelperLib/BaseManageabilityTransportHelper.inf
> +
> IpmiLib|MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiPr
> otocol.inf
> 
>  [LibraryClasses.ARM, LibraryClasses.AARCH64]
>    #
> @@ -22,4 +24,4 @@
>  [Components.X64]
>    ManageabilityPkg/Universal/IpmiProtocol/Dxe/IpmiProtocolDxe.inf
>    ManageabilityPkg/Universal/IpmiProtocol/Smm/IpmiProtocolSmm.inf
> -
> +
> ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
> diff --git
> a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTran
> sferDxe.inf
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTran
> sferDxe.inf
> new file mode 100644
> index 0000000000..28e9d293c1
> --- /dev/null
> +++
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTran
> sferDxe.inf
> @@ -0,0 +1,39 @@
> +## @file
> +# IPMI Blob Transfer Protocol DXE Driver.
> +#
> +#  Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights
Is 2022-2023 correct? This file will be added in 2023.


> 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/Ipmi
> BlobTransferTestUnitTestsHost.inf
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ipm
> iBlobTransferTestUnitTestsHost.inf
> new file mode 100644
> index 0000000000..1f071bbadc
> --- /dev/null
> +++
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ipm
> iBlobTransferTestUnitTestsHost.inf
> @@ -0,0 +1,40 @@
> +## @file
> +# Unit tests of the Ipmi blob transfer driver that are run from a host
> environment.
> +#
> +# Copyright (c) 2020-2023, 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..8ea71d8816
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
> @@ -0,0 +1,136 @@
> +/** @file
> +
> +  IPMI Blob Transfer driver
> +
> +  Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
Please add @Par to https://github.com/openbmc/phosphor-ipmi-blobs/blob/master/README.md, as the reference of specification.

> +
> +**/
> +#include <Library/IpmiLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <IndustryStandard/Ipmi.h>
> +
> +#define IPMI_NETFN_OEM                     0x2E
Let's move this definition to under MdePkg/Incldue/IndustryStandard/IpmiNetFnOem.h, please refer to IpmiNetFnGroupExtension.h. This keeps the consistent implementation with the current IPMI header files under MdePkg, although there is only one line definition.


> +#define IPMI_OEM_BLOB_TRANSFER_CMD         0x80
> +#define IPMI_OEM_BLOB_MAX_DATA_PER_PACKET  64
> +
> +#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
We can create a C header file "IpmiOpenBmc.h" under ManageabilityPkg/Include/IndustryStandard.  Also relocate  OpenBmcOen from IpmiBloblTransfer.c to this header file. We can have this header file that accommodates the IPMI specs defined by OpenBMC.
Please also use OpenBmc instead of "Oem".

> +
> +//
> +//  Blob Transfer Function Prototypes
> +//
> +typedef
> +EFI_STATUS
> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)(
> +  OUT UINT32 *Count
> +  );
> +
> +typedef
> +EFI_STATUS
> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)(
> +  IN  UINT32      BlobIndex,
> +  OUT CHAR8 *BlobId
> +  );
> +
> +typedef
> +EFI_STATUS
> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)(
> +  IN  CHAR8 *BlobId,
> +  IN  UINT16      Flags,
> +  OUT UINT16 *SessionId
> +  );
> +
> +typedef
> +EFI_STATUS
> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_READ)(
> +  IN  UINT16      SessionId,
> +  IN  UINT32      Offset,
> +  IN  UINT32      RequestedSize,
> +  OUT UINT8 *Data
> +  );
> +
> +typedef
> +EFI_STATUS
> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_WRITE)(
> +  IN  UINT16      SessionId,
> +  IN  UINT32      Offset,
> +  IN  UINT8 *Data,
> +  IN  UINT32      WriteLength
> +  );
> +
> +typedef
> +EFI_STATUS
> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)(
> +  IN  UINT16      SessionId,
> +  IN  UINT8       CommitDataLength,
> +  IN  UINT8 *CommitData
> +  );
> +
> +typedef
> +EFI_STATUS
> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)(
> +  IN  UINT16      SessionId
> +  );
> +
> +typedef
> +EFI_STATUS
> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)(
> +  IN  CHAR8 *BlobId
> +  );
> +
> +typedef
> +EFI_STATUS
> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_STAT)(
> +  IN  CHAR8 *BlobId,
> +  OUT UINT16 *BlobState,
> +  OUT UINT32 *Size,
> +  OUT UINT8 *MetadataLength,
> +  OUT UINT8 *Metadata
> +  );
> +
> +typedef
> +EFI_STATUS
> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT)(
> +  IN  UINT16      SessionId,
> +  OUT UINT16 *BlobState,
> +  OUT UINT32 *Size,
> +  OUT UINT8 *MetadataLength,
> +  OUT UINT8 *Metadata
> +  );
> +

You missed the function header for all function prototype here and above.

> +typedef
> +EFI_STATUS
> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)(
> +  IN  UINT16      SessionId,
> +  IN  UINT32      Offset,
> +  IN  UINT8 *Data,
> +  IN  UINT32      WriteLength
> +  );
> +
> +//
> +// Structure of IPMI_BLOB_TRANSFER_PROTOCOL
> +//
> +struct _IPMI_BLOB_TRANSFER_PROTOCOL {
> +  IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT       BlobGetCount;
> +  IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE       BlobEnumerate;
> +  IPMI_BLOB_TRANSFER_PROTOCOL_OPEN            BlobOpen;
> +  IPMI_BLOB_TRANSFER_PROTOCOL_READ            BlobRead;
> +  IPMI_BLOB_TRANSFER_PROTOCOL_WRITE           BlobWrite;
> +  IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT          BlobCommit;
> +  IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE           BlobClose;
> +  IPMI_BLOB_TRANSFER_PROTOCOL_DELETE          BlobDelete;
> +  IPMI_BLOB_TRANSFER_PROTOCOL_STAT            BlobStat;
> +  IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT    BlobSessionStat;
> +  IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META      BlobWriteMeta;
> +};
Do you think EDKII_IPMI_BLOB_TRANSFER_PROTOCOL for protocol name is better? Although IPMI_PROTOCOL wasn't named as this way. That's fine to keep the naming of function member as it.


> +
> +typedef struct _IPMI_BLOB_TRANSFER_PROTOCOL
> IPMI_BLOB_TRANSFER_PROTOCOL;
> +
> +extern EFI_GUID  gEdkiiIpmiBlobTransferProtocolGuid;
> diff --git
> a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiB
> lobTransfer.h
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiB
> lobTransfer.h
> new file mode 100644
> index 0000000000..14f0dc02bc
> --- /dev/null
> +++
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiB
> lobTransfer.h
> @@ -0,0 +1,363 @@
> +/** @file
> +
> +  Headers for IPMI Blob Transfer driver
> +
> +  Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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
> +
> +// 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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_BLOB_MAX_DATA_PER_PACKET];
> +} IPMI_BLOB_TRANSFER_BLOB_WRITE_META_SEND_DATA;
> +
> +#define IPMI_BLOB_TRANSFER_BLOB_WRITE_META_RESPONSE  NULL
> +
> +#pragma pack()

Above is defined in openbmc, we can remove it to the new C header file.

> +
> +/**
> +  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
> +CalculateCrc16 (
> +  IN UINT8  *Data,
> +  IN UINTN  DataSize
> +  );
> +

> +EFI_STATUS
> +IpmiBlobTransferSendIpmi (
> +  IN  UINT8   SubCommand,
> +  IN  UINT8   *SendData,
> +  IN  UINT32  SendDataSize,
> +  OUT UINT8   *ResponseData,
> +  OUT UINT32  *ResponseDataSize
> +  );
No function header.

> +
> +/**
> +  @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
> +  );
> +
> +/**
> +  @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
> +  );
> +
> +/**
> +  @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
> +  );
> +
> +/**
> +  @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
> +  );
> +
> +/**
> +  @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
> +
> +  @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
> +  );
> +
> +/**
> +  @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
> +  );
> +
> +/**
> +  @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
> +  );
> +
> +/**
> +  @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
> +  );
> +
> +/**
> +  @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
> +  );
> +
> +/**
> +  @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
> +  );
> +
> +/**
> +  @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
> +
> +  @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/IpmiBlobTran
> sferDxe.c
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTran
> sferDxe.c
> new file mode 100644
> index 0000000000..9e663289d5
> --- /dev/null
> +++
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTran
> sferDxe.c
> @@ -0,0 +1,799 @@
> +/** @file
> +
> +  IPMI Blob Transfer driver
> +
> +  Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights
> reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +#include <Protocol/IpmiBlobTransfer.h>
> +
> +#include "InternalIpmiBlobTransfer.h"
> +
> +#define BLOB_TRANSFER_DEBUG  0
> +
> +STATIC CONST IPMI_BLOB_TRANSFER_PROTOCOL  mIpmiBlobTransfer = {
> +
> (IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)*IpmiBlobTransferGetCou
> nt,
> +
> (IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnume
> rate,
> +  (IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)*IpmiBlobTransferOpen,
> +  (IPMI_BLOB_TRANSFER_PROTOCOL_READ)*IpmiBlobTransferRead,
> +  (IPMI_BLOB_TRANSFER_PROTOCOL_WRITE)*IpmiBlobTransferWrite,
> +  (IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)*IpmiBlobTransferCommit,
> +  (IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)*IpmiBlobTransferClose,
> +  (IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)*IpmiBlobTransferDelete,
> +  (IPMI_BLOB_TRANSFER_PROTOCOL_STAT)*IpmiBlobTransferStat,
> +
> (IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT)*IpmiBlobTransferSessi
> onStat,
> +
> (IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWrite
> Meta
> +};
> +
> +const UINT8  OpenBmcOen[] = { 0xCF, 0xC2, 0x00 };          // OpenBMC OEN
> code in little endian format
> +
> +/**
> +  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
> +CalculateCrc16 (
> +  IN UINT8  *Data,
> +  IN UINTN  DataSize
> +  )
> +{
> +  UINTN    Index;
> +  UINTN    BitIndex;
> +  UINT16   Crc     = 0xFFFF;
> +  UINT16   Poly    = 0x1021;
> +  BOOLEAN  XorFlag = FALSE;
I remember we don't do local variable initialization here.  We give it a initial value in a separate line.

> +
> +  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;
> +      }
> +    }
> +  }
> +
> + #if BLOB_TRANSFER_DEBUG
> +  DEBUG ((DEBUG_INFO, "%a: CRC-16-CCITT %x\n", __FUNCTION__, Crc));
> + #endif
Do you mind if we remove the macros those  are used through entire file, the definition of BLOB_TRANSFER_DEBUG as well. We can just output the message with DEBUG_INFO for now. We can use DEBUG_MANAGEABILITY_INFO once Manageabilty Part II patch set is reviewed and merged.
Also, I am proposing to have new debug print error level.

> +
> +  return Crc;
> +}
> +
Missed function header. 

> +EFI_STATUS
> +IpmiBlobTransferSendIpmi (
> +  IN  UINT8   SubCommand,
> +  IN  UINT8   *SendData,
> +  IN  UINT32  SendDataSize,
> +  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;
> +
> +  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) {
> +    //
> +    // Calculate the Crc of the send data
> +    //
> +    Crc = CalculateCrc16 (SendData, SendDataSize);
> +    CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER),
> &Crc, sizeof (UINT16));
> +    CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER) +
> sizeof (UINT16), SendData, SendDataSize);
> +  }
> +
> + #if BLOB_TRANSFER_DEBUG
> +  DEBUG ((DEBUG_INFO, "%a: Inputs:\n", __FUNCTION__));
> +  DEBUG ((DEBUG_INFO, "%a: SendDataSize: %02x\nData: ",
> __FUNCTION__, SendDataSize));
> +  UINT8  i;
> +  for (i = 0; i < SendDataSize; i++) {
> +    DEBUG ((DEBUG_INFO, "%02x", *((UINT8 *)SendData + i)));
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "\n"));
> +  DEBUG ((DEBUG_INFO, "%a: IpmiSendDataSize: %02x\nData: ",
> __FUNCTION__, IpmiSendDataSize));
> +  for (i = 0; i < IpmiSendDataSize; i++) {
> +    DEBUG ((DEBUG_INFO, "%02x", *((UINT8 *)IpmiSendData + i)));
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "\n"));
> + #endif
> +
> +  IpmiResponseDataSize = (*ResponseDataSize +
> PROTOCOL_RESPONSE_OVERHEAD);
> +  //
> +  // If expecting data to be returned, we have to also account for the 16 bit
> CRC
> +  //
> +  if (*ResponseDataSize) {
> +    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;
> +
> + #if BLOB_TRANSFER_DEBUG
> +  DEBUG ((DEBUG_INFO, "%a: IPMI Response:\n", __FUNCTION__));
> +  DEBUG ((DEBUG_INFO, "%a: ResponseDataSize: %02x\nData: ",
> __FUNCTION__, IpmiResponseDataSize));
> +  for (i = 0; i < IpmiResponseDataSize; i++) {
> +    DEBUG ((DEBUG_INFO, "%02x", *(ModifiedResponseData + i)));
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "\n"));
> + #endif
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  CompletionCode = *ModifiedResponseData;
> +  if (CompletionCode != IPMI_COMP_CODE_NORMAL) {
> +    DEBUG ((DEBUG_ERROR, "%a: Returning because CompletionCode =
> 0x%x\n", __FUNCTION__, 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 == CalculateCrc16 (ModifiedResponseData, IpmiResponseDataSize))
> {
> +      CopyMem (ResponseData, ModifiedResponseData,
> IpmiResponseDataSize);
> +      CopyMem (ResponseDataSize, &IpmiResponseDataSize, sizeof
> (IpmiResponseDataSize));
> +      FreePool (IpmiResponseData);
> +      return EFI_SUCCESS;
> +    } else {
> +      FreePool (IpmiResponseData);
> +      return EFI_CRC_ERROR;
> +    }
> +  }
> +}
> +
> +/**
Could we have short description for function in this files? We can copy it from openbmc spec.


> +  @param[out]        Count       The number of active blobs
> +
> +  @retval EFI_SUCCESS            The command byte stream was successfully
> submit to the device and a response was successfully received.
> +  @retval EFI_PROTOCOL_ERROR     The Ipmi command failed
> +  @retval EFI_CRC_ERROR          The Ipmi command returned a bad checksum
> +**/
> +EFI_STATUS
> +IpmiBlobTransferGetCount (
> +  OUT UINT32  *Count
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT8       *ResponseData;
> +  UINT32      ResponseDataSize;
> +
> +  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;
> +}
> +
> +/**
> +  @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;
> +  }
> +
> +  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) {
> +    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;
> +}
> +
> +/**
> +  @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
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT8       *SendData;
> +  UINT8       *ResponseData;
> +  UINT32      SendDataSize;
> +  UINT32      ResponseDataSize;
> +  CHAR8       *BlobSearch;
> +  UINT32      NumBlobs;
> +  UINT16      Index;
> +  BOOLEAN     BlobFound;
> +
> +  //
> +  // Before opening a blob, need to check if it exists
> +  //
> +  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",
> __FUNCTION__, Status));
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  BlobSearch = AllocateZeroPool (sizeof (CHAR8) *
> IPMI_OEM_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 %s\n",
> __FUNCTION__, 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;
> +
> +  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;
> +}
> +
> +/**
> +  @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
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT8       *SendData;
> +  UINT8       *ResponseData;
> +  UINT32      SendDataSize;
> +  UINT32      ResponseDataSize;
> +
> +  if (Data == NULL) {
> +    ASSERT (FALSE);
> +    return EFI_ABORTED;
> +  }
> +
> +  ResponseDataSize = RequestedSize * sizeof (UINT8);
> +  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) {
> +    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;
> +}
> +
> +/**
> +  @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
> +
> +  @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;
> +
> +  //
> +  // Format send data
> +  //
> +  SendDataSize = sizeof (SessionId) + sizeof (Offset) + WriteLength;
> +  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;
> +}
> +
> +/**
> +  @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;
> +
> +  //
> +  // 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;
> +}
> +
> +/**
> +  @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;
> +}
> +
> +/**
> +  @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;
> +
> +  //
> +  // 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;
> +}
> +
> +/**
> +  @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 (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, IPMI_OEM_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;
> +}
> +
> +/**
> +  @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;
> +}
> +
> +/**
> +  @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
> +
> +  @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
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT8       *SendData;
> +  UINT32      SendDataSize;
> +  UINT32      ResponseDataSize;
> +
> +  //
> +  // 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,
> +                &gEdkiiIpmiBlobTransferProtocolGuid,
> +                (VOID *)&mIpmiBlobTransfer,
> +                NULL
> +                );
> +}
> diff --git
> a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ipmi
> BlobTransferTestUnitTests.c
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ipm
> iBlobTransferTestUnitTests.c
> new file mode 100644
> index 0000000000..f326467922
> --- /dev/null
> +++
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ipm
> iBlobTransferTestUnitTests.c
> @@ -0,0 +1,1113 @@
> +/** @file
> +*
> +*  Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
> +*
> +*  SPDX-FileCopyrightText: Copyright (c) 2022 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 = CalculateCrc16 (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 = CalculateCrc16 (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) *
> IPMI_OEM_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;
> +  }
> +
> +  // CalculateCrc16
> +  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..47800f5801
> --- /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
> +
> +## NVIDIA's OpenBMC implements this interface as a protocol, allowing
> UEFI and BMC to transfer blobs over IPMI.
We should remove NVIDIA and use edk2 instead. 

Thanks
Abner

> +
> +### 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 1
> --
> 2.17.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#102919): https://edk2.groups.io/g/devel/message/102919
Mute This Topic: https://groups.io/mt/98212643/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list