]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Universal / SmbiosDxe / SmbiosDxe.c
CommitLineData
310b04e6 1/** @file\r
d1102dba 2 This code produces the Smbios protocol. It also responsible for constructing\r
310b04e6 3 SMBIOS table into system table.\r
d1102dba 4\r
70e8c9c3 5Copyright (c) 2009 - 2021, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
310b04e6 7\r
8**/\r
9\r
10#include "SmbiosDxe.h"\r
11\r
12//\r
13// Module Global:\r
14// Since this driver will only ever produce one instance of the\r
15// protocol you are not required to dynamically allocate the PrivateData.\r
16//\r
1436aea4 17SMBIOS_INSTANCE mPrivateData;\r
310b04e6 18\r
1436aea4
MK
19UINTN mPreAllocatedPages = 0;\r
20UINTN mPre64BitAllocatedPages = 0;\r
4233bf70 21\r
310b04e6 22//\r
23// Chassis for SMBIOS entry point structure that is to be installed into EFI system config table.\r
24//\r
1436aea4
MK
25SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure = NULL;\r
26SMBIOS_TABLE_ENTRY_POINT EntryPointStructureData = {\r
310b04e6 27 //\r
28 // AnchorString\r
29 //\r
30 {\r
31 0x5f,\r
32 0x53,\r
33 0x4d,\r
34 0x5f\r
35 },\r
36 //\r
37 // EntryPointStructureChecksum,TO BE FILLED\r
38 //\r
39 0,\r
40 //\r
41 // EntryPointStructure Length\r
42 //\r
43 0x1f,\r
44 //\r
9f7d5b46 45 // MajorVersion\r
310b04e6 46 //\r
fe781940 47 0,\r
310b04e6 48 //\r
9f7d5b46 49 // MinorVersion\r
310b04e6 50 //\r
fe781940 51 0,\r
310b04e6 52 //\r
53 // MaxStructureSize, TO BE FILLED\r
54 //\r
55 0,\r
56 //\r
57 // EntryPointRevision\r
58 //\r
59 0,\r
60 //\r
61 // FormattedArea\r
62 //\r
63 {\r
64 0,\r
65 0,\r
66 0,\r
67 0,\r
68 0\r
69 },\r
70 //\r
71 // IntermediateAnchorString\r
72 //\r
73 {\r
74 0x5f,\r
75 0x44,\r
76 0x4d,\r
77 0x49,\r
78 0x5f\r
79 },\r
80 //\r
81 // IntermediateChecksum, TO BE FILLED\r
82 //\r
83 0,\r
84 //\r
f49146e8 85 // TableLength, TO BE FILLED\r
310b04e6 86 //\r
87 0,\r
88 //\r
f49146e8 89 // TableAddress, TO BE FILLED\r
310b04e6 90 //\r
91 0,\r
92 //\r
93 // NumberOfSmbiosStructures, TO BE FILLED\r
94 //\r
95 0,\r
96 //\r
97 // SmbiosBcdRevision\r
98 //\r
fe781940 99 0\r
310b04e6 100};\r
101\r
1436aea4
MK
102SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios30EntryPointStructure = NULL;\r
103SMBIOS_TABLE_3_0_ENTRY_POINT Smbios30EntryPointStructureData = {\r
e63f3308
EL
104 //\r
105 // AnchorString _SM3_\r
106 //\r
107 {\r
108 0x5f,\r
109 0x53,\r
110 0x4d,\r
111 0x33,\r
112 0x5f,\r
113 },\r
114 //\r
115 // EntryPointStructureChecksum,TO BE FILLED\r
116 //\r
117 0,\r
118 //\r
119 // EntryPointLength\r
120 //\r
121 0x18,\r
122 //\r
123 // MajorVersion\r
124 //\r
125 0,\r
126 //\r
127 // MinorVersion\r
128 //\r
129 0,\r
130 //\r
131 // DocRev\r
132 //\r
133 0,\r
134 //\r
135 // EntryPointRevision\r
136 //\r
137 0x01,\r
138 //\r
139 // Reserved\r
140 //\r
141 0,\r
142 //\r
143 // TableMaximumSize,TO BE FILLED\r
144 //\r
145 0,\r
146 //\r
147 // TableAddress,TO BE FILLED\r
148 //\r
149 0\r
150};\r
70e8c9c3 151\r
1436aea4
MK
152IS_SMBIOS_TABLE_VALID_ENTRY mIsSmbiosTableValid[] = {\r
153 { &gUniversalPayloadSmbios3TableGuid, IsValidSmbios30Table },\r
154 { &gUniversalPayloadSmbiosTableGuid, IsValidSmbios20Table }\r
70e8c9c3
ZL
155};\r
156\r
310b04e6 157/**\r
158\r
0ddd8553 159 Get the full size of SMBIOS structure including optional strings that follow the formatted structure.\r
310b04e6 160\r
afe3969c 161 @param This The EFI_SMBIOS_PROTOCOL instance.\r
0ddd8553 162 @param Head Pointer to the beginning of SMBIOS structure.\r
310b04e6 163 @param Size The returned size.\r
164 @param NumberOfStrings The returned number of optional strings that follow the formatted structure.\r
165\r
166 @retval EFI_SUCCESS Size retured in Size.\r
0ddd8553 167 @retval EFI_INVALID_PARAMETER Input SMBIOS structure mal-formed or Size is NULL.\r
d1102dba 168\r
310b04e6 169**/\r
170EFI_STATUS\r
171EFIAPI\r
172GetSmbiosStructureSize (\r
1436aea4
MK
173 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
174 IN EFI_SMBIOS_TABLE_HEADER *Head,\r
175 OUT UINTN *Size,\r
176 OUT UINTN *NumberOfStrings\r
310b04e6 177 )\r
178{\r
179 UINTN FullSize;\r
2d97e71f 180 UINTN StrLen;\r
4233bf70 181 UINTN MaxLen;\r
1436aea4 182 INT8 *CharInStr;\r
d1102dba 183\r
1436aea4 184 if ((Size == NULL) || (NumberOfStrings == NULL)) {\r
310b04e6 185 return EFI_INVALID_PARAMETER;\r
186 }\r
187\r
1436aea4
MK
188 FullSize = Head->Length;\r
189 CharInStr = (INT8 *)Head + Head->Length;\r
190 *Size = FullSize;\r
310b04e6 191 *NumberOfStrings = 0;\r
1436aea4 192 StrLen = 0;\r
310b04e6 193 //\r
194 // look for the two consecutive zeros, check the string limit by the way.\r
195 //\r
d1102dba 196 while (*CharInStr != 0 || *(CharInStr+1) != 0) {\r
310b04e6 197 if (*CharInStr == 0) {\r
310b04e6 198 *Size += 1;\r
199 CharInStr++;\r
200 }\r
201\r
1436aea4 202 if ((This->MajorVersion < 2) || ((This->MajorVersion == 2) && (This->MinorVersion < 7))) {\r
4233bf70 203 MaxLen = SMBIOS_STRING_MAX_LENGTH;\r
e63f3308 204 } else if (This->MajorVersion < 3) {\r
afe3969c 205 //\r
4233bf70
SZ
206 // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.\r
207 // However, the length of the entire structure table (including all strings) must be reported\r
208 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,\r
209 // which is a WORD field limited to 65,535 bytes.\r
afe3969c 210 //\r
4233bf70 211 MaxLen = SMBIOS_TABLE_MAX_LENGTH;\r
e63f3308
EL
212 } else {\r
213 //\r
214 // SMBIOS 3.0 defines the Structure table maximum size as DWORD field limited to 0xFFFFFFFF bytes.\r
215 // Locate the end of string as long as possible.\r
216 //\r
217 MaxLen = SMBIOS_3_0_TABLE_MAX_LENGTH;\r
4233bf70
SZ
218 }\r
219\r
1436aea4 220 for (StrLen = 0; StrLen < MaxLen; StrLen++) {\r
4233bf70
SZ
221 if (*(CharInStr+StrLen) == 0) {\r
222 break;\r
afe3969c 223 }\r
310b04e6 224 }\r
afe3969c 225\r
4233bf70
SZ
226 if (StrLen == MaxLen) {\r
227 return EFI_INVALID_PARAMETER;\r
228 }\r
229\r
310b04e6 230 //\r
231 // forward the pointer\r
232 //\r
1436aea4
MK
233 CharInStr += StrLen;\r
234 *Size += StrLen;\r
310b04e6 235 *NumberOfStrings += 1;\r
236 }\r
f8ee20c9 237\r
310b04e6 238 //\r
239 // count ending two zeros.\r
240 //\r
241 *Size += 2;\r
afe3969c 242 return EFI_SUCCESS;\r
310b04e6 243}\r
244\r
245/**\r
246\r
247 Determin whether an SmbiosHandle has already in use.\r
248\r
0ddd8553 249 @param Head Pointer to the beginning of SMBIOS structure.\r
310b04e6 250 @param Handle A unique handle will be assigned to the SMBIOS record.\r
251\r
252 @retval TRUE Smbios handle already in use.\r
253 @retval FALSE Smbios handle is NOT used.\r
d1102dba 254\r
310b04e6 255**/\r
256BOOLEAN\r
257EFIAPI\r
258CheckSmbiosHandleExistance (\r
1436aea4
MK
259 IN LIST_ENTRY *Head,\r
260 IN EFI_SMBIOS_HANDLE Handle\r
310b04e6 261 )\r
262{\r
1436aea4
MK
263 LIST_ENTRY *Link;\r
264 SMBIOS_HANDLE_ENTRY *HandleEntry;\r
d1102dba 265\r
310b04e6 266 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
1436aea4 267 HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK (Link);\r
310b04e6 268 if (HandleEntry->SmbiosHandle == Handle) {\r
269 return TRUE;\r
270 }\r
271 }\r
272\r
273 return FALSE;\r
274}\r
275\r
276/**\r
277\r
278 Get the max SmbiosHandle that could be use.\r
279\r
280 @param This The EFI_SMBIOS_PROTOCOL instance.\r
281 @param MaxHandle The max handle that could be assigned to the SMBIOS record.\r
282\r
283**/\r
284VOID\r
285EFIAPI\r
286GetMaxSmbiosHandle (\r
1436aea4
MK
287 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
288 IN OUT EFI_SMBIOS_HANDLE *MaxHandle\r
d1102dba 289 )\r
310b04e6 290{\r
1436aea4 291 if ((This->MajorVersion == 2) && (This->MinorVersion == 0)) {\r
310b04e6 292 *MaxHandle = 0xFFFE;\r
293 } else {\r
294 *MaxHandle = 0xFEFF;\r
295 }\r
296}\r
297\r
298/**\r
299\r
300 Get an SmbiosHandle that could use.\r
301\r
302 @param This The EFI_SMBIOS_PROTOCOL instance.\r
303 @param SmbiosHandle A unique handle will be assigned to the SMBIOS record.\r
304\r
305 @retval EFI_SUCCESS Smbios handle got.\r
306 @retval EFI_OUT_OF_RESOURCES Smbios handle is NOT available.\r
d1102dba 307\r
310b04e6 308**/\r
309EFI_STATUS\r
310EFIAPI\r
311GetAvailableSmbiosHandle (\r
1436aea4
MK
312 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
313 IN OUT EFI_SMBIOS_HANDLE *Handle\r
310b04e6 314 )\r
315{\r
1436aea4
MK
316 LIST_ENTRY *Head;\r
317 SMBIOS_INSTANCE *Private;\r
318 EFI_SMBIOS_HANDLE MaxSmbiosHandle;\r
319 EFI_SMBIOS_HANDLE AvailableHandle;\r
310b04e6 320\r
1436aea4 321 GetMaxSmbiosHandle (This, &MaxSmbiosHandle);\r
310b04e6 322\r
323 Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
1436aea4 324 Head = &Private->AllocatedHandleListHead;\r
4659816a 325 for (AvailableHandle = 0; AvailableHandle < MaxSmbiosHandle; AvailableHandle++) {\r
1436aea4 326 if (!CheckSmbiosHandleExistance (Head, AvailableHandle)) {\r
310b04e6 327 *Handle = AvailableHandle;\r
328 return EFI_SUCCESS;\r
329 }\r
330 }\r
331\r
332 return EFI_OUT_OF_RESOURCES;\r
333}\r
334\r
310b04e6 335/**\r
336 Add an SMBIOS record.\r
337\r
338 @param This The EFI_SMBIOS_PROTOCOL instance.\r
339 @param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL\r
340 means no handle.\r
4659816a
SZ
341 @param SmbiosHandle On entry, the handle of the SMBIOS record to add. If FFFEh, then a unique handle\r
342 will be assigned to the SMBIOS record. If the SMBIOS handle is already in use,\r
310b04e6 343 EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated.\r
344 @param Record The data for the fixed portion of the SMBIOS record. The format of the record is\r
d1102dba
LG
345 determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined\r
346 by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or\r
310b04e6 347 a set of null terminated strings and a null.\r
348\r
349 @retval EFI_SUCCESS Record was added.\r
350 @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources.\r
351 @retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use.\r
352\r
353**/\r
354EFI_STATUS\r
355EFIAPI\r
356SmbiosAdd (\r
357 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
e3917e22 358 IN EFI_HANDLE ProducerHandle OPTIONAL,\r
310b04e6 359 IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,\r
360 IN EFI_SMBIOS_TABLE_HEADER *Record\r
361 )\r
362{\r
1436aea4
MK
363 VOID *Raw;\r
364 UINTN TotalSize;\r
365 UINTN RecordSize;\r
366 UINTN StructureSize;\r
367 UINTN NumberOfStrings;\r
368 EFI_STATUS Status;\r
369 LIST_ENTRY *Head;\r
370 SMBIOS_INSTANCE *Private;\r
371 EFI_SMBIOS_ENTRY *SmbiosEntry;\r
372 EFI_SMBIOS_HANDLE MaxSmbiosHandle;\r
373 SMBIOS_HANDLE_ENTRY *HandleEntry;\r
374 EFI_SMBIOS_RECORD_HEADER *InternalRecord;\r
375 BOOLEAN Smbios32BitTable;\r
376 BOOLEAN Smbios64BitTable;\r
d1102dba 377\r
310b04e6 378 if (SmbiosHandle == NULL) {\r
379 return EFI_INVALID_PARAMETER;\r
380 }\r
d1102dba 381\r
310b04e6 382 Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
383 //\r
384 // Check whether SmbiosHandle is already in use\r
385 //\r
386 Head = &Private->AllocatedHandleListHead;\r
1436aea4 387 if ((*SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED) && CheckSmbiosHandleExistance (Head, *SmbiosHandle)) {\r
310b04e6 388 return EFI_ALREADY_STARTED;\r
389 }\r
390\r
391 //\r
4659816a 392 // when SmbiosHandle is 0xFFFE, an available handle will be assigned\r
310b04e6 393 //\r
4659816a 394 if (*SmbiosHandle == SMBIOS_HANDLE_PI_RESERVED) {\r
1436aea4
MK
395 Status = GetAvailableSmbiosHandle (This, SmbiosHandle);\r
396 if (EFI_ERROR (Status)) {\r
310b04e6 397 return Status;\r
398 }\r
399 } else {\r
400 //\r
401 // Check this handle validity\r
402 //\r
1436aea4 403 GetMaxSmbiosHandle (This, &MaxSmbiosHandle);\r
310b04e6 404 if (*SmbiosHandle > MaxSmbiosHandle) {\r
405 return EFI_INVALID_PARAMETER;\r
406 }\r
407 }\r
408\r
409 //\r
410 // Calculate record size and string number\r
411 //\r
1436aea4
MK
412 Status = GetSmbiosStructureSize (This, Record, &StructureSize, &NumberOfStrings);\r
413 if (EFI_ERROR (Status)) {\r
310b04e6 414 return Status;\r
415 }\r
416\r
e63f3308
EL
417 Smbios32BitTable = FALSE;\r
418 Smbios64BitTable = FALSE;\r
d1102dba 419 if ((This->MajorVersion < 0x3) ||\r
1436aea4
MK
420 ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0)))\r
421 {\r
4233bf70 422 //\r
e63f3308 423 // For SMBIOS 32-bit table, the length of the entire structure table (including all strings) must be reported\r
4233bf70 424 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,\r
e63f3308
EL
425 // which is a WORD field limited to 65,535 bytes. So the max size of 32-bit table should not exceed 65,535 bytes.\r
426 //\r
d1102dba 427 if ((EntryPointStructure != NULL) &&\r
1436aea4
MK
428 (EntryPointStructure->TableLength + StructureSize > SMBIOS_TABLE_MAX_LENGTH))\r
429 {\r
87000d77 430 DEBUG ((DEBUG_INFO, "SmbiosAdd: Total length exceeds max 32-bit table length with type = %d size = 0x%x\n", Record->Type, StructureSize));\r
e63f3308
EL
431 } else {\r
432 Smbios32BitTable = TRUE;\r
87000d77 433 DEBUG ((DEBUG_INFO, "SmbiosAdd: Smbios type %d with size 0x%x is added to 32-bit table\n", Record->Type, StructureSize));\r
e63f3308
EL
434 }\r
435 }\r
d1102dba 436\r
e63f3308
EL
437 //\r
438 // For SMBIOS 3.0, Structure table maximum size in Entry Point structure is DWORD field limited to 0xFFFFFFFF bytes.\r
439 //\r
440 if ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) {\r
441 //\r
442 // For SMBIOS 64-bit table, Structure table maximum size in SMBIOS 3.0 (64-bit) Entry Point\r
443 // is a DWORD field limited to 0xFFFFFFFF bytes. So the max size of 64-bit table should not exceed 0xFFFFFFFF bytes.\r
444 //\r
d1102dba 445 if ((Smbios30EntryPointStructure != NULL) &&\r
1436aea4
MK
446 (Smbios30EntryPointStructure->TableMaximumSize + StructureSize > SMBIOS_3_0_TABLE_MAX_LENGTH))\r
447 {\r
87000d77 448 DEBUG ((DEBUG_INFO, "SmbiosAdd: Total length exceeds max 64-bit table length with type = %d size = 0x%x\n", Record->Type, StructureSize));\r
e63f3308 449 } else {\r
87000d77 450 DEBUG ((DEBUG_INFO, "SmbiosAdd: Smbios type %d with size 0x%x is added to 64-bit table\n", Record->Type, StructureSize));\r
e63f3308
EL
451 Smbios64BitTable = TRUE;\r
452 }\r
453 }\r
454\r
455 if ((!Smbios32BitTable) && (!Smbios64BitTable)) {\r
456 //\r
457 // If both 32-bit and 64-bit table are not updated, quit\r
4233bf70
SZ
458 //\r
459 return EFI_OUT_OF_RESOURCES;\r
460 }\r
461\r
310b04e6 462 //\r
463 // Enter into critical section\r
d1102dba 464 //\r
310b04e6 465 Status = EfiAcquireLockOrFail (&Private->DataLock);\r
466 if (EFI_ERROR (Status)) {\r
467 return Status;\r
468 }\r
d1102dba 469\r
1436aea4
MK
470 RecordSize = sizeof (EFI_SMBIOS_RECORD_HEADER) + StructureSize;\r
471 TotalSize = sizeof (EFI_SMBIOS_ENTRY) + RecordSize;\r
310b04e6 472\r
473 //\r
474 // Allocate internal buffer\r
475 //\r
0d34b1cf 476 SmbiosEntry = AllocateZeroPool (TotalSize);\r
310b04e6 477 if (SmbiosEntry == NULL) {\r
478 EfiReleaseLock (&Private->DataLock);\r
479 return EFI_OUT_OF_RESOURCES;\r
480 }\r
1436aea4
MK
481\r
482 HandleEntry = AllocateZeroPool (sizeof (SMBIOS_HANDLE_ENTRY));\r
310b04e6 483 if (HandleEntry == NULL) {\r
484 EfiReleaseLock (&Private->DataLock);\r
485 return EFI_OUT_OF_RESOURCES;\r
486 }\r
487\r
488 //\r
489 // Build Handle Entry and insert into linked list\r
490 //\r
1436aea4
MK
491 HandleEntry->Signature = SMBIOS_HANDLE_ENTRY_SIGNATURE;\r
492 HandleEntry->SmbiosHandle = *SmbiosHandle;\r
493 InsertTailList (&Private->AllocatedHandleListHead, &HandleEntry->Link);\r
310b04e6 494\r
1436aea4
MK
495 InternalRecord = (EFI_SMBIOS_RECORD_HEADER *)(SmbiosEntry + 1);\r
496 Raw = (VOID *)(InternalRecord + 1);\r
310b04e6 497\r
498 //\r
499 // Build internal record Header\r
500 //\r
1436aea4
MK
501 InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;\r
502 InternalRecord->HeaderSize = (UINT16)sizeof (EFI_SMBIOS_RECORD_HEADER);\r
503 InternalRecord->RecordSize = RecordSize;\r
504 InternalRecord->ProducerHandle = ProducerHandle;\r
310b04e6 505 InternalRecord->NumberOfStrings = NumberOfStrings;\r
506 //\r
507 // Insert record into the internal linked list\r
508 //\r
1436aea4
MK
509 SmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;\r
510 SmbiosEntry->RecordHeader = InternalRecord;\r
511 SmbiosEntry->RecordSize = TotalSize;\r
e63f3308
EL
512 SmbiosEntry->Smbios32BitTable = Smbios32BitTable;\r
513 SmbiosEntry->Smbios64BitTable = Smbios64BitTable;\r
310b04e6 514 InsertTailList (&Private->DataListHead, &SmbiosEntry->Link);\r
515\r
516 CopyMem (Raw, Record, StructureSize);\r
1436aea4 517 ((EFI_SMBIOS_TABLE_HEADER *)Raw)->Handle = *SmbiosHandle;\r
310b04e6 518\r
0ddd8553 519 //\r
520 // Some UEFI drivers (such as network) need some information in SMBIOS table.\r
521 // Here we create SMBIOS table and publish it in\r
522 // configuration table, so other UEFI drivers can get SMBIOS table from\r
523 // configuration table without depending on PI SMBIOS protocol.\r
524 //\r
e63f3308 525 SmbiosTableConstruction (Smbios32BitTable, Smbios64BitTable);\r
d1102dba 526\r
310b04e6 527 //\r
528 // Leave critical section\r
529 //\r
530 EfiReleaseLock (&Private->DataLock);\r
531 return EFI_SUCCESS;\r
532}\r
533\r
534/**\r
535 Update the string associated with an existing SMBIOS record.\r
536\r
537 @param This The EFI_SMBIOS_PROTOCOL instance.\r
538 @param SmbiosHandle SMBIOS Handle of structure that will have its string updated.\r
539 @param StringNumber The non-zero string number of the string to update\r
540 @param String Update the StringNumber string with String.\r
541\r
542 @retval EFI_SUCCESS SmbiosHandle had its StringNumber String updated.\r
543 @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist.\r
4659816a 544 @retval EFI_UNSUPPORTED String was not added because it is longer than the SMBIOS Table supports.\r
310b04e6 545 @retval EFI_NOT_FOUND The StringNumber.is not valid for this SMBIOS record.\r
546\r
547**/\r
548EFI_STATUS\r
549EFIAPI\r
550SmbiosUpdateString (\r
1436aea4
MK
551 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
552 IN EFI_SMBIOS_HANDLE *SmbiosHandle,\r
553 IN UINTN *StringNumber,\r
554 IN CHAR8 *String\r
310b04e6 555 )\r
556{\r
557 UINTN InputStrLen;\r
558 UINTN TargetStrLen;\r
559 UINTN StrIndex;\r
560 UINTN TargetStrOffset;\r
561 UINTN NewEntrySize;\r
562 CHAR8 *StrStart;\r
563 VOID *Raw;\r
564 LIST_ENTRY *Link;\r
565 LIST_ENTRY *Head;\r
566 EFI_STATUS Status;\r
567 SMBIOS_INSTANCE *Private;\r
568 EFI_SMBIOS_ENTRY *SmbiosEntry;\r
569 EFI_SMBIOS_ENTRY *ResizedSmbiosEntry;\r
570 EFI_SMBIOS_HANDLE MaxSmbiosHandle;\r
571 EFI_SMBIOS_TABLE_HEADER *Record;\r
572 EFI_SMBIOS_RECORD_HEADER *InternalRecord;\r
d1102dba 573\r
310b04e6 574 //\r
575 // Check args validity\r
576 //\r
1436aea4 577 GetMaxSmbiosHandle (This, &MaxSmbiosHandle);\r
310b04e6 578\r
579 if (*SmbiosHandle > MaxSmbiosHandle) {\r
580 return EFI_INVALID_PARAMETER;\r
581 }\r
582\r
583 if (String == NULL) {\r
584 return EFI_ABORTED;\r
585 }\r
586\r
587 if (*StringNumber == 0) {\r
588 return EFI_NOT_FOUND;\r
589 }\r
590\r
1436aea4 591 InputStrLen = AsciiStrLen (String);\r
afe3969c 592\r
1436aea4 593 if ((This->MajorVersion < 2) || ((This->MajorVersion == 2) && (This->MinorVersion < 7))) {\r
afe3969c
SZ
594 if (InputStrLen > SMBIOS_STRING_MAX_LENGTH) {\r
595 return EFI_UNSUPPORTED;\r
596 }\r
e63f3308 597 } else if (This->MajorVersion < 3) {\r
4233bf70
SZ
598 //\r
599 // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.\r
d1102dba 600 // However, the length of the entire structure table (including all strings) must be reported\r
4233bf70
SZ
601 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,\r
602 // which is a WORD field limited to 65,535 bytes.\r
603 //\r
604 if (InputStrLen > SMBIOS_TABLE_MAX_LENGTH) {\r
605 return EFI_UNSUPPORTED;\r
606 }\r
e63f3308
EL
607 } else {\r
608 if (InputStrLen > SMBIOS_3_0_TABLE_MAX_LENGTH) {\r
609 //\r
610 // SMBIOS 3.0 defines the Structure table maximum size as DWORD field limited to 0xFFFFFFFF bytes.\r
611 // The input string length should not exceed 0xFFFFFFFF bytes.\r
d1102dba 612 //\r
e63f3308
EL
613 return EFI_UNSUPPORTED;\r
614 }\r
310b04e6 615 }\r
616\r
617 Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
618 //\r
619 // Enter into critical section\r
d1102dba 620 //\r
310b04e6 621 Status = EfiAcquireLockOrFail (&Private->DataLock);\r
622 if (EFI_ERROR (Status)) {\r
623 return Status;\r
624 }\r
625\r
626 Head = &Private->DataListHead;\r
627 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
1436aea4
MK
628 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK (Link);\r
629 Record = (EFI_SMBIOS_TABLE_HEADER *)(SmbiosEntry->RecordHeader + 1);\r
310b04e6 630\r
afe3969c 631 if (Record->Handle == *SmbiosHandle) {\r
310b04e6 632 //\r
0ddd8553 633 // Find out the specified SMBIOS record\r
310b04e6 634 //\r
635 if (*StringNumber > SmbiosEntry->RecordHeader->NumberOfStrings) {\r
636 EfiReleaseLock (&Private->DataLock);\r
637 return EFI_NOT_FOUND;\r
638 }\r
1436aea4 639\r
310b04e6 640 //\r
641 // Point to unformed string section\r
642 //\r
1436aea4 643 StrStart = (CHAR8 *)Record + Record->Length;\r
d1102dba 644\r
310b04e6 645 for (StrIndex = 1, TargetStrOffset = 0; StrIndex < *StringNumber; StrStart++, TargetStrOffset++) {\r
646 //\r
647 // A string ends in 00h\r
648 //\r
649 if (*StrStart == 0) {\r
650 StrIndex++;\r
651 }\r
d1102dba 652\r
310b04e6 653 //\r
654 // String section ends in double-null (0000h)\r
655 //\r
1436aea4 656 if ((*StrStart == 0) && (*(StrStart + 1) == 0)) {\r
310b04e6 657 EfiReleaseLock (&Private->DataLock);\r
658 return EFI_NOT_FOUND;\r
d1102dba 659 }\r
310b04e6 660 }\r
661\r
f8ee20c9 662 if (*StrStart == 0) {\r
afe3969c
SZ
663 StrStart++;\r
664 TargetStrOffset++;\r
f8ee20c9 665 }\r
d1102dba 666\r
310b04e6 667 //\r
668 // Now we get the string target\r
669 //\r
1436aea4 670 TargetStrLen = AsciiStrLen (StrStart);\r
310b04e6 671 if (InputStrLen == TargetStrLen) {\r
1436aea4 672 AsciiStrCpyS (StrStart, TargetStrLen + 1, String);\r
0ddd8553 673 //\r
674 // Some UEFI drivers (such as network) need some information in SMBIOS table.\r
675 // Here we create SMBIOS table and publish it in\r
676 // configuration table, so other UEFI drivers can get SMBIOS table from\r
677 // configuration table without depending on PI SMBIOS protocol.\r
678 //\r
e63f3308 679 SmbiosTableConstruction (SmbiosEntry->Smbios32BitTable, SmbiosEntry->Smbios64BitTable);\r
310b04e6 680 EfiReleaseLock (&Private->DataLock);\r
681 return EFI_SUCCESS;\r
682 }\r
d1102dba 683\r
e63f3308
EL
684 SmbiosEntry->Smbios32BitTable = FALSE;\r
685 SmbiosEntry->Smbios64BitTable = FALSE;\r
d1102dba 686 if ((This->MajorVersion < 0x3) ||\r
1436aea4
MK
687 ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0)))\r
688 {\r
e63f3308
EL
689 //\r
690 // 32-bit table is produced, check the valid length.\r
691 //\r
d1102dba 692 if ((EntryPointStructure != NULL) &&\r
1436aea4
MK
693 (EntryPointStructure->TableLength + InputStrLen - TargetStrLen > SMBIOS_TABLE_MAX_LENGTH))\r
694 {\r
e63f3308
EL
695 //\r
696 // The length of the entire structure table (including all strings) must be reported\r
697 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,\r
698 // which is a WORD field limited to 65,535 bytes.\r
699 //\r
87000d77 700 DEBUG ((DEBUG_INFO, "SmbiosUpdateString: Total length exceeds max 32-bit table length\n"));\r
e63f3308 701 } else {\r
87000d77 702 DEBUG ((DEBUG_INFO, "SmbiosUpdateString: New smbios record add to 32-bit table\n"));\r
e63f3308
EL
703 SmbiosEntry->Smbios32BitTable = TRUE;\r
704 }\r
d1102dba 705 }\r
310b04e6 706\r
e63f3308 707 if ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) {\r
4233bf70 708 //\r
e63f3308 709 // 64-bit table is produced, check the valid length.\r
4233bf70 710 //\r
d1102dba 711 if ((Smbios30EntryPointStructure != NULL) &&\r
1436aea4
MK
712 (Smbios30EntryPointStructure->TableMaximumSize + InputStrLen - TargetStrLen > SMBIOS_3_0_TABLE_MAX_LENGTH))\r
713 {\r
87000d77 714 DEBUG ((DEBUG_INFO, "SmbiosUpdateString: Total length exceeds max 64-bit table length\n"));\r
e63f3308 715 } else {\r
87000d77 716 DEBUG ((DEBUG_INFO, "SmbiosUpdateString: New smbios record add to 64-bit table\n"));\r
e63f3308
EL
717 SmbiosEntry->Smbios64BitTable = TRUE;\r
718 }\r
719 }\r
720\r
721 if ((!SmbiosEntry->Smbios32BitTable) && (!SmbiosEntry->Smbios64BitTable)) {\r
722 EfiReleaseLock (&Private->DataLock);\r
4233bf70
SZ
723 return EFI_UNSUPPORTED;\r
724 }\r
725\r
310b04e6 726 //\r
727 // Original string buffer size is not exactly match input string length.\r
728 // Re-allocate buffer is needed.\r
729 //\r
1436aea4 730 NewEntrySize = SmbiosEntry->RecordSize + InputStrLen - TargetStrLen;\r
0d34b1cf 731 ResizedSmbiosEntry = AllocateZeroPool (NewEntrySize);\r
310b04e6 732\r
733 if (ResizedSmbiosEntry == NULL) {\r
734 EfiReleaseLock (&Private->DataLock);\r
735 return EFI_OUT_OF_RESOURCES;\r
736 }\r
737\r
1436aea4
MK
738 InternalRecord = (EFI_SMBIOS_RECORD_HEADER *)(ResizedSmbiosEntry + 1);\r
739 Raw = (VOID *)(InternalRecord + 1);\r
310b04e6 740\r
741 //\r
742 // Build internal record Header\r
743 //\r
1436aea4
MK
744 InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;\r
745 InternalRecord->HeaderSize = (UINT16)sizeof (EFI_SMBIOS_RECORD_HEADER);\r
746 InternalRecord->RecordSize = SmbiosEntry->RecordHeader->RecordSize + InputStrLen - TargetStrLen;\r
747 InternalRecord->ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;\r
310b04e6 748 InternalRecord->NumberOfStrings = SmbiosEntry->RecordHeader->NumberOfStrings;\r
749\r
750 //\r
0ddd8553 751 // Copy SMBIOS structure and optional strings.\r
310b04e6 752 //\r
f8ee20c9 753 CopyMem (Raw, SmbiosEntry->RecordHeader + 1, Record->Length + TargetStrOffset);\r
1436aea4
MK
754 CopyMem ((VOID *)((UINTN)Raw + Record->Length + TargetStrOffset), String, InputStrLen + 1);\r
755 CopyMem (\r
756 (CHAR8 *)((UINTN)Raw + Record->Length + TargetStrOffset + InputStrLen + 1),\r
757 (CHAR8 *)Record + Record->Length + TargetStrOffset + TargetStrLen + 1,\r
758 SmbiosEntry->RecordHeader->RecordSize - sizeof (EFI_SMBIOS_RECORD_HEADER) - Record->Length - TargetStrOffset - TargetStrLen - 1\r
759 );\r
310b04e6 760\r
761 //\r
762 // Insert new record\r
763 //\r
1436aea4
MK
764 ResizedSmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;\r
765 ResizedSmbiosEntry->RecordHeader = InternalRecord;\r
766 ResizedSmbiosEntry->RecordSize = NewEntrySize;\r
e63f3308
EL
767 ResizedSmbiosEntry->Smbios32BitTable = SmbiosEntry->Smbios32BitTable;\r
768 ResizedSmbiosEntry->Smbios64BitTable = SmbiosEntry->Smbios64BitTable;\r
310b04e6 769 InsertTailList (Link->ForwardLink, &ResizedSmbiosEntry->Link);\r
770\r
771 //\r
772 // Remove old record\r
773 //\r
1436aea4
MK
774 RemoveEntryList (Link);\r
775 FreePool (SmbiosEntry);\r
0ddd8553 776 //\r
777 // Some UEFI drivers (such as network) need some information in SMBIOS table.\r
778 // Here we create SMBIOS table and publish it in\r
779 // configuration table, so other UEFI drivers can get SMBIOS table from\r
780 // configuration table without depending on PI SMBIOS protocol.\r
781 //\r
e63f3308 782 SmbiosTableConstruction (ResizedSmbiosEntry->Smbios32BitTable, ResizedSmbiosEntry->Smbios64BitTable);\r
310b04e6 783 EfiReleaseLock (&Private->DataLock);\r
784 return EFI_SUCCESS;\r
785 }\r
786 }\r
787\r
788 EfiReleaseLock (&Private->DataLock);\r
789 return EFI_INVALID_PARAMETER;\r
790}\r
791\r
792/**\r
793 Remove an SMBIOS record.\r
794\r
795 @param This The EFI_SMBIOS_PROTOCOL instance.\r
796 @param SmbiosHandle The handle of the SMBIOS record to remove.\r
797\r
798 @retval EFI_SUCCESS SMBIOS record was removed.\r
799 @retval EFI_INVALID_PARAMETER SmbiosHandle does not specify a valid SMBIOS record.\r
800\r
801**/\r
802EFI_STATUS\r
803EFIAPI\r
804SmbiosRemove (\r
1436aea4
MK
805 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
806 IN EFI_SMBIOS_HANDLE SmbiosHandle\r
310b04e6 807 )\r
808{\r
1436aea4
MK
809 LIST_ENTRY *Link;\r
810 LIST_ENTRY *Head;\r
811 EFI_STATUS Status;\r
812 EFI_SMBIOS_HANDLE MaxSmbiosHandle;\r
813 SMBIOS_INSTANCE *Private;\r
814 EFI_SMBIOS_ENTRY *SmbiosEntry;\r
815 SMBIOS_HANDLE_ENTRY *HandleEntry;\r
816 EFI_SMBIOS_TABLE_HEADER *Record;\r
310b04e6 817\r
818 //\r
819 // Check args validity\r
820 //\r
1436aea4 821 GetMaxSmbiosHandle (This, &MaxSmbiosHandle);\r
310b04e6 822\r
823 if (SmbiosHandle > MaxSmbiosHandle) {\r
824 return EFI_INVALID_PARAMETER;\r
825 }\r
826\r
827 Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
828 //\r
829 // Enter into critical section\r
d1102dba 830 //\r
310b04e6 831 Status = EfiAcquireLockOrFail (&Private->DataLock);\r
832 if (EFI_ERROR (Status)) {\r
833 return Status;\r
834 }\r
835\r
836 Head = &Private->DataListHead;\r
837 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
1436aea4
MK
838 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK (Link);\r
839 Record = (EFI_SMBIOS_TABLE_HEADER *)(SmbiosEntry->RecordHeader + 1);\r
afe3969c 840 if (Record->Handle == SmbiosHandle) {\r
310b04e6 841 //\r
842 // Remove specified smobios record from DataList\r
843 //\r
1436aea4 844 RemoveEntryList (Link);\r
d1102dba 845 //\r
310b04e6 846 // Remove this handle from AllocatedHandleList\r
847 //\r
848 Head = &Private->AllocatedHandleListHead;\r
849 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
1436aea4 850 HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK (Link);\r
afe3969c 851 if (HandleEntry->SmbiosHandle == SmbiosHandle) {\r
1436aea4
MK
852 RemoveEntryList (Link);\r
853 FreePool (HandleEntry);\r
310b04e6 854 break;\r
855 }\r
856 }\r
1436aea4 857\r
0ddd8553 858 //\r
859 // Some UEFI drivers (such as network) need some information in SMBIOS table.\r
860 // Here we create SMBIOS table and publish it in\r
861 // configuration table, so other UEFI drivers can get SMBIOS table from\r
862 // configuration table without depending on PI SMBIOS protocol.\r
863 //\r
e63f3308 864 if (SmbiosEntry->Smbios32BitTable) {\r
87000d77 865 DEBUG ((DEBUG_INFO, "SmbiosRemove: remove from 32-bit table\n"));\r
e63f3308 866 }\r
1436aea4 867\r
e63f3308 868 if (SmbiosEntry->Smbios64BitTable) {\r
87000d77 869 DEBUG ((DEBUG_INFO, "SmbiosRemove: remove from 64-bit table\n"));\r
e63f3308 870 }\r
1436aea4 871\r
e63f3308
EL
872 //\r
873 // Update the whole SMBIOS table again based on which table the removed SMBIOS record is in.\r
874 //\r
875 SmbiosTableConstruction (SmbiosEntry->Smbios32BitTable, SmbiosEntry->Smbios64BitTable);\r
1436aea4 876 FreePool (SmbiosEntry);\r
310b04e6 877 EfiReleaseLock (&Private->DataLock);\r
878 return EFI_SUCCESS;\r
879 }\r
880 }\r
881\r
882 //\r
883 // Leave critical section\r
884 //\r
885 EfiReleaseLock (&Private->DataLock);\r
886 return EFI_INVALID_PARAMETER;\r
310b04e6 887}\r
888\r
889/**\r
890 Allow the caller to discover all or some of the SMBIOS records.\r
891\r
892 @param This The EFI_SMBIOS_PROTOCOL instance.\r
893 @param SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the\r
4659816a
SZ
894 next SMBIOS record handle. If it is FFFEh on entry, then the first SMBIOS record\r
895 handle will be returned. If it returns FFFEh on exit, then there are no more SMBIOS records.\r
d1102dba 896 @param Type On entry it means return the next SMBIOS record of type Type. If a NULL is passed in\r
310b04e6 897 this functionally it ignored. Type is not modified by the GetNext() function.\r
898 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by\r
899 the unformatted area. The unformatted area optionally contains text strings.\r
d1102dba
LG
900 @param ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no ProducerHandle was passed into Add() NULL is returned.\r
901 If a NULL pointer is passed in no data will be returned\r
902\r
310b04e6 903 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.\r
310b04e6 904 @retval EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record.\r
905\r
906**/\r
907EFI_STATUS\r
908EFIAPI\r
909SmbiosGetNext (\r
1436aea4
MK
910 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
911 IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,\r
912 IN EFI_SMBIOS_TYPE *Type OPTIONAL,\r
913 OUT EFI_SMBIOS_TABLE_HEADER **Record,\r
914 OUT EFI_HANDLE *ProducerHandle OPTIONAL\r
310b04e6 915 )\r
916{\r
917 BOOLEAN StartPointFound;\r
918 LIST_ENTRY *Link;\r
919 LIST_ENTRY *Head;\r
920 SMBIOS_INSTANCE *Private;\r
921 EFI_SMBIOS_ENTRY *SmbiosEntry;\r
922 EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader;\r
923\r
924 if (SmbiosHandle == NULL) {\r
925 return EFI_INVALID_PARAMETER;\r
926 }\r
927\r
928 StartPointFound = FALSE;\r
1436aea4
MK
929 Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
930 Head = &Private->DataListHead;\r
310b04e6 931 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
1436aea4
MK
932 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK (Link);\r
933 SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER *)(SmbiosEntry->RecordHeader + 1);\r
310b04e6 934\r
935 //\r
4659816a 936 // If SmbiosHandle is 0xFFFE, the first matched SMBIOS record handle will be returned\r
310b04e6 937 //\r
4659816a 938 if (*SmbiosHandle == SMBIOS_HANDLE_PI_RESERVED) {\r
310b04e6 939 if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {\r
d1102dba 940 continue;\r
310b04e6 941 }\r
942\r
943 *SmbiosHandle = SmbiosTableHeader->Handle;\r
1436aea4 944 *Record = SmbiosTableHeader;\r
310b04e6 945 if (ProducerHandle != NULL) {\r
946 *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;\r
947 }\r
1436aea4 948\r
310b04e6 949 return EFI_SUCCESS;\r
950 }\r
951\r
952 //\r
0ddd8553 953 // Start this round search from the next SMBIOS handle\r
310b04e6 954 //\r
955 if (!StartPointFound && (*SmbiosHandle == SmbiosTableHeader->Handle)) {\r
956 StartPointFound = TRUE;\r
957 continue;\r
958 }\r
959\r
960 if (StartPointFound) {\r
961 if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {\r
d1102dba 962 continue;\r
310b04e6 963 }\r
d1102dba 964\r
310b04e6 965 *SmbiosHandle = SmbiosTableHeader->Handle;\r
1436aea4 966 *Record = SmbiosTableHeader;\r
310b04e6 967 if (ProducerHandle != NULL) {\r
968 *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;\r
969 }\r
970\r
d1102dba 971 return EFI_SUCCESS;\r
310b04e6 972 }\r
973 }\r
974\r
4659816a 975 *SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;\r
310b04e6 976 return EFI_NOT_FOUND;\r
310b04e6 977}\r
978\r
0ddd8553 979/**\r
980 Allow the caller to discover all of the SMBIOS records.\r
981\r
982 @param This The EFI_SMBIOS_PROTOCOL instance.\r
d1102dba
LG
983 @param CurrentSmbiosEntry On exit, points to the SMBIOS entry on the list which includes the returned SMBIOS record information.\r
984 If *CurrentSmbiosEntry is NULL on entry, then the first SMBIOS entry on the list will be returned.\r
0ddd8553 985 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by\r
986 the unformatted area. The unformatted area optionally contains text strings.\r
d1102dba 987\r
0ddd8553 988 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.\r
989 *CurrentSmbiosEntry points to the SMBIOS entry which includes the returned SMBIOS record information.\r
990 @retval EFI_NOT_FOUND There is no more SMBIOS entry.\r
991\r
992**/\r
993EFI_STATUS\r
994EFIAPI\r
995GetNextSmbiosRecord (\r
1436aea4
MK
996 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
997 IN OUT EFI_SMBIOS_ENTRY **CurrentSmbiosEntry,\r
998 OUT EFI_SMBIOS_TABLE_HEADER **Record\r
0ddd8553 999 )\r
1000{\r
1001 LIST_ENTRY *Link;\r
1002 LIST_ENTRY *Head;\r
1003 SMBIOS_INSTANCE *Private;\r
1004 EFI_SMBIOS_ENTRY *SmbiosEntry;\r
1005 EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader;\r
1006\r
1007 Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
1008 if (*CurrentSmbiosEntry == NULL) {\r
1009 //\r
1010 // Get the beginning of SMBIOS entry.\r
1011 //\r
1012 Head = &Private->DataListHead;\r
1013 } else {\r
1014 //\r
1015 // Get previous SMBIOS entry and make it as start point.\r
1016 //\r
1017 Head = &(*CurrentSmbiosEntry)->Link;\r
1018 }\r
d1102dba 1019\r
1436aea4 1020 Link = Head->ForwardLink;\r
d1102dba 1021\r
0ddd8553 1022 if (Link == &Private->DataListHead) {\r
1023 //\r
1024 // If no more SMBIOS entry in the list, return not found.\r
1025 //\r
1026 return EFI_NOT_FOUND;\r
1027 }\r
d1102dba 1028\r
1436aea4
MK
1029 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK (Link);\r
1030 SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER *)(SmbiosEntry->RecordHeader + 1);\r
1031 *Record = SmbiosTableHeader;\r
0ddd8553 1032 *CurrentSmbiosEntry = SmbiosEntry;\r
d1102dba 1033 return EFI_SUCCESS;\r
0ddd8553 1034}\r
310b04e6 1035\r
1036/**\r
0ddd8553 1037 Assembles SMBIOS table from the SMBIOS protocol. Produce Table\r
310b04e6 1038 Entry Point and return the pointer to it.\r
d1102dba 1039\r
310b04e6 1040 @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.\r
d1102dba 1041\r
310b04e6 1042 @retval EFI_SUCCESS Structure created sucessfully.\r
310b04e6 1043 @retval EFI_OUT_OF_RESOURCES No enough memory.\r
d1102dba 1044\r
310b04e6 1045**/\r
1046EFI_STATUS\r
1047EFIAPI\r
1048SmbiosCreateTable (\r
1436aea4 1049 OUT VOID **TableEntryPointStructure\r
310b04e6 1050 )\r
1051{\r
310b04e6 1052 UINT8 *BufferPointer;\r
310b04e6 1053 UINTN RecordSize;\r
1054 UINTN NumOfStr;\r
1055 EFI_STATUS Status;\r
1056 EFI_SMBIOS_HANDLE SmbiosHandle;\r
1057 EFI_SMBIOS_PROTOCOL *SmbiosProtocol;\r
1058 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
1059 EFI_SMBIOS_TABLE_HEADER *SmbiosRecord;\r
1060 EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure;\r
0ddd8553 1061 EFI_SMBIOS_ENTRY *CurrentSmbiosEntry;\r
d1102dba 1062\r
1436aea4
MK
1063 Status = EFI_SUCCESS;\r
1064 BufferPointer = NULL;\r
310b04e6 1065\r
e63f3308
EL
1066 if (EntryPointStructure == NULL) {\r
1067 //\r
1068 // Initialize the EntryPointStructure with initial values.\r
1069 // It should be done only once.\r
1070 // Allocate memory (below 4GB).\r
1071 //\r
87000d77 1072 DEBUG ((DEBUG_INFO, "SmbiosCreateTable: Initialize 32-bit entry point structure\n"));\r
1436aea4
MK
1073 EntryPointStructureData.MajorVersion = mPrivateData.Smbios.MajorVersion;\r
1074 EntryPointStructureData.MinorVersion = mPrivateData.Smbios.MinorVersion;\r
1075 EntryPointStructureData.SmbiosBcdRevision = (UINT8)((PcdGet16 (PcdSmbiosVersion) >> 4) & 0xf0) | (UINT8)(PcdGet16 (PcdSmbiosVersion) & 0x0f);\r
1076 PhysicalAddress = 0xffffffff;\r
1077 Status = gBS->AllocatePages (\r
1078 AllocateMaxAddress,\r
1079 EfiRuntimeServicesData,\r
1080 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),\r
1081 &PhysicalAddress\r
1082 );\r
e63f3308 1083 if (EFI_ERROR (Status)) {\r
87000d77 1084 DEBUG ((DEBUG_ERROR, "SmbiosCreateTable () could not allocate EntryPointStructure < 4GB\n"));\r
e63f3308
EL
1085 Status = gBS->AllocatePages (\r
1086 AllocateAnyPages,\r
1087 EfiRuntimeServicesData,\r
1088 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),\r
1089 &PhysicalAddress\r
1090 );\r
1436aea4 1091 if (EFI_ERROR (Status)) {\r
e63f3308
EL
1092 return EFI_OUT_OF_RESOURCES;\r
1093 }\r
1094 }\r
d1102dba 1095\r
1436aea4 1096 EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN)PhysicalAddress;\r
d1102dba 1097\r
e63f3308
EL
1098 CopyMem (\r
1099 EntryPointStructure,\r
1100 &EntryPointStructureData,\r
1101 sizeof (SMBIOS_TABLE_ENTRY_POINT)\r
1102 );\r
1103 }\r
1104\r
310b04e6 1105 //\r
0ddd8553 1106 // Get Smbios protocol to traverse SMBIOS records.\r
310b04e6 1107 //\r
0ddd8553 1108 SmbiosProtocol = &mPrivateData.Smbios;\r
310b04e6 1109\r
310b04e6 1110 //\r
1111 // Make some statistics about all the structures\r
1112 //\r
1113 EntryPointStructure->NumberOfSmbiosStructures = 0;\r
1114 EntryPointStructure->TableLength = 0;\r
1115 EntryPointStructure->MaxStructureSize = 0;\r
310b04e6 1116\r
1117 //\r
1118 // Calculate EPS Table Length\r
1119 //\r
0ddd8553 1120 CurrentSmbiosEntry = NULL;\r
310b04e6 1121 do {\r
0ddd8553 1122 Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);\r
d1102dba 1123\r
e63f3308 1124 if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios32BitTable)) {\r
1436aea4 1125 GetSmbiosStructureSize (SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);\r
310b04e6 1126 //\r
1127 // Record NumberOfSmbiosStructures, TableLength and MaxStructureSize\r
1128 //\r
afe3969c 1129 EntryPointStructure->NumberOfSmbiosStructures++;\r
1436aea4 1130 EntryPointStructure->TableLength = (UINT16)(EntryPointStructure->TableLength + RecordSize);\r
310b04e6 1131 if (RecordSize > EntryPointStructure->MaxStructureSize) {\r
1436aea4 1132 EntryPointStructure->MaxStructureSize = (UINT16)RecordSize;\r
310b04e6 1133 }\r
1134 }\r
1436aea4 1135 } while (!EFI_ERROR (Status));\r
d1102dba 1136\r
310b04e6 1137 //\r
1138 // Create End-Of-Table structure\r
1139 //\r
1436aea4
MK
1140 GetMaxSmbiosHandle (SmbiosProtocol, &SmbiosHandle);\r
1141 EndStructure.Header.Type = SMBIOS_TYPE_END_OF_TABLE;\r
1142 EndStructure.Header.Length = (UINT8)sizeof (EFI_SMBIOS_TABLE_HEADER);\r
310b04e6 1143 EndStructure.Header.Handle = SmbiosHandle;\r
1436aea4
MK
1144 EndStructure.Tailing[0] = 0;\r
1145 EndStructure.Tailing[1] = 0;\r
310b04e6 1146 EntryPointStructure->NumberOfSmbiosStructures++;\r
1436aea4 1147 EntryPointStructure->TableLength = (UINT16)(EntryPointStructure->TableLength + sizeof (EndStructure));\r
310b04e6 1148 if (sizeof (EndStructure) > EntryPointStructure->MaxStructureSize) {\r
1436aea4 1149 EntryPointStructure->MaxStructureSize = (UINT16)sizeof (EndStructure);\r
310b04e6 1150 }\r
310b04e6 1151\r
1436aea4 1152 if (EFI_SIZE_TO_PAGES ((UINT32)EntryPointStructure->TableLength) > mPreAllocatedPages) {\r
0ddd8553 1153 //\r
d1102dba 1154 // If new SMBIOS table size exceeds the previous allocated page,\r
0ddd8553 1155 // it is time to re-allocate memory (below 4GB).\r
d1102dba 1156 //\r
1436aea4
MK
1157 DEBUG ((\r
1158 DEBUG_INFO,\r
1159 "%a() re-allocate SMBIOS 32-bit table\n",\r
1160 __FUNCTION__\r
1161 ));\r
0ddd8553 1162 if (EntryPointStructure->TableAddress != 0) {\r
1163 //\r
e63f3308 1164 // Free the previous allocated page\r
d1102dba 1165 //\r
0ddd8553 1166 FreePages (\r
1436aea4
MK
1167 (VOID *)(UINTN)EntryPointStructure->TableAddress,\r
1168 mPreAllocatedPages\r
1169 );\r
0ddd8553 1170 EntryPointStructure->TableAddress = 0;\r
1436aea4 1171 mPreAllocatedPages = 0;\r
0ddd8553 1172 }\r
d1102dba 1173\r
0ddd8553 1174 PhysicalAddress = 0xffffffff;\r
1436aea4
MK
1175 Status = gBS->AllocatePages (\r
1176 AllocateMaxAddress,\r
1177 EfiRuntimeServicesData,\r
1178 EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength),\r
1179 &PhysicalAddress\r
1180 );\r
0ddd8553 1181 if (EFI_ERROR (Status)) {\r
87000d77 1182 DEBUG ((DEBUG_ERROR, "SmbiosCreateTable() could not allocate SMBIOS table < 4GB\n"));\r
c7ce5169 1183 EntryPointStructure->TableAddress = 0;\r
0ddd8553 1184 return EFI_OUT_OF_RESOURCES;\r
c7ce5169 1185 } else {\r
1436aea4
MK
1186 EntryPointStructure->TableAddress = (UINT32)PhysicalAddress;\r
1187 mPreAllocatedPages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength);\r
0ddd8553 1188 }\r
0ddd8553 1189 }\r
d1102dba 1190\r
310b04e6 1191 //\r
1192 // Assemble the tables\r
1193 //\r
f63085f5 1194 ASSERT (EntryPointStructure->TableAddress != 0);\r
1436aea4 1195 BufferPointer = (UINT8 *)(UINTN)EntryPointStructure->TableAddress;\r
0ddd8553 1196 CurrentSmbiosEntry = NULL;\r
310b04e6 1197 do {\r
0ddd8553 1198 Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);\r
1199\r
e63f3308 1200 if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios32BitTable)) {\r
1436aea4 1201 GetSmbiosStructureSize (SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);\r
310b04e6 1202 CopyMem (BufferPointer, SmbiosRecord, RecordSize);\r
1203 BufferPointer = BufferPointer + RecordSize;\r
1204 }\r
1436aea4 1205 } while (!EFI_ERROR (Status));\r
d1102dba 1206\r
310b04e6 1207 //\r
1208 // Assemble End-Of-Table structure\r
1209 //\r
1210 CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure));\r
1211\r
1212 //\r
1213 // Fixup checksums in the Entry Point Structure\r
1214 //\r
1436aea4 1215 EntryPointStructure->IntermediateChecksum = 0;\r
47f8d0f3
JY
1216 EntryPointStructure->EntryPointStructureChecksum = 0;\r
1217\r
afe3969c 1218 EntryPointStructure->IntermediateChecksum =\r
1436aea4 1219 CalculateCheckSum8 ((UINT8 *)EntryPointStructure + 0x10, EntryPointStructure->EntryPointLength - 0x10);\r
afe3969c 1220 EntryPointStructure->EntryPointStructureChecksum =\r
1436aea4 1221 CalculateCheckSum8 ((UINT8 *)EntryPointStructure, EntryPointStructure->EntryPointLength);\r
310b04e6 1222\r
1223 //\r
1224 // Returns the pointer\r
1225 //\r
1226 *TableEntryPointStructure = EntryPointStructure;\r
1227\r
1228 return EFI_SUCCESS;\r
1229}\r
1230\r
310b04e6 1231/**\r
e63f3308
EL
1232 Assembles SMBIOS 64-bit table from the SMBIOS protocol. Produce Table\r
1233 Entry Point and return the pointer to it.\r
1234\r
1235 @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.\r
1236\r
1237 @retval EFI_SUCCESS Structure created sucessfully.\r
1238 @retval EFI_OUT_OF_RESOURCES No enough memory.\r
1239\r
1240**/\r
1241EFI_STATUS\r
1242EFIAPI\r
1243SmbiosCreate64BitTable (\r
1436aea4 1244 OUT VOID **TableEntryPointStructure\r
e63f3308
EL
1245 )\r
1246{\r
1247 UINT8 *BufferPointer;\r
1248 UINTN RecordSize;\r
1249 UINTN NumOfStr;\r
1250 EFI_STATUS Status;\r
1251 EFI_SMBIOS_HANDLE SmbiosHandle;\r
1252 EFI_SMBIOS_PROTOCOL *SmbiosProtocol;\r
1253 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
1254 EFI_SMBIOS_TABLE_HEADER *SmbiosRecord;\r
1255 EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure;\r
1256 EFI_SMBIOS_ENTRY *CurrentSmbiosEntry;\r
d1102dba 1257\r
1436aea4
MK
1258 Status = EFI_SUCCESS;\r
1259 BufferPointer = NULL;\r
e63f3308
EL
1260\r
1261 if (Smbios30EntryPointStructure == NULL) {\r
1262 //\r
1263 // Initialize the Smbios30EntryPointStructure with initial values.\r
1264 // It should be done only once.\r
1265 // Allocate memory at any address.\r
1266 //\r
87000d77 1267 DEBUG ((DEBUG_INFO, "SmbiosCreateTable: Initialize 64-bit entry point structure\n"));\r
1436aea4
MK
1268 Smbios30EntryPointStructureData.MajorVersion = mPrivateData.Smbios.MajorVersion;\r
1269 Smbios30EntryPointStructureData.MinorVersion = mPrivateData.Smbios.MinorVersion;\r
1270 Smbios30EntryPointStructureData.DocRev = PcdGet8 (PcdSmbiosDocRev);\r
1271 Status = gBS->AllocatePages (\r
1272 AllocateAnyPages,\r
1273 EfiRuntimeServicesData,\r
1274 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT)),\r
1275 &PhysicalAddress\r
1276 );\r
e63f3308 1277 if (EFI_ERROR (Status)) {\r
87000d77 1278 DEBUG ((DEBUG_ERROR, "SmbiosCreate64BitTable() could not allocate Smbios30EntryPointStructure\n"));\r
e63f3308
EL
1279 return EFI_OUT_OF_RESOURCES;\r
1280 }\r
d1102dba 1281\r
1436aea4 1282 Smbios30EntryPointStructure = (SMBIOS_TABLE_3_0_ENTRY_POINT *)(UINTN)PhysicalAddress;\r
d1102dba 1283\r
e63f3308
EL
1284 CopyMem (\r
1285 Smbios30EntryPointStructure,\r
1286 &Smbios30EntryPointStructureData,\r
1287 sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT)\r
1288 );\r
1289 }\r
1290\r
1291 //\r
1292 // Get Smbios protocol to traverse SMBIOS records.\r
1293 //\r
1436aea4 1294 SmbiosProtocol = &mPrivateData.Smbios;\r
e63f3308
EL
1295 Smbios30EntryPointStructure->TableMaximumSize = 0;\r
1296\r
1297 //\r
1298 // Calculate EPS Table Length\r
1299 //\r
1300 CurrentSmbiosEntry = NULL;\r
1301 do {\r
1302 Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);\r
d1102dba 1303\r
e63f3308 1304 if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios64BitTable)) {\r
1436aea4 1305 GetSmbiosStructureSize (SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);\r
e63f3308
EL
1306 //\r
1307 // Record TableMaximumSize\r
1308 //\r
1436aea4 1309 Smbios30EntryPointStructure->TableMaximumSize = (UINT32)(Smbios30EntryPointStructure->TableMaximumSize + RecordSize);\r
e63f3308 1310 }\r
1436aea4 1311 } while (!EFI_ERROR (Status));\r
e63f3308
EL
1312\r
1313 //\r
1314 // Create End-Of-Table structure\r
1315 //\r
1436aea4
MK
1316 GetMaxSmbiosHandle (SmbiosProtocol, &SmbiosHandle);\r
1317 EndStructure.Header.Type = SMBIOS_TYPE_END_OF_TABLE;\r
1318 EndStructure.Header.Length = (UINT8)sizeof (EFI_SMBIOS_TABLE_HEADER);\r
1319 EndStructure.Header.Handle = SmbiosHandle;\r
1320 EndStructure.Tailing[0] = 0;\r
1321 EndStructure.Tailing[1] = 0;\r
1322 Smbios30EntryPointStructure->TableMaximumSize = (UINT32)(Smbios30EntryPointStructure->TableMaximumSize + sizeof (EndStructure));\r
e63f3308 1323\r
16f69227 1324 if (EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize) > mPre64BitAllocatedPages) {\r
e63f3308 1325 //\r
d1102dba 1326 // If new SMBIOS table size exceeds the previous allocated page,\r
e63f3308
EL
1327 // it is time to re-allocate memory at anywhere.\r
1328 //\r
1436aea4
MK
1329 DEBUG ((\r
1330 DEBUG_INFO,\r
1331 "%a() re-allocate SMBIOS 64-bit table\n",\r
1332 __FUNCTION__\r
1333 ));\r
e63f3308
EL
1334 if (Smbios30EntryPointStructure->TableAddress != 0) {\r
1335 //\r
1336 // Free the previous allocated page\r
d1102dba 1337 //\r
e63f3308 1338 FreePages (\r
1436aea4
MK
1339 (VOID *)(UINTN)Smbios30EntryPointStructure->TableAddress,\r
1340 mPre64BitAllocatedPages\r
1341 );\r
e63f3308 1342 Smbios30EntryPointStructure->TableAddress = 0;\r
1436aea4 1343 mPre64BitAllocatedPages = 0;\r
e63f3308
EL
1344 }\r
1345\r
1346 Status = gBS->AllocatePages (\r
1347 AllocateAnyPages,\r
1348 EfiRuntimeServicesData,\r
1349 EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize),\r
1350 &PhysicalAddress\r
1351 );\r
1352 if (EFI_ERROR (Status)) {\r
87000d77 1353 DEBUG ((DEBUG_ERROR, "SmbiosCreateTable() could not allocate SMBIOS 64-bit table\n"));\r
e63f3308
EL
1354 Smbios30EntryPointStructure->TableAddress = 0;\r
1355 return EFI_OUT_OF_RESOURCES;\r
1356 } else {\r
1357 Smbios30EntryPointStructure->TableAddress = PhysicalAddress;\r
1436aea4 1358 mPre64BitAllocatedPages = EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize);\r
e63f3308
EL
1359 }\r
1360 }\r
1361\r
1362 //\r
1363 // Assemble the tables\r
1364 //\r
1365 ASSERT (Smbios30EntryPointStructure->TableAddress != 0);\r
1436aea4 1366 BufferPointer = (UINT8 *)(UINTN)Smbios30EntryPointStructure->TableAddress;\r
e63f3308
EL
1367 CurrentSmbiosEntry = NULL;\r
1368 do {\r
1369 Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);\r
1370\r
1371 if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios64BitTable)) {\r
1372 //\r
1373 // This record can be added to 64-bit table\r
1374 //\r
1436aea4 1375 GetSmbiosStructureSize (SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);\r
e63f3308
EL
1376 CopyMem (BufferPointer, SmbiosRecord, RecordSize);\r
1377 BufferPointer = BufferPointer + RecordSize;\r
1378 }\r
1436aea4 1379 } while (!EFI_ERROR (Status));\r
e63f3308
EL
1380\r
1381 //\r
1382 // Assemble End-Of-Table structure\r
1383 //\r
1384 CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure));\r
1385\r
1386 //\r
1387 // Fixup checksums in the Entry Point Structure\r
1388 //\r
1389 Smbios30EntryPointStructure->EntryPointStructureChecksum = 0;\r
1390 Smbios30EntryPointStructure->EntryPointStructureChecksum =\r
1436aea4 1391 CalculateCheckSum8 ((UINT8 *)Smbios30EntryPointStructure, Smbios30EntryPointStructure->EntryPointLength);\r
e63f3308
EL
1392\r
1393 //\r
1394 // Returns the pointer\r
1395 //\r
1396 *TableEntryPointStructure = Smbios30EntryPointStructure;\r
1397\r
1398 return EFI_SUCCESS;\r
1399}\r
1400\r
1401/**\r
1402 Create Smbios Table and installs the Smbios Table to the System Table.\r
d1102dba 1403\r
e63f3308
EL
1404 @param Smbios32BitTable The flag to update 32-bit table.\r
1405 @param Smbios64BitTable The flag to update 64-bit table.\r
1406\r
310b04e6 1407**/\r
1408VOID\r
1409EFIAPI\r
1410SmbiosTableConstruction (\r
1436aea4
MK
1411 BOOLEAN Smbios32BitTable,\r
1412 BOOLEAN Smbios64BitTable\r
310b04e6 1413 )\r
1414{\r
1415 UINT8 *Eps;\r
e63f3308 1416 UINT8 *Eps64Bit;\r
310b04e6 1417 EFI_STATUS Status;\r
1418\r
e63f3308 1419 if (Smbios32BitTable) {\r
1436aea4 1420 Status = SmbiosCreateTable ((VOID **)&Eps);\r
e63f3308
EL
1421 if (!EFI_ERROR (Status)) {\r
1422 gBS->InstallConfigurationTable (&gEfiSmbiosTableGuid, Eps);\r
1423 }\r
1424 }\r
1425\r
1426 if (Smbios64BitTable) {\r
1436aea4 1427 Status = SmbiosCreate64BitTable ((VOID **)&Eps64Bit);\r
e63f3308
EL
1428 if (!EFI_ERROR (Status)) {\r
1429 gBS->InstallConfigurationTable (&gEfiSmbios3TableGuid, Eps64Bit);\r
1430 }\r
310b04e6 1431 }\r
1432}\r
1433\r
70e8c9c3
ZL
1434/**\r
1435 Validates a SMBIOS 2.0 table entry point.\r
1436\r
1437 @param TableEntry The SmBios table entry to validate.\r
1438 @param TableAddress On exit, point to the smbios table addres.\r
1439 @param TableMaximumSize On exit, point to the maximum size of the table.\r
1440\r
1441 @retval TRUE SMBIOS table entry point is valid.\r
1442 @retval FALSE SMBIOS table entry point is malformed.\r
1443\r
1444**/\r
1445STATIC\r
1446BOOLEAN\r
1447IsValidSmbios20Table (\r
1436aea4
MK
1448 IN VOID *TableEntry,\r
1449 OUT VOID **TableAddress,\r
1450 OUT UINTN *TableMaximumSize\r
70e8c9c3
ZL
1451 )\r
1452{\r
1436aea4
MK
1453 UINT8 Checksum;\r
1454 SMBIOS_TABLE_ENTRY_POINT *SmbiosTable;\r
1455\r
1456 SmbiosTable = (SMBIOS_TABLE_ENTRY_POINT *)TableEntry;\r
70e8c9c3
ZL
1457\r
1458 if (CompareMem (SmbiosTable->AnchorString, "_SM_", 4) != 0) {\r
1459 return FALSE;\r
1460 }\r
1461\r
1462 if (CompareMem (SmbiosTable->IntermediateAnchorString, "_DMI_", 5) != 0) {\r
1463 return FALSE;\r
1464 }\r
1465\r
1466 //\r
1467 // The actual value of the EntryPointLength should be 1Fh.\r
1468 // However, it was incorrectly stated in version 2.1 of smbios specification.\r
1469 // Therefore, 0x1F and 0x1E are both accepted.\r
1470 //\r
1436aea4 1471 if ((SmbiosTable->EntryPointLength != 0x1E) && (SmbiosTable->EntryPointLength != sizeof (SMBIOS_TABLE_ENTRY_POINT))) {\r
70e8c9c3
ZL
1472 return FALSE;\r
1473 }\r
1474\r
1475 //\r
1476 // MajorVersion should not be less than 2.\r
1477 //\r
1478 if (SmbiosTable->MajorVersion < 2) {\r
1479 return FALSE;\r
1480 }\r
1481\r
1482 //\r
1483 // The whole struct check sum should be zero\r
1484 //\r
1485 Checksum = CalculateSum8 (\r
1436aea4 1486 (UINT8 *)SmbiosTable,\r
70e8c9c3
ZL
1487 SmbiosTable->EntryPointLength\r
1488 );\r
1489 if (Checksum != 0) {\r
1490 return FALSE;\r
1491 }\r
1492\r
1493 //\r
1494 // The Intermediate Entry Point Structure check sum should be zero.\r
1495 //\r
1496 Checksum = CalculateSum8 (\r
1436aea4 1497 (UINT8 *)SmbiosTable + OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString),\r
70e8c9c3
ZL
1498 SmbiosTable->EntryPointLength - OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString)\r
1499 );\r
1500 if (Checksum != 0) {\r
1501 return FALSE;\r
1502 }\r
1503\r
1436aea4 1504 *TableAddress = (VOID *)(UINTN)SmbiosTable->TableAddress;\r
70e8c9c3
ZL
1505 *TableMaximumSize = SmbiosTable->TableLength;\r
1506 return TRUE;\r
1507}\r
1508\r
1509/**\r
1510 Validates a SMBIOS 3.0 table entry point.\r
1511\r
1512 @param TableEntry The SmBios table entry to validate.\r
1513 @param TableAddress On exit, point to the smbios table addres.\r
1514 @param TableMaximumSize On exit, point to the maximum size of the table.\r
1515\r
1516 @retval TRUE SMBIOS table entry point is valid.\r
1517 @retval FALSE SMBIOS table entry point is malformed.\r
1518\r
1519**/\r
1520STATIC\r
1521BOOLEAN\r
1522IsValidSmbios30Table (\r
1436aea4
MK
1523 IN VOID *TableEntry,\r
1524 OUT VOID **TableAddress,\r
1525 OUT UINTN *TableMaximumSize\r
70e8c9c3
ZL
1526 )\r
1527{\r
1436aea4
MK
1528 UINT8 Checksum;\r
1529 SMBIOS_TABLE_3_0_ENTRY_POINT *SmbiosTable;\r
1530\r
1531 SmbiosTable = (SMBIOS_TABLE_3_0_ENTRY_POINT *)TableEntry;\r
70e8c9c3
ZL
1532\r
1533 if (CompareMem (SmbiosTable->AnchorString, "_SM3_", 5) != 0) {\r
1534 return FALSE;\r
1535 }\r
1436aea4 1536\r
70e8c9c3
ZL
1537 if (SmbiosTable->EntryPointLength < sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT)) {\r
1538 return FALSE;\r
1539 }\r
1436aea4 1540\r
70e8c9c3
ZL
1541 if (SmbiosTable->MajorVersion < 3) {\r
1542 return FALSE;\r
1543 }\r
1544\r
1545 //\r
1546 // The whole struct check sum should be zero\r
1547 //\r
1548 Checksum = CalculateSum8 (\r
1436aea4 1549 (UINT8 *)SmbiosTable,\r
70e8c9c3
ZL
1550 SmbiosTable->EntryPointLength\r
1551 );\r
1552 if (Checksum != 0) {\r
1553 return FALSE;\r
1554 }\r
1555\r
1436aea4 1556 *TableAddress = (VOID *)(UINTN)SmbiosTable->TableAddress;\r
70e8c9c3
ZL
1557 *TableMaximumSize = SmbiosTable->TableMaximumSize;\r
1558 return TRUE;\r
1559}\r
1560\r
1561/**\r
1562 Parse an existing SMBIOS table and insert it using SmbiosAdd.\r
1563\r
1564 @param ImageHandle The EFI_HANDLE to this driver.\r
1565 @param Smbios The SMBIOS table to parse.\r
1566 @param Length The length of the SMBIOS table.\r
1567\r
1568 @retval EFI_SUCCESS SMBIOS table was parsed and installed.\r
1569 @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources.\r
1570 @retval EFI_INVALID_PARAMETER Smbios is not a correct smbios table\r
1571\r
1572**/\r
1573STATIC\r
1574EFI_STATUS\r
1575ParseAndAddExistingSmbiosTable (\r
1436aea4
MK
1576 IN EFI_HANDLE ImageHandle,\r
1577 IN SMBIOS_STRUCTURE_POINTER Smbios,\r
1578 IN UINTN Length\r
70e8c9c3
ZL
1579 )\r
1580{\r
1436aea4
MK
1581 EFI_STATUS Status;\r
1582 CHAR8 *String;\r
1583 EFI_SMBIOS_HANDLE SmbiosHandle;\r
1584 SMBIOS_STRUCTURE_POINTER SmbiosEnd;\r
70e8c9c3
ZL
1585\r
1586 SmbiosEnd.Raw = Smbios.Raw + Length;\r
1587\r
1436aea4 1588 if ((Smbios.Raw >= SmbiosEnd.Raw) || (Smbios.Raw == NULL)) {\r
70e8c9c3
ZL
1589 return EFI_INVALID_PARAMETER;\r
1590 }\r
1591\r
1592 do {\r
1593 //\r
1594 // Make sure not to access memory beyond SmbiosEnd\r
1595 //\r
1436aea4
MK
1596 if ((Smbios.Raw + sizeof (SMBIOS_STRUCTURE) > SmbiosEnd.Raw) ||\r
1597 (Smbios.Raw + sizeof (SMBIOS_STRUCTURE) < Smbios.Raw))\r
1598 {\r
70e8c9c3
ZL
1599 return EFI_INVALID_PARAMETER;\r
1600 }\r
1436aea4 1601\r
70e8c9c3
ZL
1602 //\r
1603 // Check for end marker\r
1604 //\r
1605 if (Smbios.Hdr->Type == SMBIOS_TYPE_END_OF_TABLE) {\r
1606 break;\r
1607 }\r
1436aea4 1608\r
70e8c9c3
ZL
1609 //\r
1610 // Make sure not to access memory beyond SmbiosEnd\r
1611 // Each structure shall be terminated by a double-null (0000h).\r
1612 //\r
1436aea4
MK
1613 if ((Smbios.Raw + Smbios.Hdr->Length + 2 * sizeof (UINT8) > SmbiosEnd.Raw) ||\r
1614 (Smbios.Raw + Smbios.Hdr->Length + 2 * sizeof (UINT8) < Smbios.Raw))\r
1615 {\r
70e8c9c3
ZL
1616 return EFI_INVALID_PARAMETER;\r
1617 }\r
1436aea4 1618\r
70e8c9c3
ZL
1619 //\r
1620 // Install the table\r
1621 //\r
1622 SmbiosHandle = Smbios.Hdr->Handle;\r
1436aea4
MK
1623 Status = SmbiosAdd (\r
1624 &mPrivateData.Smbios,\r
1625 ImageHandle,\r
1626 &SmbiosHandle,\r
1627 Smbios.Hdr\r
1628 );\r
70e8c9c3
ZL
1629\r
1630 ASSERT_EFI_ERROR (Status);\r
1631 if (EFI_ERROR (Status)) {\r
1632 return Status;\r
1633 }\r
1436aea4 1634\r
70e8c9c3
ZL
1635 //\r
1636 // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts:\r
1637 // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed\r
1638 // to skip one SMBIOS structure.\r
1639 //\r
1640\r
1641 //\r
1642 // Step 1: Skip over formatted section.\r
1643 //\r
1436aea4 1644 String = (CHAR8 *)(Smbios.Raw + Smbios.Hdr->Length);\r
70e8c9c3
ZL
1645\r
1646 //\r
1647 // Step 2: Skip over unformatted string section.\r
1648 //\r
1649 do {\r
1650 //\r
1651 // Each string is terminated with a NULL(00h) BYTE and the sets of strings\r
1652 // is terminated with an additional NULL(00h) BYTE.\r
1653 //\r
1654 for ( ; *String != 0; String++) {\r
1436aea4 1655 if ((UINTN)String >= (UINTN)SmbiosEnd.Raw - sizeof (UINT8)) {\r
70e8c9c3
ZL
1656 return EFI_INVALID_PARAMETER;\r
1657 }\r
1658 }\r
1659\r
1436aea4 1660 if (*(UINT8 *)++String == 0) {\r
70e8c9c3
ZL
1661 //\r
1662 // Pointer to the next SMBIOS structure.\r
1663 //\r
1436aea4 1664 Smbios.Raw = (UINT8 *)++String;\r
70e8c9c3
ZL
1665 break;\r
1666 }\r
1667 } while (TRUE);\r
1668 } while (Smbios.Raw < SmbiosEnd.Raw);\r
1669\r
1670 return EFI_SUCCESS;\r
1671}\r
1672\r
1673/**\r
1674 Retrieve SMBIOS from Hob.\r
1675 @param ImageHandle Module's image handle\r
1676\r
1677 @retval EFI_SUCCESS Smbios from Hob is installed.\r
1678 @return EFI_NOT_FOUND Not found Smbios from Hob.\r
1679 @retval Other No Smbios from Hob is installed.\r
1680\r
1681**/\r
1682EFI_STATUS\r
1683RetrieveSmbiosFromHob (\r
1436aea4 1684 IN EFI_HANDLE ImageHandle\r
70e8c9c3
ZL
1685 )\r
1686{\r
1436aea4
MK
1687 EFI_STATUS Status;\r
1688 UINTN Index;\r
1689 SMBIOS_STRUCTURE_POINTER Smbios;\r
1690 EFI_HOB_GUID_TYPE *GuidHob;\r
1691 UNIVERSAL_PAYLOAD_SMBIOS_TABLE *SmBiosTableAdress;\r
1692 UNIVERSAL_PAYLOAD_GENERIC_HEADER *GenericHeader;\r
1693 VOID *TableAddress;\r
1694 UINTN TableMaximumSize;\r
70e8c9c3
ZL
1695\r
1696 Status = EFI_NOT_FOUND;\r
1697\r
1698 for (Index = 0; Index < ARRAY_SIZE (mIsSmbiosTableValid); Index++) {\r
1699 GuidHob = GetFirstGuidHob (mIsSmbiosTableValid[Index].Guid);\r
1700 if (GuidHob == NULL) {\r
1701 continue;\r
1702 }\r
1436aea4
MK
1703\r
1704 GenericHeader = (UNIVERSAL_PAYLOAD_GENERIC_HEADER *)GET_GUID_HOB_DATA (GuidHob);\r
70e8c9c3
ZL
1705 if ((sizeof (UNIVERSAL_PAYLOAD_GENERIC_HEADER) <= GET_GUID_HOB_DATA_SIZE (GuidHob)) && (GenericHeader->Length <= GET_GUID_HOB_DATA_SIZE (GuidHob))) {\r
1706 if (GenericHeader->Revision == UNIVERSAL_PAYLOAD_SMBIOS_TABLE_REVISION) {\r
1707 //\r
1708 // UNIVERSAL_PAYLOAD_SMBIOS_TABLE structure is used when Revision equals to UNIVERSAL_PAYLOAD_SMBIOS_TABLE_REVISION\r
1709 //\r
1436aea4 1710 SmBiosTableAdress = (UNIVERSAL_PAYLOAD_SMBIOS_TABLE *)GET_GUID_HOB_DATA (GuidHob);\r
70e8c9c3 1711 if (GenericHeader->Length >= UNIVERSAL_PAYLOAD_SIZEOF_THROUGH_FIELD (UNIVERSAL_PAYLOAD_SMBIOS_TABLE, SmBiosEntryPoint)) {\r
1436aea4 1712 if (mIsSmbiosTableValid[Index].IsValid ((VOID *)(UINTN)SmBiosTableAdress->SmBiosEntryPoint, &TableAddress, &TableMaximumSize)) {\r
70e8c9c3 1713 Smbios.Raw = TableAddress;\r
1436aea4 1714 Status = ParseAndAddExistingSmbiosTable (ImageHandle, Smbios, TableMaximumSize);\r
70e8c9c3
ZL
1715 if (EFI_ERROR (Status)) {\r
1716 DEBUG ((DEBUG_ERROR, "RetrieveSmbiosFromHob: Failed to parse preinstalled tables from Guid Hob\n"));\r
1717 Status = EFI_UNSUPPORTED;\r
1718 } else {\r
1719 return EFI_SUCCESS;\r
1720 }\r
1721 }\r
1722 }\r
1723 }\r
1724 }\r
1725 }\r
1436aea4 1726\r
70e8c9c3
ZL
1727 return Status;\r
1728}\r
1729\r
310b04e6 1730/**\r
1731\r
d1102dba 1732 Driver to produce Smbios protocol and pre-allocate 1 page for the final SMBIOS table.\r
310b04e6 1733\r
1734 @param ImageHandle Module's image handle\r
1735 @param SystemTable Pointer of EFI_SYSTEM_TABLE\r
1736\r
1737 @retval EFI_SUCCESS Smbios protocol installed\r
1738 @retval Other No protocol installed, unload driver.\r
1739\r
1740**/\r
1741EFI_STATUS\r
1742EFIAPI\r
1743SmbiosDriverEntryPoint (\r
1436aea4
MK
1744 IN EFI_HANDLE ImageHandle,\r
1745 IN EFI_SYSTEM_TABLE *SystemTable\r
310b04e6 1746 )\r
1747{\r
1436aea4 1748 EFI_STATUS Status;\r
310b04e6 1749\r
1436aea4
MK
1750 mPrivateData.Signature = SMBIOS_INSTANCE_SIGNATURE;\r
1751 mPrivateData.Smbios.Add = SmbiosAdd;\r
1752 mPrivateData.Smbios.UpdateString = SmbiosUpdateString;\r
1753 mPrivateData.Smbios.Remove = SmbiosRemove;\r
1754 mPrivateData.Smbios.GetNext = SmbiosGetNext;\r
1755 mPrivateData.Smbios.MajorVersion = (UINT8)(PcdGet16 (PcdSmbiosVersion) >> 8);\r
1756 mPrivateData.Smbios.MinorVersion = (UINT8)(PcdGet16 (PcdSmbiosVersion) & 0x00ff);\r
310b04e6 1757\r
1758 InitializeListHead (&mPrivateData.DataListHead);\r
1759 InitializeListHead (&mPrivateData.AllocatedHandleListHead);\r
1760 EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);\r
d1102dba 1761\r
310b04e6 1762 //\r
1763 // Make a new handle and install the protocol\r
1764 //\r
1765 mPrivateData.Handle = NULL;\r
1436aea4
MK
1766 Status = gBS->InstallProtocolInterface (\r
1767 &mPrivateData.Handle,\r
1768 &gEfiSmbiosProtocolGuid,\r
1769 EFI_NATIVE_INTERFACE,\r
1770 &mPrivateData.Smbios\r
1771 );\r
310b04e6 1772\r
70e8c9c3 1773 RetrieveSmbiosFromHob (ImageHandle);\r
310b04e6 1774 return Status;\r
1775}\r