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