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 BDS Lib functions which relate with create or process the boot
22 #include "Performance.h"
24 BOOLEAN mEnumBootDevice
= FALSE
;
28 IN BDS_COMMON_OPTION
*Option
34 Boot the legacy system with the boot option
38 Option - The legacy boot option which have BBS device path
42 EFI_UNSUPPORTED - There is no legacybios protocol, do not support
45 EFI_STATUS - Return the status of LegacyBios->LegacyBoot ().
50 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
52 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, &LegacyBios
);
53 if (EFI_ERROR (Status
)) {
55 // If no LegacyBios protocol we do not support legacy boot
57 return EFI_UNSUPPORTED
;
60 // Notes: if we seperate the int 19, then we don't need to refresh BBS
62 BdsRefreshBbsTableForBoot (Option
);
65 // Write boot to OS performance data to a file
68 WriteBootToOsPerformanceData ();
72 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Legacy Boot: %S\n", Option
->Description
));
73 return LegacyBios
->LegacyBoot (
75 (BBS_BBS_DEVICE_PATH
*) Option
->DevicePath
,
76 Option
->LoadOptionsSize
,
82 BdsLibBootViaBootOption (
83 IN BDS_COMMON_OPTION
* Option
,
84 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
85 OUT UINTN
*ExitDataSize
,
86 OUT CHAR16
**ExitData OPTIONAL
92 Process the boot option follow the EFI 1.1 specification and
93 special treat the legacy boot option with BBS_DEVICE_PATH.
97 Option - The boot option need to be processed
99 DevicePath - The device path which describe where to load
100 the boot image or the legcy BBS device path
101 to boot the legacy OS
103 ExitDataSize - Returned directly from gBS->StartImage ()
105 ExitData - Returned directly from gBS->StartImage ()
109 EFI_SUCCESS - Status from gBS->StartImage (),
110 or BdsBootByDiskSignatureAndPartition ()
112 EFI_NOT_FOUND - If the Device Path is not found in the system
118 EFI_HANDLE ImageHandle
;
119 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
120 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
121 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
122 EFI_ACPI_S3_SAVE_PROTOCOL
*AcpiS3Save
;
128 // Notes: put EFI64 ROM Shadow Solution
130 EFI64_SHADOW_ALL_LEGACY_ROM ();
133 // Notes: this code can be remove after the s3 script table
134 // hook on the event EFI_EVENT_SIGNAL_READY_TO_BOOT or
135 // EFI_EVENT_SIGNAL_LEGACY_BOOT
137 Status
= gBS
->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid
, NULL
, &AcpiS3Save
);
138 if (!EFI_ERROR (Status
)) {
139 AcpiS3Save
->S3Save (AcpiS3Save
, NULL
);
142 // If it's Device Path that starts with a hard drive path,
143 // this routine will do the booting.
145 Status
= BdsBootByDiskSignatureAndPartition (
147 (HARDDRIVE_DEVICE_PATH
*) DevicePath
,
148 Option
->LoadOptionsSize
,
153 if (!EFI_ERROR (Status
)) {
155 // If we found a disk signature and partition device path return success
160 EfiSignalEventReadyToBoot ();
167 &gEfiGlobalVariableGuid
,
168 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
173 if ((DevicePathType (Option
->DevicePath
) == BBS_DEVICE_PATH
) &&
174 (DevicePathSubType (Option
->DevicePath
) == BBS_BBS_DP
)
177 // Check to see if we should legacy BOOT. If yes then do the legacy boot
179 return BdsLibDoLegacyBoot (Option
);
182 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Booting EFI 1.1 way %S\n", Option
->Description
));
184 Status
= gBS
->LoadImage (
194 // If we didn't find an image, we may need to load the default
195 // boot behavior for the device.
197 if (EFI_ERROR (Status
)) {
199 // Find a Simple File System protocol on the device path. If the remaining
200 // device path is set to end then no Files are being specified, so try
201 // the removable media file name.
203 TempDevicePath
= DevicePath
;
204 Status
= gBS
->LocateDevicePath (
205 &gEfiSimpleFileSystemProtocolGuid
,
209 if (!EFI_ERROR (Status
) && IsDevicePathEnd (TempDevicePath
)) {
210 FilePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
212 Status
= gBS
->LoadImage (
220 if (EFI_ERROR (Status
)) {
222 // The DevicePath failed, and it's not a valid
223 // removable media device.
229 Status
= EFI_NOT_FOUND
;
233 if (EFI_ERROR (Status
)) {
235 // It there is any error from the Boot attempt exit now.
240 // Provide the image with it's load options
242 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, &ImageInfo
);
243 ASSERT_EFI_ERROR (Status
);
245 if (Option
->LoadOptionsSize
!= 0) {
246 ImageInfo
->LoadOptionsSize
= Option
->LoadOptionsSize
;
247 ImageInfo
->LoadOptions
= Option
->LoadOptions
;
250 // Before calling the image, enable the Watchdog Timer for
251 // the 5 Minute period
253 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
255 Status
= gBS
->StartImage (ImageHandle
, ExitDataSize
, ExitData
);
256 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Image Return Status = %r\n", Status
));
259 // Clear the Watchdog Timer after the image returns
261 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
265 // Clear Boot Current
269 &gEfiGlobalVariableGuid
,
270 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
279 BdsBootByDiskSignatureAndPartition (
280 IN BDS_COMMON_OPTION
* Option
,
281 IN HARDDRIVE_DEVICE_PATH
* HardDriveDevicePath
,
282 IN UINT32 LoadOptionsSize
,
283 IN VOID
*LoadOptions
,
284 OUT UINTN
*ExitDataSize
,
285 OUT CHAR16
**ExitData OPTIONAL
291 Check to see if a hard ware device path was passed in. If it was then search
292 all the block IO devices for the passed in hard drive device path.
296 Option - The current processing boot option.
298 HardDriveDevicePath - EFI Device Path to boot, if it starts with a hard
301 LoadOptionsSize - Passed into gBS->StartImage ()
302 via the loaded image protocol.
304 LoadOptions - Passed into gBS->StartImage ()
305 via the loaded image protocol.
307 ExitDataSize - returned directly from gBS->StartImage ()
309 ExitData - returned directly from gBS->StartImage ()
313 EFI_SUCCESS - Status from gBS->StartImage (),
314 or BootByDiskSignatureAndPartition ()
316 EFI_NOT_FOUND - If the Device Path is not found in the system
321 UINTN BlockIoHandleCount
;
322 EFI_HANDLE
*BlockIoBuffer
;
323 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
324 EFI_DEVICE_PATH_PROTOCOL
*BlockIoHdDevicePath
;
325 HARDDRIVE_DEVICE_PATH
*TmpHdPath
;
326 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
327 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
329 BOOLEAN DevicePathMatch
;
330 HARDDRIVE_DEVICE_PATH
*TempPath
;
335 if ( !((DevicePathType (&HardDriveDevicePath
->Header
) == MEDIA_DEVICE_PATH
) &&
336 (DevicePathSubType (&HardDriveDevicePath
->Header
) == MEDIA_HARDDRIVE_DP
))
339 // If the HardDriveDevicePath does not start with a Hard Drive Device Path
342 return EFI_NOT_FOUND
;
345 // The boot device have already been connected
347 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
348 if (EFI_ERROR (Status
) || BlockIoHandleCount
== 0) {
350 // If there was an error or there are no device handles that support
351 // the BLOCK_IO Protocol, then return.
353 return EFI_NOT_FOUND
;
356 // Loop through all the device handles that support the BLOCK_IO Protocol
358 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
360 Status
= gBS
->HandleProtocol (BlockIoBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*) &BlockIoDevicePath
);
361 if (EFI_ERROR (Status
) || BlockIoDevicePath
== NULL
) {
365 // Make PreviousDevicePath == the device path node before the end node
367 DevicePath
= BlockIoDevicePath
;
368 BlockIoHdDevicePath
= NULL
;
371 // find HardDriver device path node
373 while (!IsDevicePathEnd (DevicePath
)) {
374 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) &&
375 (DevicePathSubType (DevicePath
) == MEDIA_HARDDRIVE_DP
)
377 BlockIoHdDevicePath
= DevicePath
;
381 DevicePath
= NextDevicePathNode (DevicePath
);
384 if (BlockIoHdDevicePath
== NULL
) {
388 // See if the harddrive device path in blockio matches the orig Hard Drive Node
390 DevicePathMatch
= FALSE
;
392 TmpHdPath
= (HARDDRIVE_DEVICE_PATH
*) BlockIoHdDevicePath
;
393 TempPath
= (HARDDRIVE_DEVICE_PATH
*) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
396 // Only several fields will be checked. NOT whole NODE
398 if ( TmpHdPath
->PartitionNumber
== TempPath
->PartitionNumber
&&
399 TmpHdPath
->MBRType
== TempPath
->MBRType
&&
400 TmpHdPath
->SignatureType
== TempPath
->SignatureType
&&
401 CompareGuid ((EFI_GUID
*) TmpHdPath
->Signature
, (EFI_GUID
*) TempPath
->Signature
)) {
403 // Get the matched device path
405 DevicePathMatch
= TRUE
;
408 // Only do the boot, when devicepath match
410 if (DevicePathMatch
) {
412 // Combine the Block IO and Hard Drive Device path together and try
415 DevicePath
= NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
416 NewDevicePath
= AppendDevicePath (BlockIoDevicePath
, DevicePath
);
419 // Recursive boot with new device path
421 Status
= BdsLibBootViaBootOption (Option
, NewDevicePath
, ExitDataSize
, ExitData
);
422 if (!EFI_ERROR (Status
)) {
428 gBS
->FreePool (BlockIoBuffer
);
433 BdsLibEnumerateAllBootOption (
434 IN OUT LIST_ENTRY
*BdsBootOptionList
440 This function will enumerate all possible boot device in the system,
441 it will only excute once of every boot.
445 BdsBootOptionList - The header of the link list which indexed all
450 EFI_SUCCESS - Finished all the boot device enumerate and create
451 the boot option base on that boot device
456 UINT16 BootOptionNumber
;
457 UINTN NumberFileSystemHandles
;
458 EFI_HANDLE
*FileSystemHandles
;
459 UINTN NumberBlkIoHandles
;
460 EFI_HANDLE
*BlkIoHandles
;
461 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
463 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
464 UINTN NumberLoadFileHandles
;
465 EFI_HANDLE
*LoadFileHandles
;
466 VOID
*ProtocolInstance
;
467 EFI_FIRMWARE_VOLUME_PROTOCOL
*Fv
;
469 EFI_HANDLE
*FvHandleBuffer
;
470 EFI_FV_FILETYPE Type
;
472 EFI_FV_FILE_ATTRIBUTES Attributes
;
473 UINT32 AuthenticationStatus
;
475 BootOptionNumber
= 0;
478 // If the boot device enumerate happened, just get the boot
479 // device from the boot order variable
481 if (mEnumBootDevice
) {
482 BdsLibBuildOptionFromVar (BdsBootOptionList
, L
"BootOrder");
486 // Notes: this dirty code is to get the legacy boot option from the
487 // BBS table and create to variable as the EFI boot option, it should
488 // be removed after the CSM can provide legacy boot option directly
490 REFRESH_LEGACY_BOOT_OPTIONS
;
493 // Check all the block IO to create boot option
495 gBS
->LocateHandleBuffer (
497 &gEfiBlockIoProtocolGuid
,
502 for (Index
= 0; Index
< NumberBlkIoHandles
; Index
++) {
503 Status
= gBS
->HandleProtocol (
505 &gEfiBlockIoProtocolGuid
,
508 if (EFI_ERROR (Status
)) {
512 if (!BlkIo
->Media
->RemovableMedia
) {
514 // Skip fixed Media device on first loop interration
519 DevicePath
= DevicePathFromHandle (BlkIoHandles
[Index
]);
520 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) &&
521 (DevicePathSubType (DevicePath
) == MEDIA_HARDDRIVE_DP
)
524 // Build the boot option
526 BdsLibBuildOptionFromHandle (BlkIoHandles
[Index
], BdsBootOptionList
);
531 if (NumberBlkIoHandles
) {
532 gBS
->FreePool (BlkIoHandles
);
535 // Parse Fixed Disk Devices.
537 gBS
->LocateHandleBuffer (
539 &gEfiSimpleFileSystemProtocolGuid
,
541 &NumberFileSystemHandles
,
544 for (Index
= 0; Index
< NumberFileSystemHandles
; Index
++) {
545 Status
= gBS
->HandleProtocol (
546 FileSystemHandles
[Index
],
547 &gEfiBlockIoProtocolGuid
,
550 if (!EFI_ERROR (Status
)) {
551 if (BlkIo
->Media
->RemovableMedia
) {
553 // If the file system handle supports a BlkIo protocol,
554 // skip the removable media devices
560 DevicePath
= DevicePathFromHandle (FileSystemHandles
[Index
]);
561 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) &&
562 (DevicePathSubType (DevicePath
) == MEDIA_HARDDRIVE_DP
)
565 // If the FileSystem protocol does not contain a BlkIo protocol,
568 BdsLibBuildOptionFromHandle (FileSystemHandles
[Index
], BdsBootOptionList
);
573 if (NumberFileSystemHandles
) {
574 gBS
->FreePool (FileSystemHandles
);
577 // Parse Network Boot Device
579 gBS
->LocateHandleBuffer (
581 &gEfiSimpleNetworkProtocolGuid
,
583 &NumberLoadFileHandles
,
586 for (Index
= 0; Index
< NumberLoadFileHandles
; Index
++) {
587 Status
= gBS
->HandleProtocol (
588 LoadFileHandles
[Index
],
589 &gEfiLoadFileProtocolGuid
,
590 (VOID
**) &ProtocolInstance
592 if (EFI_ERROR (Status
)) {
596 BdsLibBuildOptionFromHandle (LoadFileHandles
[Index
], BdsBootOptionList
);
600 if (NumberLoadFileHandles
) {
601 gBS
->FreePool (LoadFileHandles
);
604 // Check if we have on flash shell
606 gBS
->LocateHandleBuffer (
608 &gEfiFirmwareVolumeProtocolGuid
,
613 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
614 gBS
->HandleProtocol (
615 FvHandleBuffer
[Index
],
616 &gEfiFirmwareVolumeProtocolGuid
,
620 Status
= Fv
->ReadFile (
627 &AuthenticationStatus
629 if (EFI_ERROR (Status
)) {
631 // Skip if no shell file in the FV
636 // Build the shell boot option
638 BdsLibBuildOptionFromShell (FvHandleBuffer
[Index
], BdsBootOptionList
);
643 gBS
->FreePool (FvHandleBuffer
);
646 // Make sure every boot only have one time
647 // boot device enumerate
649 BdsLibBuildOptionFromVar (BdsBootOptionList
, L
"BootOrder");
650 mEnumBootDevice
= TRUE
;
656 BdsLibBuildOptionFromHandle (
657 IN EFI_HANDLE Handle
,
658 IN LIST_ENTRY
*BdsBootOptionList
664 Build the boot option with the handle parsed in
668 Handle - The handle which present the device path to create boot option
670 BdsBootOptionList - The header of the link list which indexed all current
679 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
682 DevicePath
= DevicePathFromHandle (Handle
);
683 TempString
= DevicePathToStr (DevicePath
);
686 // Create and register new boot option
688 BdsLibRegisterNewOption (BdsBootOptionList
, DevicePath
, TempString
, L
"BootOrder");
692 BdsLibBuildOptionFromShell (
693 IN EFI_HANDLE Handle
,
694 IN OUT LIST_ENTRY
*BdsBootOptionList
700 Build the on flash shell boot option with the handle parsed in
704 Handle - The handle which present the device path to create on flash shell
707 BdsBootOptionList - The header of the link list which indexed all current
716 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
717 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode
;
719 DevicePath
= DevicePathFromHandle (Handle
);
722 // Build the shell device path
724 EfiInitializeFwVolDevicepathNode (&ShellNode
, &gEfiShellFileGuid
);
725 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*) &ShellNode
);
728 // Create and register the shell boot option
730 BdsLibRegisterNewOption (BdsBootOptionList
, DevicePath
, L
"Internal EFI Shell", L
"BootOrder");
742 Boot from the EFI1.1 spec defined "BootNext" variable
757 BDS_COMMON_OPTION
*BootOption
;
763 // Init the boot option name buffer and temp link list
765 InitializeListHead (&TempList
);
766 ZeroMem (Buffer
, sizeof (Buffer
));
768 BootNext
= BdsLibGetVariableAndSize (
770 &gEfiGlobalVariableGuid
,
775 // Clear the boot next variable first
777 if (BootNext
!= NULL
) {
780 &gEfiGlobalVariableGuid
,
781 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
787 // Start to build the boot option and try to boot
789 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", *BootNext
);
790 BootOption
= BdsLibVariableToOption (&TempList
, Buffer
);
791 BdsLibConnectDevicePath (BootOption
->DevicePath
);
792 BdsLibBootViaBootOption (BootOption
, BootOption
->DevicePath
, &ExitDataSize
, &ExitData
);