]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c
1. PI SMBIOS Checkin. Major change include:
[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 = AllocatePool (TotalSize);
362 if (SmbiosEntry == NULL) {
363 EfiReleaseLock (&Private->DataLock);
364 return EFI_OUT_OF_RESOURCES;
365 }
366 HandleEntry = AllocatePool (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 ZeroMem(HandleEntry, sizeof(SMBIOS_HANDLE_ENTRY));
376 HandleEntry->Signature = SMBIOS_HANDLE_ENTRY_SIGNATURE;
377 HandleEntry->SmbiosHandle = *SmbiosHandle;
378 InsertTailList(&Private->AllocatedHandleListHead, &HandleEntry->Link);
379
380 ZeroMem (SmbiosEntry, TotalSize);
381 InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (SmbiosEntry + 1);
382 Raw = (VOID *) (InternalRecord + 1);
383
384 //
385 // Build internal record Header
386 //
387 InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;
388 InternalRecord->HeaderSize = sizeof (EFI_SMBIOS_RECORD_HEADER);
389 InternalRecord->RecordSize = RecordSize;
390 InternalRecord->ProducerHandle = ProducerHandle;
391 InternalRecord->NumberOfStrings = NumberOfStrings;
392 //
393 // Insert record into the internal linked list
394 //
395 SmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;
396 SmbiosEntry->RecordHeader = InternalRecord;
397 SmbiosEntry->RecordSize = TotalSize;
398 InsertTailList (&Private->DataListHead, &SmbiosEntry->Link);
399
400 CopyMem (Raw, Record, StructureSize);
401 ((EFI_SMBIOS_TABLE_HEADER*)Raw)->Handle = *SmbiosHandle;
402
403 //
404 // Leave critical section
405 //
406 EfiReleaseLock (&Private->DataLock);
407 return EFI_SUCCESS;
408 }
409
410 /**
411 Update the string associated with an existing SMBIOS record.
412
413 @param This The EFI_SMBIOS_PROTOCOL instance.
414 @param SmbiosHandle SMBIOS Handle of structure that will have its string updated.
415 @param StringNumber The non-zero string number of the string to update
416 @param String Update the StringNumber string with String.
417
418 @retval EFI_SUCCESS SmbiosHandle had its StringNumber String updated.
419 @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist.
420 @retval EFI_UNSUPPORTED String was not added since it's longer than 64 significant characters.
421 @retval EFI_NOT_FOUND The StringNumber.is not valid for this SMBIOS record.
422
423 **/
424 EFI_STATUS
425 EFIAPI
426 SmbiosUpdateString (
427 IN CONST EFI_SMBIOS_PROTOCOL *This,
428 IN EFI_SMBIOS_HANDLE *SmbiosHandle,
429 IN UINTN *StringNumber,
430 IN CHAR8 *String
431 )
432 {
433 UINTN InputStrLen;
434 UINTN TargetStrLen;
435 UINTN StrIndex;
436 UINTN TargetStrOffset;
437 UINTN NewEntrySize;
438 CHAR8 *StrStart;
439 VOID *Raw;
440 LIST_ENTRY *Link;
441 LIST_ENTRY *Head;
442 EFI_STATUS Status;
443 SMBIOS_INSTANCE *Private;
444 EFI_SMBIOS_ENTRY *SmbiosEntry;
445 EFI_SMBIOS_ENTRY *ResizedSmbiosEntry;
446 EFI_SMBIOS_HANDLE MaxSmbiosHandle;
447 EFI_SMBIOS_TABLE_HEADER *Record;
448 EFI_SMBIOS_RECORD_HEADER *InternalRecord;
449
450 //
451 // Check args validity
452 //
453 GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
454
455 if (*SmbiosHandle > MaxSmbiosHandle) {
456 return EFI_INVALID_PARAMETER;
457 }
458
459 if (String == NULL) {
460 return EFI_ABORTED;
461 }
462
463 if (*StringNumber == 0) {
464 return EFI_NOT_FOUND;
465 }
466
467 InputStrLen = AsciiStrLen(String);
468 if (InputStrLen > SMBIOS_STRING_MAX_LENGTH) {
469 return EFI_UNSUPPORTED;
470 }
471
472 Private = SMBIOS_INSTANCE_FROM_THIS (This);
473 //
474 // Enter into critical section
475 //
476 Status = EfiAcquireLockOrFail (&Private->DataLock);
477 if (EFI_ERROR (Status)) {
478 return Status;
479 }
480
481 Head = &Private->DataListHead;
482 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
483 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
484 Record = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
485
486 if ((UINTN)Record->Handle == *SmbiosHandle) {
487 //
488 // Find out the specified Smbios record
489 //
490 if (*StringNumber > SmbiosEntry->RecordHeader->NumberOfStrings) {
491 EfiReleaseLock (&Private->DataLock);
492 return EFI_NOT_FOUND;
493 }
494 //
495 // Point to unformed string section
496 //
497 StrStart = (CHAR8*)Record + Record->Length;
498
499 for (StrIndex = 1, TargetStrOffset = 0; StrIndex < *StringNumber; StrStart++, TargetStrOffset++) {
500 //
501 // A string ends in 00h
502 //
503 if (*StrStart == 0) {
504 StrIndex++;
505 }
506
507 //
508 // String section ends in double-null (0000h)
509 //
510 if (*StrStart == 0 && *(StrStart + 1) == 0) {
511 EfiReleaseLock (&Private->DataLock);
512 return EFI_NOT_FOUND;
513 }
514 }
515
516 //
517 // Now we get the string target
518 //
519 TargetStrLen = AsciiStrLen(StrStart);
520 if (InputStrLen == TargetStrLen) {
521 AsciiStrCpy(StrStart, String);
522 EfiReleaseLock (&Private->DataLock);
523 return EFI_SUCCESS;
524 }
525
526 //
527 // Original string buffer size is not exactly match input string length.
528 // Re-allocate buffer is needed.
529 //
530 NewEntrySize = SmbiosEntry->RecordSize + InputStrLen - TargetStrLen;
531 ResizedSmbiosEntry = AllocatePool (NewEntrySize);
532
533 if (ResizedSmbiosEntry == NULL) {
534 EfiReleaseLock (&Private->DataLock);
535 return EFI_OUT_OF_RESOURCES;
536 }
537
538 ZeroMem (ResizedSmbiosEntry, NewEntrySize);
539 InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (ResizedSmbiosEntry + 1);
540 Raw = (VOID *) (InternalRecord + 1);
541
542 //
543 // Build internal record Header
544 //
545 InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;
546 InternalRecord->HeaderSize = sizeof (EFI_SMBIOS_RECORD_HEADER);
547 InternalRecord->RecordSize = SmbiosEntry->RecordHeader->RecordSize + InputStrLen - TargetStrLen;
548 InternalRecord->ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;
549 InternalRecord->NumberOfStrings = SmbiosEntry->RecordHeader->NumberOfStrings;
550
551 //
552 // Copy smbios structure and optional strings.
553 //
554 CopyMem (Raw, SmbiosEntry->RecordHeader + 1, sizeof(EFI_SMBIOS_TABLE_HEADER) + TargetStrOffset);
555 CopyMem ((VOID*)((UINTN)Raw + sizeof(EFI_SMBIOS_TABLE_HEADER) + TargetStrOffset), String, InputStrLen + 1);
556 AsciiStrCpy((CHAR8*)((UINTN)Raw + sizeof(EFI_SMBIOS_TABLE_HEADER) + TargetStrOffset + InputStrLen + 1), (CHAR8*)Record + Record->Length + TargetStrOffset + TargetStrLen + 1);
557
558 //
559 // Insert new record
560 //
561 ResizedSmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;
562 ResizedSmbiosEntry->RecordHeader = InternalRecord;
563 ResizedSmbiosEntry->RecordSize = NewEntrySize;
564 InsertTailList (Link->ForwardLink, &ResizedSmbiosEntry->Link);
565
566 //
567 // Remove old record
568 //
569 RemoveEntryList(Link);
570 FreePool(SmbiosEntry);
571 EfiReleaseLock (&Private->DataLock);
572 return EFI_SUCCESS;
573 }
574 }
575
576 EfiReleaseLock (&Private->DataLock);
577 return EFI_INVALID_PARAMETER;
578 }
579
580 /**
581 Remove an SMBIOS record.
582
583 @param This The EFI_SMBIOS_PROTOCOL instance.
584 @param SmbiosHandle The handle of the SMBIOS record to remove.
585
586 @retval EFI_SUCCESS SMBIOS record was removed.
587 @retval EFI_INVALID_PARAMETER SmbiosHandle does not specify a valid SMBIOS record.
588
589 **/
590 EFI_STATUS
591 EFIAPI
592 SmbiosRemove (
593 IN CONST EFI_SMBIOS_PROTOCOL *This,
594 IN EFI_SMBIOS_HANDLE SmbiosHandle
595 )
596 {
597 LIST_ENTRY *Link;
598 LIST_ENTRY *Head;
599 EFI_STATUS Status;
600 EFI_SMBIOS_HANDLE MaxSmbiosHandle;
601 SMBIOS_INSTANCE *Private;
602 EFI_SMBIOS_ENTRY *SmbiosEntry;
603 SMBIOS_HANDLE_ENTRY *HandleEntry;
604 EFI_SMBIOS_TABLE_HEADER *Record;
605
606 //
607 // Check args validity
608 //
609 GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
610
611 if (SmbiosHandle > MaxSmbiosHandle) {
612 return EFI_INVALID_PARAMETER;
613 }
614
615 Private = SMBIOS_INSTANCE_FROM_THIS (This);
616 //
617 // Enter into critical section
618 //
619 Status = EfiAcquireLockOrFail (&Private->DataLock);
620 if (EFI_ERROR (Status)) {
621 return Status;
622 }
623
624 Head = &Private->DataListHead;
625 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
626 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
627 Record = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
628 if ((UINTN)Record->Handle == SmbiosHandle) {
629 //
630 // Remove specified smobios record from DataList
631 //
632 RemoveEntryList(Link);
633 FreePool(SmbiosEntry);
634 //
635 // Remove this handle from AllocatedHandleList
636 //
637 Head = &Private->AllocatedHandleListHead;
638 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
639 HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK(Link);
640 if ((UINTN)HandleEntry->SmbiosHandle == SmbiosHandle) {
641 RemoveEntryList(Link);
642 FreePool(HandleEntry);
643 break;
644 }
645 }
646 EfiReleaseLock (&Private->DataLock);
647 return EFI_SUCCESS;
648 }
649 }
650
651 //
652 // Leave critical section
653 //
654 EfiReleaseLock (&Private->DataLock);
655 return EFI_INVALID_PARAMETER;
656
657 }
658
659 /**
660 Allow the caller to discover all or some of the SMBIOS records.
661
662 @param This The EFI_SMBIOS_PROTOCOL instance.
663 @param SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the
664 next SMBIOS record handle. If it is zero on entry, then the first SMBIOS record
665 handle will be returned. If it returns zero on exit, then there are no more SMBIOS records.
666 @param Type On entry it means return the next SMBIOS record of type Type. If a NULL is passed in
667 this functionally it ignored. Type is not modified by the GetNext() function.
668 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
669 the unformatted area. The unformatted area optionally contains text strings.
670 @param ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no ProducerHandle was passed into Add() NULL is returned.
671 If a NULL pointer is passed in no data will be returned
672
673 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
674 SmbiosHandle is the handle of the current SMBIOS record
675 @retval EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record.
676
677 **/
678 EFI_STATUS
679 EFIAPI
680 SmbiosGetNext (
681 IN CONST EFI_SMBIOS_PROTOCOL *This,
682 IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,
683 IN EFI_SMBIOS_TYPE *Type, OPTIONAL
684 OUT EFI_SMBIOS_TABLE_HEADER **Record,
685 OUT EFI_HANDLE *ProducerHandle OPTIONAL
686 )
687 {
688 BOOLEAN StartPointFound;
689 LIST_ENTRY *Link;
690 LIST_ENTRY *Head;
691 SMBIOS_INSTANCE *Private;
692 EFI_SMBIOS_ENTRY *SmbiosEntry;
693 EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader;
694
695 if (SmbiosHandle == NULL) {
696 return EFI_INVALID_PARAMETER;
697 }
698
699 StartPointFound = FALSE;
700 Private = SMBIOS_INSTANCE_FROM_THIS (This);
701 Head = &Private->DataListHead;
702 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
703 SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
704 SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
705
706 //
707 // If SmbiosHandle is zero, the first matched SMBIOS record handle will be returned
708 //
709 if (*SmbiosHandle == 0) {
710 if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {
711 continue;
712 }
713
714 *SmbiosHandle = SmbiosTableHeader->Handle;
715 *Record =SmbiosTableHeader;
716 if (ProducerHandle != NULL) {
717 *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;
718 }
719 return EFI_SUCCESS;
720 }
721
722 //
723 // Start this round search from the next Smbios handle
724 //
725 if (!StartPointFound && (*SmbiosHandle == SmbiosTableHeader->Handle)) {
726 StartPointFound = TRUE;
727 continue;
728 }
729
730 if (StartPointFound) {
731 if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {
732 continue;
733 }
734
735 *SmbiosHandle = SmbiosTableHeader->Handle;
736 *Record = SmbiosTableHeader;
737 if (ProducerHandle != NULL) {
738 *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;
739 }
740
741 return EFI_SUCCESS;
742 }
743 }
744
745 *SmbiosHandle = 0;
746 return EFI_NOT_FOUND;
747
748 }
749
750
751 /**
752 Assembles Smbios table from the SMBIOS protocol. Produce Table
753 Entry Point and return the pointer to it.
754
755 @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.
756
757 @retval EFI_SUCCESS Structure created sucessfully.
758 @retval EFI_NOT_READY Some of The SMBIOS records was not available yet.
759 @retval EFI_OUT_OF_RESOURCES No enough memory.
760
761 **/
762 EFI_STATUS
763 EFIAPI
764 SmbiosCreateTable (
765 OUT VOID **TableEntryPointStructure
766 )
767 {
768 UINT8 CheckSum;
769 UINT8 *BufferPointer;
770 UINTN Index;
771 UINTN RecordSize;
772 UINTN NumOfStr;
773 EFI_STATUS Status;
774 EFI_SMBIOS_HANDLE SmbiosHandle;
775 EFI_SMBIOS_PROTOCOL *SmbiosProtocol;
776 EFI_PHYSICAL_ADDRESS PhysicalAddress;
777 EFI_SMBIOS_TABLE_HEADER *SmbiosRecord;
778 EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure;
779
780 Status = EFI_SUCCESS;
781 BufferPointer = NULL;
782 CheckSum = 0;
783
784 //
785 // Initialize the EntryPointStructure with initial values.
786 //
787 if (EntryPointStructure == NULL) {
788 //
789 // Allocate memory (below 4GB)
790 //
791 PhysicalAddress = 0xffffffff;
792 Status = gBS->AllocatePages (
793 AllocateMaxAddress,
794 EfiReservedMemoryType,
795 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),
796 &PhysicalAddress
797 );
798 if (EFI_ERROR (Status)) {
799 return EFI_OUT_OF_RESOURCES;
800 }
801
802 EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) (UINTN) PhysicalAddress;
803
804 CopyMem (
805 EntryPointStructure,
806 &EntryPointStructureData,
807 sizeof (SMBIOS_TABLE_ENTRY_POINT)
808 );
809 }
810
811 //
812 // Free the original image
813 //
814 if (EntryPointStructure->TableAddress) {
815 FreePages (
816 (VOID*)(UINTN)EntryPointStructure->TableAddress,
817 EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength)
818 );
819 EntryPointStructure->TableAddress = 0;
820 }
821
822 //
823 // Locate smbios protocol to traverse smbios records.
824 //
825 gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **) &SmbiosProtocol);
826
827 ASSERT (SmbiosProtocol != NULL);
828
829 //
830 // Make some statistics about all the structures
831 //
832 EntryPointStructure->NumberOfSmbiosStructures = 0;
833 EntryPointStructure->TableLength = 0;
834 EntryPointStructure->MaxStructureSize = 0;
835 SmbiosHandle = 0;
836
837 //
838 // Calculate EPS Table Length
839 //
840 do {
841 Status = SmbiosProtocol->GetNext (
842 SmbiosProtocol,
843 &SmbiosHandle,
844 NULL,
845 &SmbiosRecord,
846 NULL
847 );
848
849 if (Status == EFI_SUCCESS) {
850 GetSmbiosStructureSize(SmbiosRecord, &RecordSize, &NumOfStr);
851 //
852 // Record NumberOfSmbiosStructures, TableLength and MaxStructureSize
853 //
854 EntryPointStructure->NumberOfSmbiosStructures++;
855 EntryPointStructure->TableLength = (UINT16) (EntryPointStructure->TableLength + RecordSize);
856 if (RecordSize > EntryPointStructure->MaxStructureSize) {
857 EntryPointStructure->MaxStructureSize = (UINT16) RecordSize;
858 }
859 }
860 } while (!EFI_ERROR(Status));
861
862 //
863 // Create End-Of-Table structure
864 //
865 GetMaxSmbiosHandle(SmbiosProtocol, &SmbiosHandle);
866 EndStructure.Header.Type = EFI_SMBIOS_TYPE_END_OF_TABLE;
867 EndStructure.Header.Length = sizeof(EFI_SMBIOS_TABLE_HEADER);
868 EndStructure.Header.Handle = SmbiosHandle;
869 EndStructure.Tailing[0] = 0;
870 EndStructure.Tailing[1] = 0;
871 EntryPointStructure->NumberOfSmbiosStructures++;
872 EntryPointStructure->TableLength = (UINT16) (EntryPointStructure->TableLength + sizeof (EndStructure));
873 if (sizeof (EndStructure) > EntryPointStructure->MaxStructureSize) {
874 EntryPointStructure->MaxStructureSize = (UINT16) sizeof (EndStructure);
875 }
876
877 //
878 // Allocate memory (below 4GB)
879 //
880 PhysicalAddress = 0xffffffff;
881 Status = gBS->AllocatePages (
882 AllocateMaxAddress,
883 EfiReservedMemoryType,
884 EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength),
885 &PhysicalAddress
886 );
887 if (EFI_ERROR (Status)) {
888 FreePages ((VOID*)(UINTN)EntryPointStructure, EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength));
889 EntryPointStructure = NULL;
890 return EFI_OUT_OF_RESOURCES;
891 }
892
893 EntryPointStructure->TableAddress = (UINT32) PhysicalAddress;
894
895 //
896 // Assemble the tables
897 //
898 BufferPointer = (UINT8 *) (UINTN) PhysicalAddress;
899 SmbiosHandle = 0;
900 do {
901 Status = SmbiosProtocol->GetNext (
902 SmbiosProtocol,
903 &SmbiosHandle,
904 NULL,
905 &SmbiosRecord,
906 NULL
907 );
908 if (Status == EFI_SUCCESS) {
909 GetSmbiosStructureSize(SmbiosRecord, &RecordSize, &NumOfStr);
910 CopyMem (BufferPointer, SmbiosRecord, RecordSize);
911 BufferPointer = BufferPointer + RecordSize;
912 }
913 } while (!EFI_ERROR(Status));
914
915 //
916 // Assemble End-Of-Table structure
917 //
918 CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure));
919
920 //
921 // Fixup checksums in the Entry Point Structure
922 //
923 CheckSum = 0;
924 EntryPointStructure->IntermediateChecksum = 0;
925 for (Index = 0x10; Index < EntryPointStructure->EntryPointLength; Index++) {
926 CheckSum = (UINT8) (CheckSum + ((UINT8 *) (EntryPointStructure))[Index]);
927 }
928
929 EntryPointStructure->IntermediateChecksum = (UINT8) (0 - CheckSum);
930
931 CheckSum = 0;
932 EntryPointStructure->EntryPointStructureChecksum = 0;
933 for (Index = 0x0; Index < EntryPointStructure->EntryPointLength; Index++) {
934 CheckSum = (UINT8) (CheckSum + ((UINT8 *) (EntryPointStructure))[Index]);
935 }
936
937 EntryPointStructure->EntryPointStructureChecksum = (UINT8) (0 - CheckSum);
938
939 //
940 // Returns the pointer
941 //
942 *TableEntryPointStructure = EntryPointStructure;
943
944 return EFI_SUCCESS;
945 }
946
947
948
949 /**
950 Installs the Smbios Table to the System Table. This function gets called
951 when the EFI_EVENT_SIGNAL_READY_TO_BOOT gets signaled
952
953 @param Event The event to signal
954 @param Context Event contex
955
956 **/
957 VOID
958 EFIAPI
959 SmbiosTableConstruction (
960 IN EFI_EVENT Event,
961 IN VOID *Context
962 )
963 {
964 UINT8 *Eps;
965 EFI_STATUS Status;
966
967 Status = SmbiosCreateTable ((VOID **) &Eps);
968 if (!EFI_ERROR (Status)) {
969 gBS->InstallConfigurationTable (&gEfiSmbiosTableGuid, Eps);
970 }
971 }
972
973
974 /**
975
976 Driver to produce Smbios protocol and register event for constructing SMBIOS table.
977
978 @param ImageHandle Module's image handle
979 @param SystemTable Pointer of EFI_SYSTEM_TABLE
980
981 @retval EFI_SUCCESS Smbios protocol installed
982 @retval Other No protocol installed, unload driver.
983
984 **/
985 EFI_STATUS
986 EFIAPI
987 SmbiosDriverEntryPoint (
988 IN EFI_HANDLE ImageHandle,
989 IN EFI_SYSTEM_TABLE *SystemTable
990 )
991 {
992 EFI_STATUS Status;
993 EFI_EVENT ReadyToBootEvent;
994
995 mPrivateData.Signature = SMBIOS_INSTANCE_SIGNATURE;
996 mPrivateData.Smbios.Add = SmbiosAdd;
997 mPrivateData.Smbios.UpdateString = SmbiosUpdateString;
998 mPrivateData.Smbios.Remove = SmbiosRemove;
999 mPrivateData.Smbios.GetNext = SmbiosGetNext;
1000 mPrivateData.Smbios.MajorVersion = SMBIOS_MAJOR_VERSION;
1001 mPrivateData.Smbios.MinorVersion = SMBIOS_MINOR_VERSION;
1002
1003 InitializeListHead (&mPrivateData.DataListHead);
1004 InitializeListHead (&mPrivateData.AllocatedHandleListHead);
1005 EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);
1006
1007 //
1008 // Make a new handle and install the protocol
1009 //
1010 mPrivateData.Handle = NULL;
1011 Status = gBS->InstallProtocolInterface (
1012 &mPrivateData.Handle,
1013 &gEfiSmbiosProtocolGuid,
1014 EFI_NATIVE_INTERFACE,
1015 &mPrivateData.Smbios
1016 );
1017
1018 if (EFI_ERROR(Status)) {
1019 return Status;
1020 }
1021 //
1022 // Register the event to install SMBIOS Table into EFI System Table
1023 //
1024 Status = gBS->CreateEventEx (
1025 EVT_NOTIFY_SIGNAL,
1026 TPL_NOTIFY,
1027 SmbiosTableConstruction,
1028 NULL,
1029 &gEfiEventReadyToBootGuid,
1030 &ReadyToBootEvent
1031 );
1032
1033 return Status;
1034 }