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