From: Abner Chang <abner.ch...@amd.com> PldmProtocol that transmits PLDM message over manageability transport interface library.
Signed-off-by: Abner Chang <abner.ch...@amd.com> Cc: Isaac Oram <isaac.w.o...@intel.com> Cc: Abdul Lateef Attar <abdat...@amd.com> Cc: Nickle Wang <nick...@nvidia.com> Cc: Igor Kulchytskyy <ig...@ami.com> --- .../Include/Dsc/Manageability.dsc | 1 + .../PldmProtocol/Dxe/PldmProtocolDxe.inf | 50 ++ .../PldmProtocol/Common/PldmProtocolCommon.h | 109 +++++ .../PldmProtocol/Common/PldmProtocolCommon.c | 437 ++++++++++++++++++ .../Universal/PldmProtocol/Dxe/PldmProtocol.c | 181 ++++++++ 5 files changed, 778 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 17f067c6d0..0fab562844 100644 --- a/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc +++ b/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc @@ -32,6 +32,7 @@ [Components.X64] 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..bb4d3f61a0 --- /dev/null +++ b/Features/ManageabilityPkg/Universal/PldmProtocol/Common/PldmProtocolCommon.c @@ -0,0 +1,437 @@ +/** @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_MANAGEABILITY_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_MANAGEABILITY_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_MANAGEABILITY_INFO, + "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..bb34fec16e --- /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_MANAGEABILITY_INFO, "%a: Transport interface maximum payload is undefined.\n", __FUNCTION__)); + } else { + TransportMaximumPayload -= 1; + DEBUG ((DEBUG_MANAGEABILITY_INFO, "%a: Transport interface for PLDM protocol has maximum payload 0x%x.\n", __FUNCTION__, TransportMaximumPayload)); + } + + mTransportName = HelperManageabilitySpecName (mTransportToken->Transport->ManageabilityTransportSpecification); + DEBUG ((DEBUG_MANAGEABILITY_INFO, "%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 (#103146): https://edk2.groups.io/g/devel/message/103146 Mute This Topic: https://groups.io/mt/98339123/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-