Update video card preference policy, together with some memory leaks in Generic BDS...
[people/mcb30/edk2.git] / edk2 / EdkUnixPkg / Library / EdkGenericBdsLib / BdsMisc.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   BdsMisc.c\r
15 \r
16 Abstract:\r
17 \r
18   Misc BDS library function\r
19 \r
20 --*/\r
21 \r
22 #define MAX_STRING_LEN        200\r
23 static BOOLEAN   mFeaturerSwitch = TRUE;\r
24 static BOOLEAN   mResetRequired  = FALSE;\r
25 extern UINT16 gPlatformBootTimeOutDefault;\r
26 \r
27 UINT16\r
28 BdsLibGetTimeout (\r
29   VOID\r
30   )\r
31 /*++\r
32 \r
33 Routine Description:\r
34   \r
35   Return the default value for system Timeout variable.\r
36 \r
37 Arguments:\r
38 \r
39   None\r
40 \r
41 Returns:\r
42   \r
43   Timeout value.\r
44 \r
45 --*/\r
46 {\r
47   UINT16      Timeout;\r
48   UINTN       Size;\r
49   EFI_STATUS  Status;\r
50 \r
51   //\r
52   // Return Timeout variable or 0xffff if no valid\r
53   // Timeout variable exists.\r
54   //\r
55   Size    = sizeof (UINT16);\r
56   Status  = gRT->GetVariable (L"Timeout", &gEfiGlobalVariableGuid, NULL, &Size, &Timeout);\r
57   if (!EFI_ERROR (Status)) {\r
58     return Timeout;\r
59   }\r
60   //\r
61   // To make the current EFI Automatic-Test activity possible, just add\r
62   // following code to make AutoBoot enabled when this variable is not\r
63   // present.\r
64   // This code should be removed later.\r
65   //\r
66   Timeout = gPlatformBootTimeOutDefault;\r
67 \r
68   //\r
69   // Notes: Platform should set default variable if non exists on all error cases!!!\r
70   //\r
71   Status = gRT->SetVariable (\r
72                   L"Timeout",\r
73                   &gEfiGlobalVariableGuid,\r
74                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
75                   sizeof (UINT16),\r
76                   &Timeout\r
77                   );\r
78   return Timeout;\r
79 }\r
80 \r
81 VOID\r
82 BdsLibLoadDrivers (\r
83   IN LIST_ENTRY               *BdsDriverLists\r
84   )\r
85 /*++\r
86 \r
87 Routine Description:\r
88   \r
89   The function will go through the driver optoin link list, load and start\r
90   every driver the driver optoin device path point to.\r
91 \r
92 Arguments:\r
93 \r
94   BdsDriverLists   - The header of the current driver option link list\r
95 \r
96 Returns:\r
97   \r
98   None\r
99 \r
100 --*/\r
101 {\r
102   EFI_STATUS                Status;\r
103   LIST_ENTRY                *Link;\r
104   BDS_COMMON_OPTION         *Option;\r
105   EFI_HANDLE                ImageHandle;\r
106   EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
107   UINTN                     ExitDataSize;\r
108   CHAR16                    *ExitData;\r
109   BOOLEAN                   ReconnectAll;\r
110 \r
111   ReconnectAll = FALSE;\r
112 \r
113   //\r
114   // Process the driver option\r
115   //\r
116   for (Link = BdsDriverLists->ForwardLink; Link != BdsDriverLists; Link = Link->ForwardLink) {\r
117     Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
118     //\r
119     // If a load option is not marked as LOAD_OPTION_ACTIVE,\r
120     // the boot manager will not automatically load the option.\r
121     //\r
122     if (!IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_ACTIVE)) {\r
123       continue;\r
124     }\r
125     //\r
126     // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,\r
127     // then all of the EFI drivers in the system will be disconnected and\r
128     // reconnected after the last driver load option is processed.\r
129     //\r
130     if (IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_FORCE_RECONNECT)) {\r
131       ReconnectAll = TRUE;\r
132     }\r
133     //\r
134     // Make sure the driver path is connected.\r
135     //\r
136     BdsLibConnectDevicePath (Option->DevicePath);\r
137 \r
138     //\r
139     // Load and start the image that Driver#### describes\r
140     //\r
141     Status = gBS->LoadImage (\r
142                     FALSE,\r
143                     mBdsImageHandle,\r
144                     Option->DevicePath,\r
145                     NULL,\r
146                     0,\r
147                     &ImageHandle\r
148                     );\r
149 \r
150     if (!EFI_ERROR (Status)) {\r
151       gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid,
152                            (VOID **)&ImageInfo);\r
153 \r
154       //\r
155       // Verify whether this image is a driver, if not,\r
156       // exit it and continue to parse next load option\r
157       //\r
158       if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {\r
159         gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);\r
160         continue;\r
161       }\r
162 \r
163       if (Option->LoadOptionsSize != 0) {\r
164         ImageInfo->LoadOptionsSize  = Option->LoadOptionsSize;\r
165         ImageInfo->LoadOptions      = Option->LoadOptions;\r
166       }\r
167       //\r
168       // Before calling the image, enable the Watchdog Timer for\r
169       // the 5 Minute period\r
170       //\r
171       gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
172 \r
173       Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);\r
174       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Driver Return Status = %r\n", Status));\r
175 \r
176       //\r
177       // Clear the Watchdog Timer after the image returns\r
178       //\r
179       gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
180     }\r
181   }\r
182   //\r
183   // Process the LOAD_OPTION_FORCE_RECONNECT driver option\r
184   //\r
185   if (ReconnectAll) {\r
186     BdsLibDisconnectAllEfi ();\r
187     BdsLibConnectAll ();\r
188   }\r
189 \r
190 }\r
191 \r
192 EFI_STATUS\r
193 BdsLibRegisterNewOption (\r
194   IN  LIST_ENTRY                     *BdsOptionList,\r
195   IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,\r
196   IN  CHAR16                         *String,\r
197   IN  CHAR16                         *VariableName\r
198   )\r
199 /*++\r
200 \r
201 Routine Description:\r
202   \r
203   This function will register the new boot#### or driver#### option base on\r
204   the VariableName. The new registered boot#### or driver#### will be linked\r
205   to BdsOptionList and also update to the VariableName. After the boot#### or\r
206   driver#### updated, the BootOrder or DriverOrder will also be updated.\r
207 \r
208 Arguments:\r
209 \r
210   BdsOptionList    - The header of the boot#### or driver#### link list\r
211   \r
212   DevicePath       - The device path which the boot####\r
213                      or driver#### option present\r
214                      \r
215   String           - The description of the boot#### or driver####\r
216   \r
217   VariableName     - Indicate if the boot#### or driver#### option\r
218 \r
219 Returns:\r
220   \r
221   EFI_SUCCESS      - The boot#### or driver#### have been success registered\r
222   \r
223   EFI_STATUS       - Return the status of gRT->SetVariable ().\r
224 \r
225 --*/\r
226 {\r
227   EFI_STATUS                Status;\r
228   UINTN                     Index;\r
229   UINT16                    MaxOptionNumber;\r
230   UINT16                    RegisterOptionNumber;\r
231   UINT16                    *TempOptionPtr;\r
232   UINTN                     TempOptionSize;\r
233   UINT16                    *OptionOrderPtr;\r
234   VOID                      *OptionPtr;\r
235   UINTN                     OptionSize;\r
236   UINT8                     *TempPtr;\r
237   EFI_DEVICE_PATH_PROTOCOL  *OptionDevicePath;\r
238   CHAR16                    *Description;\r
239   CHAR16                    OptionName[10];\r
240   BOOLEAN                   UpdateBootDevicePath;\r
241 \r
242   OptionPtr             = NULL;\r
243   OptionSize            = 0;\r
244   TempPtr               = NULL;\r
245   OptionDevicePath      = NULL;\r
246   Description           = NULL;\r
247   MaxOptionNumber       = 0;\r
248   OptionOrderPtr        = NULL;\r
249   UpdateBootDevicePath  = FALSE;\r
250   ZeroMem (OptionName, sizeof (OptionName));\r
251 \r
252   TempOptionSize = 0;\r
253   TempOptionPtr = BdsLibGetVariableAndSize (\r
254                     VariableName,\r
255                     &gEfiGlobalVariableGuid,\r
256                     &TempOptionSize\r
257                     );\r
258   //\r
259   // Compare with current option variable\r
260   //\r
261   for (Index = 0; Index < TempOptionSize / sizeof (UINT16); Index++) {\r
262     //\r
263     // Got the max option#### number\r
264     //\r
265     if (MaxOptionNumber < TempOptionPtr[Index]) {\r
266       MaxOptionNumber = TempOptionPtr[Index];\r
267     }\r
268 \r
269     if (*VariableName == 'B') {\r
270       UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", TempOptionPtr[Index]);\r
271     } else {\r
272       UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", TempOptionPtr[Index]);\r
273     }\r
274 \r
275     OptionPtr = BdsLibGetVariableAndSize (\r
276                   OptionName,\r
277                   &gEfiGlobalVariableGuid,\r
278                   &OptionSize\r
279                   );\r
280     TempPtr = OptionPtr;\r
281     TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
282     Description = (CHAR16 *) TempPtr;\r
283     TempPtr += StrSize ((CHAR16 *) TempPtr);\r
284     OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
285 \r
286     //\r
287     // Notes: the description may will change base on the GetStringToken\r
288     //\r
289     if (CompareMem (Description, String, StrSize (Description)) == 0) {\r
290       if (CompareMem (OptionDevicePath, DevicePath, GetDevicePathSize (OptionDevicePath)) == 0) {\r
291         //\r
292         // Got the option, so just return\r
293         //\r
294         gBS->FreePool (OptionPtr);\r
295         gBS->FreePool (TempOptionPtr);\r
296         return EFI_SUCCESS;\r
297       } else {\r
298         //\r
299         // Boot device path changed, need update.\r
300         //\r
301         UpdateBootDevicePath = TRUE;\r
302         break;\r
303       }\r
304     }\r
305 \r
306     gBS->FreePool (OptionPtr);\r
307   }\r
308 \r
309   OptionSize          = sizeof (UINT32) + sizeof (UINT16) + StrSize (String) + GetDevicePathSize (DevicePath);\r
310   OptionPtr           = AllocateZeroPool (OptionSize);\r
311   TempPtr             = OptionPtr;\r
312   *(UINT32 *) TempPtr = LOAD_OPTION_ACTIVE;\r
313   TempPtr += sizeof (UINT32);\r
314   *(UINT16 *) TempPtr = (UINT16) GetDevicePathSize (DevicePath);\r
315   TempPtr += sizeof (UINT16);\r
316   CopyMem (TempPtr, String, StrSize (String));\r
317   TempPtr += StrSize (String);\r
318   CopyMem (TempPtr, DevicePath, GetDevicePathSize (DevicePath));\r
319 \r
320   if (UpdateBootDevicePath) {\r
321     //\r
322     // The number in option#### to be updated\r
323     //\r
324     RegisterOptionNumber = TempOptionPtr[Index];\r
325   } else {\r
326     //\r
327     // The new option#### number\r
328     //\r
329     RegisterOptionNumber = MaxOptionNumber + 1;\r
330   }\r
331 \r
332   if (*VariableName == 'B') {\r
333     UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", RegisterOptionNumber);\r
334   } else {\r
335     UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", RegisterOptionNumber);\r
336   }\r
337 \r
338   Status = gRT->SetVariable (\r
339                   OptionName,\r
340                   &gEfiGlobalVariableGuid,\r
341                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
342                   OptionSize,\r
343                   OptionPtr\r
344                   );\r
345   if (EFI_ERROR (Status) || UpdateBootDevicePath) {\r
346     gBS->FreePool (OptionPtr);\r
347     gBS->FreePool (TempOptionPtr);\r
348     return Status;\r
349   }\r
350 \r
351   gBS->FreePool (OptionPtr);\r
352 \r
353   //\r
354   // Update the option order variable\r
355   //\r
356   OptionOrderPtr = AllocateZeroPool ((Index + 1) * sizeof (UINT16));\r
357   CopyMem (OptionOrderPtr, TempOptionPtr, Index * sizeof (UINT16));\r
358   OptionOrderPtr[Index] = RegisterOptionNumber;\r
359   Status = gRT->SetVariable (\r
360                   VariableName,\r
361                   &gEfiGlobalVariableGuid,\r
362                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
363                   (Index + 1) * sizeof (UINT16),\r
364                   OptionOrderPtr\r
365                   );\r
366   if (EFI_ERROR (Status)) {\r
367     gBS->FreePool (TempOptionPtr);\r
368     gBS->FreePool (OptionOrderPtr);\r
369     return Status;\r
370   }\r
371 \r
372   gBS->FreePool (TempOptionPtr);\r
373   gBS->FreePool (OptionOrderPtr);\r
374 \r
375   return EFI_SUCCESS;\r
376 }\r
377 \r
378 BDS_COMMON_OPTION *\r
379 BdsLibVariableToOption (\r
380   IN OUT LIST_ENTRY               *BdsCommonOptionList,\r
381   IN  CHAR16                      *VariableName\r
382   )\r
383 /*++\r
384 \r
385 Routine Description:\r
386 \r
387   Build the boot#### or driver#### option from the VariableName, the \r
388   build boot#### or driver#### will also be linked to BdsCommonOptionList\r
389   \r
390 Arguments:\r
391 \r
392   BdsCommonOptionList - The header of the boot#### or driver#### option link list\r
393 \r
394   VariableName - EFI Variable name indicate if it is boot#### or driver####\r
395 \r
396 Returns:\r
397 \r
398   BDS_COMMON_OPTION    - Get the option just been created\r
399 \r
400   NULL                 - Failed to get the new option\r
401 \r
402 --*/\r
403 {\r
404   UINT32                    Attribute;\r
405   UINT16                    FilePathSize;\r
406   UINT8                     *Variable;\r
407   UINT8                     *TempPtr;\r
408   UINTN                     VariableSize;\r
409   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
410   BDS_COMMON_OPTION         *Option;\r
411   VOID                      *LoadOptions;\r
412   UINT32                    LoadOptionsSize;\r
413   CHAR16                    *Description;\r
414 \r
415   //\r
416   // Read the variable. We will never free this data.\r
417   //\r
418   Variable = BdsLibGetVariableAndSize (\r
419               VariableName,\r
420               &gEfiGlobalVariableGuid,\r
421               &VariableSize\r
422               );\r
423   if (Variable == NULL) {\r
424     return NULL;\r
425   }\r
426   //\r
427   // Notes: careful defined the variable of Boot#### or\r
428   // Driver####, consider use some macro to abstract the code\r
429   //\r
430   //\r
431   // Get the option attribute\r
432   //\r
433   TempPtr   = Variable;\r
434   Attribute = *(UINT32 *) Variable;\r
435   TempPtr += sizeof (UINT32);\r
436 \r
437   //\r
438   // Get the option's device path size\r
439   //\r
440   FilePathSize = *(UINT16 *) TempPtr;\r
441   TempPtr += sizeof (UINT16);\r
442 \r
443   //\r
444   // Get the option's description string\r
445   //\r
446   Description = (CHAR16 *) TempPtr;\r
447 \r
448   //\r
449   // Get the option's description string size\r
450   //\r
451   TempPtr += StrSize ((CHAR16 *) TempPtr);\r
452 \r
453   //\r
454   // Get the option's device path\r
455   //\r
456   DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
457   TempPtr += FilePathSize;\r
458 \r
459   LoadOptions     = TempPtr;\r
460   LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));\r
461 \r
462   //\r
463   // The Console variables may have multiple device paths, so make\r
464   // an Entry for each one.\r
465   //\r
466   Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION));\r
467   if (Option == NULL) {\r
468     return NULL;\r
469   }\r
470 \r
471   Option->Signature   = BDS_LOAD_OPTION_SIGNATURE;\r
472   Option->DevicePath  = AllocateZeroPool (GetDevicePathSize (DevicePath));\r
473   CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));\r
474   Option->Attribute   = Attribute;\r
475   Option->Description = AllocateZeroPool (StrSize (Description));\r
476   CopyMem (Option->Description, Description, StrSize (Description));\r
477   Option->LoadOptions = AllocateZeroPool (LoadOptionsSize);\r
478   CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize);\r
479   Option->LoadOptionsSize = LoadOptionsSize;\r
480 \r
481   //\r
482   // Insert active entry to BdsDeviceList\r
483   //\r
484   if ((Option->Attribute & LOAD_OPTION_ACTIVE) == LOAD_OPTION_ACTIVE) {\r
485     InsertTailList (BdsCommonOptionList, &Option->Link);\r
486     gBS->FreePool (Variable);\r
487     return Option;\r
488   }\r
489 \r
490   gBS->FreePool (Variable);\r
491   gBS->FreePool (Option);\r
492   return NULL;\r
493 \r
494 }\r
495 \r
496 EFI_STATUS\r
497 BdsLibBuildOptionFromVar (\r
498   IN  LIST_ENTRY                  *BdsCommonOptionList,\r
499   IN  CHAR16                      *VariableName\r
500   )\r
501 /*++\r
502 \r
503 Routine Description:\r
504 \r
505   Process BootOrder, or DriverOrder variables, by calling\r
506   BdsLibVariableToOption () for each UINT16 in the variables.\r
507 \r
508 Arguments:\r
509 \r
510   BdsCommonOptionList - The header of the option list base on variable\r
511                         VariableName\r
512 \r
513   VariableName - EFI Variable name indicate the BootOrder or DriverOrder\r
514 \r
515 Returns:\r
516 \r
517   EFI_SUCCESS - Success create the boot option or driver option list\r
518 \r
519   EFI_OUT_OF_RESOURCES - Failed to get the boot option or driver option list\r
520 \r
521 --*/\r
522 {\r
523   UINT16            *OptionOrder;\r
524   UINTN             OptionOrderSize;\r
525   UINTN             Index;\r
526   BDS_COMMON_OPTION *Option;\r
527   CHAR16            OptionName[20];\r
528 \r
529   //\r
530   // Zero Buffer in order to get all BOOT#### variables\r
531   //\r
532   ZeroMem (OptionName, sizeof (OptionName));\r
533 \r
534   //\r
535   // Read the BootOrder, or DriverOrder variable.\r
536   //\r
537   OptionOrder = BdsLibGetVariableAndSize (\r
538                   VariableName,\r
539                   &gEfiGlobalVariableGuid,\r
540                   &OptionOrderSize\r
541                   );\r
542   if (OptionOrder == NULL) {\r
543     return EFI_OUT_OF_RESOURCES;\r
544   }\r
545 \r
546   for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {\r
547     if (*VariableName == 'B') {\r
548       UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionOrder[Index]);\r
549     } else {\r
550       UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionOrder[Index]);\r
551     }\r
552     Option              = BdsLibVariableToOption (BdsCommonOptionList, OptionName);\r
553     Option->BootCurrent = OptionOrder[Index];\r
554 \r
555   }\r
556 \r
557   gBS->FreePool (OptionOrder);\r
558 \r
559   return EFI_SUCCESS;\r
560 }\r
561 \r
562 EFI_STATUS\r
563 BdsLibGetBootMode (\r
564   OUT EFI_BOOT_MODE       *BootMode\r
565   )\r
566 /*++\r
567 \r
568 Routine Description:\r
569 \r
570   Get boot mode by looking up configuration table and parsing HOB list\r
571 \r
572 Arguments:\r
573 \r
574   BootMode - Boot mode from PEI handoff HOB.\r
575 \r
576 Returns:\r
577 \r
578   EFI_SUCCESS - Successfully get boot mode\r
579   \r
580   EFI_NOT_FOUND - Can not find the current system boot mode\r
581 \r
582 --*/\r
583 {\r
584   EFI_HOB_HANDOFF_INFO_TABLE        *HobList;\r
585 \r
586   HobList = GetHobList ();\r
587   ASSERT (HobList->Header.HobType == EFI_HOB_TYPE_HANDOFF);\r
588   *BootMode = HobList->BootMode;\r
589 \r
590   return EFI_SUCCESS;\r
591 }\r
592 \r
593 VOID *\r
594 BdsLibGetVariableAndSize (\r
595   IN  CHAR16              *Name,\r
596   IN  EFI_GUID            *VendorGuid,\r
597   OUT UINTN               *VariableSize\r
598   )\r
599 /*++\r
600 \r
601 Routine Description:\r
602 \r
603   Read the EFI variable (VendorGuid/Name) and return a dynamically allocated\r
604   buffer, and the size of the buffer. If failure return NULL.\r
605 \r
606 Arguments:\r
607 \r
608   Name       - String part of EFI variable name\r
609 \r
610   VendorGuid - GUID part of EFI variable name\r
611 \r
612   VariableSize - Returns the size of the EFI variable that was read\r
613 \r
614 Returns:\r
615 \r
616   Dynamically allocated memory that contains a copy of the EFI variable.\r
617   Caller is responsible freeing the buffer.\r
618 \r
619   NULL - Variable was not read\r
620 \r
621 --*/\r
622 {\r
623   EFI_STATUS  Status;\r
624   UINTN       BufferSize;\r
625   VOID        *Buffer;\r
626 \r
627   Buffer = NULL;\r
628 \r
629   //\r
630   // Pass in a zero size buffer to find the required buffer size.\r
631   //\r
632   BufferSize  = 0;\r
633   Status      = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
634   if (Status == EFI_BUFFER_TOO_SMALL) {\r
635     //\r
636     // Allocate the buffer to return\r
637     //\r
638     Buffer = AllocateZeroPool (BufferSize);\r
639     if (Buffer == NULL) {\r
640       return NULL;\r
641     }\r
642     //\r
643     // Read variable into the allocated buffer.\r
644     //\r
645     Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
646     if (EFI_ERROR (Status)) {\r
647       BufferSize = 0;\r
648     }\r
649   }\r
650 \r
651   *VariableSize = BufferSize;\r
652   return Buffer;\r
653 }\r
654 \r
655 VOID\r
656 BdsLibSafeFreePool (\r
657   IN  VOID             *Buffer\r
658   )\r
659 /*++\r
660 \r
661 Routine Description:\r
662 \r
663   Free pool safely.\r
664 \r
665 Arguments:\r
666   \r
667   Buffer          - The allocated pool entry to free\r
668 \r
669 Returns:\r
670 \r
671   Pointer of the buffer allocated.\r
672 \r
673 --*/\r
674 {\r
675   if (Buffer != NULL) {\r
676     gBS->FreePool (Buffer);\r
677     Buffer = NULL;\r
678   }\r
679 }\r
680 \r
681 EFI_DEVICE_PATH_PROTOCOL *\r
682 BdsLibDelPartMatchInstance (\r
683   IN     EFI_DEVICE_PATH_PROTOCOL  *Multi,\r
684   IN     EFI_DEVICE_PATH_PROTOCOL  *Single\r
685   )\r
686 /*++\r
687 \r
688 Routine Description:\r
689 \r
690   Delete the instance in Multi which matches partly with Single instance\r
691 \r
692 Arguments:\r
693 \r
694   Multi        - A pointer to a multi-instance device path data structure.\r
695 \r
696   Single       - A pointer to a single-instance device path data structure.\r
697 \r
698 Returns:\r
699 \r
700   This function will remove the device path instances in Multi which partly \r
701   match with the Single, and return the result device path. If there is no\r
702   remaining device path as a result, this function will return NULL.\r
703 \r
704 --*/\r
705 {\r
706   EFI_DEVICE_PATH_PROTOCOL  *Instance;\r
707   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;\r
708   EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;\r
709   UINTN                     InstanceSize;\r
710   UINTN                     SingleDpSize;  \r
711   UINTN                     Size; \r
712   \r
713   NewDevicePath     = NULL;\r
714   TempNewDevicePath = NULL;\r
715 \r
716   if (Multi == NULL || Single == NULL) {\r
717     return Multi;\r
718   }\r
719   \r
720   Instance        =  GetNextDevicePathInstance (&Multi, &InstanceSize);\r
721   SingleDpSize    =  GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;\r
722   InstanceSize    -= END_DEVICE_PATH_LENGTH;\r
723 \r
724   while (Instance != NULL) {\r
725 \r
726     Size = (SingleDpSize < InstanceSize) ? SingleDpSize : InstanceSize;    \r
727         \r
728     if ((CompareMem (Instance, Single, Size) != 0)) {\r
729       //\r
730       // Append the device path instance which does not match with Single\r
731       //\r
732       TempNewDevicePath = NewDevicePath;\r
733       NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);\r
734       BdsLibSafeFreePool(TempNewDevicePath);\r
735     }\r
736     BdsLibSafeFreePool(Instance);\r
737     Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);\r
738     InstanceSize  -= END_DEVICE_PATH_LENGTH;\r
739   }\r
740   \r
741   return NewDevicePath;\r
742 }\r
743 \r
744 BOOLEAN\r
745 BdsLibMatchDevicePaths (\r
746   IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,\r
747   IN  EFI_DEVICE_PATH_PROTOCOL  *Single\r
748   )\r
749 /*++\r
750 \r
751 Routine Description:\r
752 \r
753   Function compares a device path data structure to that of all the nodes of a\r
754   second device path instance.\r
755 \r
756 Arguments:\r
757 \r
758   Multi        - A pointer to a multi-instance device path data structure.\r
759 \r
760   Single       - A pointer to a single-instance device path data structure.\r
761 \r
762 Returns:\r
763 \r
764   TRUE   - If the Single is contained within Multi\r
765   \r
766   FALSE  - The Single is not match within Multi\r
767   \r
768 \r
769 --*/\r
770 {\r
771   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
772   EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;\r
773   UINTN                     Size;\r
774 \r
775   if (!Multi || !Single) {\r
776     return FALSE;\r
777   }\r
778 \r
779   DevicePath      = Multi;\r
780   DevicePathInst  = GetNextDevicePathInstance (&DevicePath, &Size);\r
781 \r
782   //\r
783   // Search for the match of 'Single' in 'Multi'\r
784   //\r
785   while (DevicePathInst != NULL) {\r
786     //\r
787     // If the single device path is found in multiple device paths,\r
788     // return success\r
789     //\r
790     if (CompareMem (Single, DevicePathInst, Size) == 0) {\r
791       gBS->FreePool (DevicePathInst);\r
792       return TRUE;\r
793     }\r
794 \r
795     gBS->FreePool (DevicePathInst);\r
796     DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
797   }\r
798 \r
799   return FALSE;\r
800 }\r
801 \r
802 EFI_STATUS\r
803 BdsLibOutputStrings (\r
804   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL   *ConOut,\r
805   ...\r
806   )\r
807 /*++\r
808 \r
809 Routine Description:\r
810 \r
811   This function prints a series of strings.\r
812 \r
813 Arguments:\r
814 \r
815   ConOut               - Pointer to EFI_SIMPLE_TEXT_OUT_PROTOCOL\r
816 \r
817   ...                  - A variable argument list containing series of strings,\r
818                          the last string must be NULL.\r
819 \r
820 Returns:\r
821 \r
822   EFI_SUCCESS          - Success print out the string using ConOut.\r
823   \r
824   EFI_STATUS           - Return the status of the ConOut->OutputString ().\r
825 \r
826 --*/\r
827 {\r
828   VA_LIST     args;\r
829   EFI_STATUS  Status;\r
830   CHAR16      *String;\r
831 \r
832   Status = EFI_SUCCESS;\r
833   VA_START (args, ConOut);\r
834 \r
835   while (!EFI_ERROR (Status)) {\r
836     //\r
837     // If String is NULL, then it's the end of the list\r
838     //\r
839     String = VA_ARG (args, CHAR16 *);\r
840     if (!String) {\r
841       break;\r
842     }\r
843 \r
844     Status = ConOut->OutputString (ConOut, String);\r
845 \r
846     if (EFI_ERROR (Status)) {\r
847       break;\r
848     }\r
849   }\r
850 \r
851   return Status;\r
852 }\r
853 \r
854 //\r
855 //  Following are BDS Lib functions which  contain all the code about setup browser reset reminder feature.\r
856 //  Setup Browser reset reminder feature is that an reset reminder will be given before user leaves the setup browser  if \r
857 //  user change any option setting which needs a reset to be effective, and  the reset will be applied according to  the user selection.\r
858 //\r
859 \r
860 VOID\r
861 EnableResetReminderFeature (\r
862   VOID\r
863   )\r
864 /*++\r
865 \r
866 Routine Description:\r
867  \r
868   Enable the setup browser reset reminder feature.\r
869   This routine is used in platform tip. If the platform policy need the feature, use the routine to enable it.\r
870 \r
871 Arguments:\r
872 \r
873   VOID\r
874 \r
875 Returns:\r
876 \r
877   VOID\r
878 \r
879 --*/\r
880 {\r
881   mFeaturerSwitch = TRUE;\r
882\r
883 \r
884 VOID\r
885 DisableResetReminderFeature (\r
886   VOID\r
887   )\r
888 /*++\r
889 \r
890 Routine Description:\r
891  \r
892   Disable the setup browser reset reminder feature.\r
893   This routine is used in platform tip. If the platform policy do not want the feature, use the routine to disable it.\r
894   \r
895 Arguments:\r
896 \r
897   VOID\r
898 \r
899 Returns:\r
900 \r
901   VOID\r
902 \r
903 --*/\r
904 {\r
905   mFeaturerSwitch = FALSE;\r
906\r
907 \r
908 VOID\r
909 EnableResetRequired (\r
910   VOID\r
911   )\r
912 /*++\r
913 \r
914 Routine Description:\r
915  \r
916    Record the info that  a reset is required.\r
917    A  module boolean variable is used to record whether a reset is required. \r
918   \r
919 Arguments:\r
920 \r
921   VOID\r
922 \r
923 Returns:\r
924 \r
925   VOID\r
926 \r
927 --*/\r
928 {\r
929   mResetRequired = TRUE;\r
930\r
931 \r
932 VOID\r
933 DisableResetRequired (\r
934   VOID\r
935   )\r
936 /*++\r
937 \r
938 Routine Description:\r
939 \r
940    Record the info that  no reset is required.\r
941    A  module boolean variable is used to record whether a reset is required. \r
942 \r
943 Arguments:\r
944 \r
945   VOID\r
946 \r
947 Returns:\r
948 \r
949   VOID\r
950 \r
951 --*/\r
952 {\r
953   mResetRequired = FALSE;\r
954\r
955 \r
956 BOOLEAN\r
957 IsResetReminderFeatureEnable (\r
958   VOID\r
959   )\r
960 /*++\r
961 \r
962 Routine Description:\r
963  \r
964   Check whether platform policy enable the reset reminder feature. The default is enabled.\r
965 \r
966 Arguments:\r
967 \r
968   VOID\r
969 \r
970 Returns:\r
971 \r
972   VOID\r
973 \r
974 --*/\r
975 {\r
976   return mFeaturerSwitch;\r
977 }\r
978 \r
979 BOOLEAN\r
980 IsResetRequired (\r
981   VOID\r
982   )\r
983 /*++\r
984 \r
985 Routine Description:\r
986  \r
987   Check if  user changed any option setting which needs a system reset to be effective.\r
988   \r
989 Arguments:\r
990 \r
991   VOID\r
992 \r
993 Returns:\r
994 \r
995   VOID\r
996 \r
997 --*/\r
998 {\r
999   return mResetRequired;\r
1000 }\r
1001 \r
1002 VOID\r
1003 SetupResetReminder (\r
1004   VOID\r
1005   )\r
1006 /*++\r
1007 \r
1008 Routine Description:\r
1009  \r
1010   Check whether a reset is needed, and finish the reset reminder feature.\r
1011   If a reset is needed, Popup a menu to notice user, and finish the feature \r
1012   according to the user selection.\r
1013 \r
1014 Arguments:\r
1015 \r
1016   VOID\r
1017 \r
1018 Returns:\r
1019 \r
1020   VOID\r
1021 \r
1022 --*/\r
1023 {\r
1024   EFI_STATUS                    Status;\r
1025   EFI_FORM_BROWSER_PROTOCOL     *Browser;\r
1026   EFI_INPUT_KEY                 Key;  \r
1027   CHAR16                        *StringBuffer1;\r
1028   CHAR16                        *StringBuffer2;    \r
1029 \r
1030 \r
1031   //\r
1032   //check any reset required change is applied? if yes, reset system\r
1033   //\r
1034   if (IsResetReminderFeatureEnable ()) {\r
1035     if (IsResetRequired ()) {\r
1036     \r
1037       Status = gBS->LocateProtocol (\r
1038                       &gEfiFormBrowserProtocolGuid,\r
1039                       NULL,\r
1040                       (VOID **)&Browser\r
1041                       );      \r
1042                       \r
1043       StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));\r
1044       ASSERT (StringBuffer1 != NULL);\r
1045       StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));\r
1046       ASSERT (StringBuffer2 != NULL);      \r
1047       StrCpy (StringBuffer1, L"Configuration changed. Reset to apply it Now ? ");\r
1048       StrCpy (StringBuffer2, L"Enter (YES)  /   Esc (NO)");      \r
1049       //\r
1050       // Popup a menu to notice user\r
1051       // \r
1052       do {\r
1053         Browser->CreatePopUp (2, TRUE, 0, NULL, &Key, StringBuffer1, StringBuffer2);\r
1054       } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); \r
1055       \r
1056       gBS->FreePool (StringBuffer1);      \r
1057       gBS->FreePool (StringBuffer2);            \r
1058       //\r
1059       // If the user hits the YES Response key, reset\r
1060       //\r
1061       if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {\r
1062         gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
1063       }\r
1064       gST->ConOut->ClearScreen (gST->ConOut);\r
1065     } \r
1066   } \r
1067\r
1068 \r
1069 EFI_STATUS\r
1070 BdsLibGetHiiHandles (\r
1071   IN     EFI_HII_PROTOCOL *Hii,\r
1072   IN OUT UINT16           *HandleBufferLength,\r
1073   OUT    EFI_HII_HANDLE   **HiiHandleBuffer\r
1074   )\r
1075 /*++\r
1076 \r
1077 Routine Description:\r
1078 \r
1079   Determines the handles that are currently active in the database.\r
1080   It's the caller's responsibility to free handle buffer.\r
1081 \r
1082 Arguments:\r
1083 \r
1084   This                  - A pointer to the EFI_HII_PROTOCOL instance.\r
1085   HandleBufferLength    - On input, a pointer to the length of the handle buffer. On output, \r
1086                           the length of the handle buffer that is required for the handles found.\r
1087   HiiHandleBuffer       - Pointer to an array of EFI_HII_PROTOCOL instances returned.\r
1088 \r
1089 Returns:\r
1090 \r
1091   EFI_SUCCESS           - Get an array of EFI_HII_PROTOCOL instances successfully.\r
1092   EFI_INVALID_PARAMETER - Hii is NULL.\r
1093   EFI_NOT_FOUND         - Database not found.\r
1094   \r
1095 --*/\r
1096 {\r
1097   UINT16      TempBufferLength;\r
1098   EFI_STATUS  Status;\r
1099   \r
1100   TempBufferLength = 0;\r
1101   \r
1102   //\r
1103   // Try to find the actual buffer size for HiiHandle Buffer.\r
1104   //\r
1105   Status = Hii->FindHandles (Hii, &TempBufferLength, *HiiHandleBuffer);\r
1106   \r
1107   if (Status == EFI_BUFFER_TOO_SMALL) {\r
1108     *HiiHandleBuffer = AllocateZeroPool (TempBufferLength);\r
1109     Status = Hii->FindHandles (Hii, &TempBufferLength, *HiiHandleBuffer);\r
1110     //\r
1111     // we should not fail here.\r
1112     //\r
1113     ASSERT_EFI_ERROR (Status);\r
1114   }\r
1115   \r
1116   *HandleBufferLength = TempBufferLength;\r
1117   \r
1118   return Status;\r
1119   \r
1120 }\r