From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail05.groups.io (mail05.groups.io [45.79.224.7]) by spool.mail.gandi.net (Postfix) with ESMTPS id 3B3457803CD for ; Wed, 15 May 2024 15:07:28 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=R+Ik3Ryc0jmTEAUdhrfij/SGYWYUfmnbT0xV2imJAh0=; c=relaxed/simple; d=groups.io; h=Received-SPF:From:To:CC:Subject:Date:Message-ID:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Resent-Date:Resent-From:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding:Content-Type; s=20240206; t=1715785646; v=1; b=l0TRHdKSZ2ElsHlSrnjexnLs0Qg1Qp46HLm2Syp3I7EnGvF3NJqQtIipzuL6iKLN5+DMy2wK 1dFmVv9m0YBt61xOBPWUD8X67OIDkaKAp067BXoMuhyuHSZ/ybPOT0n6WOf1G+d3evHkgrCwjxK rPlmFvJuXs5XYYPvcarHb542EjfsvPlQhHLhTipkA8jhpogHTdKyv64g7JXAQpeb/ik4Z5+TfBN IKoLdCziCgimFIfvP8O4OO/GxrLZTcpQgv8HNdQs7pU2DuVu/EYyHYz/J3PyBr8EW5bM6igz83w hLUNo0jiDCNb6c0J+JdfwLvv4BkYfQqPA+8DcD8//aExA== X-Received: by 127.0.0.2 with SMTP id EBeJYY7687511xfFe2bQ5EyM; Wed, 15 May 2024 08:07:26 -0700 X-Received: from NAM12-MW2-obe.outbound.protection.outlook.com (NAM12-MW2-obe.outbound.protection.outlook.com [40.107.244.46]) by mx.groups.io with SMTP id smtpd.web11.18489.1715785644946700528 for ; Wed, 15 May 2024 08:07:25 -0700 X-Received: from MN2PR07CA0023.namprd07.prod.outlook.com (2603:10b6:208:1a0::33) by DM4PR12MB5770.namprd12.prod.outlook.com (2603:10b6:8:61::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7544.55; Wed, 15 May 2024 15:07:09 +0000 X-Received: from MN1PEPF0000F0E0.namprd04.prod.outlook.com (2603:10b6:208:1a0:cafe::34) by MN2PR07CA0023.outlook.office365.com (2603:10b6:208:1a0::33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7587.27 via Frontend Transport; Wed, 15 May 2024 15:07:09 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.118.232) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.118.232 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.118.232; helo=mail.nvidia.com; pr=C X-Received: from mail.nvidia.com (216.228.118.232) by MN1PEPF0000F0E0.mail.protection.outlook.com (10.167.242.38) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7587.21 via Frontend Transport; Wed, 15 May 2024 15:07:08 +0000 X-Received: from drhqmail201.nvidia.com (10.126.190.180) by mail.nvidia.com (10.127.129.5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.4; Wed, 15 May 2024 08:06:38 -0700 X-Received: from NV-CL38DL3.nvidia.com (10.126.230.35) by drhqmail201.nvidia.com (10.126.190.180) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.4; Wed, 15 May 2024 08:06:35 -0700 From: "Nickle Wang via groups.io" To: CC: Abner Chang , Abdul Lateef Attar , Tinh Nguyen , Nhi Pham , Thang Nguyen OS , Mike Maslenkin Subject: [edk2-devel] [edk2-platforms][PATCH v2] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol Date: Wed, 15 May 2024 23:06:29 +0800 Message-ID: <20240515150629.236739-1-nicklew@nvidia.com> MIME-Version: 1.0 X-NVConfidentiality: public X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail203.nvidia.com (10.129.68.9) To drhqmail201.nvidia.com (10.126.190.180) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: MN1PEPF0000F0E0:EE_|DM4PR12MB5770:EE_ X-MS-Office365-Filtering-Correlation-Id: 225ad25a-fbba-489c-bca6-08dc74f0b102 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?0XNA83SiB6MtuP8HdTQsSIP+rcNcpnjRMxP658BgcT6JLEBphdJzFIP2EFxz?= =?us-ascii?Q?dFw05m79+Oi9nNr87Tii6Qvbj1rupt9t42KhF1O1LoeWv70JV4nGJXruZcCd?= =?us-ascii?Q?fRTCXcCcQxkfLHGAsPkq9PiAOe06EjpTUpr9f9GBFVyg9JT4ImycXfyMcrTE?= =?us-ascii?Q?xa0+RThEU7zVBEO2XC/h9sfyPTBfJ5/cUGyx+1qXSdWc583vMDVUVKPlkNKd?= =?us-ascii?Q?Sq6UNyZw84ZOPrUpxM8U1Gat++W+lpBOM4FFbGKgiAGYhiqeXV6hfjFHFMDH?= =?us-ascii?Q?GkuUaFOVW5xo6i0LZ687ftqFvIVM+IY6tgXjdmZNJ87j2IMsF+xP5yl7Br/2?= =?us-ascii?Q?BE8iwWQl7Fl+lowazWKHKT2PCE0eytXoP38Yy/ieIBnPVfqd73C7tOJTiBrU?= =?us-ascii?Q?TFdAH2+tAqNLpJrQC0YZxSwLJdS8lJMZGeFpyfx8FytBy6khpInJxGhZB1oE?= =?us-ascii?Q?HPYed8wlYe8xR0v+/oDLqHVxpSyMW95WkEyQBkuqhlbyelFA98qW9wuM4sA6?= =?us-ascii?Q?+BhwJFuZoPbsHROZKgYUjpuRV54saaHiX02XJtmxGEI2t5IA1NkDvpOww2qV?= =?us-ascii?Q?84KDIx62tPiyVIFiQCm5k21+tctyAOZPHP17nZ3UQS01yXtavtmw9vciKzga?= =?us-ascii?Q?KOJ8oZUrY6/gL3yW9PT2wZBOa5zvcML1Ri8KzJ33Mu4GPjna3uJBGXdeh1Gr?= =?us-ascii?Q?dalLRsFQGz9RVL5eS4MQXQpZorf5Q3r79Q8msg6eTScQg7w30/kLjcXm1hjT?= =?us-ascii?Q?pPs07NywEMbytYMOkrNHQyOHqTjMsBcSJnMLdFKo8yC+UC2/onTPgjwIXKCZ?= =?us-ascii?Q?sBthLo4i0CP6Olgy11QZAgn9OIWy+Z9no/OSGqvvGgClYuk+cDJkRMUHmZ5b?= =?us-ascii?Q?lnpWvxylP0CoCoGDqeFsK0+Msx8AE6gdX/NuX6w/h5tanr9aiNIPWJyRCrsl?= =?us-ascii?Q?4yD4/7ctNUgZtqbJ9UCZjG8ZL/epkC/XnuzZOerqRy5Sv2/LDFhAUXN7lmQm?= =?us-ascii?Q?bjNqisA920R9AlTQaXrlmao4i1llD3zy+9kr8xquN67mBo6tb213YtUhZWcs?= =?us-ascii?Q?VeKjuPKD7/I7nxItGv/MpcXm4h54F09qH2/+NS5adDq6QD2uLfqsFMRjjmsw?= =?us-ascii?Q?vaxSsSWbb/9jx3PPZ6hll4M0UtGKCHWI++4TFFGYcQdt9N8miWgXt1clHf1G?= =?us-ascii?Q?UCg9z+i1O39ZEhnmFsh/8TgnxQR3nAZXM7uZnIXieWRGi9mhh4w5xuUP+Xiv?= =?us-ascii?Q?u9D1E2D9aLMMgauG9LZjOJVCX7j3jexYUOPPTggW5V+cOPz9TNKFs+SG3dKe?= =?us-ascii?Q?8kd+IrNMj7dDoiIoqGT63Mx6iheCft7dPokXAobu8bMfQ05yDhzaGuegNtql?= =?us-ascii?Q?OMot2jnuwbdhOPNrj1x122t3iO5c?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 15 May 2024 15:07:08.8456 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 225ad25a-fbba-489c-bca6-08dc74f0b102 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a;Ip=[216.228.118.232];Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: MN1PEPF0000F0E0.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM4PR12MB5770 Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Resent-Date: Wed, 15 May 2024 08:07:25 -0700 Resent-From: nicklew@nvidia.com Reply-To: devel@edk2.groups.io,nicklew@nvidia.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: QTfhTrb2mPGH5ZzBIG1tIU7hx7686176AA= Content-Transfer-Encoding: quoted-printable Content-Type: text/plain X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20240206 header.b=l0TRHdKS; dmarc=pass (policy=none) header.from=groups.io; spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 45.79.224.7 as permitted sender) smtp.mailfrom=bounce@groups.io REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3D4773 This change implements the blob transfer protocol used in OpenBmc documented here: https://github.com/openbmc/phosphor-ipmi-blobs Signed-off-by: Nick Ramirez Co-authored-by: Nickle Wang Cc: Abner Chang Cc: Abdul Lateef Attar Cc: Tinh Nguyen Cc: Nhi Pham Cc: Thang Nguyen OS Cc: Mike Maslenkin --- .../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/IpmiBlobTran= sfer.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/Mana= geabilityPkg/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.
+# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved= . # SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -58,6 +59,8 @@ gEdkiiPldmProtocolGuid =3D { 0x60997616, 0xDB70, 0x4B5F, = { 0x86, 0xA4, 0x09, 0x58, 0xA3, 0x71, 0x47, 0xB4 } } gEdkiiPldmSmbiosTransferProtocolGuid =3D { 0xFA431C3C, 0x816B, 0x4B32, = { 0xA3, 0xE0, 0xAD, 0x9B, 0x7F, 0x64, 0x27, 0x2E } } gEdkiiMctpProtocolGuid =3D { 0xE93465C1, 0x9A31, 0x4C96, = { 0x92, 0x56, 0x22, 0x0A, 0xE1, 0x80, 0xB4, 0x1B } } + ## Include/Protocol/IpmiBlobTransfer.h + gEdkiiIpmiBlobTransferProtocolGuid =3D { 0x05837c75, 0x1d65, 0x468b, = { 0xb1, 0xc2, 0x81, 0xaf, 0x9a, 0x31, 0x5b, 0x2c } } =20 [PcdsFixedAtBuild] ## This value is the MCTP Interface source and destination endpoint ID f= or 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.
+# 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 =3D=3D T= RUE ManageabilityPkg/Universal/IpmiProtocol/Dxe/IpmiProtocolDxe.inf + ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf !endif =20 [Components.X64] diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBl= obTransferDxe.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe= /IpmiBlobTransferDxe.inf new file mode 100644 index 0000000000..108f4bb5f8 --- /dev/null +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTrans= ferDxe.inf @@ -0,0 +1,39 @@ +## @file +# IPMI Blob Transfer Protocol DXE Driver. +# +# Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights re= served. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D IpmiBlobTransferDxe + FILE_GUID =3D 6357c804-78bb-4b0c-abdf-c75df942f319 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D 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/UnitTe= st/IpmiBlobTransferTestUnitTestsHost.inf b/Features/ManageabilityPkg/Univer= sal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf new file mode 100644 index 0000000000..dab6858f09 --- /dev/null +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ipmi= BlobTransferTestUnitTestsHost.inf @@ -0,0 +1,40 @@ +## @file +# Unit tests of the Ipmi blob transfer driver that are run from a host env= ironment. +# +# Copyright (c) 2020-2024, NVIDIA CORPORATION & AFFILIATES. All rights res= erved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010006 + BASE_NAME =3D IpmiBlobTransferDxeUnitTestsHost + FILE_GUID =3D 1f5d4095-ea52-432c-b078-86097fef6004 + MODULE_TYPE =3D HOST_APPLICATION + VERSION_STRING =3D 1.0 + +# +# The following information is for reference only +# and not required by the build tools. +# +# VALID_ARCHITECTURES =3D 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 res= erved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + + @Par: https://github.com/openbmc/phosphor-ipmi-blobs/blob/master/README.= md +**/ +#include +#include +#include +#include + +#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[] =3D { 0xCF, 0xC2, 0x00 }; + +// +// Blob Transfer Function Prototypes +// + +/** + This function retrieves the count of blob transfers available through th= e IPMI. + + @param[out] Count The number of active blobs + + @retval EFI_SUCCESS Successfully retrieved the number of acti= ve 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 enum= erate + @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 open= ed + @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 t= o 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 t= o 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 I= PMI. + + @param[in] SessionId The session ID returned from a call t= o 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 BlobI= d 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 stati= stics 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 metada= ta for + @param[in] Offset The offset of the metadata to write t= o + @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 wr= itten. + @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/Intern= alIpmiBlobTransfer.h b/Features/ManageabilityPkg/Universal/IpmiBlobTransfer= Dxe/InternalIpmiBlobTransfer.h new file mode 100644 index 0000000000..3e90dc6871 --- /dev/null +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiB= lobTransfer.h @@ -0,0 +1,407 @@ +/** @file + + Headers for IPMI Blob Transfer driver + + Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights res= erved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#define PROTOCOL_RESPONSE_OVERHEAD (4 * sizeof(UINT8)) // 1 byte co= mpletion code + 3 bytes OEN +#define BLOB_MAX_DATA_PER_PACKET 64 + +// Subcommands for this protocol +typedef enum { + IpmiBlobTransferSubcommandGetCount =3D 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 th= e IPMI. + + @param[out] Count The number of active blobs + + @retval EFI_SUCCESS Successfully retrieved the number of acti= ve 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 enum= erate + @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 open= ed + @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 t= o 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 t= o 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 I= PMI. + + @param[in] SessionId The session ID returned from a call t= o 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 BlobI= d 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 stati= stics 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 metada= ta for + @param[in] Offset The offset of the metadata to write t= o + @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 wr= itten. + @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/IpmiBl= obTransferDxe.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/I= pmiBlobTransferDxe.c new file mode 100644 index 0000000000..b8a2db193b --- /dev/null +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTrans= ferDxe.c @@ -0,0 +1,872 @@ +/** @file + + IPMI Blob Transfer driver + + Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights res= erved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include + +#include "InternalIpmiBlobTransfer.h" + +#define BLOB_TRANSFER_DEBUG DEBUG_MANAGEABILITY + +STATIC CONST EDKII_IPMI_BLOB_TRANSFER_PROTOCOL mIpmiBlobTransfer =3D { + (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)*IpmiBlobTransferSession= Stat, + (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 =3D 0xFFFF; + Poly =3D 0x1021; + XorFlag =3D FALSE; + + for (Index =3D 0; Index < (DataSize + 2); ++Index) { + for (BitIndex =3D 0; BitIndex < 8; ++BitIndex) { + XorFlag =3D (Crc & 0x8000) ? TRUE : FALSE; + Crc <<=3D 1; + if ((Index < DataSize) && (Data[Index] & (1 << (7 - BitIndex)))) { + Crc++; + } + + if (XorFlag =3D=3D TRUE) { + Crc ^=3D 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, + OUT UINT8 *ResponseData, + OUT UINT32 *ResponseDataSize + ) +{ + EFI_STATUS Status; + UINT8 CompletionCode; + UINT16 Crc; + UINT8 Oen[3]; + UINT8 *IpmiSendData; + UINT32 IpmiSendDataSize; + UINT8 *IpmiResponseData; + UINT8 *ModifiedResponseData; + UINT32 IpmiResponseDataSize; + IPMI_BLOB_TRANSFER_HEADER Header; + + Crc =3D 0; + + // + // Prepend the proper header to the SendData + // + IpmiSendDataSize =3D (sizeof (IPMI_BLOB_TRANSFER_HEADER)); + if (SendDataSize) { + IpmiSendDataSize +=3D sizeof (Crc) + (sizeof (UINT8) * SendDataSize); + } + + IpmiSendData =3D AllocateZeroPool (IpmiSendDataSize); + if (IpmiSendData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Header.OEN[0] =3D OpenBmcOen[0]; + Header.OEN[1] =3D OpenBmcOen[1]; + Header.OEN[2] =3D OpenBmcOen[2]; + Header.SubCommand =3D SubCommand; + CopyMem (IpmiSendData, &Header, sizeof (IPMI_BLOB_TRANSFER_HEADER)); + if (SendDataSize) { + // + // Calculate the Crc of the send data + // + Crc =3D CalculateCrc16Ccitt (SendData, SendDataSize); + CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER), &Crc, size= of (UINT16)); + CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER) + sizeof (U= INT16), 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 =3D 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: ", __fun= c__, IpmiSendDataSize)); + for (i =3D 0; i < IpmiSendDataSize; i++) { + DEBUG ((BLOB_TRANSFER_DEBUG, "%02x", *((UINT8 *)IpmiSendData + i))); + } + + DEBUG ((BLOB_TRANSFER_DEBUG, "\n")); + DEBUG_CODE_END (); + + IpmiResponseDataSize =3D (*ResponseDataSize + PROTOCOL_RESPONSE_OVERHEAD= ); + // + // If expecting data to be returned, we have to also account for the 16 = bit CRC + // + if (*ResponseDataSize) { + IpmiResponseDataSize +=3D sizeof (Crc); + } + + IpmiResponseData =3D AllocateZeroPool (IpmiResponseDataSize); + if (IpmiResponseData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status =3D IpmiSubmitCommand ( + IPMI_NETFN_OEM, + IPMI_OEM_BLOB_TRANSFER_CMD, + (VOID *)IpmiSendData, + IpmiSendDataSize, + (VOID *)IpmiResponseData, + &IpmiResponseDataSize + ); + + FreePool (IpmiSendData); + ModifiedResponseData =3D IpmiResponseData; + + DEBUG_CODE_BEGIN (); + DEBUG ((BLOB_TRANSFER_DEBUG, "%a: IPMI Response:\n", __func__)); + DEBUG ((BLOB_TRANSFER_DEBUG, "%a: ResponseDataSize: %02x\nData: ", __fun= c__, IpmiResponseDataSize)); + UINT8 i; + + for (i =3D 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 =3D *ModifiedResponseData; + if (CompletionCode !=3D IPMI_COMP_CODE_NORMAL) { + DEBUG ((DEBUG_ERROR, "%a: Returning because CompletionCode =3D 0x%x\n"= , __func__, CompletionCode)); + FreePool (IpmiResponseData); + return EFI_PROTOCOL_ERROR; + } + + // Strip completion code, we are done with it + ModifiedResponseData =3D ModifiedResponseData + sizeof (CompletionCode)= ; + IpmiResponseDataSize -=3D sizeof (CompletionCode); + + // Check OEN code and verify it matches the OpenBMC OEN + CopyMem (Oen, ModifiedResponseData, sizeof (OpenBmcOen)); + if (CompareMem (Oen, OpenBmcOen, sizeof (OpenBmcOen)) !=3D 0) { + FreePool (IpmiResponseData); + return EFI_PROTOCOL_ERROR; + } + + if (IpmiResponseDataSize =3D=3D sizeof (OpenBmcOen)) { + // + // In this case, there was no response data sent. This is not an error= . + // Some messages do not require a response. + // + *ResponseDataSize =3D 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 =3D ModifiedResponseData + sizeof (Oen); + IpmiResponseDataSize -=3D sizeof (Oen); + // Then validate the Crc + CopyMem (&Crc, ModifiedResponseData, sizeof (Crc)); + ModifiedResponseData =3D ModifiedResponseData + sizeof (Crc); + IpmiResponseDataSize -=3D sizeof (Crc); + + if (Crc =3D=3D CalculateCrc16Ccitt (ModifiedResponseData, IpmiResponse= DataSize)) { + CopyMem (ResponseData, ModifiedResponseData, IpmiResponseDataSize); + CopyMem (ResponseDataSize, &IpmiResponseDataSize, sizeof (IpmiRespon= seDataSize)); + FreePool (IpmiResponseData); + return EFI_SUCCESS; + } else { + FreePool (IpmiResponseData); + return EFI_CRC_ERROR; + } + } +} + +/** + This function retrieves the count of blob transfers available through th= e IPMI. + + @param[out] Count The number of active blobs + + @retval EFI_SUCCESS Successfully retrieved the number of acti= ve blobs. + @retval Other An error occurred +**/ +EFI_STATUS +IpmiBlobTransferGetCount ( + OUT UINT32 *Count + ) +{ + EFI_STATUS Status; + UINT8 *ResponseData; + UINT32 ResponseDataSize; + + if (Count =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + ResponseDataSize =3D sizeof (IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE); + ResponseData =3D AllocateZeroPool (ResponseDataSize); + if (ResponseData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount,= NULL, 0, (UINT8 *)ResponseData, &ResponseDataSize); + if (!EFI_ERROR (Status)) { + *Count =3D ((IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE *)ResponseData)->Bl= obCount; + } + + FreePool (ResponseData); + return Status; +} + +/** + This function enumerates blob transfers available through the IPMI. + + @param[in] BlobIndex The 0-based Index of the blob to enum= erate + @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 =3D=3D NULL) { + ASSERT (FALSE); + return EFI_ABORTED; + } + + ResponseDataSize =3D sizeof (IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_RESPONSE)= ; + ResponseData =3D AllocateZeroPool (ResponseDataSize); + if (ResponseData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Format send data + // + SendDataSize =3D sizeof (IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA); + SendData =3D AllocateZeroPool (SendDataSize); + if (SendData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ((IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA *)SendData)->BlobIndex =3D= BlobIndex; + + Status =3D 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 open= ed + @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 =3D=3D NULL) || (SessionId =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Before opening a blob, need to check if it exists + // + Status =3D IpmiBlobTransferGetCount (&NumBlobs); + if (EFI_ERROR (Status) || (NumBlobs =3D=3D 0)) { + if (Status =3D=3D EFI_UNSUPPORTED) { + return Status; + } + + DEBUG ((DEBUG_ERROR, "%a: Could not find any blobs: %r\n", __func__, S= tatus)); + return EFI_NOT_FOUND; + } + + BlobSearch =3D AllocateZeroPool (sizeof (CHAR8) * BLOB_MAX_DATA_PER_PACK= ET); + if (BlobSearch =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + BlobFound =3D FALSE; + for (Index =3D 0; Index < NumBlobs; Index++) { + Status =3D IpmiBlobTransferEnumerate (Index, BlobSearch); + if ((!EFI_ERROR (Status)) && (AsciiStrCmp (BlobSearch, BlobId) =3D=3D = 0)) { + BlobFound =3D 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 =3D sizeof (IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE); + ResponseData =3D AllocateZeroPool (ResponseDataSize); + if (ResponseData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Format send data + // + SendDataSize =3D sizeof (((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA *)Send= Data)->Flags) + ((AsciiStrLen (BlobId)) * sizeof (CHAR8)) + sizeof (CHAR8); + SendData =3D AllocateZeroPool (SendDataSize); + if (SendData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA *)SendData)->Blob= Id, AsciiStrSize (BlobId) / sizeof (CHAR8), BlobId); + ((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA *)SendData)->Flags =3D Flags; + // append null char to SendData + SendData[SendDataSize-1] =3D 0; + + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandOpen, Sen= dData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize); + if (!EFI_ERROR (Status)) { + *SessionId =3D ((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 t= o BlobOpen + @param[in] Offset The offset of the blob from which to = start reading + @param[in] RequestedSize The length of data to read + @param[out] Data Data read from the blob + + @retval EFI_SUCCESS Successfully read from the blob. + @retval Other An error occurred +**/ +EFI_STATUS +IpmiBlobTransferRead ( + IN UINT16 SessionId, + IN UINT32 Offset, + IN UINT32 RequestedSize, + OUT UINT8 *Data + ) +{ + EFI_STATUS Status; + UINT8 *SendData; + UINT8 *ResponseData; + UINT32 SendDataSize; + UINT32 ResponseDataSize; + + if (Data =3D=3D NULL) { + ASSERT (FALSE); + return EFI_ABORTED; + } + + ResponseDataSize =3D RequestedSize * sizeof (UINT8); + ResponseData =3D AllocateZeroPool (ResponseDataSize); + if (ResponseData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Format send data + // + SendDataSize =3D sizeof (IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA); + SendData =3D AllocateZeroPool (SendDataSize); + if (SendData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)->SessionId =3D = SessionId; + ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)->Offset =3D = Offset; + ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)->RequestedSize =3D = RequestedSize; + + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandRead, Sen= dData, 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 t= o 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Format send data + // + SendDataSize =3D sizeof (SessionId) + sizeof (Offset) + WriteLength; + SendData =3D AllocateZeroPool (SendDataSize); + if (SendData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->SessionId =3D Ses= sionId; + ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset =3D Off= set; + CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Data, Da= ta, sizeof (UINT8) * WriteLength); + + ResponseDataSize =3D 0; + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcomman= dWrite, 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Format send data + // + SendDataSize =3D sizeof (SessionId) + sizeof (CommitDataLength) + Commit= DataLength; + SendData =3D AllocateZeroPool (SendDataSize); + if (SendData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)->SessionId = =3D SessionId; + ((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)->CommitDataLength= =3D CommitDataLength; + CopyMem (((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)->CommitD= ata, CommitData, sizeof (UINT8) * CommitDataLength); + + ResponseDataSize =3D 0; + + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandCommit, S= endData, SendDataSize, NULL, &ResponseDataSize); + + FreePool (SendData); + return Status; +} + +/** + This function close a session associated with a blob transfer over the I= PMI. + + @param[in] SessionId The session ID returned from a call t= o 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 =3D sizeof (IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA); + SendData =3D AllocateZeroPool (SendDataSize); + if (SendData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ((IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA *)SendData)->SessionId =3D Ses= sionId; + + ResponseDataSize =3D 0; + + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandClose, Se= ndData, 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Format send data + // + SendDataSize =3D sizeof (IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA); + SendData =3D AllocateZeroPool (SendDataSize); + if (SendData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA *)SendData)->Bl= obId, AsciiStrLen (BlobId), BlobId); + + ResponseDataSize =3D 0; + + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandDelete, S= endData, SendDataSize, NULL, &ResponseDataSize); + + FreePool (SendData); + return Status; +} + +/** + This function retrieve the status of a specific blob identified by BlobI= d 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 =3D=3D NULL) || (BlobState =3D=3D NULL) || (Size =3D=3D NULL= ) || (MetadataLength =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (Metadata =3D=3D NULL) { + ASSERT (FALSE); + return EFI_ABORTED; + } + + ResponseDataSize =3D sizeof (IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE); + ResponseData =3D AllocateZeroPool (ResponseDataSize); + if (ResponseData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Format send data + // + SendDataSize =3D sizeof (IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA); + SendData =3D AllocateZeroPool (SendDataSize); + if (SendData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA *)SendData)->Blob= Id, BLOB_MAX_DATA_PER_PACKET, BlobId); + + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandStat, Sen= dData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize); + if (!EFI_ERROR (Status)) { + *BlobState =3D ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)Response= Data)->BlobState; + *Size =3D ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)Response= Data)->Size; + *MetadataLength =3D ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)Response= Data)->MetaDataLen; + + CopyMem (&Metadata, &((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)Respons= eData)->MetaData, sizeof (((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)Respons= eData)->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 stati= stics 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 =3D=3D NULL) || (Size =3D=3D NULL) || (MetadataLength =3D= =3D NULL) || (Metadata =3D=3D NULL)) { + ASSERT (FALSE); + return EFI_ABORTED; + } + + ResponseDataSize =3D sizeof (IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE); + ResponseData =3D AllocateZeroPool (ResponseDataSize); + if (ResponseData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Format send data + // + SendDataSize =3D sizeof (IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA)= ; + SendData =3D AllocateZeroPool (SendDataSize); + if (SendData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA *)SendData)->SessionId = =3D SessionId; + + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandSessionSt= at, SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize); + + if (!EFI_ERROR (Status)) { + *BlobState =3D ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE *)= ResponseData)->BlobState; + *Size =3D ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE *)= ResponseData)->Size; + *MetadataLength =3D ((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_RE= SPONSE *)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 metada= ta for + @param[in] Offset The offset of the metadata to write t= o + @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 wr= itten. + @retval Other An error occurred +**/ +EFI_STATUS +IpmiBlobTransferWriteMeta ( + IN UINT16 SessionId, + IN UINT32 Offset, + IN UINT8 *Data, + IN UINT32 WriteLength + ) +{ + EFI_STATUS Status; + UINT8 *SendData; + UINT32 SendDataSize; + UINT32 ResponseDataSize; + + if (Data =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Format send data + // + SendDataSize =3D sizeof (IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA); + SendData =3D AllocateZeroPool (SendDataSize); + if (SendData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->SessionId =3D Ses= sionId; + ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset =3D Off= set; + CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Data, Da= ta, sizeof (UINT8) * WriteLength); + + ResponseDataSize =3D 0; + + Status =3D 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 includ= ing + both device drivers and bus drivers. + + @param[in] ImageHandle The firmware allocated handle for the UEFI= image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The operation completed successfully. + @retval Others An unexpected error occurred. + +**/ +EFI_STATUS +EFIAPI +IpmiBlobTransferDxeDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEdkiiIpmiBlobTransferProtocolGuid, + (VOID *)&mIpmiBlobTransfer, + NULL + ); +} diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTe= st/IpmiBlobTransferTestUnitTests.c b/Features/ManageabilityPkg/Universal/Ip= miBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c new file mode 100644 index 0000000000..0f728527b8 --- /dev/null +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ipmi= BlobTransferTestUnitTests.c @@ -0,0 +1,1113 @@ +/** @file +* +* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. +* +* SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AF= FILIATES +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include "../InternalIpmiBlobTransfer.h" + +#define UNIT_TEST_NAME "IPMI Blob Transfer Unit Tests" +#define UNIT_TEST_VERSION "1.0" + +UINT8 InvalidCompletion[] =3D { + 0xC0, // CompletionCode + 0xCF, 0xC2, 0x00, // OpenBMC OEN +}; +#define INVALID_COMPLETION_SIZE 4 * sizeof(UINT8) + +UINT8 NoDataResponse[] =3D { + 0x00, // CompletionCode + 0xCF, 0xC2, 0x00, // OpenBMC OEN +}; +#define NO_DATA_RESPONSE_SIZE 4 * sizeof(UINT8) + +UINT8 BadOenResponse[] =3D { + 0x00, // CompletionCode + 0xFF, 0xC2, 0x00, // Wrong OEN +}; +#define BAD_OEN_RESPONSE_SIZE 4 * sizeof(UINT8) + +UINT8 BadCrcResponse[] =3D { + 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[] =3D { + 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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] =3D { 0x12, 0x34, 0x56, 0x78, 0x90 }; + UINTN DataSize; + UINT16 Crc; + + DataSize =3D sizeof (Data); + + Crc =3D 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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] =3D { 0x12, 0x34, 0x56, 0x78, 0x90 }; + UINTN DataSize; + UINT16 Crc; + + DataSize =3D sizeof (Data); + + Crc =3D 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (INVALID_COMPLETION_SI= ZE); + ResponseDataSize =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32)); + CopyMem (MockResponseResults, &InvalidCompletion, INVALID_COMPLETION_SIZ= E); + + MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, INVALID_COMPLETION_= SIZE, EFI_SUCCESS); + + ResponseData =3D (UINT8 *)AllocateZeroPool (*ResponseDataSize); + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGet= Count, 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (NO_DATA_RESPONSE_SIZE= ); + ResponseDataSize =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32)); + CopyMem (MockResponseResults, &NoDataResponse, NO_DATA_RESPONSE_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, NO_DATA_= RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + ResponseData =3D (UINT8 *)AllocateZeroPool (sizeof (NoDataResponse)); + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGet= Count, 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (BAD_OEN_RESPONSE_SIZE= ); + ResponseDataSize =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32)); + CopyMem (MockResponseResults, &BadOenResponse, BAD_OEN_RESPONSE_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, BAD_OEN_= RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + ResponseData =3D (UINT8 *)AllocateZeroPool (sizeof (BadOenResponse)); + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGet= Count, 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (BAD_CRC_RESPO= NSE_SIZE)); + ResponseDataSize =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32)); + CopyMem (MockResponseResults, &BadCrcResponse, BAD_CRC_RESPONSE_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, BAD_CRC_= RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + ResponseData =3D (UINT8 *)AllocateZeroPool (sizeof (BadCrcResponse)); + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGet= Count, NULL, 0, ResponseData, ResponseDataSize); + + UT_ASSERT_STATUS_EQUAL (Status, EFI_CRC_ERROR); + FreePool (MockResponseResults); + FreePool (ResponseDataSize); + FreePool (ResponseData); + return UNIT_TEST_PASSED; +} + +UINT8 ValidGetCountResponse[] =3D { + 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_GET_COU= NT_RESPONSE_SIZE)); + ResponseDataSize =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32)); + CopyMem (MockResponseResults, &ValidGetCountResponse, VALID_GET_COUNT_RE= SPONSE_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_GE= T_COUNT_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + ResponseData =3D AllocateZeroPool (sizeof (ValidGetCountResponse)); + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGet= Count, 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + Count =3D 0; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_GET_COU= NT_RESPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidGetCountResponse, VALID_GET_COUNT_RE= SPONSE_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_GE= T_COUNT_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + Status =3D IpmiBlobTransferGetCount (&Count); + + UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); + UT_ASSERT_EQUAL (Count, 1); + FreePool (MockResponseResults); + return UNIT_TEST_PASSED; +} + +UINT8 ValidEnumerateResponse[] =3D { + 0x00, // CompletionCode + 0xCF, 0xC2, 0x00, // OpenBMC OEN + 0x81, 0x13, // CRC + 0x2F, 0x73, 0x6D, 0x62, // Data =3D "/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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_ENUMERA= TE_RESPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidEnumerateResponse, VALID_ENUMERATE_R= ESPONSE_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_EN= UMERATE_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + BlobId =3D AllocateZeroPool (sizeof (CHAR8) * BLOB_MAX_DATA_PER_PACKET); + + Status =3D 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_ENUMERA= TE_RESPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidEnumerateResponse, VALID_ENUMERATE_R= ESPONSE_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_EN= UMERATE_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + BlobId =3D NULL; + + UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferEnumerate (0, BlobId), NULL); + + FreePool (MockResponseResults); + return UNIT_TEST_PASSED; +} + +UINT8 ValidOpenResponse[] =3D { + 0x00, // CompletionCode + 0xCF, 0xC2, 0x00, // OpenBMC OEN + 0x93, 0xD1, // CRC + 0x03, 0x00, // SessionId =3D 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + VOID *MockResponseResults2 =3D NULL; + VOID *MockResponseResults3 =3D NULL; + + Flags =3D 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 =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_OPEN_RE= SPONSE_SIZE)); + + CopyMem (MockResponseResults, &ValidOpenResponse, VALID_OPEN_RESPONSE_SI= ZE); + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_OP= EN_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + MockResponseResults2 =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_ENUMER= ATE_RESPONSE_SIZE)); + CopyMem (MockResponseResults2, &ValidEnumerateResponse, VALID_ENUMERATE_= RESPONSE_SIZE); + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults2, VALID_E= NUMERATE_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + MockResponseResults3 =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_GET_CO= UNT_RESPONSE_SIZE)); + CopyMem (MockResponseResults3, &ValidGetCountResponse, VALID_GET_COUNT_R= ESPONSE_SIZE); + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults3, VALID_G= ET_COUNT_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + BlobId =3D "/smbios"; + + Status =3D IpmiBlobTransferOpen (BlobId, Flags, &SessionId); + + UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); + UT_ASSERT_EQUAL (SessionId, 3); + FreePool (MockResponseResults); + return UNIT_TEST_PASSED; +} + +UINT8 ValidReadResponse[] =3D { + 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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] =3D { 0x00, 0x01, 0x02, 0x03 }; + VOID *MockResponseResults =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_READ_RE= SPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidReadResponse, VALID_READ_RESPONSE_SI= ZE); + ResponseData =3D AllocateZeroPool (sizeof (ValidReadResponse)); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_RE= AD_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + Status =3D 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_READ_RE= SPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidReadResponse, VALID_READ_RESPONSE_SI= ZE); + ResponseData =3D NULL; + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_RE= AD_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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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] =3D { 0x00, 0x01, 0x02, 0x03 }; + VOID *MockResponseResults =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_NODATA_= RESPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPONS= E_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_NO= DATA_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + Status =3D 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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] =3D { 0x00, 0x01, 0x02, 0x03 }; + VOID *MockResponseResults =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_NODATA_= RESPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPONS= E_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_NO= DATA_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + Status =3D 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_NODATA_= RESPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPONS= E_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_NO= DATA_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + Status =3D 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_NODATA_= RESPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPONS= E_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_NO= DATA_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + Status =3D IpmiBlobTransferDelete ("/smbios"); + + UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); + FreePool (MockResponseResults); + return UNIT_TEST_PASSED; +} + +UINT8 ValidBlobStatResponse[] =3D { + 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + BlobState =3D AllocateZeroPool (sizeof (UINT16)); + Size =3D AllocateZeroPool (sizeof (UINT32)); + BlobId =3D "BlobId"; + MetadataLength =3D AllocateZeroPool (sizeof (UINT8)); + Metadata =3D AllocateZeroPool (4 * sizeof (UINT8)); + ExpectedMetadata =3D AllocateZeroPool (4 * sizeof (UINT8)); + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_BLOB_ST= AT_RESPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidBlobStatResponse, VALID_BLOB_STAT_RE= SPONSE_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_BL= OB_STAT_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + Status =3D 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + Metadata =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_BLOB_ST= AT_RESPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidBlobStatResponse, VALID_BLOB_STAT_RE= SPONSE_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_BL= OB_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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + BlobState =3D AllocateZeroPool (sizeof (UINT16)); + Size =3D AllocateZeroPool (sizeof (UINT32)); + MetadataLength =3D AllocateZeroPool (sizeof (UINT8)); + Metadata =3D AllocateZeroPool (4 * sizeof (UINT8)); + ExpectedMetadata =3D AllocateZeroPool (4 * sizeof (UINT8)); + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_BLOB_ST= AT_RESPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidBlobStatResponse, VALID_BLOB_STAT_RE= SPONSE_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_BL= OB_STAT_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + Status =3D IpmiBlobTransferSessionStat (0, BlobState, Size, MetadataLeng= th, 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + Metadata =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_BLOB_ST= AT_RESPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidBlobStatResponse, VALID_BLOB_STAT_RE= SPONSE_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_BL= OB_STAT_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferSessionStat (0, 0, 0, 0, Metad= ata), 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 th= at may + consume it. + @retval UNIT_TEST_PASSED The Unit test has completed and th= e 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 =3D NULL; + + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_NODATA_= RESPONSE_SIZE)); + CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPONS= E_SIZE); + + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_NO= DATA_RESPONSE_SIZE, EFI_SUCCESS); + if (EFI_ERROR (Status)) { + return UNIT_TEST_ERROR_TEST_FAILED; + } + + Status =3D 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 =3D NULL; + DEBUG ((DEBUG_INFO, "%a: v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION)); + + Status =3D InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCaller= BaseName, UNIT_TEST_VERSION); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to setup Test Framework. Exiting with sta= tus =3D %r\n", Status)); + ASSERT (FALSE); + return Status; + } + + // + // Populate the Unit Test Suite. + // + Status =3D CreateUnitTestSuite (&IpmiBlobTransfer, Framework, "IPMI Blob= Transfer Tests", "UnitTest.IpmiBlobTransferCB", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for IPMI Blob Tran= sfer Tests\n")); + Status =3D EFI_OUT_OF_RESOURCES; + return Status; + } + + // CalculateCrc16Ccitt + Status =3D AddTestCase (IpmiBlobTransfer, "Test CRC Calculation", "GoodC= rc", GoodCrc, NULL, NULL, NULL); + Status =3D AddTestCase (IpmiBlobTransfer, "Test Bad CRC Calculation", "B= adCrc", BadCrc, NULL, NULL, NULL); + // IpmiBlobTransferSendIpmi + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns bad complet= ion", "SendIpmiBadCompletion", SendIpmiBadCompletion, NULL, NULL, NULL); + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfull= y with no data", "SendIpmiNoDataResponse", SendIpmiNoDataResponse, NULL, NU= LL, NULL); + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfull= y with bad OEN", "SendIpmiBadOenResponse", SendIpmiBadOenResponse, NULL, NU= LL, NULL); + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfull= y with bad CRC", "SendIpmiBadCrcResponse", SendIpmiBadCrcResponse, NULL, NU= LL, NULL); + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns with valid = GetCount data", "SendIpmiValidCountResponse", SendIpmiValidCountResponse, N= ULL, NULL, NULL); + // IpmiBlobTransferGetCount + Status =3D AddTestCase (IpmiBlobTransfer, "GetCount call with valid data= ", "GetCountValidCountResponse", GetCountValidCountResponse, NULL, NULL, NU= LL); + // IpmiBlobTransferEnumerate + Status =3D AddTestCase (IpmiBlobTransfer, "Enumerate call with valid dat= a", "EnumerateValidResponse", EnumerateValidResponse, NULL, NULL, NULL); + Status =3D AddTestCase (IpmiBlobTransfer, "Enumerate call with invalid o= utput buffer", "EnumerateInvalidBuffer", EnumerateInvalidBuffer, NULL, NULL= , NULL); + // IpmiBlobTransferOpen + Status =3D AddTestCase (IpmiBlobTransfer, "Open call with valid data", "= OpenValidResponse", OpenValidResponse, NULL, NULL, NULL); + // IpmiBlobTransferRead + Status =3D AddTestCase (IpmiBlobTransfer, "Read call with valid data", "= ReadValidResponse", ReadValidResponse, NULL, NULL, NULL); + Status =3D AddTestCase (IpmiBlobTransfer, "Read call with invalid buffer= ", "ReadInvalidBuffer", ReadInvalidBuffer, NULL, NULL, NULL); + // IpmiBlobTransferWrite + Status =3D AddTestCase (IpmiBlobTransfer, "Write call with valid data", = "WriteValidResponse", WriteValidResponse, NULL, NULL, NULL); + // IpmiBlobTransferCommit + Status =3D AddTestCase (IpmiBlobTransfer, "Commit call with valid data",= "CommitValidResponse", CommitValidResponse, NULL, NULL, NULL); + // IpmiBlobTransferClose + Status =3D AddTestCase (IpmiBlobTransfer, "Close call with valid data", = "CloseValidResponse", CloseValidResponse, NULL, NULL, NULL); + // IpmiBlobTransferDelete + Status =3D AddTestCase (IpmiBlobTransfer, "Delete call with valid data",= "DeleteValidResponse", DeleteValidResponse, NULL, NULL, NULL); + // IpmiBlobTransferStat + Status =3D AddTestCase (IpmiBlobTransfer, "Blob Stat call with valid dat= a", "BlobStatValidResponse", BlobStatValidResponse, NULL, NULL, NULL); + Status =3D AddTestCase (IpmiBlobTransfer, "Blob Stat call with invalid b= uffer", "BlobStatInvalidBuffer", BlobStatInvalidBuffer, NULL, NULL, NULL); + // IpmiBlobTransferSessionStat + Status =3D AddTestCase (IpmiBlobTransfer, "Session Stat call with valid = data", "SessionStatValidResponse", SessionStatValidResponse, NULL, NULL, NU= LL); + Status =3D AddTestCase (IpmiBlobTransfer, "Session Stat call with invali= d buffer", "SessionStatInvalidBuffer", SessionStatInvalidBuffer, NULL, NULL= , NULL); + // IpmiBlobTransferWriteMeta + Status =3D AddTestCase (IpmiBlobTransfer, "WriteMeta call with valid dat= a", "WriteMetaValidResponse", WriteMetaValidResponse, NULL, NULL, NULL); + + // Execute the tests. + Status =3D 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 Int= erface 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 gEdkiiIpmiBlobTransferProtocolGu= id in its inf "Depex" section +2) The module should list gEdkiiIpmiBlobTransferProtocolGuid in its inf "P= rotocol" section +3) The module's entry point should do a LocateProtocol on gEdkiiIpmiBlobTr= ansferProtocolGuid + +### 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 imple= mentation. +Any changes to IpmiBlobTransferDxe should include proof of successful unit= tests. + +### Debugging +To assist in debugging any issues, change BLOB_TRANSFER_DEBUG to desired d= ebug level, such as DEBUG_ERROR or DEBUG_INFO. --=20 2.34.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118922): https://edk2.groups.io/g/devel/message/118922 Mute This Topic: https://groups.io/mt/106115743/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-