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