]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c
Use AllocateZeroPool instead of using AllocatePool + ZeroMem
[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, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "SmbiosDxe.h"
17
18 //
19 // Module Global:
20 // Since this driver will only ever produce one instance of the
21 // protocol you are not required to dynamically allocate the PrivateData.
22 //
23 SMBIOS_INSTANCE mPrivateData;
24
25 //
26 // Chassis for SMBIOS entry point structure that is to be installed into EFI system config table.
27 //
28 SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure = NULL;
29 SMBIOS_TABLE_ENTRY_POINT EntryPointStructureData = {
30 //
31 // AnchorString
32 //
33 {
34 0x5f,
35 0x53,
36 0x4d,
37 0x5f
38 },
39 //
40 // EntryPointStructureChecksum,TO BE FILLED
41 //
42 0,
43 //
44 // EntryPointStructure Length
45 //
46 0x1f,
47 //
48 // MajorVersion: 2 (Version 2.4)
49 //
50 0x02,
51 //
52 // MinorVersion: 4 (Version 2.4)
53 //
54 0x04,
55 //
56 // MaxStructureSize, TO BE FILLED
57 //
58 0,
59 //
60 // EntryPointRevision
61 //
62 0,
63 //
64 // FormattedArea
65 //
66 {
67 0,
68 0,
69 0,
70 0,
71 0
72 },
73 //
74 // IntermediateAnchorString
75 //
76 {
77 0x5f,
78 0x44,
79 0x4d,
80 0x49,
81 0x5f
82 },
83 //
84 // IntermediateChecksum, TO BE FILLED
85 //
86 0,
87 //
88 // StructureTableLength, TO BE FILLED
89 //
90 0,
91 //
92 // StructureTableAddress, TO BE FILLED
93 //
94 0,
95 //
96 // NumberOfSmbiosStructures, TO BE FILLED
97 //
98 0,
99 //
100 // SmbiosBcdRevision
101 //
102 0
103 };
104
105
106 /**
107
108 Get the full size of smbios structure including optional strings that follow the formatted structure.
109
110 @param Head Pointer to the beginning of smbios structure.
111 @param Size The returned size.
112 @param NumberOfStrings The returned number of optional strings that follow the formatted structure.
113
114 @retval EFI_SUCCESS Size retured in Size.
115 @retval EFI_INVALID_PARAMETER Input smbios structure mal-formed or Size is NULL.
116
117 **/
118 EFI_STATUS
119 EFIAPI
120 GetSmbiosStructureSize (
121 IN EFI_SMBIOS_TABLE_HEADER *Head,
122 OUT UINTN *Size,
123 OUT UINTN *NumberOfStrings
124 )
125 {
126 UINTN FullSize;
127 UINT8 StrLen;
128 INT8* CharInStr;
129
130 if (Size == NULL || NumberOfStrings == NULL) {
131 return EFI_INVALID_PARAMETER;
132 }
133
134 FullSize = Head->Length;
135 CharInStr = (INT8*)Head + Head->Length;
136 *Size = FullSize;
137 *NumberOfStrings = 0;
138 StrLen = 0;
139 //
140 // look for the two consecutive zeros, check the string limit by the way.
141 //
142 while (*CharInStr != 0 || *(CharInStr+1) != 0) {
143 if (*CharInStr == 0) {
144 *NumberOfStrings += 1;
145 *Size += 1;
146 CharInStr++;
147 }
148
149 for (StrLen = 0 ; StrLen < SMBIOS_STRING_MAX_LENGTH; StrLen++) {
150 if (*(CharInStr+StrLen) == 0) {
151 break;
152 }
153 }
154
155 if (StrLen == SMBIOS_STRING_MAX_LENGTH) {
156 return EFI_INVALID_PARAMETER;
157 }
158 //
159 // forward the pointer
160 //
161 CharInStr += StrLen;
162 *Size += StrLen;
163
164 }
165
166 if (*NumberOfStrings > 0) {
167 *NumberOfStrings += 1;
168 }
169 //
170 // count ending two zeros.
171 //
172 *Size += 2;
173 return EFI_SUCCESS;
174 }
175
176 /**
177
178 Determin whether an SmbiosHandle has already in use.
179
180 @param Head Pointer to the beginning of smbios structure.
181 @param Handle A unique handle will be assigned to the SMBIOS record.
182
183 @retval TRUE Smbios handle already in use.
184 @retval FALSE Smbios handle is NOT used.
185
186 **/
187 BOOLEAN
188 EFIAPI
189 CheckSmbiosHandleExistance (
190 IN LIST_ENTRY *Head,
191 IN EFI_SMBIOS_HANDLE Handle
192 )
193 {
194 LIST_ENTRY *Link;
195 SMBIOS_HANDLE_ENTRY *HandleEntry;
196
197 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
198 HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK(Link);
199 if (HandleEntry->SmbiosHandle == Handle) {
200 return TRUE;
201 }
202 }
203
204 return FALSE;
205 }
206
207 /**
208
209 Get the max SmbiosHandle that could be use.
210
211 @param This The EFI_SMBIOS_PROTOCOL instance.
212 @param MaxHandle The max handle that could be assigned to the SMBIOS record.
213
214 **/
215 VOID
216 EFIAPI
217 GetMaxSmbiosHandle (
218 IN CONST EFI_SMBIOS_PROTOCOL *This,
219 IN OUT EFI_SMBIOS_HANDLE *MaxHandle
220 )
221 {
222 if (This->MajorVersion == 2 && This->MinorVersion == 0) {
223 *MaxHandle = 0xFFFE;
224 } else {
225 *MaxHandle = 0xFEFF;
226 }
227 }
228
229 /**
230
231 Get an SmbiosHandle that could use.
232
233 @param This The EFI_SMBIOS_PROTOCOL instance.
234 @param SmbiosHandle A unique handle will be assigned to the SMBIOS record.
235
236 @retval EFI_SUCCESS Smbios handle got.
237 @retval EFI_OUT_OF_RESOURCES Smbios handle is NOT available.
238
239 **/
240 EFI_STATUS
241 EFIAPI
242 GetAvailableSmbiosHandle (
243 IN CONST EFI_SMBIOS_PROTOCOL *This,
244 IN OUT EFI_SMBIOS_HANDLE *Handle
245 )
246 {
247 LIST_ENTRY *Head;
248 SMBIOS_INSTANCE *Private;
249 EFI_SMBIOS_HANDLE MaxSmbiosHandle;
250 EFI_SMBIOS_HANDLE AvailableHandle;
251
252 GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
253
254 Private = SMBIOS_INSTANCE_FROM_THIS (This);
255 Head = &Private->AllocatedHandleListHead;
256 for (AvailableHandle = 1; AvailableHandle < MaxSmbiosHandle; AvailableHandle++) {
257 if (!CheckSmbiosHandleExistance(Head, AvailableHandle)) {
258 *Handle = AvailableHandle;
259 return EFI_SUCCESS;
260 }
261 }
262
263 return EFI_OUT_OF_RESOURCES;
264 }
265
266
267 /**
268 Add an SMBIOS record.
269
270 @param This The EFI_SMBIOS_PROTOCOL instance.
271 @param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL
272 means no handle.
273 @param SmbiosHandle On entry, if non-zero, the handle of the SMBIOS record. If zero, then a unique handle
274 will be assigned to the SMBIOS record. If the SMBIOS handle is already in use
275 EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated.
276 @param Record The data for the fixed portion of the SMBIOS record. The format of the record is
277 determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined
278 by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or
279 a set of null terminated strings and a null.
280
281 @retval EFI_SUCCESS Record was added.
282 @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources.
283 @retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use.
284
285 **/
286 EFI_STATUS
287 EFIAPI
288 SmbiosAdd (
289 IN CONST EFI_SMBIOS_PROTOCOL *This,
290 IN EFI_HANDLE ProducerHandle, OPTIONAL
291 IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,
292 IN EFI_SMBIOS_TABLE_HEADER *Record
293 )
294 {
295 VOID *Raw;
296 UINTN TotalSize;
297 UINTN RecordSize;
298 UINTN StructureSize;
299 UINTN NumberOfStrings;
300 EFI_STATUS Status;
301 LIST_ENTRY *Head;
302 SMBIOS_INSTANCE *Private;
303 EFI_SMBIOS_ENTRY *SmbiosEntry;
304 EFI_SMBIOS_HANDLE MaxSmbiosHandle;
305 SMBIOS_HANDLE_ENTRY *HandleEntry;
306 EFI_SMBIOS_RECORD_HEADER *InternalRecord;
307
308 if (SmbiosHandle == NULL) {
309 return EFI_INVALID_PARAMETER;
310 }
311
312 Private = SMBIOS_INSTANCE_FROM_THIS (This);
313 //
314 // Check whether SmbiosHandle is already in use
315 //
316 Head = &Private->AllocatedHandleListHead;
317 if (*SmbiosHandle != 0 && CheckSmbiosHandleExistance(Head, *SmbiosHandle)) {
318 return EFI_ALREADY_STARTED;
319 }
320
321 //
322 // when SmbiosHandle is zero, an available handle will be assigned
323 //
324 if (*SmbiosHandle == 0) {
325 Status = GetAvailableSmbiosHandle(This, SmbiosHandle);
326 if (EFI_ERROR(Status)) {
327 return Status;
328 }
329 } else {
330 //
331 // Check this handle validity
332 //
333 GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
334 if (*SmbiosHandle > MaxSmbiosHandle) {
335 return EFI_INVALID_PARAMETER;
336 }
337 }
338
339 //
340 // Calculate record size and string number
341 //
342 Status = GetSmbiosStructureSize(Record, &StructureSize, &NumberOfStrings);
343 if (EFI_ERROR(Status)) {
344 return Status;
345 }
346
347 //
348 // Enter into critical section
349 //
350 Status = EfiAcquireLockOrFail (&Private->DataLock);
351 if (EFI_ERROR (Status)) {
352 return Status;
353 }
354
355 RecordSize = sizeof (EFI_SMBIOS_RECORD_HEADER) + StructureSize;
356 TotalSize = sizeof (EFI_SMBIOS_ENTRY) + RecordSize;
357
358 //
359 // Allocate internal buffer
360 //
361 SmbiosEntry = AllocateZeroPool (TotalSize);
362 if (SmbiosEntry == NULL) {
363 EfiReleaseLock (&Private->DataLock);
364 return EFI_OUT_OF_RESOURCES;
365 }
366 HandleEntry = AllocateZeroPool (sizeof(SMBIOS_HANDLE_ENTRY));
367 if (HandleEntry == NULL) {
368 EfiReleaseLock (&Private->DataLock);
369 return EFI_OUT_OF_RESOURCES;
370 }
371
372 //
373 // Build Handle Entry and insert into linked list
374 //
375 HandleEntry->Signature = SMBIOS_HANDLE_ENTRY_SIGNATURE;
376 HandleEntry->SmbiosHandle = *SmbiosHandle;
377 InsertTailList(&Private->AllocatedHandleListHead, &HandleEntry->Link);
378
379 InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (SmbiosEntry + 1);
380 Raw = (VOID *) (InternalRecord + 1);
381
382 //
383 // Build internal record Header
384 //
385 InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;
386 InternalRecord->HeaderSize = sizeof (EFI_SMBIOS_RECORD_HEADER);
387 InternalRecord->RecordSize = RecordSize;
388 InternalRecord->ProducerHandle = ProducerHandle;
389 InternalRecord->NumberOfStrings = NumberOfStrings;
390 //
391 // Insert record into the internal linked list
392 //
393 SmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;
394 SmbiosEntry->RecordHeader = InternalRecord;
395 SmbiosEntry->RecordSize = TotalSize;
396 InsertTailList (&Private->DataListHead, &SmbiosEntry->Link);
397
398 CopyMem (Raw, Record, StructureSize);
399 ((EFI_SMBIOS_TABLE_HEADER*)Raw)->Handle = *SmbiosHandle;
400
401 //
402 // Leave critical section
403 //
404 EfiReleaseLock (&Private->DataLock);
405 return EFI_SUCCESS;
406 }
407
408 /**
409 Update the string associated with an existing SMBIOS record.
410
411 @param This The EFI_SMBIOS_PROTOCOL instance.
412 @param SmbiosHandle SMBIOS Handle of structure that will have its string updated.
413 @param StringNumber The non-zero string number of the string to update
414 @param String Update the StringNumber string with String.
415
416 @retval EFI_SUCCESS SmbiosHandle had its StringNumber String updated.
417 @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist.
418 @retval EFI_UNSUPPORTED String was not added since it's longer than 64 significant characters.
419 @retval EFI_NOT_FOUND The StringNumber.is not valid for this SMBIOS record.
420
421 **/
422 EFI_STATUS
423 EFIAPI
424 SmbiosUpdateString (
425 IN CONST EFI_SMBIOS_PROTOCOL *This,
426 IN EFI_SMBIOS_HANDLE *SmbiosHandle,
427 IN UINTN *StringNumber,
428 IN CHAR8 *String
429 )
430 {
431 UINTN InputStrLen;
432 UINTN TargetStrLen;
433 UINTN StrIndex;
434 UINTN TargetStrOffset;
435 UINTN NewEntrySize;
436 CHAR8 *StrStart;
437 VOID *Raw;
438 LIST_ENTRY *Link;
439 LIST_ENTRY *Head;
440 EFI_STATUS Status;
441 SMBIOS_INSTANCE *Private;
442 EFI_SMBIOS_ENTRY *SmbiosEntry;
443 EFI_SMBIOS_ENTRY *ResizedSmbiosEntry;
444 EFI_SMBIOS_HANDLE MaxSmbiosHandle;
445 EFI_SMBIOS_TABLE_HEADER *Record;
446 EFI_SMBIOS_RECORD_HEADER *InternalRecord;
447
448 //
449 // Check args validity
450 //
451 GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
452
453 if (*SmbiosHandle > MaxSmbiosHandle) {
454 return EFI_INVALID_PARAMETER;
455 }
456
457 if (String == NULL) {
458 return EFI_ABORTED;
459 }
460
461 if (*StringNumber == 0) {
462 return EFI_NOT_FOUND;
463 }
464
465 InputStrLen = AsciiStrLen(String);
466 if (InputStrLen > SMBIOS_STRING_MAX_LENGTH) {
467 return EFI_UNSUPPORTED;
468 }
469
470 Private = SMBIOS_INSTANCE_FROM_THIS (This);
471 //
472 // Enter into critical section
473 //
474 Status = EfiAcquireLockOrFail (&Private->DataLock);
475 if (EFI_ERROR (Status)) {
476 return Status;
477 }
478
479 Head = &Private->DataListHead;
480 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
481 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
482 Record = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
483
484 if ((UINTN)Record->Handle == *SmbiosHandle) {
485 //
486 // Find out the specified Smbios record
487 //
488 if (*StringNumber > SmbiosEntry->RecordHeader->NumberOfStrings) {
489 EfiReleaseLock (&Private->DataLock);
490 return EFI_NOT_FOUND;
491 }
492 //
493 // Point to unformed string section
494 //
495 StrStart = (CHAR8*)Record + Record->Length;
496
497 for (StrIndex = 1, TargetStrOffset = 0; StrIndex < *StringNumber; StrStart++, TargetStrOffset++) {
498 //
499 // A string ends in 00h
500 //
501 if (*StrStart == 0) {
502 StrIndex++;
503 }
504
505 //
506 // String section ends in double-null (0000h)
507 //
508 if (*StrStart == 0 && *(StrStart + 1) == 0) {
509 EfiReleaseLock (&Private->DataLock);
510 return EFI_NOT_FOUND;
511 }
512 }
513
514 //
515 // Now we get the string target
516 //
517 TargetStrLen = AsciiStrLen(StrStart);
518 if (InputStrLen == TargetStrLen) {
519 AsciiStrCpy(StrStart, String);
520 EfiReleaseLock (&Private->DataLock);
521 return EFI_SUCCESS;
522 }
523
524 //
525 // Original string buffer size is not exactly match input string length.
526 // Re-allocate buffer is needed.
527 //
528 NewEntrySize = SmbiosEntry->RecordSize + InputStrLen - TargetStrLen;
529 ResizedSmbiosEntry = AllocateZeroPool (NewEntrySize);
530
531 if (ResizedSmbiosEntry == NULL) {
532 EfiReleaseLock (&Private->DataLock);
533 return EFI_OUT_OF_RESOURCES;
534 }
535
536 InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (ResizedSmbiosEntry + 1);
537 Raw = (VOID *) (InternalRecord + 1);
538
539 //
540 // Build internal record Header
541 //
542 InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;
543 InternalRecord->HeaderSize = sizeof (EFI_SMBIOS_RECORD_HEADER);
544 InternalRecord->RecordSize = SmbiosEntry->RecordHeader->RecordSize + InputStrLen - TargetStrLen;
545 InternalRecord->ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;
546 InternalRecord->NumberOfStrings = SmbiosEntry->RecordHeader->NumberOfStrings;
547
548 //
549 // Copy smbios structure and optional strings.
550 //
551 CopyMem (Raw, SmbiosEntry->RecordHeader + 1, sizeof(EFI_SMBIOS_TABLE_HEADER) + TargetStrOffset);
552 CopyMem ((VOID*)((UINTN)Raw + sizeof(EFI_SMBIOS_TABLE_HEADER) + TargetStrOffset), String, InputStrLen + 1);
553 AsciiStrCpy((CHAR8*)((UINTN)Raw + sizeof(EFI_SMBIOS_TABLE_HEADER) + TargetStrOffset + InputStrLen + 1), (CHAR8*)Record + Record->Length + TargetStrOffset + TargetStrLen + 1);
554
555 //
556 // Insert new record
557 //
558 ResizedSmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;
559 ResizedSmbiosEntry->RecordHeader = InternalRecord;
560 ResizedSmbiosEntry->RecordSize = NewEntrySize;
561 InsertTailList (Link->ForwardLink, &ResizedSmbiosEntry->Link);
562
563 //
564 // Remove old record
565 //
566 RemoveEntryList(Link);
567 FreePool(SmbiosEntry);
568 EfiReleaseLock (&Private->DataLock);
569 return EFI_SUCCESS;
570 }
571 }
572
573 EfiReleaseLock (&Private->DataLock);
574 return EFI_INVALID_PARAMETER;
575 }
576
577 /**
578 Remove an SMBIOS record.
579
580 @param This The EFI_SMBIOS_PROTOCOL instance.
581 @param SmbiosHandle The handle of the SMBIOS record to remove.
582
583 @retval EFI_SUCCESS SMBIOS record was removed.
584 @retval EFI_INVALID_PARAMETER SmbiosHandle does not specify a valid SMBIOS record.
585
586 **/
587 EFI_STATUS
588 EFIAPI
589 SmbiosRemove (
590 IN CONST EFI_SMBIOS_PROTOCOL *This,
591 IN EFI_SMBIOS_HANDLE SmbiosHandle
592 )
593 {
594 LIST_ENTRY *Link;
595 LIST_ENTRY *Head;
596 EFI_STATUS Status;
597 EFI_SMBIOS_HANDLE MaxSmbiosHandle;
598 SMBIOS_INSTANCE *Private;
599 EFI_SMBIOS_ENTRY *SmbiosEntry;
600 SMBIOS_HANDLE_ENTRY *HandleEntry;
601 EFI_SMBIOS_TABLE_HEADER *Record;
602
603 //
604 // Check args validity
605 //
606 GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
607
608 if (SmbiosHandle > MaxSmbiosHandle) {
609 return EFI_INVALID_PARAMETER;
610 }
611
612 Private = SMBIOS_INSTANCE_FROM_THIS (This);
613 //
614 // Enter into critical section
615 //
616 Status = EfiAcquireLockOrFail (&Private->DataLock);
617 if (EFI_ERROR (Status)) {
618 return Status;
619 }
620
621 Head = &Private->DataListHead;
622 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
623 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
624 Record = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
625 if ((UINTN)Record->Handle == SmbiosHandle) {
626 //
627 // Remove specified smobios record from DataList
628 //
629 RemoveEntryList(Link);
630 FreePool(SmbiosEntry);
631 //
632 // Remove this handle from AllocatedHandleList
633 //
634 Head = &Private->AllocatedHandleListHead;
635 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
636 HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK(Link);
637 if ((UINTN)HandleEntry->SmbiosHandle == SmbiosHandle) {
638 RemoveEntryList(Link);
639 FreePool(HandleEntry);
640 break;
641 }
642 }
643 EfiReleaseLock (&Private->DataLock);
644 return EFI_SUCCESS;
645 }
646 }
647
648 //
649 // Leave critical section
650 //
651 EfiReleaseLock (&Private->DataLock);
652 return EFI_INVALID_PARAMETER;
653
654 }
655
656 /**
657 Allow the caller to discover all or some of the SMBIOS records.
658
659 @param This The EFI_SMBIOS_PROTOCOL instance.
660 @param SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the
661 next SMBIOS record handle. If it is zero on entry, then the first SMBIOS record
662 handle will be returned. If it returns zero on exit, then there are no more SMBIOS records.
663 @param Type On entry it means return the next SMBIOS record of type Type. If a NULL is passed in
664 this functionally it ignored. Type is not modified by the GetNext() function.
665 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
666 the unformatted area. The unformatted area optionally contains text strings.
667 @param ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no ProducerHandle was passed into Add() NULL is returned.
668 If a NULL pointer is passed in no data will be returned
669
670 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
671 SmbiosHandle is the handle of the current SMBIOS record
672 @retval EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record.
673
674 **/
675 EFI_STATUS
676 EFIAPI
677 SmbiosGetNext (
678 IN CONST EFI_SMBIOS_PROTOCOL *This,
679 IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,
680 IN EFI_SMBIOS_TYPE *Type, OPTIONAL
681 OUT EFI_SMBIOS_TABLE_HEADER **Record,
682 OUT EFI_HANDLE *ProducerHandle OPTIONAL
683 )
684 {
685 BOOLEAN StartPointFound;
686 LIST_ENTRY *Link;
687 LIST_ENTRY *Head;
688 SMBIOS_INSTANCE *Private;
689 EFI_SMBIOS_ENTRY *SmbiosEntry;
690 EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader;
691
692 if (SmbiosHandle == NULL) {
693 return EFI_INVALID_PARAMETER;
694 }
695
696 StartPointFound = FALSE;
697 Private = SMBIOS_INSTANCE_FROM_THIS (This);
698 Head = &Private->DataListHead;
699 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
700 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
701 SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
702
703 //
704 // If SmbiosHandle is zero, the first matched SMBIOS record handle will be returned
705 //
706 if (*SmbiosHandle == 0) {
707 if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {
708 continue;
709 }
710
711 *SmbiosHandle = SmbiosTableHeader->Handle;
712 *Record =SmbiosTableHeader;
713 if (ProducerHandle != NULL) {
714 *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;
715 }
716 return EFI_SUCCESS;
717 }
718
719 //
720 // Start this round search from the next Smbios handle
721 //
722 if (!StartPointFound && (*SmbiosHandle == SmbiosTableHeader->Handle)) {
723 StartPointFound = TRUE;
724 continue;
725 }
726
727 if (StartPointFound) {
728 if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {
729 continue;
730 }
731
732 *SmbiosHandle = SmbiosTableHeader->Handle;
733 *Record = SmbiosTableHeader;
734 if (ProducerHandle != NULL) {
735 *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;
736 }
737
738 return EFI_SUCCESS;
739 }
740 }
741
742 *SmbiosHandle = 0;
743 return EFI_NOT_FOUND;
744
745 }
746
747
748 /**
749 Assembles Smbios table from the SMBIOS protocol. Produce Table
750 Entry Point and return the pointer to it.
751
752 @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.
753
754 @retval EFI_SUCCESS Structure created sucessfully.
755 @retval EFI_NOT_READY Some of The SMBIOS records was not available yet.
756 @retval EFI_OUT_OF_RESOURCES No enough memory.
757
758 **/
759 EFI_STATUS
760 EFIAPI
761 SmbiosCreateTable (
762 OUT VOID **TableEntryPointStructure
763 )
764 {
765 UINT8 CheckSum;
766 UINT8 *BufferPointer;
767 UINTN Index;
768 UINTN RecordSize;
769 UINTN NumOfStr;
770 EFI_STATUS Status;
771 EFI_SMBIOS_HANDLE SmbiosHandle;
772 EFI_SMBIOS_PROTOCOL *SmbiosProtocol;
773 EFI_PHYSICAL_ADDRESS PhysicalAddress;
774 EFI_SMBIOS_TABLE_HEADER *SmbiosRecord;
775 EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure;
776
777 Status = EFI_SUCCESS;
778 BufferPointer = NULL;
779 CheckSum = 0;
780
781 //
782 // Initialize the EntryPointStructure with initial values.
783 //
784 if (EntryPointStructure == NULL) {
785 //
786 // Allocate memory (below 4GB)
787 //
788 PhysicalAddress = 0xffffffff;
789 Status = gBS->AllocatePages (
790 AllocateMaxAddress,
791 EfiReservedMemoryType,
792 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),
793 &PhysicalAddress
794 );
795 if (EFI_ERROR (Status)) {
796 return EFI_OUT_OF_RESOURCES;
797 }
798
799 EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) (UINTN) PhysicalAddress;
800
801 CopyMem (
802 EntryPointStructure,
803 &EntryPointStructureData,
804 sizeof (SMBIOS_TABLE_ENTRY_POINT)
805 );
806 }
807
808 //
809 // Free the original image
810 //
811 if (EntryPointStructure->TableAddress != 0) {
812 FreePages (
813 (VOID*)(UINTN)EntryPointStructure->TableAddress,
814 EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength)
815 );
816 EntryPointStructure->TableAddress = 0;
817 }
818
819 //
820 // Locate smbios protocol to traverse smbios records.
821 //
822 Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **) &SmbiosProtocol);
823 ASSERT_EFI_ERROR (Status);
824 ASSERT (SmbiosProtocol != NULL);
825
826 //
827 // Make some statistics about all the structures
828 //
829 EntryPointStructure->NumberOfSmbiosStructures = 0;
830 EntryPointStructure->TableLength = 0;
831 EntryPointStructure->MaxStructureSize = 0;
832 SmbiosHandle = 0;
833
834 //
835 // Calculate EPS Table Length
836 //
837 do {
838 Status = SmbiosProtocol->GetNext (
839 SmbiosProtocol,
840 &SmbiosHandle,
841 NULL,
842 &SmbiosRecord,
843 NULL
844 );
845
846 if (Status == EFI_SUCCESS) {
847 GetSmbiosStructureSize(SmbiosRecord, &RecordSize, &NumOfStr);
848 //
849 // Record NumberOfSmbiosStructures, TableLength and MaxStructureSize
850 //
851 EntryPointStructure->NumberOfSmbiosStructures ++;
852 EntryPointStructure->TableLength = (UINT16) (EntryPointStructure->TableLength + RecordSize);
853 if (RecordSize > EntryPointStructure->MaxStructureSize) {
854 EntryPointStructure->MaxStructureSize = (UINT16) RecordSize;
855 }
856 }
857 } while (!EFI_ERROR(Status));
858
859 //
860 // Create End-Of-Table structure
861 //
862 GetMaxSmbiosHandle(SmbiosProtocol, &SmbiosHandle);
863 EndStructure.Header.Type = EFI_SMBIOS_TYPE_END_OF_TABLE;
864 EndStructure.Header.Length = sizeof(EFI_SMBIOS_TABLE_HEADER);
865 EndStructure.Header.Handle = SmbiosHandle;
866 EndStructure.Tailing[0] = 0;
867 EndStructure.Tailing[1] = 0;
868 EntryPointStructure->NumberOfSmbiosStructures++;
869 EntryPointStructure->TableLength = (UINT16) (EntryPointStructure->TableLength + sizeof (EndStructure));
870 if (sizeof (EndStructure) > EntryPointStructure->MaxStructureSize) {
871 EntryPointStructure->MaxStructureSize = (UINT16) sizeof (EndStructure);
872 }
873
874 //
875 // Allocate memory (below 4GB)
876 //
877 PhysicalAddress = 0xffffffff;
878 Status = gBS->AllocatePages (
879 AllocateMaxAddress,
880 EfiReservedMemoryType,
881 EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength),
882 &PhysicalAddress
883 );
884 if (EFI_ERROR (Status)) {
885 FreePages ((VOID*)(UINTN)EntryPointStructure, EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength));
886 EntryPointStructure = NULL;
887 return EFI_OUT_OF_RESOURCES;
888 }
889
890 EntryPointStructure->TableAddress = (UINT32) PhysicalAddress;
891
892 //
893 // Assemble the tables
894 //
895 BufferPointer = (UINT8 *) (UINTN) PhysicalAddress;
896 SmbiosHandle = 0;
897 do {
898 Status = SmbiosProtocol->GetNext (
899 SmbiosProtocol,
900 &SmbiosHandle,
901 NULL,
902 &SmbiosRecord,
903 NULL
904 );
905 if (Status == EFI_SUCCESS) {
906 GetSmbiosStructureSize(SmbiosRecord, &RecordSize, &NumOfStr);
907 CopyMem (BufferPointer, SmbiosRecord, RecordSize);
908 BufferPointer = BufferPointer + RecordSize;
909 }
910 } while (!EFI_ERROR(Status));
911
912 //
913 // Assemble End-Of-Table structure
914 //
915 CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure));
916
917 //
918 // Fixup checksums in the Entry Point Structure
919 //
920 CheckSum = 0;
921 EntryPointStructure->IntermediateChecksum = 0;
922 for (Index = 0x10; Index < EntryPointStructure->EntryPointLength; Index++) {
923 CheckSum = (UINT8) (CheckSum + ((UINT8 *) (EntryPointStructure))[Index]);
924 }
925
926 EntryPointStructure->IntermediateChecksum = (UINT8) (0 - CheckSum);
927
928 CheckSum = 0;
929 EntryPointStructure->EntryPointStructureChecksum = 0;
930 for (Index = 0x0; Index < EntryPointStructure->EntryPointLength; Index++) {
931 CheckSum = (UINT8) (CheckSum + ((UINT8 *) (EntryPointStructure))[Index]);
932 }
933
934 EntryPointStructure->EntryPointStructureChecksum = (UINT8) (0 - CheckSum);
935
936 //
937 // Returns the pointer
938 //
939 *TableEntryPointStructure = EntryPointStructure;
940
941 return EFI_SUCCESS;
942 }
943
944
945
946 /**
947 Installs the Smbios Table to the System Table. This function gets called
948 when the EFI_EVENT_SIGNAL_READY_TO_BOOT gets signaled
949
950 @param Event The event to signal
951 @param Context Event contex
952
953 **/
954 VOID
955 EFIAPI
956 SmbiosTableConstruction (
957 IN EFI_EVENT Event,
958 IN VOID *Context
959 )
960 {
961 UINT8 *Eps;
962 EFI_STATUS Status;
963
964 Status = SmbiosCreateTable ((VOID **) &Eps);
965 if (!EFI_ERROR (Status)) {
966 gBS->InstallConfigurationTable (&gEfiSmbiosTableGuid, Eps);
967 }
968 }
969
970
971 /**
972
973 Driver to produce Smbios protocol and register event for constructing SMBIOS table.
974
975 @param ImageHandle Module's image handle
976 @param SystemTable Pointer of EFI_SYSTEM_TABLE
977
978 @retval EFI_SUCCESS Smbios protocol installed
979 @retval Other No protocol installed, unload driver.
980
981 **/
982 EFI_STATUS
983 EFIAPI
984 SmbiosDriverEntryPoint (
985 IN EFI_HANDLE ImageHandle,
986 IN EFI_SYSTEM_TABLE *SystemTable
987 )
988 {
989 EFI_STATUS Status;
990 EFI_EVENT ReadyToBootEvent;
991
992 mPrivateData.Signature = SMBIOS_INSTANCE_SIGNATURE;
993 mPrivateData.Smbios.Add = SmbiosAdd;
994 mPrivateData.Smbios.UpdateString = SmbiosUpdateString;
995 mPrivateData.Smbios.Remove = SmbiosRemove;
996 mPrivateData.Smbios.GetNext = SmbiosGetNext;
997 mPrivateData.Smbios.MajorVersion = SMBIOS_MAJOR_VERSION;
998 mPrivateData.Smbios.MinorVersion = SMBIOS_MINOR_VERSION;
999
1000 InitializeListHead (&mPrivateData.DataListHead);
1001 InitializeListHead (&mPrivateData.AllocatedHandleListHead);
1002 EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);
1003
1004 //
1005 // Make a new handle and install the protocol
1006 //
1007 mPrivateData.Handle = NULL;
1008 Status = gBS->InstallProtocolInterface (
1009 &mPrivateData.Handle,
1010 &gEfiSmbiosProtocolGuid,
1011 EFI_NATIVE_INTERFACE,
1012 &mPrivateData.Smbios
1013 );
1014
1015 if (EFI_ERROR(Status)) {
1016 return Status;
1017 }
1018 //
1019 // Register the event to install SMBIOS Table into EFI System Table
1020 //
1021 Status = gBS->CreateEventEx (
1022 EVT_NOTIFY_SIGNAL,
1023 TPL_NOTIFY,
1024 SmbiosTableConstruction,
1025 NULL,
1026 &gEfiEventReadyToBootGuid,
1027 &ReadyToBootEvent
1028 );
1029
1030 return Status;
1031 }