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