3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Misc BDS library function
22 #define MAX_STRING_LEN 200
23 static BOOLEAN mFeaturerSwitch
= TRUE
;
24 static BOOLEAN mResetRequired
= FALSE
;
25 extern UINT16 gPlatformBootTimeOutDefault
;
35 Return the default value for system Timeout variable.
52 // Return Timeout variable or 0xffff if no valid
53 // Timeout variable exists.
55 Size
= sizeof (UINT16
);
56 Status
= gRT
->GetVariable (L
"Timeout", &gEfiGlobalVariableGuid
, NULL
, &Size
, &Timeout
);
57 if (!EFI_ERROR (Status
)) {
61 // To make the current EFI Automatic-Test activity possible, just add
62 // following code to make AutoBoot enabled when this variable is not
64 // This code should be removed later.
66 Timeout
= gPlatformBootTimeOutDefault
;
69 // Notes: Platform should set default variable if non exists on all error cases!!!
71 Status
= gRT
->SetVariable (
73 &gEfiGlobalVariableGuid
,
74 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
83 IN LIST_ENTRY
*BdsDriverLists
89 The function will go through the driver optoin link list, load and start
90 every driver the driver optoin device path point to.
94 BdsDriverLists - The header of the current driver option link list
104 BDS_COMMON_OPTION
*Option
;
105 EFI_HANDLE ImageHandle
;
106 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
109 BOOLEAN ReconnectAll
;
111 ReconnectAll
= FALSE
;
114 // Process the driver option
116 for (Link
= BdsDriverLists
->ForwardLink
; Link
!= BdsDriverLists
; Link
= Link
->ForwardLink
) {
117 Option
= CR (Link
, BDS_COMMON_OPTION
, Link
, BDS_LOAD_OPTION_SIGNATURE
);
119 // If a load option is not marked as LOAD_OPTION_ACTIVE,
120 // the boot manager will not automatically load the option.
122 if (!IS_LOAD_OPTION_TYPE (Option
->Attribute
, LOAD_OPTION_ACTIVE
)) {
126 // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
127 // then all of the EFI drivers in the system will be disconnected and
128 // reconnected after the last driver load option is processed.
130 if (IS_LOAD_OPTION_TYPE (Option
->Attribute
, LOAD_OPTION_FORCE_RECONNECT
)) {
134 // Make sure the driver path is connected.
136 BdsLibConnectDevicePath (Option
->DevicePath
);
139 // Load and start the image that Driver#### describes
141 Status
= gBS
->LoadImage (
150 if (!EFI_ERROR (Status
)) {
151 gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, &ImageInfo
);
154 // Verify whether this image is a driver, if not,
155 // exit it and continue to parse next load option
157 if (ImageInfo
->ImageCodeType
!= EfiBootServicesCode
&& ImageInfo
->ImageCodeType
!= EfiRuntimeServicesCode
) {
158 gBS
->Exit (ImageHandle
, EFI_INVALID_PARAMETER
, 0, NULL
);
162 if (Option
->LoadOptionsSize
!= 0) {
163 ImageInfo
->LoadOptionsSize
= Option
->LoadOptionsSize
;
164 ImageInfo
->LoadOptions
= Option
->LoadOptions
;
167 // Before calling the image, enable the Watchdog Timer for
168 // the 5 Minute period
170 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
172 Status
= gBS
->StartImage (ImageHandle
, &ExitDataSize
, &ExitData
);
173 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Driver Return Status = %r\n", Status
));
176 // Clear the Watchdog Timer after the image returns
178 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
182 // Process the LOAD_OPTION_FORCE_RECONNECT driver option
185 BdsLibDisconnectAllEfi ();
192 BdsLibRegisterNewOption (
193 IN LIST_ENTRY
*BdsOptionList
,
194 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
196 IN CHAR16
*VariableName
202 This function will register the new boot#### or driver#### option base on
203 the VariableName. The new registered boot#### or driver#### will be linked
204 to BdsOptionList and also update to the VariableName. After the boot#### or
205 driver#### updated, the BootOrder or DriverOrder will also be updated.
209 BdsOptionList - The header of the boot#### or driver#### link list
211 DevicePath - The device path which the boot####
212 or driver#### option present
214 String - The description of the boot#### or driver####
216 VariableName - Indicate if the boot#### or driver#### option
220 EFI_SUCCESS - The boot#### or driver#### have been success registered
222 EFI_STATUS - Return the status of gRT->SetVariable ().
228 UINT16 MaxOptionNumber
;
229 UINT16 RegisterOptionNumber
;
230 UINT16
*TempOptionPtr
;
231 UINTN TempOptionSize
;
232 UINT16
*OptionOrderPtr
;
236 EFI_DEVICE_PATH_PROTOCOL
*OptionDevicePath
;
238 CHAR16 OptionName
[10];
239 BOOLEAN UpdateBootDevicePath
;
244 OptionDevicePath
= NULL
;
247 OptionOrderPtr
= NULL
;
248 UpdateBootDevicePath
= FALSE
;
249 ZeroMem (OptionName
, sizeof (OptionName
));
252 TempOptionPtr
= BdsLibGetVariableAndSize (
254 &gEfiGlobalVariableGuid
,
258 // Compare with current option variable
260 for (Index
= 0; Index
< TempOptionSize
/ sizeof (UINT16
); Index
++) {
262 // Got the max option#### number
264 if (MaxOptionNumber
< TempOptionPtr
[Index
]) {
265 MaxOptionNumber
= TempOptionPtr
[Index
];
268 if (*VariableName
== 'B') {
269 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"Boot%04x", TempOptionPtr
[Index
]);
271 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"Driver%04x", TempOptionPtr
[Index
]);
274 OptionPtr
= BdsLibGetVariableAndSize (
276 &gEfiGlobalVariableGuid
,
280 TempPtr
+= sizeof (UINT32
) + sizeof (UINT16
);
281 Description
= (CHAR16
*) TempPtr
;
282 TempPtr
+= StrSize ((CHAR16
*) TempPtr
);
283 OptionDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) TempPtr
;
286 // Notes: the description may will change base on the GetStringToken
288 if (CompareMem (Description
, String
, StrSize (Description
)) == 0) {
289 if (CompareMem (OptionDevicePath
, DevicePath
, GetDevicePathSize (OptionDevicePath
)) == 0) {
291 // Got the option, so just return
293 gBS
->FreePool (OptionPtr
);
294 gBS
->FreePool (TempOptionPtr
);
298 // Boot device path changed, need update.
300 UpdateBootDevicePath
= TRUE
;
305 gBS
->FreePool (OptionPtr
);
308 OptionSize
= sizeof (UINT32
) + sizeof (UINT16
) + StrSize (String
) + GetDevicePathSize (DevicePath
);
309 OptionPtr
= AllocateZeroPool (OptionSize
);
311 *(UINT32
*) TempPtr
= LOAD_OPTION_ACTIVE
;
312 TempPtr
+= sizeof (UINT32
);
313 *(UINT16
*) TempPtr
= (UINT16
) GetDevicePathSize (DevicePath
);
314 TempPtr
+= sizeof (UINT16
);
315 CopyMem (TempPtr
, String
, StrSize (String
));
316 TempPtr
+= StrSize (String
);
317 CopyMem (TempPtr
, DevicePath
, GetDevicePathSize (DevicePath
));
319 if (UpdateBootDevicePath
) {
321 // The number in option#### to be updated
323 RegisterOptionNumber
= TempOptionPtr
[Index
];
326 // The new option#### number
328 RegisterOptionNumber
= MaxOptionNumber
+ 1;
331 if (*VariableName
== 'B') {
332 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"Boot%04x", RegisterOptionNumber
);
334 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"Driver%04x", RegisterOptionNumber
);
337 Status
= gRT
->SetVariable (
339 &gEfiGlobalVariableGuid
,
340 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
344 if (EFI_ERROR (Status
) || UpdateBootDevicePath
) {
345 gBS
->FreePool (OptionPtr
);
346 gBS
->FreePool (TempOptionPtr
);
350 gBS
->FreePool (OptionPtr
);
353 // Update the option order variable
355 OptionOrderPtr
= AllocateZeroPool ((Index
+ 1) * sizeof (UINT16
));
356 CopyMem (OptionOrderPtr
, TempOptionPtr
, Index
* sizeof (UINT16
));
357 OptionOrderPtr
[Index
] = RegisterOptionNumber
;
358 Status
= gRT
->SetVariable (
360 &gEfiGlobalVariableGuid
,
361 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
362 (Index
+ 1) * sizeof (UINT16
),
365 if (EFI_ERROR (Status
)) {
366 gBS
->FreePool (TempOptionPtr
);
367 gBS
->FreePool (OptionOrderPtr
);
371 gBS
->FreePool (TempOptionPtr
);
372 gBS
->FreePool (OptionOrderPtr
);
378 BdsLibVariableToOption (
379 IN OUT LIST_ENTRY
*BdsCommonOptionList
,
380 IN CHAR16
*VariableName
386 Build the boot#### or driver#### option from the VariableName, the
387 build boot#### or driver#### will also be linked to BdsCommonOptionList
391 BdsCommonOptionList - The header of the boot#### or driver#### option link list
393 VariableName - EFI Variable name indicate if it is boot#### or driver####
397 BDS_COMMON_OPTION - Get the option just been created
399 NULL - Failed to get the new option
408 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
409 BDS_COMMON_OPTION
*Option
;
411 UINT32 LoadOptionsSize
;
415 // Read the variable. We will never free this data.
417 Variable
= BdsLibGetVariableAndSize (
419 &gEfiGlobalVariableGuid
,
422 if (Variable
== NULL
) {
426 // Notes: careful defined the variable of Boot#### or
427 // Driver####, consider use some macro to abstract the code
430 // Get the option attribute
433 Attribute
= *(UINT32
*) Variable
;
434 TempPtr
+= sizeof (UINT32
);
437 // Get the option's device path size
439 FilePathSize
= *(UINT16
*) TempPtr
;
440 TempPtr
+= sizeof (UINT16
);
443 // Get the option's description string
445 Description
= (CHAR16
*) TempPtr
;
448 // Get the option's description string size
450 TempPtr
+= StrSize ((CHAR16
*) TempPtr
);
453 // Get the option's device path
455 DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) TempPtr
;
456 TempPtr
+= FilePathSize
;
458 LoadOptions
= TempPtr
;
459 LoadOptionsSize
= (UINT32
) (VariableSize
- (UINTN
) (TempPtr
- Variable
));
462 // The Console variables may have multiple device paths, so make
463 // an Entry for each one.
465 Option
= AllocateZeroPool (sizeof (BDS_COMMON_OPTION
));
466 if (Option
== NULL
) {
470 Option
->Signature
= BDS_LOAD_OPTION_SIGNATURE
;
471 Option
->DevicePath
= AllocateZeroPool (GetDevicePathSize (DevicePath
));
472 CopyMem (Option
->DevicePath
, DevicePath
, GetDevicePathSize (DevicePath
));
473 Option
->Attribute
= Attribute
;
474 Option
->Description
= AllocateZeroPool (StrSize (Description
));
475 CopyMem (Option
->Description
, Description
, StrSize (Description
));
476 Option
->LoadOptions
= AllocateZeroPool (LoadOptionsSize
);
477 CopyMem (Option
->LoadOptions
, LoadOptions
, LoadOptionsSize
);
478 Option
->LoadOptionsSize
= LoadOptionsSize
;
481 // Insert active entry to BdsDeviceList
483 if ((Option
->Attribute
& LOAD_OPTION_ACTIVE
) == LOAD_OPTION_ACTIVE
) {
484 InsertTailList (BdsCommonOptionList
, &Option
->Link
);
485 gBS
->FreePool (Variable
);
489 gBS
->FreePool (Variable
);
490 gBS
->FreePool (Option
);
496 BdsLibBuildOptionFromVar (
497 IN LIST_ENTRY
*BdsCommonOptionList
,
498 IN CHAR16
*VariableName
504 Process BootOrder, or DriverOrder variables, by calling
505 BdsLibVariableToOption () for each UINT16 in the variables.
509 BdsCommonOptionList - The header of the option list base on variable
512 VariableName - EFI Variable name indicate the BootOrder or DriverOrder
516 EFI_SUCCESS - Success create the boot option or driver option list
518 EFI_OUT_OF_RESOURCES - Failed to get the boot option or driver option list
523 UINTN OptionOrderSize
;
525 BDS_COMMON_OPTION
*Option
;
526 CHAR16 OptionName
[20];
529 // Zero Buffer in order to get all BOOT#### variables
531 ZeroMem (OptionName
, sizeof (OptionName
));
534 // Read the BootOrder, or DriverOrder variable.
536 OptionOrder
= BdsLibGetVariableAndSize (
538 &gEfiGlobalVariableGuid
,
541 if (OptionOrder
== NULL
) {
542 return EFI_OUT_OF_RESOURCES
;
545 for (Index
= 0; Index
< OptionOrderSize
/ sizeof (UINT16
); Index
++) {
546 if (*VariableName
== 'B') {
547 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"Boot%04x", OptionOrder
[Index
]);
549 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"Driver%04x", OptionOrder
[Index
]);
551 Option
= BdsLibVariableToOption (BdsCommonOptionList
, OptionName
);
552 Option
->BootCurrent
= OptionOrder
[Index
];
556 gBS
->FreePool (OptionOrder
);
563 OUT EFI_BOOT_MODE
*BootMode
569 Get boot mode by looking up configuration table and parsing HOB list
573 BootMode - Boot mode from PEI handoff HOB.
577 EFI_SUCCESS - Successfully get boot mode
579 EFI_NOT_FOUND - Can not find the current system boot mode
583 EFI_HOB_HANDOFF_INFO_TABLE
*HobList
;
585 HobList
= GetHobList ();
586 ASSERT (HobList
->Header
.HobType
== EFI_HOB_TYPE_HANDOFF
);
587 *BootMode
= HobList
->BootMode
;
593 BdsLibGetVariableAndSize (
595 IN EFI_GUID
*VendorGuid
,
596 OUT UINTN
*VariableSize
602 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
603 buffer, and the size of the buffer. If failure return NULL.
607 Name - String part of EFI variable name
609 VendorGuid - GUID part of EFI variable name
611 VariableSize - Returns the size of the EFI variable that was read
615 Dynamically allocated memory that contains a copy of the EFI variable.
616 Caller is responsible freeing the buffer.
618 NULL - Variable was not read
629 // Pass in a zero size buffer to find the required buffer size.
632 Status
= gRT
->GetVariable (Name
, VendorGuid
, NULL
, &BufferSize
, Buffer
);
633 if (Status
== EFI_BUFFER_TOO_SMALL
) {
635 // Allocate the buffer to return
637 Buffer
= AllocateZeroPool (BufferSize
);
638 if (Buffer
== NULL
) {
642 // Read variable into the allocated buffer.
644 Status
= gRT
->GetVariable (Name
, VendorGuid
, NULL
, &BufferSize
, Buffer
);
645 if (EFI_ERROR (Status
)) {
650 *VariableSize
= BufferSize
;
655 BdsLibMatchDevicePaths (
656 IN EFI_DEVICE_PATH_PROTOCOL
*Multi
,
657 IN EFI_DEVICE_PATH_PROTOCOL
*Single
663 Function compares a device path data structure to that of all the nodes of a
664 second device path instance.
668 Multi - A pointer to a multi-instance device path data structure.
670 Single - A pointer to a single-instance device path data structure.
674 TRUE - If the Single is contained within Multi
676 FALSE - The Single is not match within Multi
681 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
682 EFI_DEVICE_PATH_PROTOCOL
*DevicePathInst
;
685 if (!Multi
|| !Single
) {
690 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
691 Size
-= sizeof (EFI_DEVICE_PATH_PROTOCOL
);
694 // Search for the match of 'Single' in 'Multi'
696 while (DevicePathInst
!= NULL
) {
698 // If the single device path is found in multiple device paths,
705 if (CompareMem (Single
, DevicePathInst
, Size
) == 0) {
709 gBS
->FreePool (DevicePathInst
);
710 DevicePathInst
= GetNextDevicePathInstance (&DevicePath
, &Size
);
711 Size
-= sizeof (EFI_DEVICE_PATH_PROTOCOL
);
718 BdsLibOutputStrings (
719 IN EFI_SIMPLE_TEXT_OUT_PROTOCOL
*ConOut
,
726 This function prints a series of strings.
730 ConOut - Pointer to EFI_SIMPLE_TEXT_OUT_PROTOCOL
732 ... - A variable argument list containing series of strings,
733 the last string must be NULL.
737 EFI_SUCCESS - Success print out the string using ConOut.
739 EFI_STATUS - Return the status of the ConOut->OutputString ().
747 Status
= EFI_SUCCESS
;
748 VA_START (args
, ConOut
);
750 while (!EFI_ERROR (Status
)) {
752 // If String is NULL, then it's the end of the list
754 String
= VA_ARG (args
, CHAR16
*);
759 Status
= ConOut
->OutputString (ConOut
, String
);
761 if (EFI_ERROR (Status
)) {
770 // Following are BDS Lib functions which contain all the code about setup browser reset reminder feature.
771 // Setup Browser reset reminder feature is that an reset reminder will be given before user leaves the setup browser if
772 // user change any option setting which needs a reset to be effective, and the reset will be applied according to the user selection.
776 EnableResetReminderFeature (
783 Enable the setup browser reset reminder feature.
784 This routine is used in platform tip. If the platform policy need the feature, use the routine to enable it.
796 mFeaturerSwitch
= TRUE
;
800 DisableResetReminderFeature (
807 Disable the setup browser reset reminder feature.
808 This routine is used in platform tip. If the platform policy do not want the feature, use the routine to disable it.
820 mFeaturerSwitch
= FALSE
;
824 EnableResetRequired (
831 Record the info that a reset is required.
832 A module boolean variable is used to record whether a reset is required.
844 mResetRequired
= TRUE
;
848 DisableResetRequired (
855 Record the info that no reset is required.
856 A module boolean variable is used to record whether a reset is required.
868 mResetRequired
= FALSE
;
872 IsResetReminderFeatureEnable (
879 Check whether platform policy enable the reset reminder feature. The default is enabled.
891 return mFeaturerSwitch
;
902 Check if user changed any option setting which needs a system reset to be effective.
914 return mResetRequired
;
925 Check whether a reset is needed, and finish the reset reminder feature.
926 If a reset is needed, Popup a menu to notice user, and finish the feature
927 according to the user selection.
940 EFI_FORM_BROWSER_PROTOCOL
*Browser
;
942 CHAR16
*StringBuffer1
;
943 CHAR16
*StringBuffer2
;
947 //check any reset required change is applied? if yes, reset system
949 if (IsResetReminderFeatureEnable ()) {
950 if (IsResetRequired ()) {
952 Status
= gBS
->LocateProtocol (
953 &gEfiFormBrowserProtocolGuid
,
958 StringBuffer1
= AllocateZeroPool (MAX_STRING_LEN
* sizeof (CHAR16
));
959 ASSERT (StringBuffer1
!= NULL
);
960 StringBuffer2
= AllocateZeroPool (MAX_STRING_LEN
* sizeof (CHAR16
));
961 ASSERT (StringBuffer2
!= NULL
);
962 StrCpy (StringBuffer1
, L
"Configuration changed. Reset to apply it Now ? ");
963 StrCpy (StringBuffer2
, L
"Enter (YES) / Esc (NO)");
965 // Popup a menu to notice user
968 Browser
->CreatePopUp (2, TRUE
, 0, NULL
, &Key
, StringBuffer1
, StringBuffer2
);
969 } while ((Key
.ScanCode
!= SCAN_ESC
) && (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
));
971 gBS
->FreePool (StringBuffer1
);
972 gBS
->FreePool (StringBuffer2
);
974 // If the user hits the YES Response key, reset
976 if ((Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
)) {
977 gRT
->ResetSystem (EfiResetCold
, EFI_SUCCESS
, 0, NULL
);
979 gST
->ConOut
->ClearScreen (gST
->ConOut
);