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