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
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
|
/** @file
Manageability Transport Helper Library
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/ManageabilityTransportHelperLib.h>
//
// BaseManageabilityTransportHelper is used by PEI, DXE and SMM.
// Make sure the global variables added here should be unchangeable.
//
MANAGEABILITY_SPECIFICATION_NAME ManageabilitySpecNameTable[] = {
{ &gManageabilityTransportKcsGuid, L"KCS" },
{ &gManageabilityTransportSmbusI2cGuid, L"SMBUS I2C" },
{ &gManageabilityTransportPciVdmGuid, L"PCI VDM" },
{ &gManageabilityTransportSerialGuid, L"SERIAL" },
{ &gManageabilityTransportMctpGuid, L"MCTP" },
{ &gManageabilityProtocolIpmiGuid, L"IPMI" },
{ &gManageabilityProtocolMctpGuid, L"MCTP" },
{ &gManageabilityProtocolPldmGuid, L"PLDM" }
};
UINT16 mManageabilitySpecNum = sizeof (ManageabilitySpecNameTable)/ sizeof (MANAGEABILITY_SPECIFICATION_NAME);
/**
Helper function returns the human readable name of Manageability specification.
@param[in] SpecificationGuid The Manageability specification GUID
@retval !NULL Human readable name is returned;
@retval NULL No string found, the given Manageability specification is
not supported.
**/
CHAR16 *
EFIAPI
HelperManageabilitySpecName (
IN EFI_GUID *SpecificationGuid
)
{
UINT16 Index;
MANAGEABILITY_SPECIFICATION_NAME *ThisSpec;
if (mManageabilitySpecNum == 0) {
return NULL;
}
if ((SpecificationGuid == NULL) || IsZeroGuid (SpecificationGuid)) {
DEBUG ((DEBUG_ERROR, "%a: Improper input GUIDs, could be NULL or zero GUID.\n", __func__));
return NULL;
}
ThisSpec = ManageabilitySpecNameTable;
for (Index = 0; Index < mManageabilitySpecNum; Index++) {
if (CompareGuid (
SpecificationGuid,
ThisSpec->SpecificationGuid
))
{
return ThisSpec->SpecificationName;
}
ThisSpec++;
}
return NULL;
}
/**
Helper function to check if the Manageability specification is supported
by transport interface or not.
@param[in] TransportGuid GUID of the transport interface.
@param[in] SupportedManageabilityProtocolArray The Manageability protocols supported
by the transport interface.
@param[in] NumberOfSupportedProtocolInArray Number of protocols in the array.
@param[in] ManageabilityProtocolToCheck The Manageability specification to check.
@retval EFI_SUCCESS Token is created successfully.
@retval EFI_INVALID_PARAMETER Either NumberOfSupportedProtocolInArray = 0 or
SupportedManageabilityProtocolArray = NULL.
@retval EFI_UNSUPPORTED Out of resource to create a new transport session.
Otherwise Other errors.
**/
EFI_STATUS
EFIAPI
HelperManageabilityCheckSupportedSpec (
IN EFI_GUID *TransportGuid,
IN EFI_GUID **SupportedManageabilityProtocolArray,
IN UINT8 NumberOfSupportedProtocolInArray,
IN EFI_GUID *ManageabilityProtocolToCheck
)
{
UINT16 Index;
EFI_GUID **ThisSpecGuid;
if ((NumberOfSupportedProtocolInArray == 0) || (SupportedManageabilityProtocolArray == NULL)) {
return EFI_INVALID_PARAMETER;
}
if ((TransportGuid == NULL) ||
IsZeroGuid (TransportGuid) ||
(ManageabilityProtocolToCheck == NULL) ||
IsZeroGuid (ManageabilityProtocolToCheck)
)
{
DEBUG ((DEBUG_ERROR, "%a: Improper input GUIDs, could be NULL or zero GUID.\n", __func__));
return EFI_INVALID_PARAMETER;
}
ThisSpecGuid = SupportedManageabilityProtocolArray;
for (Index = 0; Index < NumberOfSupportedProtocolInArray; Index++) {
if (CompareGuid (
*ThisSpecGuid,
ManageabilityProtocolToCheck
))
{
DEBUG ((
DEBUG_MANAGEABILITY_INFO,
"%a: Transport interface %s supports %s manageability specification.\n",
__func__,
HelperManageabilitySpecName (TransportGuid),
HelperManageabilitySpecName (ManageabilityProtocolToCheck)
));
return EFI_SUCCESS;
}
ThisSpecGuid++;
}
DEBUG ((
DEBUG_ERROR,
"%a: Transport interface %s doesn't support %s manageability specification.\n",
__func__,
HelperManageabilitySpecName (TransportGuid),
HelperManageabilitySpecName (ManageabilityProtocolToCheck)
));
return EFI_UNSUPPORTED;
}
/**
Helper function to acquire the Manageability transport token.
@param[in] ManageabilityProtocolSpec The Manageability protocol specification.
@param[out] TransportToken Pointer to receive Manageability transport
token.
@retval EFI_SUCCESS Token is created successfully.
@retval EFI_OUT_OF_RESOURCES Out of resource to create a new transport session.
@retval EFI_UNSUPPORTED Token is created successfully.
@retval EFI_INVALID_PARAMETER Input parameter is not valid.
Otherwise Other errors.
**/
EFI_STATUS
EFIAPI
HelperAcquireManageabilityTransport (
IN EFI_GUID *ManageabilityProtocolSpec,
OUT MANAGEABILITY_TRANSPORT_TOKEN **TransportToken
)
{
EFI_STATUS Status;
CHAR16 *ManageabilityProtocolName;
CHAR16 *ManageabilityTransportName;
DEBUG ((DEBUG_MANAGEABILITY_INFO, "%a: Entry\n", __func__));
if ((TransportToken == NULL) || (ManageabilityProtocolSpec == NULL)) {
DEBUG ((DEBUG_ERROR, "%a: One of the required input parameters is NULL.\n", __func__));
return EFI_INVALID_PARAMETER;
}
*TransportToken = NULL;
ManageabilityProtocolName = HelperManageabilitySpecName (ManageabilityProtocolSpec);
if (ManageabilityProtocolName == NULL) {
DEBUG ((DEBUG_ERROR, "%a: Unsupported Manageability Protocol Specification.\n", __func__));
return EFI_UNSUPPORTED;
}
DEBUG ((DEBUG_MANAGEABILITY_INFO, " Manageability protocol %s is going to acquire transport interface token...\n", ManageabilityProtocolName));
Status = AcquireTransportSession (ManageabilityProtocolSpec, TransportToken);
if (Status == EFI_UNSUPPORTED) {
DEBUG ((DEBUG_ERROR, "%a: No supported transport interface for %s packet.\n", __func__, ManageabilityProtocolName));
return Status;
}
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"%a: Fail to acquire Manageability transport token for %s (%r).\n",
__func__,
ManageabilityProtocolName,
Status
));
return Status;
}
ManageabilityTransportName = HelperManageabilitySpecName ((*TransportToken)->Transport->ManageabilityTransportSpecification);
if (ManageabilityTransportName == NULL) {
DEBUG ((DEBUG_ERROR, "%a: Unsupported Manageability Transport Interface Specification\n", __func__));
return EFI_UNSUPPORTED;
}
DEBUG ((DEBUG_MANAGEABILITY_INFO, "%a: This is the transfer session for %s over %s\n", __func__, ManageabilityProtocolName, ManageabilityTransportName));
return Status;
}
/**
Helper function to initial the transport interface.
@param[in] TransportToken Transport token.
@param[in] HardwareInfo Optional hardware information of transport interface.
@param[out] TransportAdditionalStatus Transport additional status.
@retval EFI_SUCCESS Transport interface is initiated successfully.
@retval EFI_DEVICE_ERROR The transport interface has problems
@retval EFI_INVALID_PARAMETER INput parameter is not valid.
Otherwise Other errors.
**/
EFI_STATUS
EFIAPI
HelperInitManageabilityTransport (
IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken,
IN MANAGEABILITY_TRANSPORT_HARDWARE_INFORMATION HardwareInfo OPTIONAL,
OUT MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS *TransportAdditionalStatus OPTIONAL
)
{
EFI_STATUS Status;
if (TransportToken == NULL) {
DEBUG ((DEBUG_ERROR, "%a: TransportToken is invalid.\n", __func__));
return EFI_INVALID_PARAMETER;
}
// Initial transport interface.
Status = TransportToken->Transport->Function.Version1_0->TransportInit (TransportToken, HardwareInfo);
if ((Status != EFI_SUCCESS) && (Status != EFI_ALREADY_STARTED)) {
if (Status == EFI_DEVICE_ERROR) {
// Try to reset the transport and initialize it again.
Status = TransportToken->Transport->Function.Version1_0->TransportReset (
TransportToken,
TransportAdditionalStatus
);
if (EFI_ERROR (Status)) {
if (Status == EFI_UNSUPPORTED) {
DEBUG ((DEBUG_ERROR, "%a: Transport interface doesn't have reset capability.\n", __func__));
} else {
DEBUG ((DEBUG_ERROR, "%a: Fail to reset transport interface (%r).\n", __func__, Status));
}
Status = EFI_DEVICE_ERROR;
} else {
Status = TransportToken->Transport->Function.Version1_0->TransportInit (TransportToken, HardwareInfo);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Transport interface is not able to use after the reset (%r).\n", __func__, Status));
}
}
} else {
DEBUG ((DEBUG_ERROR, "%a: Transport interface is not able to use (%r).\n", __func__, Status));
}
}
return Status;
}
/**
This function generates CRC8 with given polynomial.
@param[in] Polynomial Polynomial in 8-bit.
@param[in] CrcInitialValue CRC initial value.
@param[in] BufferStart Pointer to buffer starts the CRC calculation.
@param[in] BufferSize Size of buffer.
@retval UINT8 CRC value.
**/
UINT8
EFIAPI
HelperManageabilityGenerateCrc8 (
IN UINT8 Polynomial,
IN UINT8 CrcInitialValue,
IN UINT8 *BufferStart,
IN UINT32 BufferSize
)
{
UINT8 BitIndex;
UINT32 BufferIndex;
BufferIndex = 0;
while (BufferIndex < BufferSize) {
CrcInitialValue = CrcInitialValue ^ *(BufferStart + BufferIndex);
BufferIndex++;
for (BitIndex = 0; BitIndex < 8; BitIndex++) {
if ((CrcInitialValue & 0x80) != 0) {
CrcInitialValue = (CrcInitialValue << 1) ^ Polynomial;
} else {
CrcInitialValue <<= 1;
}
}
}
return CrcInitialValue;
}
/**
This function splits payload into multiple packages according to
the given transport interface Maximum Transfer Unit (MTU).
@param[in] PreambleSize The additional data size precedes
each package.
@param[in] PostambleSize The additional data size succeeds
each package.
@param[in] Payload Pointer to payload.
@param[in] PayloadSize Payload size in byte.
@param[in] MaximumTransferUnit MTU of transport interface.
@param[out] MultiplePackages Pointer to receive
MANAGEABILITY_TRANSMISSION_MULTI_PACKAGES
structure. Caller has to free the memory
allocated for MANAGEABILITY_TRANSMISSION_MULTI_PACKAGES.
@retval EFI_SUCCESS MANAGEABILITY_TRANSMISSION_MULTI_PACKAGES structure
is returned successfully.
@retval EFI_OUT_OF_RESOURCE Not enough resource to create
MANAGEABILITY_TRANSMISSION_MULTI_PACKAGES structure.
**/
EFI_STATUS
EFIAPI
HelperManageabilitySplitPayload (
IN UINT16 PreambleSize,
IN UINT16 PostambleSize,
IN UINT8 *Payload,
IN UINT32 PayloadSize,
IN UINT32 MaximumTransferUnit,
OUT MANAGEABILITY_TRANSMISSION_MULTI_PACKAGES **MultiplePackages
)
{
UINT16 NumberOfPackages;
UINT16 IndexOfPackage;
UINT32 PackagePayloadSize;
UINT32 TotalPayloadRemaining;
MANAGEABILITY_TRANSMISSION_MULTI_PACKAGES *ThisMultiplePackages;
MANAGEABILITY_TRANSMISSION_PACKAGE_ATTR *ThisPackage;
if ((INT16)(MaximumTransferUnit - PreambleSize - PostambleSize) < 0) {
DEBUG ((
DEBUG_ERROR,
"%a: (Preamble 0x%x + PostambleSize 0x%x) is greater than MaximumTransferUnit 0x%x.\n",
__func__,
PreambleSize,
PostambleSize,
MaximumTransferUnit
));
return EFI_INVALID_PARAMETER;
}
PackagePayloadSize = MaximumTransferUnit -PreambleSize - PostambleSize;
NumberOfPackages = (UINT16)((PayloadSize + (PackagePayloadSize - 1)) / PackagePayloadSize);
ThisMultiplePackages = (MANAGEABILITY_TRANSMISSION_MULTI_PACKAGES *)AllocateZeroPool (
sizeof (MANAGEABILITY_TRANSMISSION_MULTI_PACKAGES) +
sizeof (MANAGEABILITY_TRANSMISSION_PACKAGE_ATTR) * NumberOfPackages
);
if (ThisMultiplePackages == NULL) {
DEBUG ((DEBUG_ERROR, "%a: Not enough memory for MANAGEABILITY_TRANSMISSION_MULTI_PACKAGES\n", __func__));
return EFI_OUT_OF_RESOURCES;
}
ThisMultiplePackages->NumberOfPackages = NumberOfPackages;
ThisPackage = (MANAGEABILITY_TRANSMISSION_PACKAGE_ATTR *)(ThisMultiplePackages + 1);
TotalPayloadRemaining = PayloadSize;
for (IndexOfPackage = 0; IndexOfPackage < NumberOfPackages; IndexOfPackage++) {
ThisPackage->PayloadPointer = Payload + (IndexOfPackage * PackagePayloadSize);
ThisPackage->PayloadSize = MIN (TotalPayloadRemaining, PackagePayloadSize);
TotalPayloadRemaining -= ThisPackage->PayloadSize;
ThisPackage++;
}
if (TotalPayloadRemaining != 0) {
DEBUG ((DEBUG_ERROR, "%a: Error processing multiple packages (TotalPayloadRemaining != 0)\n", __func__));
FreePool (ThisMultiplePackages);
return EFI_INVALID_PARAMETER;
}
*MultiplePackages = ThisMultiplePackages;
return EFI_SUCCESS;
}
/**
Print out manageability transmit payload to the debug output device.
@param[in] Payload Payload to print.
@param[in] PayloadSize Payload size.
**/
VOID
EFIAPI
HelperManageabilityPayLoadDebugPrint (
IN VOID *Payload,
IN UINT32 PayloadSize
)
{
UINTN Block;
UINTN BlockSize;
UINTN RowSize;
UINTN RemainingBytes;
UINTN BytesPrinted;
RemainingBytes = PayloadSize;
BlockSize = 256;
RowSize = 16;
for (Block = 0, BytesPrinted = 0; RemainingBytes > 0;) {
UINTN BlockBase;
UINTN Row;
UINTN RowsToPrint;
UINTN Column;
Block = BytesPrinted / BlockSize;
BlockBase = Block * BlockSize;
if (BytesPrinted % BlockSize == 0) {
DEBUG ((DEBUG_MANAGEABILITY_INFO, "======== Manageability Payload %04xH - %04xH =========\n", BlockBase, BlockBase + MIN (RemainingBytes, BlockSize) - 1));
DEBUG ((DEBUG_MANAGEABILITY_INFO, " "));
for (Column = 0; Column < RowSize; Column++) {
DEBUG ((DEBUG_MANAGEABILITY_INFO, "%02x ", Column));
}
DEBUG ((DEBUG_MANAGEABILITY_INFO, "\n -----------------------------------------------\n"));
}
if (RemainingBytes >= BlockSize) {
RowsToPrint = BlockSize / RowSize;
} else {
RowsToPrint = RemainingBytes / RowSize + 1;
}
for (Row = 0; Row < RowsToPrint; Row++) {
DEBUG ((DEBUG_MANAGEABILITY_INFO, "%04x | ", BlockBase + Row * RowSize));
for (Column = 0; Column < MIN (RemainingBytes, RowSize); Column++) {
DEBUG ((DEBUG_MANAGEABILITY_INFO, "%02x ", *((UINT8 *)Payload + BlockBase + Row * RowSize + Column)));
}
RemainingBytes -= Column;
BytesPrinted += Column;
DEBUG ((DEBUG_MANAGEABILITY_INFO, "\n"));
}
DEBUG ((DEBUG_MANAGEABILITY_INFO, "\n"));
}
}
/**
Prints a debug message and manageability payload to the debug output device.
@param[in] Payload Payload to print.
@param[in] PayloadSize Payload size.
@param[in] Format The format string for the debug message to print.
@param[in] ... The variable argument list whose contents are accessed
based on the format string specified by Format.
**/
VOID
EFIAPI
HelperManageabilityDebugPrint (
IN VOID *Payload,
IN UINT32 PayloadSize,
IN CONST CHAR8 *Format,
...
)
{
VA_LIST Marker;
VA_START (Marker, Format);
DEBUG ((DEBUG_MANAGEABILITY_INFO, "Manageability Transmission: "));
DebugVPrint ((UINTN)DEBUG_MANAGEABILITY_INFO, Format, Marker);
HelperManageabilityPayLoadDebugPrint (Payload, PayloadSize);
VA_END (Marker);
}
|