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 ECD2E740038 for ; Wed, 10 Jul 2024 15:12:27 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=UK85Q1KAJXnbPbaWcmhbLLr0SUBQHJ2fVieA7rO/UTo=; c=relaxed/simple; d=groups.io; h=From:To:CC:Subject:Thread-Topic:Thread-Index:Date:Message-ID:References:In-Reply-To:Accept-Language: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-Language:Content-Type; s=20240206; t=1720624347; v=1; b=4dsLG5Oh+o+Rh+bQEUSGIw0sRUrQJ/AstnoYI2ACTm6Yh5OuXIMuAQ5b81oU7BXgxv3zDjVB mgvtRXoEcgTHGfgpk239Kr8ZWYnArV6DNApNrz6DWA+o6FFVud5mVvbQSv9HvNIXfqQWXTWX8GF MgC43OSRu1SpVaZZeIgoWPgL5Y0D/jNHV/vXiljStKjN9X+9+Potp3ZJI0XSHNianO1qbihoXHU jtgRAfFKT8/wRxP1mYQpyCZWKayZo798E+gbzpDgXzDCeCtI2DRI5zXrU7qYu0MasKNlpmCx7xT YxuDfTE0yr/UYaqyNv19WVsAQ3J9w+JCDEf7HcFt6ehPA== X-Received: by 127.0.0.2 with SMTP id eFZtYY7687511xfYflzq7VwR; Wed, 10 Jul 2024 08:12:26 -0700 X-Received: from NAM02-DM3-obe.outbound.protection.outlook.com (NAM02-DM3-obe.outbound.protection.outlook.com [40.107.95.55]) by mx.groups.io with SMTP id smtpd.web11.17052.1720624345266871941 for ; Wed, 10 Jul 2024 08:12:25 -0700 X-Received: from PH8PR12MB7025.namprd12.prod.outlook.com (2603:10b6:510:1bc::22) by MW4PR12MB7262.namprd12.prod.outlook.com (2603:10b6:303:228::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7741.35; Wed, 10 Jul 2024 15:12:10 +0000 X-Received: from PH8PR12MB7025.namprd12.prod.outlook.com ([fe80::3d04:2556:ea5d:9f0c]) by PH8PR12MB7025.namprd12.prod.outlook.com ([fe80::3d04:2556:ea5d:9f0c%3]) with mapi id 15.20.7741.033; Wed, 10 Jul 2024 15:12:10 +0000 From: "Nickle Wang via groups.io" To: Nhi Pham , "devel@edk2.groups.io" CC: Abner Chang , Abdul Lateef Attar , Tinh Nguyen , Thang Nguyen OS , Mike Maslenkin Subject: Re: [edk2-devel] [edk2-platforms][PATCH v2] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol Thread-Topic: [edk2-platforms][PATCH v2] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol Thread-Index: AQHaqC7FfXnwgw/alUC+CQauDJjIh7HwYSIA Date: Wed, 10 Jul 2024 15:12:10 +0000 Message-ID: References: <20240515150629.236739-1-nicklew@nvidia.com> <7d928ca7-e312-4a2e-9470-cbd96fbdc643@os.amperecomputing.com> In-Reply-To: <7d928ca7-e312-4a2e-9470-cbd96fbdc643@os.amperecomputing.com> Accept-Language: en-US X-Mentions: nhi@os.amperecomputing.com X-MS-Has-Attach: X-MS-TNEF-Correlator: x-ms-publictraffictype: Email x-ms-traffictypediagnostic: PH8PR12MB7025:EE_|MW4PR12MB7262:EE_ x-ms-office365-filtering-correlation-id: 732973ce-ea2d-4de6-cf4c-08dca0f2abe0 x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam-message-info: =?us-ascii?Q?D5kCsarzXRXr8J2OI9RmBtgL07R2mCc5DsCkPZq+aCjj/iKigCDzVRxhtim2?= =?us-ascii?Q?VQ3PcRGwBL81LavQj54f4fTRDzA2WWvwCIhvPnj9xslG88BjyLpVpG6PvHek?= =?us-ascii?Q?Y1u+Keo4ZD0mvNxVmHyuIP1ehyAGqiv2AHYoJGHJNNcvnzWbB7fSCrQAnsIo?= =?us-ascii?Q?lYk3p1tNMtfi3WS1vGWqCAiuxQ0j7GStvfkG1rpc81wJg9ztxYp/xGM138BS?= =?us-ascii?Q?0ktdxgB77WwbAPctNhDAWBe0et9Rm5G3ZViuaKqxlh1jJxrjOxRK4o5PeH0O?= =?us-ascii?Q?qphF4SnNdMtOOuH0VK0V7PxbGYpQbAwGo8QuOcY2siq3nteolsAKgJlDA+v2?= =?us-ascii?Q?H1bvAslcpiF5LwzFynOjYH7nyMYlWUsc7X43+pSd4A9+PcIglWw3NR5cbTFh?= =?us-ascii?Q?riSJ2kuDhNUl2/NC8bLsoSLaYuyaoeGu74BkT+cOfkFko12M5oxSrQMtytav?= =?us-ascii?Q?Lz+eJ3YCQRKEwaSChl35ez1sAyuVR34sj2449lsBVnqCldPPjLu66KavobRl?= =?us-ascii?Q?FEPW5Vh0Q6URiVOB29O0wae0UAfO+K40wE7K6Mohfe8EvOyezUZQ926YenzV?= =?us-ascii?Q?+UClfHspKxYK/kfvnXK3yTctUUly0KAzUik9YGTsEiCM6EV2+BLYSC2tNNUz?= =?us-ascii?Q?jw/kCaTGa51CadjXutH3Hfv4cfcgzVuMkIJtHV1asMVZ+J8vbNQX+JVjKR7N?= =?us-ascii?Q?8RrV8a6lu3hjXK4F9Zx6h7mrLUfMmk5IDEeMFbDyHQxv4Sbca5J3l77KVbSh?= =?us-ascii?Q?3jXkwBrTHblFCBMDgDW0J4kpBOjzpJz4WwupA0rQH5BUSrZcH6jKdgc9GEb4?= =?us-ascii?Q?5xshl5u6iC5ARVD385KcBCJUcVQ9Ho1WIocqpOW1wx+I0Txm9UViZ7chpL3I?= =?us-ascii?Q?wmC0Lip6XINRUrVNlLuNOJt7BLipf7oOV6cWQu0LyX3GfaOQu4AvgBnZKR4L?= =?us-ascii?Q?mZw9Lf/hGiP81qzTJYBN9tAjyszYrE+QnPa5cB6DpJyHpKK0YiaF0oECuGFs?= =?us-ascii?Q?elxR/WXFIWLI8WblPgH8srNqqO4KQ5wl4n+uBdQsd30r9AdjorwUZ1qYfDGQ?= =?us-ascii?Q?6oEz+vJPPHQW+6PMGXPw720QZypBbZqM363opE7rTFvJzse5P2qaxn3r1SOB?= =?us-ascii?Q?W/ukzo6HGMbVp8vcqQgNFBGoJMJrt7vQST4bL/VBPv+LfgISxekAIX+F9O5G?= =?us-ascii?Q?eUMSybdOHZMaQykq2JuUh5klplhQucnTmliPcp+BET/teeaXSPJ9lj5ffkRD?= =?us-ascii?Q?sRp2Mej0kthJQsbyx7x73qZ/uJw5kknkCqHf7KmSMhqsL/dBK9ngkOy8lfAJ?= =?us-ascii?Q?H/lp54fk+znZIMi13afl76CupMsRtjjqG7+FxdkoJ1+1hByAZRepekIWi9sr?= =?us-ascii?Q?+qYUM0c=3D?= x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?8wBj2ojmujHta+k+BKhoKM1kGDN6fCSRicJR/lBX2UQ3dinFZeg4BCKnVdkV?= =?us-ascii?Q?iffykST+QibMb780KFFmOHo6WXK/lLL6HBRBDJwAqeNz7ABiepj1yY+3+tI/?= =?us-ascii?Q?me6tFjRRF0OtI+xMkvRr0N9rTKKh3mtfb8nD/XVb479LFsh/mzSwOFCsiPAP?= =?us-ascii?Q?M+UZIJ5rF3VPMPLk40IxT5ZUbo4+LJGAh/LBr0E2skGh8bNTjnVrGqRV4Uzq?= =?us-ascii?Q?KOVR3vO5bwTPqaCU6HRbmQNE6Ygrw9Xol4dBPbwMeR+Q8ryOs4a4X2Dh/bkW?= =?us-ascii?Q?EDTf8Kltxeicu3xWaEnUKCQrHUEUB25wJ6iVIg2QXc9rA1ml1dkNjMeXxXku?= =?us-ascii?Q?au9J3IRz22+wGMbJNcd08gKQdpKOJBzvgf+JoSmfG73oPmEhxccAC4Eu43q/?= =?us-ascii?Q?eAgVTn8OMU7k6Gmeaj1QDj7dgMNdPmTkTzYa85XG388+urqFqb9Pqt4mRqqa?= =?us-ascii?Q?kbltjdbFU+YTYA8qAo93BsibblIgCg6xeCpbnNLyP7aFGt4CupK3EI0Pi7EJ?= =?us-ascii?Q?XmddHmBNhGE/xJTO9IIyiBXmt80kCyYFj8Fl9/vUreu+nCYJf1LvodMdAP88?= =?us-ascii?Q?CfJNbd9AoeUFixTTCTcs0D6xN+q6fjFcl7BzoQ8iGeQX1UBuUzrOch4/avF9?= =?us-ascii?Q?fYwKUDp33ZGPYKmyihWI18QXCJnuhWf6RsIjIa0pv2LvNB1w9/iORMU7xAQr?= =?us-ascii?Q?qKfpyJe60fhEiAFjr3jxyiTT7ySkwX+Cqld4XeCuXo9b7Xn+IDfnZ57VQKpl?= =?us-ascii?Q?U9L2UPK8uV0OWsFtmH6oHwlL8s4ScncBW9p6X1FzcohPxSzE1kaRvaPO6PY3?= =?us-ascii?Q?T6MKDFj2N93b/jxNwS9AXXal0VyJzjBQN3MLZauj/bp3v8Z/3Hy98kDAE/w5?= =?us-ascii?Q?8p0Rs4t6FC9BliEPqgyTQ1Yor0+mX8K/HMUvBZsFTAFbgH8TgxZyUiVTqow9?= =?us-ascii?Q?1oaT3KlT26jyxfKxWqL1ANz2sVulUa0DpQW1sSxGxEaNX1wsLwx9aQTlWlqw?= =?us-ascii?Q?9bXXlPVIHyJJbsGeyqes0VP/5xE/9G5Z6qrndTj6IJSG6tSZlddy4GldkEfl?= =?us-ascii?Q?AackBVsiBrxXab3cbr4SfciOZs9Tr57xFnXKsu6pEn9NKgn5RlQOLaVpJEaM?= =?us-ascii?Q?1QIgMQ4KCkFmxhC77aq9oF1ZgMtSr3GzumDACON9rBlsAOyZg4d65wKJYX+L?= =?us-ascii?Q?Pd1a9mTpVj+FORwifHH8K1uBOkH5rC9WBwhxjwi6gILoYgvJxydSS7AT9gX+?= =?us-ascii?Q?cgJc08GVuE8xbVcorc47W41Uaq5mX8fniYNPp7JCrwX2Cz2Z86RTkGDuu7Ku?= =?us-ascii?Q?7WgjQaXQaxD+HHe5CX4/LNAvdQVQXUCI+R9DRlBbRXkTMVfUP70fH9HHffBi?= =?us-ascii?Q?hHplwPVBPXyZ9nlDRqMFgdAO09o87b7pSZ1qMcW46tv5prMykaD+Qt28rckn?= =?us-ascii?Q?UYXLm/9Z3xdZX1pLoek17U3LDeNbOLttbsCOtIIpobT9h2wBHXZmVK6SPh4X?= =?us-ascii?Q?FxCsPLbQytYxRbq/blfCQG5kQgBrCBhCy6oE5r0Y6hwkL4/vKhn9t6ZqaPHi?= =?us-ascii?Q?0tU7jsadhrO2bLQ5Zqc7zorkeBMMfb+jnXx6taHPHOgXLClyStXZdgOH+Omh?= =?us-ascii?Q?UR30JsQQXwf8oBeJ0no26OT2XSqp3H79+kDHn7DzXupo?= MIME-Version: 1.0 X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: PH8PR12MB7025.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 732973ce-ea2d-4de6-cf4c-08dca0f2abe0 X-MS-Exchange-CrossTenant-originalarrivaltime: 10 Jul 2024 15:12:10.5321 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: PSDG/O0xsUGZChoIxZioqhfUu81J9qW37JeshazP2ZcgaPHb4+HEbjqj2FkQGbzpVWZzT2EY1AKpMaRmEH8uRg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW4PR12MB7262 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, 10 Jul 2024 08:12: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: jzOzuI0iYBJWclBCYxfv8x8Ex7686176AA= Content-Language: en-US Content-Type: multipart/alternative; boundary="_000_PH8PR12MB7025D13EAE875175691200F7D9A42PH8PR12MB7025namp_" X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20240206 header.b=4dsLG5Oh; 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 --_000_PH8PR12MB7025D13EAE875175691200F7D9A42PH8PR12MB7025namp_ Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Hi @Nhi Pham, I am sorry for taking so long to address your review comments. I updated pu= ll request here: https://github.com/tianocore/edk2-platforms/pull/76 I addressed most of comments and I have questions about below review commen= ts. Please find my feedback inline below. > Should we add a PCD for the OEN to be configured by platform specific > BMC? Or this protocol is only to support OpenBMC. Yes, per description in Readme.md, this is the protocol only to support Ope= nBMC implementation. > I'm thinking the caller sequence here. Typically, the caller might check > the presence of a blob by calling GetCount () and Enumerate () before > opening a blob session. This check here could waste time. Or, do we call > open direction the blob session without pre-checking? With this implementation, user can call open directly and it will check the= presence of blob for us. And yes, this is how we use it in NVIDIA driver. > There might be developer mistake when executing the transfer before > opening the session. How do we handle this failure path? Do we need to > maintain a state machine for that? Caller can only get the session ID by calling open(). Session ID is require= d when calling read, write, and commit. If caller make up a session ID, cal= ler is expected to see error return. > How do callers know the data format of metadata for writing correctly? I check the spec here: https://github.com/openbmc/phosphor-ipmi-blobs?tab= =3Dreadme-ov-file#bmcblobwritemeta-10 And there is no description about da= ta format. Since we don't use this function in our driver, may I know if y= ou have suggestion for this? > +IpmiBlobTransferDxeDriverEntryPoint ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + return gBS->InstallMultipleProtocolInterfaces ( > + &ImageHandle, > Nit: Typically, we could also use gImageHandle instead. Sorry I don't follow you here. gImageHandle is used as global variable in driver. But here we just use the= ImageHandle from function parameter and we don't keep it as global variabl= e, right? Regards, Nickle > -----Original Message----- > From: Nhi Pham > Sent: Friday, May 17, 2024 3:49 PM > To: Nickle Wang ; devel@edk2.groups.io > Cc: Abner Chang ; Abdul Lateef Attar > ; Tinh Nguyen > ; Thang Nguyen OS > ; Mike Maslenkin > > Subject: Re: [edk2-platforms][PATCH v2] ManageabilityPkg: add support for= the > phosphor ipmi blob transfer protocol > > External email: Use caution opening links or attachments > > > Hi Nickle, > > Please see my comments inline... > > P/s: I just realized that I can not test this protocol without IPMI SSIF > to be compatible with ManageabilityPkg framework. > > On 5/15/2024 10:06 PM, Nickle Wang wrote: > > > REF:https://nam11.safelinks.protection.outlook.com/?url=3Dhttps%3A%2F%2Fb= ugzi > lla.tianocore.org%2Fshow_bug.cgi%3Fid%3D4773&data=3D05%7C02%7Cnicklew%4 > 0nvidia.com%7Cd22932100e16475feff608dc7645e177%7C43083d15727340c1b7 > db39efd9ccc17a%7C0%7C0%7C638515289789817250%7CUnknown%7CTWFpb > GZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn > 0%3D%7C0%7C%7C%7C&sdata=3D99Xm%2B3kir7CnWHFt%2FI04nBAuLT2SPeOKPE > DIGkZpz%2FM%3D&reserved=3D0 > > > > This change implements the blob transfer protocol used in OpenBmc > > documented here: > https://nam11.safelinks.protection.outlook.com/?url=3Dhttps%3A%2F%2Fgithu= b.co > m%2Fopenbmc%2Fphosphor-ipmi- > blobs&data=3D05%7C02%7Cnicklew%40nvidia.com%7Cd22932100e16475feff608d > c7645e177%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C638515289 > 789828686%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2 > luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=3Dcqngm6B% > 2F%2BGOfyIp5YqxVLVUvyHzRdpfiwcWNSD3SwZk%3D&reserved=3D0 > > > > 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/IpmiBlobTransferD= xe > .inf > > create mode 100644 > Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlob= Tr > ansferTestUnitTestsHost.inf > > create mode 100644 > Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h > > create mode 100644 > Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobT= ra > nsfer.h > > create mode 100644 > Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferD= xe > .c > > create mode 100644 > Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlob= Tr > ansferTestUnitTests.c > > create mode 100644 > Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md > > > > diff --git a/Features/ManageabilityPkg/ManageabilityPkg.dec > b/Features/ManageabilityPkg/ManageabilityPkg.dec > > index eb0ee67cba..dc1d00162c 100644 > > --- a/Features/ManageabilityPkg/ManageabilityPkg.dec > > +++ b/Features/ManageabilityPkg/ManageabilityPkg.dec > > @@ -4,6 +4,7 @@ > > # those are related to the platform management. > > # > > # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved= .
> > +# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights rese= rved. > > # SPDX-License-Identifier: BSD-2-Clause-Patent > > # > > ## > > @@ -58,6 +59,8 @@ > > gEdkiiPldmProtocolGuid =3D { 0x60997616, 0xDB70, 0x4= B5F, { 0x86, > 0xA4, 0x09, 0x58, 0xA3, 0x71, 0x47, 0xB4 } } > > gEdkiiPldmSmbiosTransferProtocolGuid =3D { 0xFA431C3C, 0x816B, 0x4= B32, > { 0xA3, 0xE0, 0xAD, 0x9B, 0x7F, 0x64, 0x27, 0x2E } } > > gEdkiiMctpProtocolGuid =3D { 0xE93465C1, 0x9A31, 0x4= C96, { 0x92, > 0x56, 0x22, 0x0A, 0xE1, 0x80, 0xB4, 0x1B } } > > + ## Include/Protocol/IpmiBlobTransfer.h > > + gEdkiiIpmiBlobTransferProtocolGuid =3D { 0x05837c75, 0x1d65, 0x46= 8b, > { 0xb1, 0xc2, 0x81, 0xaf, 0x9a, 0x31, 0x5b, 0x2c } } > > > > [PcdsFixedAtBuild] > > ## This value is the MCTP Interface source and destination endpoint= ID for > transmiting MCTP message. > > diff --git a/Features/ManageabilityPkg/Include/Manageability.dsc > b/Features/ManageabilityPkg/Include/Manageability.dsc > > index 2e410df9ba..aae343a733 100644 > > --- a/Features/ManageabilityPkg/Include/Manageability.dsc > > +++ b/Features/ManageabilityPkg/Include/Manageability.dsc > > @@ -2,6 +2,7 @@ > > # Common libraries for Manageabilty Package > > # > > # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved= .
> > +# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights rese= rved. > > # SPDX-License-Identifier: BSD-2-Clause-Patent > > # > > ## > > @@ -37,6 +38,7 @@ > > [Components.X64, Components.AARCH64] > > !if gManageabilityPkgTokenSpaceGuid.PcdManageabilityDxeIpmiEnable =3D= =3D > TRUE > > ManageabilityPkg/Universal/IpmiProtocol/Dxe/IpmiProtocolDxe.inf > > + ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.i= nf > > !endif > > > > [Components.X64] > > diff --git > a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransfe= rD > xe.inf > b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransfe= rD > xe.inf > > new file mode 100644 > > index 0000000000..108f4bb5f8 > > --- /dev/null > > +++ > b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransfe= rD > xe.inf > > @@ -0,0 +1,39 @@ > > +## @file > > +# IPMI Blob Transfer Protocol DXE Driver. > > +# > > +# Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All right= s > reserved. > > +# > > +# SPDX-License-Identifier: BSD-2-Clause-Patent > > +# > > + > > +[Defines] > > + INF_VERSION =3D 0x00010005 > > + BASE_NAME =3D IpmiBlobTransferDxe > > + FILE_GUID =3D 6357c804-78bb-4b0c-abdf-c75df942f= 319 > > + MODULE_TYPE =3D DXE_DRIVER > > + VERSION_STRING =3D 1.0 > > + ENTRY_POINT =3D IpmiBlobTransferDxeDriverEntryPoi= nt > > + > > +[Sources.common] > > + IpmiBlobTransferDxe.c > > + > > +[LibraryClasses] > > + BaseLib > > + BaseMemoryLib > > + DebugLib > > + IpmiLib > > + MemoryAllocationLib > > + PcdLib > > + UefiBootServicesTableLib > > + UefiDriverEntryPoint > > + > > +[Packages] > > + MdePkg/MdePkg.dec > > + MdeModulePkg/MdeModulePkg.dec > > + ManageabilityPkg/ManageabilityPkg.dec > > + > > +[Protocols] > > + gEdkiiIpmiBlobTransferProtocolGuid > > + > > +[Depex] > > + TRUE > > diff --git > a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl= ob > TransferTestUnitTestsHost.inf > b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl= ob > TransferTestUnitTestsHost.inf > > new file mode 100644 > > index 0000000000..dab6858f09 > > --- /dev/null > > +++ > b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl= ob > TransferTestUnitTestsHost.inf > > @@ -0,0 +1,40 @@ > > +## @file > > +# Unit tests of the Ipmi blob transfer driver that are run from a host > environment. > > +# > > +# Copyright (c) 2020-2024, NVIDIA CORPORATION & AFFILIATES. All rights > reserved. > > +# > > +# SPDX-License-Identifier: BSD-2-Clause-Patent > > +## > > + > > +[Defines] > > + INF_VERSION =3D 0x00010006 > > + BASE_NAME =3D IpmiBlobTransferDxeUnitTestsHost > > + FILE_GUID =3D 1f5d4095-ea52-432c-b078-86097fef6= 004 > > + 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/IpmiBlobTransfe= r.h > b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h > > new file mode 100644 > > index 0000000000..14b5294314 > > --- /dev/null > > +++ b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h > > @@ -0,0 +1,253 @@ > > +/** @file > > + > > + IPMI Blob Transfer driver > > + > > + Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights > reserved. > > + > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > + > > + @Par: > https://nam11.safelinks.protection.outlook.com/?url=3Dhttps%3A%2F%2Fgithu= b.co > m%2Fopenbmc%2Fphosphor-ipmi- > blobs%2Fblob%2Fmaster%2FREADME.md&data=3D05%7C02%7Cnicklew%40nvidia > .com%7Cd22932100e16475feff608dc7645e177%7C43083d15727340c1b7db39ef > d9ccc17a%7C0%7C0%7C638515289789834490%7CUnknown%7CTWFpbGZsb3d > 8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D > %7C0%7C%7C%7C&sdata=3Dq6CCTU5qwF8mHHYus0AcBlZGCJpqNARsB9SO697NT > o0%3D&reserved=3D0 > > +**/ > > Lack of header guard > #ifndef IPMI_BLOB_TRANSFER_H_ > > > +#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 }; > > const -> CONST > > Should we add a PCD for the OEN to be configured by platform specific > BMC? Or this protocol is only to support OpenBMC. > > > + > > +// > > +// Blob Transfer Function Prototypes > > +// > > + > > +/** > > + This function retrieves the count of blob transfers available throug= h the IPMI. > > + > > + @param[out] Count The number of active blobs > > + > > + @retval EFI_SUCCESS Successfully retrieved the number of = active > blobs. > > + @retval Other An error occurred > > +**/ > > +typedef > > +EFI_STATUS > > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)( > > + OUT UINT32 *Count > > + ); > > + > > +/** > > + This function enumerates blob transfers available through the IPMI. > > + > > + @param[in] BlobIndex The 0-based Index of the blob to = enumerate > > + @param[out] BlobId The ID of the blob > > + > > + @retval EFI_SUCCESS Successfully enumerated the blob. > > + @retval Other An error occurred > > +**/ > > +typedef > > +EFI_STATUS > > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)( > > + IN UINT32 BlobIndex, > > + OUT CHAR8 *BlobId > > + ); > > + > > +/** > > + This function is designed to open a session for a specific blob > > + identified by its ID, using the IPMI. > > + > > + @param[in] BlobId The ID of the blob to open > > + @param[in] Flags Flags to control how the blob is = opened > > + @param[out] SessionId A unique session identifier > > + > > + @retval EFI_SUCCESS Successfully opened the blob. > > + @retval Other An error occurred > > +**/ > > +typedef > > +EFI_STATUS > > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)( > > + IN CHAR8 *BlobId, > > + IN UINT16 Flags, > > + OUT UINT16 *SessionId > > + ); > > + > > +/** > > + This function reads data from a blob over the IPMI. > > + > > + @param[in] SessionId The session ID returned from a ca= ll to > BlobOpen > > + @param[in] Offset The offset of the blob from which= to start > reading > > + @param[in] RequestedSize The length of data to read > > + @param[out] Data Data read from the blob > > + > > + @retval EFI_SUCCESS Successfully read from the blob. > > + @retval Other An error occurred > > +**/ > > +typedef > > +EFI_STATUS > > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_READ)( > > + IN UINT16 SessionId, > > + IN UINT32 Offset, > > + IN UINT32 RequestedSize, > > + OUT UINT8 *Data > > + ); > > + > > +/** > > + This function writes data to a blob over the IPMI. > > + > > + @param[in] SessionId The session ID returned from a ca= ll to > BlobOpen > > + @param[in] Offset The offset of the blob from which= to start writing > > + @param[in] Data A pointer to the data to write > > + @param[in] WriteLength The length to write > > + > > + @retval EFI_SUCCESS Successfully wrote to the blob. > > + @retval Other An error occurred > > +**/ > > +typedef > > +EFI_STATUS > > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE)( > > + IN UINT16 SessionId, > > + IN UINT32 Offset, > > + IN UINT8 *Data, > > + IN UINT32 WriteLength > > + ); > > + > > +/** > > + This function commits data to a blob over the IPMI. > > + > > + @param[in] SessionId The session ID returned from a c= all 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 t= he IPMI. > > + > > + @param[in] SessionId The session ID returned from a ca= ll to > BlobOpen > > + > > + @retval EFI_SUCCESS The blob was closed. > > + @retval Other An error occurred > > +**/ > > +typedef > > +EFI_STATUS > > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)( > > + IN UINT16 SessionId > > + ); > > + > > +/** > > + This function deletes a specific blob identified by its ID over the = IPMI. > > + > > + @param[in] BlobId The BlobId to be deleted > > + > > + @retval EFI_SUCCESS The blob was deleted. > > + @retval Other An error occurred > > +**/ > > +typedef > > +EFI_STATUS > > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)( > > + IN CHAR8 *BlobId > > + ); > > + > > +/** > > + This function retrieve the status of a specific blob identified by B= lobId 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 successf= ully 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 s= tatistics 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 successf= ully 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 me= tadata for > > + @param[in] Offset The offset of the metadata to wri= te to > > + @param[in] Data The data to write to the metadata > > + @param[in] WriteLength The length to write > > + > > + @retval EFI_SUCCESS The blob metadata was successfull= y written. > > + @retval Other An error occurred > > +**/ > > +typedef > > +EFI_STATUS > > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)( > > + IN UINT16 SessionId, > > + IN UINT32 Offset, > > + IN UINT8 *Data, > > + IN UINT32 WriteLength > > + ); > > + > > +// > > +// Structure of EDKII_IPMI_BLOB_TRANSFER_PROTOCOL > > +// > > +struct _EDKII_IPMI_BLOB_TRANSFER_PROTOCOL { > > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT BlobGetCount; > > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE BlobEnumerate; > > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_OPEN BlobOpen; > > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_READ BlobRead; > > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE BlobWrite; > > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT BlobCommit; > > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE BlobClose; > > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_DELETE BlobDelete; > > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_STAT BlobStat; > > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT BlobSessionStat; > > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META BlobWriteMeta; > > +}; > > + > > +typedef struct _EDKII_IPMI_BLOB_TRANSFER_PROTOCOL > EDKII_IPMI_BLOB_TRANSFER_PROTOCOL; > > + > > +extern EFI_GUID gEdkiiIpmiBlobTransferProtocolGuid; > > diff --git > a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlo= bTr > ansfer.h > b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlo= bTr > ansfer.h > > new file mode 100644 > > index 0000000000..3e90dc6871 > > --- /dev/null > > +++ > b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlo= bTr > ansfer.h > > @@ -0,0 +1,407 @@ > > +/** @file > > + > > + Headers for IPMI Blob Transfer driver > > + > > + Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights > reserved. > > + > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > + > > +**/ > > + > > Lack of header guard > #ifndef INTERNAL_IPMI_BLOB_TRANSFER_H_ > > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#define PROTOCOL_RESPONSE_OVERHEAD (4 * sizeof(UINT8)) // 1 byt= e > completion code + 3 bytes OEN > > Nit: Add a space after sizeof > > > +#define BLOB_MAX_DATA_PER_PACKET 64 > > Should it be moved to Include/Protocol/IpmiBlobTransfer.h? The caller > could need to be aware the max length of the package. > > > + > > +// Subcommands for this protocol > > +typedef enum { > > + IpmiBlobTransferSubcommandGetCount =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 bl= ob > > +// 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 execute= d as > part of > > + the blob transfer operation. > > + @param[in] SendData A pointer to the data buffer that cont= ains the > data to be sent. > > + @param[in] SendDataSize The size of the data to be sent, in by= tes. > > + @param[out] ResponseData A pointer to the buffer where the resp= onse > 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 throug= h the IPMI. > > + > > + @param[out] Count The number of active blobs > > + > > + @retval EFI_SUCCESS Successfully retrieved the number of = active > blobs. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferGetCount ( > > + OUT UINT32 *Count > > + ); > > + > > +/** > > + This function enumerates blob transfers available through the IPMI. > > + > > + @param[in] BlobIndex The 0-based Index of the blob to = enumerate > > + @param[out] BlobId The ID of the blob > > + > > + @retval EFI_SUCCESS Successfully enumerated the blob. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferEnumerate ( > > + IN UINT32 BlobIndex, > > + OUT CHAR8 *BlobId > > + ); > > + > > +/** > > + This function is designed to open a session for a specific blob > > + identified by its ID, using the IPMI. > > + > > + @param[in] BlobId The ID of the blob to open > > + @param[in] Flags Flags to control how the blob is = opened > > + @param[out] SessionId A unique session identifier > > + > > + @retval EFI_SUCCESS Successfully opened the blob. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferOpen ( > > + IN CHAR8 *BlobId, > > + IN UINT16 Flags, > > + OUT UINT16 *SessionId > > + ); > > + > > +/** > > + This function reads data from a blob over the IPMI. > > + > > + @param[in] SessionId The session ID returned from a ca= ll to > BlobOpen > > + @param[in] Offset The offset of the blob from which= to start > reading > > + @param[in] RequestedSize The length of data to read > > + @param[out] Data Data read from the blob > > + > > + @retval EFI_SUCCESS Successfully read from the blob. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferRead ( > > + IN UINT16 SessionId, > > + IN UINT32 Offset, > > + IN UINT32 RequestedSize, > > + OUT UINT8 *Data > > + ); > > + > > +/** > > + This function writes data to a blob over the IPMI. > > + > > + @param[in] SessionId The session ID returned from a ca= ll to > BlobOpen > > + @param[in] Offset The offset of the blob from which= to start writing > > + @param[in] Data A pointer to the data to write > > + @param[in] WriteLength The length to write > > + > > + @retval EFI_SUCCESS Successfully wrote to the blob. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferWrite ( > > + IN UINT16 SessionId, > > + IN UINT32 Offset, > > + IN UINT8 *Data, > > + IN UINT32 WriteLength > > + ); > > + > > +/** > > + This function commits data to a blob over the IPMI. > > + > > + @param[in] SessionId The session ID returned from a c= all 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 t= he IPMI. > > + > > + @param[in] SessionId The session ID returned from a ca= ll to > BlobOpen > > + > > + @retval EFI_SUCCESS The blob was closed. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferClose ( > > + IN UINT16 SessionId > > + ); > > + > > +/** > > + This function deletes a specific blob identified by its ID over the = IPMI. > > + > > + @param[in] BlobId The BlobId to be deleted > > + > > + @retval EFI_SUCCESS The blob was deleted. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferDelete ( > > + IN CHAR8 *BlobId > > + ); > > + > > +/** > > + This function retrieve the status of a specific blob identified by B= lobId 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 successf= ully 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 s= tatistics 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 successf= ully 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 me= tadata for > > + @param[in] Offset The offset of the metadata to wri= te to > > + @param[in] Data The data to write to the metadata > > + @param[in] WriteLength The length to write > > + > > + @retval EFI_SUCCESS The blob metadata was successfull= y written. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferWriteMeta ( > > + IN UINT16 SessionId, > > + IN UINT32 Offset, > > + IN UINT8 *Data, > > + IN UINT32 WriteLength > > + ); > > diff --git > a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransfe= rD > xe.c > b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransfe= rD > xe.c > > new file mode 100644 > > index 0000000000..b8a2db193b > > --- /dev/null > > +++ > b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransfe= rD > xe.c > > @@ -0,0 +1,872 @@ > > +/** @file > > + > > + IPMI Blob Transfer driver > > + > > + Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights > reserved. > > + > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > + > > +**/ > > +#include > > + > > +#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)*IpmiBlobTransferGetC > ount, > > + > (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnu > merate, > > + (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)*IpmiBlobTransferSes > sionStat, > > + > (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWrit > eMeta > > +}; > > + > > +/** > > + 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 execute= d as > part of > > + the blob transfer operation. > > + @param[in] SendData A pointer to the data buffer that cont= ains the > data to be sent. > > + @param[in] SendDataSize The size of the data to be sent, in by= tes. > > + @param[out] ResponseData A pointer to the buffer where the resp= onse > data will be stored. > > + @param[out] ResponseDataSize A pointer to a variable that will hold= the size > of the response > > + data received. > > + > > + @retval EFI_SUCCESS Successfully sends blob data. > > + @retval EFI_OUT_OF_RESOURCES Memory allocation fails. > > + @retval EFI_PROTOCOL_ERROR Communication errors. > > + @retval EFI_CRC_ERROR Data integrity checks fail. > > + @retval Other An error occurred > > + > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferSendIpmi ( > > + IN UINT8 SubCommand, > > + IN UINT8 *SendData, > > + IN UINT32 SendDataSize, > > Should describe SendData and SendDataSize as OPTIONAL > > > + OUT UINT8 *ResponseData, > > + OUT UINT32 *ResponseDataSize > > + ) > > +{ > > + EFI_STATUS Status; > > + UINT8 CompletionCode; > > + UINT16 Crc; > > + UINT8 Oen[3]; > > + UINT8 *IpmiSendData; > > + UINT32 IpmiSendDataSize; > > + UINT8 *IpmiResponseData; > > + UINT8 *ModifiedResponseData; > > + UINT32 IpmiResponseDataSize; > > + IPMI_BLOB_TRANSFER_HEADER Header; > > + > > Should validate the pointer of input arguments: SendData, ResponseData, > ResponseDataSize. > > > + Crc =3D 0; > > + > > + // > > + // Prepend the proper header to the SendData > > + // > > + IpmiSendDataSize =3D (sizeof (IPMI_BLOB_TRANSFER_HEADER)); > > + if (SendDataSize) { > > + IpmiSendDataSize +=3D sizeof (Crc) + (sizeof (UINT8) * SendDataSiz= e); > > + } > > + > > + 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) { > > if (SendDataSize !=3D 0) > > > + // > > + // Calculate the Crc of the send data > > + // > > + Crc =3D CalculateCrc16Ccitt (SendData, SendDataSize); > > + CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER), &Crc, > sizeof (UINT16)); > > + CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER) + sizeo= f > (UINT16), SendData, SendDataSize); > > + } > > + > > + DEBUG_CODE_BEGIN (); > > + DEBUG ((BLOB_TRANSFER_DEBUG, "%a: Inputs:\n", __func__)); > > + DEBUG ((BLOB_TRANSFER_DEBUG, "%a: SendDataSize: %02x\nData: ", > __func__, SendDataSize)); > > + UINT8 i; > > + > > + for (i =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: ", > __func__, 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) { > > if (*ResponseDataSize !=3D 0) > > > + 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: ", > __func__, 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 (CompletionC= ode); > > + 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 e= rror. > > + // 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 bac= k > > + } 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, > IpmiResponseDataSize)) { > > + CopyMem (ResponseData, ModifiedResponseData, IpmiResponseDataSiz= e); > > + CopyMem (ResponseDataSize, &IpmiResponseDataSize, sizeof > (IpmiResponseDataSize)); > > + FreePool (IpmiResponseData); > > + return EFI_SUCCESS; > > + } else { > > + FreePool (IpmiResponseData); > > + return EFI_CRC_ERROR; > > + } > > + } > > +} > > + > > +/** > > + This function retrieves the count of blob transfers available throug= h the IPMI. > > + > > + @param[out] Count The number of active blobs > > + > > + @retval EFI_SUCCESS Successfully retrieved the number of = active > blobs. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferGetCount ( > > + OUT UINT32 *Count > > + ) > > +{ > > + EFI_STATUS Status; > > + UINT8 *ResponseData; > > + UINT32 ResponseDataSize; > > + > > + if (Count =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 (IpmiBlobTransferSubcommandGetCo= unt, > NULL, 0, (UINT8 *)ResponseData, &ResponseDataSize); > > + if (!EFI_ERROR (Status)) { > > + *Count =3D ((IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE > *)ResponseData)->BlobCount; > > + } > > + > > + FreePool (ResponseData); > > + return Status; > > +} > > + > > +/** > > + This function enumerates blob transfers available through the IPMI. > > + > > + @param[in] BlobIndex The 0-based Index of the blob to = enumerate > > + @param[out] BlobId The ID of the blob > > + > > + @retval EFI_SUCCESS Successfully enumerated the blob. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferEnumerate ( > > + IN UINT32 BlobIndex, > > + OUT CHAR8 *BlobId > > + ) > > +{ > > + EFI_STATUS Status; > > + > > + UINT8 *SendData; > > + UINT8 *ResponseData; > > + UINT32 SendDataSize; > > + UINT32 ResponseDataSize; > > + > > + if (BlobId =3D=3D NULL) { > > + ASSERT (FALSE); > > + return EFI_ABORTED; > > Should return EFI_INVALID_PARAMETER for input validation? > > > + } > > + > > + 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) { > > FreePool (ResponseData); > > > + 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 = opened > > It would be good if we can list out all flag definitions here. Actually, > I don't know how to input for this argument. > > Are they BLOB_OPEN_FLAG_READ and BLOB_OPEN_FLAG_WRITE in the private > include header? > > > + @param[out] SessionId A unique session identifier > > + > > + @retval EFI_SUCCESS Successfully opened the blob. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferOpen ( > > + IN CHAR8 *BlobId, > > + IN UINT16 Flags, > > + OUT UINT16 *SessionId > > + ) > > +{ > > + EFI_STATUS Status; > > + UINT8 *SendData; > > + UINT8 *ResponseData; > > + UINT32 SendDataSize; > > + UINT32 ResponseDataSize; > > + CHAR8 *BlobSearch; > > + UINT32 NumBlobs; > > + UINT16 Index; > > + BOOLEAN BlobFound; > > + > > + if ((BlobId =3D=3D NULL) || (SessionId =3D=3D NULL)) { > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + // > > + // Before opening a blob, need to check if it exists > > I'm thinking the caller sequence here. Typically, the caller might check > the presence of a blob by calling GetCount () and Enumerate () before > opening a blob session. This check here could waste time. Or, do we call > open direction the blob session without pre-checking? > > > + // > > + Status =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_= _, > Status)); > > + return EFI_NOT_FOUND; > > + } > > + > > + BlobSearch =3D AllocateZeroPool (sizeof (CHAR8) * > BLOB_MAX_DATA_PER_PACKET); > > + 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 > *)SendData)->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)->BlobId, 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; > > Nit: add spaces around minus (-) for readability. > > > + > > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandOpen, > SendData, 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 ca= ll to > BlobOpen > > + @param[in] Offset The offset of the blob from which= to start > reading > > + @param[in] RequestedSize The length of data to read > > + @param[out] Data Data read from the blob > > + > > + @retval EFI_SUCCESS Successfully read from the blob. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferRead ( > > + IN UINT16 SessionId, > > There might be developer mistake when executing the transfer before > opening the session. How do we handle this failure path? Do we need to > maintain a state machine for that? > > This comment applies to other functions as well. > > > + IN UINT32 Offset, > > + IN UINT32 RequestedSize, > > + OUT UINT8 *Data > > + ) > > +{ > > + EFI_STATUS Status; > > + UINT8 *SendData; > > + UINT8 *ResponseData; > > + UINT32 SendDataSize; > > + UINT32 ResponseDataSize; > > + > > + if (Data =3D=3D NULL) { > > + ASSERT (FALSE); > > + return EFI_ABORTED; > > Should return EFI_INVALID_PARAMETER? > > > + } > > + > > + ResponseDataSize =3D RequestedSize * sizeof (UINT8); > > Should check the RequestedSize against BLOB_MAX_DATA_PER_PACKET? > > > + 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) { > > FreePool (ResponseData); > > > + 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, > SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize); > > + if (!EFI_ERROR (Status)) { > > + CopyMem (Data, ((IPMI_BLOB_TRANSFER_BLOB_READ_RESPONSE > *)ResponseData)->Data, ResponseDataSize * sizeof (UINT8)); > > + } > > + > > + FreePool (ResponseData); > > + FreePool (SendData); > > + return Status; > > +} > > + > > +/** > > + This function writes data to a blob over the IPMI. > > + > > + @param[in] SessionId The session ID returned from a ca= ll to > BlobOpen > > + @param[in] Offset The offset of the blob from which= to start writing > > + @param[in] Data A pointer to the data to write > > + @param[in] WriteLength The length to write > > + > > + @retval EFI_SUCCESS Successfully wrote to the blob. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferWrite ( > > + IN UINT16 SessionId, > > + IN UINT32 Offset, > > + IN UINT8 *Data, > > + IN UINT32 WriteLength > > + ) > > +{ > > + EFI_STATUS Status; > > + UINT8 *SendData; > > + UINT32 SendDataSize; > > + UINT32 ResponseDataSize; > > + > > + if (Data =3D=3D NULL) { > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + // > > + // Format send data > > + // > > + SendDataSize =3D sizeof (SessionId) + sizeof (Offset) + WriteLength; > > Should we check whether or not the WriteLength is equal to or less than > BLOB_MAX_DATA_PER_PACKET? > > > + SendData =3D AllocateZeroPool (SendDataSize); > > + if (SendData =3D=3D NULL) { > > + return EFI_OUT_OF_RESOURCES; > > + } > > + > > + ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->SessionId > =3D SessionId; > > + ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset =3D > Offset; > > + CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA > *)SendData)->Data, Data, sizeof (UINT8) * WriteLength); > > + > > + ResponseDataSize =3D 0; > > + Status =3D IpmiBlobTransferSendIpmi > (IpmiBlobTransferSubcommandWrite, SendData, SendDataSize, NULL, > &ResponseDataSize); > > + > > + FreePool (SendData); > > + return Status; > > +} > > + > > +/** > > + This function commits data to a blob over the IPMI. > > + > > + @param[in] SessionId The session ID returned from a c= all 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) { > > According to the spec > https://nam11.safelinks.protection.outlook.com/?url=3Dhttps%3A%2F%2Fgithu= b.co > m%2Fopenbmc%2Fphosphor-ipmi- > blobs&data=3D05%7C02%7Cnicklew%40nvidia.com%7Cd22932100e16475feff608d > c7645e177%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C638515289 > 789839336%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2 > luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=3DfJbeNhF74 > Co7aHmkYc3U0ym1ISeNznrV2UXDNMEFcoE%3D&reserved=3D0, > the commit data is block-specific optional. > > For instance, the commit data is optional for SMBIOS blob transfer. Look > at > https://nam11.safelinks.protection.outlook.com/?url=3Dhttps%3A%2F%2Fgithu= b.co > m%2Fopenbmc%2Fsmbios- > mdr&data=3D05%7C02%7Cnicklew%40nvidia.com%7Cd22932100e16475feff608dc > 7645e177%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C6385152897 > 89844890%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2l > uMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=3D4OBktrF6b1 > vyHaI%2FvIOcXOCZQxaFZKwO3lPwLsjIgWY%3D&reserved=3D0 > > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + // > > + // Format send data > > + // > > + SendDataSize =3D sizeof (SessionId) + sizeof (CommitDataLength) + > CommitDataLength; > > + 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)->CommitData, CommitData, sizeof (UINT8) * CommitDataLength); > > + > > + ResponseDataSize =3D 0; > > + > > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandCommi= t, > SendData, SendDataSize, NULL, &ResponseDataSize); > > + > > + FreePool (SendData); > > + return Status; > > +} > > + > > +/** > > + This function close a session associated with a blob transfer over t= he IPMI. > > + > > + @param[in] SessionId The session ID returned from a ca= ll to > BlobOpen > > + > > + @retval EFI_SUCCESS The blob was closed. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferClose ( > > + IN UINT16 SessionId > > + ) > > +{ > > + EFI_STATUS Status; > > + UINT8 *SendData; > > + UINT32 SendDataSize; > > + UINT32 ResponseDataSize; > > + > > + // > > + // Format send data > > + // > > + SendDataSize =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 SessionId; > > + > > + ResponseDataSize =3D 0; > > + > > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandClose= , > SendData, SendDataSize, NULL, &ResponseDataSize); > > + > > + FreePool (SendData); > > + return Status; > > +} > > + > > +/** > > + This function deletes a specific blob identified by its ID over the = IPMI. > > + > > + @param[in] BlobId The BlobId to be deleted > > + > > + @retval EFI_SUCCESS The blob was deleted. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferDelete ( > > + IN CHAR8 *BlobId > > + ) > > +{ > > + EFI_STATUS Status; > > + UINT8 *SendData; > > + UINT32 SendDataSize; > > + UINT32 ResponseDataSize; > > + > > + if (BlobId =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)->BlobId, AsciiStrLen (BlobId), BlobId); > > + > > + ResponseDataSize =3D 0; > > + > > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandDelet= e, > SendData, SendDataSize, NULL, &ResponseDataSize); > > + > > + FreePool (SendData); > > + return Status; > > +} > > + > > +/** > > + This function retrieve the status of a specific blob identified by B= lobId 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 successf= ully 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)) { > > Could we make Metadata **per spec**, MetadataLength, and Size optional? > We could not care them rather than BlobState. > > This comment applies to IpmiBlobTransferSessionStat () as well. > > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + if (Metadata =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)- > >BlobId, BLOB_MAX_DATA_PER_PACKET, BlobId); > > + > > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandStat, > SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize); > > + if (!EFI_ERROR (Status)) { > > + *BlobState =3D ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE > *)ResponseData)->BlobState; > > + *Size =3D ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE > *)ResponseData)->Size; > > + *MetadataLength =3D ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE > *)ResponseData)->MetaDataLen; > > + > > + CopyMem (&Metadata, &((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE > *)ResponseData)->MetaData, sizeof > (((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)ResponseData)->MetaData)); > > + } > > + > > + FreePool (ResponseData); > > + FreePool (SendData); > > + return Status; > > +} > > + > > +/** > > + This function query the status of a blob transfer session in an IPMI= . > > + > > + @param[in] SessionId The ID of the session to gather s= tatistics 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 successf= ully 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 > (IpmiBlobTransferSubcommandSessionStat, SendData, SendDataSize, (UINT8 > *)ResponseData, &ResponseDataSize); > > + > > + if (!EFI_ERROR (Status)) { > > + *BlobState =3D ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONS= E > *)ResponseData)->BlobState; > > + *Size =3D ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONS= E > *)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_RESPONSE > *)ResponseData)->MetaData)); > > + } > > + > > + FreePool (ResponseData); > > + FreePool (SendData); > > + return Status; > > +} > > + > > +/** > > + This function writes metadata to a blob associated with a session in= an IPMI. > > + > > + @param[in] SessionId The ID of the session to write me= tadata for > > + @param[in] Offset The offset of the metadata to wri= te to > > + @param[in] Data The data to write to the metadata > > + @param[in] WriteLength The length to write > > + > > + @retval EFI_SUCCESS The blob metadata was successfull= y written. > > + @retval Other An error occurred > > +**/ > > +EFI_STATUS > > +IpmiBlobTransferWriteMeta ( > > + IN UINT16 SessionId, > > + IN UINT32 Offset, > > + IN UINT8 *Data, > > How do callers know the data format of metadata for writing correctly? > > > + IN UINT32 WriteLength > > Should check with BLOB_MAX_DATA_PER_PACKET > > > + ) > > +{ > > + EFI_STATUS Status; > > + UINT8 *SendData; > > + UINT32 SendDataSize; > > + UINT32 ResponseDataSize; > > + > > + if (Data =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 SessionId; > > + ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset =3D > Offset; > > + CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA > *)SendData)->Data, Data, 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 poin= t is > > + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers in= cluding > > + both device drivers and bus drivers. > > + > > + @param[in] ImageHandle The firmware allocated handle for the = UEFI > image. > > + @param[in] SystemTable A pointer to the EFI System Table. > > + > > + @retval EFI_SUCCESS The operation completed successfully. > > + @retval Others An unexpected error occurred. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +IpmiBlobTransferDxeDriverEntryPoint ( > > + IN EFI_HANDLE ImageHandle, > > + IN EFI_SYSTEM_TABLE *SystemTable > > + ) > > +{ > > + return gBS->InstallMultipleProtocolInterfaces ( > > + &ImageHandle, > > Nit: Typically, we could also use gImageHandle instead. > > > + &gEdkiiIpmiBlobTransferProtocolGuid, > > + (VOID *)&mIpmiBlobTransfer, > > + NULL > > + ); > > +} > > diff --git > a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl= ob > TransferTestUnitTests.c > b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl= ob > TransferTestUnitTests.c > > new file mode 100644 > > index 0000000000..0f728527b8 > > --- /dev/null > > +++ > b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl= ob > TransferTestUnitTests.c > > @@ -0,0 +1,1113 @@ > > +/** @file > > +* > > +* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. > > +* > > +* SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION = & > AFFILIATES > > +* SPDX-License-Identifier: BSD-2-Clause-Patent > > +* > > +**/ > > +#include > > +#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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_SIZE); > > + ResponseDataSize =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32))= ; > > + CopyMem (MockResponseResults, &InvalidCompletion, > INVALID_COMPLETION_SIZE); > > + > > + MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > INVALID_COMPLETION_SIZE, EFI_SUCCESS); > > + > > + ResponseData =3D (UINT8 *)AllocateZeroPool (*ResponseDataSize); > > + Status =3D IpmiBlobTransferSendIpmi > (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData, > ResponseDataSize); > > + > > + UT_ASSERT_STATUS_EQUAL (Status, EFI_PROTOCOL_ERROR); > > + FreePool (MockResponseResults); > > + FreePool (ResponseDataSize); > > + FreePool (ResponseData); > > + return UNIT_TEST_PASSED; > > +} > > + > > +/** > > + @param[in] Context [Optional] An optional parameter that enables= : > > + 1) test-case reuse with varied parameters and > > + 2) test-case re-entry for Target tests that n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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 > (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData, > ResponseDataSize); > > + > > + UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); > > + UT_ASSERT_EQUAL (*ResponseDataSize, 0); > > + FreePool (MockResponseResults); > > + FreePool (ResponseDataSize); > > + FreePool (ResponseData); > > + return UNIT_TEST_PASSED; > > +} > > + > > +/** > > + @param[in] Context [Optional] An optional parameter that enables= : > > + 1) test-case reuse with varied parameters and > > + 2) test-case re-entry for Target tests that n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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 > (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData, > ResponseDataSize); > > + > > + UT_ASSERT_STATUS_EQUAL (Status, EFI_PROTOCOL_ERROR); > > + FreePool (MockResponseResults); > > + FreePool (ResponseDataSize); > > + FreePool (ResponseData); > > + return UNIT_TEST_PASSED; > > +} > > + > > +/** > > + @param[in] Context [Optional] An optional parameter that enables= : > > + 1) test-case reuse with varied parameters and > > + 2) test-case re-entry for Target tests that n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_RESPONSE_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 > (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData, > ResponseDataSize); > > + > > + UT_ASSERT_STATUS_EQUAL (Status, EFI_CRC_ERROR); > > + FreePool (MockResponseResults); > > + FreePool (ResponseDataSize); > > + FreePool (ResponseData); > > + return UNIT_TEST_PASSED; > > +} > > + > > +UINT8 ValidGetCountResponse[] =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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_COUNT_RESPONSE_SIZE)); > > + ResponseDataSize =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32))= ; > > + CopyMem (MockResponseResults, &ValidGetCountResponse, > VALID_GET_COUNT_RESPONSE_SIZE); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS); > > + if (EFI_ERROR (Status)) { > > + return UNIT_TEST_ERROR_TEST_FAILED; > > + } > > + > > + ResponseData =3D AllocateZeroPool (sizeof (ValidGetCountResponse)); > > + Status =3D IpmiBlobTransferSendIpmi > (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData, > ResponseDataSize); > > + > > + UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); > > + FreePool (MockResponseResults); > > + FreePool (ResponseDataSize); > > + FreePool (ResponseData); > > + return UNIT_TEST_PASSED; > > +} > > + > > +/** > > + @param[in] Context [Optional] An optional parameter that enables= : > > + 1) test-case reuse with varied parameters and > > + 2) test-case re-entry for Target tests that n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_COUNT_RESPONSE_SIZE)); > > + CopyMem (MockResponseResults, &ValidGetCountResponse, > VALID_GET_COUNT_RESPONSE_SIZE); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_GET_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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_ENUMERATE_RESPONSE_SIZE)); > > + CopyMem (MockResponseResults, &ValidEnumerateResponse, > VALID_ENUMERATE_RESPONSE_SIZE); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS); > > + if (EFI_ERROR (Status)) { > > + return UNIT_TEST_ERROR_TEST_FAILED; > > + } > > + > > + BlobId =3D AllocateZeroPool (sizeof (CHAR8) * BLOB_MAX_DATA_PER_PACK= ET); > > + > > + 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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_ENUMERATE_RESPONSE_SIZE)); > > + CopyMem (MockResponseResults, &ValidEnumerateResponse, > VALID_ENUMERATE_RESPONSE_SIZE); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_ENUMERATE_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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_RESPONSE_SIZE)); > > + > > + CopyMem (MockResponseResults, &ValidOpenResponse, > VALID_OPEN_RESPONSE_SIZE); > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_OPEN_RESPONSE_SIZE, EFI_SUCCESS); > > + if (EFI_ERROR (Status)) { > > + return UNIT_TEST_ERROR_TEST_FAILED; > > + } > > + > > + MockResponseResults2 =3D (UINT8 *)AllocateZeroPool (sizeof > (VALID_ENUMERATE_RESPONSE_SIZE)); > > + CopyMem (MockResponseResults2, &ValidEnumerateResponse, > VALID_ENUMERATE_RESPONSE_SIZE); > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults2, > VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS); > > + if (EFI_ERROR (Status)) { > > + return UNIT_TEST_ERROR_TEST_FAILED; > > + } > > + > > + MockResponseResults3 =3D (UINT8 *)AllocateZeroPool (sizeof > (VALID_GET_COUNT_RESPONSE_SIZE)); > > + CopyMem (MockResponseResults3, &ValidGetCountResponse, > VALID_GET_COUNT_RESPONSE_SIZE); > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults3, > VALID_GET_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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_RESPONSE_SIZE)); > > + CopyMem (MockResponseResults, &ValidReadResponse, > VALID_READ_RESPONSE_SIZE); > > + ResponseData =3D AllocateZeroPool (sizeof (ValidReadResponse)); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_READ_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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_RESPONSE_SIZE)); > > + CopyMem (MockResponseResults, &ValidReadResponse, > VALID_READ_RESPONSE_SIZE); > > + ResponseData =3D NULL; > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_READ_RESPONSE_SIZE, EFI_SUCCESS); > > + if (EFI_ERROR (Status)) { > > + return UNIT_TEST_ERROR_TEST_FAILED; > > + } > > + > > + UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferRead (0, 0, 4, ResponseDat= a), > 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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_RESPONSE_SIZE); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_NODATA_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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_RESPONSE_SIZE); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_NODATA_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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_RESPONSE_SIZE); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_NODATA_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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_RESPONSE_SIZE); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_NODATA_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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_STAT_RESPONSE_SIZE)); > > + CopyMem (MockResponseResults, &ValidBlobStatResponse, > VALID_BLOB_STAT_RESPONSE_SIZE); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS); > > + if (EFI_ERROR (Status)) { > > + return UNIT_TEST_ERROR_TEST_FAILED; > > + } > > + > > + Status =3D IpmiBlobTransferStat (BlobId, BlobState, Size, MetadataLe= ngth, > 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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_STAT_RESPONSE_SIZE)); > > + CopyMem (MockResponseResults, &ValidBlobStatResponse, > VALID_BLOB_STAT_RESPONSE_SIZE); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS); > > + if (EFI_ERROR (Status)) { > > + return UNIT_TEST_ERROR_TEST_FAILED; > > + } > > + > > + UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferStat (NULL, 0, 0, 0, > Metadata), NULL); > > + > > + FreePool (MockResponseResults); > > + return UNIT_TEST_PASSED; > > +} > > + > > +/** > > + @param[in] Context [Optional] An optional parameter that enables= : > > + 1) test-case reuse with varied parameters and > > + 2) test-case re-entry for Target tests that n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_STAT_RESPONSE_SIZE)); > > + CopyMem (MockResponseResults, &ValidBlobStatResponse, > VALID_BLOB_STAT_RESPONSE_SIZE); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS); > > + if (EFI_ERROR (Status)) { > > + return UNIT_TEST_ERROR_TEST_FAILED; > > + } > > + > > + Status =3D IpmiBlobTransferSessionStat (0, BlobState, Size, Metadata= Length, > 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 n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_STAT_RESPONSE_SIZE)); > > + CopyMem (MockResponseResults, &ValidBlobStatResponse, > VALID_BLOB_STAT_RESPONSE_SIZE); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS); > > + if (EFI_ERROR (Status)) { > > + return UNIT_TEST_ERROR_TEST_FAILED; > > + } > > + > > + UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferSessionStat (0, 0, 0, 0, > Metadata), NULL); > > + > > + FreePool (MockResponseResults); > > + return UNIT_TEST_PASSED; > > +} > > + > > +/** > > + @param[in] Context [Optional] An optional parameter that enables= : > > + 1) test-case reuse with varied parameters and > > + 2) test-case re-entry for Target tests that n= eed a > > + reboot. This parameter is a VOID* and it is = the > > + responsibility of the test author to ensure t= hat the > > + contents are well understood by all test case= s that may > > + consume it. > > + @retval UNIT_TEST_PASSED The Unit test has completed an= d the test > > + case was successful. > > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has fail= ed. > > +**/ > > +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_RESPONSE_SIZE); > > + > > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, > VALID_NODATA_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, > gEfiCallerBaseName, UNIT_TEST_VERSION); > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "Failed to setup Test Framework. Exiting with > status =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 > Transfer Tests\n")); > > + Status =3D EFI_OUT_OF_RESOURCES; > > + return Status; > > + } > > + > > + // CalculateCrc16Ccitt > > + Status =3D AddTestCase (IpmiBlobTransfer, "Test CRC Calculation", "G= oodCrc", > GoodCrc, NULL, NULL, NULL); > > + Status =3D AddTestCase (IpmiBlobTransfer, "Test Bad CRC Calculation"= , > "BadCrc", BadCrc, NULL, NULL, NULL); > > + // IpmiBlobTransferSendIpmi > > + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns bad com= pletion", > "SendIpmiBadCompletion", SendIpmiBadCompletion, NULL, NULL, NULL); > > + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns success= fully with > no data", "SendIpmiNoDataResponse", SendIpmiNoDataResponse, NULL, NULL, > NULL); > > + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns success= fully with > bad OEN", "SendIpmiBadOenResponse", SendIpmiBadOenResponse, NULL, NULL, > NULL); > > + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns success= fully with > bad CRC", "SendIpmiBadCrcResponse", SendIpmiBadCrcResponse, NULL, NULL, > NULL); > > + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns with va= lid > GetCount data", "SendIpmiValidCountResponse", SendIpmiValidCountResponse, > NULL, NULL, NULL); > > + // IpmiBlobTransferGetCount > > + Status =3D AddTestCase (IpmiBlobTransfer, "GetCount call with valid = data", > "GetCountValidCountResponse", GetCountValidCountResponse, NULL, NULL, > NULL); > > + // IpmiBlobTransferEnumerate > > + Status =3D AddTestCase (IpmiBlobTransfer, "Enumerate call with valid= data", > "EnumerateValidResponse", EnumerateValidResponse, NULL, NULL, NULL); > > + Status =3D AddTestCase (IpmiBlobTransfer, "Enumerate call with inval= id output > buffer", "EnumerateInvalidBuffer", EnumerateInvalidBuffer, NULL, NULL, NU= LL); > > + // 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 bu= ffer", > "ReadInvalidBuffer", ReadInvalidBuffer, NULL, NULL, NULL); > > + // IpmiBlobTransferWrite > > + Status =3D AddTestCase (IpmiBlobTransfer, "Write call with valid dat= a", > "WriteValidResponse", WriteValidResponse, NULL, NULL, NULL); > > + // IpmiBlobTransferCommit > > + Status =3D AddTestCase (IpmiBlobTransfer, "Commit call with valid da= ta", > "CommitValidResponse", CommitValidResponse, NULL, NULL, NULL); > > + // IpmiBlobTransferClose > > + Status =3D AddTestCase (IpmiBlobTransfer, "Close call with valid dat= a", > "CloseValidResponse", CloseValidResponse, NULL, NULL, NULL); > > + // IpmiBlobTransferDelete > > + Status =3D AddTestCase (IpmiBlobTransfer, "Delete call with valid da= ta", > "DeleteValidResponse", DeleteValidResponse, NULL, NULL, NULL); > > + // IpmiBlobTransferStat > > + Status =3D AddTestCase (IpmiBlobTransfer, "Blob Stat call with valid= data", > "BlobStatValidResponse", BlobStatValidResponse, NULL, NULL, NULL); > > + Status =3D AddTestCase (IpmiBlobTransfer, "Blob Stat call with inval= id buffer", > "BlobStatInvalidBuffer", BlobStatInvalidBuffer, NULL, NULL, NULL); > > + // IpmiBlobTransferSessionStat > > + Status =3D AddTestCase (IpmiBlobTransfer, "Session Stat call with va= lid data", > "SessionStatValidResponse", SessionStatValidResponse, NULL, NULL, NULL); > > + Status =3D AddTestCase (IpmiBlobTransfer, "Session Stat call with in= valid buffer", > "SessionStatInvalidBuffer", SessionStatInvalidBuffer, NULL, NULL, NULL); > > + // IpmiBlobTransferWriteMeta > > + Status =3D AddTestCase (IpmiBlobTransfer, "WriteMeta call with valid= data", > "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 > Interface defined in OpenBMC > > > +https://nam11.safelinks.protection.outlook.com/?url=3Dhttps%3A%2F%2Fgith= ub.c > om%2Fopenbmc%2Fphosphor-ipmi- > blobs&data=3D05%7C02%7Cnicklew%40nvidia.com%7Cd22932100e16475feff608d > c7645e177%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C638515289 > 789849374%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2 > luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=3DD7SscKqXG > OZWyXJUtSBIMmBUUf%2FAAK0G%2FHrH0nrqCUE%3D&reserved=3D0 > > + > > +## 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 followin= g: > > +1) The module should have a dependency on > gEdkiiIpmiBlobTransferProtocolGuid in its inf "Depex" section > > +2) The module should list gEdkiiIpmiBlobTransferProtocolGuid in its in= f > "Protocol" section > > +3) The module's entry point should do a LocateProtocol on > gEdkiiIpmiBlobTransferProtocolGuid > > + > > +### A sample flow of protocol usage is as follows: > > +1) A call to IpmiBlobTransferOpen () > > +2) Iterative calls to IpmiBlobTransferWrite > > +3) A call to IpmiBlobTransferClose () > > + > > +### Unit Tests: > > +IpmiBlobTransferDxe/UnitTest/ contains host based unit tests of this > implementation. > > +Any changes to IpmiBlobTransferDxe should include proof of successful = unit > tests. > > + > > +### Debugging > > +To assist in debugging any issues, change BLOB_TRANSFER_DEBUG to desir= ed > debug level, such as DEBUG_ERROR or DEBUG_INFO. -=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 (#119869): https://edk2.groups.io/g/devel/message/119869 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- --_000_PH8PR12MB7025D13EAE875175691200F7D9A42PH8PR12MB7025namp_ Content-Type: text/html; charset="us-ascii" Content-Transfer-Encoding: quoted-printable

Hi @Nhi Pham,

 

I am sorry for taking so long to address your rev= iew comments. I updated pull request here: https://git= hub.com/tianocore/edk2-platforms/pull/76

 

I addressed most of comments and I have questions= about below review comments. Please find my feedback inline below.

 

> Should we add a PCD for the OEN to be config= ured by platform specific

> BMC? Or this protocol is only to support Ope= nBMC.

 

Yes, per description in Readme.md, this is the pr= otocol only to support OpenBMC implementation.

 

> I'm thinking the caller sequence here. Typic= ally, the caller might check

> the presence of a blob by calling GetCount (= ) and Enumerate () before

> opening a blob session. This check here coul= d waste time. Or, do we call

> open direction the blob session without pre-= checking?

 

With this implementation, user can call open dire= ctly and it will check the presence of blob for us. And yes, this is how we= use it in NVIDIA driver.

 

> There might be developer mistake when execut= ing the transfer before

> opening the session. How do we handle this f= ailure path? Do we need to

> maintain a state machine for that?

 

Caller can only get the session ID by calling ope= n(). Session ID is required when calling read, write, and commit. If caller= make up a session ID, caller is expected to see error return.

 

> How do callers know the data format of metad= ata for writing correctly?

 

I check the spec here: https://github.com/openbmc/phosphor-ipmi-blobs?tab=3Dreadme-ov-file#bmcblob= writemeta-10  And there is no description about data format. = Since we don't use this function in our driver, may I know if you have sug= gestion for this?

 

 

> +IpmiBlobTransferDxeDriverEntryPoint (<= /o:p>

> +  IN EFI_HANDLE    = ;    ImageHandle,

> +  IN EFI_SYSTEM_TABLE  *SystemTab= le

> +  )

> +{

> +  return gBS->InstallMultipleProtoc= olInterfaces (

> +       &= nbsp;        &ImageHandle,

> Nit: Typically, we could also use gImageHand= le instead.

 

Sorry I don't follow you here.

gImageHandle is used as global variable in driver= . But here we just use the ImageHandle from function parameter and we don't= keep it as global variable, right?

 

 

Regards,

Nickle

 

> -----Original Message-----

> From: Nhi Pham <nhi@os.amperecomputing.co= m>

> Sent: Friday, May 17, 2024 3:49 PM

> To: Nickle Wang <nicklew@nvidia.com>; = devel@edk2.groups.io

> Cc: Abner Chang <abner.chang@amd.com>;= Abdul Lateef Attar

> <AbdulLateef.Attar@amd.com>; Tinh Nguy= en

> <tinhnguyen@amperemail.onmicrosoft.com>= ;; Thang Nguyen OS

> <thang@amperemail.onmicrosoft.com>; Mi= ke Maslenkin

> <mike.maslenkin@gmail.com>

> Subject: Re: [edk2-platforms][PATCH v2] Mana= geabilityPkg: add support for the

> phosphor ipmi blob transfer protocol

>

> External email: Use caution opening links or= attachments

>

>

> Hi Nickle,

>

> Please see my comments inline...

>

> P/s: I just realized that I can not test thi= s protocol without IPMI SSIF

> to be compatible with ManageabilityPkg frame= work.

>

> On 5/15/2024 10:06 PM, Nickle Wang wrote:

> >

> REF:https://nam11.safelinks.protection.outlo= ok.com/?url=3Dhttps%3A%2F%2Fbugzi

> lla.tianocore.org%2Fshow_bug.cgi%3Fid%3D4773= &data=3D05%7C02%7Cnicklew%4

> 0nvidia.com%7Cd22932100e16475feff608dc7645e1= 77%7C43083d15727340c1b7

> db39efd9ccc17a%7C0%7C0%7C638515289789817250%= 7CUnknown%7CTWFpb

> GZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiL= CJBTiI6Ik1haWwiLCJXVCI6Mn

> 0%3D%7C0%7C%7C%7C&sdata=3D99Xm%2B3kir7Cn= WHFt%2FI04nBAuLT2SPeOKPE

> DIGkZpz%2FM%3D&reserved=3D0

> >

> > This change implements the blob transfe= r protocol used in OpenBmc

> > documented here:

> https://nam11.safelin= ks.protection.outlook.com/?url=3Dhttps%3A%2F%2Fgithub.co

> m%2Fop= enbmc%2Fphosphor-ipmi-

> blobs&= amp;data=3D05%7C02%7Cnicklew%40nvidia.com%7Cd22932100e16475feff608d<= /a>

> c7645e= 177%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C638515289

> 789828= 686%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2

> luMzIi= LCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=3Dcqngm6B%=

> 2F%2BG= OfyIp5YqxVLVUvyHzRdpfiwcWNSD3SwZk%3D&reserved=3D0

> >

> > Signed-off-by: Nick Ramirez <nramirez@nvidia.com>

> > Co-authored-by: Nickle Wang <nicklew@nvidia.com>

> > Cc: Abner Chang <a= bner.chang@amd.com>

> > Cc: Abdul Lateef Attar <AbdulLateef.Attar@amd.com>

> > Cc: Tinh Nguyen <tinhnguyen@amperemail.onmicrosoft.com>

> > Cc: Nhi Pham <nhi@os.amperecomputing.com>

> > Cc: Thang Nguyen OS <thang@amperemail.onmicrosoft.com>

> > Cc: Mike Maslenkin <mike.maslenkin@gmail.com>

> > ---

> >   .../ManageabilityPkg/Manage= abilityPkg.dec     |    3 +

> >   .../Include/Manageability.d= sc            &= nbsp;    |    2 +

> >   .../IpmiBlobTransferDxe.inf=             &nb= sp;      |   39 +

> >   .../IpmiBlobTransferTestUni= tTestsHost.inf     |   40 +

> >   .../Include/Protocol/IpmiBl= obTransfer.h       |  253 ++++

> >   .../InternalIpmiBlobTransfe= r.h            =     |  407 ++++++

> >   .../IpmiBlobTransferDxe/Ipm= iBlobTransferDxe.c |  872 +++++++++++++

> >   .../UnitTest/IpmiBlobTransf= erTestUnitTests.c  | 1113 +++++++++++++++++

> >   .../Universal/IpmiBlobTrans= ferDxe/Readme.md   |   24 +

> >   9 files changed, 2753 inser= tions(+)

> >   create mode 100644

> Features/ManageabilityPkg/Universal/IpmiBlob= TransferDxe/IpmiBlobTransferDxe

> .inf

> >   create mode 100644

> Features/ManageabilityPkg/Universal/IpmiBlob= TransferDxe/UnitTest/IpmiBlobTr

> ansferTestUnitTestsHost.inf

> >   create mode 100644

> Features/ManageabilityPkg/Include/Protocol/I= pmiBlobTransfer.h

> >   create mode 100644

> Features/ManageabilityPkg/Universal/IpmiBlob= TransferDxe/InternalIpmiBlobTra

> nsfer.h

> >   create mode 100644

> Features/ManageabilityPkg/Universal/IpmiBlob= TransferDxe/IpmiBlobTransferDxe

> .c

> >   create mode 100644

> Features/ManageabilityPkg/Universal/IpmiBlob= TransferDxe/UnitTest/IpmiBlobTr

> ansferTestUnitTests.c

> >   create mode 100644

> Features/ManageabilityPkg/Universal/IpmiBlob= TransferDxe/Readme.md

> >

> > diff --git a/Features/ManageabilityPkg/= ManageabilityPkg.dec

> b/Features/ManageabilityPkg/ManageabilityPkg= .dec

> > index eb0ee67cba..dc1d00162c 100644

> > --- a/Features/ManageabilityPkg/Managea= bilityPkg.dec

> > +++ b/Features/ManageabilityPkg/Managea= bilityPkg.dec

> > @@ -4,6 +4,7 @@

> >   # those are related to the = platform management.

> >   #

> >   # Copyright (C) 2023 Advanc= ed Micro Devices, Inc. All rights reserved.<BR>

> > +# Copyright (c) 2024, NVIDIA CORPORATI= ON & AFFILIATES. All rights reserved.

> >   # SPDX-License-Identifier: = BSD-2-Clause-Patent

> >   #

> >   ##

> > @@ -58,6 +59,8 @@

> >     gEdkiiPldmProto= colGuid           &n= bsp;    =3D { 0x60997616, 0xDB70, 0x4B5F, { 0x86,

> 0xA4, 0x09, 0x58, 0xA3, 0x71, 0x47, 0xB4 } }=

> >     gEdkiiPldmSmbio= sTransferProtocolGuid  =3D { 0xFA431C3C, 0x816B, 0x4B32,

> { 0xA3, 0xE0, 0xAD, 0x9B, 0x7F, 0x64, 0x27, = 0x2E } }

> >     gEdkiiMctpProto= colGuid           &n= bsp;    =3D { 0xE93465C1, 0x9A31, 0x4C96, { 0x92,

> 0x56, 0x22, 0x0A, 0xE1, 0x80, 0xB4, 0x1B } }=

> > +  ## Include/Protocol/IpmiBlobTra= nsfer.h

> > +  gEdkiiIpmiBlobTransferProtocolG= uid    =3D { 0x05837c75, 0x1d65, 0x468b,

> { 0xb1, 0xc2, 0x81, 0xaf, 0x9a, 0x31, 0x5b, = 0x2c } }

> >

> >   [PcdsFixedAtBuild]

> >     ## This value i= s the MCTP Interface source and destination endpoint ID for

> transmiting MCTP message.

> > diff --git a/Features/ManageabilityPkg/= Include/Manageability.dsc

> b/Features/ManageabilityPkg/Include/Manageab= ility.dsc

> > index 2e410df9ba..aae343a733 100644

> > --- a/Features/ManageabilityPkg/Include= /Manageability.dsc

> > +++ b/Features/ManageabilityPkg/Include= /Manageability.dsc

> > @@ -2,6 +2,7 @@

> >   # Common libraries for Mana= geabilty Package

> >   #

> >   # Copyright (C) 2023 Advanc= ed Micro Devices, Inc. All rights reserved.<BR>

> > +# Copyright (c) 2024, NVIDIA CORPORATI= ON & AFFILIATES. All rights reserved.

> >   # SPDX-License-Identifier: = BSD-2-Clause-Patent

> >   #

> >   ##

> > @@ -37,6 +38,7 @@

> >   [Components.X64, Components= .AARCH64]

> >   !if gManageabilityPkgTokenS= paceGuid.PcdManageabilityDxeIpmiEnable =3D=3D

> TRUE

> >     ManageabilityPk= g/Universal/IpmiProtocol/Dxe/IpmiProtocolDxe.inf

> > +  ManageabilityPkg/Universal/Ipmi= BlobTransferDxe/IpmiBlobTransferDxe.inf

> >   !endif

> >

> >   [Components.X64]

> > diff --git

> a/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/IpmiBlobTransferD

> xe.inf

> b/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/IpmiBlobTransferD

> xe.inf

> > new file mode 100644

> > index 0000000000..108f4bb5f8

> > --- /dev/null

> > +++

> b/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/IpmiBlobTransferD

> xe.inf

> > @@ -0,0 +1,39 @@

> > +## @file

> > +# IPMI Blob Transfer Protocol DXE Driv= er.

> > +#

> > +#  Copyright (c) 2022-2024, NVIDI= A CORPORATION & AFFILIATES. All rights

> reserved.

> > +#

> > +#  SPDX-License-Identifier: BSD-2= -Clause-Patent

> > +#

> > +

> > +[Defines]

> > +  INF_VERSION   &n= bsp;            = ;    =3D 0x00010005

> > +  BASE_NAME   &nbs= p;            &= nbsp;     =3D IpmiBlobTransferDxe

> > +  FILE_GUID   &nbs= p;            &= nbsp;     =3D 6357c804-78bb-4b0c-abdf-c75df942f319

> > +  MODULE_TYPE   &n= bsp;            = ;    =3D DXE_DRIVER

> > +  VERSION_STRING   = ;            &n= bsp; =3D 1.0

> > +  ENTRY_POINT   &n= bsp;            = ;    =3D IpmiBlobTransferDxeDriverEntryPoint

> > +

> > +[Sources.common]

> > +  IpmiBlobTransferDxe.c

> > +

> > +[LibraryClasses]

> > +  BaseLib

> > +  BaseMemoryLib

> > +  DebugLib

> > +  IpmiLib

> > +  MemoryAllocationLib

> > +  PcdLib

> > +  UefiBootServicesTableLib

> > +  UefiDriverEntryPoint

> > +

> > +[Packages]

> > +  MdePkg/MdePkg.dec

> > +  MdeModulePkg/MdeModulePkg.dec

> > +  ManageabilityPkg/ManageabilityP= kg.dec

> > +

> > +[Protocols]

> > +  gEdkiiIpmiBlobTransferProtocolG= uid

> > +

> > +[Depex]

> > +  TRUE

> > diff --git

> a/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/UnitTest/IpmiBlob

> TransferTestUnitTestsHost.inf

> b/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/UnitTest/IpmiBlob

> TransferTestUnitTestsHost.inf

> > new file mode 100644

> > index 0000000000..dab6858f09

> > --- /dev/null

> > +++

> b/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/UnitTest/IpmiBlob

> TransferTestUnitTestsHost.inf

> > @@ -0,0 +1,40 @@

> > +## @file

> > +# Unit tests of the Ipmi blob transfer= driver that are run from a host

> environment.

> > +#

> > +# Copyright (c) 2020-2024, NVIDIA CORP= ORATION & AFFILIATES. All rights

> reserved.

> > +#

> > +# SPDX-License-Identifier: BSD-2-Claus= e-Patent

> > +##

> > +

> > +[Defines]

> > +  INF_VERSION   &n= bsp;            = ;    =3D 0x00010006

> > +  BASE_NAME   &nbs= p;            &= nbsp;     =3D IpmiBlobTransferDxeUnitTestsHost

> > +  FILE_GUID   &nbs= p;            &= nbsp;     =3D 1f5d4095-ea52-432c-b078-86097fef6004

> > +  MODULE_TYPE   &n= bsp;            = ;    =3D HOST_APPLICATION

> > +  VERSION_STRING   = ;            &n= bsp; =3D 1.0

> > +

> > +#

> > +# The following information is for ref= erence only

> > +# and not required by the build tools.=

> > +#

> > +#  VALID_ARCHITECTURES  = ;         =3D X64

> > +#

> > +

> > +[Sources]

> > +  IpmiBlobTransferTestUnitTests.c=

> > +

> > +[Packages]

> > +  MdePkg/MdePkg.dec

> > +  MdeModulePkg/MdeModulePkg.dec

> > +  ManageabilityPkg/ManageabilityP= kg.dec

> > +  UnitTestFrameworkPkg/UnitTestFr= ameworkPkg.dec

> > +

> > +[LibraryClasses]

> > +  BaseLib

> > +  BaseMemoryLib

> > +  DebugLib

> > +  UnitTestLib

> > +  IpmiLib

> > +

> > +[Protocols]

> > +  gEdkiiIpmiBlobTransferProtocolG= uid

> > diff --git a/Features/ManageabilityPkg/= Include/Protocol/IpmiBlobTransfer.h

> b/Features/ManageabilityPkg/Include/Protocol= /IpmiBlobTransfer.h

> > new file mode 100644

> > index 0000000000..14b5294314

> > --- /dev/null

> > +++ b/Features/ManageabilityPkg/Include= /Protocol/IpmiBlobTransfer.h

> > @@ -0,0 +1,253 @@

> > +/** @file

> > +

> > +  IPMI Blob Transfer driver

> > +

> > +  Copyright (c) 2022-2024, NVIDIA= CORPORATION & AFFILIATES. All rights

> reserved.

> > +

> > +  SPDX-License-Identifier: BSD-2-= Clause-Patent

> > +

> > +  @Par:

> https://nam11.safelin= ks.protection.outlook.com/?url=3Dhttps%3A%2F%2Fgithub.co

> m%2Fopenbmc%2Fphosphor-ipmi-

> blobs%2Fblob%2Fmaster%2FREADME.md&data=3D05%7C02%7Cnick= lew%40nvidia

> .com%7Cd22932100e16475feff608dc7645e177%7C43083d15727340c1b= 7db39ef

> d9ccc17a%7C0%7C0%7C638515289789834490%7CUnknown%7CTWFpbGZsb= 3d

> 8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVC= I6Mn0%3D

> %7C0%7C%7C%7C&sdata=3Dq6CCTU5qwF8mHHYus0AcBlZGCJpqNARsB= 9SO697NT

> o0%3D&reserved=3D0

> > +**/

>

> Lack of header guard

> #ifndef IPMI_BLOB_TRANSFER_H_

>

> > +#include <Library/IpmiLib.h>

> > +#include <Library/UefiBootServicesT= ableLib.h>

> > +#include <IndustryStandard/Ipmi.h&g= t;

> > +#include <IndustryStandard/IpmiNetF= nOem.h>

> > +

> > +#define IPMI_OEM_BLOB_TRANSFER_CMD&nbs= p; 0x80

> > +

> > +#define BLOB_TRANSFER_STAT_OPEN_R = ;       BIT0

> > +#define BLOB_TRANSFER_STAT_OPEN_W = ;       BIT1

> > +#define BLOB_TRANSFER_STAT_COMMITING&n= bsp;    BIT2

> > +#define BLOB_TRANSFER_STAT_COMMITTED&n= bsp;    BIT3

> > +#define BLOB_TRANSFER_STAT_COMMIT_ERRO= R  BIT4

> > +// Bits 5-7 are reserved

> > +// Bits 8-15 are blob-specific definit= ions

> > +

> > +//

> > +// OpenBMC OEN code in little endian f= ormat

> > +//

> > +const UINT8  OpenBmcOen[] =3D { 0= xCF, 0xC2, 0x00 };

>

> const -> CONST

>

> Should we add a PCD for the OEN to be config= ured by platform specific

> BMC? Or this protocol is only to support Ope= nBMC.

>

> > +

> > +//

> > +//  Blob Transfer Function Protot= ypes

> > +//

> > +

> > +/**

> > +  This function retrieves the cou= nt of blob transfers available through the IPMI.

> > +

> > +  @param[out]   &n= bsp;    Count       The number= of active blobs

> > +

> > +  @retval EFI_SUCCESS  =           Successfully retriev= ed the number of active

> blobs.

> > +  @retval Other   =             &nb= sp;  An error occurred

> > +**/

> > +typedef

> > +EFI_STATUS

> > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROT= OCOL_GET_COUNT)(

> > +  OUT UINT32 *Count

> > +  );

> > +

> > +/**

> > +  This function enumerates blob t= ransfers available through the IPMI.

> > +

> > +  @param[in]   &nb= sp;     BlobIndex       T= he 0-based Index of the blob to enumerate

> > +  @param[out]   &n= bsp;    BlobId       &nbs= p;  The ID of the blob

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successfully enumerated the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +typedef

> > +EFI_STATUS

> > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROT= OCOL_ENUMERATE)(

> > +  IN  UINT32  BlobIndex= ,

> > +  OUT CHAR8   *BlobId

> > +  );

> > +

> > +/**

> > +  This function is designed to op= en a session for a specific blob

> > +  identified by its ID, using the= IPMI.

> > +

> > +  @param[in]   &nb= sp;     BlobId       = ;   The ID of the blob to open

> > +  @param[in]   &nb= sp;     Flags       =     Flags to control how the blob is opened

> > +  @param[out]   &n= bsp;    SessionId       A uniq= ue session identifier

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successfully opened the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +typedef

> > +EFI_STATUS

> > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROT= OCOL_OPEN)(

> > +  IN  CHAR8  *BlobId,

> > +  IN  UINT16 Flags,

> > +  OUT UINT16 *SessionId

> > +  );

> > +

> > +/**

> > +  This function reads data from a= blob over the IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId       T= he session ID returned from a call to

> BlobOpen

> > +  @param[in]   &nb= sp;     Offset       = ;   The offset of the blob from which to start

> reading

> > +  @param[in]   &nb= sp;     RequestedSize   The length of data to= read

> > +  @param[out]   &n= bsp;    Data        =     Data read from the blob

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successfully read from the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +typedef

> > +EFI_STATUS

> > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROT= OCOL_READ)(

> > +  IN  UINT16  &nbs= p;   SessionId,

> > +  IN  UINT32  &nbs= p;   Offset,

> > +  IN  UINT32  &nbs= p;   RequestedSize,

> > +  OUT UINT8   &nbs= p;   *Data

> > +  );

> > +

> > +/**

> > +  This function writes data to a = blob over the IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId       T= he session ID returned from a call to

> BlobOpen

> > +  @param[in]   &nb= sp;     Offset       = ;   The offset of the blob from which to start writing

> > +  @param[in]   &nb= sp;     Data       &= nbsp;    A pointer to the data to write

> > +  @param[in]   &nb= sp;     WriteLength     The length = to write

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successfully wrote to the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +typedef

> > +EFI_STATUS

> > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROT= OCOL_WRITE)(

> > +  IN  UINT16  &nbs= p;   SessionId,

> > +  IN  UINT32  &nbs= p;   Offset,

> > +  IN  UINT8   = ;    *Data,

> > +  IN  UINT32  &nbs= p;   WriteLength

> > +  );

> > +

> > +/**

> > +  This function commits data to a= blob over the IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId      &n= bsp; The session ID returned from a call to

> BlobOpen

> > +  @param[in]   &nb= sp;     CommitDataLength The length of data to commit t= o the blob

> > +  @param[in]   &nb= sp;     CommitData       = A pointer to the data to commit

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successful commit to the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +typedef

> > +EFI_STATUS

> > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROT= OCOL_COMMIT)(

> > +  IN  UINT16  &nbs= p;   SessionId,

> > +  IN  UINT8   = ;    CommitDataLength,

> > +  IN  UINT8   = ;    *CommitData

> > +  );

> > +

> > +/**

> > +  This function close a session a= ssociated with a blob transfer over the IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId       T= he session ID returned from a call to

> BlobOpen

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob was closed.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +typedef

> > +EFI_STATUS

> > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROT= OCOL_CLOSE)(

> > +  IN  UINT16  &nbs= p;   SessionId

> > +  );

> > +

> > +/**

> > +  This function deletes a specifi= c blob identified by its ID over the IPMI.

> > +

> > +  @param[in]   &nb= sp;     BlobId       = ;   The BlobId to be deleted

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob was deleted.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +typedef

> > +EFI_STATUS

> > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROT= OCOL_DELETE)(

> > +  IN  CHAR8 *BlobId

> > +  );

> > +

> > +/**

> > +  This function retrieve the stat= us of a specific blob identified by BlobId from an

> IPMI.

> > +

> > +  @param[in]   &nb= sp;     BlobId       = ;   The Blob ID to gather statistics for

> > +  @param[out]   &n= bsp;    BlobState       The cu= rrent state of the blob

> > +  @param[out]   &n= bsp;    Size        =     Size in bytes of the blob

> > +  @param[out]   &n= bsp;    MetadataLength  Length of the optional metadata=

> > +  @param[out]   &n= bsp;    Metadata        O= ptional blob-specific metadata

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob statistics were successfully gathered.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +typedef

> > +EFI_STATUS

> > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROT= OCOL_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]   &nb= sp;     SessionId       T= he ID of the session to gather statistics for

> > +  @param[out]   &n= bsp;    BlobState       The cu= rrent state of the blob

> > +  @param[out]   &n= bsp;    Size        =     Size in bytes of the blob

> > +  @param[out]   &n= bsp;    MetadataLength  Length of the optional metadata=

> > +  @param[out]   &n= bsp;    Metadata        O= ptional blob-specific metadata

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob statistics were successfully gathered.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +typedef

> > +EFI_STATUS

> > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROT= OCOL_SESSION_STAT)(

> > +  IN  UINT16 SessionId,

> > +  OUT UINT16 *BlobState,

> > +  OUT UINT32 *Size,

> > +  OUT UINT8  *MetadataLength= ,

> > +  OUT UINT8  *Metadata

> > +  );

> > +

> > +/**

> > +  This function writes metadata t= o a blob associated with a session in an IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId       T= he ID of the session to write metadata for

> > +  @param[in]   &nb= sp;     Offset       = ;   The offset of the metadata to write to

> > +  @param[in]   &nb= sp;     Data       &= nbsp;    The data to write to the metadata

> > +  @param[in]   &nb= sp;     WriteLength     The length = to write

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob metadata was successfully written.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +typedef

> > +EFI_STATUS

> > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROT= OCOL_WRITE_META)(

> > +  IN  UINT16  &nbs= p;   SessionId,

> > +  IN  UINT32  &nbs= p;   Offset,

> > +  IN  UINT8   = ;    *Data,

> > +  IN  UINT32  &nbs= p;   WriteLength

> > +  );

> > +

> > +//

> > +// Structure of EDKII_IPMI_BLOB_TRANSF= ER_PROTOCOL

> > +//

> > +struct _EDKII_IPMI_BLOB_TRANSFER_PROTO= COL {

> > +  EDKII_IPMI_BLOB_TRANSFER_PROTOC= OL_GET_COUNT       BlobGetCount;

> > +  EDKII_IPMI_BLOB_TRANSFER_PROTOC= OL_ENUMERATE       BlobEnumerate;

> > +  EDKII_IPMI_BLOB_TRANSFER_PROTOC= OL_OPEN            B= lobOpen;

> > +  EDKII_IPMI_BLOB_TRANSFER_PROTOC= OL_READ            B= lobRead;

> > +  EDKII_IPMI_BLOB_TRANSFER_PROTOC= OL_WRITE           BlobWr= ite;

> > +  EDKII_IPMI_BLOB_TRANSFER_PROTOC= OL_COMMIT          BlobCommit;=

> > +  EDKII_IPMI_BLOB_TRANSFER_PROTOC= OL_CLOSE           BlobCl= ose;

> > +  EDKII_IPMI_BLOB_TRANSFER_PROTOC= OL_DELETE          BlobDelete;=

> > +  EDKII_IPMI_BLOB_TRANSFER_PROTOC= OL_STAT            B= lobStat;

> > +  EDKII_IPMI_BLOB_TRANSFER_PROTOC= OL_SESSION_STAT    BlobSessionStat;

> > +  EDKII_IPMI_BLOB_TRANSFER_PROTOC= OL_WRITE_META      BlobWriteMeta;

> > +};

> > +

> > +typedef struct _EDKII_IPMI_BLOB_TRANSF= ER_PROTOCOL

> EDKII_IPMI_BLOB_TRANSFER_PROTOCOL;

> > +

> > +extern EFI_GUID  gEdkiiIpmiBlobTr= ansferProtocolGuid;

> > diff --git

> a/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/InternalIpmiBlobTr

> ansfer.h

> b/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/InternalIpmiBlobTr

> ansfer.h

> > new file mode 100644

> > index 0000000000..3e90dc6871

> > --- /dev/null

> > +++

> b/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/InternalIpmiBlobTr

> ansfer.h

> > @@ -0,0 +1,407 @@

> > +/** @file

> > +

> > +  Headers for IPMI Blob Transfer = driver

> > +

> > +  Copyright (c) 2022-2024, NVIDIA= CORPORATION & AFFILIATES. All rights

> reserved.

> > +

> > +  SPDX-License-Identifier: BSD-2-= Clause-Patent

> > +

> > +**/

> > +

>

> Lack of header guard

> #ifndef INTERNAL_IPMI_BLOB_TRANSFER_H_

>

> > +#include <Library/BaseLib.h>

> > +#include <Library/BaseMemoryLib.h&g= t;

> > +#include <Library/DebugLib.h>

> > +#include <Library/IpmiLib.h>

> > +#include <Library/MemoryAllocationL= ib.h>

> > +#include <Library/PcdLib.h>

> > +

> > +#define PROTOCOL_RESPONSE_OVERHEAD&nbs= p; (4 * sizeof(UINT8))       // 1 byte

> completion code + 3 bytes OEN

>

> Nit: Add a space after sizeof

>

> > +#define BLOB_MAX_DATA_PER_PACKET =    64

>

> Should it be moved to Include/Protocol/IpmiB= lobTransfer.h? The caller

> could need to be aware the max length of the= package.

>

> > +

> > +// Subcommands for this protocol

> > +typedef enum {

> > +  IpmiBlobTransferSubcommandGetCo= unt =3D 0,

> > +  IpmiBlobTransferSubcommandEnume= rate,

> > +  IpmiBlobTransferSubcommandOpen,=

> > +  IpmiBlobTransferSubcommandRead,=

> > +  IpmiBlobTransferSubcommandWrite= ,

> > +  IpmiBlobTransferSubcommandCommi= t,

> > +  IpmiBlobTransferSubcommandClose= ,

> > +  IpmiBlobTransferSubcommandDelet= e,

> > +  IpmiBlobTransferSubcommandStat,=

> > +  IpmiBlobTransferSubcommandSessi= onStat,

> > +  IpmiBlobTransferSubcommandWrite= Meta,

> > +} IPMI_BLOB_TRANSFER_SUBCOMMANDS;

> > +

> > +#pragma pack(1)

> > +

> > +typedef struct {

> > +  UINT8    OEN[3];=

> > +  UINT8    SubComm= and;

> > +} IPMI_BLOB_TRANSFER_HEADER;

> > +

> > +//

> > +// Command 0 - BmcBlobGetCount

> > +// The BmcBlobGetCount command expects= to receive an empty body.

> > +// The BMC will return the number of e= numerable blobs

> > +//

> > +typedef struct {

> > +  UINT32    BlobCo= unt;

> > +} IPMI_BLOB_TRANSFER_GET_COUNT_RESPONS= E;

> > +

> > +//

> > +// Command 1 - BmcBlobEnumerate

> > +// The BmcBlobEnumerate command expect= s to receive a body of:

> > +//

> > +typedef struct {

> > +  UINT32    BlobIn= dex; // 0-based index of blob to receive

> > +} IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SE= ND_DATA;

> > +

> > +typedef struct {

> > +  CHAR8    BlobId[= BLOB_MAX_DATA_PER_PACKET];

> > +} IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_RE= SPONSE;

> > +

> > +//

> > +// Command 2 - BmcBlobOpen

> > +// The BmcBlobOpen command expects to = receive a body of:

> > +//

> > +typedef struct {

> > +  UINT16    Flags;=

> > +  CHAR8     B= lobId[BLOB_MAX_DATA_PER_PACKET];

> > +} IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DA= TA;

> > +

> > +#define BLOB_OPEN_FLAG_READ  = ; 0

> > +#define BLOB_OPEN_FLAG_WRITE  1

> > +// Bits 2-7 are reserved

> > +// Bits 8-15 are blob-specific definit= ions

> > +

> > +typedef struct {

> > +  UINT16    Sessio= nId;

> > +} IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONS= E;

> > +

> > +//

> > +// Command 3 - BmcBlobRead

> > +// The BmcBlobRead command expects to = receive a body of:

> > +//

> > +typedef struct {

> > +  UINT16    Sessio= nId; // Returned from BlobOpen

> > +  UINT32    Offset= ;

> > +  UINT32    Reques= tedSize;

> > +} IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DA= TA;

> > +

> > +typedef struct {

> > +  UINT8    Data[BL= OB_MAX_DATA_PER_PACKET];

> > +} IPMI_BLOB_TRANSFER_BLOB_READ_RESPONS= E;

> > +

> > +//

> > +// Command 4 - BmcBlobWrite

> > +// The BmcBlobWrite command expects to= receive a body of:

> > +//

> > +typedef struct {

> > +  UINT16    Sessio= nId; // Returned from BlobOpen

> > +  UINT32    Offset= ;

> > +  UINT8     D= ata[BLOB_MAX_DATA_PER_PACKET];

> > +} IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_D= ATA;

> > +

> > +//

> > +// Command 5 - BmcBlobCommit

> > +// The BmcBlobCommit command expects t= o receive a body of:

> > +//

> > +typedef struct {

> > +  UINT16    Sessio= nId; // Returned from BlobOpen

> > +  UINT8     C= ommitDataLength;

> > +  UINT8     C= ommitData[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    Sessio= nId; // Returned from BlobOpen

> > +} IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_D= ATA;

> > +

> > +//

> > +// Command 7 - BmcBlobDelete

> > +// NOTE: This command will fail if the= re are open sessions for this blob

> > +// The BmcBlobDelete command expects t= o 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 abo= ut a blob.

> > +// This command expects to receive a b= ody of:

> > +//

> > +typedef struct {

> > +  CHAR8    BlobId[= BLOB_MAX_DATA_PER_PACKET];

> > +} IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DA= TA;

> > +

> > +typedef struct {

> > +  UINT16    BlobSt= ate;

> > +  UINT32    Size; = // Size in bytes of the blob

> > +  UINT8     M= etaDataLen;

> > +  UINT8     M= etaData[BLOB_MAX_DATA_PER_PACKET];

> > +} IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONS= E;

> > +

> > +//

> > +// Command 9 - BmcBlobSessionStat

> > +// Returns same data as BmcBlobState e= xpect for a session, not a blob

> > +// This command expects to receive a b= ody of:

> > +//

> > +typedef struct {

> > +  UINT16    Sessio= nId;

> > +} IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT= _SEND_DATA;

> > +

> > +typedef struct {

> > +  UINT16    BlobSt= ate;

> > +  UINT32    Size; = // Size in bytes of the blob

> > +  UINT8     M= etaDataLen;

> > +  UINT8     M= etaData[BLOB_MAX_DATA_PER_PACKET];

> > +} IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT= _RESPONSE;

> > +

> > +//

> > +// Command 10 - BmcBlobWriteMeta

> > +// The BmcBlobWriteMeta command expect= s to receive a body of:

> > +//

> > +typedef struct {

> > +  UINT16    Sessio= nId;

> > +  UINT32    Offset= ;

> > +  UINT8     D= ata[BLOB_MAX_DATA_PER_PACKET];

> > +} IPMI_BLOB_TRANSFER_BLOB_WRITE_META_S= END_DATA;

> > +

> > +#define IPMI_BLOB_TRANSFER_BLOB_WRITE_= META_RESPONSE  NULL

> > +

> > +#pragma pack()

> > +

> > +/**

> > +  Calculate CRC-16-CCITT with pol= y of 0x1021

> > +

> > +  @param[in]  Data &nbs= p;            The ta= rget 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 transfe= r over IPMI command.

> > +

> > +  @param[in]  SubCommand&nbs= p;       The specific sub-command to be execu= ted as

> part of

> > +      &n= bsp;            = ;             t= he blob transfer operation.

> > +  @param[in]  SendData =          A pointer to the data buff= er that contains the

> data to be sent.

> > +  @param[in]  SendDataSize&n= bsp;     The size of the data to be sent, in bytes.

> > +  @param[out] ResponseData &= nbsp;    A pointer to the buffer where the response

> data will be stored.

> > +  @param[out] ResponseDataSize&nb= sp; A pointer to a variable that will hold the size

> of the response

> > +      &n= bsp;            = ;             d= ata received.

> > +

> > +  @retval EFI_SUCCESS  =           Successfully sends b= lob data.

> > +  @retval EFI_OUT_OF_RESOURCES&nb= sp;  Memory allocation fails.

> > +  @retval EFI_PROTOCOL_ERROR = ;    Communication errors.

> > +  @retval EFI_CRC_ERROR &nbs= p;        Data integrity checks fail.

> > +  @retval Other   =             &nb= sp;  An error occurred

> > +

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferSendIpmi (

> > +  IN  UINT8   SubC= ommand,

> > +  IN  UINT8   *Sen= dData,

> > +  IN  UINT32  SendDataS= ize,

> > +  OUT UINT8   *Response= Data,

> > +  OUT UINT32  *ResponseDataS= ize

> > +  );

> > +

> > +/**

> > +  This function retrieves the cou= nt of blob transfers available through the IPMI.

> > +

> > +  @param[out]   &n= bsp;    Count       The number= of active blobs

> > +

> > +  @retval EFI_SUCCESS  =           Successfully retriev= ed the number of active

> blobs.

> > +  @retval Other   =             &nb= sp;  An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferGetCount (

> > +  OUT UINT32  *Count

> > +  );

> > +

> > +/**

> > +  This function enumerates blob t= ransfers available through the IPMI.

> > +

> > +  @param[in]   &nb= sp;     BlobIndex       T= he 0-based Index of the blob to enumerate

> > +  @param[out]   &n= bsp;    BlobId       &nbs= p;  The ID of the blob

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successfully enumerated the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferEnumerate (

> > +  IN  UINT32  BlobIndex= ,

> > +  OUT CHAR8   *BlobId

> > +  );

> > +

> > +/**

> > +  This function is designed to op= en a session for a specific blob

> > +  identified by its ID, using the= IPMI.

> > +

> > +  @param[in]   &nb= sp;     BlobId       = ;   The ID of the blob to open

> > +  @param[in]   &nb= sp;     Flags       =     Flags to control how the blob is opened

> > +  @param[out]   &n= bsp;    SessionId       A uniq= ue session identifier

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successfully opened the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferOpen (

> > +  IN  CHAR8   *Blo= bId,

> > +  IN  UINT16  Flags,

> > +  OUT UINT16  *SessionId

> > +  );

> > +

> > +/**

> > +  This function reads data from a= blob over the IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId       T= he session ID returned from a call to

> BlobOpen

> > +  @param[in]   &nb= sp;     Offset       = ;   The offset of the blob from which to start

> reading

> > +  @param[in]   &nb= sp;     RequestedSize   The length of data to= read

> > +  @param[out]   &n= bsp;    Data        =     Data read from the blob

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successfully read from the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferRead (

> > +  IN  UINT16  SessionId= ,

> > +  IN  UINT32  Offset,

> > +  IN  UINT32  Requested= Size,

> > +  OUT UINT8   *Data

> > +  );

> > +

> > +/**

> > +  This function writes data to a = blob over the IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId       T= he session ID returned from a call to

> BlobOpen

> > +  @param[in]   &nb= sp;     Offset       = ;   The offset of the blob from which to start writing

> > +  @param[in]   &nb= sp;     Data       &= nbsp;    A pointer to the data to write

> > +  @param[in]   &nb= sp;     WriteLength     The length = to write

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successfully wrote to the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferWrite (

> > +  IN  UINT16  SessionId= ,

> > +  IN  UINT32  Offset,

> > +  IN  UINT8   *Dat= a,

> > +  IN  UINT32  WriteLeng= th

> > +  );

> > +

> > +/**

> > +  This function commits data to a= blob over the IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId      &n= bsp; The session ID returned from a call to

> BlobOpen

> > +  @param[in]   &nb= sp;     CommitDataLength The length of data to commit t= o the blob

> > +  @param[in]   &nb= sp;     CommitData       = A pointer to the data to commit

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successful commit to the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferCommit (

> > +  IN  UINT16  SessionId= ,

> > +  IN  UINT8   Comm= itDataLength,

> > +  IN  UINT8   *Com= mitData

> > +  );

> > +

> > +/**

> > +  This function close a session a= ssociated with a blob transfer over the IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId       T= he session ID returned from a call to

> BlobOpen

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob was closed.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferClose (

> > +  IN  UINT16  SessionId=

> > +  );

> > +

> > +/**

> > +  This function deletes a specifi= c blob identified by its ID over the IPMI.

> > +

> > +  @param[in]   &nb= sp;     BlobId       = ;   The BlobId to be deleted

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob was deleted.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferDelete (

> > +  IN  CHAR8  *BlobId

> > +  );

> > +

> > +/**

> > +  This function retrieve the stat= us of a specific blob identified by BlobId from an

> IPMI.

> > +

> > +  @param[in]   &nb= sp;     BlobId       = ;   The Blob ID to gather statistics for

> > +  @param[out]   &n= bsp;    BlobState       The cu= rrent state of the blob

> > +  @param[out]   &n= bsp;    Size        =     Size in bytes of the blob

> > +  @param[out]   &n= bsp;    MetadataLength  Length of the optional metadata=

> > +  @param[out]   &n= bsp;    Metadata        O= ptional blob-specific metadata

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob statistics were successfully gathered.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferStat (

> > +  IN  CHAR8   *Blo= bId,

> > +  OUT UINT16  *BlobState,

> > +  OUT UINT32  *Size,

> > +  OUT UINT8   *Metadata= Length,

> > +  OUT UINT8   *Metadata=

> > +  );

> > +

> > +/**

> > +  This function query the status = of a blob transfer session in an IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId       T= he ID of the session to gather statistics for

> > +  @param[out]   &n= bsp;    BlobState       The cu= rrent state of the blob

> > +  @param[out]   &n= bsp;    Size        =     Size in bytes of the blob

> > +  @param[out]   &n= bsp;    MetadataLength  Length of the optional metadata=

> > +  @param[out]   &n= bsp;    Metadata        O= ptional blob-specific metadata

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob statistics were successfully gathered.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferSessionStat (

> > +  IN  UINT16  SessionId= ,

> > +  OUT UINT16  *BlobState,

> > +  OUT UINT32  *Size,

> > +  OUT UINT8   *Metadata= Length,

> > +  OUT UINT8   *Metadata=

> > +  );

> > +

> > +/**

> > +  This function writes metadata t= o a blob associated with a session in an IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId       T= he ID of the session to write metadata for

> > +  @param[in]   &nb= sp;     Offset       = ;   The offset of the metadata to write to

> > +  @param[in]   &nb= sp;     Data       &= nbsp;    The data to write to the metadata

> > +  @param[in]   &nb= sp;     WriteLength     The length = to write

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob metadata was successfully written.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferWriteMeta (

> > +  IN  UINT16  SessionId= ,

> > +  IN  UINT32  Offset,

> > +  IN  UINT8   *Dat= a,

> > +  IN  UINT32  WriteLeng= th

> > +  );

> > diff --git

> a/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/IpmiBlobTransferD

> xe.c

> b/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/IpmiBlobTransferD

> xe.c

> > new file mode 100644

> > index 0000000000..b8a2db193b

> > --- /dev/null

> > +++

> b/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/IpmiBlobTransferD

> xe.c

> > @@ -0,0 +1,872 @@

> > +/** @file

> > +

> > +  IPMI Blob Transfer driver

> > +

> > +  Copyright (c) 2022-2024, NVIDIA= CORPORATION & AFFILIATES. All rights

> reserved.

> > +

> > +  SPDX-License-Identifier: BSD-2-= Clause-Patent

> > +

> > +**/

> > +#include <Protocol/IpmiBlobTransfer= .h>

> > +

> > +#include "InternalIpmiBlobTransfe= r.h"

> > +

> > +#define BLOB_TRANSFER_DEBUG  DEBU= G_MANAGEABILITY

> > +

> > +STATIC CONST EDKII_IPMI_BLOB_TRANSFER_= PROTOCOL  mIpmiBlobTransfer

> =3D {

> > +

> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT= )*IpmiBlobTransferGetC

> ount,

> > +

> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE= )*IpmiBlobTransferEnu

> merate,

> > +  (EDKII_IPMI_BLOB_TRANSFER_PROTO= COL_OPEN)*IpmiBlobTransferOpen,

> > +  (EDKII_IPMI_BLOB_TRANSFER_PROTO= COL_READ)*IpmiBlobTransferRead,

> > +  (EDKII_IPMI_BLOB_TRANSFER_PROTO= COL_WRITE)*IpmiBlobTransferWrite,

> > +

> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)*I= pmiBlobTransferCommit,

> > +  (EDKII_IPMI_BLOB_TRANSFER_PROTO= COL_CLOSE)*IpmiBlobTransferClose,

> > +

> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)*I= pmiBlobTransferDelete,

> > +  (EDKII_IPMI_BLOB_TRANSFER_PROTO= COL_STAT)*IpmiBlobTransferStat,

> > +

> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_S= TAT)*IpmiBlobTransferSes

> sionStat,

> > +

> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_MET= A)*IpmiBlobTransferWrit

> eMeta

> > +};

> > +

> > +/**

> > +  Calculate CRC-16-CCITT with pol= y of 0x1021

> > +

> > +  @param[in]  Data &nbs= p;            The ta= rget data.

> > +  @param[in]  DataSize =          The target data size.

> > +

> > +  @return UINT16   = ;  The CRC16 value.

> > +

> > +**/

> > +UINT16

> > +CalculateCrc16Ccitt (

> > +  IN UINT8  *Data,

> > +  IN UINTN  DataSize

> > +  )

> > +{

> > +  UINTN    Index;<= /p>

> > +  UINTN    BitInde= x;

> > +  UINT16   Crc;

> > +  UINT16   Poly;

> > +  BOOLEAN  XorFlag;

> > +

> > +  Crc     =3D= 0xFFFF;

> > +  Poly    =3D 0x10= 21;

> > +  XorFlag =3D FALSE;

> > +

> > +  for (Index =3D 0; Index < (D= ataSize + 2); ++Index) {

> > +    for (BitIndex =3D 0= ; BitIndex < 8; ++BitIndex) {

> > +      XorFlag= =3D (Crc & 0x8000) ? TRUE : FALSE;

> > +      Crc&nbs= p;  <<=3D 1;

> > +      if ((In= dex < DataSize) && (Data[Index] & (1 << (7 - BitIndex)= ))) {

> > +      &n= bsp; Crc++;

> > +      }

> > +

> > +      if (Xor= Flag =3D=3D TRUE) {

> > +      &n= bsp; Crc ^=3D Poly;

> > +      }

> > +    }

> > +  }

> > +

> > +  DEBUG ((BLOB_TRANSFER_DEBUG, &q= uot;%a: CRC-16-CCITT %x\n", __func__,

> Crc));

> > +

> > +  return Crc;

> > +}

> > +

> > +/**

> > +  This function does blob transfe= r over IPMI command.

> > +

> > +  @param[in]  SubCommand&nbs= p;       The specific sub-command to be execu= ted as

> part of

> > +      &n= bsp;            = ;             t= he blob transfer operation.

> > +  @param[in]  SendData =          A pointer to the data buff= er that contains the

> data to be sent.

> > +  @param[in]  SendDataSize&n= bsp;     The size of the data to be sent, in bytes.

> > +  @param[out] ResponseData &= nbsp;    A pointer to the buffer where the response

> data will be stored.

> > +  @param[out] ResponseDataSize&nb= sp; A pointer to a variable that will hold the size

> of the response

> > +      &n= bsp;            = ;             d= ata received.

> > +

> > +  @retval EFI_SUCCESS  =           Successfully sends b= lob data.

> > +  @retval EFI_OUT_OF_RESOURCES&nb= sp;  Memory allocation fails.

> > +  @retval EFI_PROTOCOL_ERROR = ;    Communication errors.

> > +  @retval EFI_CRC_ERROR &nbs= p;        Data integrity checks fail.

> > +  @retval Other   =             &nb= sp;  An error occurred

> > +

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferSendIpmi (

> > +  IN  UINT8   SubC= ommand,

> > +  IN  UINT8   *Sen= dData,

> > +  IN  UINT32  SendDataS= ize,

>

> Should describe SendData and SendDataSize as= OPTIONAL

>

> > +  OUT UINT8   *Response= Data,

> > +  OUT UINT32  *ResponseDataS= ize

> > +  )

> > +{

> > +  EFI_STATUS   &nb= sp;            = Status;

> > +  UINT8    &n= bsp;            = ;     CompletionCode;

> > +  UINT16    &= nbsp;           &nbs= p;    Crc;

> > +  UINT8    &n= bsp;            = ;     Oen[3];

> > +  UINT8    &n= bsp;            = ;     *IpmiSendData;

> > +  UINT32    &= nbsp;           &nbs= p;    IpmiSendDataSize;

> > +  UINT8    &n= bsp;            = ;     *IpmiResponseData;

> > +  UINT8    &n= bsp;            = ;     *ModifiedResponseData;

> > +  UINT32    &= nbsp;           &nbs= p;    IpmiResponseDataSize;

> > +  IPMI_BLOB_TRANSFER_HEADER = Header;

> > +

>

> Should validate the pointer of input argumen= ts: SendData, ResponseData,

> ResponseDataSize.

>

> > +  Crc =3D 0;

> > +

> > +  //

> > +  // Prepend the proper header to= the SendData

> > +  //

> > +  IpmiSendDataSize =3D (sizeof (I= PMI_BLOB_TRANSFER_HEADER));

> > +  if (SendDataSize) {

> > +    IpmiSendDataSize += =3D sizeof (Crc) + (sizeof (UINT8) * SendDataSize);

> > +  }

> > +

> > +  IpmiSendData =3D AllocateZeroPo= ol (IpmiSendDataSize);

> > +  if (IpmiSendData =3D=3D NULL) {=

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  Header.OEN[0]   =   =3D OpenBmcOen[0];

> > +  Header.OEN[1]   =   =3D OpenBmcOen[1];

> > +  Header.OEN[2]   =   =3D OpenBmcOen[2];

> > +  Header.SubCommand =3D SubComman= d;

> > +  CopyMem (IpmiSendData, &Hea= der, sizeof

> (IPMI_BLOB_TRANSFER_HEADER));

> > +  if (SendDataSize) {

>

> if (SendDataSize !=3D 0)

>

> > +    //

> > +    // Calculate the Cr= c of the send data

> > +    //

> > +    Crc =3D CalculateCr= c16Ccitt (SendData, SendDataSize);

> > +    CopyMem (IpmiSendDa= ta + sizeof (IPMI_BLOB_TRANSFER_HEADER), &Crc,

> sizeof (UINT16));

> > +    CopyMem (IpmiSendDa= ta + sizeof (IPMI_BLOB_TRANSFER_HEADER) + sizeof

> (UINT16), SendData, SendDataSize);

> > +  }

> > +

> > +  DEBUG_CODE_BEGIN ();

> > +  DEBUG ((BLOB_TRANSFER_DEBUG, &q= uot;%a: Inputs:\n", __func__));

> > +  DEBUG ((BLOB_TRANSFER_DEBUG, &q= uot;%a: SendDataSize: %02x\nData: ",

> __func__, SendDataSize));

> > +  UINT8  i;

> > +

> > +  for (i =3D 0; i < SendDataSi= ze; i++) {

> > +    DEBUG ((BLOB_TRANSF= ER_DEBUG, "%02x", *((UINT8 *)SendData + i)));

> > +  }

> > +

> > +  DEBUG ((BLOB_TRANSFER_DEBUG, &q= uot;\n"));

> > +  DEBUG ((BLOB_TRANSFER_DEBUG, &q= uot;%a: IpmiSendDataSize: %02x\nData: ",

> __func__, IpmiSendDataSize));

> > +  for (i =3D 0; i < IpmiSendDa= taSize; i++) {

> > +    DEBUG ((BLOB_TRANSF= ER_DEBUG, "%02x", *((UINT8 *)IpmiSendData + i)));

> > +  }

> > +

> > +  DEBUG ((BLOB_TRANSFER_DEBUG, &q= uot;\n"));

> > +  DEBUG_CODE_END ();

> > +

> > +  IpmiResponseDataSize =3D (*Resp= onseDataSize +

> PROTOCOL_RESPONSE_OVERHEAD);

> > +  //

> > +  // If expecting data to be retu= rned, we have to also account for the 16 bit CRC

> > +  //

> > +  if (*ResponseDataSize) {

>

> if (*ResponseDataSize !=3D 0)

>

> > +    IpmiResponseDataSiz= e +=3D sizeof (Crc);

> > +  }

> > +

> > +  IpmiResponseData =3D AllocateZe= roPool (IpmiResponseDataSize);

> > +  if (IpmiResponseData =3D=3D NUL= L) {

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  Status =3D IpmiSubmitCommand (<= /p>

> > +      &n= bsp;      IPMI_NETFN_OEM,

> > +      &n= bsp;      IPMI_OEM_BLOB_TRANSFER_CMD,

> > +      &n= bsp;      (VOID *)IpmiSendData,

> > +      &n= bsp;      IpmiSendDataSize,

> > +      &n= bsp;      (VOID *)IpmiResponseData,

> > +      &n= bsp;      &IpmiResponseDataSize

> > +      &n= bsp;      );

> > +

> > +  FreePool (IpmiSendData);

> > +  ModifiedResponseData =3D IpmiRe= sponseData;

> > +

> > +  DEBUG_CODE_BEGIN ();

> > +  DEBUG ((BLOB_TRANSFER_DEBUG, &q= uot;%a: IPMI Response:\n", __func__));

> > +  DEBUG ((BLOB_TRANSFER_DEBUG, &q= uot;%a: ResponseDataSize: %02x\nData: ",

> __func__, IpmiResponseDataSize));

> > +  UINT8  i;

> > +

> > +  for (i =3D 0; i < IpmiRespon= seDataSize; i++) {

> > +    DEBUG ((BLOB_TRANSF= ER_DEBUG, "%02x", *(ModifiedResponseData + i)));

> > +  }

> > +

> > +  DEBUG ((BLOB_TRANSFER_DEBUG, &q= uot;\n"));

> > +  DEBUG_CODE_END ();

> > +

> > +  if (EFI_ERROR (Status)) {

> > +    return Status;

> > +  }

> > +

> > +  CompletionCode =3D *ModifiedRes= ponseData;

> > +  if (CompletionCode !=3D IPMI_CO= MP_CODE_NORMAL) {

> > +    DEBUG ((DEBUG_ERROR= , "%a: Returning because CompletionCode =3D

> 0x%x\n", __func__, CompletionCode));

> > +    FreePool (IpmiRespo= nseData);

> > +    return EFI_PROTOCOL= _ERROR;

> > +  }

> > +

> > +  // Strip completion code, we ar= e done with it

> > +  ModifiedResponseData  =3D = ModifiedResponseData + sizeof (CompletionCode);

> > +  IpmiResponseDataSize -=3D sizeo= f (CompletionCode);

> > +

> > +  // Check OEN code and verify it= matches the OpenBMC OEN

> > +  CopyMem (Oen, ModifiedResponseD= ata, sizeof (OpenBmcOen));

> > +  if (CompareMem (Oen, OpenBmcOen= , sizeof (OpenBmcOen)) !=3D 0) {

> > +    FreePool (IpmiRespo= nseData);

> > +    return EFI_PROTOCOL= _ERROR;

> > +  }

> > +

> > +  if (IpmiResponseDataSize =3D=3D= sizeof (OpenBmcOen)) {

> > +    //

> > +    // In this case, th= ere was no response data sent. This is not an error.

> > +    // Some messages do= not require a response.

> > +    //

> > +    *ResponseDataSize = =3D 0;

> > +    FreePool (IpmiRespo= nseData);

> > +    return Status;

> > +    // Now we need to v= alidate the CRC then send the Response body back

> > +  } else {

> > +    // Strip the OEN, w= e are done with it now

> > +    ModifiedResponseDat= a  =3D ModifiedResponseData + sizeof (Oen);

> > +    IpmiResponseDataSiz= e -=3D sizeof (Oen);

> > +    // Then validate th= e Crc

> > +    CopyMem (&Crc, = ModifiedResponseData, sizeof (Crc));

> > +    ModifiedResponseDat= a  =3D ModifiedResponseData + sizeof (Crc);

> > +    IpmiResponseDataSiz= e -=3D sizeof (Crc);

> > +

> > +    if (Crc =3D=3D Calc= ulateCrc16Ccitt (ModifiedResponseData,

> IpmiResponseDataSize)) {

> > +      CopyMem= (ResponseData, ModifiedResponseData, IpmiResponseDataSize);

> > +      CopyMem= (ResponseDataSize, &IpmiResponseDataSize, sizeof

> (IpmiResponseDataSize));

> > +      FreePoo= l (IpmiResponseData);

> > +      return = EFI_SUCCESS;

> > +    } else {

> > +      FreePoo= l (IpmiResponseData);

> > +      return = EFI_CRC_ERROR;

> > +    }

> > +  }

> > +}

> > +

> > +/**

> > +  This function retrieves the cou= nt of blob transfers available through the IPMI.

> > +

> > +  @param[out]   &n= bsp;    Count       The number= of active blobs

> > +

> > +  @retval EFI_SUCCESS  =           Successfully retriev= ed the number of active

> blobs.

> > +  @retval Other   =             &nb= sp;  An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferGetCount (

> > +  OUT UINT32  *Count

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT8    &n= bsp;  *ResponseData;

> > +  UINT32    &= nbsp; ResponseDataSize;

> > +

> > +  if (Count =3D=3D NULL) {

> > +    return EFI_INVALID_= PARAMETER;

> > +  }

> > +

> > +  ResponseDataSize =3D sizeof

> (IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE);

> > +  ResponseData   &= nbsp; =3D AllocateZeroPool (ResponseDataSize);

> > +  if (ResponseData =3D=3D NULL) {=

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  Status =3D IpmiBlobTransferSend= Ipmi (IpmiBlobTransferSubcommandGetCount,

> NULL, 0, (UINT8 *)ResponseData, &Respons= eDataSize);

> > +  if (!EFI_ERROR (Status)) {

> > +    *Count =3D ((IPMI_B= LOB_TRANSFER_GET_COUNT_RESPONSE

> *)ResponseData)->BlobCount;

> > +  }

> > +

> > +  FreePool (ResponseData);

> > +  return Status;

> > +}

> > +

> > +/**

> > +  This function enumerates blob t= ransfers available through the IPMI.

> > +

> > +  @param[in]   &nb= sp;     BlobIndex       T= he 0-based Index of the blob to enumerate

> > +  @param[out]   &n= bsp;    BlobId       &nbs= p;  The ID of the blob

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successfully enumerated the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferEnumerate (

> > +  IN  UINT32  BlobIndex= ,

> > +  OUT CHAR8   *BlobId

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +

> > +  UINT8   *SendData;

> > +  UINT8   *ResponseData= ;

> > +  UINT32  SendDataSize;

> > +  UINT32  ResponseDataSize;<= /p>

> > +

> > +  if (BlobId =3D=3D NULL) {

> > +    ASSERT (FALSE);

> > +    return EFI_ABORTED;=

>

> Should return EFI_INVALID_PARAMETER for inpu= t validation?

>

> > +  }

> > +

> > +  ResponseDataSize =3D sizeof

> (IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_RESPONSE)= ;

> > +  ResponseData   &= nbsp; =3D AllocateZeroPool (ResponseDataSize);

> > +  if (ResponseData =3D=3D NULL) {=

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  //

> > +  // Format send data

> > +  //

> > +  SendDataSize =3D sizeof

> (IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA= );

> > +  SendData    = ; =3D AllocateZeroPool (SendDataSize);

> > +  if (SendData =3D=3D NULL) {

>

> FreePool (ResponseData);

>

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  ((IPMI_BLOB_TRANSFER_BLOB_ENUME= RATE_SEND_DATA *)SendData)-

> >BlobIndex =3D BlobIndex;

> > +

> > +  Status =3D IpmiBlobTransferSend= Ipmi

> (IpmiBlobTransferSubcommandEnumerate, SendDa= ta, SendDataSize, (UINT8

> *)ResponseData, &ResponseDataSize);

> > +  if (!EFI_ERROR (Status)) {

> > +    AsciiStrCpyS (BlobI= d, ResponseDataSize, (CHAR8 *)ResponseData);

> > +  }

> > +

> > +  FreePool (ResponseData);

> > +  return Status;

> > +}

> > +

> > +/**

> > +  This function is designed to op= en a session for a specific blob

> > +  identified by its ID, using the= IPMI.

> > +

> > +  @param[in]   &nb= sp;     BlobId       = ;   The ID of the blob to open

> > +  @param[in]   &nb= sp;     Flags       =     Flags to control how the blob is opened

>

> It would be good if we can list out all flag= definitions here. Actually,

> I don't know how to input for this argument.=

>

> Are they BLOB_OPEN_FLAG_READ and BLOB_OPEN_F= LAG_WRITE in the private

> include header?

>

> > +  @param[out]   &n= bsp;    SessionId       A uniq= ue session identifier

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successfully opened the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferOpen (

> > +  IN  CHAR8   *Blo= bId,

> > +  IN  UINT16  Flags,

> > +  OUT UINT16  *SessionId

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT8    &n= bsp;  *SendData;

> > +  UINT8    &n= bsp;  *ResponseData;

> > +  UINT32    &= nbsp; SendDataSize;

> > +  UINT32    &= nbsp; ResponseDataSize;

> > +  CHAR8    &n= bsp;  *BlobSearch;

> > +  UINT32    &= nbsp; NumBlobs;

> > +  UINT16    &= nbsp; Index;

> > +  BOOLEAN    = BlobFound;

> > +

> > +  if ((BlobId =3D=3D NULL) || (Se= ssionId =3D=3D NULL)) {

> > +    return EFI_INVALID_= PARAMETER;

> > +  }

> > +

> > +  //

> > +  // Before opening a blob, need = to check if it exists

>

> I'm thinking the caller sequence here. Typic= ally, the caller might check

> the presence of a blob by calling GetCount (= ) and Enumerate () before

> opening a blob session. This check here coul= d waste time. Or, do we call

> open direction the blob session without pre-= checking?

>

> > +  //

> > +  Status =3D IpmiBlobTransferGetC= ount (&NumBlobs);

> > +  if (EFI_ERROR (Status) || (NumB= lobs =3D=3D 0)) {

> > +    if (Status =3D=3D E= FI_UNSUPPORTED) {

> > +      return = Status;

> > +    }

> > +

> > +    DEBUG ((DEBUG_ERROR= , "%a: Could not find any blobs: %r\n", __func__,

> Status));

> > +    return EFI_NOT_FOUN= D;

> > +  }

> > +

> > +  BlobSearch =3D AllocateZeroPool= (sizeof (CHAR8) *

> BLOB_MAX_DATA_PER_PACKET);

> > +  if (BlobSearch =3D=3D NULL) {

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  BlobFound =3D FALSE;

> > +  for (Index =3D 0; Index < Nu= mBlobs; Index++) {

> > +    Status =3D IpmiBlob= TransferEnumerate (Index, BlobSearch);

> > +    if ((!EFI_ERROR (St= atus)) && (AsciiStrCmp (BlobSearch, BlobId) =3D=3D 0)) {

> > +      BlobFou= nd =3D TRUE;

> > +      break;<= /p>

> > +    } else {

> > +      continu= e;

> > +    }

> > +  }

> > +

> > +  if (!BlobFound) {

> > +    DEBUG ((DEBUG_ERROR= , "%a: Could not find a blob that matches %a\n",

> __func__, BlobId));

> > +    FreePool (BlobSearc= h);

> > +    return EFI_NOT_FOUN= D;

> > +  }

> > +

> > +  ResponseDataSize =3D sizeof

> (IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE);

> > +  ResponseData   &= nbsp; =3D AllocateZeroPool (ResponseDataSize);

> > +  if (ResponseData =3D=3D NULL) {=

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  //

> > +  // Format send data

> > +  //

> > +  SendDataSize =3D sizeof (((IPMI= _BLOB_TRANSFER_BLOB_OPEN_SEND_DATA

> *)SendData)->Flags) + ((AsciiStrLen (Blob= Id)) * sizeof (CHAR8)) + sizeof (CHAR8);

> > +  SendData    = ; =3D AllocateZeroPool (SendDataSize);

> > +  if (SendData =3D=3D NULL) {

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  AsciiStrCpyS (((IPMI_BLOB_TRANS= FER_BLOB_OPEN_SEND_DATA

> *)SendData)->BlobId, 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;=

>

> Nit: add spaces around minus (-) for readabi= lity.

>

> > +

> > +  Status =3D IpmiBlobTransferSend= Ipmi (IpmiBlobTransferSubcommandOpen,

> SendData, SendDataSize, (UINT8 *)ResponseDat= a, &ResponseDataSize);

> > +  if (!EFI_ERROR (Status)) {

> > +    *SessionId =3D ((IP= MI_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]   &nb= sp;     SessionId       T= he session ID returned from a call to

> BlobOpen

> > +  @param[in]   &nb= sp;     Offset       = ;   The offset of the blob from which to start

> reading

> > +  @param[in]   &nb= sp;     RequestedSize   The length of data to= read

> > +  @param[out]   &n= bsp;    Data        =     Data read from the blob

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successfully read from the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferRead (

> > +  IN  UINT16  SessionId= ,

>

> There might be developer mistake when execut= ing the transfer before

> opening the session. How do we handle this f= ailure path? Do we need to

> maintain a state machine for that?

>

> This comment applies to other functions as w= ell.

>

> > +  IN  UINT32  Offset,

> > +  IN  UINT32  Requested= Size,

> > +  OUT UINT8   *Data

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT8    &n= bsp;  *SendData;

> > +  UINT8    &n= bsp;  *ResponseData;

> > +  UINT32    &= nbsp; SendDataSize;

> > +  UINT32    &= nbsp; ResponseDataSize;

> > +

> > +  if (Data =3D=3D NULL) {

> > +    ASSERT (FALSE);

> > +    return EFI_ABORTED;=

>

> Should return EFI_INVALID_PARAMETER?

>

> > +  }

> > +

> > +  ResponseDataSize =3D RequestedS= ize * sizeof (UINT8);

>

> Should check the RequestedSize against BLOB_= MAX_DATA_PER_PACKET?

>

> > +  ResponseData   &= nbsp; =3D AllocateZeroPool (ResponseDataSize);

> > +  if (ResponseData =3D=3D NULL) {=

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  //

> > +  // Format send data

> > +  //

> > +  SendDataSize =3D sizeof (IPMI_B= LOB_TRANSFER_BLOB_READ_SEND_DATA);

> > +  SendData    = ; =3D AllocateZeroPool (SendDataSize);

> > +  if (SendData =3D=3D NULL) {

>

> FreePool (ResponseData);

>

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  ((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 IpmiBlobTransferSend= Ipmi (IpmiBlobTransferSubcommandRead,

> SendData, SendDataSize, (UINT8 *)ResponseDat= a, &ResponseDataSize);

> > +  if (!EFI_ERROR (Status)) {

> > +    CopyMem (Data, ((IP= MI_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]   &nb= sp;     SessionId       T= he session ID returned from a call to

> BlobOpen

> > +  @param[in]   &nb= sp;     Offset       = ;   The offset of the blob from which to start writing

> > +  @param[in]   &nb= sp;     Data       &= nbsp;    A pointer to the data to write

> > +  @param[in]   &nb= sp;     WriteLength     The length = to write

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successfully wrote to the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferWrite (

> > +  IN  UINT16  SessionId= ,

> > +  IN  UINT32  Offset,

> > +  IN  UINT8   *Dat= a,

> > +  IN  UINT32  WriteLeng= th

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT8    &n= bsp;  *SendData;

> > +  UINT32    &= nbsp; SendDataSize;

> > +  UINT32    &= nbsp; ResponseDataSize;

> > +

> > +  if (Data =3D=3D NULL) {

> > +    return EFI_INVALID_= PARAMETER;

> > +  }

> > +

> > +  //

> > +  // Format send data

> > +  //

> > +  SendDataSize =3D sizeof (Sessio= nId) + sizeof (Offset) + WriteLength;

>

> Should we check whether or not the WriteLeng= th is equal to or less than

> BLOB_MAX_DATA_PER_PACKET?

>

> > +  SendData    = ; =3D AllocateZeroPool (SendDataSize);

> > +  if (SendData =3D=3D NULL) {

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  ((IPMI_BLOB_TRANSFER_BLOB_WRITE= _SEND_DATA *)SendData)->SessionId

> =3D SessionId;

> > +  ((IPMI_BLOB_TRANSFER_BLOB_WRITE= _SEND_DATA *)SendData)->Offset    =3D

> Offset;

> > +  CopyMem (((IPMI_BLOB_TRANSFER_B= LOB_WRITE_SEND_DATA

> *)SendData)->Data, Data, sizeof (UINT8) *= WriteLength);

> > +

> > +  ResponseDataSize =3D 0;

> > +  Status    &= nbsp;      =3D IpmiBlobTransferSendIpmi

> (IpmiBlobTransferSubcommandWrite, SendData, = SendDataSize, NULL,

> &ResponseDataSize);

> > +

> > +  FreePool (SendData);

> > +  return Status;

> > +}

> > +

> > +/**

> > +  This function commits data to a= blob over the IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId      &n= bsp; The session ID returned from a call to

> BlobOpen

> > +  @param[in]   &nb= sp;     CommitDataLength The length of data to commit t= o the blob

> > +  @param[in]   &nb= sp;     CommitData       = A pointer to the data to commit

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; Successful commit to the blob.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferCommit (

> > +  IN  UINT16  SessionId= ,

> > +  IN  UINT8   Comm= itDataLength,

> > +  IN  UINT8   *Com= mitData

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT8    &n= bsp;  *SendData;

> > +  UINT32    &= nbsp; SendDataSize;

> > +  UINT32    &= nbsp; ResponseDataSize;

> > +

> > +  if (CommitData =3D=3D NULL) {

>

> According to the spec

> https://nam11.safelinks.protection.outlook.c= om/?url=3Dhttps%3A%2F%2Fgithub.co

> m%2Fopenbmc%2Fphosphor-ipmi-

> blobs&data=3D05%7C02%7Cnicklew%40nvidia.= com%7Cd22932100e16475feff608d

> c7645e177%7C43083d15727340c1b7db39efd9ccc17a= %7C0%7C0%7C638515289

> 789839336%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC= 4wLjAwMDAiLCJQIjoiV2

> luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%= 7C%7C&sdata=3DfJbeNhF74

> Co7aHmkYc3U0ym1ISeNznrV2UXDNMEFcoE%3D&re= served=3D0,

> the commit data is block-specific optional.<= /p>

>

> For instance, the commit data is optional fo= r SMBIOS blob transfer. Look

> at

> https://nam11.safelinks.protection.outlook.c= om/?url=3Dhttps%3A%2F%2Fgithub.co

> m%2Fopenbmc%2Fsmbios-

> mdr&data=3D05%7C02%7Cnicklew%40nvidia.co= m%7Cd22932100e16475feff608dc

> 7645e177%7C43083d15727340c1b7db39efd9ccc17a%= 7C0%7C0%7C6385152897

> 89844890%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4= wLjAwMDAiLCJQIjoiV2l

> uMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7= C%7C&sdata=3D4OBktrF6b1

> vyHaI%2FvIOcXOCZQxaFZKwO3lPwLsjIgWY%3D&r= eserved=3D0

>

> > +    return EFI_INVALID_= PARAMETER;

> > +  }

> > +

> > +  //

> > +  // Format send data

> > +  //

> > +  SendDataSize =3D sizeof (Sessio= nId) + sizeof (CommitDataLength) +

> CommitDataLength;

> > +  SendData    = ; =3D AllocateZeroPool (SendDataSize);

> > +  if (SendData =3D=3D NULL) {

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  ((IPMI_BLOB_TRANSFER_BLOB_COMMI= T_SEND_DATA *)SendData)-

> >SessionId     &= nbsp;  =3D SessionId;

> > +  ((IPMI_BLOB_TRANSFER_BLOB_COMMI= T_SEND_DATA *)SendData)-

> >CommitDataLength =3D CommitDataLength;

> > +  CopyMem (((IPMI_BLOB_TRANSFER_B= LOB_COMMIT_SEND_DATA

> *)SendData)->CommitData, CommitData, size= of (UINT8) * CommitDataLength);

> > +

> > +  ResponseDataSize =3D 0;

> > +

> > +  Status =3D IpmiBlobTransferSend= Ipmi (IpmiBlobTransferSubcommandCommit,

> SendData, SendDataSize, NULL, &ResponseD= ataSize);

> > +

> > +  FreePool (SendData);

> > +  return Status;

> > +}

> > +

> > +/**

> > +  This function close a session a= ssociated with a blob transfer over the IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId       T= he session ID returned from a call to

> BlobOpen

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob was closed.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferClose (

> > +  IN  UINT16  SessionId=

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT8    &n= bsp;  *SendData;

> > +  UINT32    &= nbsp; SendDataSize;

> > +  UINT32    &= nbsp; ResponseDataSize;

> > +

> > +  //

> > +  // Format send data

> > +  //

> > +  SendDataSize =3D sizeof (IPMI_B= LOB_TRANSFER_BLOB_CLOSE_SEND_DATA);

> > +  SendData    = ; =3D AllocateZeroPool (SendDataSize);

> > +  if (SendData =3D=3D NULL) {

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  ((IPMI_BLOB_TRANSFER_BLOB_CLOSE= _SEND_DATA *)SendData)->SessionId

> =3D SessionId;

> > +

> > +  ResponseDataSize =3D 0;

> > +

> > +  Status =3D IpmiBlobTransferSend= Ipmi (IpmiBlobTransferSubcommandClose,

> SendData, SendDataSize, NULL, &ResponseD= ataSize);

> > +

> > +  FreePool (SendData);

> > +  return Status;

> > +}

> > +

> > +/**

> > +  This function deletes a specifi= c blob identified by its ID over the IPMI.

> > +

> > +  @param[in]   &nb= sp;     BlobId       = ;   The BlobId to be deleted

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob was deleted.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferDelete (

> > +  IN  CHAR8  *BlobId

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT8    &n= bsp;  *SendData;

> > +  UINT32    &= nbsp; SendDataSize;

> > +  UINT32    &= nbsp; ResponseDataSize;

> > +

> > +  if (BlobId =3D=3D NULL) {

> > +    return EFI_INVALID_= PARAMETER;

> > +  }

> > +

> > +  //

> > +  // Format send data

> > +  //

> > +  SendDataSize =3D sizeof (IPMI_B= LOB_TRANSFER_BLOB_DELETE_SEND_DATA);

> > +  SendData    = ; =3D AllocateZeroPool (SendDataSize);

> > +  if (SendData =3D=3D NULL) {

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  AsciiStrCpyS (((IPMI_BLOB_TRANS= FER_BLOB_DELETE_SEND_DATA

> *)SendData)->BlobId, AsciiStrLen (BlobId)= , BlobId);

> > +

> > +  ResponseDataSize =3D 0;

> > +

> > +  Status =3D IpmiBlobTransferSend= Ipmi (IpmiBlobTransferSubcommandDelete,

> SendData, SendDataSize, NULL, &ResponseD= ataSize);

> > +

> > +  FreePool (SendData);

> > +  return Status;

> > +}

> > +

> > +/**

> > +  This function retrieve the stat= us of a specific blob identified by BlobId from an

> IPMI.

> > +

> > +  @param[in]   &nb= sp;     BlobId       = ;   The Blob ID to gather statistics for

> > +  @param[out]   &n= bsp;    BlobState       The cu= rrent state of the blob

> > +  @param[out]   &n= bsp;    Size        =     Size in bytes of the blob

> > +  @param[out]   &n= bsp;    MetadataLength  Length of the optional metadata=

> > +  @param[out]   &n= bsp;    Metadata        O= ptional blob-specific metadata

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob statistics were successfully gathered.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferStat (

> > +  IN  CHAR8   *Blo= bId,

> > +  OUT UINT16  *BlobState,

> > +  OUT UINT32  *Size,

> > +  OUT UINT8   *Metadata= Length,

> > +  OUT UINT8   *Metadata=

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT8    &n= bsp;  *SendData;

> > +  UINT8    &n= bsp;  *ResponseData;

> > +  UINT32    &= nbsp; SendDataSize;

> > +  UINT32    &= nbsp; ResponseDataSize;

> > +

> > +  if ((BlobId =3D=3D NULL) || (Bl= obState =3D=3D NULL) || (Size =3D=3D NULL) ||

> (MetadataLength =3D=3D NULL)) {

>

> Could we make Metadata **per spec**, Metadat= aLength, and Size optional?

> We could not care them rather than BlobState= .

>

> This comment applies to IpmiBlobTransferSess= ionStat () as well.

>

> > +    return EFI_INVALID_= PARAMETER;

> > +  }

> > +

> > +  if (Metadata =3D=3D NULL) {

> > +    ASSERT (FALSE);

> > +    return EFI_ABORTED;=

> > +  }

> > +

> > +  ResponseDataSize =3D sizeof (IP= MI_BLOB_TRANSFER_BLOB_STAT_RESPONSE);

> > +  ResponseData   &= nbsp; =3D AllocateZeroPool (ResponseDataSize);

> > +  if (ResponseData =3D=3D NULL) {=

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  //

> > +  // Format send data

> > +  //

> > +  SendDataSize =3D sizeof (IPMI_B= LOB_TRANSFER_BLOB_STAT_SEND_DATA);

> > +  SendData    = ; =3D AllocateZeroPool (SendDataSize);

> > +  if (SendData =3D=3D NULL) {

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  AsciiStrCpyS (((IPMI_BLOB_TRANS= FER_BLOB_STAT_SEND_DATA *)SendData)-

> >BlobId, BLOB_MAX_DATA_PER_PACKET, BlobId= );

> > +

> > +  Status =3D IpmiBlobTransferSend= Ipmi (IpmiBlobTransferSubcommandStat,

> SendData, SendDataSize, (UINT8 *)ResponseDat= a, &ResponseDataSize);

> > +  if (!EFI_ERROR (Status)) {

> > +    *BlobState &nb= sp;    =3D ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE

> *)ResponseData)->BlobState;

> > +    *Size  &n= bsp;        =3D ((IPMI_BLOB_TRANSFER_BLO= B_STAT_RESPONSE

> *)ResponseData)->Size;

> > +    *MetadataLength =3D= ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE

> *)ResponseData)->MetaDataLen;

> > +

> > +    CopyMem (&Metad= ata, &((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE

> *)ResponseData)->MetaData, sizeof

> (((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)R= esponseData)->MetaData));

> > +  }

> > +

> > +  FreePool (ResponseData);

> > +  FreePool (SendData);

> > +  return Status;

> > +}

> > +

> > +/**

> > +  This function query the status = of a blob transfer session in an IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId       T= he ID of the session to gather statistics for

> > +  @param[out]   &n= bsp;    BlobState       The cu= rrent state of the blob

> > +  @param[out]   &n= bsp;    Size        =     Size in bytes of the blob

> > +  @param[out]   &n= bsp;    MetadataLength  Length of the optional metadata=

> > +  @param[out]   &n= bsp;    Metadata        O= ptional blob-specific metadata

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob statistics were successfully gathered.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferSessionStat (

> > +  IN  UINT16  SessionId= ,

> > +  OUT UINT16  *BlobState,

> > +  OUT UINT32  *Size,

> > +  OUT UINT8   *Metadata= Length,

> > +  OUT UINT8   *Metadata=

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT8    &n= bsp;  *SendData;

> > +  UINT8    &n= bsp;  *ResponseData;

> > +  UINT32    &= nbsp; SendDataSize;

> > +  UINT32    &= nbsp; 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 (IP= MI_BLOB_TRANSFER_BLOB_STAT_RESPONSE);

> > +  ResponseData   &= nbsp; =3D AllocateZeroPool (ResponseDataSize);

> > +  if (ResponseData =3D=3D NULL) {=

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  //

> > +  // Format send data

> > +  //

> > +  SendDataSize =3D sizeof

> (IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_D= ATA);

> > +  SendData    = ; =3D AllocateZeroPool (SendDataSize);

> > +  if (SendData =3D=3D NULL) {

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  ((IPMI_BLOB_TRANSFER_BLOB_SESSI= ON_STAT_SEND_DATA *)SendData)-

> >SessionId =3D SessionId;

> > +

> > +  Status =3D IpmiBlobTransferSend= Ipmi

> (IpmiBlobTransferSubcommandSessionStat, Send= Data, SendDataSize, (UINT8

> *)ResponseData, &ResponseDataSize);

> > +

> > +  if (!EFI_ERROR (Status)) {

> > +    *BlobState &nb= sp;    =3D ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE

> *)ResponseData)->BlobState;

> > +    *Size  &n= bsp;        =3D ((IPMI_BLOB_TRANSFER_BLO= B_SESSION_STAT_RESPONSE

> *)ResponseData)->Size;

> > +    *MetadataLength =3D=

> ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPO= NSE *)ResponseData)-

> >MetaDataLen;

> > +

> > +    CopyMem (&Metad= ata,

> &((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_= RESPONSE *)ResponseData)-

> >MetaData, sizeof (((IPMI_BLOB_TRANSFER_B= LOB_SESSION_STAT_RESPONSE

> *)ResponseData)->MetaData));

> > +  }

> > +

> > +  FreePool (ResponseData);

> > +  FreePool (SendData);

> > +  return Status;

> > +}

> > +

> > +/**

> > +  This function writes metadata t= o a blob associated with a session in an IPMI.

> > +

> > +  @param[in]   &nb= sp;     SessionId       T= he ID of the session to write metadata for

> > +  @param[in]   &nb= sp;     Offset       = ;   The offset of the metadata to write to

> > +  @param[in]   &nb= sp;     Data       &= nbsp;    The data to write to the metadata

> > +  @param[in]   &nb= sp;     WriteLength     The length = to write

> > +

> > +  @retval EFI_SUCCESS  =             &nb= sp; The blob metadata was successfully written.

> > +  @retval Other   =             &nb= sp;      An error occurred

> > +**/

> > +EFI_STATUS

> > +IpmiBlobTransferWriteMeta (

> > +  IN  UINT16  SessionId= ,

> > +  IN  UINT32  Offset,

> > +  IN  UINT8   *Dat= a,

>

> How do callers know the data format of metad= ata for writing correctly?

>

> > +  IN  UINT32  WriteLeng= th

>

> Should check with BLOB_MAX_DATA_PER_PACKET

>

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT8    &n= bsp;  *SendData;

> > +  UINT32    &= nbsp; SendDataSize;

> > +  UINT32    &= nbsp; ResponseDataSize;

> > +

> > +  if (Data =3D=3D NULL) {

> > +    return EFI_INVALID_= PARAMETER;

> > +  }

> > +

> > +  //

> > +  // Format send data

> > +  //

> > +  SendDataSize =3D sizeof (IPMI_B= LOB_TRANSFER_BLOB_WRITE_SEND_DATA);

> > +  SendData    = ; =3D AllocateZeroPool (SendDataSize);

> > +  if (SendData =3D=3D NULL) {

> > +    return EFI_OUT_OF_R= ESOURCES;

> > +  }

> > +

> > +  ((IPMI_BLOB_TRANSFER_BLOB_WRITE= _SEND_DATA *)SendData)->SessionId

> =3D SessionId;

> > +  ((IPMI_BLOB_TRANSFER_BLOB_WRITE= _SEND_DATA *)SendData)->Offset    =3D

> Offset;

> > +  CopyMem (((IPMI_BLOB_TRANSFER_B= LOB_WRITE_SEND_DATA

> *)SendData)->Data, Data, sizeof (UINT8) *= WriteLength);

> > +

> > +  ResponseDataSize =3D 0;

> > +

> > +  Status =3D IpmiBlobTransferSend= Ipmi

> (IpmiBlobTransferSubcommandWriteMeta, SendDa= ta, SendDataSize, NULL,

> &ResponseDataSize);

> > +

> > +  FreePool (SendData);

> > +  return Status;

> > +}

> > +

> > +/**

> > +  This is the declaration of an E= FI image entry point. This entry point is

> > +  the same for UEFI Applications,= UEFI OS Loaders, and UEFI Drivers including

> > +  both device drivers and bus dri= vers.

> > +

> > +  @param[in]  ImageHandle&nb= sp;      The firmware allocated handle for the UEF= I

> image.

> > +  @param[in]  SystemTable&nb= sp;      A pointer to the EFI System Table.

> > +

> > +  @retval EFI_SUCCESS  =          The operation completed su= ccessfully.

> > +  @retval Others   = ;             A= n unexpected error occurred.

> > +

> > +**/

> > +EFI_STATUS

> > +EFIAPI

> > +IpmiBlobTransferDxeDriverEntryPoint (<= /p>

> > +  IN EFI_HANDLE   =      ImageHandle,

> > +  IN EFI_SYSTEM_TABLE  *Syst= emTable

> > +  )

> > +{

> > +  return gBS->InstallMultipleP= rotocolInterfaces (

> > +      &n= bsp;         &ImageHandle,

>

> Nit: Typically, we could also use gImageHand= le instead.

>

> > +      &n= bsp;         &gEdkiiIpmiBlobTra= nsferProtocolGuid,

> > +      &n= bsp;         (VOID *)&mIpmiBlob= Transfer,

> > +      &n= bsp;         NULL

> > +      &n= bsp;         );

> > +}

> > diff --git

> a/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/UnitTest/IpmiBlob

> TransferTestUnitTests.c

> b/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/UnitTest/IpmiBlob

> TransferTestUnitTests.c

> > new file mode 100644

> > index 0000000000..0f728527b8

> > --- /dev/null

> > +++

> b/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/UnitTest/IpmiBlob

> TransferTestUnitTests.c

> > @@ -0,0 +1,1113 @@

> > +/** @file

> > +*

> > +*  Copyright (c) 2022-2024, NVIDI= A CORPORATION. All rights reserved.

> > +*

> > +*  SPDX-FileCopyrightText: Copyri= ght (c) 2022-2024 NVIDIA CORPORATION &

> AFFILIATES

> > +*  SPDX-License-Identifier: BSD-2= -Clause-Patent

> > +*

> > +**/

> > +#include <stdarg.h>

> > +#include <stddef.h>

> > +#include <setjmp.h>

> > +#include <stdint.h>

> > +#include <cmocka.h>

> > +

> > +#include <Uefi.h>

> > +#include <Library/BaseMemoryLib.h&g= t;

> > +#include <Library/DebugLib.h>

> > +#include <Library/MemoryAllocationL= ib.h>

> > +#include <Library/HostBasedTestStub= Lib/IpmiStubLib.h>

> > +

> > +#include <Library/UnitTestLib.h>=

> > +#include <Protocol/IpmiBlobTransfer= .h>

> > +#include "../InternalIpmiBlobTran= sfer.h"

> > +

> > +#define UNIT_TEST_NAME  &nbs= p;  "IPMI Blob Transfer Unit Tests"

> > +#define UNIT_TEST_VERSION  "= 1.0"

> > +

> > +UINT8  InvalidCompletion[] =3D {<= /p>

> > +  0xC0,    &n= bsp;        // CompletionCode

> > +  0xCF, 0xC2, 0x00, // OpenBMC OE= N

> > +};

> > +#define INVALID_COMPLETION_SIZE  = 4 * sizeof(UINT8)

> > +

> > +UINT8  NoDataResponse[] =3D {

> > +  0x00,    &n= bsp;        // CompletionCode

> > +  0xCF, 0xC2, 0x00, // OpenBMC OE= N

> > +};

> > +#define NO_DATA_RESPONSE_SIZE  4 = * sizeof(UINT8)

> > +

> > +UINT8  BadOenResponse[] =3D {

> > +  0x00,    &n= bsp;        // CompletionCode

> > +  0xFF, 0xC2, 0x00, // Wrong OEN<= /p>

> > +};

> > +#define BAD_OEN_RESPONSE_SIZE  4 = * sizeof(UINT8)

> > +

> > +UINT8  BadCrcResponse[] =3D {

> > +  0x00,    &n= bsp;            = ;  // CompletionCode

> > +  0xCF, 0xC2, 0x00,  &n= bsp;    // OpenBMC OEN

> > +  0x00, 0x00,   &n= bsp;         // CRC

> > +  0x01, 0x00, 0x00, 0x00, // Data=

> > +};

> > +#define BAD_CRC_RESPONSE_SIZE  10= * sizeof(UINT8)

> > +

> > +UINT8  ValidNoDataResponse[] =3D = {

> > +  0x00,    &n= bsp;        // CompletionCode

> > +  0xCF, 0xC2, 0x00, // OpenBMC OE= N

> > +};

> > +

> > +#define VALID_NODATA_RESPONSE_SIZE&nbs= p; 4 * sizeof(UINT8)

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +GoodCrc (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  UINT8   Data[5] =3D {= 0x12, 0x34, 0x56, 0x78, 0x90 };

> > +  UINTN   DataSize;

> > +  UINT16  Crc;

> > +

> > +  DataSize =3D sizeof (Data);

> > +

> > +  Crc =3D CalculateCrc16Ccitt (Da= ta, DataSize);

> > +

> > +  UT_ASSERT_EQUAL (Crc, 0xB928);<= /p>

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +BadCrc (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  UINT8   Data[5] =3D {= 0x12, 0x34, 0x56, 0x78, 0x90 };

> > +  UINTN   DataSize;

> > +  UINT16  Crc;

> > +

> > +  DataSize =3D sizeof (Data);

> > +

> > +  Crc =3D CalculateCrc16Ccitt (Da= ta, DataSize);

> > +

> > +  UT_ASSERT_NOT_EQUAL (Crc, 0x340= 9);

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +SendIpmiBadCompletion (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  VOID    &nb= sp;   *ResponseData;

> > +  UINT32    &= nbsp; *ResponseDataSize;

> > +  EFI_STATUS  Status;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool

> (INVALID_COMPLETION_SIZE);

> > +  ResponseDataSize  &nb= sp; =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32));

> > +  CopyMem (MockResponseResults, &= amp;InvalidCompletion,

> INVALID_COMPLETION_SIZE);

> > +

> > +  MockIpmiSubmitCommand ((UINT8 *= )MockResponseResults,

> INVALID_COMPLETION_SIZE, EFI_SUCCESS);

> > +

> > +  ResponseData =3D (UINT8 *)Alloc= ateZeroPool (*ResponseDataSize);

> > +  Status    &= nbsp;  =3D IpmiBlobTransferSendIpmi

> (IpmiBlobTransferSubcommandGetCount, NULL, 0= , ResponseData,

> ResponseDataSize);

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_PROTOCOL_ERROR);

> > +  FreePool (MockResponseResults);=

> > +  FreePool (ResponseDataSize);

> > +  FreePool (ResponseData);

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +SendIpmiNoDataResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  VOID    &nb= sp;   *ResponseData;

> > +  UINT32    &= nbsp; *ResponseDataSize;

> > +  EFI_STATUS  Status;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool

> (NO_DATA_RESPONSE_SIZE);

> > +  ResponseDataSize  &nb= sp; =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32));

> > +  CopyMem (MockResponseResults, &= amp;NoDataResponse,

> NO_DATA_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> NO_DATA_RESPONSE_SIZE, EFI_SUCCESS);

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  ResponseData =3D (UINT8 *)Alloc= ateZeroPool (sizeof (NoDataResponse));

> > +  Status    &= nbsp;  =3D IpmiBlobTransferSendIpmi

> (IpmiBlobTransferSubcommandGetCount, NULL, 0= , ResponseData,

> ResponseDataSize);

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_SUCCESS);

> > +  UT_ASSERT_EQUAL (*ResponseDataS= ize, 0);

> > +  FreePool (MockResponseResults);=

> > +  FreePool (ResponseDataSize);

> > +  FreePool (ResponseData);

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +SendIpmiBadOenResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  VOID    &nb= sp;   *ResponseData;

> > +  UINT32    &= nbsp; *ResponseDataSize;

> > +  EFI_STATUS  Status;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool

> (BAD_OEN_RESPONSE_SIZE);

> > +  ResponseDataSize  &nb= sp; =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32));

> > +  CopyMem (MockResponseResults, &= amp;BadOenResponse,

> BAD_OEN_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> BAD_OEN_RESPONSE_SIZE, EFI_SUCCESS);

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  ResponseData =3D (UINT8 *)Alloc= ateZeroPool (sizeof (BadOenResponse));

> > +  Status    &= nbsp;  =3D IpmiBlobTransferSendIpmi

> (IpmiBlobTransferSubcommandGetCount, NULL, 0= , ResponseData,

> ResponseDataSize);

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_PROTOCOL_ERROR);

> > +  FreePool (MockResponseResults);=

> > +  FreePool (ResponseDataSize);

> > +  FreePool (ResponseData);

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +SendIpmiBadCrcResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  VOID    &nb= sp;   *ResponseData;

> > +  UINT32    &= nbsp; *ResponseDataSize;

> > +  EFI_STATUS  Status;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (BAD_CRC_RESPONSE_SIZE));

> > +  ResponseDataSize  &nb= sp; =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32));

> > +  CopyMem (MockResponseResults, &= amp;BadCrcResponse,

> BAD_CRC_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> BAD_CRC_RESPONSE_SIZE, EFI_SUCCESS);

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  ResponseData =3D (UINT8 *)Alloc= ateZeroPool (sizeof (BadCrcResponse));

> > +  Status    &= nbsp;  =3D IpmiBlobTransferSendIpmi

> (IpmiBlobTransferSubcommandGetCount, NULL, 0= , ResponseData,

> ResponseDataSize);

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_CRC_ERROR);

> > +  FreePool (MockResponseResults);=

> > +  FreePool (ResponseDataSize);

> > +  FreePool (ResponseData);

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +UINT8  ValidGetCountResponse[] = =3D {

> > +  0x00,    &n= bsp;            = ;  // CompletionCode

> > +  0xCF, 0xC2, 0x00,  &n= bsp;    // OpenBMC OEN

> > +  0xA4, 0x78,   &n= bsp;         // CRC

> > +  0x01, 0x00, 0x00, 0x00, // Data=

> > +};

> > +#define VALID_GET_COUNT_RESPONSE_SIZE&= nbsp; 10 * sizeof(UINT8)

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +SendIpmiValidCountResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  UINT8    &n= bsp;  *ResponseData;

> > +  UINT32    &= nbsp; *ResponseDataSize;

> > +  EFI_STATUS  Status;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_GET_COUNT_RESPONSE_SIZE));

> > +  ResponseDataSize  &nb= sp; =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32));

> > +  CopyMem (MockResponseResults, &= amp;ValidGetCountResponse,

> VALID_GET_COUNT_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);=

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  ResponseData =3D AllocateZeroPo= ol (sizeof (ValidGetCountResponse));

> > +  Status    &= nbsp;  =3D IpmiBlobTransferSendIpmi

> (IpmiBlobTransferSubcommandGetCount, NULL, 0= , ResponseData,

> ResponseDataSize);

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_SUCCESS);

> > +  FreePool (MockResponseResults);=

> > +  FreePool (ResponseDataSize);

> > +  FreePool (ResponseData);

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +GetCountValidCountResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT32    &= nbsp; Count;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  Count =3D 0;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_GET_COUNT_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidGetCountResponse,

> VALID_GET_COUNT_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);=

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  Status =3D IpmiBlobTransferGetC= ount (&Count);

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_SUCCESS);

> > +  UT_ASSERT_EQUAL (Count, 1);

> > +  FreePool (MockResponseResults);=

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +UINT8  ValidEnumerateResponse[] = =3D {

> > +  0x00,    &n= bsp;            = ;  // CompletionCode

> > +  0xCF, 0xC2, 0x00,  &n= bsp;    // OpenBMC OEN

> > +  0x81, 0x13,   &n= bsp;         // CRC

> > +  0x2F, 0x73, 0x6D, 0x62, // Data= =3D "/smbios"

> > +  0x69, 0x6F, 0x73, 0x00,

> > +};

> > +#define VALID_ENUMERATE_RESPONSE_SIZE&= nbsp; 14 * sizeof(UINT8)

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +EnumerateValidResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  CHAR8    &n= bsp;  *BlobId;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_ENUMERATE_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidEnumerateResponse,

> VALID_ENUMERATE_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);=

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  BlobId =3D AllocateZeroPool (si= zeof (CHAR8) * BLOB_MAX_DATA_PER_PACKET);

> > +

> > +  Status =3D IpmiBlobTransferEnum= erate (0, BlobId);

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_SUCCESS);

> > +  UT_ASSERT_MEM_EQUAL (BlobId, &q= uot;/smbios", 7);

> > +  FreePool (MockResponseResults);=

> > +  FreePool (BlobId);

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +EnumerateInvalidBuffer (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  CHAR8    &n= bsp;  *BlobId;

> > +  EFI_STATUS  Status;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_ENUMERATE_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidEnumerateResponse,

> VALID_ENUMERATE_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);=

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  BlobId =3D NULL;

> > +

> > +  UT_EXPECT_ASSERT_FAILURE (IpmiB= lobTransferEnumerate (0, BlobId),

> NULL);

> > +

> > +  FreePool (MockResponseResults);=

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +UINT8  ValidOpenResponse[] =3D {<= /p>

> > +  0x00,    &n= bsp;        // CompletionCode

> > +  0xCF, 0xC2, 0x00, // OpenBMC OE= N

> > +  0x93, 0xD1,   &n= bsp;   // CRC

> > +  0x03, 0x00,   &n= bsp;   // SessionId =3D 3

> > +};

> > +#define VALID_OPEN_RESPONSE_SIZE = 8 * sizeof(UINT8)

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +OpenValidResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  CHAR8    &n= bsp;  *BlobId;

> > +  UINT16    &= nbsp; Flags;

> > +  UINT16    &= nbsp; SessionId;

> > +  VOID    &nb= sp;   *MockResponseResults  =3D NULL;

> > +  VOID    &nb= sp;   *MockResponseResults2 =3D NULL;

> > +  VOID    &nb= sp;   *MockResponseResults3 =3D NULL;

> > +

> > +  Flags =3D BLOB_TRANSFER_STAT_OP= EN_W;

> > +

> > +  //

> > +  // An open call effectively lea= ds to three IPMI commands

> > +  // 1. GetCount of blobs

> > +  // 2. Enumerate the requested b= lob

> > +  // 3. Open the requested blob

> > +  //

> > +  // So we'll push three Ipmi res= ponses in this case

> > +  //

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_OPEN_RESPONSE_SIZE));

> > +

> > +  CopyMem (MockResponseResults, &= amp;ValidOpenResponse,

> VALID_OPEN_RESPONSE_SIZE);

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_OPEN_RESPONSE_SIZE, EFI_SUCCESS);

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  MockResponseResults2 =3D (UINT8= *)AllocateZeroPool (sizeof

> (VALID_ENUMERATE_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults2, = &ValidEnumerateResponse,

> VALID_ENUMERATE_RESPONSE_SIZE);

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults2,

> VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);=

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  MockResponseResults3 =3D (UINT8= *)AllocateZeroPool (sizeof

> (VALID_GET_COUNT_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults3, = &ValidGetCountResponse,

> VALID_GET_COUNT_RESPONSE_SIZE);

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults3,

> VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);=

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_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 {<= /p>

> > +  0x00,    &n= bsp;            = ;  // CompletionCode

> > +  0xCF, 0xC2, 0x00,  &n= bsp;    // OpenBMC OEN

> > +  0x21, 0x6F,   &n= bsp;         // CRC

> > +  0x00, 0x01, 0x02, 0x03, // Data= to read

> > +};

> > +

> > +#define VALID_READ_RESPONSE_SIZE = 10 * sizeof(UINT8)

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +ReadValidResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT8    &n= bsp;  *ResponseData;

> > +  UINT8    &n= bsp;  ExpectedDataResponse[4] =3D { 0x00, 0x01, 0x02, 0x03 };

> > +  VOID    &nb= sp;   *MockResponseResults    =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_READ_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidReadResponse,

> VALID_READ_RESPONSE_SIZE);

> > +  ResponseData =3D AllocateZeroPo= ol (sizeof (ValidReadResponse));

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_READ_RESPONSE_SIZE, EFI_SUCCESS);

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  Status =3D IpmiBlobTransferRead= (0, 0, 4, ResponseData);

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_SUCCESS);

> > +  UT_ASSERT_MEM_EQUAL (ResponseDa= ta, ExpectedDataResponse, 4);

> > +  FreePool (MockResponseResults);=

> > +  FreePool (ResponseData);

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +ReadInvalidBuffer (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  UINT8    &n= bsp;  *ResponseData;

> > +  EFI_STATUS  Status;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_READ_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidReadResponse,

> VALID_READ_RESPONSE_SIZE);

> > +  ResponseData =3D NULL;

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_READ_RESPONSE_SIZE, EFI_SUCCESS);

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  UT_EXPECT_ASSERT_FAILURE (IpmiB= lobTransferRead (0, 0, 4, ResponseData),

> NULL);

> > +

> > +  FreePool (MockResponseResults);=

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +WriteValidResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT8    &n= bsp;  SendData[4]         = ; =3D { 0x00, 0x01, 0x02, 0x03 };

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_NODATA_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidNoDataResponse,

> VALID_NODATA_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  Status =3D IpmiBlobTransferWrit= e (0, 0, SendData, 4);

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_SUCCESS);

> > +  FreePool (MockResponseResults);=

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +CommitValidResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT8    &n= bsp;  SendData[4]         = ; =3D { 0x00, 0x01, 0x02, 0x03 };

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_NODATA_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidNoDataResponse,

> VALID_NODATA_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  Status =3D IpmiBlobTransferComm= it (0, 4, SendData);

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_SUCCESS);

> > +  FreePool (MockResponseResults);=

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +CloseValidResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_NODATA_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidNoDataResponse,

> VALID_NODATA_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  Status =3D IpmiBlobTransferClos= e (1);

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_SUCCESS);

> > +  FreePool (MockResponseResults);=

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +DeleteValidResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_NODATA_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidNoDataResponse,

> VALID_NODATA_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  Status =3D IpmiBlobTransferDele= te ("/smbios");

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_SUCCESS);

> > +  FreePool (MockResponseResults);=

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +UINT8  ValidBlobStatResponse[] = =3D {

> > +  0x00,    &n= bsp;            = ;  // CompletionCode

> > +  0xCF, 0xC2, 0x00,  &n= bsp;    // OpenBMC OEN

> > +  0x1F, 0x4F,   &n= bsp;         // Crc

> > +  0x01, 0x00,   &n= bsp;         // BlobState

> > +  0x02, 0x03, 0x04, 0x05, // Blob= Size

> > +  0x04,    &n= bsp;            = ;  // MetaDataLen

> > +  0x06, 0x07, 0x08, 0x09, // Meta= Data

> > +};

> > +

> > +#define VALID_BLOB_STAT_RESPONSE_SIZE&= nbsp; 17 * sizeof(UINT8)

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +BlobStatValidResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT16    &= nbsp; *BlobState;

> > +  UINT32    &= nbsp; *Size;

> > +  UINT8    &n= bsp;  *MetadataLength;

> > +  UINT8    &n= bsp;  *Metadata;

> > +  UINT8    &n= bsp;  *ExpectedMetadata;

> > +  CHAR8    &n= bsp;  *BlobId;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  BlobState   &nbs= p;    =3D AllocateZeroPool (sizeof (UINT16));

> > +  Size    &nb= sp;        =3D AllocateZeroPool (sizeof = (UINT32));

> > +  BlobId    &= nbsp;      =3D "BlobId";

> > +  MetadataLength   =3D = AllocateZeroPool (sizeof (UINT8));

> > +  Metadata    = ;     =3D AllocateZeroPool (4 * sizeof (UINT8));

> > +  ExpectedMetadata =3D AllocateZe= roPool (4 * sizeof (UINT8));

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_BLOB_STAT_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidBlobStatResponse,

> VALID_BLOB_STAT_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);=

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_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, 0x05040= 302);

> > +  UT_ASSERT_EQUAL (*MetadataLengt= h, 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 &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +BlobStatInvalidBuffer (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  UINT8    &n= bsp;  *Metadata;

> > +  EFI_STATUS  Status;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  Metadata =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_BLOB_STAT_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidBlobStatResponse,

> VALID_BLOB_STAT_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);=

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  UT_EXPECT_ASSERT_FAILURE (IpmiB= lobTransferStat (NULL, 0, 0, 0,

> Metadata), NULL);

> > +

> > +  FreePool (MockResponseResults);=

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +SessionStatValidResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  UINT16    &= nbsp; *BlobState;

> > +  UINT32    &= nbsp; *Size;

> > +  UINT8    &n= bsp;  *MetadataLength;

> > +  UINT8    &n= bsp;  *Metadata;

> > +  UINT8    &n= bsp;  *ExpectedMetadata;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  BlobState   &nbs= p;    =3D AllocateZeroPool (sizeof (UINT16));

> > +  Size    &nb= sp;        =3D AllocateZeroPool (sizeof = (UINT32));

> > +  MetadataLength   =3D = AllocateZeroPool (sizeof (UINT8));

> > +  Metadata    = ;     =3D AllocateZeroPool (4 * sizeof (UINT8));

> > +  ExpectedMetadata =3D AllocateZe= roPool (4 * sizeof (UINT8));

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_BLOB_STAT_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidBlobStatResponse,

> VALID_BLOB_STAT_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);=

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  Status =3D IpmiBlobTransferSess= ionStat (0, BlobState, Size, MetadataLength,

> Metadata);

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_SUCCESS);

> > +  UT_ASSERT_EQUAL (*BlobState, 1)= ;

> > +  UT_ASSERT_EQUAL (*Size, 0x05040= 302);

> > +  UT_ASSERT_EQUAL (*MetadataLengt= h, 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 &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +SessionStatInvalidBuffer (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  UINT8    &n= bsp;  *Metadata;

> > +  EFI_STATUS  Status;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  Metadata =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_BLOB_STAT_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidBlobStatResponse,

> VALID_BLOB_STAT_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);=

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  UT_EXPECT_ASSERT_FAILURE (IpmiB= lobTransferSessionStat (0, 0, 0, 0,

> Metadata), NULL);

> > +

> > +  FreePool (MockResponseResults);=

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  @param[in]  Context &= nbsp;  [Optional] An optional parameter that enables:

> > +      &n= bsp;            = ;      1) test-case reuse with varied parameters a= nd

> > +      &n= bsp;            = ;      2) test-case re-entry for Target tests that= need a

> > +      &n= bsp;            = ;      reboot.  This parameter is a VOID* and= it is the

> > +      &n= bsp;            = ;      responsibility of the test author to ensure= that the

> > +      &n= bsp;            = ;      contents are well understood by all test ca= ses that may

> > +      &n= bsp;            = ;      consume it.

> > +  @retval  UNIT_TEST_PASSED&= nbsp;            The= Unit test has completed and the test

> > +      &n= bsp;            = ;            &n= bsp;        case was successful.

> > +  @retval  UNIT_TEST_ERROR_T= EST_FAILED  A test case assertion has failed.

> > +**/

> > +UNIT_TEST_STATUS

> > +EFIAPI

> > +WriteMetaValidResponse (

> > +  IN UNIT_TEST_CONTEXT  Cont= ext

> > +  )

> > +{

> > +  EFI_STATUS  Status;

> > +  VOID    &nb= sp;   *MockResponseResults =3D NULL;

> > +

> > +  MockResponseResults =3D (UINT8 = *)AllocateZeroPool (sizeof

> (VALID_NODATA_RESPONSE_SIZE));

> > +  CopyMem (MockResponseResults, &= amp;ValidNoDataResponse,

> VALID_NODATA_RESPONSE_SIZE);

> > +

> > +  Status =3D MockIpmiSubmitComman= d ((UINT8 *)MockResponseResults,

> VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);

> > +  if (EFI_ERROR (Status)) {

> > +    return UNIT_TEST_ER= ROR_TEST_FAILED;

> > +  }

> > +

> > +  Status =3D IpmiBlobTransferWrit= eMeta (0, 0, NULL, 0);

> > +

> > +  UT_ASSERT_STATUS_EQUAL (Status,= EFI_SUCCESS);

> > +  FreePool (MockResponseResults);=

> > +  return UNIT_TEST_PASSED;

> > +}

> > +

> > +/**

> > +  Initialize the unit test framew= ork, suite, and unit tests for the

> > +  sample unit tests and run the u= nit tests.

> > +  @retval  EFI_SUCCESS =           All test cases were = dispatched.

> > +  @retval  EFI_OUT_OF_RESOUR= CES  There are not enough resources

> available to

> > +      &n= bsp;            = ;            &n= bsp; initialize the unit tests.

> > +**/

> > +EFI_STATUS

> > +EFIAPI

> > +SetupAndRunUnitTests (

> > +  VOID

> > +  )

> > +{

> > +  EFI_STATUS   &nb= sp;            =   Status;

> > +  UNIT_TEST_FRAMEWORK_HANDLE = ; Framework;

> > +  UNIT_TEST_SUITE_HANDLE &nb= sp;    IpmiBlobTransfer;

> > +

> > +  Framework =3D NULL;

> > +  DEBUG ((DEBUG_INFO, "%a: v= %a\n", UNIT_TEST_NAME,

> UNIT_TEST_VERSION));

> > +

> > +  Status =3D InitUnitTestFramewor= k (&Framework, UNIT_TEST_NAME,

> gEfiCallerBaseName, UNIT_TEST_VERSION);

> > +  if (EFI_ERROR (Status)) {

> > +    DEBUG ((DEBUG_ERROR= , "Failed to setup Test Framework. Exiting with

> status =3D %r\n", Status));

> > +    ASSERT (FALSE);

> > +    return Status;

> > +  }

> > +

> > +  //

> > +  // Populate the Unit Test Suite= .

> > +  //

> > +  Status =3D CreateUnitTestSuite = (&IpmiBlobTransfer, Framework, "IPMI Blob

> Transfer Tests", "UnitTest.IpmiBlo= bTransferCB", NULL, NULL);

> > +  if (EFI_ERROR (Status)) {

> > +    DEBUG ((DEBUG_ERROR= , "Failed in CreateUnitTestSuite for IPMI Blob

> Transfer Tests\n"));

> > +    Status =3D EFI_OUT_= OF_RESOURCES;

> > +    return Status;

> > +  }

> > +

> > +  // CalculateCrc16Ccitt

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Test CRC Calculation", "GoodCrc",

> GoodCrc, NULL, NULL, NULL);

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Test Bad CRC Calculation",

> "BadCrc", BadCrc, NULL, NULL, NULL= );

> > +  // IpmiBlobTransferSendIpmi

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Send IPMI returns bad completion",

> "SendIpmiBadCompletion", SendIpmiB= adCompletion, NULL, NULL, NULL);

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Send IPMI returns successfully with

> no data", "SendIpmiNoDataResponse&= quot;, SendIpmiNoDataResponse, NULL, NULL,

> NULL);

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Send IPMI returns successfully with

> bad OEN", "SendIpmiBadOenResponse&= quot;, SendIpmiBadOenResponse, NULL, NULL,

> NULL);

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Send IPMI returns successfully with

> bad CRC", "SendIpmiBadCrcResponse&= quot;, SendIpmiBadCrcResponse, NULL, NULL,

> NULL);

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Send IPMI returns with valid

> GetCount data", "SendIpmiValidCoun= tResponse", SendIpmiValidCountResponse,

> NULL, NULL, NULL);

> > +  // IpmiBlobTransferGetCount

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "GetCount call with valid data",

> "GetCountValidCountResponse", GetC= ountValidCountResponse, NULL, NULL,

> NULL);

> > +  // IpmiBlobTransferEnumerate

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Enumerate call with valid data",

> "EnumerateValidResponse", Enumerat= eValidResponse, NULL, NULL, NULL);

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Enumerate call with invalid output

> buffer", "EnumerateInvalidBuffer&q= uot;, EnumerateInvalidBuffer, NULL, NULL, NULL);

> > +  // IpmiBlobTransferOpen

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Open call with valid data",

> "OpenValidResponse", OpenValidResp= onse, NULL, NULL, NULL);

> > +  // IpmiBlobTransferRead

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Read call with valid data",

> "ReadValidResponse", ReadValidResp= onse, NULL, NULL, NULL);

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Read call with invalid buffer",

> "ReadInvalidBuffer", ReadInvalidBu= ffer, NULL, NULL, NULL);

> > +  // IpmiBlobTransferWrite

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Write call with valid data",

> "WriteValidResponse", WriteValidRe= sponse, NULL, NULL, NULL);

> > +  // IpmiBlobTransferCommit

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Commit call with valid data",

> "CommitValidResponse", CommitValid= Response, NULL, NULL, NULL);

> > +  // IpmiBlobTransferClose

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Close call with valid data",

> "CloseValidResponse", CloseValidRe= sponse, NULL, NULL, NULL);

> > +  // IpmiBlobTransferDelete

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Delete call with valid data",

> "DeleteValidResponse", DeleteValid= Response, NULL, NULL, NULL);

> > +  // IpmiBlobTransferStat

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Blob Stat call with valid data",

> "BlobStatValidResponse", BlobStatV= alidResponse, NULL, NULL, NULL);

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Blob Stat call with invalid buffer",

> "BlobStatInvalidBuffer", BlobStatI= nvalidBuffer, NULL, NULL, NULL);

> > +  // IpmiBlobTransferSessionStat<= /p>

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Session Stat call with valid data",

> "SessionStatValidResponse", Sessio= nStatValidResponse, NULL, NULL, NULL);

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "Session Stat call with invalid buffer",

> "SessionStatInvalidBuffer", Sessio= nStatInvalidBuffer, NULL, NULL, NULL);

> > +  // IpmiBlobTransferWriteMeta

> > +  Status =3D AddTestCase (IpmiBlo= bTransfer, "WriteMeta call with valid data",

> "WriteMetaValidResponse", WriteMet= aValidResponse, NULL, NULL, NULL);

> > +

> > +  // Execute the tests.

> > +  Status =3D RunAllTestSuites (Fr= amework);

> > +  return Status;

> > +}

> > +

> > +/**

> > +  Standard UEFI entry point for t= arget based

> > +  unit test execution from UEFI S= hell.

> > +**/

> > +EFI_STATUS

> > +EFIAPI

> > +BaseLibUnitTestAppEntry (

> > +  IN EFI_HANDLE   =      ImageHandle,

> > +  IN EFI_SYSTEM_TABLE  *Syst= emTable

> > +  )

> > +{

> > +  return SetupAndRunUnitTests ();=

> > +}

> > +

> > +/**

> > +  Standard POSIX C entry point fo= r host based unit test execution.

> > +**/

> > +int

> > +main (

> > +  int   argc,

> > +  char  *argv[]

> > +  )

> > +{

> > +  return SetupAndRunUnitTests ();=

> > +}

> > diff --git

> a/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/Readme.md

> b/Features/ManageabilityPkg/Universal/IpmiBl= obTransferDxe/Readme.md

> > new file mode 100644

> > index 0000000000..9eed5d3728

> > --- /dev/null

> > +++ b/Features/ManageabilityPkg/Univers= al/IpmiBlobTransferDxe/Readme.md

> > @@ -0,0 +1,24 @@

> > +# IPMI Blob Transfer Interface Driver<= /p>

> > +

> > +This DXE module is a UEFI implementati= on of the Phorphor Blob Transfer

> Interface defined in OpenBMC

> >

> +https://nam11.safelinks.protection.outlook.= com/?url=3Dhttps%3A%2F%2Fgithub.c

> om%2Fopenbmc%2Fphosphor-ipmi-

> blobs&data=3D05%7C02%7Cnicklew%40nvidia.= com%7Cd22932100e16475feff608d

> c7645e177%7C43083d15727340c1b7db39efd9ccc17a= %7C0%7C0%7C638515289

> 789849374%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC= 4wLjAwMDAiLCJQIjoiV2

> luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%= 7C%7C&sdata=3DD7SscKqXG

> OZWyXJUtSBIMmBUUf%2FAAK0G%2FHrH0nrqCUE%3D&am= p;reserved=3D0

> > +

> > +## OpenBMC implements this interface a= s a protocol, allowing UEFI and BMC

> to transfer blobs over IPMI.

> > +

> > +### Usage:

> > +Any DXE module that wishes to use this= protocol should do the following:

> > +1) The module should have a dependency= on

> gEdkiiIpmiBlobTransferProtocolGuid in its in= f "Depex" section

> > +2) The module should list gEdkiiIpmiBl= obTransferProtocolGuid in its inf

> "Protocol" section

> > +3) The module's entry point should do = a LocateProtocol on

> gEdkiiIpmiBlobTransferProtocolGuid

> > +

> > +### A sample flow of protocol usage is= as follows:

> > +1) A call to IpmiBlobTransferOpen ()

> > +2) Iterative calls to IpmiBlobTransfer= Write

> > +3) A call to IpmiBlobTransferClose ()<= /p>

> > +

> > +### Unit Tests:

> > +IpmiBlobTransferDxe/UnitTest/ contains= host based unit tests of this

> implementation.

> > +Any changes to IpmiBlobTransferDxe sho= uld include proof of successful unit

> tests.

> > +

> > +### Debugging

> > +To assist in debugging any issues, cha= nge BLOB_TRANSFER_DEBUG to desired

> debug level, such as DEBUG_ERROR or DEBUG_IN= FO.

_._,_._,_

Groups.io Links:

=20 You receive all messages sent to this group. =20 =20

View/Reply Online (#119869) | =20 | Mute= This Topic | New Topic
Your Subscriptio= n | Contact Group Owner | Unsubscribe [rebecca@openfw.io]

_._,_._,_
--_000_PH8PR12MB7025D13EAE875175691200F7D9A42PH8PR12MB7025namp_--