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