1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
|
/** @file
IPMI Manageability Protocol common file.
Copyright (C) 2023-2026 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;
/**
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[in] SourceId PLDM source terminus ID.
@param[in] DestinationId PLDM destination terminus ID.
@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,
IN UINT8 SourceId,
IN UINT8 DestinationId,
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", __func__));
return EFI_INVALID_PARAMETER;
}
if (CompareGuid (&gManageabilityTransportMctpGuid, TransportToken->Transport->ManageabilityTransportSpecification)) {
DEBUG ((DEBUG_MANAGEABILITY_INFO, "%a: Setup transport header for PLDM over MCTP.\n", __func__));
// 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", __func__));
return EFI_OUT_OF_RESOURCES;
}
MctpHeader->SourceEndpointId = SourceId;
MctpHeader->DestinationEndpointId = DestinationId;
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", __func__));
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", __func__));
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] PldmTerminusSourceId PLDM source terminus ID.
@param[in] PldmTerminusDestinationId PLDM destination terminus ID.
@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 PldmTerminusSourceId,
IN UINT8 PldmTerminusDestinationId,
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", __func__));
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", __func__, 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,
PldmTerminusSourceId,
PldmTerminusDestinationId,
&PldmTransportHeader,
&HeaderSize,
&ThisRequestData,
&ThisRequestDataSize,
&PldmTransportTrailer,
&TrailerSize
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Fail to build packets - (%r)\n", __func__, 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.
if ((ResponseData == NULL) && (*ResponseDataSize == 0)) {
FullPacketResponseDataSize = sizeof (PLDM_RESPONSE_HEADER);
} else {
FullPacketResponseDataSize = *ResponseDataSize + sizeof (PLDM_RESPONSE_HEADER);
}
FullPacketResponseData = (UINT8 *)AllocateZeroPool (FullPacketResponseDataSize);
if (FullPacketResponseData == NULL) {
DEBUG ((DEBUG_ERROR, " Not enough memory for FullPacketResponseDataSize.\n"));
Status = EFI_OUT_OF_RESOURCES;
goto ErrorExit;
}
// 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",
__func__,
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
));
HelperManageabilityDebugPrint ((VOID *)FullPacketResponseData, TransferToken.ReceivePackage.ReceiveSizeInByte, "Failed response payload\n");
Status = EFI_DEVICE_ERROR;
goto ErrorExit;
}
//
// Check the integrity of response. data.
//
ResponseHeader = (PLDM_RESPONSE_HEADER *)FullPacketResponseData;
if ((ResponseHeader->PldmHeader.DatagramBit != (!PLDM_MESSAGE_HEADER_IS_DATAGRAM)) ||
(ResponseHeader->PldmHeader.RequestBit != PLDM_MESSAGE_HEADER_IS_RESPONSE) ||
(ResponseHeader->PldmHeader.InstanceId != mPldmRequestInstanceId) ||
(ResponseHeader->PldmHeader.PldmType != PldmType) ||
(ResponseHeader->PldmHeader.PldmTypeCommandCode != PldmCommand) ||
(ResponseHeader->PldmCompletionCode != PLDM_COMPLETION_CODE_SUCCESS))
{
DEBUG ((DEBUG_ERROR, "PLDM integrity check of response data is failed.\n"));
DEBUG ((DEBUG_ERROR, " Datagram = %d (Expected value: %d)\n", ResponseHeader->PldmHeader.DatagramBit, (!PLDM_MESSAGE_HEADER_IS_DATAGRAM)));
DEBUG ((DEBUG_ERROR, " Request bit = %d (Expected value: %d)\n", ResponseHeader->PldmHeader.RequestBit, PLDM_MESSAGE_HEADER_IS_RESPONSE));
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));
DEBUG ((DEBUG_ERROR, " Pldm Completion Code = 0x%x\n", ResponseHeader->PldmCompletionCode));
HelperManageabilityDebugPrint ((VOID *)FullPacketResponseData, TransferToken.ReceivePackage.ReceiveSizeInByte, "Failed response payload\n");
Status = EFI_DEVICE_ERROR;
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
));
HelperManageabilityDebugPrint ((VOID *)FullPacketResponseData, TransferToken.ReceivePackage.ReceiveSizeInByte, "Failed response payload\n");
Status = EFI_DEVICE_ERROR;
goto ErrorExit;
}
if (*ResponseDataSize < GET_PLDM_MESSAGE_PAYLOAD_SIZE (TransferToken.ReceivePackage.ReceiveSizeInByte)) {
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,
GET_PLDM_MESSAGE_PAYLOAD_SIZE (TransferToken.ReceivePackage.ReceiveSizeInByte),
ResponseHeader->PldmCompletionCode
));
HelperManageabilityDebugPrint ((VOID *)FullPacketResponseData, GET_PLDM_MESSAGE_PAYLOAD_SIZE (TransferToken.ReceivePackage.ReceiveSizeInByte), "Failed response payload\n");
Status = EFI_DEVICE_ERROR;
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 = GET_PLDM_MESSAGE_PAYLOAD_SIZE (TransferToken.ReceivePackage.ReceiveSizeInByte);
CopyMem (
(VOID *)ResponseData,
GET_PLDM_MESSAGE_PAYLOAD_PTR (FullPacketResponseData),
*ResponseDataSize
);
}
// Return transfer status.
//
Status = TransferToken.TransferStatus;
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Failed to send PLDM command over %s\n", __func__, mTransportName));
}
ErrorExit:
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;
}
|