[edk2-devel] [edk2-platforms][PATCH 11/14] ManageabilityPkg/PldmProtocol: Add PLDM protocol

Chang, Abner via groups.io abner.chang=amd.com at groups.io
Mon Apr 3 15:04:56 UTC 2023


From: Abner Chang <abner.chang at amd.com>

PldmProtocol that transmits PLDM message
over manageability transport interface
library.

Signed-off-by: Abner Chang <abner.chang at amd.com>
Cc: Isaac Oram <isaac.w.oram at intel.com>
Cc: Abdul Lateef Attar <abdattar at amd.com>
Cc: Nickle Wang <nicklew at nvidia.com>
Cc: Igor Kulchytskyy <igork at ami.com>
---
 .../Include/Dsc/Manageability.dsc             |   1 +
 .../PldmProtocol/Dxe/PldmProtocolDxe.inf      |  50 ++
 .../PldmProtocol/Common/PldmProtocolCommon.h  | 109 +++++
 .../PldmProtocol/Common/PldmProtocolCommon.c  | 432 ++++++++++++++++++
 .../Universal/PldmProtocol/Dxe/PldmProtocol.c | 181 ++++++++
 5 files changed, 773 insertions(+)
 create mode 100644 Features/ManageabilityPkg/Universal/PldmProtocol/Dxe/PldmProtocolDxe.inf
 create mode 100644 Features/ManageabilityPkg/Universal/PldmProtocol/Common/PldmProtocolCommon.h
 create mode 100644 Features/ManageabilityPkg/Universal/PldmProtocol/Common/PldmProtocolCommon.c
 create mode 100644 Features/ManageabilityPkg/Universal/PldmProtocol/Dxe/PldmProtocol.c

diff --git a/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc b/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc
index bdb3bc8378..e7659f437a 100644
--- a/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc
+++ b/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc
@@ -25,6 +25,7 @@
 [Components.X64]
   ManageabilityPkg/Universal/IpmiProtocol/Dxe/IpmiProtocolDxe.inf
   ManageabilityPkg/Universal/IpmiProtocol/Smm/IpmiProtocolSmm.inf
+  ManageabilityPkg/Universal/PldmProtocol/Dxe/PldmProtocolDxe.inf
   ManageabilityPkg/Universal/PldmSmbiosTransferDxe/PldmSmbiosTransferDxe.inf
   ManageabilityPkg/Universal/MctpProtocol/Dxe/MctpProtocolDxe.inf
 
diff --git a/Features/ManageabilityPkg/Universal/PldmProtocol/Dxe/PldmProtocolDxe.inf b/Features/ManageabilityPkg/Universal/PldmProtocol/Dxe/PldmProtocolDxe.inf
new file mode 100644
index 0000000000..006f77b09a
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/PldmProtocol/Dxe/PldmProtocolDxe.inf
@@ -0,0 +1,50 @@
+## @file
+# EDKII PLDM Pootocol module INF file.
+#
+# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001d
+  BASE_NAME                      = PldmProtocolDxe
+  FILE_GUID                      = DA83FBDC-ECFE-4094-9ED3-EAFD1342333F
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = DxePldmProtocolEntry
+  UNLOAD_IMAGE                   = PldmProtocolUnloadImage
+
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+  PldmProtocol.c
+  ../Common/PldmProtocolCommon.c
+  ../Common/PldmProtocolCommon.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  ManageabilityPkg/ManageabilityPkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  DebugLib
+  ManageabilityTransportHelperLib
+  ManageabilityTransportLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+
+[Guids]
+  gManageabilityTransportMctpGuid
+
+[Protocols]
+  gEdkiiPldmProtocolGuid
+
+[FixedPcd]
+  gManageabilityPkgTokenSpaceGuid.PcdMctpSourceEndpointId
+  gManageabilityPkgTokenSpaceGuid.PcdMctpDestinationEndpointId
+
+[Depex]
+  TRUE
diff --git a/Features/ManageabilityPkg/Universal/PldmProtocol/Common/PldmProtocolCommon.h b/Features/ManageabilityPkg/Universal/PldmProtocol/Common/PldmProtocolCommon.h
new file mode 100644
index 0000000000..231d6e802e
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/PldmProtocol/Common/PldmProtocolCommon.h
@@ -0,0 +1,109 @@
+/** @file
+
+  EDKII PLDM Protocol common header file.
+
+  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef MANAGEABILITY_EDKII_PLDM_COMMON_H_
+#define MANAGEABILITY_EDKII_PLDM_COMMON_H_
+
+#include <IndustryStandard/Pldm.h>
+#include <Library/ManageabilityTransportLib.h>
+
+typedef struct {
+  UINT8     PldmType;
+  UINT8     PldmCommand;
+  UINT32    ResponseSize;
+} PLDM_MESSAGE_PACKET_MAPPING;
+
+/**
+  This functions setup the PLDM transport hardware information according
+  to the specification of transport token acquired from transport library.
+
+  @param[in]         TransportToken       The transport interface.
+  @param[out]        HardwareInformation  Pointer to receive the hardware information.
+
+  @retval EFI_SUCCESS            Hardware information is returned in HardwareInformation.
+                                 Caller must free the memory allocated for HardwareInformation
+                                 once it doesn't need it.
+  @retval EFI_UNSUPPORTED        No hardware information for the specification specified
+                                 in the transport token.
+**/
+EFI_STATUS
+SetupPldmTransportHardwareInformation (
+  IN   MANAGEABILITY_TRANSPORT_TOKEN                 *TransportToken,
+  OUT  MANAGEABILITY_TRANSPORT_HARDWARE_INFORMATION  *HardwareInformation
+  );
+
+/**
+  This functions setup the final header/body/trailer packets for
+  the acquired transport interface.
+
+  @param[in]         TransportToken     The transport interface.
+  @param[in]         PldmType           PLDM message type.
+  @param[in]         PldmCommand        PLDM command of this PLDM type.
+  @param[out]        PacketHeader       The pointer to receive header of request.
+  @param[out]        PacketHeaderSize   Packet header size in bytes.
+  @param[in, out]    PacketBody         The request body.
+                                        When IN, it is the caller's request body.
+                                        When OUT and NULL, the request body is not
+                                        changed.
+                                        Whee out and non-NULL, the request body is
+                                        changed to comfort the transport interface.
+  @param[in, out]    PacketBodySize     The request body size.
+                                        When IN and non-zero, it is the new data
+                                        length of request body.
+                                        When IN and zero, the request body is unchanged.
+  @param[out]        PacketTrailer      The pointer to receive trailer of request.
+  @param[out]        PacketTrailerSize  Packet trailer size in bytes.
+
+  @retval EFI_SUCCESS            Request packet is returned.
+  @retval EFI_UNSUPPORTED        Request packet is not returned because
+                                 the unsupported transport interface.
+**/
+EFI_STATUS
+SetupPldmRequestTransportPacket (
+  IN   MANAGEABILITY_TRANSPORT_TOKEN    *TransportToken,
+  IN   UINT8                            PldmType,
+  IN   UINT8                            PldmCommand,
+  OUT  MANAGEABILITY_TRANSPORT_HEADER   *PacketHeader,
+  OUT  UINT16                           *PacketHeaderSize,
+  IN OUT UINT8                          **PacketBody,
+  IN OUT UINT32                         *PacketBodySize,
+  OUT  MANAGEABILITY_TRANSPORT_TRAILER  *PacketTrailer,
+  OUT  UINT16                           *PacketTrailerSize
+  );
+
+/**
+  Common code to submit PLDM commands
+
+  @param[in]         TransportToken    Transport token.
+  @param[in]         PldmType          PLDM message type.
+  @param[in]         PldmCommand       PLDM command of this PLDM type.
+  @param[in]         RequestData       Command Request Data.
+  @param[in]         RequestDataSize   Size of Command Request Data.
+  @param[out]        ResponseData      Command Response Data. The completion code is the first byte of response data.
+  @param[in, out]    ResponseDataSize  Size of Command Response Data.
+
+  @retval EFI_SUCCESS            The command byte stream was successfully submit to the device and a response was successfully received.
+  @retval EFI_NOT_FOUND          The command was not successfully sent to the device or a response was not successfully received from the device.
+  @retval EFI_NOT_READY          PLDM transport interface is not ready for PLDM command access.
+  @retval EFI_DEVICE_ERROR       PLDM Device hardware error.
+  @retval EFI_TIMEOUT            The command time out.
+  @retval EFI_UNSUPPORTED        The command was not successfully sent to the device.
+  @retval EFI_OUT_OF_RESOURCES   The resource allocation is out of resource or data size error.
+**/
+EFI_STATUS
+CommonPldmSubmitCommand (
+  IN     MANAGEABILITY_TRANSPORT_TOKEN  *TransportToken,
+  IN     UINT8                          PldmType,
+  IN     UINT8                          PldmCommand,
+  IN     UINT8                          *RequestData OPTIONAL,
+  IN     UINT32                         RequestDataSize,
+  OUT    UINT8                          *ResponseData OPTIONAL,
+  IN OUT UINT32                         *ResponseDataSize
+  );
+
+#endif // MANAGEABILITY_EDKII_PLDM_COMMON_H_
diff --git a/Features/ManageabilityPkg/Universal/PldmProtocol/Common/PldmProtocolCommon.c b/Features/ManageabilityPkg/Universal/PldmProtocol/Common/PldmProtocolCommon.c
new file mode 100644
index 0000000000..fd3a4f57e7
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/PldmProtocol/Common/PldmProtocolCommon.c
@@ -0,0 +1,432 @@
+/** @file
+
+  IPMI Manageability Protocol common file.
+
+  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ManageabilityTransportLib.h>
+#include <Library/ManageabilityTransportHelperLib.h>
+#include <Library/ManageabilityTransportMctpLib.h>
+#include <IndustryStandard/Mctp.h>
+#include <IndustryStandard/Pldm.h>
+#include <IndustryStandard/PldmSmbiosTransfer.h>
+#include "PldmProtocolCommon.h"
+
+extern CHAR16  *mTransportName;
+extern UINT8   mPldmRequestInstanceId;
+
+PLDM_MESSAGE_PACKET_MAPPING  PldmMessagePacketMappingTable[] = {
+  { PLDM_TYPE_SMBIOS, PLDM_GET_SMBIOS_STRUCTURE_TABLE_METADATA_COMMAND_CODE, sizeof (PLDM_GET_SMBIOS_STRUCTURE_TABLE_METADATA_RESPONSE_FORMAT) },
+  { PLDM_TYPE_SMBIOS, PLDM_SET_SMBIOS_STRUCTURE_TABLE_METADATA_COMMAND_CODE, sizeof (PLDM_SET_SMBIOS_STRUCTURE_TABLE_METADATA_RESPONSE_FORMAT) },
+  { PLDM_TYPE_SMBIOS, PLDM_SET_SMBIOS_STRUCTURE_TABLE_COMMAND_CODE,          sizeof (PLDM_SET_SMBIOS_STRUCTURE_TABLE_REQUEST_FORMAT)           }
+};
+
+/**
+  This function returns the expected full size of PLDM response message.
+
+  @param[in]         PldmType        PLDM message type.
+  @param[in]         PldmCommand     PLDM command of this PLDM type.
+
+  @retval  Zero       No matched entry for this PldmType/PldmCommand.
+  @retval  None-zero  Size of full packet is returned.
+**/
+UINT32
+GetFullPacketResponseSize (
+  IN UINT8  PldmType,
+  IN UINT8  PldmCommand
+  )
+{
+  INT16                        Index;
+  PLDM_MESSAGE_PACKET_MAPPING  *ThisEntry;
+
+  ThisEntry = PldmMessagePacketMappingTable;
+  for (Index = 0; Index < (sizeof (PldmMessagePacketMappingTable)/ sizeof (PLDM_MESSAGE_PACKET_MAPPING)); Index++) {
+    if ((PldmType == ThisEntry->PldmType) && (PldmCommand == ThisEntry->PldmCommand)) {
+      return ThisEntry->ResponseSize;
+    }
+    ThisEntry++;
+  }
+
+  return 0;
+}
+
+/**
+  This functions setup the final header/body/trailer packets for
+  the acquired transport interface.
+
+  @param[in]         TransportToken     The transport interface.
+  @param[in]         PldmType           PLDM message type.
+  @param[in]         PldmCommand        PLDM command of this PLDM type.
+  @param[out]        PacketHeader       The pointer to receive header of request.
+  @param[out]        PacketHeaderSize   Packet header size in bytes.
+  @param[in, out]    PacketBody         The request body.
+                                        When IN, it is the caller's request body.
+                                        When OUT and NULL, the request body is not
+                                        changed.
+                                        Whee out and non-NULL, the request body is
+                                        changed to comfort the transport interface.
+  @param[in, out]    PacketBodySize     The request body size.
+                                        When IN and non-zero, it is the new data
+                                        length of request body.
+                                        When IN and zero, the request body is unchanged.
+  @param[out]        PacketTrailer      The pointer to receive trailer of request.
+  @param[out]        PacketTrailerSize  Packet trailer size in bytes.
+
+  @retval EFI_SUCCESS            Request packet is returned.
+  @retval EFI_UNSUPPORTED        Request packet is not returned because
+                                 the unsupported transport interface.
+**/
+EFI_STATUS
+SetupPldmRequestTransportPacket (
+  IN   MANAGEABILITY_TRANSPORT_TOKEN    *TransportToken,
+  IN   UINT8                            PldmType,
+  IN   UINT8                            PldmCommand,
+  OUT  MANAGEABILITY_TRANSPORT_HEADER   *PacketHeader,
+  OUT  UINT16                           *PacketHeaderSize,
+  IN OUT UINT8                          **PacketBody,
+  IN OUT UINT32                         *PacketBodySize,
+  OUT  MANAGEABILITY_TRANSPORT_TRAILER  *PacketTrailer,
+  OUT  UINT16                           *PacketTrailerSize
+  )
+{
+  MANAGEABILITY_MCTP_TRANSPORT_HEADER  *MctpHeader;
+  PLDM_REQUEST_HEADER                  *PldmRequestHeader;
+
+  if ((PacketHeader == NULL) || (PacketHeaderSize == NULL) ||
+      (PacketBody   == NULL) || (PacketBodySize == NULL) ||
+      (PacketTrailer == NULL) || (PacketTrailerSize == NULL)
+      )
+  {
+    DEBUG ((DEBUG_ERROR, "%a: One or more than one of the required parameters is NULL.\n", __FUNCTION__));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (CompareGuid (&gManageabilityTransportMctpGuid, TransportToken->Transport->ManageabilityTransportSpecification)) {
+    DEBUG ((DEBUG_INFO, "%a: Setup transport header for PLDM over MCTP.\n", __FUNCTION__));
+
+    // This is MCTP transport interface.
+    MctpHeader = AllocateZeroPool (sizeof (MANAGEABILITY_MCTP_TRANSPORT_HEADER));
+    if (MctpHeader == NULL) {
+      DEBUG ((DEBUG_ERROR, "%a: Not enough memory for MANAGEABILITY_MCTP_TRANSPORT_HEADER.\n", __FUNCTION__));
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    MctpHeader->SourceEndpointId             = PcdGet8 (PcdMctpSourceEndpointId);
+    MctpHeader->SourceEndpointId             = PcdGet8 (PcdMctpDestinationEndpointId);
+    MctpHeader->MessageHeader.IntegrityCheck = FALSE;
+    MctpHeader->MessageHeader.MessageType    = MCTP_MESSAGE_TYPE_PLDM;
+    *PacketHeader                            = (MANAGEABILITY_TRANSPORT_HEADER *)MctpHeader;
+    *PacketHeaderSize                        = sizeof (MANAGEABILITY_TRANSPORT_HEADER);
+    *PacketTrailer                           = NULL;
+    *PacketTrailerSize                       = 0;
+  } else {
+    DEBUG ((DEBUG_ERROR, "%a: No implementation of building up packet.\n", __FUNCTION__));
+    ASSERT (FALSE);
+  }
+
+  //
+  // Create header for the final request message.
+  //
+  PldmRequestHeader = (PLDM_REQUEST_HEADER *)AllocateZeroPool (sizeof (PLDM_REQUEST_HEADER) + *PacketBodySize);
+  if (PldmRequestHeader == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Not enough memory for final PLDM request message.\n", __FUNCTION__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  PldmRequestHeader->RequestBit          = PLDM_MESSAGE_HEADER_IS_REQUEST;
+  PldmRequestHeader->HeaderVersion       = PLDM_MESSAGE_HEADER_VERSION;
+  PldmRequestHeader->PldmType            = PldmType;
+  PldmRequestHeader->PldmTypeCommandCode = PldmCommand;
+  PldmRequestHeader->InstanceId          = mPldmRequestInstanceId;
+  if ((*PacketBody != NULL) && (*PacketBodySize != 0)) {
+    CopyMem (
+      (VOID *)((UINT8 *)PldmRequestHeader + sizeof (PLDM_REQUEST_HEADER)),
+      (VOID *)*PacketBody,
+      *PacketBodySize
+      );
+  }
+
+  *PacketBody     = (UINT8 *)PldmRequestHeader;
+  *PacketBodySize = sizeof (PLDM_REQUEST_HEADER) + *PacketBodySize;
+  return EFI_SUCCESS;
+}
+
+/**
+  Common code to submit PLDM commands
+
+  @param[in]         TransportToken    Transport token.
+  @param[in]         PldmType          PLDM message type.
+  @param[in]         PldmCommand       PLDM command of this PLDM type.
+  @param[in]         RequestData       Command Request Data.
+  @param[in]         RequestDataSize   Size of Command Request Data.
+  @param[out]        ResponseData      Command Response Data. The completion code is the first byte of response data.
+  @param[in, out]    ResponseDataSize  Size of Command Response Data.
+
+  @retval EFI_SUCCESS            The command byte stream was successfully submit to the device and a response was successfully received.
+  @retval EFI_NOT_FOUND          The command was not successfully sent to the device or a response was not successfully received from the device.
+  @retval EFI_NOT_READY          Ipmi Device is not ready for Ipmi command access.
+  @retval EFI_DEVICE_ERROR       Ipmi Device hardware error.
+  @retval EFI_TIMEOUT            The command time out.
+  @retval EFI_UNSUPPORTED        The command was not successfully sent to the device.
+  @retval EFI_OUT_OF_RESOURCES   The resource allocation is out of resource or data size error.
+**/
+EFI_STATUS
+CommonPldmSubmitCommand (
+  IN     MANAGEABILITY_TRANSPORT_TOKEN  *TransportToken,
+  IN     UINT8                          PldmType,
+  IN     UINT8                          PldmCommand,
+  IN     UINT8                          *RequestData OPTIONAL,
+  IN     UINT32                         RequestDataSize,
+  OUT    UINT8                          *ResponseData OPTIONAL,
+  IN OUT UINT32                         *ResponseDataSize
+  )
+{
+  EFI_STATUS                                 Status;
+  UINT8                                      *ThisRequestData;
+  UINT32                                     ThisRequestDataSize;
+  MANAGEABILITY_TRANSFER_TOKEN               TransferToken;
+  MANAGEABILITY_TRANSPORT_HEADER             PldmTransportHeader;
+  MANAGEABILITY_TRANSPORT_TRAILER            PldmTransportTrailer;
+  MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS  TransportAdditionalStatus;
+  UINT8                                      *FullPacketResponseData;
+  UINT32                                     FullPacketResponseDataSize;
+  PLDM_RESPONSE_HEADER                       *ResponseHeader;
+  UINT16                                     HeaderSize;
+  UINT16                                     TrailerSize;
+
+  if (TransportToken == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: No transport token for PLDM\n", __FUNCTION__));
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = TransportToken->Transport->Function.Version1_0->TransportStatus (
+                                                             TransportToken,
+                                                             &TransportAdditionalStatus
+                                                             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Transport %s for PLDM has problem - (%r)\n", __FUNCTION__, mTransportName, Status));
+    return Status;
+  }
+
+  ThisRequestData = RequestData;            // Save the original request data because the request data maybe modified
+                                            // in SetupIpmiRequestTransportPacket() according to transport interface.
+  ThisRequestDataSize = RequestDataSize;    // Save the original request data size because the request data size maybe modified
+                                            //  in SetupIpmiRequestTransportPacket() according to transport interface.
+  PldmTransportHeader  = NULL;
+  PldmTransportTrailer = NULL;
+  Status               = SetupPldmRequestTransportPacket (
+                           TransportToken,
+                           PldmType,
+                           PldmCommand,
+                           &PldmTransportHeader,
+                           &HeaderSize,
+                           &ThisRequestData,
+                           &ThisRequestDataSize,
+                           &PldmTransportTrailer,
+                           &TrailerSize
+                           );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Fail to build packets - (%r)\n", __FUNCTION__, Status));
+    return Status;
+  }
+
+  ZeroMem (&TransferToken, sizeof (MANAGEABILITY_TRANSFER_TOKEN));
+  TransferToken.TransmitHeader      = PldmTransportHeader;
+  TransferToken.TransmitHeaderSize  = HeaderSize;
+  TransferToken.TransmitTrailer     = PldmTransportTrailer;
+  TransferToken.TransmitTrailerSize = TrailerSize;
+
+  // Transmit packet.
+  if ((ThisRequestData == NULL) || (ThisRequestDataSize == 0)) {
+    // Transmit parameter were not changed by SetupIpmiRequestTransportPacket().
+    TransferToken.TransmitPackage.TransmitPayload    = RequestData;
+    TransferToken.TransmitPackage.TransmitSizeInByte = ThisRequestDataSize;
+  } else {
+    // Transmit parameter were changed by SetupIpmiRequestTransportPacket().
+    TransferToken.TransmitPackage.TransmitPayload    = ThisRequestData;
+    TransferToken.TransmitPackage.TransmitSizeInByte = ThisRequestDataSize;
+  }
+
+  TransferToken.TransmitPackage.TransmitTimeoutInMillisecond = MANAGEABILITY_TRANSPORT_NO_TIMEOUT;
+
+  // Set receive packet.
+  FullPacketResponseDataSize = GetFullPacketResponseSize (PldmType, PldmCommand);
+  if (FullPacketResponseDataSize == 0) {
+    DEBUG ((DEBUG_ERROR, "  No mapping entry in PldmMessagePacketMappingTable for PLDM Type:%d Command %d\n", PldmType, PldmCommand));
+    ASSERT (FALSE);
+  }
+
+  FullPacketResponseData = (UINT8 *)AllocateZeroPool (FullPacketResponseDataSize);
+  if (FullPacketResponseData == NULL) {
+    DEBUG ((DEBUG_ERROR, "  Not enough memory for FullPacketResponseDataSize.\n"));
+    Status = EFI_OUT_OF_RESOURCES;
+    goto ErrorExit2;
+  }
+
+  // Print out PLDM packet.
+  DEBUG ((
+    DEBUG_INFO,
+    "%a: Send PLDM type: 0x%x, Command: 0x%x: Request size: 0x%x, Response size: 0x%x\n",
+    __FUNCTION__,
+    PldmType,
+    PldmCommand,
+    TransferToken.TransmitPackage.TransmitSizeInByte,
+    FullPacketResponseDataSize
+    ));
+
+  HelperManageabilityDebugPrint (
+    (VOID *)TransferToken.TransmitPackage.TransmitPayload,
+    TransferToken.TransmitPackage.TransmitSizeInByte,
+    "PLDM full request payload.\n"
+    );
+
+  TransferToken.ReceivePackage.ReceiveBuffer                = FullPacketResponseData;
+  TransferToken.ReceivePackage.ReceiveSizeInByte            = FullPacketResponseDataSize;
+  TransferToken.ReceivePackage.TransmitTimeoutInMillisecond = MANAGEABILITY_TRANSPORT_NO_TIMEOUT;
+  TransportToken->Transport->Function.Version1_0->TransportTransmitReceive (
+                                                    TransportToken,
+                                                    &TransferToken
+                                                    );
+  //
+  // Check the response size.
+  if (TransferToken.ReceivePackage.ReceiveSizeInByte < sizeof (PLDM_RESPONSE_HEADER)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "Invalid response header size of PLDM Type %d Command %d, Returned size: %d Expected size: %d\n",
+      PldmType,
+      PldmCommand,
+      TransferToken.ReceivePackage.ReceiveSizeInByte,
+      FullPacketResponseDataSize
+      ));
+    if (ResponseDataSize != NULL) {
+      if (*ResponseDataSize > TransferToken.ReceivePackage.ReceiveSizeInByte) {
+        *ResponseDataSize = TransferToken.ReceivePackage.ReceiveSizeInByte;
+      }
+    }
+    if (ResponseData != NULL) {
+      CopyMem ((VOID *)ResponseData, (VOID *)FullPacketResponseData, *ResponseDataSize);
+    }
+
+    goto ErrorExit;
+  }
+
+  //
+  // Check the integrity of response. data.
+  ResponseHeader = (PLDM_RESPONSE_HEADER *)FullPacketResponseData;
+  if ((ResponseHeader->PldmHeader.DatagramBit != 0) ||
+      (ResponseHeader->PldmHeader.RequestBit != 0) ||
+      (ResponseHeader->PldmHeader.InstanceId != mPldmRequestInstanceId) ||
+      (ResponseHeader->PldmHeader.PldmType != PldmType) ||
+      (ResponseHeader->PldmHeader.PldmTypeCommandCode != PldmCommand))
+  {
+    DEBUG ((DEBUG_ERROR, "PLDM integrity check of response data is failed.\n"));
+    DEBUG ((DEBUG_ERROR, "    Request bit  = %d (Expected value: 0)\n"));
+    DEBUG ((DEBUG_ERROR, "    Datagram     = %d (Expected value: 0)\n"));
+    DEBUG ((DEBUG_ERROR, "    Instance ID  = %d (Expected value: %d)\n", ResponseHeader->PldmHeader.InstanceId, mPldmRequestInstanceId));
+    DEBUG ((DEBUG_ERROR, "    Pldm Type    = %d (Expected value: %d)\n", ResponseHeader->PldmHeader.PldmType, PldmType));
+    DEBUG ((DEBUG_ERROR, "    Pldm Command = %d (Expected value: %d)\n", ResponseHeader->PldmHeader.PldmTypeCommandCode, PldmCommand));
+    if (ResponseDataSize != NULL) {
+      if (*ResponseDataSize > TransferToken.ReceivePackage.ReceiveSizeInByte) {
+        *ResponseDataSize = TransferToken.ReceivePackage.ReceiveSizeInByte;
+      }
+    }
+    if (ResponseData != NULL) {
+      CopyMem ((VOID *)ResponseData, (VOID *)FullPacketResponseData, *ResponseDataSize);
+    }
+
+    goto ErrorExit;
+  }
+
+  //
+  // Check the response size
+  if (TransferToken.ReceivePackage.ReceiveSizeInByte != FullPacketResponseDataSize) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "The response size is incorrect: Response size %d (Expected %d), Completion code %d.\n",
+      TransferToken.ReceivePackage.ReceiveSizeInByte,
+      FullPacketResponseDataSize,
+      ResponseHeader->PldmCompletionCode
+      ));
+    if (ResponseDataSize != NULL) {
+      if (*ResponseDataSize > TransferToken.ReceivePackage.ReceiveSizeInByte) {
+        *ResponseDataSize = TransferToken.ReceivePackage.ReceiveSizeInByte;
+      }
+    }
+    if (ResponseData != NULL) {
+      CopyMem ((VOID *)ResponseData, (VOID *)FullPacketResponseData, *ResponseDataSize);
+    }
+
+    goto ErrorExit;
+  }
+
+  if (*ResponseDataSize != (TransferToken.ReceivePackage.ReceiveSizeInByte - sizeof (PLDM_RESPONSE_HEADER))) {
+    DEBUG ((DEBUG_ERROR, "  The size of response is not matched to RequestDataSize assigned by caller.\n"));
+    DEBUG ((
+      DEBUG_ERROR,
+      "Caller expects %d, the response size minus PLDM_RESPONSE_HEADER size is %d, Completion Code %d.\n",
+      *ResponseDataSize,
+      TransferToken.ReceivePackage.ReceiveSizeInByte - sizeof (PLDM_RESPONSE_HEADER),
+      ResponseHeader->PldmCompletionCode
+      ));
+    if (ResponseDataSize != NULL) {
+      if (*ResponseDataSize > TransferToken.ReceivePackage.ReceiveSizeInByte) {
+        *ResponseDataSize = TransferToken.ReceivePackage.ReceiveSizeInByte;
+      }
+    }
+    if (ResponseData != NULL) {
+      CopyMem ((VOID *)ResponseData, (VOID *)FullPacketResponseData, *ResponseDataSize);
+    }
+
+    goto ErrorExit;
+  }
+
+  // Print out PLDM full responses payload.
+  HelperManageabilityDebugPrint ((VOID *)FullPacketResponseData, FullPacketResponseDataSize, "PLDM full response payload\n");
+
+  // Copy response data (without header) to caller's buffer.
+  if ((ResponseData != NULL) && (*ResponseDataSize != 0)) {
+    *ResponseDataSize = FullPacketResponseDataSize - sizeof (PLDM_RESPONSE_HEADER);
+    CopyMem (
+      (VOID *)ResponseData,
+      (VOID *)(FullPacketResponseData + sizeof (PLDM_RESPONSE_HEADER)),
+      *ResponseDataSize
+      );
+  }
+
+  // Return transfer status.
+  //
+ErrorExit:
+  Status = TransferToken.TransferStatus;
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to send PLDM command over %s\n", __FUNCTION__, mTransportName));
+  }
+
+ErrorExit2:
+  if (PldmTransportHeader != NULL) {
+    FreePool ((VOID *)PldmTransportHeader);
+  }
+
+  if (PldmTransportTrailer != NULL) {
+    FreePool ((VOID *)PldmTransportTrailer);
+  }
+
+  if (ThisRequestData != NULL) {
+    FreePool ((VOID *)ThisRequestData);
+  }
+
+  if (FullPacketResponseData != NULL) {
+    FreePool ((VOID *)FullPacketResponseData);
+  }
+
+  //
+  // Update PLDM message instance ID.
+  mPldmRequestInstanceId++;
+  mPldmRequestInstanceId &= PLDM_MESSAGE_HEADER_INSTANCE_ID_MASK;
+  return Status;
+}
diff --git a/Features/ManageabilityPkg/Universal/PldmProtocol/Dxe/PldmProtocol.c b/Features/ManageabilityPkg/Universal/PldmProtocol/Dxe/PldmProtocol.c
new file mode 100644
index 0000000000..9904263cb0
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/PldmProtocol/Dxe/PldmProtocol.c
@@ -0,0 +1,181 @@
+/** @file
+  This file provides edk2 PLDM SMBIOS Transfer Protocol implementation.
+
+  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiDxe.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ManageabilityTransportLib.h>
+#include <Library/ManageabilityTransportHelperLib.h>
+#include <IndustryStandard/Pldm.h>
+#include <Protocol/PldmProtocol.h>
+
+#include "PldmProtocolCommon.h"
+
+MANAGEABILITY_TRANSPORT_TOKEN  *mTransportToken = NULL;
+CHAR16                         *mTransportName;
+UINT8                          mPldmRequestInstanceId;
+UINT32                         TransportMaximumPayload;
+
+/**
+  This service enables submitting commands via EDKII PLDM protocol.
+
+  @param[in]         This              EDKII_PLDM_PROTOCOL instance.
+  @param[in]         PldmType          PLDM message type.
+  @param[in]         Command           PLDM Command of PLDM message type.
+  @param[in]         RequestData       Command Request Data.
+  @param[in]         RequestDataSize   Size of Command Request Data.
+  @param[out]        ResponseData      Command Response Data. The completion code is the first byte of response data.
+  @param[in, out]    ResponseDataSize  Size of Command Response Data.
+
+  @retval EFI_SUCCESS            The command byte stream was successfully submit to the device and a response was successfully received.
+  @retval EFI_NOT_FOUND          The command was not successfully sent to the device or a response was not successfully received from the device.
+  @retval EFI_NOT_READY          PLDM transport interface is not ready for PLDM command access.
+  @retval EFI_DEVICE_ERROR       PLDM transport interface Device hardware error.
+  @retval EFI_TIMEOUT            The command time out.
+  @retval EFI_UNSUPPORTED        The command was not successfully sent to the device.
+  @retval EFI_OUT_OF_RESOURCES   The resource allocation is out of resource or data size error.
+  @retval EFI_INVALID_PARAMETER  Both RequestData and ResponseData are NULL
+**/
+EFI_STATUS
+EFIAPI
+PldmSubmitCommand (
+  IN     EDKII_PLDM_PROTOCOL  *This,
+  IN     UINT8                PldmType,
+  IN     UINT8                Command,
+  IN     UINT8                *RequestData,
+  IN     UINT32               RequestDataSize,
+  OUT    UINT8                *ResponseData,
+  IN OUT UINT32               *ResponseDataSize
+  )
+{
+  EFI_STATUS  Status;
+
+  if ((RequestData == NULL) && (ResponseData == NULL)) {
+    DEBUG ((DEBUG_ERROR, "%a: Both RequestData and ResponseData are NULL\n", __FUNCTION__));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = CommonPldmSubmitCommand (
+             mTransportToken,
+             PldmType,
+             Command,
+             RequestData,
+             RequestDataSize,
+             ResponseData,
+             ResponseDataSize
+             );
+  return Status;
+}
+
+EDKII_PLDM_PROTOCOL_V1_0  mPldmProtocolV10 = {
+  PldmSubmitCommand
+};
+
+EDKII_PLDM_PROTOCOL  mPldmProtocol;
+
+/**
+  The entry point of the PLDM SMBIOS Transfer DXE driver.
+
+  @param[in] ImageHandle - Handle of this driver image
+  @param[in] SystemTable - Table containing standard EFI services
+
+  @retval EFI_SUCCESS    - PLDM Protocol is installed successfully.
+  @retval Otherwise      - Other errors.
+**/
+EFI_STATUS
+EFIAPI
+DxePldmProtocolEntry (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS                                    Status;
+  EFI_HANDLE                                    Handle;
+  MANAGEABILITY_TRANSPORT_CAPABILITY            TransportCapability;
+  MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS     TransportAdditionalStatus;
+  MANAGEABILITY_TRANSPORT_HARDWARE_INFORMATION  HardwareInfo;
+
+  Status = HelperAcquireManageabilityTransport (
+             &gManageabilityProtocolPldmGuid,
+             &mTransportToken
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to acquire transport interface for PLDM protocol - %r\n", __FUNCTION__, Status));
+    return Status;
+  }
+
+  Status = GetTransportCapability (mTransportToken, &TransportCapability);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to GetTransportCapability().\n", __FUNCTION__));
+    return Status;
+  }
+
+  TransportMaximumPayload = MANAGEABILITY_TRANSPORT_PAYLOAD_SIZE_FROM_CAPABILITY (TransportCapability);
+  if (TransportMaximumPayload == (1 << MANAGEABILITY_TRANSPORT_CAPABILITY_MAXIMUM_PAYLOAD_NOT_AVAILABLE)) {
+    DEBUG ((DEBUG_INFO, "%a: Transport interface maximum payload is undefined.\n", __FUNCTION__));
+  } else {
+    TransportMaximumPayload -= 1;
+    DEBUG ((DEBUG_INFO, "%a: Transport interface for PLDM protocol has maximum payload 0x%x.\n", __FUNCTION__, TransportMaximumPayload));
+  }
+
+  mTransportName = HelperManageabilitySpecName (mTransportToken->Transport->ManageabilityTransportSpecification);
+  DEBUG ((DEBUG_ERROR, "%a: PLDM protocol over %s.\n", __FUNCTION__, mTransportName));
+
+  // Initial transport interface with the hardware information assigned.
+  HardwareInfo.Pointer = NULL;
+  Status               = HelperInitManageabilityTransport (
+                           mTransportToken,
+                           HardwareInfo,
+                           &TransportAdditionalStatus
+                           );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  mPldmRequestInstanceId             = 0;
+  mPldmProtocol.ProtocolVersion      = EDKII_PLDM_PROTOCOL_VERSION;
+  mPldmProtocol.Functions.Version1_0 = &mPldmProtocolV10;
+  Handle                             = NULL;
+  Status                             = gBS->InstallProtocolInterface (
+                                              &Handle,
+                                              &gEdkiiPldmProtocolGuid,
+                                              EFI_NATIVE_INTERFACE,
+                                              (VOID **)&mPldmProtocol
+                                              );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to install EDKII PLDM protocol - %r\n", __FUNCTION__, Status));
+  }
+
+  return Status;
+}
+
+/**
+  This is the unload handler of PLDM SMBIOS Transfer DXE driver.
+
+  @param[in] ImageHandle           The driver's image handle.
+
+  @retval    EFI_SUCCESS           The image is unloaded.
+  @retval    Others                Failed to unload the image.
+
+**/
+EFI_STATUS
+EFIAPI
+PldmProtocolUnloadImage (
+  IN EFI_HANDLE  ImageHandle
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+  if (mTransportToken != NULL) {
+    Status = ReleaseTransportSession (mTransportToken);
+  }
+
+  return Status;
+}
-- 
2.37.1.windows.1



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




More information about the edk2-devel-archive mailing list