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