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,
53 (void **)&LegacyBios);
54 if (EFI_ERROR (Status)) {
56 // If no LegacyBios protocol we do not support legacy boot
58 return EFI_UNSUPPORTED;
61 // Notes: if we seperate the int 19, then we don't need to refresh BBS
63 BdsRefreshBbsTableForBoot (Option);
66 // Write boot to OS performance data to a file
69 WriteBootToOsPerformanceData ();
73 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Legacy Boot: %S\n", Option->Description));
74 return LegacyBios->LegacyBoot (
76 (BBS_BBS_DEVICE_PATH *) Option->DevicePath,
77 Option->LoadOptionsSize,
83 BdsLibBootViaBootOption (
84 IN BDS_COMMON_OPTION * Option,
85 IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,
86 OUT UINTN *ExitDataSize,
87 OUT CHAR16 **ExitData OPTIONAL
93 Process the boot option follow the EFI 1.1 specification and
94 special treat the legacy boot option with BBS_DEVICE_PATH.
98 Option - The boot option need to be processed
100 DevicePath - The device path which describe where to load
101 the boot image or the legcy BBS device path
102 to boot the legacy OS
104 ExitDataSize - Returned directly from gBS->StartImage ()
106 ExitData - Returned directly from gBS->StartImage ()
110 EFI_SUCCESS - Status from gBS->StartImage (),
111 or BdsBootByDiskSignatureAndPartition ()
113 EFI_NOT_FOUND - If the Device Path is not found in the system
119 EFI_HANDLE ImageHandle;
120 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
121 EFI_DEVICE_PATH_PROTOCOL *FilePath;
122 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
123 EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
129 // Notes: put EFI64 ROM Shadow Solution
131 EFI64_SHADOW_ALL_LEGACY_ROM ();
134 // Notes: this code can be remove after the s3 script table
135 // hook on the event EFI_EVENT_SIGNAL_READY_TO_BOOT or
136 // EFI_EVENT_SIGNAL_LEGACY_BOOT
138 Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL,
139 (VOID **)&AcpiS3Save);
140 if (!EFI_ERROR (Status)) {
141 AcpiS3Save->S3Save (AcpiS3Save, NULL);
144 // If it's Device Path that starts with a hard drive path,
145 // this routine will do the booting.
147 Status = BdsBootByDiskSignatureAndPartition (
149 (HARDDRIVE_DEVICE_PATH *) DevicePath,
150 Option->LoadOptionsSize,
155 if (!EFI_ERROR (Status)) {
157 // If we found a disk signature and partition device path return success
162 EfiSignalEventReadyToBoot ();
169 &gEfiGlobalVariableGuid,
170 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
175 if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
176 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
179 // Check to see if we should legacy BOOT. If yes then do the legacy boot
181 return BdsLibDoLegacyBoot (Option);
184 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Booting EFI 1.1 way %S\n", Option->Description));
186 Status = gBS->LoadImage (
196 // If we didn't find an image, we may need to load the default
197 // boot behavior for the device.
199 if (EFI_ERROR (Status)) {
201 // Find a Simple File System protocol on the device path. If the remaining
202 // device path is set to end then no Files are being specified, so try
203 // the removable media file name.
205 TempDevicePath = DevicePath;
206 Status = gBS->LocateDevicePath (
207 &gEfiSimpleFileSystemProtocolGuid,
211 if (!EFI_ERROR (Status) && IsDevicePathEnd (TempDevicePath)) {
212 FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
214 Status = gBS->LoadImage (
222 if (EFI_ERROR (Status)) {
224 // The DevicePath failed, and it's not a valid
225 // removable media device.
231 Status = EFI_NOT_FOUND;
235 if (EFI_ERROR (Status)) {
237 // It there is any error from the Boot attempt exit now.
242 // Provide the image with it's load options
244 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid,
245 (VOID **) &ImageInfo);
246 ASSERT_EFI_ERROR (Status);
248 if (Option->LoadOptionsSize != 0) {
249 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
250 ImageInfo->LoadOptions = Option->LoadOptions;
253 // Before calling the image, enable the Watchdog Timer for
254 // the 5 Minute period
256 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
258 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
259 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Image Return Status = %r\n", Status));
262 // Clear the Watchdog Timer after the image returns
264 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
268 // Clear Boot Current
272 &gEfiGlobalVariableGuid,
273 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
282 BdsBootByDiskSignatureAndPartition (
283 IN BDS_COMMON_OPTION * Option,
284 IN HARDDRIVE_DEVICE_PATH * HardDriveDevicePath,
285 IN UINT32 LoadOptionsSize,
286 IN VOID *LoadOptions,
287 OUT UINTN *ExitDataSize,
288 OUT CHAR16 **ExitData OPTIONAL
294 Check to see if a hard ware device path was passed in. If it was then search
295 all the block IO devices for the passed in hard drive device path.
299 Option - The current processing boot option.
301 HardDriveDevicePath - EFI Device Path to boot, if it starts with a hard
304 LoadOptionsSize - Passed into gBS->StartImage ()
305 via the loaded image protocol.
307 LoadOptions - Passed into gBS->StartImage ()
308 via the loaded image protocol.
310 ExitDataSize - returned directly from gBS->StartImage ()
312 ExitData - returned directly from gBS->StartImage ()
316 EFI_SUCCESS - Status from gBS->StartImage (),
317 or BootByDiskSignatureAndPartition ()
319 EFI_NOT_FOUND - If the Device Path is not found in the system
324 UINTN BlockIoHandleCount;
325 EFI_HANDLE *BlockIoBuffer;
326 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
327 EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePath;
328 HARDDRIVE_DEVICE_PATH *TmpHdPath;
329 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
330 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
332 BOOLEAN DevicePathMatch;
333 HARDDRIVE_DEVICE_PATH *TempPath;
338 if ( !((DevicePathType (&HardDriveDevicePath->Header) == MEDIA_DEVICE_PATH) &&
339 (DevicePathSubType (&HardDriveDevicePath->Header) == MEDIA_HARDDRIVE_DP))
342 // If the HardDriveDevicePath does not start with a Hard Drive Device Path
345 return EFI_NOT_FOUND;
348 // The boot device have already been connected
350 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
351 if (EFI_ERROR (Status) || BlockIoHandleCount == 0) {
353 // If there was an error or there are no device handles that support
354 // the BLOCK_IO Protocol, then return.
356 return EFI_NOT_FOUND;
359 // Loop through all the device handles that support the BLOCK_IO Protocol
361 for (Index = 0; Index < BlockIoHandleCount; Index++) {
363 Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
364 if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
368 // Make PreviousDevicePath == the device path node before the end node
370 DevicePath = BlockIoDevicePath;
371 BlockIoHdDevicePath = NULL;
374 // find HardDriver device path node
376 while (!IsDevicePathEnd (DevicePath)) {
377 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
378 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
380 BlockIoHdDevicePath = DevicePath;
384 DevicePath = NextDevicePathNode (DevicePath);
387 if (BlockIoHdDevicePath == NULL) {
391 // See if the harddrive device path in blockio matches the orig Hard Drive Node
393 DevicePathMatch = FALSE;
395 TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePath;
396 TempPath = (HARDDRIVE_DEVICE_PATH *) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
399 // Only several fields will be checked. NOT whole NODE
401 if ( TmpHdPath->PartitionNumber == TempPath->PartitionNumber &&
402 TmpHdPath->MBRType == TempPath->MBRType &&
403 TmpHdPath->SignatureType == TempPath->SignatureType &&
404 CompareGuid ((EFI_GUID *) TmpHdPath->Signature, (EFI_GUID *) TempPath->Signature)) {
406 // Get the matched device path
408 DevicePathMatch = TRUE;
411 // Only do the boot, when devicepath match
413 if (DevicePathMatch) {
415 // Combine the Block IO and Hard Drive Device path together and try
418 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
419 NewDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
422 // Recursive boot with new device path
424 Status = BdsLibBootViaBootOption (Option, NewDevicePath, ExitDataSize, ExitData);
425 if (!EFI_ERROR (Status)) {
431 gBS->FreePool (BlockIoBuffer);
436 BdsLibEnumerateAllBootOption (
437 IN OUT LIST_ENTRY *BdsBootOptionList
443 This function will enumerate all possible boot device in the system,
444 it will only excute once of every boot.
448 BdsBootOptionList - The header of the link list which indexed all
453 EFI_SUCCESS - Finished all the boot device enumerate and create
454 the boot option base on that boot device
459 UINT16 BootOptionNumber;
460 UINTN NumberFileSystemHandles;
461 EFI_HANDLE *FileSystemHandles;
462 UINTN NumberBlkIoHandles;
463 EFI_HANDLE *BlkIoHandles;
464 EFI_BLOCK_IO_PROTOCOL *BlkIo;
466 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
467 UINTN NumberLoadFileHandles;
468 EFI_HANDLE *LoadFileHandles;
469 VOID *ProtocolInstance;
470 EFI_FIRMWARE_VOLUME_PROTOCOL *Fv;
472 EFI_HANDLE *FvHandleBuffer;
473 EFI_FV_FILETYPE Type;
475 EFI_FV_FILE_ATTRIBUTES Attributes;
476 UINT32 AuthenticationStatus;
478 BootOptionNumber = 0;
481 // If the boot device enumerate happened, just get the boot
482 // device from the boot order variable
484 if (mEnumBootDevice) {
485 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
489 // Notes: this dirty code is to get the legacy boot option from the
490 // BBS table and create to variable as the EFI boot option, it should
491 // be removed after the CSM can provide legacy boot option directly
493 REFRESH_LEGACY_BOOT_OPTIONS;
496 // Check all the block IO to create boot option
498 gBS->LocateHandleBuffer (
500 &gEfiBlockIoProtocolGuid,
505 for (Index = 0; Index < NumberBlkIoHandles; Index++) {
506 Status = gBS->HandleProtocol (
508 &gEfiBlockIoProtocolGuid,
511 if (EFI_ERROR (Status)) {
515 if (!BlkIo->Media->RemovableMedia) {
517 // Skip fixed Media device on first loop interration
522 DevicePath = DevicePathFromHandle (BlkIoHandles[Index]);
523 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
524 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
527 // Build the boot option
529 BdsLibBuildOptionFromHandle (BlkIoHandles[Index], BdsBootOptionList);
534 if (NumberBlkIoHandles) {
535 gBS->FreePool (BlkIoHandles);
538 // Parse Fixed Disk Devices.
540 gBS->LocateHandleBuffer (
542 &gEfiSimpleFileSystemProtocolGuid,
544 &NumberFileSystemHandles,
547 for (Index = 0; Index < NumberFileSystemHandles; Index++) {
548 Status = gBS->HandleProtocol (
549 FileSystemHandles[Index],
550 &gEfiBlockIoProtocolGuid,
553 if (!EFI_ERROR (Status)) {
554 if (BlkIo->Media->RemovableMedia) {
556 // If the file system handle supports a BlkIo protocol,
557 // skip the removable media devices
563 DevicePath = DevicePathFromHandle (FileSystemHandles[Index]);
564 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
565 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
568 // If the FileSystem protocol does not contain a BlkIo protocol,
571 BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList);
576 if (NumberFileSystemHandles) {
577 gBS->FreePool (FileSystemHandles);
580 // Parse Network Boot Device
582 gBS->LocateHandleBuffer (
584 &gEfiSimpleNetworkProtocolGuid,
586 &NumberLoadFileHandles,
589 for (Index = 0; Index < NumberLoadFileHandles; Index++) {
590 Status = gBS->HandleProtocol (
591 LoadFileHandles[Index],
592 &gEfiLoadFileProtocolGuid,
593 (VOID **) &ProtocolInstance
595 if (EFI_ERROR (Status)) {
599 BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList);
603 if (NumberLoadFileHandles) {
604 gBS->FreePool (LoadFileHandles);
607 // Check if we have on flash shell
609 gBS->LocateHandleBuffer (
611 &gEfiFirmwareVolumeProtocolGuid,
616 for (Index = 0; Index < FvHandleCount; Index++) {
617 gBS->HandleProtocol (
618 FvHandleBuffer[Index],
619 &gEfiFirmwareVolumeProtocolGuid,
623 Status = Fv->ReadFile (
630 &AuthenticationStatus
632 if (EFI_ERROR (Status)) {
634 // Skip if no shell file in the FV
639 // Build the shell boot option
641 BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);
646 gBS->FreePool (FvHandleBuffer);
649 // Make sure every boot only have one time
650 // boot device enumerate
652 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
653 mEnumBootDevice = TRUE;
659 BdsLibBuildOptionFromHandle (
660 IN EFI_HANDLE Handle,
661 IN LIST_ENTRY *BdsBootOptionList
667 Build the boot option with the handle parsed in
671 Handle - The handle which present the device path to create boot option
673 BdsBootOptionList - The header of the link list which indexed all current
682 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
685 DevicePath = DevicePathFromHandle (Handle);
686 TempString = DevicePathToStr (DevicePath);
689 // Create and register new boot option
691 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, TempString, L"BootOrder");
695 BdsLibBuildOptionFromShell (
696 IN EFI_HANDLE Handle,
697 IN OUT LIST_ENTRY *BdsBootOptionList
703 Build the on flash shell boot option with the handle parsed in
707 Handle - The handle which present the device path to create on flash shell
710 BdsBootOptionList - The header of the link list which indexed all current
719 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
720 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
722 DevicePath = DevicePathFromHandle (Handle);
725 // Build the shell device path
727 EfiInitializeFwVolDevicepathNode (&ShellNode, &gEfiShellFileGuid);
728 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);
731 // Create and register the shell boot option
733 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"Internal EFI Shell", L"BootOrder");
745 Boot from the EFI1.1 spec defined "BootNext" variable
760 BDS_COMMON_OPTION *BootOption;
766 // Init the boot option name buffer and temp link list
768 InitializeListHead (&TempList);
769 ZeroMem (Buffer, sizeof (Buffer));
771 BootNext = BdsLibGetVariableAndSize (
773 &gEfiGlobalVariableGuid,
778 // Clear the boot next variable first
780 if (BootNext != NULL) {
783 &gEfiGlobalVariableGuid,
784 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
790 // Start to build the boot option and try to boot
792 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);
793 BootOption = BdsLibVariableToOption (&TempList, Buffer);
794 BdsLibConnectDevicePath (BootOption->DevicePath);
795 BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);