]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - IntelFrameworkModulePkg/Library/GenericBdsLib/BdsMisc.c
IntelFrameworkModulePkg GenericBdsLib: Potential read over memory boudary
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / GenericBdsLib / BdsMisc.c
... / ...
CommitLineData
1/** @file\r
2 Misc BDS library function\r
3\r
4Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "InternalBdsLib.h"\r
16\r
17\r
18#define MAX_STRING_LEN 200\r
19\r
20BOOLEAN mFeaturerSwitch = TRUE;\r
21BOOLEAN mResetRequired = FALSE;\r
22\r
23extern UINT16 gPlatformBootTimeOutDefault;\r
24\r
25/**\r
26 The function will go through the driver option link list, load and start\r
27 every driver the driver option device path point to.\r
28\r
29 @param BdsDriverLists The header of the current driver option link list\r
30\r
31**/\r
32VOID\r
33EFIAPI\r
34BdsLibLoadDrivers (\r
35 IN LIST_ENTRY *BdsDriverLists\r
36 )\r
37{\r
38 EFI_STATUS Status;\r
39 LIST_ENTRY *Link;\r
40 BDS_COMMON_OPTION *Option;\r
41 EFI_HANDLE ImageHandle;\r
42 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
43 UINTN ExitDataSize;\r
44 CHAR16 *ExitData;\r
45 BOOLEAN ReconnectAll;\r
46\r
47 ReconnectAll = FALSE;\r
48\r
49 //\r
50 // Process the driver option\r
51 //\r
52 for (Link = BdsDriverLists->ForwardLink; Link != BdsDriverLists; Link = Link->ForwardLink) {\r
53 Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
54 \r
55 //\r
56 // If a load option is not marked as LOAD_OPTION_ACTIVE,\r
57 // the boot manager will not automatically load the option.\r
58 //\r
59 if (!IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_ACTIVE)) {\r
60 continue;\r
61 }\r
62 \r
63 //\r
64 // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,\r
65 // then all of the EFI drivers in the system will be disconnected and\r
66 // reconnected after the last driver load option is processed.\r
67 //\r
68 if (IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_FORCE_RECONNECT)) {\r
69 ReconnectAll = TRUE;\r
70 }\r
71 \r
72 //\r
73 // Make sure the driver path is connected.\r
74 //\r
75 BdsLibConnectDevicePath (Option->DevicePath);\r
76\r
77 //\r
78 // Load and start the image that Driver#### describes\r
79 //\r
80 Status = gBS->LoadImage (\r
81 FALSE,\r
82 gImageHandle,\r
83 Option->DevicePath,\r
84 NULL,\r
85 0,\r
86 &ImageHandle\r
87 );\r
88\r
89 if (!EFI_ERROR (Status)) {\r
90 gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
91\r
92 //\r
93 // Verify whether this image is a driver, if not,\r
94 // exit it and continue to parse next load option\r
95 //\r
96 if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {\r
97 gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);\r
98 continue;\r
99 }\r
100\r
101 if (Option->LoadOptionsSize != 0) {\r
102 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;\r
103 ImageInfo->LoadOptions = Option->LoadOptions;\r
104 }\r
105 //\r
106 // Before calling the image, enable the Watchdog Timer for\r
107 // the 5 Minute period\r
108 //\r
109 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
110\r
111 Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);\r
112 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", Status));\r
113\r
114 //\r
115 // Clear the Watchdog Timer after the image returns\r
116 //\r
117 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
118 }\r
119 }\r
120 \r
121 //\r
122 // Process the LOAD_OPTION_FORCE_RECONNECT driver option\r
123 //\r
124 if (ReconnectAll) {\r
125 BdsLibDisconnectAllEfi ();\r
126 BdsLibConnectAll ();\r
127 }\r
128\r
129}\r
130\r
131/**\r
132 Get the Option Number that does not used.\r
133 Try to locate the specific option variable one by one utile find a free number.\r
134\r
135 @param VariableName Indicate if the boot#### or driver#### option\r
136\r
137 @return The Minimal Free Option Number\r
138\r
139**/\r
140UINT16\r
141BdsLibGetFreeOptionNumber (\r
142 IN CHAR16 *VariableName\r
143 )\r
144{\r
145 UINTN Index;\r
146 CHAR16 StrTemp[10];\r
147 UINT16 *OptionBuffer;\r
148 UINTN OptionSize;\r
149\r
150 //\r
151 // Try to find the minimum free number from 0, 1, 2, 3....\r
152 //\r
153 Index = 0;\r
154 do {\r
155 if (*VariableName == 'B') {\r
156 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);\r
157 } else {\r
158 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Driver%04x", Index);\r
159 }\r
160 //\r
161 // try if the option number is used\r
162 //\r
163 OptionBuffer = BdsLibGetVariableAndSize (\r
164 StrTemp,\r
165 &gEfiGlobalVariableGuid,\r
166 &OptionSize\r
167 );\r
168 if (OptionBuffer == NULL) {\r
169 break;\r
170 }\r
171 FreePool(OptionBuffer);\r
172 Index++;\r
173 } while (TRUE);\r
174\r
175 return ((UINT16) Index);\r
176}\r
177\r
178\r
179/**\r
180 This function will register the new boot#### or driver#### option base on\r
181 the VariableName. The new registered boot#### or driver#### will be linked\r
182 to BdsOptionList and also update to the VariableName. After the boot#### or\r
183 driver#### updated, the BootOrder or DriverOrder will also be updated.\r
184\r
185 @param BdsOptionList The header of the boot#### or driver#### link list\r
186 @param DevicePath The device path which the boot#### or driver####\r
187 option present\r
188 @param String The description of the boot#### or driver####\r
189 @param VariableName Indicate if the boot#### or driver#### option\r
190\r
191 @retval EFI_SUCCESS The boot#### or driver#### have been success\r
192 registered\r
193 @retval EFI_STATUS Return the status of gRT->SetVariable ().\r
194\r
195**/\r
196EFI_STATUS\r
197EFIAPI\r
198BdsLibRegisterNewOption (\r
199 IN LIST_ENTRY *BdsOptionList,\r
200 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
201 IN CHAR16 *String,\r
202 IN CHAR16 *VariableName\r
203 )\r
204{\r
205 EFI_STATUS Status;\r
206 UINTN Index;\r
207 UINT16 RegisterOptionNumber;\r
208 UINT16 *TempOptionPtr;\r
209 UINTN TempOptionSize;\r
210 UINT16 *OptionOrderPtr;\r
211 VOID *OptionPtr;\r
212 UINTN OptionSize;\r
213 UINT8 *TempPtr;\r
214 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
215 CHAR16 *Description;\r
216 CHAR16 OptionName[10];\r
217 BOOLEAN UpdateDescription;\r
218 UINT16 BootOrderEntry;\r
219 UINTN OrderItemNum;\r
220\r
221 if (DevicePath == NULL) {\r
222 return EFI_INVALID_PARAMETER;\r
223 }\r
224\r
225 OptionPtr = NULL;\r
226 OptionSize = 0;\r
227 TempPtr = NULL;\r
228 OptionDevicePath = NULL;\r
229 Description = NULL;\r
230 OptionOrderPtr = NULL;\r
231 UpdateDescription = FALSE;\r
232 Status = EFI_SUCCESS;\r
233 ZeroMem (OptionName, sizeof (OptionName));\r
234\r
235 TempOptionSize = 0;\r
236 TempOptionPtr = BdsLibGetVariableAndSize (\r
237 VariableName,\r
238 &gEfiGlobalVariableGuid,\r
239 &TempOptionSize\r
240 );\r
241 //\r
242 // Compare with current option variable if the previous option is set in global variable.\r
243 //\r
244 for (Index = 0; Index < TempOptionSize / sizeof (UINT16); Index++) {\r
245 //\r
246 // TempOptionPtr must not be NULL if we have non-zero TempOptionSize.\r
247 //\r
248 ASSERT (TempOptionPtr != NULL);\r
249\r
250 if (*VariableName == 'B') {\r
251 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", TempOptionPtr[Index]);\r
252 } else {\r
253 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", TempOptionPtr[Index]);\r
254 }\r
255\r
256 OptionPtr = BdsLibGetVariableAndSize (\r
257 OptionName,\r
258 &gEfiGlobalVariableGuid,\r
259 &OptionSize\r
260 );\r
261 if (OptionPtr == NULL) {\r
262 continue;\r
263 }\r
264\r
265 //\r
266 // Validate the variable.\r
267 //\r
268 if (!ValidateOption(OptionPtr, OptionSize)) {\r
269 FreePool(OptionPtr);\r
270 continue;\r
271 }\r
272\r
273 TempPtr = OptionPtr;\r
274 TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
275 Description = (CHAR16 *) TempPtr;\r
276 TempPtr += StrSize ((CHAR16 *) TempPtr);\r
277 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
278\r
279 //\r
280 // Notes: the description may will change base on the GetStringToken\r
281 //\r
282 if (CompareMem (OptionDevicePath, DevicePath, GetDevicePathSize (OptionDevicePath)) == 0) {\r
283 if (CompareMem (Description, String, StrSize (Description)) == 0) { \r
284 //\r
285 // Got the option, so just return\r
286 //\r
287 FreePool (OptionPtr);\r
288 FreePool (TempOptionPtr);\r
289 return EFI_SUCCESS;\r
290 } else {\r
291 //\r
292 // Option description changed, need update.\r
293 //\r
294 UpdateDescription = TRUE;\r
295 FreePool (OptionPtr);\r
296 break;\r
297 }\r
298 }\r
299\r
300 FreePool (OptionPtr);\r
301 }\r
302\r
303 OptionSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (String);\r
304 OptionSize += GetDevicePathSize (DevicePath);\r
305 OptionPtr = AllocateZeroPool (OptionSize);\r
306 ASSERT (OptionPtr != NULL);\r
307 \r
308 TempPtr = OptionPtr;\r
309 *(UINT32 *) TempPtr = LOAD_OPTION_ACTIVE;\r
310 TempPtr += sizeof (UINT32);\r
311 *(UINT16 *) TempPtr = (UINT16) GetDevicePathSize (DevicePath);\r
312 TempPtr += sizeof (UINT16);\r
313 CopyMem (TempPtr, String, StrSize (String));\r
314 TempPtr += StrSize (String);\r
315 CopyMem (TempPtr, DevicePath, GetDevicePathSize (DevicePath));\r
316\r
317 if (UpdateDescription) {\r
318 //\r
319 // The number in option#### to be updated. \r
320 // In this case, we must have non-NULL TempOptionPtr.\r
321 //\r
322 ASSERT (TempOptionPtr != NULL);\r
323 RegisterOptionNumber = TempOptionPtr[Index];\r
324 } else {\r
325 //\r
326 // The new option#### number\r
327 //\r
328 RegisterOptionNumber = BdsLibGetFreeOptionNumber(VariableName);\r
329 }\r
330\r
331 if (*VariableName == 'B') {\r
332 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", RegisterOptionNumber);\r
333 } else {\r
334 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", RegisterOptionNumber);\r
335 }\r
336\r
337 Status = gRT->SetVariable (\r
338 OptionName,\r
339 &gEfiGlobalVariableGuid,\r
340 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
341 OptionSize,\r
342 OptionPtr\r
343 );\r
344 //\r
345 // Return if only need to update a changed description or fail to set option.\r
346 //\r
347 if (EFI_ERROR (Status) || UpdateDescription) {\r
348 FreePool (OptionPtr);\r
349 if (TempOptionPtr != NULL) {\r
350 FreePool (TempOptionPtr);\r
351 }\r
352 return Status;\r
353 }\r
354\r
355 FreePool (OptionPtr);\r
356\r
357 //\r
358 // Update the option order variable\r
359 //\r
360\r
361 //\r
362 // If no option order\r
363 //\r
364 if (TempOptionSize == 0) {\r
365 BootOrderEntry = 0;\r
366 Status = gRT->SetVariable (\r
367 VariableName,\r
368 &gEfiGlobalVariableGuid,\r
369 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
370 sizeof (UINT16),\r
371 &BootOrderEntry\r
372 );\r
373 if (TempOptionPtr != NULL) {\r
374 FreePool (TempOptionPtr);\r
375 }\r
376 return Status;\r
377 }\r
378 \r
379 //\r
380 // TempOptionPtr must not be NULL if TempOptionSize is not zero.\r
381 //\r
382 ASSERT (TempOptionPtr != NULL);\r
383 //\r
384 // Append the new option number to the original option order\r
385 //\r
386 OrderItemNum = (TempOptionSize / sizeof (UINT16)) + 1 ;\r
387 OptionOrderPtr = AllocateZeroPool ( OrderItemNum * sizeof (UINT16));\r
388 ASSERT (OptionOrderPtr!= NULL);\r
389 CopyMem (OptionOrderPtr, TempOptionPtr, (OrderItemNum - 1) * sizeof (UINT16));\r
390\r
391 OptionOrderPtr[Index] = RegisterOptionNumber;\r
392\r
393 Status = gRT->SetVariable (\r
394 VariableName,\r
395 &gEfiGlobalVariableGuid,\r
396 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
397 OrderItemNum * sizeof (UINT16),\r
398 OptionOrderPtr\r
399 );\r
400 FreePool (TempOptionPtr);\r
401 FreePool (OptionOrderPtr);\r
402\r
403 return Status;\r
404}\r
405\r
406/**\r
407 Returns the size of a device path in bytes.\r
408\r
409 This function returns the size, in bytes, of the device path data structure \r
410 specified by DevicePath including the end of device path node. If DevicePath \r
411 is NULL, then 0 is returned. If the length of the device path is bigger than\r
412 MaxSize, also return 0 to indicate this is an invalidate device path.\r
413\r
414 @param DevicePath A pointer to a device path data structure.\r
415 @param MaxSize Max valid device path size. If big than this size, \r
416 return error.\r
417 \r
418 @retval 0 An invalid device path.\r
419 @retval Others The size of a device path in bytes.\r
420\r
421**/\r
422UINTN\r
423GetDevicePathSizeEx (\r
424 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
425 IN UINTN MaxSize\r
426 )\r
427{\r
428 UINTN Size;\r
429 UINTN NodeSize;\r
430\r
431 if (DevicePath == NULL) {\r
432 return 0;\r
433 }\r
434\r
435 //\r
436 // Search for the end of the device path structure\r
437 //\r
438 Size = 0;\r
439 while (!IsDevicePathEnd (DevicePath)) {\r
440 NodeSize = DevicePathNodeLength (DevicePath);\r
441 if (NodeSize < END_DEVICE_PATH_LENGTH) {\r
442 return 0;\r
443 }\r
444 Size += NodeSize;\r
445 if (Size > MaxSize) {\r
446 return 0;\r
447 }\r
448 DevicePath = NextDevicePathNode (DevicePath);\r
449 }\r
450 Size += DevicePathNodeLength (DevicePath);\r
451 if (Size > MaxSize) {\r
452 return 0;\r
453 }\r
454\r
455 return Size;\r
456}\r
457\r
458/**\r
459 Returns the length of a Null-terminated Unicode string. If the length is \r
460 bigger than MaxStringLen, return length 0 to indicate that this is an \r
461 invalidate string.\r
462\r
463 This function returns the byte length of Unicode characters in the Null-terminated\r
464 Unicode string specified by String. \r
465\r
466 If String is NULL, then ASSERT().\r
467 If String is not aligned on a 16-bit boundary, then ASSERT().\r
468\r
469 @param String A pointer to a Null-terminated Unicode string.\r
470 @param MaxStringLen Max string len in this string.\r
471\r
472 @retval 0 An invalid string.\r
473 @retval Others The length of String.\r
474\r
475**/\r
476UINTN\r
477StrSizeEx (\r
478 IN CONST CHAR16 *String,\r
479 IN UINTN MaxStringLen\r
480 )\r
481{\r
482 UINTN Length;\r
483\r
484 ASSERT (String != NULL && MaxStringLen != 0);\r
485 ASSERT (((UINTN) String & BIT0) == 0);\r
486\r
487 for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);\r
488\r
489 if (*String != L'\0' && MaxStringLen == Length) {\r
490 return 0;\r
491 }\r
492\r
493 return Length + 2;\r
494}\r
495\r
496/**\r
497 Validate the EFI Boot#### variable (VendorGuid/Name)\r
498\r
499 @param Variable Boot#### variable data.\r
500 @param VariableSize Returns the size of the EFI variable that was read\r
501\r
502 @retval TRUE The variable data is correct.\r
503 @retval FALSE The variable data is corrupted.\r
504\r
505**/\r
506BOOLEAN \r
507ValidateOption (\r
508 UINT8 *Variable,\r
509 UINTN VariableSize\r
510 )\r
511{\r
512 UINT16 FilePathSize;\r
513 UINT8 *TempPtr;\r
514 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
515 UINTN TempSize;\r
516\r
517 if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {\r
518 return FALSE;\r
519 }\r
520\r
521 //\r
522 // Skip the option attribute\r
523 //\r
524 TempPtr = Variable;\r
525 TempPtr += sizeof (UINT32);\r
526\r
527 //\r
528 // Get the option's device path size\r
529 //\r
530 FilePathSize = *(UINT16 *) TempPtr;\r
531 TempPtr += sizeof (UINT16);\r
532\r
533 //\r
534 // Get the option's description string size\r
535 //\r
536 TempSize = StrSizeEx ((CHAR16 *) TempPtr, VariableSize - sizeof (UINT16) - sizeof (UINT32));\r
537 TempPtr += TempSize;\r
538\r
539 //\r
540 // Get the option's device path\r
541 //\r
542 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
543 TempPtr += FilePathSize;\r
544\r
545 //\r
546 // Validation boot option variable.\r
547 //\r
548 if ((FilePathSize == 0) || (TempSize == 0)) {\r
549 return FALSE;\r
550 }\r
551\r
552 if (TempSize + FilePathSize + sizeof (UINT16) + sizeof (UINT32) > VariableSize) {\r
553 return FALSE;\r
554 }\r
555\r
556 return (BOOLEAN) (GetDevicePathSizeEx (DevicePath, FilePathSize) != 0);\r
557}\r
558\r
559/**\r
560 Convert a single character to number.\r
561 It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'\r
562 \r
563 @param Char The input char which need to change to a hex number.\r
564 \r
565**/\r
566UINTN\r
567CharToUint (\r
568 IN CHAR16 Char\r
569 )\r
570{\r
571 if ((Char >= L'0') && (Char <= L'9')) {\r
572 return (UINTN) (Char - L'0');\r
573 }\r
574\r
575 if ((Char >= L'A') && (Char <= L'F')) {\r
576 return (UINTN) (Char - L'A' + 0xA);\r
577 }\r
578\r
579 ASSERT (FALSE);\r
580 return 0;\r
581}\r
582\r
583/**\r
584 Build the boot#### or driver#### option from the VariableName, the\r
585 build boot#### or driver#### will also be linked to BdsCommonOptionList.\r
586\r
587 @param BdsCommonOptionList The header of the boot#### or driver#### option\r
588 link list\r
589 @param VariableName EFI Variable name indicate if it is boot#### or\r
590 driver####\r
591\r
592 @retval BDS_COMMON_OPTION Get the option just been created\r
593 @retval NULL Failed to get the new option\r
594\r
595**/\r
596BDS_COMMON_OPTION *\r
597EFIAPI\r
598BdsLibVariableToOption (\r
599 IN OUT LIST_ENTRY *BdsCommonOptionList,\r
600 IN CHAR16 *VariableName\r
601 )\r
602{\r
603 UINT32 Attribute;\r
604 UINT16 FilePathSize;\r
605 UINT8 *Variable;\r
606 UINT8 *TempPtr;\r
607 UINTN VariableSize;\r
608 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
609 BDS_COMMON_OPTION *Option;\r
610 VOID *LoadOptions;\r
611 UINT32 LoadOptionsSize;\r
612 CHAR16 *Description;\r
613 UINT8 NumOff;\r
614\r
615 //\r
616 // Read the variable. We will never free this data.\r
617 //\r
618 Variable = BdsLibGetVariableAndSize (\r
619 VariableName,\r
620 &gEfiGlobalVariableGuid,\r
621 &VariableSize\r
622 );\r
623 if (Variable == NULL) {\r
624 return NULL;\r
625 }\r
626\r
627 //\r
628 // Validate Boot#### variable data.\r
629 //\r
630 if (!ValidateOption(Variable, VariableSize)) {\r
631 FreePool (Variable);\r
632 return NULL;\r
633 }\r
634\r
635 //\r
636 // Notes: careful defined the variable of Boot#### or\r
637 // Driver####, consider use some macro to abstract the code\r
638 //\r
639 //\r
640 // Get the option attribute\r
641 //\r
642 TempPtr = Variable;\r
643 Attribute = *(UINT32 *) Variable;\r
644 TempPtr += sizeof (UINT32);\r
645\r
646 //\r
647 // Get the option's device path size\r
648 //\r
649 FilePathSize = *(UINT16 *) TempPtr;\r
650 TempPtr += sizeof (UINT16);\r
651\r
652 //\r
653 // Get the option's description string\r
654 //\r
655 Description = (CHAR16 *) TempPtr;\r
656\r
657 //\r
658 // Get the option's description string size\r
659 //\r
660 TempPtr += StrSize((CHAR16 *) TempPtr);\r
661\r
662 //\r
663 // Get the option's device path\r
664 //\r
665 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
666 TempPtr += FilePathSize;\r
667\r
668 //\r
669 // Get load opion data.\r
670 //\r
671 LoadOptions = TempPtr;\r
672 LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));\r
673\r
674 //\r
675 // The Console variables may have multiple device paths, so make\r
676 // an Entry for each one.\r
677 //\r
678 Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION));\r
679 if (Option == NULL) {\r
680 FreePool (Variable);\r
681 return NULL;\r
682 }\r
683\r
684 Option->Signature = BDS_LOAD_OPTION_SIGNATURE;\r
685 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));\r
686 ASSERT(Option->DevicePath != NULL);\r
687 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));\r
688\r
689 Option->Attribute = Attribute;\r
690 Option->Description = AllocateZeroPool (StrSize (Description));\r
691 ASSERT(Option->Description != NULL);\r
692 CopyMem (Option->Description, Description, StrSize (Description));\r
693\r
694 Option->LoadOptions = AllocateZeroPool (LoadOptionsSize);\r
695 ASSERT(Option->LoadOptions != NULL);\r
696 CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize);\r
697 Option->LoadOptionsSize = LoadOptionsSize;\r
698\r
699 //\r
700 // Get the value from VariableName Unicode string\r
701 // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this\r
702 // Unicode stream to ASCII without any loss in meaning.\r
703 //\r
704 if (*VariableName == 'B') {\r
705 NumOff = (UINT8) (sizeof (L"Boot") / sizeof (CHAR16) - 1);\r
706 Option->BootCurrent = (UINT16) (CharToUint (VariableName[NumOff+0]) * 0x1000) \r
707 + (UINT16) (CharToUint (VariableName[NumOff+1]) * 0x100)\r
708 + (UINT16) (CharToUint (VariableName[NumOff+2]) * 0x10)\r
709 + (UINT16) (CharToUint (VariableName[NumOff+3]) * 0x1);\r
710 }\r
711 InsertTailList (BdsCommonOptionList, &Option->Link);\r
712 FreePool (Variable);\r
713 return Option;\r
714}\r
715\r
716/**\r
717 Process BootOrder, or DriverOrder variables, by calling\r
718 BdsLibVariableToOption () for each UINT16 in the variables.\r
719\r
720 @param BdsCommonOptionList The header of the option list base on variable\r
721 VariableName\r
722 @param VariableName EFI Variable name indicate the BootOrder or\r
723 DriverOrder\r
724\r
725 @retval EFI_SUCCESS Success create the boot option or driver option\r
726 list\r
727 @retval EFI_OUT_OF_RESOURCES Failed to get the boot option or driver option list\r
728\r
729**/\r
730EFI_STATUS\r
731EFIAPI\r
732BdsLibBuildOptionFromVar (\r
733 IN LIST_ENTRY *BdsCommonOptionList,\r
734 IN CHAR16 *VariableName\r
735 )\r
736{\r
737 UINT16 *OptionOrder;\r
738 UINTN OptionOrderSize;\r
739 UINTN Index;\r
740 BDS_COMMON_OPTION *Option;\r
741 CHAR16 OptionName[20];\r
742\r
743 //\r
744 // Zero Buffer in order to get all BOOT#### variables\r
745 //\r
746 ZeroMem (OptionName, sizeof (OptionName));\r
747\r
748 //\r
749 // Read the BootOrder, or DriverOrder variable.\r
750 //\r
751 OptionOrder = BdsLibGetVariableAndSize (\r
752 VariableName,\r
753 &gEfiGlobalVariableGuid,\r
754 &OptionOrderSize\r
755 );\r
756 if (OptionOrder == NULL) {\r
757 return EFI_OUT_OF_RESOURCES;\r
758 }\r
759\r
760 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {\r
761 if (*VariableName == 'B') {\r
762 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionOrder[Index]);\r
763 } else {\r
764 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionOrder[Index]);\r
765 }\r
766\r
767 Option = BdsLibVariableToOption (BdsCommonOptionList, OptionName);\r
768 if (Option != NULL) {\r
769 Option->BootCurrent = OptionOrder[Index];\r
770 }\r
771 }\r
772\r
773 FreePool (OptionOrder);\r
774\r
775 return EFI_SUCCESS;\r
776}\r
777\r
778/**\r
779 Get boot mode by looking up configuration table and parsing HOB list\r
780\r
781 @param BootMode Boot mode from PEI handoff HOB.\r
782\r
783 @retval EFI_SUCCESS Successfully get boot mode\r
784\r
785**/\r
786EFI_STATUS\r
787EFIAPI\r
788BdsLibGetBootMode (\r
789 OUT EFI_BOOT_MODE *BootMode\r
790 )\r
791{\r
792 *BootMode = GetBootModeHob ();\r
793\r
794 return EFI_SUCCESS;\r
795}\r
796\r
797/**\r
798 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated\r
799 buffer, and the size of the buffer. If failure return NULL.\r
800\r
801 @param Name String part of EFI variable name\r
802 @param VendorGuid GUID part of EFI variable name\r
803 @param VariableSize Returns the size of the EFI variable that was read\r
804\r
805 @return Dynamically allocated memory that contains a copy of the EFI variable\r
806 Caller is responsible freeing the buffer.\r
807 @retval NULL Variable was not read\r
808\r
809**/\r
810VOID *\r
811EFIAPI\r
812BdsLibGetVariableAndSize (\r
813 IN CHAR16 *Name,\r
814 IN EFI_GUID *VendorGuid,\r
815 OUT UINTN *VariableSize\r
816 )\r
817{\r
818 EFI_STATUS Status;\r
819 UINTN BufferSize;\r
820 VOID *Buffer;\r
821\r
822 Buffer = NULL;\r
823\r
824 //\r
825 // Pass in a zero size buffer to find the required buffer size.\r
826 //\r
827 BufferSize = 0;\r
828 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
829 if (Status == EFI_BUFFER_TOO_SMALL) {\r
830 //\r
831 // Allocate the buffer to return\r
832 //\r
833 Buffer = AllocateZeroPool (BufferSize);\r
834 if (Buffer == NULL) {\r
835 *VariableSize = 0;\r
836 return NULL;\r
837 }\r
838 //\r
839 // Read variable into the allocated buffer.\r
840 //\r
841 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
842 if (EFI_ERROR (Status)) {\r
843 FreePool (Buffer);\r
844 BufferSize = 0;\r
845 Buffer = NULL;\r
846 }\r
847 }\r
848\r
849 ASSERT (((Buffer == NULL) && (BufferSize == 0)) ||\r
850 ((Buffer != NULL) && (BufferSize != 0))\r
851 );\r
852 *VariableSize = BufferSize;\r
853 return Buffer;\r
854}\r
855\r
856/**\r
857 Delete the instance in Multi which matches partly with Single instance\r
858\r
859 @param Multi A pointer to a multi-instance device path data\r
860 structure.\r
861 @param Single A pointer to a single-instance device path data\r
862 structure.\r
863\r
864 @return This function will remove the device path instances in Multi which partly\r
865 match with the Single, and return the result device path. If there is no\r
866 remaining device path as a result, this function will return NULL.\r
867\r
868**/\r
869EFI_DEVICE_PATH_PROTOCOL *\r
870EFIAPI\r
871BdsLibDelPartMatchInstance (\r
872 IN EFI_DEVICE_PATH_PROTOCOL *Multi,\r
873 IN EFI_DEVICE_PATH_PROTOCOL *Single\r
874 )\r
875{\r
876 EFI_DEVICE_PATH_PROTOCOL *Instance;\r
877 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
878 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;\r
879 UINTN InstanceSize;\r
880 UINTN SingleDpSize;\r
881 UINTN Size;\r
882\r
883 NewDevicePath = NULL;\r
884 TempNewDevicePath = NULL;\r
885\r
886 if (Multi == NULL || Single == NULL) {\r
887 return Multi;\r
888 }\r
889\r
890 Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);\r
891 SingleDpSize = GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;\r
892 InstanceSize -= END_DEVICE_PATH_LENGTH;\r
893\r
894 while (Instance != NULL) {\r
895\r
896 Size = (SingleDpSize < InstanceSize) ? SingleDpSize : InstanceSize;\r
897\r
898 if ((CompareMem (Instance, Single, Size) != 0)) {\r
899 //\r
900 // Append the device path instance which does not match with Single\r
901 //\r
902 TempNewDevicePath = NewDevicePath;\r
903 NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);\r
904 if (TempNewDevicePath != NULL) {\r
905 FreePool(TempNewDevicePath);\r
906 }\r
907 }\r
908 FreePool(Instance);\r
909 Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);\r
910 InstanceSize -= END_DEVICE_PATH_LENGTH;\r
911 }\r
912\r
913 return NewDevicePath;\r
914}\r
915\r
916/**\r
917 Function compares a device path data structure to that of all the nodes of a\r
918 second device path instance.\r
919\r
920 @param Multi A pointer to a multi-instance device path data\r
921 structure.\r
922 @param Single A pointer to a single-instance device path data\r
923 structure.\r
924\r
925 @retval TRUE If the Single device path is contained within Multi device path.\r
926 @retval FALSE The Single device path is not match within Multi device path.\r
927\r
928**/\r
929BOOLEAN\r
930EFIAPI\r
931BdsLibMatchDevicePaths (\r
932 IN EFI_DEVICE_PATH_PROTOCOL *Multi,\r
933 IN EFI_DEVICE_PATH_PROTOCOL *Single\r
934 )\r
935{\r
936 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
937 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;\r
938 UINTN Size;\r
939\r
940 if (Multi == NULL || Single == NULL) {\r
941 return FALSE;\r
942 }\r
943\r
944 DevicePath = Multi;\r
945 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
946\r
947 //\r
948 // Search for the match of 'Single' in 'Multi'\r
949 //\r
950 while (DevicePathInst != NULL) {\r
951 //\r
952 // If the single device path is found in multiple device paths,\r
953 // return success\r
954 //\r
955 if (CompareMem (Single, DevicePathInst, Size) == 0) {\r
956 FreePool (DevicePathInst);\r
957 return TRUE;\r
958 }\r
959\r
960 FreePool (DevicePathInst);\r
961 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
962 }\r
963\r
964 return FALSE;\r
965}\r
966\r
967/**\r
968 This function prints a series of strings.\r
969\r
970 @param ConOut Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL\r
971 @param ... A variable argument list containing series of\r
972 strings, the last string must be NULL.\r
973\r
974 @retval EFI_SUCCESS Success print out the string using ConOut.\r
975 @retval EFI_STATUS Return the status of the ConOut->OutputString ().\r
976\r
977**/\r
978EFI_STATUS\r
979EFIAPI\r
980BdsLibOutputStrings (\r
981 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,\r
982 ...\r
983 )\r
984{\r
985 VA_LIST Args;\r
986 EFI_STATUS Status;\r
987 CHAR16 *String;\r
988\r
989 Status = EFI_SUCCESS;\r
990 VA_START (Args, ConOut);\r
991\r
992 while (!EFI_ERROR (Status)) {\r
993 //\r
994 // If String is NULL, then it's the end of the list\r
995 //\r
996 String = VA_ARG (Args, CHAR16 *);\r
997 if (String == NULL) {\r
998 break;\r
999 }\r
1000\r
1001 Status = ConOut->OutputString (ConOut, String);\r
1002\r
1003 if (EFI_ERROR (Status)) {\r
1004 break;\r
1005 }\r
1006 }\r
1007 \r
1008 VA_END(Args);\r
1009 return Status;\r
1010}\r
1011\r
1012//\r
1013// Following are BDS Lib functions which contain all the code about setup browser reset reminder feature.\r
1014// Setup Browser reset reminder feature is that an reset reminder will be given before user leaves the setup browser if\r
1015// user change any option setting which needs a reset to be effective, and the reset will be applied according to the user selection.\r
1016//\r
1017\r
1018\r
1019/**\r
1020 Enable the setup browser reset reminder feature.\r
1021 This routine is used in platform tip. If the platform policy need the feature, use the routine to enable it.\r
1022\r
1023**/\r
1024VOID\r
1025EFIAPI\r
1026EnableResetReminderFeature (\r
1027 VOID\r
1028 )\r
1029{\r
1030 mFeaturerSwitch = TRUE;\r
1031}\r
1032\r
1033\r
1034/**\r
1035 Disable the setup browser reset reminder feature.\r
1036 This routine is used in platform tip. If the platform policy do not want the feature, use the routine to disable it.\r
1037\r
1038**/\r
1039VOID\r
1040EFIAPI\r
1041DisableResetReminderFeature (\r
1042 VOID\r
1043 )\r
1044{\r
1045 mFeaturerSwitch = FALSE;\r
1046}\r
1047\r
1048\r
1049/**\r
1050 Record the info that a reset is required.\r
1051 A module boolean variable is used to record whether a reset is required.\r
1052\r
1053**/\r
1054VOID\r
1055EFIAPI\r
1056EnableResetRequired (\r
1057 VOID\r
1058 )\r
1059{\r
1060 mResetRequired = TRUE;\r
1061}\r
1062\r
1063\r
1064/**\r
1065 Record the info that no reset is required.\r
1066 A module boolean variable is used to record whether a reset is required.\r
1067\r
1068**/\r
1069VOID\r
1070EFIAPI\r
1071DisableResetRequired (\r
1072 VOID\r
1073 )\r
1074{\r
1075 mResetRequired = FALSE;\r
1076}\r
1077\r
1078\r
1079/**\r
1080 Check whether platform policy enable the reset reminder feature. The default is enabled.\r
1081\r
1082**/\r
1083BOOLEAN\r
1084EFIAPI\r
1085IsResetReminderFeatureEnable (\r
1086 VOID\r
1087 )\r
1088{\r
1089 return mFeaturerSwitch;\r
1090}\r
1091\r
1092\r
1093/**\r
1094 Check if user changed any option setting which needs a system reset to be effective.\r
1095\r
1096**/\r
1097BOOLEAN\r
1098EFIAPI\r
1099IsResetRequired (\r
1100 VOID\r
1101 )\r
1102{\r
1103 return mResetRequired;\r
1104}\r
1105\r
1106\r
1107/**\r
1108 Check whether a reset is needed, and finish the reset reminder feature.\r
1109 If a reset is needed, Popup a menu to notice user, and finish the feature\r
1110 according to the user selection.\r
1111\r
1112**/\r
1113VOID\r
1114EFIAPI\r
1115SetupResetReminder (\r
1116 VOID\r
1117 )\r
1118{\r
1119 EFI_INPUT_KEY Key;\r
1120 CHAR16 *StringBuffer1;\r
1121 CHAR16 *StringBuffer2;\r
1122\r
1123\r
1124 //\r
1125 //check any reset required change is applied? if yes, reset system\r
1126 //\r
1127 if (IsResetReminderFeatureEnable ()) {\r
1128 if (IsResetRequired ()) {\r
1129\r
1130 StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));\r
1131 ASSERT (StringBuffer1 != NULL);\r
1132 StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));\r
1133 ASSERT (StringBuffer2 != NULL);\r
1134 StrCpyS (\r
1135 StringBuffer1,\r
1136 MAX_STRING_LEN,\r
1137 L"Configuration changed. Reset to apply it Now."\r
1138 );\r
1139 StrCpyS (\r
1140 StringBuffer2,\r
1141 MAX_STRING_LEN,\r
1142 L"Press ENTER to reset"\r
1143 );\r
1144 //\r
1145 // Popup a menu to notice user\r
1146 //\r
1147 do {\r
1148 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, StringBuffer1, StringBuffer2, NULL);\r
1149 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1150\r
1151 FreePool (StringBuffer1);\r
1152 FreePool (StringBuffer2);\r
1153\r
1154 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
1155 }\r
1156 }\r
1157}\r
1158\r
1159/**\r
1160 Get the headers (dos, image, optional header) from an image\r
1161\r
1162 @param Device SimpleFileSystem device handle\r
1163 @param FileName File name for the image\r
1164 @param DosHeader Pointer to dos header\r
1165 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.\r
1166\r
1167 @retval EFI_SUCCESS Successfully get the machine type.\r
1168 @retval EFI_NOT_FOUND The file is not found.\r
1169 @retval EFI_LOAD_ERROR File is not a valid image file.\r
1170\r
1171**/\r
1172EFI_STATUS\r
1173EFIAPI\r
1174BdsLibGetImageHeader (\r
1175 IN EFI_HANDLE Device,\r
1176 IN CHAR16 *FileName,\r
1177 OUT EFI_IMAGE_DOS_HEADER *DosHeader,\r
1178 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr\r
1179 )\r
1180{\r
1181 EFI_STATUS Status;\r
1182 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;\r
1183 EFI_FILE_HANDLE Root;\r
1184 EFI_FILE_HANDLE ThisFile;\r
1185 UINTN BufferSize;\r
1186 UINT64 FileSize;\r
1187 EFI_FILE_INFO *Info;\r
1188\r
1189 Root = NULL;\r
1190 ThisFile = NULL;\r
1191 //\r
1192 // Handle the file system interface to the device\r
1193 //\r
1194 Status = gBS->HandleProtocol (\r
1195 Device,\r
1196 &gEfiSimpleFileSystemProtocolGuid,\r
1197 (VOID *) &Volume\r
1198 );\r
1199 if (EFI_ERROR (Status)) {\r
1200 goto Done;\r
1201 }\r
1202\r
1203 Status = Volume->OpenVolume (\r
1204 Volume,\r
1205 &Root\r
1206 );\r
1207 if (EFI_ERROR (Status)) {\r
1208 Root = NULL;\r
1209 goto Done;\r
1210 }\r
1211 ASSERT (Root != NULL);\r
1212 Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0);\r
1213 if (EFI_ERROR (Status)) {\r
1214 goto Done;\r
1215 }\r
1216 ASSERT (ThisFile != NULL);\r
1217\r
1218 //\r
1219 // Get file size\r
1220 //\r
1221 BufferSize = SIZE_OF_EFI_FILE_INFO + 200;\r
1222 do {\r
1223 Info = NULL;\r
1224 Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) &Info);\r
1225 if (EFI_ERROR (Status)) {\r
1226 goto Done;\r
1227 }\r
1228 Status = ThisFile->GetInfo (\r
1229 ThisFile,\r
1230 &gEfiFileInfoGuid,\r
1231 &BufferSize,\r
1232 Info\r
1233 );\r
1234 if (!EFI_ERROR (Status)) {\r
1235 break;\r
1236 }\r
1237 if (Status != EFI_BUFFER_TOO_SMALL) {\r
1238 FreePool (Info);\r
1239 goto Done;\r
1240 }\r
1241 FreePool (Info);\r
1242 } while (TRUE);\r
1243\r
1244 FileSize = Info->FileSize;\r
1245 FreePool (Info);\r
1246\r
1247 //\r
1248 // Read dos header\r
1249 //\r
1250 BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);\r
1251 Status = ThisFile->Read (ThisFile, &BufferSize, DosHeader);\r
1252 if (EFI_ERROR (Status) ||\r
1253 BufferSize < sizeof (EFI_IMAGE_DOS_HEADER) ||\r
1254 FileSize <= DosHeader->e_lfanew ||\r
1255 DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
1256 Status = EFI_LOAD_ERROR;\r
1257 goto Done;\r
1258 }\r
1259\r
1260 //\r
1261 // Move to PE signature\r
1262 //\r
1263 Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew);\r
1264 if (EFI_ERROR (Status)) {\r
1265 Status = EFI_LOAD_ERROR;\r
1266 goto Done;\r
1267 }\r
1268\r
1269 //\r
1270 // Read and check PE signature\r
1271 //\r
1272 BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
1273 Status = ThisFile->Read (ThisFile, &BufferSize, Hdr.Pe32);\r
1274 if (EFI_ERROR (Status) ||\r
1275 BufferSize < sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) ||\r
1276 Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1277 Status = EFI_LOAD_ERROR;\r
1278 goto Done;\r
1279 }\r
1280\r
1281 //\r
1282 // Check PE32 or PE32+ magic\r
1283 //\r
1284 if (Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC &&\r
1285 Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
1286 Status = EFI_LOAD_ERROR;\r
1287 goto Done;\r
1288 }\r
1289\r
1290 Done:\r
1291 if (ThisFile != NULL) {\r
1292 ThisFile->Close (ThisFile);\r
1293 }\r
1294 if (Root != NULL) {\r
1295 Root->Close (Root);\r
1296 }\r
1297 return Status;\r
1298}\r
1299\r
1300/**\r
1301 This routine adjust the memory information for different memory type and \r
1302 save them into the variables for next boot.\r
1303**/\r
1304VOID\r
1305BdsSetMemoryTypeInformationVariable (\r
1306 VOID\r
1307 )\r
1308{\r
1309 EFI_STATUS Status;\r
1310 EFI_MEMORY_TYPE_INFORMATION *PreviousMemoryTypeInformation;\r
1311 EFI_MEMORY_TYPE_INFORMATION *CurrentMemoryTypeInformation;\r
1312 UINTN VariableSize;\r
1313 UINTN Index;\r
1314 UINTN Index1;\r
1315 UINT32 Previous;\r
1316 UINT32 Current;\r
1317 UINT32 Next;\r
1318 EFI_HOB_GUID_TYPE *GuidHob;\r
1319 BOOLEAN MemoryTypeInformationModified;\r
1320 BOOLEAN MemoryTypeInformationVariableExists;\r
1321 EFI_BOOT_MODE BootMode;\r
1322\r
1323 MemoryTypeInformationModified = FALSE;\r
1324 MemoryTypeInformationVariableExists = FALSE;\r
1325\r
1326\r
1327 BootMode = GetBootModeHob ();\r
1328 //\r
1329 // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable.\r
1330 //\r
1331 if (BootMode == BOOT_IN_RECOVERY_MODE) {\r
1332 return;\r
1333 }\r
1334\r
1335 //\r
1336 // Only check the the Memory Type Information variable in the boot mode \r
1337 // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type\r
1338 // Information is not valid in this boot mode.\r
1339 //\r
1340 if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) {\r
1341 VariableSize = 0;\r
1342 Status = gRT->GetVariable (\r
1343 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,\r
1344 &gEfiMemoryTypeInformationGuid,\r
1345 NULL, \r
1346 &VariableSize, \r
1347 NULL\r
1348 );\r
1349 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1350 MemoryTypeInformationVariableExists = TRUE;\r
1351 }\r
1352 }\r
1353\r
1354 //\r
1355 // Retrieve the current memory usage statistics. If they are not found, then\r
1356 // no adjustments can be made to the Memory Type Information variable.\r
1357 //\r
1358 Status = EfiGetSystemConfigurationTable (\r
1359 &gEfiMemoryTypeInformationGuid,\r
1360 (VOID **) &CurrentMemoryTypeInformation\r
1361 );\r
1362 if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) {\r
1363 return;\r
1364 }\r
1365\r
1366 //\r
1367 // Get the Memory Type Information settings from Hob if they exist,\r
1368 // PEI is responsible for getting them from variable and build a Hob to save them.\r
1369 // If the previous Memory Type Information is not available, then set defaults\r
1370 //\r
1371 GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);\r
1372 if (GuidHob == NULL) {\r
1373 //\r
1374 // If Platform has not built Memory Type Info into the Hob, just return.\r
1375 //\r
1376 return;\r
1377 }\r
1378 PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);\r
1379 VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob);\r
1380\r
1381 //\r
1382 // Use a heuristic to adjust the Memory Type Information for the next boot\r
1383 //\r
1384 DEBUG ((EFI_D_INFO, "Memory Previous Current Next \n"));\r
1385 DEBUG ((EFI_D_INFO, " Type Pages Pages Pages \n"));\r
1386 DEBUG ((EFI_D_INFO, "====== ======== ======== ========\n"));\r
1387\r
1388 for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
1389\r
1390 for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {\r
1391 if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {\r
1392 break;\r
1393 }\r
1394 }\r
1395 if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {\r
1396 continue;\r
1397 }\r
1398\r
1399 //\r
1400 // Previous is the number of pages pre-allocated\r
1401 // Current is the number of pages actually needed\r
1402 //\r
1403 Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;\r
1404 Current = CurrentMemoryTypeInformation[Index1].NumberOfPages;\r
1405 Next = Previous;\r
1406\r
1407 //\r
1408 // Inconsistent Memory Reserved across bootings may lead to S4 fail\r
1409 // Write next varible to 125% * current when the pre-allocated memory is:\r
1410 // 1. More than 150% of needed memory and boot mode is BOOT_WITH_DEFAULT_SETTING\r
1411 // 2. Less than the needed memory\r
1412 //\r
1413 if ((Current + (Current >> 1)) < Previous) {\r
1414 if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {\r
1415 Next = Current + (Current >> 2);\r
1416 }\r
1417 } else if (Current > Previous) {\r
1418 Next = Current + (Current >> 2);\r
1419 }\r
1420 if (Next > 0 && Next < 4) {\r
1421 Next = 4;\r
1422 }\r
1423\r
1424 if (Next != Previous) {\r
1425 PreviousMemoryTypeInformation[Index].NumberOfPages = Next;\r
1426 MemoryTypeInformationModified = TRUE;\r
1427 }\r
1428\r
1429 DEBUG ((EFI_D_INFO, " %02x %08x %08x %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next));\r
1430 }\r
1431\r
1432 //\r
1433 // If any changes were made to the Memory Type Information settings, then set the new variable value;\r
1434 // Or create the variable in first boot.\r
1435 //\r
1436 if (MemoryTypeInformationModified || !MemoryTypeInformationVariableExists) {\r
1437 Status = SetVariableAndReportStatusCodeOnError (\r
1438 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,\r
1439 &gEfiMemoryTypeInformationGuid,\r
1440 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1441 VariableSize,\r
1442 PreviousMemoryTypeInformation\r
1443 );\r
1444\r
1445 if (!EFI_ERROR (Status)) {\r
1446 //\r
1447 // If the Memory Type Information settings have been modified, then reset the platform\r
1448 // so the new Memory Type Information setting will be used to guarantee that an S4\r
1449 // entry/resume cycle will not fail.\r
1450 //\r
1451 if (MemoryTypeInformationModified && PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {\r
1452 DEBUG ((EFI_D_INFO, "Memory Type Information settings change. Warm Reset!!!\n"));\r
1453 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
1454 }\r
1455 } else {\r
1456 DEBUG ((EFI_D_ERROR, "Memory Type Information settings cannot be saved. OS S4 may fail!\n"));\r
1457 }\r
1458 }\r
1459}\r
1460\r
1461/**\r
1462 This routine is kept for backward compatibility.\r
1463**/\r
1464VOID\r
1465EFIAPI\r
1466BdsLibSaveMemoryTypeInformation (\r
1467 VOID\r
1468 )\r
1469{\r
1470}\r
1471\r
1472\r
1473/**\r
1474 Identify a user and, if authenticated, returns the current user profile handle.\r
1475\r
1476 @param[out] User Point to user profile handle.\r
1477 \r
1478 @retval EFI_SUCCESS User is successfully identified, or user identification\r
1479 is not supported.\r
1480 @retval EFI_ACCESS_DENIED User is not successfully identified\r
1481\r
1482**/\r
1483EFI_STATUS\r
1484EFIAPI\r
1485BdsLibUserIdentify (\r
1486 OUT EFI_USER_PROFILE_HANDLE *User\r
1487 )\r
1488{\r
1489 EFI_STATUS Status;\r
1490 EFI_USER_MANAGER_PROTOCOL *Manager;\r
1491 \r
1492 Status = gBS->LocateProtocol (\r
1493 &gEfiUserManagerProtocolGuid,\r
1494 NULL,\r
1495 (VOID **) &Manager\r
1496 );\r
1497 if (EFI_ERROR (Status)) {\r
1498 return EFI_SUCCESS;\r
1499 }\r
1500\r
1501 return Manager->Identify (Manager, User);\r
1502}\r
1503\r
1504/**\r
1505 Set the variable and report the error through status code upon failure.\r
1506\r
1507 @param VariableName A Null-terminated string that is the name of the vendor's variable.\r
1508 Each VariableName is unique for each VendorGuid. VariableName must\r
1509 contain 1 or more characters. If VariableName is an empty string,\r
1510 then EFI_INVALID_PARAMETER is returned.\r
1511 @param VendorGuid A unique identifier for the vendor.\r
1512 @param Attributes Attributes bitmask to set for the variable.\r
1513 @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, \r
1514 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or \r
1515 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero \r
1516 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is \r
1517 set, then a SetVariable() call with a DataSize of zero will not cause any change to \r
1518 the variable value (the timestamp associated with the variable may be updated however \r
1519 even if no new data value is provided,see the description of the \r
1520 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not \r
1521 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). \r
1522 @param Data The contents for the variable.\r
1523\r
1524 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as\r
1525 defined by the Attributes.\r
1526 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the\r
1527 DataSize exceeds the maximum allowed.\r
1528 @retval EFI_INVALID_PARAMETER VariableName is an empty string.\r
1529 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.\r
1530 @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.\r
1531 @retval EFI_WRITE_PROTECTED The variable in question is read-only.\r
1532 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.\r
1533 @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS \r
1534 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo \r
1535 does NOT pass the validation check carried out by the firmware.\r
1536\r
1537 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.\r
1538**/\r
1539EFI_STATUS\r
1540SetVariableAndReportStatusCodeOnError (\r
1541 IN CHAR16 *VariableName,\r
1542 IN EFI_GUID *VendorGuid,\r
1543 IN UINT32 Attributes,\r
1544 IN UINTN DataSize,\r
1545 IN VOID *Data\r
1546 )\r
1547{\r
1548 EFI_STATUS Status;\r
1549 EDKII_SET_VARIABLE_STATUS *SetVariableStatus;\r
1550 UINTN NameSize;\r
1551\r
1552 Status = gRT->SetVariable (\r
1553 VariableName,\r
1554 VendorGuid,\r
1555 Attributes,\r
1556 DataSize,\r
1557 Data\r
1558 );\r
1559 if (EFI_ERROR (Status)) {\r
1560 NameSize = StrSize (VariableName);\r
1561 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);\r
1562 if (SetVariableStatus != NULL) {\r
1563 CopyGuid (&SetVariableStatus->Guid, VendorGuid);\r
1564 SetVariableStatus->NameSize = NameSize;\r
1565 SetVariableStatus->DataSize = DataSize;\r
1566 SetVariableStatus->SetStatus = Status;\r
1567 SetVariableStatus->Attributes = Attributes;\r
1568 CopyMem (SetVariableStatus + 1, VariableName, NameSize);\r
1569 if ((Data != NULL) && (DataSize != 0)) {\r
1570 CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);\r
1571 }\r
1572\r
1573 REPORT_STATUS_CODE_EX (\r
1574 EFI_ERROR_CODE,\r
1575 PcdGet32 (PcdErrorCodeSetVariable),\r
1576 0,\r
1577 NULL,\r
1578 &gEdkiiStatusCodeDataTypeVariableGuid,\r
1579 SetVariableStatus,\r
1580 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize\r
1581 );\r
1582\r
1583 FreePool (SetVariableStatus);\r
1584 }\r
1585 }\r
1586\r
1587 return Status;\r
1588}\r
1589\r