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