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 413E39411B4 for ; Fri, 17 May 2024 07:49:32 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=9FWfxHCNBz4moumie0nOmuWC4MK9hOv9LViJNUgCTDg=; c=relaxed/simple; d=groups.io; h=Message-ID:Date:User-Agent:Subject:To:Cc:References:From:In-Reply-To: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:Content-Transfer-Encoding; s=20240206; t=1715932170; v=1; b=xdZetAev+phgDjqKrF2B02uqYRTEjSawvJgUadyk98wCq45iVAN6CYZABNNSpOw2fR1zlH2x 2qGi8DR5BtJU8FWyWos338cbVEyepsy1H21sLabk+EQUH5/A0vctDtoVVL26lBiEv5oK7UKKhT6 bVoiil3qFC+0djmaex6YAZuRMuPRko/jR2d5TuqKXfJNNQWRHAtTVLSy6ntXZ9/joI9yleBqHWj JeHpKgfroWYCPTTPJ2AKvQMz64OnHlJSRG3j1lMoohlwm9ckBS692+mkAABcaUlCkv4XxyvjVfU CEhX4/Gm3s8hAaUUVWlfSzcnCkrjVDrGjpnxRhIUsOV1A== X-Received: by 127.0.0.2 with SMTP id XYitYY7687511xTvkZuJKpmj; Fri, 17 May 2024 00:49:30 -0700 X-Received: from NAM12-BN8-obe.outbound.protection.outlook.com (NAM12-BN8-obe.outbound.protection.outlook.com [40.107.237.114]) by mx.groups.io with SMTP id smtpd.web11.35314.1715932169087962891 for ; Fri, 17 May 2024 00:49:29 -0700 X-Received: from PH0PR01MB7287.prod.exchangelabs.com (2603:10b6:510:10a::21) by DS0PR01MB7939.prod.exchangelabs.com (2603:10b6:8:152::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7587.28; Fri, 17 May 2024 07:49:24 +0000 X-Received: from PH0PR01MB7287.prod.exchangelabs.com ([fe80::9ee2:336e:a1f6:486b]) by PH0PR01MB7287.prod.exchangelabs.com ([fe80::9ee2:336e:a1f6:486b%4]) with mapi id 15.20.7587.028; Fri, 17 May 2024 07:49:24 +0000 Message-ID: <7d928ca7-e312-4a2e-9470-cbd96fbdc643@os.amperecomputing.com> Date: Fri, 17 May 2024 14:49:15 +0700 User-Agent: Mozilla Thunderbird Subject: Re: [edk2-devel] [edk2-platforms][PATCH v2] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol To: Nickle Wang , devel@edk2.groups.io Cc: Abner Chang , Abdul Lateef Attar , Tinh Nguyen , Thang Nguyen OS , Mike Maslenkin References: <20240515150629.236739-1-nicklew@nvidia.com> From: "Nhi Pham via groups.io" In-Reply-To: <20240515150629.236739-1-nicklew@nvidia.com> X-ClientProxiedBy: SI2P153CA0030.APCP153.PROD.OUTLOOK.COM (2603:1096:4:190::15) To PH0PR01MB7287.prod.exchangelabs.com (2603:10b6:510:10a::21) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PH0PR01MB7287:EE_|DS0PR01MB7939:EE_ X-MS-Office365-Filtering-Correlation-Id: f71289d5-5498-4ec0-6074-08dc7645de91 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Message-Info: =?utf-8?B?eFpNWVo1b2tjMEhXR3NEdGRBT0RLSkVHeW5vcDA3Wmo1MXA2aEl6NWFXbThC?= =?utf-8?B?MzhoVlNHVWNiSXJuRmluNmtGa0lZRGZGSThGM0NpR0N1dHFvcHByWUsvNnBr?= =?utf-8?B?TmIwVFZVN3k2U2NqVmlGTDF6LzBzelhCc2QyekIzZmxNYk5iVGJxNmpvQUEy?= =?utf-8?B?S1MrOWhTTU1ueFhwMEdSekFHa3l1QUMwNnVQVDlCTlRKNXNmalIxTm9RRFlC?= =?utf-8?B?R1MrdHRRZjBBZnEreEM0WFlYVklmTDBsMEt0VW50UVdYd0Rad1dPMGdWUm9W?= =?utf-8?B?MGptN1NLTXUzdll2WWNjSVB0bnZaeGtwaHBocWtXOThzbkR3N0EzbUF1ckJq?= =?utf-8?B?R0hyNk05QXZqNWFPeUhUbVA0ZW11QkxKVXVXaWRqZU5rSHRINzM5cCtnb3pz?= =?utf-8?B?M3A5eXhNNVhldHRqcUcyaGNneVFKM09Bdktaai9NZWxIKzFFVG4zMjRZdkxq?= =?utf-8?B?ajhQSTU2aER0Y0VxN3ZvUXFVVzRveDkvclRxZlE5SVdjbW9qMHZMZG1TbXJz?= =?utf-8?B?Yk5LOElNZm9aVVk1enU1SGlnWDR0aFl6MmhpbXRDNk5JQWZRU1RLdE8veWFO?= =?utf-8?B?T2RjQ1FibWJGQ09KbTJMMk5wbm9aNGltZ3gydEZXU1BwSytJU3BBMVJGZWRV?= =?utf-8?B?SzFWQzVXTEdPY3ppYjUwZ3pxS0hRY3lBQVRZbjNjclM4aGhGTnlUSkVZOUMr?= =?utf-8?B?M0pFY3ltVlFPLzUydUx2ZTVSd1RnRm81S05UUEhZdWhQMlM0UTVEdUxTR2Fk?= =?utf-8?B?ZVU2YklJbzRHUDA3RXI0WS94Wk11WDU3ditRVDZjMkVOTmluVzBSVFZ4L3VL?= =?utf-8?B?dlV4RUM2Zk1NbzhyaWFnQlhyMXd6WGJUSmlFeUtpVUpjWUl1dms2YTJsb1cz?= =?utf-8?B?a2VMNkhaZXcyWVp2VjVHd1A3N2h6TitpSy96QkVyd0wvSmtpSGMzSE1kTWI4?= =?utf-8?B?QXFRd1RsOUY3dnEyMjgrWTJ4OGljZ0IvSzdja1Nqc2VjajFxQXBKZjYyZEd5?= =?utf-8?B?R0VSdGMvWkJCNWpMbHdVVEh1elhSYW0yNmV3SHN4V3ZPVEY3R2hrdElxdjRw?= =?utf-8?B?Y3c5K1poUEZNdkJrNFFRQ2dXa2FkendWLy84NUJwb3JxWUo0SnliRS9MeEtI?= =?utf-8?B?Smw1b2tGTnpFQUM3T240VGF6QzVyWnhJb2IwTnAvYS9lM1dBN0NTMGVuTzdq?= =?utf-8?B?M0xIYk5DRCtMMEdrSUtjeWxoZ25EdWEvZVFRbVlaMDMxWUJ4UGFHVG5wL1p0?= =?utf-8?B?WXg2K0hWS3hKREF4Mkc5Qkt2cnlWVkpoZWtIWUozWHVSRVZSWHB1NDJ1OXVo?= =?utf-8?B?akl3d3N3T042UWdzY21iTWVSRTFKMFdRQndsWGN4MkwzZzdITWRPOHNMdjFy?= =?utf-8?B?dWhQQlF4b0h1MUpwQjVPRTFNUGlEbFlFRFRqTEhWN080SW4wRW1ibGpqY1VI?= =?utf-8?B?azZzN1N2STR4M2RNTm1SdUxLUFpUSnM1clM2NHROaTRIN2tQaTZVRit6NUxs?= =?utf-8?B?MFQ5VVIxbDIxNXQ2WmxQcEphSFE5QURjQ2ptb2wvL01IWGpuL2FpNFVrU0hJ?= =?utf-8?B?M3RCN3pWSzVGYnFkVzFrby94RnVuc3AyQU1EckYwaWd0Ty9DN2tMTkVrWSti?= =?utf-8?Q?dc5K/gBhRx4PeneHmbBPF/iysSwNn14h6e4Zfkef4xMM=3D?= X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?UTNWbVdRMC8yMHpRcmg2TjVHQ2tXTDNLSmJ4aVE1TkY0MjJmdTZTelV4Rjds?= =?utf-8?B?bFByUlNpWFh3Z0JJYnV3L0hiN1N2TDV5MkhtbkxLV3cvZUtNVGpEWnhMYy82?= =?utf-8?B?U085U2ZyQ245MDMvc05veTI1ZWx5MzBuejZ2bzdwcS9vVmhwNzlKL204d21k?= =?utf-8?B?Vjl2QUNTelBuZDNyUkdRbXJpU01RY1dERVBuUy9iMGJNUkF5SHdxU3NOZVBE?= =?utf-8?B?eXUyZFFvaUV3RnBGY1RwZVovWkR4ekpHR3dZaTQ4QWpmMWd1TEJHM2hPK0p5?= =?utf-8?B?UjFQKy81V1RWaW1XZXpjby9haGxFdllBU3lqZTRVMTBlbXB1TkZqbVVmTnQz?= =?utf-8?B?M013bm9jeEVXdVV4Rnk0NGJmSlpoVWVnb0dGY2w0eTZTZGQ1OUo2alNqYkVQ?= =?utf-8?B?MERhdFd4bkEyclBSMlZEdFJIcGl5elJwQzFEYlZTUUZNOW8xYlZEZFFmODFZ?= =?utf-8?B?T2E1cGF5UGN1NDRZQnYwZXBZVUxvYzAxekpWbDA0djBJUDYvakEzeWkrSlY5?= =?utf-8?B?L0VEVHR1V1VSSFE3MVNmdnpVVUpyV2VKVUhOQlZiZlpVZ2VGRWdja3hmd3JC?= =?utf-8?B?L1kySlRMa3BDUVludTFqVWJ3R2V2KythU0poc0tQWmdEV25rUDVtYlV4QlZh?= =?utf-8?B?bVYyWWVWY0J3VWw3VU9ubVNyS3BLYzlUWUpibGc4WWl0WkhROUVCQnI2MmQ5?= =?utf-8?B?QldTN3ZGMWpmUUdlQXFBYVYvdHRpeEgwRUQxQ1grYlIzNjhDNVp5ZUExNTQ3?= =?utf-8?B?WERVWGRraVpJVDBMK0VLT0p0Y1BYU0cyWmlreGhUa1BaL1F1anNoUDJuWGFM?= =?utf-8?B?emFHb2lyU3Y0SFRCaS9WZWZra01MNHF6dVU3OUtqU3M0aTdpRkdIbXJva2l3?= =?utf-8?B?dUFYRFljaG9zMFdWejJPNHoxWXplMFJwK3pYMmw1WjNXaWQwMjdRQWZ2em96?= =?utf-8?B?NklVWTVSTTRlUlpjTWhOZmdMOVk4ajZuaU1ZR2gyU1g2M3Uva2JhQ0dqekQ3?= =?utf-8?B?L1lHY3FBN0c2Vnl2WHlFK0VvUEg3Uyt3S29PdHh6NHk3cGxKQjN6TXVNNGJL?= =?utf-8?B?TVdhRmNiT1ljZk9zTlRYMmNRNnlRVzlmM3FOQUhKL3NvT3NONk1SM09pcG5k?= =?utf-8?B?eTZqcTFNSDBVQlF0eEV3T1JCRnJXU2VKWWVEajBGdVVLSm1QTmxWVEdEVDdE?= =?utf-8?B?MXl0WXQ4YWNBbjExNzdDNlF1Y2JTQjdRMUlYQ3pjYnpsdmtSRDlMamp4SEtW?= =?utf-8?B?M2xpanRkMkZBYWE1dnUvejhZc1hMTDFGQmFraFVMVUpXb0tkOUhjTlgzZk1S?= =?utf-8?B?RTQ0ZmR2VUM2aXM4MmgxMFM2VnhYcFhjTzNGSFg3dVdYVVlJMzN3MFNmaHpE?= =?utf-8?B?VjZ1L3k4dU5weTZDL08zZElVdmZiMkY2SkRsTFB3VjMySUNVWWRadW91Smc0?= =?utf-8?B?N1RTK1FNTzYybmlzQlJQVHk5bnlWcDlkQ0t5dW5wY2piMTZtd0pOdUdkZmZy?= =?utf-8?B?dlJPN0JJS1lmeFc4U3Z1cjJvaUZVMC9Gd2Q3aURrMXZLdjFxWlhxd0VyZFE1?= =?utf-8?B?bXJNNmdoSElaNDc2MDhtdHJJSERLbFNyaFM0UlVIcXJ6Vkt2eVBrSGRKMlR1?= =?utf-8?B?VTFOV1JYelVZbnMzTXhRT25Tc20zaXRvbzhDK1hFQUh6TUtKRHpSSFZ4V1pj?= =?utf-8?B?N0JOMWkzSTdKNTdqd3JFbEdxYzQvUnRIbHI0aHYrNXgweWhxVWFIZTNjQUFR?= =?utf-8?B?Y01hZnRReXBrV25PWUNtOUt6TkdXdDB6bk9DNXc0MjNjQ25XMEp0aHRRaGdo?= =?utf-8?B?OUptb1pNZk1zeUhRbG5Cd3A4MkF2cmcwWktvR2FjbWxTMVdueXRMV3JsYUJ5?= =?utf-8?B?bWhvK05EbzkvdjdYWm8xRzhYWm1CYTdZd1R2alFCYTcraHkxaFkvb0lrQlJr?= =?utf-8?B?VkxzVWdaOG5OMUNpMDVPbkx4K0hLQUxrZll4NndhT0YzYXZEVGp3aEprcFJi?= =?utf-8?B?SmFQTWFKdlN3S05rQ1hwbktZOXByQXl5UHhyc2poazM1YXJYNXp0U0g0dXph?= =?utf-8?B?TzdvQXArRDlMdWdUMjdVMWpySE9CU0M0MkRPMWRmTkQ0ZWU0V3dqbXBlNGph?= =?utf-8?B?M0M1ajF5MDJFTHlBVTI2VXliZ3plYWkvR2prekZmY3lXZDJyZFRPRk56ejFv?= =?utf-8?B?S1E9PQ==?= X-OriginatorOrg: os.amperecomputing.com X-MS-Exchange-CrossTenant-Network-Message-Id: f71289d5-5498-4ec0-6074-08dc7645de91 X-MS-Exchange-CrossTenant-AuthSource: PH0PR01MB7287.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 May 2024 07:49:24.4169 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3bc2b170-fd94-476d-b0ce-4229bdc904a7 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: htkmWH3oJjOm8ikl9M0VfXs94Lz34IJ/bxQLufnA8xMEqjNjIj5JDqH4BJcgU0gF6r6nvIK92egPQ3rrfZ04gNgpTWMMDWvt4HKVFpw9LZM= X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS0PR01MB7939 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: Fri, 17 May 2024 00:49:29 -0700 Resent-From: nhi@os.amperecomputing.com Reply-To: devel@edk2.groups.io,nhi@os.amperecomputing.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: rLo1x52ogeJXkzixDHpDB0Mrx7686176AA= Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20240206 header.b=xdZetAev; 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 Hi Nickle, Please see my comments inline... P/s: I just realized that I can not test this protocol without IPMI SSIF=20 to be compatible with ManageabilityPkg framework. On 5/15/2024 10:06 PM, Nickle Wang wrote: > REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3D4773 >=20 > This change implements the blob transfer protocol used in OpenBmc > documented here: https://github.com/openbmc/phosphor-ipmi-blobs >=20 > 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/IpmiBlobTransfer= Dxe/IpmiBlobTransferDxe.inf > create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransfer= Dxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf > create mode 100644 Features/ManageabilityPkg/Include/Protocol/IpmiBlobT= ransfer.h > create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransfer= Dxe/InternalIpmiBlobTransfer.h > create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransfer= Dxe/IpmiBlobTransferDxe.c > create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransfer= Dxe/UnitTest/IpmiBlobTransferTestUnitTests.c > create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransfer= Dxe/Readme.md >=20 > diff --git a/Features/ManageabilityPkg/ManageabilityPkg.dec b/Features/Ma= nageabilityPkg/ManageabilityPkg.dec > index eb0ee67cba..dc1d00162c 100644 > --- a/Features/ManageabilityPkg/ManageabilityPkg.dec > +++ b/Features/ManageabilityPkg/ManageabilityPkg.dec > @@ -4,6 +4,7 @@ > # those are related to the platform management. > # > # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<= BR> > +# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserv= ed. > # SPDX-License-Identifier: BSD-2-Clause-Patent > # > ## > @@ -58,6 +59,8 @@ > gEdkiiPldmProtocolGuid =3D { 0x60997616, 0xDB70, 0x4B5= F, { 0x86, 0xA4, 0x09, 0x58, 0xA3, 0x71, 0x47, 0xB4 } } > gEdkiiPldmSmbiosTransferProtocolGuid =3D { 0xFA431C3C, 0x816B, 0x4B3= 2, { 0xA3, 0xE0, 0xAD, 0x9B, 0x7F, 0x64, 0x27, 0x2E } } > gEdkiiMctpProtocolGuid =3D { 0xE93465C1, 0x9A31, 0x4C9= 6, { 0x92, 0x56, 0x22, 0x0A, 0xE1, 0x80, 0xB4, 0x1B } } > + ## Include/Protocol/IpmiBlobTransfer.h > + gEdkiiIpmiBlobTransferProtocolGuid =3D { 0x05837c75, 0x1d65, 0x468b= , { 0xb1, 0xc2, 0x81, 0xaf, 0x9a, 0x31, 0x5b, 0x2c } } > =20 > [PcdsFixedAtBuild] > ## This value is the MCTP Interface source and destination endpoint I= D for transmiting MCTP message. > diff --git a/Features/ManageabilityPkg/Include/Manageability.dsc b/Featur= es/ManageabilityPkg/Include/Manageability.dsc > index 2e410df9ba..aae343a733 100644 > --- a/Features/ManageabilityPkg/Include/Manageability.dsc > +++ b/Features/ManageabilityPkg/Include/Manageability.dsc > @@ -2,6 +2,7 @@ > # Common libraries for Manageabilty Package > # > # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<= BR> > +# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserv= ed. > # 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.inf > !endif > =20 > [Components.X64] > diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Ipmi= BlobTransferDxe.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferD= xe/IpmiBlobTransferDxe.inf > new file mode 100644 > index 0000000000..108f4bb5f8 > --- /dev/null > +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTra= nsferDxe.inf > @@ -0,0 +1,39 @@ > +## @file > +# IPMI Blob Transfer Protocol DXE Driver. > +# > +# Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights = reserved. > +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > + > +[Defines] > + INF_VERSION =3D 0x00010005 > + BASE_NAME =3D IpmiBlobTransferDxe > + FILE_GUID =3D 6357c804-78bb-4b0c-abdf-c75df942f31= 9 > + MODULE_TYPE =3D DXE_DRIVER > + VERSION_STRING =3D 1.0 > + ENTRY_POINT =3D IpmiBlobTransferDxeDriverEntryPoint > + > +[Sources.common] > + IpmiBlobTransferDxe.c > + > +[LibraryClasses] > + BaseLib > + BaseMemoryLib > + DebugLib > + IpmiLib > + MemoryAllocationLib > + PcdLib > + UefiBootServicesTableLib > + UefiDriverEntryPoint > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + ManageabilityPkg/ManageabilityPkg.dec > + > +[Protocols] > + gEdkiiIpmiBlobTransferProtocolGuid > + > +[Depex] > + TRUE > diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Unit= Test/IpmiBlobTransferTestUnitTestsHost.inf b/Features/ManageabilityPkg/Univ= ersal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf > new file mode 100644 > index 0000000000..dab6858f09 > --- /dev/null > +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ip= miBlobTransferTestUnitTestsHost.inf > @@ -0,0 +1,40 @@ > +## @file > +# Unit tests of the Ipmi blob transfer driver that are run from a host e= nvironment. > +# > +# Copyright (c) 2020-2024, NVIDIA CORPORATION & AFFILIATES. All rights r= eserved. > +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +## > + > +[Defines] > + INF_VERSION =3D 0x00010006 > + BASE_NAME =3D IpmiBlobTransferDxeUnitTestsHost > + FILE_GUID =3D 1f5d4095-ea52-432c-b078-86097fef600= 4 > + MODULE_TYPE =3D HOST_APPLICATION > + VERSION_STRING =3D 1.0 > + > +# > +# The following information is for reference only > +# and not required by the build tools. > +# > +# VALID_ARCHITECTURES =3D X64 > +# > + > +[Sources] > + IpmiBlobTransferTestUnitTests.c > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + ManageabilityPkg/ManageabilityPkg.dec > + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec > + > +[LibraryClasses] > + BaseLib > + BaseMemoryLib > + DebugLib > + UnitTestLib > + IpmiLib > + > +[Protocols] > + gEdkiiIpmiBlobTransferProtocolGuid > diff --git a/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.= h b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h > new file mode 100644 > index 0000000000..14b5294314 > --- /dev/null > +++ b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h > @@ -0,0 +1,253 @@ > +/** @file > + > + IPMI Blob Transfer driver > + > + Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights r= eserved. > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + @Par: https://github.com/openbmc/phosphor-ipmi-blobs/blob/master/READM= E.md > +**/ 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=20 BMC? Or this protocol is only to support OpenBMC. > + > +// > +// Blob Transfer Function Prototypes > +// > + > +/** > + This function retrieves the count of blob transfers available through = the IPMI. > + > + @param[out] Count The number of active blobs > + > + @retval EFI_SUCCESS Successfully retrieved the number of ac= tive 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 en= umerate > + @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 op= ened > + @param[out] SessionId A unique session identifier > + > + @retval EFI_SUCCESS Successfully opened the blob. > + @retval Other An error occurred > +**/ > +typedef > +EFI_STATUS > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)( > + IN CHAR8 *BlobId, > + IN UINT16 Flags, > + OUT UINT16 *SessionId > + ); > + > +/** > + This function reads data from a blob over the IPMI. > + > + @param[in] SessionId The session ID returned from a call= to BlobOpen > + @param[in] Offset The offset of the blob from which t= o start reading > + @param[in] RequestedSize The length of data to read > + @param[out] Data Data read from the blob > + > + @retval EFI_SUCCESS Successfully read from the blob. > + @retval Other An error occurred > +**/ > +typedef > +EFI_STATUS > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_READ)( > + IN UINT16 SessionId, > + IN UINT32 Offset, > + IN UINT32 RequestedSize, > + OUT UINT8 *Data > + ); > + > +/** > + This function writes data to a blob over the IPMI. > + > + @param[in] SessionId The session ID returned from a call= to BlobOpen > + @param[in] Offset The offset of the blob from which t= o 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 cal= l to BlobOpen > + @param[in] CommitDataLength The length of data to commit to th= e blob > + @param[in] CommitData A pointer to the data to commit > + > + @retval EFI_SUCCESS Successful commit to the blob. > + @retval Other An error occurred > +**/ > +typedef > +EFI_STATUS > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)( > + IN UINT16 SessionId, > + IN UINT8 CommitDataLength, > + IN UINT8 *CommitData > + ); > + > +/** > + This function close a session associated with a blob transfer over the= IPMI. > + > + @param[in] SessionId The session ID returned from a call= to BlobOpen > + > + @retval EFI_SUCCESS The blob was closed. > + @retval Other An error occurred > +**/ > +typedef > +EFI_STATUS > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)( > + IN UINT16 SessionId > + ); > + > +/** > + This function deletes a specific blob identified by its ID over the IP= MI. > + > + @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 Blo= bId from an IPMI. > + > + @param[in] BlobId The Blob ID to gather statistics fo= r > + @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 successful= ly 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 sta= tistics 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 successful= ly 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 a= n IPMI. > + > + @param[in] SessionId The ID of the session to write meta= data for > + @param[in] Offset The offset of the metadata to write= to > + @param[in] Data The data to write to the metadata > + @param[in] WriteLength The length to write > + > + @retval EFI_SUCCESS The blob metadata was successfully = written. > + @retval Other An error occurred > +**/ > +typedef > +EFI_STATUS > +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)( > + IN UINT16 SessionId, > + IN UINT32 Offset, > + IN UINT8 *Data, > + IN UINT32 WriteLength > + ); > + > +// > +// Structure of EDKII_IPMI_BLOB_TRANSFER_PROTOCOL > +// > +struct _EDKII_IPMI_BLOB_TRANSFER_PROTOCOL { > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT BlobGetCount; > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE BlobEnumerate; > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_OPEN BlobOpen; > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_READ BlobRead; > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE BlobWrite; > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT BlobCommit; > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE BlobClose; > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_DELETE BlobDelete; > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_STAT BlobStat; > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT BlobSessionStat; > + EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META BlobWriteMeta; > +}; > + > +typedef struct _EDKII_IPMI_BLOB_TRANSFER_PROTOCOL EDKII_IPMI_BLOB_TRANSF= ER_PROTOCOL; > + > +extern EFI_GUID gEdkiiIpmiBlobTransferProtocolGuid; > diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Inte= rnalIpmiBlobTransfer.h b/Features/ManageabilityPkg/Universal/IpmiBlobTransf= erDxe/InternalIpmiBlobTransfer.h > new file mode 100644 > index 0000000000..3e90dc6871 > --- /dev/null > +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpm= iBlobTransfer.h > @@ -0,0 +1,407 @@ > +/** @file > + > + Headers for IPMI Blob Transfer driver > + > + Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights r= eserved. > + > + 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 byte = completion code + 3 bytes OEN Nit: Add a space after sizeof > +#define BLOB_MAX_DATA_PER_PACKET 64 Should it be moved to Include/Protocol/IpmiBlobTransfer.h? The caller=20 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 blob > +// The BmcBlobDelete command expects to receive a body of: > +// > +typedef struct { > + CHAR8 BlobId[BLOB_MAX_DATA_PER_PACKET]; > +} IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA; > + > +// > +// Command 8 - BmcBlobStat > +// This command returns statistics about a blob. > +// This command expects to receive a body of: > +// > +typedef struct { > + CHAR8 BlobId[BLOB_MAX_DATA_PER_PACKET]; > +} IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA; > + > +typedef struct { > + UINT16 BlobState; > + UINT32 Size; // Size in bytes of the blob > + UINT8 MetaDataLen; > + UINT8 MetaData[BLOB_MAX_DATA_PER_PACKET]; > +} IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE; > + > +// > +// Command 9 - BmcBlobSessionStat > +// Returns same data as BmcBlobState expect for a session, not a blob > +// This command expects to receive a body of: > +// > +typedef struct { > + UINT16 SessionId; > +} IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA; > + > +typedef struct { > + UINT16 BlobState; > + UINT32 Size; // Size in bytes of the blob > + UINT8 MetaDataLen; > + UINT8 MetaData[BLOB_MAX_DATA_PER_PACKET]; > +} IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE; > + > +// > +// Command 10 - BmcBlobWriteMeta > +// The BmcBlobWriteMeta command expects to receive a body of: > +// > +typedef struct { > + UINT16 SessionId; > + UINT32 Offset; > + UINT8 Data[BLOB_MAX_DATA_PER_PACKET]; > +} IPMI_BLOB_TRANSFER_BLOB_WRITE_META_SEND_DATA; > + > +#define IPMI_BLOB_TRANSFER_BLOB_WRITE_META_RESPONSE NULL > + > +#pragma pack() > + > +/** > + Calculate CRC-16-CCITT with poly of 0x1021 > + > + @param[in] Data The target data. > + @param[in] DataSize The target data size. > + > + @return UINT16 The CRC16 value. > + > +**/ > +UINT16 > +CalculateCrc16Ccitt ( > + IN UINT8 *Data, > + IN UINTN DataSize > + ); > + > +/** > + This function does blob transfer over IPMI command. > + > + @param[in] SubCommand The specific sub-command to be executed = as part of > + the blob transfer operation. > + @param[in] SendData A pointer to the data buffer that contai= ns the data to be sent. > + @param[in] SendDataSize The size of the data to be sent, in byte= s. > + @param[out] ResponseData A pointer to the buffer where the respon= se data will be stored. > + @param[out] ResponseDataSize A pointer to a variable that will hold t= he size of the response > + data received. > + > + @retval EFI_SUCCESS Successfully sends blob data. > + @retval EFI_OUT_OF_RESOURCES Memory allocation fails. > + @retval EFI_PROTOCOL_ERROR Communication errors. > + @retval EFI_CRC_ERROR Data integrity checks fail. > + @retval Other An error occurred > + > +**/ > +EFI_STATUS > +IpmiBlobTransferSendIpmi ( > + IN UINT8 SubCommand, > + IN UINT8 *SendData, > + IN UINT32 SendDataSize, > + OUT UINT8 *ResponseData, > + OUT UINT32 *ResponseDataSize > + ); > + > +/** > + This function retrieves the count of blob transfers available through = the IPMI. > + > + @param[out] Count The number of active blobs > + > + @retval EFI_SUCCESS Successfully retrieved the number of ac= tive 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 en= umerate > + @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 op= ened > + @param[out] SessionId A unique session identifier > + > + @retval EFI_SUCCESS Successfully opened the blob. > + @retval Other An error occurred > +**/ > +EFI_STATUS > +IpmiBlobTransferOpen ( > + IN CHAR8 *BlobId, > + IN UINT16 Flags, > + OUT UINT16 *SessionId > + ); > + > +/** > + This function reads data from a blob over the IPMI. > + > + @param[in] SessionId The session ID returned from a call= to BlobOpen > + @param[in] Offset The offset of the blob from which t= o start reading > + @param[in] RequestedSize The length of data to read > + @param[out] Data Data read from the blob > + > + @retval EFI_SUCCESS Successfully read from the blob. > + @retval Other An error occurred > +**/ > +EFI_STATUS > +IpmiBlobTransferRead ( > + IN UINT16 SessionId, > + IN UINT32 Offset, > + IN UINT32 RequestedSize, > + OUT UINT8 *Data > + ); > + > +/** > + This function writes data to a blob over the IPMI. > + > + @param[in] SessionId The session ID returned from a call= to BlobOpen > + @param[in] Offset The offset of the blob from which t= o 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 cal= l to BlobOpen > + @param[in] CommitDataLength The length of data to commit to th= e blob > + @param[in] CommitData A pointer to the data to commit > + > + @retval EFI_SUCCESS Successful commit to the blob. > + @retval Other An error occurred > +**/ > +EFI_STATUS > +IpmiBlobTransferCommit ( > + IN UINT16 SessionId, > + IN UINT8 CommitDataLength, > + IN UINT8 *CommitData > + ); > + > +/** > + This function close a session associated with a blob transfer over the= IPMI. > + > + @param[in] SessionId The session ID returned from a call= to BlobOpen > + > + @retval EFI_SUCCESS The blob was closed. > + @retval Other An error occurred > +**/ > +EFI_STATUS > +IpmiBlobTransferClose ( > + IN UINT16 SessionId > + ); > + > +/** > + This function deletes a specific blob identified by its ID over the IP= MI. > + > + @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 Blo= bId from an IPMI. > + > + @param[in] BlobId The Blob ID to gather statistics fo= r > + @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 successful= ly 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 sta= tistics 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 successful= ly 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 a= n IPMI. > + > + @param[in] SessionId The ID of the session to write meta= data for > + @param[in] Offset The offset of the metadata to write= to > + @param[in] Data The data to write to the metadata > + @param[in] WriteLength The length to write > + > + @retval EFI_SUCCESS The blob metadata was successfully = written. > + @retval Other An error occurred > +**/ > +EFI_STATUS > +IpmiBlobTransferWriteMeta ( > + IN UINT16 SessionId, > + IN UINT32 Offset, > + IN UINT8 *Data, > + IN UINT32 WriteLength > + ); > diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Ipmi= BlobTransferDxe.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe= /IpmiBlobTransferDxe.c > new file mode 100644 > index 0000000000..b8a2db193b > --- /dev/null > +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTra= nsferDxe.c > @@ -0,0 +1,872 @@ > +/** @file > + > + IPMI Blob Transfer driver > + > + Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights r= eserved. > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > +#include > + > +#include "InternalIpmiBlobTransfer.h" > + > +#define BLOB_TRANSFER_DEBUG DEBUG_MANAGEABILITY > + > +STATIC CONST EDKII_IPMI_BLOB_TRANSFER_PROTOCOL mIpmiBlobTransfer =3D { > + (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)*IpmiBlobTransferGetCount= , > + (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnumerat= e, > + (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)*IpmiBlobTransferSessi= onStat, > + (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWriteMe= ta > +}; > + > +/** > + Calculate CRC-16-CCITT with poly of 0x1021 > + > + @param[in] Data The target data. > + @param[in] DataSize The target data size. > + > + @return UINT16 The CRC16 value. > + > +**/ > +UINT16 > +CalculateCrc16Ccitt ( > + IN UINT8 *Data, > + IN UINTN DataSize > + ) > +{ > + UINTN Index; > + UINTN BitIndex; > + UINT16 Crc; > + UINT16 Poly; > + BOOLEAN XorFlag; > + > + Crc =3D 0xFFFF; > + Poly =3D 0x1021; > + XorFlag =3D FALSE; > + > + for (Index =3D 0; Index < (DataSize + 2); ++Index) { > + for (BitIndex =3D 0; BitIndex < 8; ++BitIndex) { > + XorFlag =3D (Crc & 0x8000) ? TRUE : FALSE; > + Crc <<=3D 1; > + if ((Index < DataSize) && (Data[Index] & (1 << (7 - BitIndex)))) { > + Crc++; > + } > + > + if (XorFlag =3D=3D TRUE) { > + Crc ^=3D Poly; > + } > + } > + } > + > + DEBUG ((BLOB_TRANSFER_DEBUG, "%a: CRC-16-CCITT %x\n", __func__, Crc)); > + > + return Crc; > +} > + > +/** > + This function does blob transfer over IPMI command. > + > + @param[in] SubCommand The specific sub-command to be executed = as part of > + the blob transfer operation. > + @param[in] SendData A pointer to the data buffer that contai= ns the data to be sent. > + @param[in] SendDataSize The size of the data to be sent, in byte= s. > + @param[out] ResponseData A pointer to the buffer where the respon= se data will be stored. > + @param[out] ResponseDataSize A pointer to a variable that will hold t= he 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,=20 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) * SendDataSize)= ; > + } > + > + IpmiSendData =3D AllocateZeroPool (IpmiSendDataSize); > + if (IpmiSendData =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + Header.OEN[0] =3D OpenBmcOen[0]; > + Header.OEN[1] =3D OpenBmcOen[1]; > + Header.OEN[2] =3D OpenBmcOen[2]; > + Header.SubCommand =3D SubCommand; > + CopyMem (IpmiSendData, &Header, sizeof (IPMI_BLOB_TRANSFER_HEADER)); > + if (SendDataSize) { if (SendDataSize !=3D 0) > + // > + // Calculate the Crc of the send data > + // > + Crc =3D CalculateCrc16Ccitt (SendData, SendDataSize); > + CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER), &Crc, si= zeof (UINT16)); > + CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER) + sizeof = (UINT16), SendData, SendDataSize); > + } > + > + DEBUG_CODE_BEGIN (); > + DEBUG ((BLOB_TRANSFER_DEBUG, "%a: Inputs:\n", __func__)); > + DEBUG ((BLOB_TRANSFER_DEBUG, "%a: SendDataSize: %02x\nData: ", __func_= _, SendDataSize)); > + UINT8 i; > + > + for (i =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: ", __f= unc__, 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_OVERHE= AD); > + // > + // If expecting data to be returned, we have to also account for the 1= 6 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: ", __f= unc__, 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 (CompletionCod= e); > + 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 err= or. > + // Some messages do not require a response. > + // > + *ResponseDataSize =3D 0; > + FreePool (IpmiResponseData); > + return Status; > + // Now we need to validate the CRC then send the Response body back > + } else { > + // Strip the OEN, we are done with it now > + ModifiedResponseData =3D ModifiedResponseData + sizeof (Oen); > + IpmiResponseDataSize -=3D sizeof (Oen); > + // Then validate the Crc > + CopyMem (&Crc, ModifiedResponseData, sizeof (Crc)); > + ModifiedResponseData =3D ModifiedResponseData + sizeof (Crc); > + IpmiResponseDataSize -=3D sizeof (Crc); > + > + if (Crc =3D=3D CalculateCrc16Ccitt (ModifiedResponseData, IpmiRespon= seDataSize)) { > + CopyMem (ResponseData, ModifiedResponseData, IpmiResponseDataSize)= ; > + CopyMem (ResponseDataSize, &IpmiResponseDataSize, sizeof (IpmiResp= onseDataSize)); > + FreePool (IpmiResponseData); > + return EFI_SUCCESS; > + } else { > + FreePool (IpmiResponseData); > + return EFI_CRC_ERROR; > + } > + } > +} > + > +/** > + This function retrieves the count of blob transfers available through = the IPMI. > + > + @param[out] Count The number of active blobs > + > + @retval EFI_SUCCESS Successfully retrieved the number of ac= tive 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 (IpmiBlobTransferSubcommandGetCoun= t, 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 en= umerate > + @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_RESPONS= E); > + 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 (IpmiBlobTransferSubcommandEnumera= te, 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 op= ened It would be good if we can list out all flag definitions here. Actually,=20 I don't know how to input for this argument. Are they BLOB_OPEN_FLAG_READ and BLOB_OPEN_FLAG_WRITE in the private=20 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=20 the presence of a blob by calling GetCount () and Enumerate () before=20 opening a blob session. This check here could waste time. Or, do we call=20 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_PA= CKET); > + 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 *)Se= ndData)->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)->Bl= obId, 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, S= endData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize); > + if (!EFI_ERROR (Status)) { > + *SessionId =3D ((IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE *)ResponseDat= a)->SessionId; > + } > + > + FreePool (ResponseData); > + FreePool (SendData); > + FreePool (BlobSearch); > + return Status; > +} > + > +/** > + This function reads data from a blob over the IPMI. > + > + @param[in] SessionId The session ID returned from a call= to BlobOpen > + @param[in] Offset The offset of the blob from which t= o 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=20 opening the session. How do we handle this failure path? Do we need to=20 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, S= endData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize); > + if (!EFI_ERROR (Status)) { > + CopyMem (Data, ((IPMI_BLOB_TRANSFER_BLOB_READ_RESPONSE *)ResponseDat= a)->Data, ResponseDataSize * sizeof (UINT8)); > + } > + > + FreePool (ResponseData); > + FreePool (SendData); > + return Status; > +} > + > +/** > + This function writes data to a blob over the IPMI. > + > + @param[in] SessionId The session ID returned from a call= to BlobOpen > + @param[in] Offset The offset of the blob from which t= o 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=20 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 S= essionId; > + ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset =3D O= ffset; > + CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Data, = Data, sizeof (UINT8) * WriteLength); > + > + ResponseDataSize =3D 0; > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcomm= andWrite, 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 cal= l to BlobOpen > + @param[in] CommitDataLength The length of data to commit to th= e 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://github.com/openbmc/phosphor-ipmi-blobs,=20 the commit data is block-specific optional. For instance, the commit data is optional for SMBIOS blob transfer. Look=20 at https://github.com/openbmc/smbios-mdr > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Format send data > + // > + SendDataSize =3D sizeof (SessionId) + sizeof (CommitDataLength) + Comm= itDataLength; > + 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)->CommitDataLeng= th =3D CommitDataLength; > + CopyMem (((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)->Commi= tData, CommitData, sizeof (UINT8) * CommitDataLength); > + > + ResponseDataSize =3D 0; > + > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandCommit,= SendData, SendDataSize, NULL, &ResponseDataSize); > + > + FreePool (SendData); > + return Status; > +} > + > +/** > + This function close a session associated with a blob transfer over the= IPMI. > + > + @param[in] SessionId The session ID returned from a call= to BlobOpen > + > + @retval EFI_SUCCESS The blob was closed. > + @retval Other An error occurred > +**/ > +EFI_STATUS > +IpmiBlobTransferClose ( > + IN UINT16 SessionId > + ) > +{ > + EFI_STATUS Status; > + UINT8 *SendData; > + UINT32 SendDataSize; > + UINT32 ResponseDataSize; > + > + // > + // Format send data > + // > + SendDataSize =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 S= essionId; > + > + 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 IP= MI. > + > + @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 (IpmiBlobTransferSubcommandDelete,= SendData, SendDataSize, NULL, &ResponseDataSize); > + > + FreePool (SendData); > + return Status; > +} > + > +/** > + This function retrieve the status of a specific blob identified by Blo= bId from an IPMI. > + > + @param[in] BlobId The Blob ID to gather statistics fo= r > + @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 successful= ly 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 NU= LL) || (MetadataLength =3D=3D NULL)) { Could we make Metadata **per spec**, MetadataLength, and Size optional?=20 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)->Bl= obId, BLOB_MAX_DATA_PER_PACKET, BlobId); > + > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandStat, S= endData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize); > + if (!EFI_ERROR (Status)) { > + *BlobState =3D ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)Respon= seData)->BlobState; > + *Size =3D ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)Respon= seData)->Size; > + *MetadataLength =3D ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)Respon= seData)->MetaDataLen; > + > + CopyMem (&Metadata, &((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)Respo= nseData)->MetaData, sizeof (((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)Respo= nseData)->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 sta= tistics 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 successful= ly 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_DAT= A); > + SendData =3D AllocateZeroPool (SendDataSize); > + if (SendData =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA *)SendData)->SessionI= d =3D SessionId; > + > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandSession= Stat, SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize); > + > + if (!EFI_ERROR (Status)) { > + *BlobState =3D ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE = *)ResponseData)->BlobState; > + *Size =3D ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE = *)ResponseData)->Size; > + *MetadataLength =3D ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE = *)ResponseData)->MetaDataLen; > + > + CopyMem (&Metadata, &((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE= *)ResponseData)->MetaData, sizeof (((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_= RESPONSE *)ResponseData)->MetaData)); > + } > + > + FreePool (ResponseData); > + FreePool (SendData); > + return Status; > +} > + > +/** > + This function writes metadata to a blob associated with a session in a= n IPMI. > + > + @param[in] SessionId The ID of the session to write meta= data for > + @param[in] Offset The offset of the metadata to write= to > + @param[in] Data The data to write to the metadata > + @param[in] WriteLength The length to write > + > + @retval EFI_SUCCESS The blob metadata was successfully = written. > + @retval Other An error occurred > +**/ > +EFI_STATUS > +IpmiBlobTransferWriteMeta ( > + IN UINT16 SessionId, > + IN UINT32 Offset, > + IN UINT8 *Data, How do callers know the data format of metadata for writing correctly? > + IN UINT32 WriteLength Should check with BLOB_MAX_DATA_PER_PACKET > + ) > +{ > + EFI_STATUS Status; > + UINT8 *SendData; > + UINT32 SendDataSize; > + UINT32 ResponseDataSize; > + > + if (Data =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 S= essionId; > + ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset =3D O= ffset; > + CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Data, = Data, sizeof (UINT8) * WriteLength); > + > + ResponseDataSize =3D 0; > + > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandWriteMe= ta, SendData, SendDataSize, NULL, &ResponseDataSize); > + > + FreePool (SendData); > + return Status; > +} > + > +/** > + This is the declaration of an EFI image entry point. This entry point = is > + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers incl= uding > + both device drivers and bus drivers. > + > + @param[in] ImageHandle The firmware allocated handle for the UE= FI 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/Unit= Test/IpmiBlobTransferTestUnitTests.c b/Features/ManageabilityPkg/Universal/= IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c > new file mode 100644 > index 0000000000..0f728527b8 > --- /dev/null > +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ip= miBlobTransferTestUnitTests.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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +GoodCrc ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + UINT8 Data[5] =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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +BadCrc ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + UINT8 Data[5] =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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +SendIpmiBadCompletion ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + VOID *ResponseData; > + UINT32 *ResponseDataSize; > + EFI_STATUS Status; > + VOID *MockResponseResults =3D NULL; > + > + MockResponseResults =3D (UINT8 *)AllocateZeroPool (INVALID_COMPLETION_= SIZE); > + ResponseDataSize =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32)); > + CopyMem (MockResponseResults, &InvalidCompletion, INVALID_COMPLETION_S= IZE); > + > + MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, INVALID_COMPLETIO= N_SIZE, EFI_SUCCESS); > + > + ResponseData =3D (UINT8 *)AllocateZeroPool (*ResponseDataSize); > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandG= etCount, 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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +SendIpmiNoDataResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + VOID *ResponseData; > + UINT32 *ResponseDataSize; > + EFI_STATUS Status; > + VOID *MockResponseResults =3D NULL; > + > + MockResponseResults =3D (UINT8 *)AllocateZeroPool (NO_DATA_RESPONSE_SI= ZE); > + ResponseDataSize =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32)); > + CopyMem (MockResponseResults, &NoDataResponse, NO_DATA_RESPONSE_SIZE); > + > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, NO_DAT= A_RESPONSE_SIZE, EFI_SUCCESS); > + if (EFI_ERROR (Status)) { > + return UNIT_TEST_ERROR_TEST_FAILED; > + } > + > + ResponseData =3D (UINT8 *)AllocateZeroPool (sizeof (NoDataResponse)); > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandG= etCount, 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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +SendIpmiBadOenResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + VOID *ResponseData; > + UINT32 *ResponseDataSize; > + EFI_STATUS Status; > + VOID *MockResponseResults =3D NULL; > + > + MockResponseResults =3D (UINT8 *)AllocateZeroPool (BAD_OEN_RESPONSE_SI= ZE); > + ResponseDataSize =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32)); > + CopyMem (MockResponseResults, &BadOenResponse, BAD_OEN_RESPONSE_SIZE); > + > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, BAD_OE= N_RESPONSE_SIZE, EFI_SUCCESS); > + if (EFI_ERROR (Status)) { > + return UNIT_TEST_ERROR_TEST_FAILED; > + } > + > + ResponseData =3D (UINT8 *)AllocateZeroPool (sizeof (BadOenResponse)); > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandG= etCount, 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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +SendIpmiBadCrcResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + VOID *ResponseData; > + UINT32 *ResponseDataSize; > + EFI_STATUS Status; > + VOID *MockResponseResults =3D NULL; > + > + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (BAD_CRC_RES= PONSE_SIZE)); > + ResponseDataSize =3D (UINT32 *)AllocateZeroPool (sizeof (UINT32)); > + CopyMem (MockResponseResults, &BadCrcResponse, BAD_CRC_RESPONSE_SIZE); > + > + Status =3D MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, BAD_CR= C_RESPONSE_SIZE, EFI_SUCCESS); > + if (EFI_ERROR (Status)) { > + return UNIT_TEST_ERROR_TEST_FAILED; > + } > + > + ResponseData =3D (UINT8 *)AllocateZeroPool (sizeof (BadCrcResponse)); > + Status =3D IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandG= etCount, 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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +SendIpmiValidCountResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + UINT8 *ResponseData; > + UINT32 *ResponseDataSize; > + EFI_STATUS Status; > + VOID *MockResponseResults =3D NULL; > + > + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_GET_C= OUNT_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 (IpmiBlobTransferSubcommandG= etCount, 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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +GetCountValidCountResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + UINT32 Count; > + VOID *MockResponseResults =3D NULL; > + > + Count =3D 0; > + > + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_GET_C= OUNT_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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +EnumerateValidResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + CHAR8 *BlobId; > + VOID *MockResponseResults =3D NULL; > + > + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_ENUME= RATE_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_PACKET= ); > + > + Status =3D IpmiBlobTransferEnumerate (0, BlobId); > + > + UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); > + UT_ASSERT_MEM_EQUAL (BlobId, "/smbios", 7); > + FreePool (MockResponseResults); > + FreePool (BlobId); > + return UNIT_TEST_PASSED; > +} > + > +/** > + @param[in] Context [Optional] An optional parameter that enables: > + 1) test-case reuse with varied parameters and > + 2) test-case re-entry for Target tests that nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +EnumerateInvalidBuffer ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + CHAR8 *BlobId; > + EFI_STATUS Status; > + VOID *MockResponseResults =3D NULL; > + > + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_ENUME= RATE_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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +OpenValidResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + CHAR8 *BlobId; > + UINT16 Flags; > + UINT16 SessionId; > + VOID *MockResponseResults =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_ENUM= ERATE_RESPONSE_SIZE)); > + CopyMem (MockResponseResults2, &ValidEnumerateResponse, VALID_ENUMERAT= E_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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +ReadValidResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + UINT8 *ResponseData; > + UINT8 ExpectedDataResponse[4] =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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +ReadInvalidBuffer ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + UINT8 *ResponseData; > + EFI_STATUS Status; > + VOID *MockResponseResults =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, ResponseData)= , NULL); > + > + FreePool (MockResponseResults); > + return UNIT_TEST_PASSED; > +} > + > +/** > + @param[in] Context [Optional] An optional parameter that enables: > + 1) test-case reuse with varied parameters and > + 2) test-case re-entry for Target tests that nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +WriteValidResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + UINT8 SendData[4] =3D { 0x00, 0x01, 0x02, 0x03 }; > + VOID *MockResponseResults =3D NULL; > + > + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_NODAT= A_RESPONSE_SIZE)); > + CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPO= NSE_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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +CommitValidResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + UINT8 SendData[4] =3D { 0x00, 0x01, 0x02, 0x03 }; > + VOID *MockResponseResults =3D NULL; > + > + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_NODAT= A_RESPONSE_SIZE)); > + CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPO= NSE_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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +CloseValidResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + VOID *MockResponseResults =3D NULL; > + > + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_NODAT= A_RESPONSE_SIZE)); > + CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPO= NSE_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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +DeleteValidResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + VOID *MockResponseResults =3D NULL; > + > + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_NODAT= A_RESPONSE_SIZE)); > + CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPO= NSE_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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +BlobStatValidResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + UINT16 *BlobState; > + UINT32 *Size; > + UINT8 *MetadataLength; > + UINT8 *Metadata; > + UINT8 *ExpectedMetadata; > + CHAR8 *BlobId; > + VOID *MockResponseResults =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, MetadataLeng= th, Metadata); > + > + UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS); > + UT_ASSERT_EQUAL (*BlobState, 1); > + UT_ASSERT_EQUAL (*Size, 0x05040302); > + UT_ASSERT_EQUAL (*MetadataLength, 4); > + UT_ASSERT_MEM_EQUAL (Metadata, ExpectedMetadata, 4); > + FreePool (MockResponseResults); > + FreePool (BlobState); > + FreePool (Size); > + FreePool (MetadataLength); > + FreePool (Metadata); > + return UNIT_TEST_PASSED; > +} > + > +/** > + @param[in] Context [Optional] An optional parameter that enables: > + 1) test-case reuse with varied parameters and > + 2) test-case re-entry for Target tests that nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +BlobStatInvalidBuffer ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + UINT8 *Metadata; > + EFI_STATUS Status; > + VOID *MockResponseResults =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, Metadat= 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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +SessionStatValidResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + UINT16 *BlobState; > + UINT32 *Size; > + UINT8 *MetadataLength; > + UINT8 *Metadata; > + UINT8 *ExpectedMetadata; > + VOID *MockResponseResults =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, 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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +SessionStatInvalidBuffer ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + UINT8 *Metadata; > + EFI_STATUS Status; > + VOID *MockResponseResults =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, Met= adata), 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 nee= d a > + reboot. This parameter is a VOID* and it is th= e > + responsibility of the test author to ensure tha= t the > + contents are well understood by all test cases = that may > + consume it. > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test > + case was successful. > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . > +**/ > +UNIT_TEST_STATUS > +EFIAPI > +WriteMetaValidResponse ( > + IN UNIT_TEST_CONTEXT Context > + ) > +{ > + EFI_STATUS Status; > + VOID *MockResponseResults =3D NULL; > + > + MockResponseResults =3D (UINT8 *)AllocateZeroPool (sizeof (VALID_NODAT= A_RESPONSE_SIZE)); > + CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPO= NSE_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 availabl= e 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, gEfiCall= erBaseName, UNIT_TEST_VERSION); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Failed to setup Test Framework. Exiting with s= tatus =3D %r\n", Status)); > + ASSERT (FALSE); > + return Status; > + } > + > + // > + // Populate the Unit Test Suite. > + // > + Status =3D CreateUnitTestSuite (&IpmiBlobTransfer, Framework, "IPMI Bl= ob Transfer Tests", "UnitTest.IpmiBlobTransferCB", NULL, NULL); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for IPMI Blob Tr= ansfer Tests\n")); > + Status =3D EFI_OUT_OF_RESOURCES; > + return Status; > + } > + > + // CalculateCrc16Ccitt > + Status =3D AddTestCase (IpmiBlobTransfer, "Test CRC Calculation", "Goo= dCrc", 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 compl= etion", "SendIpmiBadCompletion", SendIpmiBadCompletion, NULL, NULL, NULL); > + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfu= lly with no data", "SendIpmiNoDataResponse", SendIpmiNoDataResponse, NULL, = NULL, NULL); > + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfu= lly with bad OEN", "SendIpmiBadOenResponse", SendIpmiBadOenResponse, NULL, = NULL, NULL); > + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfu= lly with bad CRC", "SendIpmiBadCrcResponse", SendIpmiBadCrcResponse, NULL, = NULL, NULL); > + Status =3D AddTestCase (IpmiBlobTransfer, "Send IPMI returns with vali= d GetCount data", "SendIpmiValidCountResponse", SendIpmiValidCountResponse,= NULL, NULL, NULL); > + // IpmiBlobTransferGetCount > + Status =3D AddTestCase (IpmiBlobTransfer, "GetCount call with valid da= ta", "GetCountValidCountResponse", GetCountValidCountResponse, NULL, NULL, = NULL); > + // IpmiBlobTransferEnumerate > + Status =3D AddTestCase (IpmiBlobTransfer, "Enumerate call with valid d= ata", "EnumerateValidResponse", EnumerateValidResponse, NULL, NULL, NULL); > + Status =3D AddTestCase (IpmiBlobTransfer, "Enumerate call with invalid= output buffer", "EnumerateInvalidBuffer", EnumerateInvalidBuffer, NULL, NU= LL, NULL); > + // IpmiBlobTransferOpen > + Status =3D AddTestCase (IpmiBlobTransfer, "Open call with valid data",= "OpenValidResponse", OpenValidResponse, NULL, NULL, NULL); > + // IpmiBlobTransferRead > + Status =3D AddTestCase (IpmiBlobTransfer, "Read call with valid data",= "ReadValidResponse", ReadValidResponse, NULL, NULL, NULL); > + Status =3D AddTestCase (IpmiBlobTransfer, "Read call with invalid buff= er", "ReadInvalidBuffer", ReadInvalidBuffer, NULL, NULL, NULL); > + // IpmiBlobTransferWrite > + Status =3D AddTestCase (IpmiBlobTransfer, "Write call with valid data"= , "WriteValidResponse", WriteValidResponse, NULL, NULL, NULL); > + // IpmiBlobTransferCommit > + Status =3D AddTestCase (IpmiBlobTransfer, "Commit call with valid data= ", "CommitValidResponse", CommitValidResponse, NULL, NULL, NULL); > + // IpmiBlobTransferClose > + Status =3D AddTestCase (IpmiBlobTransfer, "Close call with valid data"= , "CloseValidResponse", CloseValidResponse, NULL, NULL, NULL); > + // IpmiBlobTransferDelete > + Status =3D AddTestCase (IpmiBlobTransfer, "Delete call with valid data= ", "DeleteValidResponse", DeleteValidResponse, NULL, NULL, NULL); > + // IpmiBlobTransferStat > + Status =3D AddTestCase (IpmiBlobTransfer, "Blob Stat call with valid d= ata", "BlobStatValidResponse", BlobStatValidResponse, NULL, NULL, NULL); > + Status =3D AddTestCase (IpmiBlobTransfer, "Blob Stat call with invalid= buffer", "BlobStatInvalidBuffer", BlobStatInvalidBuffer, NULL, NULL, NULL)= ; > + // IpmiBlobTransferSessionStat > + Status =3D AddTestCase (IpmiBlobTransfer, "Session Stat call with vali= d data", "SessionStatValidResponse", SessionStatValidResponse, NULL, NULL, = NULL); > + Status =3D AddTestCase (IpmiBlobTransfer, "Session Stat call with inva= lid buffer", "SessionStatInvalidBuffer", SessionStatInvalidBuffer, NULL, NU= LL, NULL); > + // IpmiBlobTransferWriteMeta > + Status =3D AddTestCase (IpmiBlobTransfer, "WriteMeta call with valid d= ata", "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/Read= me.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 I= nterface defined in OpenBMC > +https://github.com/openbmc/phosphor-ipmi-blobs > + > +## OpenBMC implements this interface as a protocol, allowing UEFI and BM= C 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 gEdkiiIpmiBlobTransferProtocol= Guid in its inf "Depex" section > +2) The module should list gEdkiiIpmiBlobTransferProtocolGuid in its inf = "Protocol" section > +3) The module's entry point should do a LocateProtocol on gEdkiiIpmiBlob= TransferProtocolGuid > + > +### 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 imp= lementation. > +Any changes to IpmiBlobTransferDxe should include proof of successful un= it tests. > + > +### Debugging > +To assist in debugging any issues, change BLOB_TRANSFER_DEBUG to desired= 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 (#118993): https://edk2.groups.io/g/devel/message/118993 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-