]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Library/GenericBdsLib/BdsMisc.c
IntelFrameworkModulePkg: Clean up source files
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / GenericBdsLib / BdsMisc.c
CommitLineData
5c08e117 1/** @file\r
2 Misc BDS library function\r
3\r
0a6f4824 4Copyright (c) 2004 - 2018, 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
0a6f4824 54\r
5c08e117 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
0a6f4824 62\r
5c08e117 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
0a6f4824 71\r
5c08e117 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
0a6f4824 120\r
5c08e117 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
46737a64 171 FreePool(OptionBuffer);\r
5c08e117 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
c4571f04
RN
221 if (DevicePath == NULL) {\r
222 return EFI_INVALID_PARAMETER;\r
223 }\r
5c08e117 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
8c08a567
ED
264\r
265 //\r
266 // Validate the variable.\r
267 //\r
268 if (!ValidateOption(OptionPtr, OptionSize)) {\r
46737a64 269 FreePool(OptionPtr);\r
8c08a567
ED
270 continue;\r
271 }\r
272\r
5c08e117 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
0a6f4824 283 if (CompareMem (Description, String, StrSize (Description)) == 0) {\r
5c08e117 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
0a6f4824 307\r
5c08e117 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
0a6f4824 319 // The number in option#### to be updated.\r
5c08e117 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
0a6f4824 378\r
5c08e117 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
b16cc38b
ED
406/**\r
407 Returns the size of a device path in bytes.\r
408\r
0a6f4824
LG
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
b16cc38b
ED
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
0a6f4824 415 @param MaxSize Max valid device path size. If big than this size,\r
b16cc38b 416 return error.\r
0a6f4824 417\r
b16cc38b
ED
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
8c08a567 441 if (NodeSize < END_DEVICE_PATH_LENGTH) {\r
b16cc38b
ED
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
0a6f4824
LG
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
b16cc38b
ED
461 invalidate string.\r
462\r
3e867071 463 This function returns the byte length of Unicode characters in the Null-terminated\r
0a6f4824 464 Unicode string specified by String.\r
b16cc38b
ED
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
3e867071 487 for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);\r
b16cc38b
ED
488\r
489 if (*String != L'\0' && MaxStringLen == Length) {\r
490 return 0;\r
491 }\r
492\r
3e867071 493 return Length + 2;\r
b16cc38b 494}\r
5c08e117 495\r
8c08a567
ED
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
0a6f4824 506BOOLEAN\r
8c08a567
ED
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
8c08a567
ED
515 UINTN TempSize;\r
516\r
3e867071
ED
517 if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {\r
518 return FALSE;\r
519 }\r
520\r
8c08a567
ED
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
3e867071 536 TempSize = StrSizeEx ((CHAR16 *) TempPtr, VariableSize - sizeof (UINT16) - sizeof (UINT32));\r
8c08a567
ED
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
3e867071 543 TempPtr += FilePathSize;\r
8c08a567
ED
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
3e867071 552 if (TempSize + FilePathSize + sizeof (UINT16) + sizeof (UINT32) > VariableSize) {\r
8c08a567
ED
553 return FALSE;\r
554 }\r
555\r
97627ad4 556 return (BOOLEAN) (GetDevicePathSizeEx (DevicePath, FilePathSize) != 0);\r
8c08a567
ED
557}\r
558\r
c1e2752c
ED
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
0a6f4824 562\r
c1e2752c 563 @param Char The input char which need to change to a hex number.\r
0a6f4824 564\r
c1e2752c
ED
565**/\r
566UINTN\r
567CharToUint (\r
568 IN CHAR16 Char\r
569 )\r
570{\r
571 if ((Char >= L'0') && (Char <= L'9')) {\r
aa5f60ae 572 return (Char - L'0');\r
c1e2752c
ED
573 }\r
574\r
575 if ((Char >= L'A') && (Char <= L'F')) {\r
aa5f60ae 576 return (Char - L'A' + 0xA);\r
c1e2752c
ED
577 }\r
578\r
579 ASSERT (FALSE);\r
580 return 0;\r
581}\r
582\r
5c08e117 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
3e867071 614\r
5c08e117 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
8c08a567
ED
626\r
627 //\r
628 // Validate Boot#### variable data.\r
629 //\r
630 if (!ValidateOption(Variable, VariableSize)) {\r
46737a64 631 FreePool (Variable);\r
8c08a567
ED
632 return NULL;\r
633 }\r
634\r
5c08e117 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
3e867071 660 TempPtr += StrSize((CHAR16 *) TempPtr);\r
5c08e117 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
b16cc38b
ED
668 //\r
669 // Get load opion data.\r
670 //\r
5c08e117 671 LoadOptions = TempPtr;\r
4ff5fd20 672 LoadOptionsSize = (UINT32) (VariableSize - ((UINTN)TempPtr - (UINTN)Variable));\r
5c08e117 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
46737a64 680 FreePool (Variable);\r
5c08e117 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
c1e2752c 705 NumOff = (UINT8) (sizeof (L"Boot") / sizeof (CHAR16) - 1);\r
0a6f4824 706 Option->BootCurrent = (UINT16) (CharToUint (VariableName[NumOff+0]) * 0x1000)\r
c1e2752c
ED
707 + (UINT16) (CharToUint (VariableName[NumOff+1]) * 0x100)\r
708 + (UINT16) (CharToUint (VariableName[NumOff+2]) * 0x10)\r
709 + (UINT16) (CharToUint (VariableName[NumOff+3]) * 0x1);\r
5c08e117 710 }\r
16e5944a 711 InsertTailList (BdsCommonOptionList, &Option->Link);\r
5c08e117 712 FreePool (Variable);\r
16e5944a 713 return Option;\r
5c08e117 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
7490e2be 768 if (Option != NULL) {\r
769 Option->BootCurrent = OptionOrder[Index];\r
770 }\r
5c08e117 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
2d1f3dd4 835 *VariableSize = 0;\r
5c08e117 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
2d1f3dd4 843 FreePool (Buffer);\r
5c08e117 844 BufferSize = 0;\r
2d1f3dd4 845 Buffer = NULL;\r
5c08e117 846 }\r
847 }\r
848\r
2d1f3dd4
RN
849 ASSERT (((Buffer == NULL) && (BufferSize == 0)) ||\r
850 ((Buffer != NULL) && (BufferSize != 0))\r
851 );\r
5c08e117 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
31b440cf 997 if (String == NULL) {\r
5c08e117 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
0a6f4824 1007\r
5c08e117 1008 VA_END(Args);\r
1009 return Status;\r
1010}\r
1011\r
1012//\r
8d3b5aff 1013// Following are BDS Lib functions which contain all the code about setup browser reset reminder feature.\r
5c08e117 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
885c3060 1130 StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));\r
5c08e117 1131 ASSERT (StringBuffer1 != NULL);\r
885c3060 1132 StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));\r
5c08e117 1133 ASSERT (StringBuffer2 != NULL);\r
885c3060
HW
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
5c08e117 1144 //\r
1145 // Popup a menu to notice user\r
1146 //\r
1147 do {\r
e3b236c8 1148 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, StringBuffer1, StringBuffer2, NULL);\r
63588e61 1149 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
5c08e117 1150\r
1151 FreePool (StringBuffer1);\r
1152 FreePool (StringBuffer2);\r
63588e61
ED
1153\r
1154 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
5c08e117 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
da166a5d 1211 ASSERT (Root != NULL);\r
5c08e117 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
da166a5d 1216 ASSERT (ThisFile != NULL);\r
5c08e117 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
0a6f4824 1301 This routine adjust the memory information for different memory type and\r
3999f1fe 1302 save them into the variables for next boot.\r
5c08e117 1303**/\r
1304VOID\r
5c08e117 1305BdsSetMemoryTypeInformationVariable (\r
7caf72a9 1306 VOID\r
5c08e117 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
5c08e117 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
7bee5a76 1319 BOOLEAN MemoryTypeInformationModified;\r
a4e9b4f6 1320 BOOLEAN MemoryTypeInformationVariableExists;\r
8c716296 1321 EFI_BOOT_MODE BootMode;\r
a4e9b4f6 1322\r
7bee5a76 1323 MemoryTypeInformationModified = FALSE;\r
a4e9b4f6 1324 MemoryTypeInformationVariableExists = FALSE;\r
1325\r
8c716296 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
7bee5a76 1335 //\r
0a6f4824 1336 // Only check the the Memory Type Information variable in the boot mode\r
7bee5a76
RN
1337 // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type\r
1338 // Information is not valid in this boot mode.\r
1339 //\r
8c716296 1340 if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) {\r
a4e9b4f6 1341 VariableSize = 0;\r
1342 Status = gRT->GetVariable (\r
1343 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,\r
1344 &gEfiMemoryTypeInformationGuid,\r
0a6f4824
LG
1345 NULL,\r
1346 &VariableSize,\r
a4e9b4f6 1347 NULL\r
1348 );\r
1349 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1350 MemoryTypeInformationVariableExists = TRUE;\r
a4e9b4f6 1351 }\r
1352 }\r
5c08e117 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
a4e9b4f6 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
5c08e117 1388 for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
1389\r
5c08e117 1390 for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {\r
1391 if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {\r
5c08e117 1392 break;\r
1393 }\r
1394 }\r
5c08e117 1395 if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {\r
1396 continue;\r
1397 }\r
1398\r
a97a8596
RN
1399 //\r
1400 // Previous is the number of pages pre-allocated\r
1401 // Current is the number of pages actually needed\r
1402 //\r
5c08e117 1403 Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;\r
a97a8596
RN
1404 Current = CurrentMemoryTypeInformation[Index1].NumberOfPages;\r
1405 Next = Previous;\r
5c08e117 1406\r
1407 //\r
3999f1fe
RN
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
5c08e117 1412 //\r
3999f1fe 1413 if ((Current + (Current >> 1)) < Previous) {\r
a97a8596
RN
1414 if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {\r
1415 Next = Current + (Current >> 2);\r
a97a8596 1416 }\r
a4e9b4f6 1417 } else if (Current > Previous) {\r
5c08e117 1418 Next = Current + (Current >> 2);\r
5c08e117 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
7bee5a76 1426 MemoryTypeInformationModified = TRUE;\r
5c08e117 1427 }\r
1428\r
a4e9b4f6 1429 DEBUG ((EFI_D_INFO, " %02x %08x %08x %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next));\r
5c08e117 1430 }\r
1431\r
1432 //\r
7bee5a76
RN
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
5c08e117 1435 //\r
7bee5a76 1436 if (MemoryTypeInformationModified || !MemoryTypeInformationVariableExists) {\r
69fc8f08
RN
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
7bee5a76 1444\r
e609aef9
RN
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
7bee5a76 1457 }\r
5c08e117 1458 }\r
5c08e117 1459}\r
1460\r
1461/**\r
7caf72a9 1462 This routine is kept for backward compatibility.\r
5c08e117 1463**/\r
1464VOID\r
1465EFIAPI\r
1466BdsLibSaveMemoryTypeInformation (\r
1467 VOID\r
1468 )\r
1469{\r
5c08e117 1470}\r
1471\r
1472\r
337661bb 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
0a6f4824 1477\r
337661bb 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
0a6f4824 1491\r
337661bb 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
69fc8f08
RN
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
0a6f4824
LG
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
69fc8f08
RN
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
0a6f4824
LG
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
69fc8f08
RN
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
c4571f04
RN
1569 if ((Data != NULL) && (DataSize != 0)) {\r
1570 CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);\r
1571 }\r
69fc8f08
RN
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