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