Hi Nickle,
Please see my comments inline...
P/s: I just realized that I can not test this protocol without IPMI SSIF
to be compatible with ManageabilityPkg framework.
On 5/15/2024 10:06 PM, Nickle Wang wrote:
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4773
This change implements the blob transfer protocol used in OpenBmc
documented here: https://github.com/openbmc/phosphor-ipmi-blobs
Signed-off-by: Nick Ramirez <nrami...@nvidia.com>
Co-authored-by: Nickle Wang <nick...@nvidia.com>
Cc: Abner Chang <abner.ch...@amd.com>
Cc: Abdul Lateef Attar <abdullateef.at...@amd.com>
Cc: Tinh Nguyen <tinhngu...@amperemail.onmicrosoft.com>
Cc: Nhi Pham <n...@os.amperecomputing.com>
Cc: Thang Nguyen OS <th...@amperemail.onmicrosoft.com>
Cc: Mike Maslenkin <mike.maslen...@gmail.com>
---
.../ManageabilityPkg/ManageabilityPkg.dec | 3 +
.../Include/Manageability.dsc | 2 +
.../IpmiBlobTransferDxe.inf | 39 +
.../IpmiBlobTransferTestUnitTestsHost.inf | 40 +
.../Include/Protocol/IpmiBlobTransfer.h | 253 ++++
.../InternalIpmiBlobTransfer.h | 407 ++++++
.../IpmiBlobTransferDxe/IpmiBlobTransferDxe.c | 872 +++++++++++++
.../UnitTest/IpmiBlobTransferTestUnitTests.c | 1113 +++++++++++++++++
.../Universal/IpmiBlobTransferDxe/Readme.md | 24 +
9 files changed, 2753 insertions(+)
create mode 100644
Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
create mode 100644
Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
create mode 100644
Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
create mode 100644
Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
create mode 100644
Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
create mode 100644
Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
create mode 100644
Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md
diff --git a/Features/ManageabilityPkg/ManageabilityPkg.dec
b/Features/ManageabilityPkg/ManageabilityPkg.dec
index eb0ee67cba..dc1d00162c 100644
--- a/Features/ManageabilityPkg/ManageabilityPkg.dec
+++ b/Features/ManageabilityPkg/ManageabilityPkg.dec
@@ -4,6 +4,7 @@
# those are related to the platform management.
#
# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
@@ -58,6 +59,8 @@
gEdkiiPldmProtocolGuid = { 0x60997616, 0xDB70, 0x4B5F, {
0x86, 0xA4, 0x09, 0x58, 0xA3, 0x71, 0x47, 0xB4 } }
gEdkiiPldmSmbiosTransferProtocolGuid = { 0xFA431C3C, 0x816B, 0x4B32, {
0xA3, 0xE0, 0xAD, 0x9B, 0x7F, 0x64, 0x27, 0x2E } }
gEdkiiMctpProtocolGuid = { 0xE93465C1, 0x9A31, 0x4C96, {
0x92, 0x56, 0x22, 0x0A, 0xE1, 0x80, 0xB4, 0x1B } }
+ ## Include/Protocol/IpmiBlobTransfer.h
+ gEdkiiIpmiBlobTransferProtocolGuid = { 0x05837c75, 0x1d65, 0x468b, {
0xb1, 0xc2, 0x81, 0xaf, 0x9a, 0x31, 0x5b, 0x2c } }
[PcdsFixedAtBuild]
## This value is the MCTP Interface source and destination endpoint ID for
transmiting MCTP message.
diff --git a/Features/ManageabilityPkg/Include/Manageability.dsc
b/Features/ManageabilityPkg/Include/Manageability.dsc
index 2e410df9ba..aae343a733 100644
--- a/Features/ManageabilityPkg/Include/Manageability.dsc
+++ b/Features/ManageabilityPkg/Include/Manageability.dsc
@@ -2,6 +2,7 @@
# Common libraries for Manageabilty Package
#
# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
@@ -37,6 +38,7 @@
[Components.X64, Components.AARCH64]
!if gManageabilityPkgTokenSpaceGuid.PcdManageabilityDxeIpmiEnable == TRUE
ManageabilityPkg/Universal/IpmiProtocol/Dxe/IpmiProtocolDxe.inf
+ ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
!endif
[Components.X64]
diff --git
a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
new file mode 100644
index 0000000000..108f4bb5f8
--- /dev/null
+++
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
@@ -0,0 +1,39 @@
+## @file
+# IPMI Blob Transfer Protocol DXE Driver.
+#
+# Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights
reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IpmiBlobTransferDxe
+ FILE_GUID = 6357c804-78bb-4b0c-abdf-c75df942f319
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = IpmiBlobTransferDxeDriverEntryPoint
+
+[Sources.common]
+ IpmiBlobTransferDxe.c
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ IpmiLib
+ MemoryAllocationLib
+ PcdLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ManageabilityPkg/ManageabilityPkg.dec
+
+[Protocols]
+ gEdkiiIpmiBlobTransferProtocolGuid
+
+[Depex]
+ TRUE
diff --git
a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
new file mode 100644
index 0000000000..dab6858f09
--- /dev/null
+++
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
@@ -0,0 +1,40 @@
+## @file
+# Unit tests of the Ipmi blob transfer driver that are run from a host
environment.
+#
+# Copyright (c) 2020-2024, NVIDIA CORPORATION & AFFILIATES. All rights
reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = IpmiBlobTransferDxeUnitTestsHost
+ FILE_GUID = 1f5d4095-ea52-432c-b078-86097fef6004
+ MODULE_TYPE = HOST_APPLICATION
+ VERSION_STRING = 1.0
+
+#
+# The following information is for reference only
+# and not required by the build tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ IpmiBlobTransferTestUnitTests.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ManageabilityPkg/ManageabilityPkg.dec
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UnitTestLib
+ IpmiLib
+
+[Protocols]
+ gEdkiiIpmiBlobTransferProtocolGuid
diff --git a/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
new file mode 100644
index 0000000000..14b5294314
--- /dev/null
+++ b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
@@ -0,0 +1,253 @@
+/** @file
+
+ IPMI Blob Transfer driver
+
+ Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights
reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @Par: https://github.com/openbmc/phosphor-ipmi-blobs/blob/master/README.md
+**/
Lack of header guard
#ifndef IPMI_BLOB_TRANSFER_H_
+#include <Library/IpmiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <IndustryStandard/Ipmi.h>
+#include <IndustryStandard/IpmiNetFnOem.h>
+
+#define IPMI_OEM_BLOB_TRANSFER_CMD 0x80
+
+#define BLOB_TRANSFER_STAT_OPEN_R BIT0
+#define BLOB_TRANSFER_STAT_OPEN_W BIT1
+#define BLOB_TRANSFER_STAT_COMMITING BIT2
+#define BLOB_TRANSFER_STAT_COMMITTED BIT3
+#define BLOB_TRANSFER_STAT_COMMIT_ERROR BIT4
+// Bits 5-7 are reserved
+// Bits 8-15 are blob-specific definitions
+
+//
+// OpenBMC OEN code in little endian format
+//
+const UINT8 OpenBmcOen[] = { 0xCF, 0xC2, 0x00 };
const -> CONST
Should we add a PCD for the OEN to be configured by platform specific
BMC? Or this protocol is only to support OpenBMC.
+
+//
+// Blob Transfer Function Prototypes
+//
+
+/**
+ This function retrieves the count of blob transfers available through the
IPMI.
+
+ @param[out] Count The number of active blobs
+
+ @retval EFI_SUCCESS Successfully retrieved the number of active
blobs.
+ @retval Other An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)(
+ OUT UINT32 *Count
+ );
+
+/**
+ This function enumerates blob transfers available through the IPMI.
+
+ @param[in] BlobIndex The 0-based Index of the blob to enumerate
+ @param[out] BlobId The ID of the blob
+
+ @retval EFI_SUCCESS Successfully enumerated the blob.
+ @retval Other An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)(
+ IN UINT32 BlobIndex,
+ OUT CHAR8 *BlobId
+ );
+
+/**
+ This function is designed to open a session for a specific blob
+ identified by its ID, using the IPMI.
+
+ @param[in] BlobId The ID of the blob to open
+ @param[in] Flags Flags to control how the blob is opened
+ @param[out] SessionId A unique session identifier
+
+ @retval EFI_SUCCESS Successfully opened the blob.
+ @retval Other An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)(
+ IN CHAR8 *BlobId,
+ IN UINT16 Flags,
+ OUT UINT16 *SessionId
+ );
+
+/**
+ This function reads data from a blob over the IPMI.
+
+ @param[in] SessionId The session ID returned from a call to
BlobOpen
+ @param[in] Offset The offset of the blob from which to
start reading
+ @param[in] RequestedSize The length of data to read
+ @param[out] Data Data read from the blob
+
+ @retval EFI_SUCCESS Successfully read from the blob.
+ @retval Other An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_READ)(
+ IN UINT16 SessionId,
+ IN UINT32 Offset,
+ IN UINT32 RequestedSize,
+ OUT UINT8 *Data
+ );
+
+/**
+ This function writes data to a blob over the IPMI.
+
+ @param[in] SessionId The session ID returned from a call to
BlobOpen
+ @param[in] Offset The offset of the blob from which to
start writing
+ @param[in] Data A pointer to the data to write
+ @param[in] WriteLength The length to write
+
+ @retval EFI_SUCCESS Successfully wrote to the blob.
+ @retval Other An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE)(
+ IN UINT16 SessionId,
+ IN UINT32 Offset,
+ IN UINT8 *Data,
+ IN UINT32 WriteLength
+ );
+
+/**
+ This function commits data to a blob over the IPMI.
+
+ @param[in] SessionId The session ID returned from a call to
BlobOpen
+ @param[in] CommitDataLength The length of data to commit to the blob
+ @param[in] CommitData A pointer to the data to commit
+
+ @retval EFI_SUCCESS Successful commit to the blob.
+ @retval Other An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)(
+ IN UINT16 SessionId,
+ IN UINT8 CommitDataLength,
+ IN UINT8 *CommitData
+ );
+
+/**
+ This function close a session associated with a blob transfer over the IPMI.
+
+ @param[in] SessionId The session ID returned from a call to
BlobOpen
+
+ @retval EFI_SUCCESS The blob was closed.
+ @retval Other An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)(
+ IN UINT16 SessionId
+ );
+
+/**
+ This function deletes a specific blob identified by its ID over the IPMI.
+
+ @param[in] BlobId The BlobId to be deleted
+
+ @retval EFI_SUCCESS The blob was deleted.
+ @retval Other An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)(
+ IN CHAR8 *BlobId
+ );
+
+/**
+ This function retrieve the status of a specific blob identified by BlobId
from an IPMI.
+
+ @param[in] BlobId The Blob ID to gather statistics for
+ @param[out] BlobState The current state of the blob
+ @param[out] Size Size in bytes of the blob
+ @param[out] MetadataLength Length of the optional metadata
+ @param[out] Metadata Optional blob-specific metadata
+
+ @retval EFI_SUCCESS The blob statistics were successfully
gathered.
+ @retval Other An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_STAT)(
+ IN CHAR8 *BlobId,
+ OUT UINT16 *BlobState,
+ OUT UINT32 *Size,
+ OUT UINT8 *MetadataLength,
+ OUT UINT8 *Metadata
+ );
+
+/**
+ This function query the status of a blob transfer session in an IPMI.
+
+ @param[in] SessionId The ID of the session to gather
statistics for
+ @param[out] BlobState The current state of the blob
+ @param[out] Size Size in bytes of the blob
+ @param[out] MetadataLength Length of the optional metadata
+ @param[out] Metadata Optional blob-specific metadata
+
+ @retval EFI_SUCCESS The blob statistics were successfully
gathered.
+ @retval Other An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT)(
+ IN UINT16 SessionId,
+ OUT UINT16 *BlobState,
+ OUT UINT32 *Size,
+ OUT UINT8 *MetadataLength,
+ OUT UINT8 *Metadata
+ );
+
+/**
+ This function writes metadata to a blob associated with a session in an IPMI.
+
+ @param[in] SessionId The ID of the session to write metadata
for
+ @param[in] Offset The offset of the metadata to write to
+ @param[in] Data The data to write to the metadata
+ @param[in] WriteLength The length to write
+
+ @retval EFI_SUCCESS The blob metadata was successfully
written.
+ @retval Other An error occurred
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)(
+ IN UINT16 SessionId,
+ IN UINT32 Offset,
+ IN UINT8 *Data,
+ IN UINT32 WriteLength
+ );
+
+//
+// Structure of EDKII_IPMI_BLOB_TRANSFER_PROTOCOL
+//
+struct _EDKII_IPMI_BLOB_TRANSFER_PROTOCOL {
+ EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT BlobGetCount;
+ EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE BlobEnumerate;
+ EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_OPEN BlobOpen;
+ EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_READ BlobRead;
+ EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE BlobWrite;
+ EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT BlobCommit;
+ EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE BlobClose;
+ EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_DELETE BlobDelete;
+ EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_STAT BlobStat;
+ EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT BlobSessionStat;
+ EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META BlobWriteMeta;
+};
+
+typedef struct _EDKII_IPMI_BLOB_TRANSFER_PROTOCOL
EDKII_IPMI_BLOB_TRANSFER_PROTOCOL;
+
+extern EFI_GUID gEdkiiIpmiBlobTransferProtocolGuid;
diff --git
a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
new file mode 100644
index 0000000000..3e90dc6871
--- /dev/null
+++
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
@@ -0,0 +1,407 @@
+/** @file
+
+ Headers for IPMI Blob Transfer driver
+
+ Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights
reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
Lack of header guard
#ifndef INTERNAL_IPMI_BLOB_TRANSFER_H_
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IpmiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+
+#define PROTOCOL_RESPONSE_OVERHEAD (4 * sizeof(UINT8)) // 1 byte
completion code + 3 bytes OEN
Nit: Add a space after sizeof
+#define BLOB_MAX_DATA_PER_PACKET 64
Should it be moved to Include/Protocol/IpmiBlobTransfer.h? The caller
could need to be aware the max length of the package.
+
+// Subcommands for this protocol
+typedef enum {
+ IpmiBlobTransferSubcommandGetCount = 0,
+ IpmiBlobTransferSubcommandEnumerate,
+ IpmiBlobTransferSubcommandOpen,
+ IpmiBlobTransferSubcommandRead,
+ IpmiBlobTransferSubcommandWrite,
+ IpmiBlobTransferSubcommandCommit,
+ IpmiBlobTransferSubcommandClose,
+ IpmiBlobTransferSubcommandDelete,
+ IpmiBlobTransferSubcommandStat,
+ IpmiBlobTransferSubcommandSessionStat,
+ IpmiBlobTransferSubcommandWriteMeta,
+} IPMI_BLOB_TRANSFER_SUBCOMMANDS;
+
+#pragma pack(1)
+
+typedef struct {
+ UINT8 OEN[3];
+ UINT8 SubCommand;
+} IPMI_BLOB_TRANSFER_HEADER;
+
+//
+// Command 0 - BmcBlobGetCount
+// The BmcBlobGetCount command expects to receive an empty body.
+// The BMC will return the number of enumerable blobs
+//
+typedef struct {
+ UINT32 BlobCount;
+} IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE;
+
+//
+// Command 1 - BmcBlobEnumerate
+// The BmcBlobEnumerate command expects to receive a body of:
+//
+typedef struct {
+ UINT32 BlobIndex; // 0-based index of blob to receive
+} IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA;
+
+typedef struct {
+ CHAR8 BlobId[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_RESPONSE;
+
+//
+// Command 2 - BmcBlobOpen
+// The BmcBlobOpen command expects to receive a body of:
+//
+typedef struct {
+ UINT16 Flags;
+ CHAR8 BlobId[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA;
+
+#define BLOB_OPEN_FLAG_READ 0
+#define BLOB_OPEN_FLAG_WRITE 1
+// Bits 2-7 are reserved
+// Bits 8-15 are blob-specific definitions
+
+typedef struct {
+ UINT16 SessionId;
+} IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE;
+
+//
+// Command 3 - BmcBlobRead
+// The BmcBlobRead command expects to receive a body of:
+//
+typedef struct {
+ UINT16 SessionId; // Returned from BlobOpen
+ UINT32 Offset;
+ UINT32 RequestedSize;
+} IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA;
+
+typedef struct {
+ UINT8 Data[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_READ_RESPONSE;
+
+//
+// Command 4 - BmcBlobWrite
+// The BmcBlobWrite command expects to receive a body of:
+//
+typedef struct {
+ UINT16 SessionId; // Returned from BlobOpen
+ UINT32 Offset;
+ UINT8 Data[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA;
+
+//
+// Command 5 - BmcBlobCommit
+// The BmcBlobCommit command expects to receive a body of:
+//
+typedef struct {
+ UINT16 SessionId; // Returned from BlobOpen
+ UINT8 CommitDataLength;
+ UINT8 CommitData[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA;
+
+//
+// Command 6 - BmcBlobClose
+// The BmcBlobClose command expects to receive a body of:
+//
+typedef struct {
+ UINT16 SessionId; // Returned from BlobOpen
+} IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA;
+
+//
+// Command 7 - BmcBlobDelete
+// NOTE: This command will fail if there are open sessions for this blob
+// The BmcBlobDelete command expects to receive a body of:
+//
+typedef struct {
+ CHAR8 BlobId[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA;
+
+//
+// Command 8 - BmcBlobStat
+// This command returns statistics about a blob.
+// This command expects to receive a body of:
+//
+typedef struct {
+ CHAR8 BlobId[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA;
+
+typedef struct {
+ UINT16 BlobState;
+ UINT32 Size; // Size in bytes of the blob
+ UINT8 MetaDataLen;
+ UINT8 MetaData[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE;
+
+//
+// Command 9 - BmcBlobSessionStat
+// Returns same data as BmcBlobState expect for a session, not a blob
+// This command expects to receive a body of:
+//
+typedef struct {
+ UINT16 SessionId;
+} IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA;
+
+typedef struct {
+ UINT16 BlobState;
+ UINT32 Size; // Size in bytes of the blob
+ UINT8 MetaDataLen;
+ UINT8 MetaData[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE;
+
+//
+// Command 10 - BmcBlobWriteMeta
+// The BmcBlobWriteMeta command expects to receive a body of:
+//
+typedef struct {
+ UINT16 SessionId;
+ UINT32 Offset;
+ UINT8 Data[BLOB_MAX_DATA_PER_PACKET];
+} IPMI_BLOB_TRANSFER_BLOB_WRITE_META_SEND_DATA;
+
+#define IPMI_BLOB_TRANSFER_BLOB_WRITE_META_RESPONSE NULL
+
+#pragma pack()
+
+/**
+ Calculate CRC-16-CCITT with poly of 0x1021
+
+ @param[in] Data The target data.
+ @param[in] DataSize The target data size.
+
+ @return UINT16 The CRC16 value.
+
+**/
+UINT16
+CalculateCrc16Ccitt (
+ IN UINT8 *Data,
+ IN UINTN DataSize
+ );
+
+/**
+ This function does blob transfer over IPMI command.
+
+ @param[in] SubCommand The specific sub-command to be executed as
part of
+ the blob transfer operation.
+ @param[in] SendData A pointer to the data buffer that contains the
data to be sent.
+ @param[in] SendDataSize The size of the data to be sent, in bytes.
+ @param[out] ResponseData A pointer to the buffer where the response
data will be stored.
+ @param[out] ResponseDataSize A pointer to a variable that will hold the
size of the response
+ data received.
+
+ @retval EFI_SUCCESS Successfully sends blob data.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation fails.
+ @retval EFI_PROTOCOL_ERROR Communication errors.
+ @retval EFI_CRC_ERROR Data integrity checks fail.
+ @retval Other An error occurred
+
+**/
+EFI_STATUS
+IpmiBlobTransferSendIpmi (
+ IN UINT8 SubCommand,
+ IN UINT8 *SendData,
+ IN UINT32 SendDataSize,
+ OUT UINT8 *ResponseData,
+ OUT UINT32 *ResponseDataSize
+ );
+
+/**
+ This function retrieves the count of blob transfers available through the
IPMI.
+
+ @param[out] Count The number of active blobs
+
+ @retval EFI_SUCCESS Successfully retrieved the number of active
blobs.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferGetCount (
+ OUT UINT32 *Count
+ );
+
+/**
+ This function enumerates blob transfers available through the IPMI.
+
+ @param[in] BlobIndex The 0-based Index of the blob to enumerate
+ @param[out] BlobId The ID of the blob
+
+ @retval EFI_SUCCESS Successfully enumerated the blob.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferEnumerate (
+ IN UINT32 BlobIndex,
+ OUT CHAR8 *BlobId
+ );
+
+/**
+ This function is designed to open a session for a specific blob
+ identified by its ID, using the IPMI.
+
+ @param[in] BlobId The ID of the blob to open
+ @param[in] Flags Flags to control how the blob is opened
+ @param[out] SessionId A unique session identifier
+
+ @retval EFI_SUCCESS Successfully opened the blob.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferOpen (
+ IN CHAR8 *BlobId,
+ IN UINT16 Flags,
+ OUT UINT16 *SessionId
+ );
+
+/**
+ This function reads data from a blob over the IPMI.
+
+ @param[in] SessionId The session ID returned from a call to
BlobOpen
+ @param[in] Offset The offset of the blob from which to
start reading
+ @param[in] RequestedSize The length of data to read
+ @param[out] Data Data read from the blob
+
+ @retval EFI_SUCCESS Successfully read from the blob.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferRead (
+ IN UINT16 SessionId,
+ IN UINT32 Offset,
+ IN UINT32 RequestedSize,
+ OUT UINT8 *Data
+ );
+
+/**
+ This function writes data to a blob over the IPMI.
+
+ @param[in] SessionId The session ID returned from a call to
BlobOpen
+ @param[in] Offset The offset of the blob from which to
start writing
+ @param[in] Data A pointer to the data to write
+ @param[in] WriteLength The length to write
+
+ @retval EFI_SUCCESS Successfully wrote to the blob.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferWrite (
+ IN UINT16 SessionId,
+ IN UINT32 Offset,
+ IN UINT8 *Data,
+ IN UINT32 WriteLength
+ );
+
+/**
+ This function commits data to a blob over the IPMI.
+
+ @param[in] SessionId The session ID returned from a call to
BlobOpen
+ @param[in] CommitDataLength The length of data to commit to the blob
+ @param[in] CommitData A pointer to the data to commit
+
+ @retval EFI_SUCCESS Successful commit to the blob.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferCommit (
+ IN UINT16 SessionId,
+ IN UINT8 CommitDataLength,
+ IN UINT8 *CommitData
+ );
+
+/**
+ This function close a session associated with a blob transfer over the IPMI.
+
+ @param[in] SessionId The session ID returned from a call to
BlobOpen
+
+ @retval EFI_SUCCESS The blob was closed.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferClose (
+ IN UINT16 SessionId
+ );
+
+/**
+ This function deletes a specific blob identified by its ID over the IPMI.
+
+ @param[in] BlobId The BlobId to be deleted
+
+ @retval EFI_SUCCESS The blob was deleted.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferDelete (
+ IN CHAR8 *BlobId
+ );
+
+/**
+ This function retrieve the status of a specific blob identified by BlobId
from an IPMI.
+
+ @param[in] BlobId The Blob ID to gather statistics for
+ @param[out] BlobState The current state of the blob
+ @param[out] Size Size in bytes of the blob
+ @param[out] MetadataLength Length of the optional metadata
+ @param[out] Metadata Optional blob-specific metadata
+
+ @retval EFI_SUCCESS The blob statistics were successfully
gathered.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferStat (
+ IN CHAR8 *BlobId,
+ OUT UINT16 *BlobState,
+ OUT UINT32 *Size,
+ OUT UINT8 *MetadataLength,
+ OUT UINT8 *Metadata
+ );
+
+/**
+ This function query the status of a blob transfer session in an IPMI.
+
+ @param[in] SessionId The ID of the session to gather
statistics for
+ @param[out] BlobState The current state of the blob
+ @param[out] Size Size in bytes of the blob
+ @param[out] MetadataLength Length of the optional metadata
+ @param[out] Metadata Optional blob-specific metadata
+
+ @retval EFI_SUCCESS The blob statistics were successfully
gathered.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferSessionStat (
+ IN UINT16 SessionId,
+ OUT UINT16 *BlobState,
+ OUT UINT32 *Size,
+ OUT UINT8 *MetadataLength,
+ OUT UINT8 *Metadata
+ );
+
+/**
+ This function writes metadata to a blob associated with a session in an IPMI.
+
+ @param[in] SessionId The ID of the session to write metadata
for
+ @param[in] Offset The offset of the metadata to write to
+ @param[in] Data The data to write to the metadata
+ @param[in] WriteLength The length to write
+
+ @retval EFI_SUCCESS The blob metadata was successfully
written.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferWriteMeta (
+ IN UINT16 SessionId,
+ IN UINT32 Offset,
+ IN UINT8 *Data,
+ IN UINT32 WriteLength
+ );
diff --git
a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
new file mode 100644
index 0000000000..b8a2db193b
--- /dev/null
+++
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
@@ -0,0 +1,872 @@
+/** @file
+
+ IPMI Blob Transfer driver
+
+ Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights
reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Protocol/IpmiBlobTransfer.h>
+
+#include "InternalIpmiBlobTransfer.h"
+
+#define BLOB_TRANSFER_DEBUG DEBUG_MANAGEABILITY
+
+STATIC CONST EDKII_IPMI_BLOB_TRANSFER_PROTOCOL mIpmiBlobTransfer = {
+ (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)*IpmiBlobTransferGetCount,
+ (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnumerate,
+ (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)*IpmiBlobTransferOpen,
+ (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_READ)*IpmiBlobTransferRead,
+ (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE)*IpmiBlobTransferWrite,
+ (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)*IpmiBlobTransferCommit,
+ (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)*IpmiBlobTransferClose,
+ (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)*IpmiBlobTransferDelete,
+ (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_STAT)*IpmiBlobTransferStat,
+ (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT)*IpmiBlobTransferSessionStat,
+ (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWriteMeta
+};
+
+/**
+ Calculate CRC-16-CCITT with poly of 0x1021
+
+ @param[in] Data The target data.
+ @param[in] DataSize The target data size.
+
+ @return UINT16 The CRC16 value.
+
+**/
+UINT16
+CalculateCrc16Ccitt (
+ IN UINT8 *Data,
+ IN UINTN DataSize
+ )
+{
+ UINTN Index;
+ UINTN BitIndex;
+ UINT16 Crc;
+ UINT16 Poly;
+ BOOLEAN XorFlag;
+
+ Crc = 0xFFFF;
+ Poly = 0x1021;
+ XorFlag = FALSE;
+
+ for (Index = 0; Index < (DataSize + 2); ++Index) {
+ for (BitIndex = 0; BitIndex < 8; ++BitIndex) {
+ XorFlag = (Crc & 0x8000) ? TRUE : FALSE;
+ Crc <<= 1;
+ if ((Index < DataSize) && (Data[Index] & (1 << (7 - BitIndex)))) {
+ Crc++;
+ }
+
+ if (XorFlag == TRUE) {
+ Crc ^= Poly;
+ }
+ }
+ }
+
+ DEBUG ((BLOB_TRANSFER_DEBUG, "%a: CRC-16-CCITT %x\n", __func__, Crc));
+
+ return Crc;
+}
+
+/**
+ This function does blob transfer over IPMI command.
+
+ @param[in] SubCommand The specific sub-command to be executed as
part of
+ the blob transfer operation.
+ @param[in] SendData A pointer to the data buffer that contains the
data to be sent.
+ @param[in] SendDataSize The size of the data to be sent, in bytes.
+ @param[out] ResponseData A pointer to the buffer where the response
data will be stored.
+ @param[out] ResponseDataSize A pointer to a variable that will hold the
size of the response
+ data received.
+
+ @retval EFI_SUCCESS Successfully sends blob data.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation fails.
+ @retval EFI_PROTOCOL_ERROR Communication errors.
+ @retval EFI_CRC_ERROR Data integrity checks fail.
+ @retval Other An error occurred
+
+**/
+EFI_STATUS
+IpmiBlobTransferSendIpmi (
+ IN UINT8 SubCommand,
+ IN UINT8 *SendData,
+ IN UINT32 SendDataSize,
Should describe SendData and SendDataSize as OPTIONAL
+ OUT UINT8 *ResponseData,
+ OUT UINT32 *ResponseDataSize
+ )
+{
+ EFI_STATUS Status;
+ UINT8 CompletionCode;
+ UINT16 Crc;
+ UINT8 Oen[3];
+ UINT8 *IpmiSendData;
+ UINT32 IpmiSendDataSize;
+ UINT8 *IpmiResponseData;
+ UINT8 *ModifiedResponseData;
+ UINT32 IpmiResponseDataSize;
+ IPMI_BLOB_TRANSFER_HEADER Header;
+
Should validate the pointer of input arguments: SendData, ResponseData,
ResponseDataSize.
+ Crc = 0;
+
+ //
+ // Prepend the proper header to the SendData
+ //
+ IpmiSendDataSize = (sizeof (IPMI_BLOB_TRANSFER_HEADER));
+ if (SendDataSize) {
+ IpmiSendDataSize += sizeof (Crc) + (sizeof (UINT8) * SendDataSize);
+ }
+
+ IpmiSendData = AllocateZeroPool (IpmiSendDataSize);
+ if (IpmiSendData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Header.OEN[0] = OpenBmcOen[0];
+ Header.OEN[1] = OpenBmcOen[1];
+ Header.OEN[2] = OpenBmcOen[2];
+ Header.SubCommand = SubCommand;
+ CopyMem (IpmiSendData, &Header, sizeof (IPMI_BLOB_TRANSFER_HEADER));
+ if (SendDataSize) {
if (SendDataSize != 0)
+ //
+ // Calculate the Crc of the send data
+ //
+ Crc = CalculateCrc16Ccitt (SendData, SendDataSize);
+ CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER), &Crc, sizeof
(UINT16));
+ CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER) + sizeof
(UINT16), SendData, SendDataSize);
+ }
+
+ DEBUG_CODE_BEGIN ();
+ DEBUG ((BLOB_TRANSFER_DEBUG, "%a: Inputs:\n", __func__));
+ DEBUG ((BLOB_TRANSFER_DEBUG, "%a: SendDataSize: %02x\nData: ", __func__,
SendDataSize));
+ UINT8 i;
+
+ for (i = 0; i < SendDataSize; i++) {
+ DEBUG ((BLOB_TRANSFER_DEBUG, "%02x", *((UINT8 *)SendData + i)));
+ }
+
+ DEBUG ((BLOB_TRANSFER_DEBUG, "\n"));
+ DEBUG ((BLOB_TRANSFER_DEBUG, "%a: IpmiSendDataSize: %02x\nData: ", __func__,
IpmiSendDataSize));
+ for (i = 0; i < IpmiSendDataSize; i++) {
+ DEBUG ((BLOB_TRANSFER_DEBUG, "%02x", *((UINT8 *)IpmiSendData + i)));
+ }
+
+ DEBUG ((BLOB_TRANSFER_DEBUG, "\n"));
+ DEBUG_CODE_END ();
+
+ IpmiResponseDataSize = (*ResponseDataSize + PROTOCOL_RESPONSE_OVERHEAD);
+ //
+ // If expecting data to be returned, we have to also account for the 16 bit
CRC
+ //
+ if (*ResponseDataSize) {
if (*ResponseDataSize != 0)
+ IpmiResponseDataSize += sizeof (Crc);
+ }
+
+ IpmiResponseData = AllocateZeroPool (IpmiResponseDataSize);
+ if (IpmiResponseData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = IpmiSubmitCommand (
+ IPMI_NETFN_OEM,
+ IPMI_OEM_BLOB_TRANSFER_CMD,
+ (VOID *)IpmiSendData,
+ IpmiSendDataSize,
+ (VOID *)IpmiResponseData,
+ &IpmiResponseDataSize
+ );
+
+ FreePool (IpmiSendData);
+ ModifiedResponseData = IpmiResponseData;
+
+ DEBUG_CODE_BEGIN ();
+ DEBUG ((BLOB_TRANSFER_DEBUG, "%a: IPMI Response:\n", __func__));
+ DEBUG ((BLOB_TRANSFER_DEBUG, "%a: ResponseDataSize: %02x\nData: ", __func__,
IpmiResponseDataSize));
+ UINT8 i;
+
+ for (i = 0; i < IpmiResponseDataSize; i++) {
+ DEBUG ((BLOB_TRANSFER_DEBUG, "%02x", *(ModifiedResponseData + i)));
+ }
+
+ DEBUG ((BLOB_TRANSFER_DEBUG, "\n"));
+ DEBUG_CODE_END ();
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CompletionCode = *ModifiedResponseData;
+ if (CompletionCode != IPMI_COMP_CODE_NORMAL) {
+ DEBUG ((DEBUG_ERROR, "%a: Returning because CompletionCode = 0x%x\n",
__func__, CompletionCode));
+ FreePool (IpmiResponseData);
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ // Strip completion code, we are done with it
+ ModifiedResponseData = ModifiedResponseData + sizeof (CompletionCode);
+ IpmiResponseDataSize -= sizeof (CompletionCode);
+
+ // Check OEN code and verify it matches the OpenBMC OEN
+ CopyMem (Oen, ModifiedResponseData, sizeof (OpenBmcOen));
+ if (CompareMem (Oen, OpenBmcOen, sizeof (OpenBmcOen)) != 0) {
+ FreePool (IpmiResponseData);
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ if (IpmiResponseDataSize == sizeof (OpenBmcOen)) {
+ //
+ // In this case, there was no response data sent. This is not an error.
+ // Some messages do not require a response.
+ //
+ *ResponseDataSize = 0;
+ FreePool (IpmiResponseData);
+ return Status;
+ // Now we need to validate the CRC then send the Response body back
+ } else {
+ // Strip the OEN, we are done with it now
+ ModifiedResponseData = ModifiedResponseData + sizeof (Oen);
+ IpmiResponseDataSize -= sizeof (Oen);
+ // Then validate the Crc
+ CopyMem (&Crc, ModifiedResponseData, sizeof (Crc));
+ ModifiedResponseData = ModifiedResponseData + sizeof (Crc);
+ IpmiResponseDataSize -= sizeof (Crc);
+
+ if (Crc == CalculateCrc16Ccitt (ModifiedResponseData,
IpmiResponseDataSize)) {
+ CopyMem (ResponseData, ModifiedResponseData, IpmiResponseDataSize);
+ CopyMem (ResponseDataSize, &IpmiResponseDataSize, sizeof
(IpmiResponseDataSize));
+ FreePool (IpmiResponseData);
+ return EFI_SUCCESS;
+ } else {
+ FreePool (IpmiResponseData);
+ return EFI_CRC_ERROR;
+ }
+ }
+}
+
+/**
+ This function retrieves the count of blob transfers available through the
IPMI.
+
+ @param[out] Count The number of active blobs
+
+ @retval EFI_SUCCESS Successfully retrieved the number of active
blobs.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferGetCount (
+ OUT UINT32 *Count
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *ResponseData;
+ UINT32 ResponseDataSize;
+
+ if (Count == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE);
+ ResponseData = AllocateZeroPool (ResponseDataSize);
+ if (ResponseData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount, NULL, 0,
(UINT8 *)ResponseData, &ResponseDataSize);
+ if (!EFI_ERROR (Status)) {
+ *Count = ((IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE
*)ResponseData)->BlobCount;
+ }
+
+ FreePool (ResponseData);
+ return Status;
+}
+
+/**
+ This function enumerates blob transfers available through the IPMI.
+
+ @param[in] BlobIndex The 0-based Index of the blob to enumerate
+ @param[out] BlobId The ID of the blob
+
+ @retval EFI_SUCCESS Successfully enumerated the blob.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferEnumerate (
+ IN UINT32 BlobIndex,
+ OUT CHAR8 *BlobId
+ )
+{
+ EFI_STATUS Status;
+
+ UINT8 *SendData;
+ UINT8 *ResponseData;
+ UINT32 SendDataSize;
+ UINT32 ResponseDataSize;
+
+ if (BlobId == NULL) {
+ ASSERT (FALSE);
+ return EFI_ABORTED;
Should return EFI_INVALID_PARAMETER for input validation?
+ }
+
+ ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_RESPONSE);
+ ResponseData = AllocateZeroPool (ResponseDataSize);
+ if (ResponseData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Format send data
+ //
+ SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA);
+ SendData = AllocateZeroPool (SendDataSize);
+ if (SendData == NULL) {
FreePool (ResponseData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ((IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA *)SendData)->BlobIndex =
BlobIndex;
+
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandEnumerate,
SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);
+ if (!EFI_ERROR (Status)) {
+ AsciiStrCpyS (BlobId, ResponseDataSize, (CHAR8 *)ResponseData);
+ }
+
+ FreePool (ResponseData);
+ return Status;
+}
+
+/**
+ This function is designed to open a session for a specific blob
+ identified by its ID, using the IPMI.
+
+ @param[in] BlobId The ID of the blob to open
+ @param[in] Flags Flags to control how the blob is opened
It would be good if we can list out all flag definitions here. Actually,
I don't know how to input for this argument.
Are they BLOB_OPEN_FLAG_READ and BLOB_OPEN_FLAG_WRITE in the private
include header?
+ @param[out] SessionId A unique session identifier
+
+ @retval EFI_SUCCESS Successfully opened the blob.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferOpen (
+ IN CHAR8 *BlobId,
+ IN UINT16 Flags,
+ OUT UINT16 *SessionId
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *SendData;
+ UINT8 *ResponseData;
+ UINT32 SendDataSize;
+ UINT32 ResponseDataSize;
+ CHAR8 *BlobSearch;
+ UINT32 NumBlobs;
+ UINT16 Index;
+ BOOLEAN BlobFound;
+
+ if ((BlobId == NULL) || (SessionId == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Before opening a blob, need to check if it exists
I'm thinking the caller sequence here. Typically, the caller might check
the presence of a blob by calling GetCount () and Enumerate () before
opening a blob session. This check here could waste time. Or, do we call
open direction the blob session without pre-checking?
+ //
+ Status = IpmiBlobTransferGetCount (&NumBlobs);
+ if (EFI_ERROR (Status) || (NumBlobs == 0)) {
+ if (Status == EFI_UNSUPPORTED) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_ERROR, "%a: Could not find any blobs: %r\n", __func__,
Status));
+ return EFI_NOT_FOUND;
+ }
+
+ BlobSearch = AllocateZeroPool (sizeof (CHAR8) * BLOB_MAX_DATA_PER_PACKET);
+ if (BlobSearch == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlobFound = FALSE;
+ for (Index = 0; Index < NumBlobs; Index++) {
+ Status = IpmiBlobTransferEnumerate (Index, BlobSearch);
+ if ((!EFI_ERROR (Status)) && (AsciiStrCmp (BlobSearch, BlobId) == 0)) {
+ BlobFound = TRUE;
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ if (!BlobFound) {
+ DEBUG ((DEBUG_ERROR, "%a: Could not find a blob that matches %a\n",
__func__, BlobId));
+ FreePool (BlobSearch);
+ return EFI_NOT_FOUND;
+ }
+
+ ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE);
+ ResponseData = AllocateZeroPool (ResponseDataSize);
+ if (ResponseData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Format send data
+ //
+ SendDataSize = sizeof (((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA
*)SendData)->Flags) + ((AsciiStrLen (BlobId)) * sizeof (CHAR8)) + sizeof
(CHAR8);
+ SendData = AllocateZeroPool (SendDataSize);
+ if (SendData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA *)SendData)->BlobId,
AsciiStrSize (BlobId) / sizeof (CHAR8), BlobId);
+ ((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA *)SendData)->Flags = Flags;
+ // append null char to SendData
+ SendData[SendDataSize-1] = 0;
Nit: add spaces around minus (-) for readability.
+
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandOpen, SendData,
SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);
+ if (!EFI_ERROR (Status)) {
+ *SessionId = ((IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE
*)ResponseData)->SessionId;
+ }
+
+ FreePool (ResponseData);
+ FreePool (SendData);
+ FreePool (BlobSearch);
+ return Status;
+}
+
+/**
+ This function reads data from a blob over the IPMI.
+
+ @param[in] SessionId The session ID returned from a call to
BlobOpen
+ @param[in] Offset The offset of the blob from which to
start reading
+ @param[in] RequestedSize The length of data to read
+ @param[out] Data Data read from the blob
+
+ @retval EFI_SUCCESS Successfully read from the blob.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferRead (
+ IN UINT16 SessionId,
There might be developer mistake when executing the transfer before
opening the session. How do we handle this failure path? Do we need to
maintain a state machine for that?
This comment applies to other functions as well.
+ IN UINT32 Offset,
+ IN UINT32 RequestedSize,
+ OUT UINT8 *Data
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *SendData;
+ UINT8 *ResponseData;
+ UINT32 SendDataSize;
+ UINT32 ResponseDataSize;
+
+ if (Data == NULL) {
+ ASSERT (FALSE);
+ return EFI_ABORTED;
Should return EFI_INVALID_PARAMETER?
+ }
+
+ ResponseDataSize = RequestedSize * sizeof (UINT8);
Should check the RequestedSize against BLOB_MAX_DATA_PER_PACKET?
+ ResponseData = AllocateZeroPool (ResponseDataSize);
+ if (ResponseData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Format send data
+ //
+ SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA);
+ SendData = AllocateZeroPool (SendDataSize);
+ if (SendData == NULL) {
FreePool (ResponseData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)->SessionId =
SessionId;
+ ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)->Offset = Offset;
+ ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)->RequestedSize =
RequestedSize;
+
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandRead, SendData,
SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);
+ if (!EFI_ERROR (Status)) {
+ CopyMem (Data, ((IPMI_BLOB_TRANSFER_BLOB_READ_RESPONSE
*)ResponseData)->Data, ResponseDataSize * sizeof (UINT8));
+ }
+
+ FreePool (ResponseData);
+ FreePool (SendData);
+ return Status;
+}
+
+/**
+ This function writes data to a blob over the IPMI.
+
+ @param[in] SessionId The session ID returned from a call to
BlobOpen
+ @param[in] Offset The offset of the blob from which to
start writing
+ @param[in] Data A pointer to the data to write
+ @param[in] WriteLength The length to write
+
+ @retval EFI_SUCCESS Successfully wrote to the blob.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferWrite (
+ IN UINT16 SessionId,
+ IN UINT32 Offset,
+ IN UINT8 *Data,
+ IN UINT32 WriteLength
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *SendData;
+ UINT32 SendDataSize;
+ UINT32 ResponseDataSize;
+
+ if (Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Format send data
+ //
+ SendDataSize = sizeof (SessionId) + sizeof (Offset) + WriteLength;
Should we check whether or not the WriteLength is equal to or less than
BLOB_MAX_DATA_PER_PACKET?
+ SendData = AllocateZeroPool (SendDataSize);
+ if (SendData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->SessionId = SessionId;
+ ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset = Offset;
+ CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Data, Data,
sizeof (UINT8) * WriteLength);
+
+ ResponseDataSize = 0;
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandWrite,
SendData, SendDataSize, NULL, &ResponseDataSize);
+
+ FreePool (SendData);
+ return Status;
+}
+
+/**
+ This function commits data to a blob over the IPMI.
+
+ @param[in] SessionId The session ID returned from a call to
BlobOpen
+ @param[in] CommitDataLength The length of data to commit to the blob
+ @param[in] CommitData A pointer to the data to commit
+
+ @retval EFI_SUCCESS Successful commit to the blob.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferCommit (
+ IN UINT16 SessionId,
+ IN UINT8 CommitDataLength,
+ IN UINT8 *CommitData
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *SendData;
+ UINT32 SendDataSize;
+ UINT32 ResponseDataSize;
+
+ if (CommitData == NULL) {
According to the spec https://github.com/openbmc/phosphor-ipmi-blobs,
the commit data is block-specific optional.
For instance, the commit data is optional for SMBIOS blob transfer. Look
at https://github.com/openbmc/smbios-mdr
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Format send data
+ //
+ SendDataSize = sizeof (SessionId) + sizeof (CommitDataLength) +
CommitDataLength;
+ SendData = AllocateZeroPool (SendDataSize);
+ if (SendData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)->SessionId =
SessionId;
+ ((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)->CommitDataLength =
CommitDataLength;
+ CopyMem (((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)->CommitData,
CommitData, sizeof (UINT8) * CommitDataLength);
+
+ ResponseDataSize = 0;
+
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandCommit, SendData,
SendDataSize, NULL, &ResponseDataSize);
+
+ FreePool (SendData);
+ return Status;
+}
+
+/**
+ This function close a session associated with a blob transfer over the IPMI.
+
+ @param[in] SessionId The session ID returned from a call to
BlobOpen
+
+ @retval EFI_SUCCESS The blob was closed.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferClose (
+ IN UINT16 SessionId
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *SendData;
+ UINT32 SendDataSize;
+ UINT32 ResponseDataSize;
+
+ //
+ // Format send data
+ //
+ SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA);
+ SendData = AllocateZeroPool (SendDataSize);
+ if (SendData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ((IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA *)SendData)->SessionId = SessionId;
+
+ ResponseDataSize = 0;
+
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandClose, SendData,
SendDataSize, NULL, &ResponseDataSize);
+
+ FreePool (SendData);
+ return Status;
+}
+
+/**
+ This function deletes a specific blob identified by its ID over the IPMI.
+
+ @param[in] BlobId The BlobId to be deleted
+
+ @retval EFI_SUCCESS The blob was deleted.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferDelete (
+ IN CHAR8 *BlobId
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *SendData;
+ UINT32 SendDataSize;
+ UINT32 ResponseDataSize;
+
+ if (BlobId == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Format send data
+ //
+ SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA);
+ SendData = AllocateZeroPool (SendDataSize);
+ if (SendData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA
*)SendData)->BlobId, AsciiStrLen (BlobId), BlobId);
+
+ ResponseDataSize = 0;
+
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandDelete, SendData,
SendDataSize, NULL, &ResponseDataSize);
+
+ FreePool (SendData);
+ return Status;
+}
+
+/**
+ This function retrieve the status of a specific blob identified by BlobId
from an IPMI.
+
+ @param[in] BlobId The Blob ID to gather statistics for
+ @param[out] BlobState The current state of the blob
+ @param[out] Size Size in bytes of the blob
+ @param[out] MetadataLength Length of the optional metadata
+ @param[out] Metadata Optional blob-specific metadata
+
+ @retval EFI_SUCCESS The blob statistics were successfully
gathered.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferStat (
+ IN CHAR8 *BlobId,
+ OUT UINT16 *BlobState,
+ OUT UINT32 *Size,
+ OUT UINT8 *MetadataLength,
+ OUT UINT8 *Metadata
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *SendData;
+ UINT8 *ResponseData;
+ UINT32 SendDataSize;
+ UINT32 ResponseDataSize;
+
+ if ((BlobId == NULL) || (BlobState == NULL) || (Size == NULL) ||
(MetadataLength == NULL)) {
Could we make Metadata **per spec**, MetadataLength, and Size optional?
We could not care them rather than BlobState.
This comment applies to IpmiBlobTransferSessionStat () as well.
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Metadata == NULL) {
+ ASSERT (FALSE);
+ return EFI_ABORTED;
+ }
+
+ ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE);
+ ResponseData = AllocateZeroPool (ResponseDataSize);
+ if (ResponseData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Format send data
+ //
+ SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA);
+ SendData = AllocateZeroPool (SendDataSize);
+ if (SendData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA *)SendData)->BlobId,
BLOB_MAX_DATA_PER_PACKET, BlobId);
+
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandStat, SendData,
SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);
+ if (!EFI_ERROR (Status)) {
+ *BlobState = ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE
*)ResponseData)->BlobState;
+ *Size = ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE
*)ResponseData)->Size;
+ *MetadataLength = ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE
*)ResponseData)->MetaDataLen;
+
+ CopyMem (&Metadata, &((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE
*)ResponseData)->MetaData, sizeof (((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE
*)ResponseData)->MetaData));
+ }
+
+ FreePool (ResponseData);
+ FreePool (SendData);
+ return Status;
+}
+
+/**
+ This function query the status of a blob transfer session in an IPMI.
+
+ @param[in] SessionId The ID of the session to gather
statistics for
+ @param[out] BlobState The current state of the blob
+ @param[out] Size Size in bytes of the blob
+ @param[out] MetadataLength Length of the optional metadata
+ @param[out] Metadata Optional blob-specific metadata
+
+ @retval EFI_SUCCESS The blob statistics were successfully
gathered.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferSessionStat (
+ IN UINT16 SessionId,
+ OUT UINT16 *BlobState,
+ OUT UINT32 *Size,
+ OUT UINT8 *MetadataLength,
+ OUT UINT8 *Metadata
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *SendData;
+ UINT8 *ResponseData;
+ UINT32 SendDataSize;
+ UINT32 ResponseDataSize;
+
+ if ((BlobState == NULL) || (Size == NULL) || (MetadataLength == NULL) ||
(Metadata == NULL)) {
+ ASSERT (FALSE);
+ return EFI_ABORTED;
+ }
+
+ ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE);
+ ResponseData = AllocateZeroPool (ResponseDataSize);
+ if (ResponseData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Format send data
+ //
+ SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA);
+ SendData = AllocateZeroPool (SendDataSize);
+ if (SendData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA *)SendData)->SessionId =
SessionId;
+
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandSessionStat,
SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);
+
+ if (!EFI_ERROR (Status)) {
+ *BlobState = ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE
*)ResponseData)->BlobState;
+ *Size = ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE
*)ResponseData)->Size;
+ *MetadataLength = ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE
*)ResponseData)->MetaDataLen;
+
+ CopyMem (&Metadata, &((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE
*)ResponseData)->MetaData, sizeof (((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE
*)ResponseData)->MetaData));
+ }
+
+ FreePool (ResponseData);
+ FreePool (SendData);
+ return Status;
+}
+
+/**
+ This function writes metadata to a blob associated with a session in an IPMI.
+
+ @param[in] SessionId The ID of the session to write metadata
for
+ @param[in] Offset The offset of the metadata to write to
+ @param[in] Data The data to write to the metadata
+ @param[in] WriteLength The length to write
+
+ @retval EFI_SUCCESS The blob metadata was successfully
written.
+ @retval Other An error occurred
+**/
+EFI_STATUS
+IpmiBlobTransferWriteMeta (
+ IN UINT16 SessionId,
+ IN UINT32 Offset,
+ IN UINT8 *Data,
How do callers know the data format of metadata for writing correctly?
+ IN UINT32 WriteLength
Should check with BLOB_MAX_DATA_PER_PACKET
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *SendData;
+ UINT32 SendDataSize;
+ UINT32 ResponseDataSize;
+
+ if (Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Format send data
+ //
+ SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA);
+ SendData = AllocateZeroPool (SendDataSize);
+ if (SendData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->SessionId = SessionId;
+ ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset = Offset;
+ CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Data, Data,
sizeof (UINT8) * WriteLength);
+
+ ResponseDataSize = 0;
+
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandWriteMeta,
SendData, SendDataSize, NULL, &ResponseDataSize);
+
+ FreePool (SendData);
+ return Status;
+}
+
+/**
+ This is the declaration of an EFI image entry point. This entry point is
+ the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
+ both device drivers and bus drivers.
+
+ @param[in] ImageHandle The firmware allocated handle for the UEFI
image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval Others An unexpected error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+IpmiBlobTransferDxeDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
Nit: Typically, we could also use gImageHandle instead.
+ &gEdkiiIpmiBlobTransferProtocolGuid,
+ (VOID *)&mIpmiBlobTransfer,
+ NULL
+ );
+}
diff --git
a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
new file mode 100644
index 0000000000..0f728527b8
--- /dev/null
+++
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
@@ -0,0 +1,1113 @@
+/** @file
+*
+* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
+*
+* SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION &
AFFILIATES
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdint.h>
+#include <cmocka.h>
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HostBasedTestStubLib/IpmiStubLib.h>
+
+#include <Library/UnitTestLib.h>
+#include <Protocol/IpmiBlobTransfer.h>
+#include "../InternalIpmiBlobTransfer.h"
+
+#define UNIT_TEST_NAME "IPMI Blob Transfer Unit Tests"
+#define UNIT_TEST_VERSION "1.0"
+
+UINT8 InvalidCompletion[] = {
+ 0xC0, // CompletionCode
+ 0xCF, 0xC2, 0x00, // OpenBMC OEN
+};
+#define INVALID_COMPLETION_SIZE 4 * sizeof(UINT8)
+
+UINT8 NoDataResponse[] = {
+ 0x00, // CompletionCode
+ 0xCF, 0xC2, 0x00, // OpenBMC OEN
+};
+#define NO_DATA_RESPONSE_SIZE 4 * sizeof(UINT8)
+
+UINT8 BadOenResponse[] = {
+ 0x00, // CompletionCode
+ 0xFF, 0xC2, 0x00, // Wrong OEN
+};
+#define BAD_OEN_RESPONSE_SIZE 4 * sizeof(UINT8)
+
+UINT8 BadCrcResponse[] = {
+ 0x00, // CompletionCode
+ 0xCF, 0xC2, 0x00, // OpenBMC OEN
+ 0x00, 0x00, // CRC
+ 0x01, 0x00, 0x00, 0x00, // Data
+};
+#define BAD_CRC_RESPONSE_SIZE 10 * sizeof(UINT8)
+
+UINT8 ValidNoDataResponse[] = {
+ 0x00, // CompletionCode
+ 0xCF, 0xC2, 0x00, // OpenBMC OEN
+};
+
+#define VALID_NODATA_RESPONSE_SIZE 4 * sizeof(UINT8)
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+GoodCrc (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ UINT8 Data[5] = { 0x12, 0x34, 0x56, 0x78, 0x90 };
+ UINTN DataSize;
+ UINT16 Crc;
+
+ DataSize = sizeof (Data);
+
+ Crc = CalculateCrc16Ccitt (Data, DataSize);
+
+ UT_ASSERT_EQUAL (Crc, 0xB928);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+BadCrc (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ UINT8 Data[5] = { 0x12, 0x34, 0x56, 0x78, 0x90 };
+ UINTN DataSize;
+ UINT16 Crc;
+
+ DataSize = sizeof (Data);
+
+ Crc = CalculateCrc16Ccitt (Data, DataSize);
+
+ UT_ASSERT_NOT_EQUAL (Crc, 0x3409);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SendIpmiBadCompletion (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ VOID *ResponseData;
+ UINT32 *ResponseDataSize;
+ EFI_STATUS Status;
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (INVALID_COMPLETION_SIZE);
+ ResponseDataSize = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
+ CopyMem (MockResponseResults, &InvalidCompletion, INVALID_COMPLETION_SIZE);
+
+ MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
INVALID_COMPLETION_SIZE, EFI_SUCCESS);
+
+ ResponseData = (UINT8 *)AllocateZeroPool (*ResponseDataSize);
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount,
NULL, 0, ResponseData, ResponseDataSize);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_PROTOCOL_ERROR);
+ FreePool (MockResponseResults);
+ FreePool (ResponseDataSize);
+ FreePool (ResponseData);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SendIpmiNoDataResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ VOID *ResponseData;
+ UINT32 *ResponseDataSize;
+ EFI_STATUS Status;
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (NO_DATA_RESPONSE_SIZE);
+ ResponseDataSize = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
+ CopyMem (MockResponseResults, &NoDataResponse, NO_DATA_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
NO_DATA_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ ResponseData = (UINT8 *)AllocateZeroPool (sizeof (NoDataResponse));
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount,
NULL, 0, ResponseData, ResponseDataSize);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+ UT_ASSERT_EQUAL (*ResponseDataSize, 0);
+ FreePool (MockResponseResults);
+ FreePool (ResponseDataSize);
+ FreePool (ResponseData);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SendIpmiBadOenResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ VOID *ResponseData;
+ UINT32 *ResponseDataSize;
+ EFI_STATUS Status;
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (BAD_OEN_RESPONSE_SIZE);
+ ResponseDataSize = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
+ CopyMem (MockResponseResults, &BadOenResponse, BAD_OEN_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
BAD_OEN_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ ResponseData = (UINT8 *)AllocateZeroPool (sizeof (BadOenResponse));
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount,
NULL, 0, ResponseData, ResponseDataSize);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_PROTOCOL_ERROR);
+ FreePool (MockResponseResults);
+ FreePool (ResponseDataSize);
+ FreePool (ResponseData);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SendIpmiBadCrcResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ VOID *ResponseData;
+ UINT32 *ResponseDataSize;
+ EFI_STATUS Status;
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(BAD_CRC_RESPONSE_SIZE));
+ ResponseDataSize = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
+ CopyMem (MockResponseResults, &BadCrcResponse, BAD_CRC_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
BAD_CRC_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ ResponseData = (UINT8 *)AllocateZeroPool (sizeof (BadCrcResponse));
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount,
NULL, 0, ResponseData, ResponseDataSize);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_CRC_ERROR);
+ FreePool (MockResponseResults);
+ FreePool (ResponseDataSize);
+ FreePool (ResponseData);
+ return UNIT_TEST_PASSED;
+}
+
+UINT8 ValidGetCountResponse[] = {
+ 0x00, // CompletionCode
+ 0xCF, 0xC2, 0x00, // OpenBMC OEN
+ 0xA4, 0x78, // CRC
+ 0x01, 0x00, 0x00, 0x00, // Data
+};
+#define VALID_GET_COUNT_RESPONSE_SIZE 10 * sizeof(UINT8)
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SendIpmiValidCountResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ UINT8 *ResponseData;
+ UINT32 *ResponseDataSize;
+ EFI_STATUS Status;
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_GET_COUNT_RESPONSE_SIZE));
+ ResponseDataSize = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
+ CopyMem (MockResponseResults, &ValidGetCountResponse,
VALID_GET_COUNT_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ ResponseData = AllocateZeroPool (sizeof (ValidGetCountResponse));
+ Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount,
NULL, 0, ResponseData, ResponseDataSize);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+ FreePool (MockResponseResults);
+ FreePool (ResponseDataSize);
+ FreePool (ResponseData);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+GetCountValidCountResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Count;
+ VOID *MockResponseResults = NULL;
+
+ Count = 0;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_GET_COUNT_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidGetCountResponse,
VALID_GET_COUNT_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ Status = IpmiBlobTransferGetCount (&Count);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+ UT_ASSERT_EQUAL (Count, 1);
+ FreePool (MockResponseResults);
+ return UNIT_TEST_PASSED;
+}
+
+UINT8 ValidEnumerateResponse[] = {
+ 0x00, // CompletionCode
+ 0xCF, 0xC2, 0x00, // OpenBMC OEN
+ 0x81, 0x13, // CRC
+ 0x2F, 0x73, 0x6D, 0x62, // Data = "/smbios"
+ 0x69, 0x6F, 0x73, 0x00,
+};
+#define VALID_ENUMERATE_RESPONSE_SIZE 14 * sizeof(UINT8)
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+EnumerateValidResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *BlobId;
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_ENUMERATE_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidEnumerateResponse,
VALID_ENUMERATE_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ BlobId = AllocateZeroPool (sizeof (CHAR8) * BLOB_MAX_DATA_PER_PACKET);
+
+ Status = IpmiBlobTransferEnumerate (0, BlobId);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+ UT_ASSERT_MEM_EQUAL (BlobId, "/smbios", 7);
+ FreePool (MockResponseResults);
+ FreePool (BlobId);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+EnumerateInvalidBuffer (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ CHAR8 *BlobId;
+ EFI_STATUS Status;
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_ENUMERATE_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidEnumerateResponse,
VALID_ENUMERATE_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ BlobId = NULL;
+
+ UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferEnumerate (0, BlobId), NULL);
+
+ FreePool (MockResponseResults);
+ return UNIT_TEST_PASSED;
+}
+
+UINT8 ValidOpenResponse[] = {
+ 0x00, // CompletionCode
+ 0xCF, 0xC2, 0x00, // OpenBMC OEN
+ 0x93, 0xD1, // CRC
+ 0x03, 0x00, // SessionId = 3
+};
+#define VALID_OPEN_RESPONSE_SIZE 8 * sizeof(UINT8)
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+OpenValidResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *BlobId;
+ UINT16 Flags;
+ UINT16 SessionId;
+ VOID *MockResponseResults = NULL;
+ VOID *MockResponseResults2 = NULL;
+ VOID *MockResponseResults3 = NULL;
+
+ Flags = BLOB_TRANSFER_STAT_OPEN_W;
+
+ //
+ // An open call effectively leads to three IPMI commands
+ // 1. GetCount of blobs
+ // 2. Enumerate the requested blob
+ // 3. Open the requested blob
+ //
+ // So we'll push three Ipmi responses in this case
+ //
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_OPEN_RESPONSE_SIZE));
+
+ CopyMem (MockResponseResults, &ValidOpenResponse, VALID_OPEN_RESPONSE_SIZE);
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_OPEN_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ MockResponseResults2 = (UINT8 *)AllocateZeroPool (sizeof
(VALID_ENUMERATE_RESPONSE_SIZE));
+ CopyMem (MockResponseResults2, &ValidEnumerateResponse,
VALID_ENUMERATE_RESPONSE_SIZE);
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults2,
VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ MockResponseResults3 = (UINT8 *)AllocateZeroPool (sizeof
(VALID_GET_COUNT_RESPONSE_SIZE));
+ CopyMem (MockResponseResults3, &ValidGetCountResponse,
VALID_GET_COUNT_RESPONSE_SIZE);
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults3,
VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ BlobId = "/smbios";
+
+ Status = IpmiBlobTransferOpen (BlobId, Flags, &SessionId);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+ UT_ASSERT_EQUAL (SessionId, 3);
+ FreePool (MockResponseResults);
+ return UNIT_TEST_PASSED;
+}
+
+UINT8 ValidReadResponse[] = {
+ 0x00, // CompletionCode
+ 0xCF, 0xC2, 0x00, // OpenBMC OEN
+ 0x21, 0x6F, // CRC
+ 0x00, 0x01, 0x02, 0x03, // Data to read
+};
+
+#define VALID_READ_RESPONSE_SIZE 10 * sizeof(UINT8)
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+ReadValidResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *ResponseData;
+ UINT8 ExpectedDataResponse[4] = { 0x00, 0x01, 0x02, 0x03 };
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_READ_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidReadResponse, VALID_READ_RESPONSE_SIZE);
+ ResponseData = AllocateZeroPool (sizeof (ValidReadResponse));
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_READ_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ Status = IpmiBlobTransferRead (0, 0, 4, ResponseData);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+ UT_ASSERT_MEM_EQUAL (ResponseData, ExpectedDataResponse, 4);
+ FreePool (MockResponseResults);
+ FreePool (ResponseData);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+ReadInvalidBuffer (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ UINT8 *ResponseData;
+ EFI_STATUS Status;
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_READ_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidReadResponse, VALID_READ_RESPONSE_SIZE);
+ ResponseData = NULL;
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_READ_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferRead (0, 0, 4, ResponseData),
NULL);
+
+ FreePool (MockResponseResults);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+WriteValidResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SendData[4] = { 0x00, 0x01, 0x02, 0x03 };
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_NODATA_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidNoDataResponse,
VALID_NODATA_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ Status = IpmiBlobTransferWrite (0, 0, SendData, 4);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+ FreePool (MockResponseResults);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+CommitValidResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SendData[4] = { 0x00, 0x01, 0x02, 0x03 };
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_NODATA_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidNoDataResponse,
VALID_NODATA_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ Status = IpmiBlobTransferCommit (0, 4, SendData);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+ FreePool (MockResponseResults);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+CloseValidResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_NODATA_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidNoDataResponse,
VALID_NODATA_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ Status = IpmiBlobTransferClose (1);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+ FreePool (MockResponseResults);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+DeleteValidResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_NODATA_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidNoDataResponse,
VALID_NODATA_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ Status = IpmiBlobTransferDelete ("/smbios");
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+ FreePool (MockResponseResults);
+ return UNIT_TEST_PASSED;
+}
+
+UINT8 ValidBlobStatResponse[] = {
+ 0x00, // CompletionCode
+ 0xCF, 0xC2, 0x00, // OpenBMC OEN
+ 0x1F, 0x4F, // Crc
+ 0x01, 0x00, // BlobState
+ 0x02, 0x03, 0x04, 0x05, // BlobSize
+ 0x04, // MetaDataLen
+ 0x06, 0x07, 0x08, 0x09, // MetaData
+};
+
+#define VALID_BLOB_STAT_RESPONSE_SIZE 17 * sizeof(UINT8)
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+BlobStatValidResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ EFI_STATUS Status;
+ UINT16 *BlobState;
+ UINT32 *Size;
+ UINT8 *MetadataLength;
+ UINT8 *Metadata;
+ UINT8 *ExpectedMetadata;
+ CHAR8 *BlobId;
+ VOID *MockResponseResults = NULL;
+
+ BlobState = AllocateZeroPool (sizeof (UINT16));
+ Size = AllocateZeroPool (sizeof (UINT32));
+ BlobId = "BlobId";
+ MetadataLength = AllocateZeroPool (sizeof (UINT8));
+ Metadata = AllocateZeroPool (4 * sizeof (UINT8));
+ ExpectedMetadata = AllocateZeroPool (4 * sizeof (UINT8));
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_BLOB_STAT_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidBlobStatResponse,
VALID_BLOB_STAT_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ Status = IpmiBlobTransferStat (BlobId, BlobState, Size, MetadataLength,
Metadata);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+ UT_ASSERT_EQUAL (*BlobState, 1);
+ UT_ASSERT_EQUAL (*Size, 0x05040302);
+ UT_ASSERT_EQUAL (*MetadataLength, 4);
+ UT_ASSERT_MEM_EQUAL (Metadata, ExpectedMetadata, 4);
+ FreePool (MockResponseResults);
+ FreePool (BlobState);
+ FreePool (Size);
+ FreePool (MetadataLength);
+ FreePool (Metadata);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+BlobStatInvalidBuffer (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ UINT8 *Metadata;
+ EFI_STATUS Status;
+ VOID *MockResponseResults = NULL;
+
+ Metadata = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_BLOB_STAT_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidBlobStatResponse,
VALID_BLOB_STAT_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferStat (NULL, 0, 0, 0, Metadata),
NULL);
+
+ FreePool (MockResponseResults);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SessionStatValidResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ EFI_STATUS Status;
+ UINT16 *BlobState;
+ UINT32 *Size;
+ UINT8 *MetadataLength;
+ UINT8 *Metadata;
+ UINT8 *ExpectedMetadata;
+ VOID *MockResponseResults = NULL;
+
+ BlobState = AllocateZeroPool (sizeof (UINT16));
+ Size = AllocateZeroPool (sizeof (UINT32));
+ MetadataLength = AllocateZeroPool (sizeof (UINT8));
+ Metadata = AllocateZeroPool (4 * sizeof (UINT8));
+ ExpectedMetadata = AllocateZeroPool (4 * sizeof (UINT8));
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_BLOB_STAT_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidBlobStatResponse,
VALID_BLOB_STAT_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ Status = IpmiBlobTransferSessionStat (0, BlobState, Size, MetadataLength,
Metadata);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+ UT_ASSERT_EQUAL (*BlobState, 1);
+ UT_ASSERT_EQUAL (*Size, 0x05040302);
+ UT_ASSERT_EQUAL (*MetadataLength, 4);
+ UT_ASSERT_MEM_EQUAL (Metadata, ExpectedMetadata, 4);
+ FreePool (MockResponseResults);
+ FreePool (BlobState);
+ FreePool (Size);
+ FreePool (MetadataLength);
+ FreePool (Metadata);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SessionStatInvalidBuffer (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ UINT8 *Metadata;
+ EFI_STATUS Status;
+ VOID *MockResponseResults = NULL;
+
+ Metadata = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_BLOB_STAT_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidBlobStatResponse,
VALID_BLOB_STAT_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferSessionStat (0, 0, 0, 0,
Metadata), NULL);
+
+ FreePool (MockResponseResults);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that
may
+ consume it.
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+WriteMetaValidResponse (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *MockResponseResults = NULL;
+
+ MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
(VALID_NODATA_RESPONSE_SIZE));
+ CopyMem (MockResponseResults, &ValidNoDataResponse,
VALID_NODATA_RESPONSE_SIZE);
+
+ Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ return UNIT_TEST_ERROR_TEST_FAILED;
+ }
+
+ Status = IpmiBlobTransferWriteMeta (0, 0, NULL, 0);
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
+ FreePool (MockResponseResults);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Initialize the unit test framework, suite, and unit tests for the
+ sample unit tests and run the unit tests.
+ @retval EFI_SUCCESS All test cases were dispatched.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
+ initialize the unit tests.
+**/
+EFI_STATUS
+EFIAPI
+SetupAndRunUnitTests (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UNIT_TEST_FRAMEWORK_HANDLE Framework;
+ UNIT_TEST_SUITE_HANDLE IpmiBlobTransfer;
+
+ Framework = NULL;
+ DEBUG ((DEBUG_INFO, "%a: v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION));
+
+ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME,
gEfiCallerBaseName, UNIT_TEST_VERSION);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to setup Test Framework. Exiting with status =
%r\n", Status));
+ ASSERT (FALSE);
+ return Status;
+ }
+
+ //
+ // Populate the Unit Test Suite.
+ //
+ Status = CreateUnitTestSuite (&IpmiBlobTransfer, Framework, "IPMI Blob Transfer
Tests", "UnitTest.IpmiBlobTransferCB", NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for IPMI Blob Transfer
Tests\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ // CalculateCrc16Ccitt
+ Status = AddTestCase (IpmiBlobTransfer, "Test CRC Calculation", "GoodCrc",
GoodCrc, NULL, NULL, NULL);
+ Status = AddTestCase (IpmiBlobTransfer, "Test Bad CRC Calculation",
"BadCrc", BadCrc, NULL, NULL, NULL);
+ // IpmiBlobTransferSendIpmi
+ Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns bad completion",
"SendIpmiBadCompletion", SendIpmiBadCompletion, NULL, NULL, NULL);
+ Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfully with no data",
"SendIpmiNoDataResponse", SendIpmiNoDataResponse, NULL, NULL, NULL);
+ Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfully with bad OEN",
"SendIpmiBadOenResponse", SendIpmiBadOenResponse, NULL, NULL, NULL);
+ Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfully with bad CRC",
"SendIpmiBadCrcResponse", SendIpmiBadCrcResponse, NULL, NULL, NULL);
+ Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns with valid GetCount data",
"SendIpmiValidCountResponse", SendIpmiValidCountResponse, NULL, NULL, NULL);
+ // IpmiBlobTransferGetCount
+ Status = AddTestCase (IpmiBlobTransfer, "GetCount call with valid data",
"GetCountValidCountResponse", GetCountValidCountResponse, NULL, NULL, NULL);
+ // IpmiBlobTransferEnumerate
+ Status = AddTestCase (IpmiBlobTransfer, "Enumerate call with valid data",
"EnumerateValidResponse", EnumerateValidResponse, NULL, NULL, NULL);
+ Status = AddTestCase (IpmiBlobTransfer, "Enumerate call with invalid output buffer",
"EnumerateInvalidBuffer", EnumerateInvalidBuffer, NULL, NULL, NULL);
+ // IpmiBlobTransferOpen
+ Status = AddTestCase (IpmiBlobTransfer, "Open call with valid data",
"OpenValidResponse", OpenValidResponse, NULL, NULL, NULL);
+ // IpmiBlobTransferRead
+ Status = AddTestCase (IpmiBlobTransfer, "Read call with valid data",
"ReadValidResponse", ReadValidResponse, NULL, NULL, NULL);
+ Status = AddTestCase (IpmiBlobTransfer, "Read call with invalid buffer",
"ReadInvalidBuffer", ReadInvalidBuffer, NULL, NULL, NULL);
+ // IpmiBlobTransferWrite
+ Status = AddTestCase (IpmiBlobTransfer, "Write call with valid data",
"WriteValidResponse", WriteValidResponse, NULL, NULL, NULL);
+ // IpmiBlobTransferCommit
+ Status = AddTestCase (IpmiBlobTransfer, "Commit call with valid data",
"CommitValidResponse", CommitValidResponse, NULL, NULL, NULL);
+ // IpmiBlobTransferClose
+ Status = AddTestCase (IpmiBlobTransfer, "Close call with valid data",
"CloseValidResponse", CloseValidResponse, NULL, NULL, NULL);
+ // IpmiBlobTransferDelete
+ Status = AddTestCase (IpmiBlobTransfer, "Delete call with valid data",
"DeleteValidResponse", DeleteValidResponse, NULL, NULL, NULL);
+ // IpmiBlobTransferStat
+ Status = AddTestCase (IpmiBlobTransfer, "Blob Stat call with valid data",
"BlobStatValidResponse", BlobStatValidResponse, NULL, NULL, NULL);
+ Status = AddTestCase (IpmiBlobTransfer, "Blob Stat call with invalid buffer",
"BlobStatInvalidBuffer", BlobStatInvalidBuffer, NULL, NULL, NULL);
+ // IpmiBlobTransferSessionStat
+ Status = AddTestCase (IpmiBlobTransfer, "Session Stat call with valid data",
"SessionStatValidResponse", SessionStatValidResponse, NULL, NULL, NULL);
+ Status = AddTestCase (IpmiBlobTransfer, "Session Stat call with invalid buffer",
"SessionStatInvalidBuffer", SessionStatInvalidBuffer, NULL, NULL, NULL);
+ // IpmiBlobTransferWriteMeta
+ Status = AddTestCase (IpmiBlobTransfer, "WriteMeta call with valid data",
"WriteMetaValidResponse", WriteMetaValidResponse, NULL, NULL, NULL);
+
+ // Execute the tests.
+ Status = RunAllTestSuites (Framework);
+ return Status;
+}
+
+/**
+ Standard UEFI entry point for target based
+ unit test execution from UEFI Shell.
+**/
+EFI_STATUS
+EFIAPI
+BaseLibUnitTestAppEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return SetupAndRunUnitTests ();
+}
+
+/**
+ Standard POSIX C entry point for host based unit test execution.
+**/
+int
+main (
+ int argc,
+ char *argv[]
+ )
+{
+ return SetupAndRunUnitTests ();
+}
diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md
b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md
new file mode 100644
index 0000000000..9eed5d3728
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md
@@ -0,0 +1,24 @@
+# IPMI Blob Transfer Interface Driver
+
+This DXE module is a UEFI implementation of the Phorphor Blob Transfer
Interface defined in OpenBMC
+https://github.com/openbmc/phosphor-ipmi-blobs
+
+## OpenBMC implements this interface as a protocol, allowing UEFI and BMC to
transfer blobs over IPMI.
+
+### Usage:
+Any DXE module that wishes to use this protocol should do the following:
+1) The module should have a dependency on gEdkiiIpmiBlobTransferProtocolGuid in its inf
"Depex" section
+2) The module should list gEdkiiIpmiBlobTransferProtocolGuid in its inf
"Protocol" section
+3) The module's entry point should do a LocateProtocol on
gEdkiiIpmiBlobTransferProtocolGuid
+
+### A sample flow of protocol usage is as follows:
+1) A call to IpmiBlobTransferOpen ()
+2) Iterative calls to IpmiBlobTransferWrite
+3) A call to IpmiBlobTransferClose ()
+
+### Unit Tests:
+IpmiBlobTransferDxe/UnitTest/ contains host based unit tests of this
implementation.
+Any changes to IpmiBlobTransferDxe should include proof of successful unit
tests.
+
+### Debugging
+To assist in debugging any issues, change BLOB_TRANSFER_DEBUG to desired debug
level, such as DEBUG_ERROR or DEBUG_INFO.
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118993): https://edk2.groups.io/g/devel/message/118993
Mute This Topic: https://groups.io/mt/106115743/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-