VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c@ 101291

Last change on this file since 101291 was 101291, checked in by vboxsync, 14 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette