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