VirtualBox

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

最後變更 在這個檔案從105670是 105670,由 vboxsync 提交於 7 月 前

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • 屬性 svn:eol-style 設為 native
檔案大小: 55.8 KB
 
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 = 0;
1076 if ((mPrivateData.Smbios.MajorVersion <= 9) && (mPrivateData.Smbios.MinorVersion <= 9)) {
1077 EntryPointStructureData.SmbiosBcdRevision = ((mPrivateData.Smbios.MajorVersion & 0x0f) << 4) | (mPrivateData.Smbios.MinorVersion & 0x0f);
1078 }
1079
1080 PhysicalAddress = 0xffffffff;
1081 Status = gBS->AllocatePages (
1082 AllocateMaxAddress,
1083 EfiRuntimeServicesData,
1084 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),
1085 &PhysicalAddress
1086 );
1087 if (EFI_ERROR (Status)) {
1088 DEBUG ((DEBUG_ERROR, "SmbiosCreateTable () could not allocate EntryPointStructure < 4GB\n"));
1089 Status = gBS->AllocatePages (
1090 AllocateAnyPages,
1091 EfiRuntimeServicesData,
1092 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),
1093 &PhysicalAddress
1094 );
1095 if (EFI_ERROR (Status)) {
1096 return EFI_OUT_OF_RESOURCES;
1097 }
1098 }
1099
1100 EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN)PhysicalAddress;
1101
1102 CopyMem (
1103 EntryPointStructure,
1104 &EntryPointStructureData,
1105 sizeof (SMBIOS_TABLE_ENTRY_POINT)
1106 );
1107 }
1108
1109 //
1110 // Get Smbios protocol to traverse SMBIOS records.
1111 //
1112 SmbiosProtocol = &mPrivateData.Smbios;
1113
1114 //
1115 // Make some statistics about all the structures
1116 //
1117 EntryPointStructure->NumberOfSmbiosStructures = 0;
1118 EntryPointStructure->TableLength = 0;
1119 EntryPointStructure->MaxStructureSize = 0;
1120
1121 //
1122 // Calculate EPS Table Length
1123 //
1124 CurrentSmbiosEntry = NULL;
1125 do {
1126 Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);
1127
1128 if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios32BitTable)) {
1129 GetSmbiosStructureSize (SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);
1130 //
1131 // Record NumberOfSmbiosStructures, TableLength and MaxStructureSize
1132 //
1133 EntryPointStructure->NumberOfSmbiosStructures++;
1134 EntryPointStructure->TableLength = (UINT16)(EntryPointStructure->TableLength + RecordSize);
1135 if (RecordSize > EntryPointStructure->MaxStructureSize) {
1136 EntryPointStructure->MaxStructureSize = (UINT16)RecordSize;
1137 }
1138 }
1139 } while (!EFI_ERROR (Status));
1140
1141 //
1142 // Create End-Of-Table structure
1143 //
1144 GetMaxSmbiosHandle (SmbiosProtocol, &SmbiosHandle);
1145 EndStructure.Header.Type = SMBIOS_TYPE_END_OF_TABLE;
1146 EndStructure.Header.Length = (UINT8)sizeof (EFI_SMBIOS_TABLE_HEADER);
1147 EndStructure.Header.Handle = SmbiosHandle;
1148 EndStructure.Tailing[0] = 0;
1149 EndStructure.Tailing[1] = 0;
1150 EntryPointStructure->NumberOfSmbiosStructures++;
1151 EntryPointStructure->TableLength = (UINT16)(EntryPointStructure->TableLength + sizeof (EndStructure));
1152 if (sizeof (EndStructure) > EntryPointStructure->MaxStructureSize) {
1153 EntryPointStructure->MaxStructureSize = (UINT16)sizeof (EndStructure);
1154 }
1155
1156 if (EFI_SIZE_TO_PAGES ((UINT32)EntryPointStructure->TableLength) > mPreAllocatedPages) {
1157 //
1158 // If new SMBIOS table size exceeds the previous allocated page,
1159 // it is time to re-allocate memory (below 4GB).
1160 //
1161 DEBUG ((
1162 DEBUG_INFO,
1163 "%a() re-allocate SMBIOS 32-bit table\n",
1164 __func__
1165 ));
1166 if (EntryPointStructure->TableAddress != 0) {
1167 //
1168 // Free the previous allocated page
1169 //
1170 FreePages (
1171 (VOID *)(UINTN)EntryPointStructure->TableAddress,
1172 mPreAllocatedPages
1173 );
1174 EntryPointStructure->TableAddress = 0;
1175 mPreAllocatedPages = 0;
1176 }
1177
1178 PhysicalAddress = 0xffffffff;
1179 Status = gBS->AllocatePages (
1180 AllocateMaxAddress,
1181 EfiRuntimeServicesData,
1182 EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength),
1183 &PhysicalAddress
1184 );
1185 if (EFI_ERROR (Status)) {
1186 DEBUG ((DEBUG_ERROR, "SmbiosCreateTable() could not allocate SMBIOS table < 4GB\n"));
1187 EntryPointStructure->TableAddress = 0;
1188 return EFI_OUT_OF_RESOURCES;
1189 } else {
1190 EntryPointStructure->TableAddress = (UINT32)PhysicalAddress;
1191 mPreAllocatedPages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength);
1192 }
1193 }
1194
1195 //
1196 // Assemble the tables
1197 //
1198 ASSERT (EntryPointStructure->TableAddress != 0);
1199 BufferPointer = (UINT8 *)(UINTN)EntryPointStructure->TableAddress;
1200 CurrentSmbiosEntry = NULL;
1201 do {
1202 Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);
1203
1204 if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios32BitTable)) {
1205 GetSmbiosStructureSize (SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);
1206 CopyMem (BufferPointer, SmbiosRecord, RecordSize);
1207 BufferPointer = BufferPointer + RecordSize;
1208 }
1209 } while (!EFI_ERROR (Status));
1210
1211 //
1212 // Assemble End-Of-Table structure
1213 //
1214 CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure));
1215
1216 //
1217 // Fixup checksums in the Entry Point Structure
1218 //
1219 EntryPointStructure->IntermediateChecksum = 0;
1220 EntryPointStructure->EntryPointStructureChecksum = 0;
1221
1222 EntryPointStructure->IntermediateChecksum =
1223 CalculateCheckSum8 ((UINT8 *)EntryPointStructure + 0x10, EntryPointStructure->EntryPointLength - 0x10);
1224 EntryPointStructure->EntryPointStructureChecksum =
1225 CalculateCheckSum8 ((UINT8 *)EntryPointStructure, EntryPointStructure->EntryPointLength);
1226
1227 //
1228 // Returns the pointer
1229 //
1230 *TableEntryPointStructure = EntryPointStructure;
1231
1232 return EFI_SUCCESS;
1233}
1234
1235/**
1236 Assembles SMBIOS 64-bit table from the SMBIOS protocol. Produce Table
1237 Entry Point and return the pointer to it.
1238
1239 @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.
1240
1241 @retval EFI_SUCCESS Structure created sucessfully.
1242 @retval EFI_OUT_OF_RESOURCES No enough memory.
1243
1244**/
1245EFI_STATUS
1246EFIAPI
1247SmbiosCreate64BitTable (
1248 OUT VOID **TableEntryPointStructure
1249 )
1250{
1251 UINT8 *BufferPointer;
1252 UINTN RecordSize;
1253 UINTN NumOfStr;
1254 EFI_STATUS Status;
1255 EFI_SMBIOS_HANDLE SmbiosHandle;
1256 EFI_SMBIOS_PROTOCOL *SmbiosProtocol;
1257 EFI_PHYSICAL_ADDRESS PhysicalAddress;
1258 EFI_SMBIOS_TABLE_HEADER *SmbiosRecord;
1259 EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure;
1260 EFI_SMBIOS_ENTRY *CurrentSmbiosEntry;
1261
1262 Status = EFI_SUCCESS;
1263 BufferPointer = NULL;
1264
1265 if (Smbios30EntryPointStructure == NULL) {
1266 //
1267 // Initialize the Smbios30EntryPointStructure with initial values.
1268 // It should be done only once.
1269 // Allocate memory at any address.
1270 //
1271 DEBUG ((DEBUG_INFO, "SmbiosCreateTable: Initialize 64-bit entry point structure\n"));
1272 Smbios30EntryPointStructureData.MajorVersion = mPrivateData.Smbios.MajorVersion;
1273 Smbios30EntryPointStructureData.MinorVersion = mPrivateData.Smbios.MinorVersion;
1274 Smbios30EntryPointStructureData.DocRev = PcdGet8 (PcdSmbiosDocRev);
1275 Status = gBS->AllocatePages (
1276 AllocateAnyPages,
1277 EfiRuntimeServicesData,
1278 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT)),
1279 &PhysicalAddress
1280 );
1281 if (EFI_ERROR (Status)) {
1282 DEBUG ((DEBUG_ERROR, "SmbiosCreate64BitTable() could not allocate Smbios30EntryPointStructure\n"));
1283 return EFI_OUT_OF_RESOURCES;
1284 }
1285
1286 Smbios30EntryPointStructure = (SMBIOS_TABLE_3_0_ENTRY_POINT *)(UINTN)PhysicalAddress;
1287
1288 CopyMem (
1289 Smbios30EntryPointStructure,
1290 &Smbios30EntryPointStructureData,
1291 sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT)
1292 );
1293 }
1294
1295 //
1296 // Get Smbios protocol to traverse SMBIOS records.
1297 //
1298 SmbiosProtocol = &mPrivateData.Smbios;
1299 Smbios30EntryPointStructure->TableMaximumSize = 0;
1300
1301 //
1302 // Calculate EPS Table Length
1303 //
1304 CurrentSmbiosEntry = NULL;
1305 do {
1306 Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);
1307
1308 if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios64BitTable)) {
1309 GetSmbiosStructureSize (SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);
1310 //
1311 // Record TableMaximumSize
1312 //
1313 Smbios30EntryPointStructure->TableMaximumSize = (UINT32)(Smbios30EntryPointStructure->TableMaximumSize + RecordSize);
1314 }
1315 } while (!EFI_ERROR (Status));
1316
1317 //
1318 // Create End-Of-Table structure
1319 //
1320 GetMaxSmbiosHandle (SmbiosProtocol, &SmbiosHandle);
1321 EndStructure.Header.Type = SMBIOS_TYPE_END_OF_TABLE;
1322 EndStructure.Header.Length = (UINT8)sizeof (EFI_SMBIOS_TABLE_HEADER);
1323 EndStructure.Header.Handle = SmbiosHandle;
1324 EndStructure.Tailing[0] = 0;
1325 EndStructure.Tailing[1] = 0;
1326 Smbios30EntryPointStructure->TableMaximumSize = (UINT32)(Smbios30EntryPointStructure->TableMaximumSize + sizeof (EndStructure));
1327
1328 if (EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize) > mPre64BitAllocatedPages) {
1329 //
1330 // If new SMBIOS table size exceeds the previous allocated page,
1331 // it is time to re-allocate memory at anywhere.
1332 //
1333 DEBUG ((
1334 DEBUG_INFO,
1335 "%a() re-allocate SMBIOS 64-bit table\n",
1336 __func__
1337 ));
1338 if (Smbios30EntryPointStructure->TableAddress != 0) {
1339 //
1340 // Free the previous allocated page
1341 //
1342 FreePages (
1343 (VOID *)(UINTN)Smbios30EntryPointStructure->TableAddress,
1344 mPre64BitAllocatedPages
1345 );
1346 Smbios30EntryPointStructure->TableAddress = 0;
1347 mPre64BitAllocatedPages = 0;
1348 }
1349
1350 Status = gBS->AllocatePages (
1351 AllocateAnyPages,
1352 EfiRuntimeServicesData,
1353 EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize),
1354 &PhysicalAddress
1355 );
1356 if (EFI_ERROR (Status)) {
1357 DEBUG ((DEBUG_ERROR, "SmbiosCreateTable() could not allocate SMBIOS 64-bit table\n"));
1358 Smbios30EntryPointStructure->TableAddress = 0;
1359 return EFI_OUT_OF_RESOURCES;
1360 } else {
1361 Smbios30EntryPointStructure->TableAddress = PhysicalAddress;
1362 mPre64BitAllocatedPages = EFI_SIZE_TO_PAGES (Smbios30EntryPointStructure->TableMaximumSize);
1363 }
1364 }
1365
1366 //
1367 // Assemble the tables
1368 //
1369 ASSERT (Smbios30EntryPointStructure->TableAddress != 0);
1370 BufferPointer = (UINT8 *)(UINTN)Smbios30EntryPointStructure->TableAddress;
1371 CurrentSmbiosEntry = NULL;
1372 do {
1373 Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);
1374
1375 if ((Status == EFI_SUCCESS) && (CurrentSmbiosEntry->Smbios64BitTable)) {
1376 //
1377 // This record can be added to 64-bit table
1378 //
1379 GetSmbiosStructureSize (SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);
1380 CopyMem (BufferPointer, SmbiosRecord, RecordSize);
1381 BufferPointer = BufferPointer + RecordSize;
1382 }
1383 } while (!EFI_ERROR (Status));
1384
1385 //
1386 // Assemble End-Of-Table structure
1387 //
1388 CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure));
1389
1390 //
1391 // Fixup checksums in the Entry Point Structure
1392 //
1393 Smbios30EntryPointStructure->EntryPointStructureChecksum = 0;
1394 Smbios30EntryPointStructure->EntryPointStructureChecksum =
1395 CalculateCheckSum8 ((UINT8 *)Smbios30EntryPointStructure, Smbios30EntryPointStructure->EntryPointLength);
1396
1397 //
1398 // Returns the pointer
1399 //
1400 *TableEntryPointStructure = Smbios30EntryPointStructure;
1401
1402 return EFI_SUCCESS;
1403}
1404
1405/**
1406 Create Smbios Table and installs the Smbios Table to the System Table.
1407
1408 @param Smbios32BitTable The flag to update 32-bit table.
1409 @param Smbios64BitTable The flag to update 64-bit table.
1410
1411**/
1412VOID
1413EFIAPI
1414SmbiosTableConstruction (
1415 BOOLEAN Smbios32BitTable,
1416 BOOLEAN Smbios64BitTable
1417 )
1418{
1419 UINT8 *Eps;
1420 UINT8 *Eps64Bit;
1421 EFI_STATUS Status;
1422
1423 if (Smbios32BitTable) {
1424 Status = SmbiosCreateTable ((VOID **)&Eps);
1425 if (!EFI_ERROR (Status)) {
1426 gBS->InstallConfigurationTable (&gEfiSmbiosTableGuid, Eps);
1427 }
1428 }
1429
1430 if (Smbios64BitTable) {
1431 Status = SmbiosCreate64BitTable ((VOID **)&Eps64Bit);
1432 if (!EFI_ERROR (Status)) {
1433 gBS->InstallConfigurationTable (&gEfiSmbios3TableGuid, Eps64Bit);
1434 }
1435 }
1436}
1437
1438/**
1439 Validates a SMBIOS 2.0 table entry point.
1440
1441 @param TableEntry The SmBios table entry to validate.
1442 @param TableAddress On exit, point to the smbios table addres.
1443 @param TableMaximumSize On exit, point to the maximum size of the table.
1444
1445 @retval TRUE SMBIOS table entry point is valid.
1446 @retval FALSE SMBIOS table entry point is malformed.
1447
1448**/
1449STATIC
1450BOOLEAN
1451IsValidSmbios20Table (
1452 IN VOID *TableEntry,
1453 OUT VOID **TableAddress,
1454 OUT UINTN *TableMaximumSize,
1455 OUT UINT8 *MajorVersion,
1456 OUT UINT8 *MinorVersion
1457 )
1458{
1459 UINT8 Checksum;
1460 SMBIOS_TABLE_ENTRY_POINT *SmbiosTable;
1461
1462 SmbiosTable = (SMBIOS_TABLE_ENTRY_POINT *)TableEntry;
1463
1464 if (CompareMem (SmbiosTable->AnchorString, "_SM_", 4) != 0) {
1465 return FALSE;
1466 }
1467
1468 if (CompareMem (SmbiosTable->IntermediateAnchorString, "_DMI_", 5) != 0) {
1469 return FALSE;
1470 }
1471
1472 //
1473 // The actual value of the EntryPointLength should be 1Fh.
1474 // However, it was incorrectly stated in version 2.1 of smbios specification.
1475 // Therefore, 0x1F and 0x1E are both accepted.
1476 //
1477 if ((SmbiosTable->EntryPointLength != 0x1E) && (SmbiosTable->EntryPointLength != sizeof (SMBIOS_TABLE_ENTRY_POINT))) {
1478 return FALSE;
1479 }
1480
1481 //
1482 // MajorVersion should not be less than 2.
1483 //
1484 if (SmbiosTable->MajorVersion < 2) {
1485 return FALSE;
1486 }
1487
1488 *MajorVersion = SmbiosTable->MajorVersion;
1489 *MinorVersion = SmbiosTable->MinorVersion;
1490
1491 //
1492 // The whole struct check sum should be zero
1493 //
1494 Checksum = CalculateSum8 (
1495 (UINT8 *)SmbiosTable,
1496 SmbiosTable->EntryPointLength
1497 );
1498 if (Checksum != 0) {
1499 return FALSE;
1500 }
1501
1502 //
1503 // The Intermediate Entry Point Structure check sum should be zero.
1504 //
1505 Checksum = CalculateSum8 (
1506 (UINT8 *)SmbiosTable + OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString),
1507 SmbiosTable->EntryPointLength - OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString)
1508 );
1509 if (Checksum != 0) {
1510 return FALSE;
1511 }
1512
1513 *TableAddress = (VOID *)(UINTN)SmbiosTable->TableAddress;
1514 *TableMaximumSize = SmbiosTable->TableLength;
1515 return TRUE;
1516}
1517
1518/**
1519 Validates a SMBIOS 3.0 table entry point.
1520
1521 @param TableEntry The SmBios table entry to validate.
1522 @param TableAddress On exit, point to the smbios table addres.
1523 @param TableMaximumSize On exit, point to the maximum size of the table.
1524
1525 @retval TRUE SMBIOS table entry point is valid.
1526 @retval FALSE SMBIOS table entry point is malformed.
1527
1528**/
1529STATIC
1530BOOLEAN
1531IsValidSmbios30Table (
1532 IN VOID *TableEntry,
1533 OUT VOID **TableAddress,
1534 OUT UINTN *TableMaximumSize,
1535 OUT UINT8 *MajorVersion,
1536 OUT UINT8 *MinorVersion
1537 )
1538{
1539 UINT8 Checksum;
1540 SMBIOS_TABLE_3_0_ENTRY_POINT *SmbiosTable;
1541
1542 SmbiosTable = (SMBIOS_TABLE_3_0_ENTRY_POINT *)TableEntry;
1543
1544 if (CompareMem (SmbiosTable->AnchorString, "_SM3_", 5) != 0) {
1545 return FALSE;
1546 }
1547
1548 if (SmbiosTable->EntryPointLength < sizeof (SMBIOS_TABLE_3_0_ENTRY_POINT)) {
1549 return FALSE;
1550 }
1551
1552 if (SmbiosTable->MajorVersion < 3) {
1553 return FALSE;
1554 }
1555
1556 *MajorVersion = SmbiosTable->MajorVersion;
1557 *MinorVersion = SmbiosTable->MinorVersion;
1558
1559 //
1560 // The whole struct check sum should be zero
1561 //
1562 Checksum = CalculateSum8 (
1563 (UINT8 *)SmbiosTable,
1564 SmbiosTable->EntryPointLength
1565 );
1566 if (Checksum != 0) {
1567 return FALSE;
1568 }
1569
1570 *TableAddress = (VOID *)(UINTN)SmbiosTable->TableAddress;
1571 *TableMaximumSize = SmbiosTable->TableMaximumSize;
1572 return TRUE;
1573}
1574
1575/**
1576 Parse an existing SMBIOS table and insert it using SmbiosAdd.
1577
1578 @param ImageHandle The EFI_HANDLE to this driver.
1579 @param Smbios The SMBIOS table to parse.
1580 @param Length The length of the SMBIOS table.
1581
1582 @retval EFI_SUCCESS SMBIOS table was parsed and installed.
1583 @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources.
1584 @retval EFI_INVALID_PARAMETER Smbios is not a correct smbios table
1585
1586**/
1587STATIC
1588EFI_STATUS
1589ParseAndAddExistingSmbiosTable (
1590 IN EFI_HANDLE ImageHandle,
1591 IN SMBIOS_STRUCTURE_POINTER Smbios,
1592 IN UINTN Length,
1593 IN UINT8 MajorVersion,
1594 IN UINT8 MinorVersion
1595 )
1596{
1597 EFI_STATUS Status;
1598 CHAR8 *String;
1599 EFI_SMBIOS_HANDLE SmbiosHandle;
1600 SMBIOS_STRUCTURE_POINTER SmbiosEnd;
1601
1602 mPrivateData.Smbios.MajorVersion = MajorVersion;
1603 mPrivateData.Smbios.MinorVersion = MinorVersion;
1604
1605 SmbiosEnd.Raw = Smbios.Raw + Length;
1606
1607 if ((Smbios.Raw >= SmbiosEnd.Raw) || (Smbios.Raw == NULL)) {
1608 return EFI_INVALID_PARAMETER;
1609 }
1610
1611 do {
1612 //
1613 // Make sure not to access memory beyond SmbiosEnd
1614 //
1615 if ((UINTN)(SmbiosEnd.Raw - Smbios.Raw) < sizeof (SMBIOS_STRUCTURE)) {
1616 return EFI_INVALID_PARAMETER;
1617 }
1618
1619 //
1620 // Check for end marker
1621 //
1622 if (Smbios.Hdr->Type == SMBIOS_TYPE_END_OF_TABLE) {
1623 break;
1624 }
1625
1626 //
1627 // Make sure not to access memory beyond SmbiosEnd
1628 // Each structure shall be terminated by a double-null (0000h).
1629 //
1630 if ((UINTN)(SmbiosEnd.Raw - Smbios.Raw) < (Smbios.Hdr->Length + 2U)) {
1631 return EFI_INVALID_PARAMETER;
1632 }
1633
1634 //
1635 // Install the table
1636 //
1637 SmbiosHandle = Smbios.Hdr->Handle;
1638 Status = SmbiosAdd (
1639 &mPrivateData.Smbios,
1640 ImageHandle,
1641 &SmbiosHandle,
1642 Smbios.Hdr
1643 );
1644
1645 ASSERT_EFI_ERROR (Status);
1646 if (EFI_ERROR (Status)) {
1647 return Status;
1648 }
1649
1650 //
1651 // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts:
1652 // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed
1653 // to skip one SMBIOS structure.
1654 //
1655
1656 //
1657 // Step 1: Skip over formatted section.
1658 //
1659 String = (CHAR8 *)(Smbios.Raw + Smbios.Hdr->Length);
1660
1661 //
1662 // Step 2: Skip over unformatted string section.
1663 //
1664 do {
1665 //
1666 // Each string is terminated with a NULL(00h) BYTE and the sets of strings
1667 // is terminated with an additional NULL(00h) BYTE.
1668 //
1669 for ( ; *String != 0; String++) {
1670 if ((UINTN)String >= (UINTN)SmbiosEnd.Raw - sizeof (UINT8)) {
1671 return EFI_INVALID_PARAMETER;
1672 }
1673 }
1674
1675 if (*(UINT8 *)++String == 0) {
1676 //
1677 // Pointer to the next SMBIOS structure.
1678 //
1679 Smbios.Raw = (UINT8 *)++String;
1680 break;
1681 }
1682 } while (TRUE);
1683 } while (Smbios.Raw < SmbiosEnd.Raw);
1684
1685 return EFI_SUCCESS;
1686}
1687
1688/**
1689 Retrieve SMBIOS from Hob.
1690 @param ImageHandle Module's image handle
1691
1692 @retval EFI_SUCCESS Smbios from Hob is installed.
1693 @return EFI_NOT_FOUND Not found Smbios from Hob.
1694 @retval Other No Smbios from Hob is installed.
1695
1696**/
1697EFI_STATUS
1698RetrieveSmbiosFromHob (
1699 IN EFI_HANDLE ImageHandle
1700 )
1701{
1702 EFI_STATUS Status;
1703 UINTN Index;
1704 SMBIOS_STRUCTURE_POINTER Smbios;
1705 EFI_HOB_GUID_TYPE *GuidHob;
1706 UNIVERSAL_PAYLOAD_SMBIOS_TABLE *SmBiosTableAdress;
1707 UNIVERSAL_PAYLOAD_GENERIC_HEADER *GenericHeader;
1708 VOID *TableAddress;
1709 UINTN TableMaximumSize;
1710 UINT8 MajorVersion;
1711 UINT8 MinorVersion;
1712
1713 Status = EFI_NOT_FOUND;
1714
1715 MajorVersion = 0;
1716 MinorVersion = 0;
1717
1718 for (Index = 0; Index < ARRAY_SIZE (mIsSmbiosTableValid); Index++) {
1719 GuidHob = GetFirstGuidHob (mIsSmbiosTableValid[Index].Guid);
1720 if (GuidHob == NULL) {
1721 continue;
1722 }
1723
1724 GenericHeader = (UNIVERSAL_PAYLOAD_GENERIC_HEADER *)GET_GUID_HOB_DATA (GuidHob);
1725 if ((sizeof (UNIVERSAL_PAYLOAD_GENERIC_HEADER) <= GET_GUID_HOB_DATA_SIZE (GuidHob)) && (GenericHeader->Length <= GET_GUID_HOB_DATA_SIZE (GuidHob))) {
1726 if (GenericHeader->Revision == UNIVERSAL_PAYLOAD_SMBIOS_TABLE_REVISION) {
1727 //
1728 // UNIVERSAL_PAYLOAD_SMBIOS_TABLE structure is used when Revision equals to UNIVERSAL_PAYLOAD_SMBIOS_TABLE_REVISION
1729 //
1730 SmBiosTableAdress = (UNIVERSAL_PAYLOAD_SMBIOS_TABLE *)GET_GUID_HOB_DATA (GuidHob);
1731 if (GenericHeader->Length >= UNIVERSAL_PAYLOAD_SIZEOF_THROUGH_FIELD (UNIVERSAL_PAYLOAD_SMBIOS_TABLE, SmBiosEntryPoint)) {
1732 if (mIsSmbiosTableValid[Index].IsValid ((VOID *)(UINTN)SmBiosTableAdress->SmBiosEntryPoint, &TableAddress, &TableMaximumSize, &MajorVersion, &MinorVersion)) {
1733 Smbios.Raw = TableAddress;
1734 Status = ParseAndAddExistingSmbiosTable (ImageHandle, Smbios, TableMaximumSize, MajorVersion, MinorVersion);
1735 if (EFI_ERROR (Status)) {
1736 DEBUG ((DEBUG_ERROR, "RetrieveSmbiosFromHob: Failed to parse preinstalled tables from Guid Hob\n"));
1737 Status = EFI_UNSUPPORTED;
1738 } else {
1739 return EFI_SUCCESS;
1740 }
1741 }
1742 }
1743 }
1744 }
1745 }
1746
1747 return Status;
1748}
1749
1750/**
1751
1752 Driver to produce Smbios protocol and pre-allocate 1 page for the final SMBIOS table.
1753
1754 @param ImageHandle Module's image handle
1755 @param SystemTable Pointer of EFI_SYSTEM_TABLE
1756
1757 @retval EFI_SUCCESS Smbios protocol installed
1758 @retval Other No protocol installed, unload driver.
1759
1760**/
1761EFI_STATUS
1762EFIAPI
1763SmbiosDriverEntryPoint (
1764 IN EFI_HANDLE ImageHandle,
1765 IN EFI_SYSTEM_TABLE *SystemTable
1766 )
1767{
1768 EFI_STATUS Status;
1769
1770 mPrivateData.Signature = SMBIOS_INSTANCE_SIGNATURE;
1771 mPrivateData.Smbios.Add = SmbiosAdd;
1772 mPrivateData.Smbios.UpdateString = SmbiosUpdateString;
1773 mPrivateData.Smbios.Remove = SmbiosRemove;
1774 mPrivateData.Smbios.GetNext = SmbiosGetNext;
1775 mPrivateData.Smbios.MajorVersion = (UINT8)(PcdGet16 (PcdSmbiosVersion) >> 8);
1776 mPrivateData.Smbios.MinorVersion = (UINT8)(PcdGet16 (PcdSmbiosVersion) & 0x00ff);
1777
1778 InitializeListHead (&mPrivateData.DataListHead);
1779 InitializeListHead (&mPrivateData.AllocatedHandleListHead);
1780 EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);
1781
1782 //
1783 // Make a new handle and install the protocol
1784 //
1785 mPrivateData.Handle = NULL;
1786 Status = gBS->InstallProtocolInterface (
1787 &mPrivateData.Handle,
1788 &gEfiSmbiosProtocolGuid,
1789 EFI_NATIVE_INTERFACE,
1790 &mPrivateData.Smbios
1791 );
1792
1793 RetrieveSmbiosFromHob (ImageHandle);
1794 return Status;
1795}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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