]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[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
LG
4\r
5Copyright (c) 2009 - 2018, 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
17SMBIOS_INSTANCE mPrivateData;\r
18\r
e63f3308
EL
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
25SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure = NULL;\r
26SMBIOS_TABLE_ENTRY_POINT EntryPointStructureData = {\r
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
e63f3308
EL
102SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios30EntryPointStructure = NULL;\r
103SMBIOS_TABLE_3_0_ENTRY_POINT Smbios30EntryPointStructureData = {\r
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
310b04e6 151/**\r
152\r
0ddd8553 153 Get the full size of SMBIOS structure including optional strings that follow the formatted structure.\r
310b04e6 154\r
afe3969c 155 @param This The EFI_SMBIOS_PROTOCOL instance.\r
0ddd8553 156 @param Head Pointer to the beginning of SMBIOS structure.\r
310b04e6 157 @param Size The returned size.\r
158 @param NumberOfStrings The returned number of optional strings that follow the formatted structure.\r
159\r
160 @retval EFI_SUCCESS Size retured in Size.\r
0ddd8553 161 @retval EFI_INVALID_PARAMETER Input SMBIOS structure mal-formed or Size is NULL.\r
d1102dba 162\r
310b04e6 163**/\r
164EFI_STATUS\r
165EFIAPI\r
166GetSmbiosStructureSize (\r
afe3969c 167 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
310b04e6 168 IN EFI_SMBIOS_TABLE_HEADER *Head,\r
169 OUT UINTN *Size,\r
170 OUT UINTN *NumberOfStrings\r
171 )\r
172{\r
173 UINTN FullSize;\r
2d97e71f 174 UINTN StrLen;\r
4233bf70 175 UINTN MaxLen;\r
310b04e6 176 INT8* CharInStr;\r
d1102dba 177\r
310b04e6 178 if (Size == NULL || NumberOfStrings == NULL) {\r
179 return EFI_INVALID_PARAMETER;\r
180 }\r
181\r
182 FullSize = Head->Length;\r
183 CharInStr = (INT8*)Head + Head->Length;\r
184 *Size = FullSize;\r
185 *NumberOfStrings = 0;\r
186 StrLen = 0;\r
187 //\r
188 // look for the two consecutive zeros, check the string limit by the way.\r
189 //\r
d1102dba 190 while (*CharInStr != 0 || *(CharInStr+1) != 0) {\r
310b04e6 191 if (*CharInStr == 0) {\r
310b04e6 192 *Size += 1;\r
193 CharInStr++;\r
194 }\r
195\r
afe3969c 196 if (This->MajorVersion < 2 || (This->MajorVersion == 2 && This->MinorVersion < 7)){\r
4233bf70 197 MaxLen = SMBIOS_STRING_MAX_LENGTH;\r
e63f3308 198 } else if (This->MajorVersion < 3) {\r
afe3969c 199 //\r
4233bf70
SZ
200 // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.\r
201 // However, the length of the entire structure table (including all strings) must be reported\r
202 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,\r
203 // which is a WORD field limited to 65,535 bytes.\r
afe3969c 204 //\r
4233bf70 205 MaxLen = SMBIOS_TABLE_MAX_LENGTH;\r
e63f3308
EL
206 } else {\r
207 //\r
208 // SMBIOS 3.0 defines the Structure table maximum size as DWORD field limited to 0xFFFFFFFF bytes.\r
209 // Locate the end of string as long as possible.\r
210 //\r
211 MaxLen = SMBIOS_3_0_TABLE_MAX_LENGTH;\r
4233bf70
SZ
212 }\r
213\r
214 for (StrLen = 0 ; StrLen < MaxLen; StrLen++) {\r
215 if (*(CharInStr+StrLen) == 0) {\r
216 break;\r
afe3969c 217 }\r
310b04e6 218 }\r
afe3969c 219\r
4233bf70
SZ
220 if (StrLen == MaxLen) {\r
221 return EFI_INVALID_PARAMETER;\r
222 }\r
223\r
310b04e6 224 //\r
225 // forward the pointer\r
226 //\r
227 CharInStr += StrLen;\r
228 *Size += StrLen;\r
310b04e6 229 *NumberOfStrings += 1;\r
230 }\r
f8ee20c9 231\r
310b04e6 232 //\r
233 // count ending two zeros.\r
234 //\r
235 *Size += 2;\r
afe3969c 236 return EFI_SUCCESS;\r
310b04e6 237}\r
238\r
239/**\r
240\r
241 Determin whether an SmbiosHandle has already in use.\r
242\r
0ddd8553 243 @param Head Pointer to the beginning of SMBIOS structure.\r
310b04e6 244 @param Handle A unique handle will be assigned to the SMBIOS record.\r
245\r
246 @retval TRUE Smbios handle already in use.\r
247 @retval FALSE Smbios handle is NOT used.\r
d1102dba 248\r
310b04e6 249**/\r
250BOOLEAN\r
251EFIAPI\r
252CheckSmbiosHandleExistance (\r
253 IN LIST_ENTRY *Head,\r
254 IN EFI_SMBIOS_HANDLE Handle\r
255 )\r
256{\r
257 LIST_ENTRY *Link;\r
258 SMBIOS_HANDLE_ENTRY *HandleEntry;\r
d1102dba 259\r
310b04e6 260 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
261 HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK(Link);\r
262 if (HandleEntry->SmbiosHandle == Handle) {\r
263 return TRUE;\r
264 }\r
265 }\r
266\r
267 return FALSE;\r
268}\r
269\r
270/**\r
271\r
272 Get the max SmbiosHandle that could be use.\r
273\r
274 @param This The EFI_SMBIOS_PROTOCOL instance.\r
275 @param MaxHandle The max handle that could be assigned to the SMBIOS record.\r
276\r
277**/\r
278VOID\r
279EFIAPI\r
280GetMaxSmbiosHandle (\r
281 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
282 IN OUT EFI_SMBIOS_HANDLE *MaxHandle\r
d1102dba 283 )\r
310b04e6 284{\r
285 if (This->MajorVersion == 2 && This->MinorVersion == 0) {\r
286 *MaxHandle = 0xFFFE;\r
287 } else {\r
288 *MaxHandle = 0xFEFF;\r
289 }\r
290}\r
291\r
292/**\r
293\r
294 Get an SmbiosHandle that could use.\r
295\r
296 @param This The EFI_SMBIOS_PROTOCOL instance.\r
297 @param SmbiosHandle A unique handle will be assigned to the SMBIOS record.\r
298\r
299 @retval EFI_SUCCESS Smbios handle got.\r
300 @retval EFI_OUT_OF_RESOURCES Smbios handle is NOT available.\r
d1102dba 301\r
310b04e6 302**/\r
303EFI_STATUS\r
304EFIAPI\r
305GetAvailableSmbiosHandle (\r
306 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
307 IN OUT EFI_SMBIOS_HANDLE *Handle\r
308 )\r
309{\r
310 LIST_ENTRY *Head;\r
311 SMBIOS_INSTANCE *Private;\r
312 EFI_SMBIOS_HANDLE MaxSmbiosHandle;\r
313 EFI_SMBIOS_HANDLE AvailableHandle;\r
314\r
315 GetMaxSmbiosHandle(This, &MaxSmbiosHandle);\r
316\r
317 Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
318 Head = &Private->AllocatedHandleListHead;\r
4659816a 319 for (AvailableHandle = 0; AvailableHandle < MaxSmbiosHandle; AvailableHandle++) {\r
310b04e6 320 if (!CheckSmbiosHandleExistance(Head, AvailableHandle)) {\r
321 *Handle = AvailableHandle;\r
322 return EFI_SUCCESS;\r
323 }\r
324 }\r
325\r
326 return EFI_OUT_OF_RESOURCES;\r
327}\r
328\r
329\r
330/**\r
331 Add an SMBIOS record.\r
332\r
333 @param This The EFI_SMBIOS_PROTOCOL instance.\r
334 @param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL\r
335 means no handle.\r
4659816a
SZ
336 @param SmbiosHandle On entry, the handle of the SMBIOS record to add. If FFFEh, then a unique handle\r
337 will be assigned to the SMBIOS record. If the SMBIOS handle is already in use,\r
310b04e6 338 EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated.\r
339 @param Record The data for the fixed portion of the SMBIOS record. The format of the record is\r
d1102dba
LG
340 determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined\r
341 by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or\r
310b04e6 342 a set of null terminated strings and a null.\r
343\r
344 @retval EFI_SUCCESS Record was added.\r
345 @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources.\r
346 @retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use.\r
347\r
348**/\r
349EFI_STATUS\r
350EFIAPI\r
351SmbiosAdd (\r
352 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
353 IN EFI_HANDLE ProducerHandle, OPTIONAL\r
354 IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,\r
355 IN EFI_SMBIOS_TABLE_HEADER *Record\r
356 )\r
357{\r
358 VOID *Raw;\r
359 UINTN TotalSize;\r
360 UINTN RecordSize;\r
361 UINTN StructureSize;\r
362 UINTN NumberOfStrings;\r
363 EFI_STATUS Status;\r
364 LIST_ENTRY *Head;\r
365 SMBIOS_INSTANCE *Private;\r
366 EFI_SMBIOS_ENTRY *SmbiosEntry;\r
367 EFI_SMBIOS_HANDLE MaxSmbiosHandle;\r
368 SMBIOS_HANDLE_ENTRY *HandleEntry;\r
369 EFI_SMBIOS_RECORD_HEADER *InternalRecord;\r
e63f3308
EL
370 BOOLEAN Smbios32BitTable;\r
371 BOOLEAN Smbios64BitTable;\r
d1102dba 372\r
310b04e6 373 if (SmbiosHandle == NULL) {\r
374 return EFI_INVALID_PARAMETER;\r
375 }\r
d1102dba 376\r
310b04e6 377 Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
378 //\r
379 // Check whether SmbiosHandle is already in use\r
380 //\r
381 Head = &Private->AllocatedHandleListHead;\r
4659816a 382 if (*SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED && CheckSmbiosHandleExistance(Head, *SmbiosHandle)) {\r
310b04e6 383 return EFI_ALREADY_STARTED;\r
384 }\r
385\r
386 //\r
4659816a 387 // when SmbiosHandle is 0xFFFE, an available handle will be assigned\r
310b04e6 388 //\r
4659816a 389 if (*SmbiosHandle == SMBIOS_HANDLE_PI_RESERVED) {\r
310b04e6 390 Status = GetAvailableSmbiosHandle(This, SmbiosHandle);\r
391 if (EFI_ERROR(Status)) {\r
392 return Status;\r
393 }\r
394 } else {\r
395 //\r
396 // Check this handle validity\r
397 //\r
398 GetMaxSmbiosHandle(This, &MaxSmbiosHandle);\r
399 if (*SmbiosHandle > MaxSmbiosHandle) {\r
400 return EFI_INVALID_PARAMETER;\r
401 }\r
402 }\r
403\r
404 //\r
405 // Calculate record size and string number\r
406 //\r
afe3969c 407 Status = GetSmbiosStructureSize(This, Record, &StructureSize, &NumberOfStrings);\r
310b04e6 408 if (EFI_ERROR(Status)) {\r
409 return Status;\r
410 }\r
411\r
e63f3308
EL
412 Smbios32BitTable = FALSE;\r
413 Smbios64BitTable = FALSE;\r
d1102dba 414 if ((This->MajorVersion < 0x3) ||\r
e63f3308 415 ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) {\r
4233bf70 416 //\r
e63f3308 417 // For SMBIOS 32-bit table, the length of the entire structure table (including all strings) must be reported\r
4233bf70 418 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,\r
e63f3308
EL
419 // 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
420 //\r
d1102dba 421 if ((EntryPointStructure != NULL) &&\r
e63f3308
EL
422 (EntryPointStructure->TableLength + StructureSize > SMBIOS_TABLE_MAX_LENGTH)) {\r
423 DEBUG ((EFI_D_INFO, "SmbiosAdd: Total length exceeds max 32-bit table length with type = %d size = 0x%x\n", Record->Type, StructureSize));\r
424 } else {\r
425 Smbios32BitTable = TRUE;\r
426 DEBUG ((EFI_D_INFO, "SmbiosAdd: Smbios type %d with size 0x%x is added to 32-bit table\n", Record->Type, StructureSize));\r
427 }\r
428 }\r
d1102dba 429\r
e63f3308
EL
430 //\r
431 // For SMBIOS 3.0, Structure table maximum size in Entry Point structure is DWORD field limited to 0xFFFFFFFF bytes.\r
432 //\r
433 if ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) {\r
434 //\r
435 // For SMBIOS 64-bit table, Structure table maximum size in SMBIOS 3.0 (64-bit) Entry Point\r
436 // is a DWORD field limited to 0xFFFFFFFF bytes. So the max size of 64-bit table should not exceed 0xFFFFFFFF bytes.\r
437 //\r
d1102dba 438 if ((Smbios30EntryPointStructure != NULL) &&\r
e63f3308
EL
439 (Smbios30EntryPointStructure->TableMaximumSize + StructureSize > SMBIOS_3_0_TABLE_MAX_LENGTH)) {\r
440 DEBUG ((EFI_D_INFO, "SmbiosAdd: Total length exceeds max 64-bit table length with type = %d size = 0x%x\n", Record->Type, StructureSize));\r
441 } else {\r
442 DEBUG ((EFI_D_INFO, "SmbiosAdd: Smbios type %d with size 0x%x is added to 64-bit table\n", Record->Type, StructureSize));\r
443 Smbios64BitTable = TRUE;\r
444 }\r
445 }\r
446\r
447 if ((!Smbios32BitTable) && (!Smbios64BitTable)) {\r
448 //\r
449 // If both 32-bit and 64-bit table are not updated, quit\r
4233bf70
SZ
450 //\r
451 return EFI_OUT_OF_RESOURCES;\r
452 }\r
453\r
310b04e6 454 //\r
455 // Enter into critical section\r
d1102dba 456 //\r
310b04e6 457 Status = EfiAcquireLockOrFail (&Private->DataLock);\r
458 if (EFI_ERROR (Status)) {\r
459 return Status;\r
460 }\r
d1102dba 461\r
310b04e6 462 RecordSize = sizeof (EFI_SMBIOS_RECORD_HEADER) + StructureSize;\r
463 TotalSize = sizeof (EFI_SMBIOS_ENTRY) + RecordSize;\r
464\r
465 //\r
466 // Allocate internal buffer\r
467 //\r
0d34b1cf 468 SmbiosEntry = AllocateZeroPool (TotalSize);\r
310b04e6 469 if (SmbiosEntry == NULL) {\r
470 EfiReleaseLock (&Private->DataLock);\r
471 return EFI_OUT_OF_RESOURCES;\r
472 }\r
0d34b1cf 473 HandleEntry = AllocateZeroPool (sizeof(SMBIOS_HANDLE_ENTRY));\r
310b04e6 474 if (HandleEntry == NULL) {\r
475 EfiReleaseLock (&Private->DataLock);\r
476 return EFI_OUT_OF_RESOURCES;\r
477 }\r
478\r
479 //\r
480 // Build Handle Entry and insert into linked list\r
481 //\r
310b04e6 482 HandleEntry->Signature = SMBIOS_HANDLE_ENTRY_SIGNATURE;\r
483 HandleEntry->SmbiosHandle = *SmbiosHandle;\r
484 InsertTailList(&Private->AllocatedHandleListHead, &HandleEntry->Link);\r
485\r
310b04e6 486 InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (SmbiosEntry + 1);\r
487 Raw = (VOID *) (InternalRecord + 1);\r
488\r
489 //\r
490 // Build internal record Header\r
491 //\r
492 InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;\r
c9325700 493 InternalRecord->HeaderSize = (UINT16) sizeof (EFI_SMBIOS_RECORD_HEADER);\r
310b04e6 494 InternalRecord->RecordSize = RecordSize;\r
495 InternalRecord->ProducerHandle = ProducerHandle;\r
496 InternalRecord->NumberOfStrings = NumberOfStrings;\r
497 //\r
498 // Insert record into the internal linked list\r
499 //\r
500 SmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;\r
501 SmbiosEntry->RecordHeader = InternalRecord;\r
502 SmbiosEntry->RecordSize = TotalSize;\r
e63f3308
EL
503 SmbiosEntry->Smbios32BitTable = Smbios32BitTable;\r
504 SmbiosEntry->Smbios64BitTable = Smbios64BitTable;\r
310b04e6 505 InsertTailList (&Private->DataListHead, &SmbiosEntry->Link);\r
506\r
507 CopyMem (Raw, Record, StructureSize);\r
508 ((EFI_SMBIOS_TABLE_HEADER*)Raw)->Handle = *SmbiosHandle;\r
509\r
0ddd8553 510 //\r
511 // Some UEFI drivers (such as network) need some information in SMBIOS table.\r
512 // Here we create SMBIOS table and publish it in\r
513 // configuration table, so other UEFI drivers can get SMBIOS table from\r
514 // configuration table without depending on PI SMBIOS protocol.\r
515 //\r
e63f3308 516 SmbiosTableConstruction (Smbios32BitTable, Smbios64BitTable);\r
d1102dba 517\r
310b04e6 518 //\r
519 // Leave critical section\r
520 //\r
521 EfiReleaseLock (&Private->DataLock);\r
522 return EFI_SUCCESS;\r
523}\r
524\r
525/**\r
526 Update the string associated with an existing SMBIOS record.\r
527\r
528 @param This The EFI_SMBIOS_PROTOCOL instance.\r
529 @param SmbiosHandle SMBIOS Handle of structure that will have its string updated.\r
530 @param StringNumber The non-zero string number of the string to update\r
531 @param String Update the StringNumber string with String.\r
532\r
533 @retval EFI_SUCCESS SmbiosHandle had its StringNumber String updated.\r
534 @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist.\r
4659816a 535 @retval EFI_UNSUPPORTED String was not added because it is longer than the SMBIOS Table supports.\r
310b04e6 536 @retval EFI_NOT_FOUND The StringNumber.is not valid for this SMBIOS record.\r
537\r
538**/\r
539EFI_STATUS\r
540EFIAPI\r
541SmbiosUpdateString (\r
542 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
543 IN EFI_SMBIOS_HANDLE *SmbiosHandle,\r
544 IN UINTN *StringNumber,\r
545 IN CHAR8 *String\r
546 )\r
547{\r
548 UINTN InputStrLen;\r
549 UINTN TargetStrLen;\r
550 UINTN StrIndex;\r
551 UINTN TargetStrOffset;\r
552 UINTN NewEntrySize;\r
553 CHAR8 *StrStart;\r
554 VOID *Raw;\r
555 LIST_ENTRY *Link;\r
556 LIST_ENTRY *Head;\r
557 EFI_STATUS Status;\r
558 SMBIOS_INSTANCE *Private;\r
559 EFI_SMBIOS_ENTRY *SmbiosEntry;\r
560 EFI_SMBIOS_ENTRY *ResizedSmbiosEntry;\r
561 EFI_SMBIOS_HANDLE MaxSmbiosHandle;\r
562 EFI_SMBIOS_TABLE_HEADER *Record;\r
563 EFI_SMBIOS_RECORD_HEADER *InternalRecord;\r
d1102dba 564\r
310b04e6 565 //\r
566 // Check args validity\r
567 //\r
568 GetMaxSmbiosHandle(This, &MaxSmbiosHandle);\r
569\r
570 if (*SmbiosHandle > MaxSmbiosHandle) {\r
571 return EFI_INVALID_PARAMETER;\r
572 }\r
573\r
574 if (String == NULL) {\r
575 return EFI_ABORTED;\r
576 }\r
577\r
578 if (*StringNumber == 0) {\r
579 return EFI_NOT_FOUND;\r
580 }\r
581\r
582 InputStrLen = AsciiStrLen(String);\r
afe3969c 583\r
afe3969c
SZ
584 if (This->MajorVersion < 2 || (This->MajorVersion == 2 && This->MinorVersion < 7)) {\r
585 if (InputStrLen > SMBIOS_STRING_MAX_LENGTH) {\r
586 return EFI_UNSUPPORTED;\r
587 }\r
e63f3308 588 } else if (This->MajorVersion < 3) {\r
4233bf70
SZ
589 //\r
590 // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.\r
d1102dba 591 // However, the length of the entire structure table (including all strings) must be reported\r
4233bf70
SZ
592 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,\r
593 // which is a WORD field limited to 65,535 bytes.\r
594 //\r
595 if (InputStrLen > SMBIOS_TABLE_MAX_LENGTH) {\r
596 return EFI_UNSUPPORTED;\r
597 }\r
e63f3308
EL
598 } else {\r
599 if (InputStrLen > SMBIOS_3_0_TABLE_MAX_LENGTH) {\r
600 //\r
601 // SMBIOS 3.0 defines the Structure table maximum size as DWORD field limited to 0xFFFFFFFF bytes.\r
602 // The input string length should not exceed 0xFFFFFFFF bytes.\r
d1102dba 603 //\r
e63f3308
EL
604 return EFI_UNSUPPORTED;\r
605 }\r
310b04e6 606 }\r
607\r
608 Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
609 //\r
610 // Enter into critical section\r
d1102dba 611 //\r
310b04e6 612 Status = EfiAcquireLockOrFail (&Private->DataLock);\r
613 if (EFI_ERROR (Status)) {\r
614 return Status;\r
615 }\r
616\r
617 Head = &Private->DataListHead;\r
618 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
619 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);\r
620 Record = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);\r
621\r
afe3969c 622 if (Record->Handle == *SmbiosHandle) {\r
310b04e6 623 //\r
0ddd8553 624 // Find out the specified SMBIOS record\r
310b04e6 625 //\r
626 if (*StringNumber > SmbiosEntry->RecordHeader->NumberOfStrings) {\r
627 EfiReleaseLock (&Private->DataLock);\r
628 return EFI_NOT_FOUND;\r
629 }\r
630 //\r
631 // Point to unformed string section\r
632 //\r
afe3969c 633 StrStart = (CHAR8 *) Record + Record->Length;\r
d1102dba 634\r
310b04e6 635 for (StrIndex = 1, TargetStrOffset = 0; StrIndex < *StringNumber; StrStart++, TargetStrOffset++) {\r
636 //\r
637 // A string ends in 00h\r
638 //\r
639 if (*StrStart == 0) {\r
640 StrIndex++;\r
641 }\r
d1102dba 642\r
310b04e6 643 //\r
644 // String section ends in double-null (0000h)\r
645 //\r
646 if (*StrStart == 0 && *(StrStart + 1) == 0) {\r
647 EfiReleaseLock (&Private->DataLock);\r
648 return EFI_NOT_FOUND;\r
d1102dba 649 }\r
310b04e6 650 }\r
651\r
f8ee20c9 652 if (*StrStart == 0) {\r
afe3969c
SZ
653 StrStart++;\r
654 TargetStrOffset++;\r
f8ee20c9 655 }\r
d1102dba 656\r
310b04e6 657 //\r
658 // Now we get the string target\r
659 //\r
660 TargetStrLen = AsciiStrLen(StrStart);\r
661 if (InputStrLen == TargetStrLen) {\r
5e4b8bfe 662 AsciiStrCpyS(StrStart, TargetStrLen + 1, String);\r
0ddd8553 663 //\r
664 // Some UEFI drivers (such as network) need some information in SMBIOS table.\r
665 // Here we create SMBIOS table and publish it in\r
666 // configuration table, so other UEFI drivers can get SMBIOS table from\r
667 // configuration table without depending on PI SMBIOS protocol.\r
668 //\r
e63f3308 669 SmbiosTableConstruction (SmbiosEntry->Smbios32BitTable, SmbiosEntry->Smbios64BitTable);\r
310b04e6 670 EfiReleaseLock (&Private->DataLock);\r
671 return EFI_SUCCESS;\r
672 }\r
d1102dba 673\r
e63f3308
EL
674 SmbiosEntry->Smbios32BitTable = FALSE;\r
675 SmbiosEntry->Smbios64BitTable = FALSE;\r
d1102dba 676 if ((This->MajorVersion < 0x3) ||\r
e63f3308
EL
677 ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) {\r
678 //\r
679 // 32-bit table is produced, check the valid length.\r
680 //\r
d1102dba 681 if ((EntryPointStructure != NULL) &&\r
e63f3308
EL
682 (EntryPointStructure->TableLength + InputStrLen - TargetStrLen > SMBIOS_TABLE_MAX_LENGTH)) {\r
683 //\r
684 // The length of the entire structure table (including all strings) must be reported\r
685 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,\r
686 // which is a WORD field limited to 65,535 bytes.\r
687 //\r
688 DEBUG ((EFI_D_INFO, "SmbiosUpdateString: Total length exceeds max 32-bit table length\n"));\r
689 } else {\r
690 DEBUG ((EFI_D_INFO, "SmbiosUpdateString: New smbios record add to 32-bit table\n"));\r
691 SmbiosEntry->Smbios32BitTable = TRUE;\r
692 }\r
d1102dba 693 }\r
310b04e6 694\r
e63f3308 695 if ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) {\r
4233bf70 696 //\r
e63f3308 697 // 64-bit table is produced, check the valid length.\r
4233bf70 698 //\r
d1102dba 699 if ((Smbios30EntryPointStructure != NULL) &&\r
e63f3308
EL
700 (Smbios30EntryPointStructure->TableMaximumSize + InputStrLen - TargetStrLen > SMBIOS_3_0_TABLE_MAX_LENGTH)) {\r
701 DEBUG ((EFI_D_INFO, "SmbiosUpdateString: Total length exceeds max 64-bit table length\n"));\r
702 } else {\r
703 DEBUG ((EFI_D_INFO, "SmbiosUpdateString: New smbios record add to 64-bit table\n"));\r
704 SmbiosEntry->Smbios64BitTable = TRUE;\r
705 }\r
706 }\r
707\r
708 if ((!SmbiosEntry->Smbios32BitTable) && (!SmbiosEntry->Smbios64BitTable)) {\r
709 EfiReleaseLock (&Private->DataLock);\r
4233bf70
SZ
710 return EFI_UNSUPPORTED;\r
711 }\r
712\r
310b04e6 713 //\r
714 // Original string buffer size is not exactly match input string length.\r
715 // Re-allocate buffer is needed.\r
716 //\r
717 NewEntrySize = SmbiosEntry->RecordSize + InputStrLen - TargetStrLen;\r
0d34b1cf 718 ResizedSmbiosEntry = AllocateZeroPool (NewEntrySize);\r
310b04e6 719\r
720 if (ResizedSmbiosEntry == NULL) {\r
721 EfiReleaseLock (&Private->DataLock);\r
722 return EFI_OUT_OF_RESOURCES;\r
723 }\r
724\r
310b04e6 725 InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (ResizedSmbiosEntry + 1);\r
726 Raw = (VOID *) (InternalRecord + 1);\r
727\r
728 //\r
729 // Build internal record Header\r
730 //\r
731 InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;\r
c9325700 732 InternalRecord->HeaderSize = (UINT16) sizeof (EFI_SMBIOS_RECORD_HEADER);\r
310b04e6 733 InternalRecord->RecordSize = SmbiosEntry->RecordHeader->RecordSize + InputStrLen - TargetStrLen;\r
734 InternalRecord->ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;\r
735 InternalRecord->NumberOfStrings = SmbiosEntry->RecordHeader->NumberOfStrings;\r
736\r
737 //\r
0ddd8553 738 // Copy SMBIOS structure and optional strings.\r
310b04e6 739 //\r
f8ee20c9 740 CopyMem (Raw, SmbiosEntry->RecordHeader + 1, Record->Length + TargetStrOffset);\r
741 CopyMem ((VOID*)((UINTN)Raw + Record->Length + TargetStrOffset), String, InputStrLen + 1);\r
742 CopyMem ((CHAR8*)((UINTN)Raw + Record->Length + TargetStrOffset + InputStrLen + 1),\r
743 (CHAR8*)Record + Record->Length + TargetStrOffset + TargetStrLen + 1,\r
744 SmbiosEntry->RecordHeader->RecordSize - sizeof (EFI_SMBIOS_RECORD_HEADER) - Record->Length - TargetStrOffset - TargetStrLen - 1);\r
310b04e6 745\r
746 //\r
747 // Insert new record\r
748 //\r
749 ResizedSmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;\r
750 ResizedSmbiosEntry->RecordHeader = InternalRecord;\r
751 ResizedSmbiosEntry->RecordSize = NewEntrySize;\r
e63f3308
EL
752 ResizedSmbiosEntry->Smbios32BitTable = SmbiosEntry->Smbios32BitTable;\r
753 ResizedSmbiosEntry->Smbios64BitTable = SmbiosEntry->Smbios64BitTable;\r
310b04e6 754 InsertTailList (Link->ForwardLink, &ResizedSmbiosEntry->Link);\r
755\r
756 //\r
757 // Remove old record\r
758 //\r
759 RemoveEntryList(Link);\r
760 FreePool(SmbiosEntry);\r
0ddd8553 761 //\r
762 // Some UEFI drivers (such as network) need some information in SMBIOS table.\r
763 // Here we create SMBIOS table and publish it in\r
764 // configuration table, so other UEFI drivers can get SMBIOS table from\r
765 // configuration table without depending on PI SMBIOS protocol.\r
766 //\r
e63f3308 767 SmbiosTableConstruction (ResizedSmbiosEntry->Smbios32BitTable, ResizedSmbiosEntry->Smbios64BitTable);\r
310b04e6 768 EfiReleaseLock (&Private->DataLock);\r
769 return EFI_SUCCESS;\r
770 }\r
771 }\r
772\r
773 EfiReleaseLock (&Private->DataLock);\r
774 return EFI_INVALID_PARAMETER;\r
775}\r
776\r
777/**\r
778 Remove an SMBIOS record.\r
779\r
780 @param This The EFI_SMBIOS_PROTOCOL instance.\r
781 @param SmbiosHandle The handle of the SMBIOS record to remove.\r
782\r
783 @retval EFI_SUCCESS SMBIOS record was removed.\r
784 @retval EFI_INVALID_PARAMETER SmbiosHandle does not specify a valid SMBIOS record.\r
785\r
786**/\r
787EFI_STATUS\r
788EFIAPI\r
789SmbiosRemove (\r
790 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
791 IN EFI_SMBIOS_HANDLE SmbiosHandle\r
792 )\r
793{\r
794 LIST_ENTRY *Link;\r
795 LIST_ENTRY *Head;\r
796 EFI_STATUS Status;\r
797 EFI_SMBIOS_HANDLE MaxSmbiosHandle;\r
798 SMBIOS_INSTANCE *Private;\r
799 EFI_SMBIOS_ENTRY *SmbiosEntry;\r
800 SMBIOS_HANDLE_ENTRY *HandleEntry;\r
801 EFI_SMBIOS_TABLE_HEADER *Record;\r
802\r
803 //\r
804 // Check args validity\r
805 //\r
806 GetMaxSmbiosHandle(This, &MaxSmbiosHandle);\r
807\r
808 if (SmbiosHandle > MaxSmbiosHandle) {\r
809 return EFI_INVALID_PARAMETER;\r
810 }\r
811\r
812 Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
813 //\r
814 // Enter into critical section\r
d1102dba 815 //\r
310b04e6 816 Status = EfiAcquireLockOrFail (&Private->DataLock);\r
817 if (EFI_ERROR (Status)) {\r
818 return Status;\r
819 }\r
820\r
821 Head = &Private->DataListHead;\r
822 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
823 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);\r
824 Record = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);\r
afe3969c 825 if (Record->Handle == SmbiosHandle) {\r
310b04e6 826 //\r
827 // Remove specified smobios record from DataList\r
828 //\r
829 RemoveEntryList(Link);\r
d1102dba 830 //\r
310b04e6 831 // Remove this handle from AllocatedHandleList\r
832 //\r
833 Head = &Private->AllocatedHandleListHead;\r
834 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
835 HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK(Link);\r
afe3969c 836 if (HandleEntry->SmbiosHandle == SmbiosHandle) {\r
310b04e6 837 RemoveEntryList(Link);\r
838 FreePool(HandleEntry);\r
839 break;\r
840 }\r
841 }\r
0ddd8553 842 //\r
843 // Some UEFI drivers (such as network) need some information in SMBIOS table.\r
844 // Here we create SMBIOS table and publish it in\r
845 // configuration table, so other UEFI drivers can get SMBIOS table from\r
846 // configuration table without depending on PI SMBIOS protocol.\r
847 //\r
e63f3308
EL
848 if (SmbiosEntry->Smbios32BitTable) {\r
849 DEBUG ((EFI_D_INFO, "SmbiosRemove: remove from 32-bit table\n"));\r
850 }\r
851 if (SmbiosEntry->Smbios64BitTable) {\r
852 DEBUG ((EFI_D_INFO, "SmbiosRemove: remove from 64-bit table\n"));\r
853 }\r
854 //\r
855 // Update the whole SMBIOS table again based on which table the removed SMBIOS record is in.\r
856 //\r
857 SmbiosTableConstruction (SmbiosEntry->Smbios32BitTable, SmbiosEntry->Smbios64BitTable);\r
858 FreePool(SmbiosEntry);\r
310b04e6 859 EfiReleaseLock (&Private->DataLock);\r
860 return EFI_SUCCESS;\r
861 }\r
862 }\r
863\r
864 //\r
865 // Leave critical section\r
866 //\r
867 EfiReleaseLock (&Private->DataLock);\r
868 return EFI_INVALID_PARAMETER;\r
d1102dba 869\r
310b04e6 870}\r
871\r
872/**\r
873 Allow the caller to discover all or some of the SMBIOS records.\r
874\r
875 @param This The EFI_SMBIOS_PROTOCOL instance.\r
876 @param SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the\r
4659816a
SZ
877 next SMBIOS record handle. If it is FFFEh on entry, then the first SMBIOS record\r
878 handle will be returned. If it returns FFFEh on exit, then there are no more SMBIOS records.\r
d1102dba 879 @param Type On entry it means return the next SMBIOS record of type Type. If a NULL is passed in\r
310b04e6 880 this functionally it ignored. Type is not modified by the GetNext() function.\r
881 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by\r
882 the unformatted area. The unformatted area optionally contains text strings.\r
d1102dba
LG
883 @param ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no ProducerHandle was passed into Add() NULL is returned.\r
884 If a NULL pointer is passed in no data will be returned\r
885\r
310b04e6 886 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.\r
310b04e6 887 @retval EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record.\r
888\r
889**/\r
890EFI_STATUS\r
891EFIAPI\r
892SmbiosGetNext (\r
893 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
894 IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,\r
895 IN EFI_SMBIOS_TYPE *Type, OPTIONAL\r
896 OUT EFI_SMBIOS_TABLE_HEADER **Record,\r
897 OUT EFI_HANDLE *ProducerHandle OPTIONAL\r
898 )\r
899{\r
900 BOOLEAN StartPointFound;\r
901 LIST_ENTRY *Link;\r
902 LIST_ENTRY *Head;\r
903 SMBIOS_INSTANCE *Private;\r
904 EFI_SMBIOS_ENTRY *SmbiosEntry;\r
905 EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader;\r
906\r
907 if (SmbiosHandle == NULL) {\r
908 return EFI_INVALID_PARAMETER;\r
909 }\r
910\r
911 StartPointFound = FALSE;\r
912 Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
913 Head = &Private->DataListHead;\r
914 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
915 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);\r
d1102dba 916 SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);\r
310b04e6 917\r
918 //\r
4659816a 919 // If SmbiosHandle is 0xFFFE, the first matched SMBIOS record handle will be returned\r
310b04e6 920 //\r
4659816a 921 if (*SmbiosHandle == SMBIOS_HANDLE_PI_RESERVED) {\r
310b04e6 922 if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {\r
d1102dba 923 continue;\r
310b04e6 924 }\r
925\r
926 *SmbiosHandle = SmbiosTableHeader->Handle;\r
927 *Record =SmbiosTableHeader;\r
928 if (ProducerHandle != NULL) {\r
929 *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;\r
930 }\r
931 return EFI_SUCCESS;\r
932 }\r
933\r
934 //\r
0ddd8553 935 // Start this round search from the next SMBIOS handle\r
310b04e6 936 //\r
937 if (!StartPointFound && (*SmbiosHandle == SmbiosTableHeader->Handle)) {\r
938 StartPointFound = TRUE;\r
939 continue;\r
940 }\r
941\r
942 if (StartPointFound) {\r
943 if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {\r
d1102dba 944 continue;\r
310b04e6 945 }\r
d1102dba 946\r
310b04e6 947 *SmbiosHandle = SmbiosTableHeader->Handle;\r
d1102dba 948 *Record = SmbiosTableHeader;\r
310b04e6 949 if (ProducerHandle != NULL) {\r
950 *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;\r
951 }\r
952\r
d1102dba 953 return EFI_SUCCESS;\r
310b04e6 954 }\r
955 }\r
956\r
4659816a 957 *SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;\r
310b04e6 958 return EFI_NOT_FOUND;\r
d1102dba 959\r
310b04e6 960}\r
961\r
0ddd8553 962/**\r
963 Allow the caller to discover all of the SMBIOS records.\r
964\r
965 @param This The EFI_SMBIOS_PROTOCOL instance.\r
d1102dba
LG
966 @param CurrentSmbiosEntry On exit, points to the SMBIOS entry on the list which includes the returned SMBIOS record information.\r
967 If *CurrentSmbiosEntry is NULL on entry, then the first SMBIOS entry on the list will be returned.\r
0ddd8553 968 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by\r
969 the unformatted area. The unformatted area optionally contains text strings.\r
d1102dba 970\r
0ddd8553 971 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.\r
972 *CurrentSmbiosEntry points to the SMBIOS entry which includes the returned SMBIOS record information.\r
973 @retval EFI_NOT_FOUND There is no more SMBIOS entry.\r
974\r
975**/\r
976EFI_STATUS\r
977EFIAPI\r
978GetNextSmbiosRecord (\r
979 IN CONST EFI_SMBIOS_PROTOCOL *This,\r
980 IN OUT EFI_SMBIOS_ENTRY **CurrentSmbiosEntry,\r
981 OUT EFI_SMBIOS_TABLE_HEADER **Record\r
982 )\r
983{\r
984 LIST_ENTRY *Link;\r
985 LIST_ENTRY *Head;\r
986 SMBIOS_INSTANCE *Private;\r
987 EFI_SMBIOS_ENTRY *SmbiosEntry;\r
988 EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader;\r
989\r
990 Private = SMBIOS_INSTANCE_FROM_THIS (This);\r
991 if (*CurrentSmbiosEntry == NULL) {\r
992 //\r
993 // Get the beginning of SMBIOS entry.\r
994 //\r
995 Head = &Private->DataListHead;\r
996 } else {\r
997 //\r
998 // Get previous SMBIOS entry and make it as start point.\r
999 //\r
1000 Head = &(*CurrentSmbiosEntry)->Link;\r
1001 }\r
d1102dba 1002\r
0ddd8553 1003 Link = Head->ForwardLink;\r
d1102dba 1004\r
0ddd8553 1005 if (Link == &Private->DataListHead) {\r
1006 //\r
1007 // If no more SMBIOS entry in the list, return not found.\r
1008 //\r
1009 return EFI_NOT_FOUND;\r
1010 }\r
d1102dba 1011\r
0ddd8553 1012 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);\r
1013 SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);\r
d1102dba 1014 *Record = SmbiosTableHeader;\r
0ddd8553 1015 *CurrentSmbiosEntry = SmbiosEntry;\r
d1102dba 1016 return EFI_SUCCESS;\r
0ddd8553 1017}\r
310b04e6 1018\r
1019/**\r
0ddd8553 1020 Assembles SMBIOS table from the SMBIOS protocol. Produce Table\r
310b04e6 1021 Entry Point and return the pointer to it.\r
d1102dba 1022\r
310b04e6 1023 @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.\r
d1102dba 1024\r
310b04e6 1025 @retval EFI_SUCCESS Structure created sucessfully.\r
310b04e6 1026 @retval EFI_OUT_OF_RESOURCES No enough memory.\r
d1102dba 1027\r
310b04e6 1028**/\r
1029EFI_STATUS\r
1030EFIAPI\r
1031SmbiosCreateTable (\r
1032 OUT VOID **TableEntryPointStructure\r
1033 )\r
1034{\r
310b04e6 1035 UINT8 *BufferPointer;\r
310b04e6 1036 UINTN RecordSize;\r
1037 UINTN NumOfStr;\r
1038 EFI_STATUS Status;\r
1039 EFI_SMBIOS_HANDLE SmbiosHandle;\r
1040 EFI_SMBIOS_PROTOCOL *SmbiosProtocol;\r
1041 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
1042 EFI_SMBIOS_TABLE_HEADER *SmbiosRecord;\r
1043 EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure;\r
0ddd8553 1044 EFI_SMBIOS_ENTRY *CurrentSmbiosEntry;\r
d1102dba 1045\r
310b04e6 1046 Status = EFI_SUCCESS;\r
1047 BufferPointer = NULL;\r
310b04e6 1048\r
e63f3308
EL
1049 if (EntryPointStructure == NULL) {\r
1050 //\r
1051 // Initialize the EntryPointStructure with initial values.\r
1052 // It should be done only once.\r
1053 // Allocate memory (below 4GB).\r
1054 //\r
1055 DEBUG ((EFI_D_INFO, "SmbiosCreateTable: Initialize 32-bit entry point structure\n"));\r
1056 EntryPointStructureData.MajorVersion = mPrivateData.Smbios.MajorVersion;\r
1057 EntryPointStructureData.MinorVersion = mPrivateData.Smbios.MinorVersion;\r
1058 EntryPointStructureData.SmbiosBcdRevision = (UINT8) ((PcdGet16 (PcdSmbiosVersion) >> 4) & 0xf0) | (UINT8) (PcdGet16 (PcdSmbiosVersion) & 0x0f);\r
1059 PhysicalAddress = 0xffffffff;\r
1060 Status = gBS->AllocatePages (\r
1061 AllocateMaxAddress,\r
1062 EfiRuntimeServicesData,\r
1063 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),\r
1064 &PhysicalAddress\r
1065 );\r
1066 if (EFI_ERROR (Status)) {\r
1067 DEBUG ((EFI_D_ERROR, "SmbiosCreateTable () could not allocate EntryPointStructure < 4GB\n"));\r
1068 Status = gBS->AllocatePages (\r
1069 AllocateAnyPages,\r
1070 EfiRuntimeServicesData,\r
1071 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),\r
1072 &PhysicalAddress\r
1073 );\r
1074 if (EFI_ERROR (Status)) {\r
1075 return EFI_OUT_OF_RESOURCES;\r
1076 }\r
1077 }\r
d1102dba 1078\r
e63f3308 1079 EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) (UINTN) PhysicalAddress;\r
d1102dba 1080\r
e63f3308
EL
1081 CopyMem (\r
1082 EntryPointStructure,\r
1083 &EntryPointStructureData,\r
1084 sizeof (SMBIOS_TABLE_ENTRY_POINT)\r
1085 );\r
1086 }\r
1087\r
310b04e6 1088 //\r
0ddd8553 1089 // Get Smbios protocol to traverse SMBIOS records.\r
310b04e6 1090 //\r
0ddd8553 1091 SmbiosProtocol = &mPrivateData.Smbios;\r
310b04e6 1092\r
310b04e6 1093 //\r
1094 // Make some statistics about all the structures\r
1095 //\r
1096 EntryPointStructure->NumberOfSmbiosStructures = 0;\r
1097 EntryPointStructure->TableLength = 0;\r
1098 EntryPointStructure->MaxStructureSize = 0;\r
310b04e6 1099\r
1100 //\r
1101 // Calculate EPS Table Length\r
1102 //\r
0ddd8553 1103 CurrentSmbiosEntry = NULL;\r
310b04e6 1104 do {\r
0ddd8553 1105 Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);\r
d1102dba 1106\r
e63f3308 1107 if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios32BitTable)) {\r
afe3969c 1108 GetSmbiosStructureSize(SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);\r
310b04e6 1109 //\r
1110 // Record NumberOfSmbiosStructures, TableLength and MaxStructureSize\r
1111 //\r
afe3969c 1112 EntryPointStructure->NumberOfSmbiosStructures++;\r
310b04e6 1113 EntryPointStructure->TableLength = (UINT16) (EntryPointStructure->TableLength + RecordSize);\r
1114 if (RecordSize > EntryPointStructure->MaxStructureSize) {\r
1115 EntryPointStructure->MaxStructureSize = (UINT16) RecordSize;\r
1116 }\r
1117 }\r
1118 } while (!EFI_ERROR(Status));\r
d1102dba 1119\r
310b04e6 1120 //\r
1121 // Create End-Of-Table structure\r
1122 //\r
1123 GetMaxSmbiosHandle(SmbiosProtocol, &SmbiosHandle);\r
4b1f70e2 1124 EndStructure.Header.Type = SMBIOS_TYPE_END_OF_TABLE;\r
c9325700 1125 EndStructure.Header.Length = (UINT8) sizeof (EFI_SMBIOS_TABLE_HEADER);\r
310b04e6 1126 EndStructure.Header.Handle = SmbiosHandle;\r
1127 EndStructure.Tailing[0] = 0;\r
1128 EndStructure.Tailing[1] = 0;\r
1129 EntryPointStructure->NumberOfSmbiosStructures++;\r
1130 EntryPointStructure->TableLength = (UINT16) (EntryPointStructure->TableLength + sizeof (EndStructure));\r
1131 if (sizeof (EndStructure) > EntryPointStructure->MaxStructureSize) {\r
1132 EntryPointStructure->MaxStructureSize = (UINT16) sizeof (EndStructure);\r
1133 }\r
310b04e6 1134\r
16f69227 1135 if (EFI_SIZE_TO_PAGES ((UINT32) EntryPointStructure->TableLength) > mPreAllocatedPages) {\r
0ddd8553 1136 //\r
d1102dba 1137 // If new SMBIOS table size exceeds the previous allocated page,\r
0ddd8553 1138 // it is time to re-allocate memory (below 4GB).\r
d1102dba 1139 //\r
5efb2878
LE
1140 DEBUG ((EFI_D_INFO, "%a() re-allocate SMBIOS 32-bit table\n",\r
1141 __FUNCTION__));\r
0ddd8553 1142 if (EntryPointStructure->TableAddress != 0) {\r
1143 //\r
e63f3308 1144 // Free the previous allocated page\r
d1102dba 1145 //\r
0ddd8553 1146 FreePages (\r
1147 (VOID*)(UINTN)EntryPointStructure->TableAddress,\r
4233bf70 1148 mPreAllocatedPages\r
0ddd8553 1149 );\r
1150 EntryPointStructure->TableAddress = 0;\r
4233bf70 1151 mPreAllocatedPages = 0;\r
0ddd8553 1152 }\r
d1102dba 1153\r
0ddd8553 1154 PhysicalAddress = 0xffffffff;\r
1155 Status = gBS->AllocatePages (\r
1156 AllocateMaxAddress,\r
b6823730 1157 EfiRuntimeServicesData,\r
0ddd8553 1158 EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength),\r
1159 &PhysicalAddress\r
1160 );\r
1161 if (EFI_ERROR (Status)) {\r
c7ce5169 1162 DEBUG ((EFI_D_ERROR, "SmbiosCreateTable() could not allocate SMBIOS table < 4GB\n"));\r
1163 EntryPointStructure->TableAddress = 0;\r
0ddd8553 1164 return EFI_OUT_OF_RESOURCES;\r
c7ce5169 1165 } else {\r
1166 EntryPointStructure->TableAddress = (UINT32) PhysicalAddress;\r
4233bf70 1167 mPreAllocatedPages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength);\r
0ddd8553 1168 }\r
0ddd8553 1169 }\r
d1102dba 1170\r
310b04e6 1171 //\r
1172 // Assemble the tables\r
1173 //\r
f63085f5 1174 ASSERT (EntryPointStructure->TableAddress != 0);\r
0ddd8553 1175 BufferPointer = (UINT8 *) (UINTN) EntryPointStructure->TableAddress;\r
1176 CurrentSmbiosEntry = NULL;\r
310b04e6 1177 do {\r
0ddd8553 1178 Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);\r
1179\r
e63f3308 1180 if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios32BitTable)) {\r
afe3969c 1181 GetSmbiosStructureSize(SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);\r
310b04e6 1182 CopyMem (BufferPointer, SmbiosRecord, RecordSize);\r
1183 BufferPointer = BufferPointer + RecordSize;\r
1184 }\r
1185 } while (!EFI_ERROR(Status));\r
d1102dba 1186\r
310b04e6 1187 //\r
1188 // Assemble End-Of-Table structure\r
1189 //\r
1190 CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure));\r
1191\r
1192 //\r
1193 // Fixup checksums in the Entry Point Structure\r
1194 //\r
47f8d0f3
JY
1195 EntryPointStructure->IntermediateChecksum = 0;\r
1196 EntryPointStructure->EntryPointStructureChecksum = 0;\r
1197\r
afe3969c
SZ
1198 EntryPointStructure->IntermediateChecksum =\r
1199 CalculateCheckSum8 ((UINT8 *) EntryPointStructure + 0x10, EntryPointStructure->EntryPointLength - 0x10);\r
1200 EntryPointStructure->EntryPointStructureChecksum =\r
1201 CalculateCheckSum8 ((UINT8 *) EntryPointStructure, EntryPointStructure->EntryPointLength);\r
310b04e6 1202\r
1203 //\r
1204 // Returns the pointer\r
1205 //\r
1206 *TableEntryPointStructure = EntryPointStructure;\r
1207\r
1208 return EFI_SUCCESS;\r
1209}\r
1210\r
310b04e6 1211/**\r
e63f3308
EL
1212 Assembles SMBIOS 64-bit table from the SMBIOS protocol. Produce Table\r
1213 Entry Point and return the pointer to it.\r
1214\r
1215 @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.\r
1216\r
1217 @retval EFI_SUCCESS Structure created sucessfully.\r
1218 @retval EFI_OUT_OF_RESOURCES No enough memory.\r
1219\r
1220**/\r
1221EFI_STATUS\r
1222EFIAPI\r
1223SmbiosCreate64BitTable (\r
1224 OUT VOID **TableEntryPointStructure\r
1225 )\r
1226{\r
1227 UINT8 *BufferPointer;\r
1228 UINTN RecordSize;\r
1229 UINTN NumOfStr;\r
1230 EFI_STATUS Status;\r
1231 EFI_SMBIOS_HANDLE SmbiosHandle;\r
1232 EFI_SMBIOS_PROTOCOL *SmbiosProtocol;\r
1233 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
1234 EFI_SMBIOS_TABLE_HEADER *SmbiosRecord;\r
1235 EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure;\r
1236 EFI_SMBIOS_ENTRY *CurrentSmbiosEntry;\r
d1102dba 1237\r
e63f3308
EL
1238 Status = EFI_SUCCESS;\r
1239 BufferPointer = NULL;\r
1240\r
1241 if (Smbios30EntryPointStructure == NULL) {\r
1242 //\r
1243 // Initialize the Smbios30EntryPointStructure with initial values.\r
1244 // It should be done only once.\r
1245 // Allocate memory at any address.\r
1246 //\r
1247 DEBUG ((EFI_D_INFO, "SmbiosCreateTable: Initialize 64-bit entry point structure\n"));\r
1248 Smbios30EntryPointStructureData.MajorVersion = mPrivateData.Smbios.MajorVersion;\r
1249 Smbios30EntryPointStructureData.MinorVersion = mPrivateData.Smbios.MinorVersion;\r
1250 Smbios30EntryPointStructureData.DocRev = PcdGet8 (PcdSmbiosDocRev);\r
1251 Status = gBS->AllocatePages (\r
1252 AllocateAnyPages,\r
1253 EfiRuntimeServicesData,\r
1254 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT)),\r
1255 &PhysicalAddress\r
1256 );\r
1257 if (EFI_ERROR (Status)) {\r
1258 DEBUG ((EFI_D_ERROR, "SmbiosCreate64BitTable() could not allocate Smbios30EntryPointStructure\n"));\r
1259 return EFI_OUT_OF_RESOURCES;\r
1260 }\r
d1102dba 1261\r
e63f3308 1262 Smbios30EntryPointStructure = (SMBIOS_TABLE_3_0_ENTRY_POINT *) (UINTN) PhysicalAddress;\r
d1102dba 1263\r
e63f3308
EL
1264 CopyMem (\r
1265 Smbios30EntryPointStructure,\r
1266 &Smbios30EntryPointStructureData,\r
1267 sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT)\r
1268 );\r
1269 }\r
1270\r
1271 //\r
1272 // Get Smbios protocol to traverse SMBIOS records.\r
1273 //\r
1274 SmbiosProtocol = &mPrivateData.Smbios;\r
1275 Smbios30EntryPointStructure->TableMaximumSize = 0;\r
1276\r
1277 //\r
1278 // Calculate EPS Table Length\r
1279 //\r
1280 CurrentSmbiosEntry = NULL;\r
1281 do {\r
1282 Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);\r
d1102dba 1283\r
e63f3308
EL
1284 if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios64BitTable)) {\r
1285 GetSmbiosStructureSize(SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);\r
1286 //\r
1287 // Record TableMaximumSize\r
1288 //\r
1289 Smbios30EntryPointStructure->TableMaximumSize = (UINT32) (Smbios30EntryPointStructure->TableMaximumSize + RecordSize);\r
1290 }\r
1291 } while (!EFI_ERROR(Status));\r
1292\r
1293 //\r
1294 // Create End-Of-Table structure\r
1295 //\r
1296 GetMaxSmbiosHandle(SmbiosProtocol, &SmbiosHandle);\r
4b1f70e2 1297 EndStructure.Header.Type = SMBIOS_TYPE_END_OF_TABLE;\r
e63f3308
EL
1298 EndStructure.Header.Length = (UINT8) sizeof (EFI_SMBIOS_TABLE_HEADER);\r
1299 EndStructure.Header.Handle = SmbiosHandle;\r
1300 EndStructure.Tailing[0] = 0;\r
1301 EndStructure.Tailing[1] = 0;\r
1302 Smbios30EntryPointStructure->TableMaximumSize = (UINT32) (Smbios30EntryPointStructure->TableMaximumSize + sizeof (EndStructure));\r
1303\r
16f69227 1304 if (EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize) > mPre64BitAllocatedPages) {\r
e63f3308 1305 //\r
d1102dba 1306 // If new SMBIOS table size exceeds the previous allocated page,\r
e63f3308
EL
1307 // it is time to re-allocate memory at anywhere.\r
1308 //\r
5efb2878
LE
1309 DEBUG ((EFI_D_INFO, "%a() re-allocate SMBIOS 64-bit table\n",\r
1310 __FUNCTION__));\r
e63f3308
EL
1311 if (Smbios30EntryPointStructure->TableAddress != 0) {\r
1312 //\r
1313 // Free the previous allocated page\r
d1102dba 1314 //\r
e63f3308
EL
1315 FreePages (\r
1316 (VOID*)(UINTN)Smbios30EntryPointStructure->TableAddress,\r
1317 mPre64BitAllocatedPages\r
1318 );\r
1319 Smbios30EntryPointStructure->TableAddress = 0;\r
1320 mPre64BitAllocatedPages = 0;\r
1321 }\r
1322\r
1323 Status = gBS->AllocatePages (\r
1324 AllocateAnyPages,\r
1325 EfiRuntimeServicesData,\r
1326 EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize),\r
1327 &PhysicalAddress\r
1328 );\r
1329 if (EFI_ERROR (Status)) {\r
1330 DEBUG ((EFI_D_ERROR, "SmbiosCreateTable() could not allocate SMBIOS 64-bit table\n"));\r
1331 Smbios30EntryPointStructure->TableAddress = 0;\r
1332 return EFI_OUT_OF_RESOURCES;\r
1333 } else {\r
1334 Smbios30EntryPointStructure->TableAddress = PhysicalAddress;\r
1335 mPre64BitAllocatedPages = EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize);\r
1336 }\r
1337 }\r
1338\r
1339 //\r
1340 // Assemble the tables\r
1341 //\r
1342 ASSERT (Smbios30EntryPointStructure->TableAddress != 0);\r
1343 BufferPointer = (UINT8 *) (UINTN) Smbios30EntryPointStructure->TableAddress;\r
1344 CurrentSmbiosEntry = NULL;\r
1345 do {\r
1346 Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);\r
1347\r
1348 if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios64BitTable)) {\r
1349 //\r
1350 // This record can be added to 64-bit table\r
1351 //\r
1352 GetSmbiosStructureSize(SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);\r
1353 CopyMem (BufferPointer, SmbiosRecord, RecordSize);\r
1354 BufferPointer = BufferPointer + RecordSize;\r
1355 }\r
1356 } while (!EFI_ERROR(Status));\r
1357\r
1358 //\r
1359 // Assemble End-Of-Table structure\r
1360 //\r
1361 CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure));\r
1362\r
1363 //\r
1364 // Fixup checksums in the Entry Point Structure\r
1365 //\r
1366 Smbios30EntryPointStructure->EntryPointStructureChecksum = 0;\r
1367 Smbios30EntryPointStructure->EntryPointStructureChecksum =\r
1368 CalculateCheckSum8 ((UINT8 *) Smbios30EntryPointStructure, Smbios30EntryPointStructure->EntryPointLength);\r
1369\r
1370 //\r
1371 // Returns the pointer\r
1372 //\r
1373 *TableEntryPointStructure = Smbios30EntryPointStructure;\r
1374\r
1375 return EFI_SUCCESS;\r
1376}\r
1377\r
1378/**\r
1379 Create Smbios Table and installs the Smbios Table to the System Table.\r
d1102dba 1380\r
e63f3308
EL
1381 @param Smbios32BitTable The flag to update 32-bit table.\r
1382 @param Smbios64BitTable The flag to update 64-bit table.\r
1383\r
310b04e6 1384**/\r
1385VOID\r
1386EFIAPI\r
1387SmbiosTableConstruction (\r
e63f3308
EL
1388 BOOLEAN Smbios32BitTable,\r
1389 BOOLEAN Smbios64BitTable\r
310b04e6 1390 )\r
1391{\r
1392 UINT8 *Eps;\r
e63f3308 1393 UINT8 *Eps64Bit;\r
310b04e6 1394 EFI_STATUS Status;\r
1395\r
e63f3308
EL
1396 if (Smbios32BitTable) {\r
1397 Status = SmbiosCreateTable ((VOID **) &Eps);\r
1398 if (!EFI_ERROR (Status)) {\r
1399 gBS->InstallConfigurationTable (&gEfiSmbiosTableGuid, Eps);\r
1400 }\r
1401 }\r
1402\r
1403 if (Smbios64BitTable) {\r
1404 Status = SmbiosCreate64BitTable ((VOID **) &Eps64Bit);\r
1405 if (!EFI_ERROR (Status)) {\r
1406 gBS->InstallConfigurationTable (&gEfiSmbios3TableGuid, Eps64Bit);\r
1407 }\r
310b04e6 1408 }\r
1409}\r
1410\r
310b04e6 1411/**\r
1412\r
d1102dba 1413 Driver to produce Smbios protocol and pre-allocate 1 page for the final SMBIOS table.\r
310b04e6 1414\r
1415 @param ImageHandle Module's image handle\r
1416 @param SystemTable Pointer of EFI_SYSTEM_TABLE\r
1417\r
1418 @retval EFI_SUCCESS Smbios protocol installed\r
1419 @retval Other No protocol installed, unload driver.\r
1420\r
1421**/\r
1422EFI_STATUS\r
1423EFIAPI\r
1424SmbiosDriverEntryPoint (\r
1425 IN EFI_HANDLE ImageHandle,\r
1426 IN EFI_SYSTEM_TABLE *SystemTable\r
1427 )\r
1428{\r
1429 EFI_STATUS Status;\r
310b04e6 1430\r
1431 mPrivateData.Signature = SMBIOS_INSTANCE_SIGNATURE;\r
1432 mPrivateData.Smbios.Add = SmbiosAdd;\r
1433 mPrivateData.Smbios.UpdateString = SmbiosUpdateString;\r
1434 mPrivateData.Smbios.Remove = SmbiosRemove;\r
1435 mPrivateData.Smbios.GetNext = SmbiosGetNext;\r
fe781940
SZ
1436 mPrivateData.Smbios.MajorVersion = (UINT8) (PcdGet16 (PcdSmbiosVersion) >> 8);\r
1437 mPrivateData.Smbios.MinorVersion = (UINT8) (PcdGet16 (PcdSmbiosVersion) & 0x00ff);\r
310b04e6 1438\r
1439 InitializeListHead (&mPrivateData.DataListHead);\r
1440 InitializeListHead (&mPrivateData.AllocatedHandleListHead);\r
1441 EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);\r
d1102dba 1442\r
310b04e6 1443 //\r
1444 // Make a new handle and install the protocol\r
1445 //\r
1446 mPrivateData.Handle = NULL;\r
1447 Status = gBS->InstallProtocolInterface (\r
1448 &mPrivateData.Handle,\r
1449 &gEfiSmbiosProtocolGuid,\r
1450 EFI_NATIVE_INTERFACE,\r
1451 &mPrivateData.Smbios\r
1452 );\r
1453\r
310b04e6 1454 return Status;\r
1455}\r