| /*++ | |
| Copyright (c) 2006, Intel Corporation | |
| All rights reserved. This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| Module Name: | |
| BdsBoot.c | |
| Abstract: | |
| BDS Lib functions which relate with create or process the boot | |
| option. | |
| --*/ | |
| #include "Performance.h" | |
| BOOLEAN mEnumBootDevice = FALSE; | |
| EFI_STATUS | |
| BdsLibDoLegacyBoot ( | |
| IN BDS_COMMON_OPTION *Option | |
| ) | |
| /*++ | |
| Routine Description: | |
| Boot the legacy system with the boot option | |
| Arguments: | |
| Option - The legacy boot option which have BBS device path | |
| Returns: | |
| EFI_UNSUPPORTED - There is no legacybios protocol, do not support | |
| legacy boot. | |
| EFI_STATUS - Return the status of LegacyBios->LegacyBoot (). | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; | |
| Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, | |
| (void **)&LegacyBios); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // If no LegacyBios protocol we do not support legacy boot | |
| // | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Notes: if we seperate the int 19, then we don't need to refresh BBS | |
| // | |
| BdsRefreshBbsTableForBoot (Option); | |
| // | |
| // Write boot to OS performance data to a file | |
| // | |
| PERF_CODE ( | |
| WriteBootToOsPerformanceData (); | |
| ); | |
| DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Legacy Boot: %S\n", Option->Description)); | |
| return LegacyBios->LegacyBoot ( | |
| LegacyBios, | |
| (BBS_BBS_DEVICE_PATH *) Option->DevicePath, | |
| Option->LoadOptionsSize, | |
| Option->LoadOptions | |
| ); | |
| } | |
| EFI_STATUS | |
| BdsLibBootViaBootOption ( | |
| IN BDS_COMMON_OPTION * Option, | |
| IN EFI_DEVICE_PATH_PROTOCOL * DevicePath, | |
| OUT UINTN *ExitDataSize, | |
| OUT CHAR16 **ExitData OPTIONAL | |
| ) | |
| /*++ | |
| Routine Description: | |
| Process the boot option follow the EFI 1.1 specification and | |
| special treat the legacy boot option with BBS_DEVICE_PATH. | |
| Arguments: | |
| Option - The boot option need to be processed | |
| DevicePath - The device path which describe where to load | |
| the boot image or the legcy BBS device path | |
| to boot the legacy OS | |
| ExitDataSize - Returned directly from gBS->StartImage () | |
| ExitData - Returned directly from gBS->StartImage () | |
| Returns: | |
| EFI_SUCCESS - Status from gBS->StartImage (), | |
| or BdsBootByDiskSignatureAndPartition () | |
| EFI_NOT_FOUND - If the Device Path is not found in the system | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| EFI_HANDLE Handle; | |
| EFI_HANDLE ImageHandle; | |
| EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *FilePath; | |
| EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; | |
| EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save; | |
| EFI_BLOCK_IO_PROTOCOL *BlkIo; | |
| VOID *Buffer; | |
| // | |
| // Record the performance data for End of BDS | |
| // | |
| PERF_END (0, BDS_TOK, NULL, 0); | |
| *ExitDataSize = 0; | |
| *ExitData = NULL; | |
| // | |
| // Notes: put EFI64 ROM Shadow Solution | |
| // | |
| EFI64_SHADOW_ALL_LEGACY_ROM (); | |
| // | |
| // Notes: this code can be remove after the s3 script table | |
| // hook on the event EFI_EVENT_SIGNAL_READY_TO_BOOT or | |
| // EFI_EVENT_SIGNAL_LEGACY_BOOT | |
| // | |
| Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, | |
| (VOID **)&AcpiS3Save); | |
| if (!EFI_ERROR (Status)) { | |
| AcpiS3Save->S3Save (AcpiS3Save, NULL); | |
| } | |
| // | |
| // If it's Device Path that starts with a hard drive path, | |
| // this routine will do the booting. | |
| // | |
| Status = BdsBootByDiskSignatureAndPartition ( | |
| Option, | |
| (HARDDRIVE_DEVICE_PATH *) DevicePath, | |
| Option->LoadOptionsSize, | |
| Option->LoadOptions, | |
| ExitDataSize, | |
| ExitData | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // If we found a disk signature and partition device path return success | |
| // | |
| return EFI_SUCCESS; | |
| } | |
| EfiSignalEventReadyToBoot (); | |
| // | |
| // Set Boot Current | |
| // | |
| gRT->SetVariable ( | |
| L"BootCurrent", | |
| &gEfiGlobalVariableGuid, | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, | |
| sizeof (UINT16), | |
| &Option->BootCurrent | |
| ); | |
| if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) && | |
| (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP) | |
| ) { | |
| // | |
| // Check to see if we should legacy BOOT. If yes then do the legacy boot | |
| // | |
| return BdsLibDoLegacyBoot (Option); | |
| } | |
| DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Booting EFI 1.1 way %S\n", Option->Description)); | |
| Status = gBS->LoadImage ( | |
| TRUE, | |
| mBdsImageHandle, | |
| DevicePath, | |
| NULL, | |
| 0, | |
| &ImageHandle | |
| ); | |
| // | |
| // If we didn't find an image, we may need to load the default | |
| // boot behavior for the device. | |
| // | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Find a Simple File System protocol on the device path. If the remaining | |
| // device path is set to end then no Files are being specified, so try | |
| // the removable media file name. | |
| // | |
| TempDevicePath = DevicePath; | |
| Status = gBS->LocateDevicePath ( | |
| &gEfiSimpleFileSystemProtocolGuid, | |
| &TempDevicePath, | |
| &Handle | |
| ); | |
| if (!EFI_ERROR (Status) && IsDevicePathEnd (TempDevicePath)) { | |
| FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME); | |
| if (FilePath) { | |
| // | |
| // Issue a dummy read to the device to check for media change. | |
| // When the removable media is changed, any Block IO read/write will | |
| // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is | |
| // returned. After the Block IO protocol is reinstalled, subsequent | |
| // Block IO read/write will success. | |
| // | |
| Status = gBS->HandleProtocol ( | |
| Handle, | |
| &gEfiBlockIoProtocolGuid, | |
| (VOID **) &BlkIo | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| Buffer = AllocatePool (BlkIo->Media->BlockSize); | |
| if (Buffer != NULL) { | |
| BlkIo->ReadBlocks ( | |
| BlkIo, | |
| BlkIo->Media->MediaId, | |
| 0, | |
| BlkIo->Media->BlockSize, | |
| Buffer | |
| ); | |
| gBS->FreePool (Buffer); | |
| } | |
| } | |
| Status = gBS->LoadImage ( | |
| TRUE, | |
| mBdsImageHandle, | |
| FilePath, | |
| NULL, | |
| 0, | |
| &ImageHandle | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // The DevicePath failed, and it's not a valid | |
| // removable media device. | |
| // | |
| goto Done; | |
| } | |
| } | |
| } else { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // It there is any error from the Boot attempt exit now. | |
| // | |
| goto Done; | |
| } | |
| // | |
| // Provide the image with it's load options | |
| // | |
| Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, | |
| (VOID **) &ImageInfo); | |
| ASSERT_EFI_ERROR (Status); | |
| if (Option->LoadOptionsSize != 0) { | |
| ImageInfo->LoadOptionsSize = Option->LoadOptionsSize; | |
| ImageInfo->LoadOptions = Option->LoadOptions; | |
| } | |
| // | |
| // Before calling the image, enable the Watchdog Timer for | |
| // the 5 Minute period | |
| // | |
| gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); | |
| Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData); | |
| DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Image Return Status = %r\n", Status)); | |
| // | |
| // Clear the Watchdog Timer after the image returns | |
| // | |
| gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); | |
| Done: | |
| // | |
| // Clear Boot Current | |
| // | |
| gRT->SetVariable ( | |
| L"BootCurrent", | |
| &gEfiGlobalVariableGuid, | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, | |
| 0, | |
| &Option->BootCurrent | |
| ); | |
| return Status; | |
| } | |
| EFI_STATUS | |
| BdsBootByDiskSignatureAndPartition ( | |
| IN BDS_COMMON_OPTION * Option, | |
| IN HARDDRIVE_DEVICE_PATH * HardDriveDevicePath, | |
| IN UINT32 LoadOptionsSize, | |
| IN VOID *LoadOptions, | |
| OUT UINTN *ExitDataSize, | |
| OUT CHAR16 **ExitData OPTIONAL | |
| ) | |
| /*++ | |
| Routine Description: | |
| Check to see if a hard ware device path was passed in. If it was then search | |
| all the block IO devices for the passed in hard drive device path. | |
| Arguments: | |
| Option - The current processing boot option. | |
| HardDriveDevicePath - EFI Device Path to boot, if it starts with a hard | |
| drive device path. | |
| LoadOptionsSize - Passed into gBS->StartImage () | |
| via the loaded image protocol. | |
| LoadOptions - Passed into gBS->StartImage () | |
| via the loaded image protocol. | |
| ExitDataSize - returned directly from gBS->StartImage () | |
| ExitData - returned directly from gBS->StartImage () | |
| Returns: | |
| EFI_SUCCESS - Status from gBS->StartImage (), | |
| or BootByDiskSignatureAndPartition () | |
| EFI_NOT_FOUND - If the Device Path is not found in the system | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| UINTN BlockIoHandleCount; | |
| EFI_HANDLE *BlockIoBuffer; | |
| EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePath; | |
| HARDDRIVE_DEVICE_PATH *TmpHdPath; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; | |
| UINTN Index; | |
| BOOLEAN DevicePathMatch; | |
| HARDDRIVE_DEVICE_PATH *TempPath; | |
| *ExitDataSize = 0; | |
| *ExitData = NULL; | |
| if ( !((DevicePathType (&HardDriveDevicePath->Header) == MEDIA_DEVICE_PATH) && | |
| (DevicePathSubType (&HardDriveDevicePath->Header) == MEDIA_HARDDRIVE_DP)) | |
| ) { | |
| // | |
| // If the HardDriveDevicePath does not start with a Hard Drive Device Path | |
| // exit. | |
| // | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // The boot device have already been connected | |
| // | |
| Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer); | |
| if (EFI_ERROR (Status) || BlockIoHandleCount == 0) { | |
| // | |
| // If there was an error or there are no device handles that support | |
| // the BLOCK_IO Protocol, then return. | |
| // | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // Loop through all the device handles that support the BLOCK_IO Protocol | |
| // | |
| for (Index = 0; Index < BlockIoHandleCount; Index++) { | |
| Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath); | |
| if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) { | |
| continue; | |
| } | |
| // | |
| // Make PreviousDevicePath == the device path node before the end node | |
| // | |
| DevicePath = BlockIoDevicePath; | |
| BlockIoHdDevicePath = NULL; | |
| // | |
| // find HardDriver device path node | |
| // | |
| while (!IsDevicePathEnd (DevicePath)) { | |
| if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && | |
| (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP) | |
| ) { | |
| BlockIoHdDevicePath = DevicePath; | |
| break; | |
| } | |
| DevicePath = NextDevicePathNode (DevicePath); | |
| } | |
| if (BlockIoHdDevicePath == NULL) { | |
| continue; | |
| } | |
| // | |
| // See if the harddrive device path in blockio matches the orig Hard Drive Node | |
| // | |
| DevicePathMatch = FALSE; | |
| TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePath; | |
| TempPath = (HARDDRIVE_DEVICE_PATH *) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath); | |
| // | |
| // Only several fields will be checked. NOT whole NODE | |
| // | |
| if ( TmpHdPath->PartitionNumber == TempPath->PartitionNumber && | |
| TmpHdPath->MBRType == TempPath->MBRType && | |
| TmpHdPath->SignatureType == TempPath->SignatureType && | |
| CompareGuid ((EFI_GUID *) TmpHdPath->Signature, (EFI_GUID *) TempPath->Signature)) { | |
| // | |
| // Get the matched device path | |
| // | |
| DevicePathMatch = TRUE; | |
| } | |
| // | |
| // Only do the boot, when devicepath match | |
| // | |
| if (DevicePathMatch) { | |
| // | |
| // Combine the Block IO and Hard Drive Device path together and try | |
| // to boot from it. | |
| // | |
| DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath); | |
| NewDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath); | |
| // | |
| // Recursive boot with new device path | |
| // | |
| Status = BdsLibBootViaBootOption (Option, NewDevicePath, ExitDataSize, ExitData); | |
| if (!EFI_ERROR (Status)) { | |
| break; | |
| } | |
| } | |
| } | |
| gBS->FreePool (BlockIoBuffer); | |
| return Status; | |
| } | |
| EFI_STATUS | |
| BdsLibDeleteOptionFromHandle ( | |
| IN EFI_HANDLE Handle | |
| ) | |
| /*++ | |
| Routine Description: | |
| Delete the boot option associated with the handle passed in | |
| Arguments: | |
| Handle - The handle which present the device path to create boot option | |
| Returns: | |
| EFI_SUCCESS - Delete the boot option success | |
| EFI_NOT_FOUND - If the Device Path is not found in the system | |
| EFI_OUT_OF_RESOURCES - Lack of memory resource | |
| Other - Error return value from SetVariable() | |
| --*/ | |
| { | |
| UINT16 *BootOrder; | |
| UINT8 *BootOptionVar; | |
| UINTN BootOrderSize; | |
| UINTN BootOptionSize; | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| UINT16 BootOption[BOOT_OPTION_MAX_CHAR]; | |
| UINTN DevicePathSize; | |
| UINTN OptionDevicePathSize; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath; | |
| UINT8 *TempPtr; | |
| CHAR16 *Description; | |
| Status = EFI_SUCCESS; | |
| BootOrder = NULL; | |
| BootOrderSize = 0; | |
| BootOrder = BdsLibGetVariableAndSize ( | |
| L"BootOrder", | |
| &gEfiGlobalVariableGuid, | |
| &BootOrderSize | |
| ); | |
| if (NULL == BootOrder) { | |
| return EFI_NOT_FOUND; | |
| } | |
| DevicePath = DevicePathFromHandle (Handle); | |
| if (DevicePath == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| DevicePathSize = GetDevicePathSize (DevicePath); | |
| Index = 0; | |
| while (Index < BootOrderSize / sizeof (UINT16)) { | |
| UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); | |
| BootOptionVar = BdsLibGetVariableAndSize ( | |
| BootOption, | |
| &gEfiGlobalVariableGuid, | |
| &BootOptionSize | |
| ); | |
| if (NULL == BootOptionVar) { | |
| gBS->FreePool (BootOrder); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| TempPtr = BootOptionVar; | |
| TempPtr += sizeof (UINT32) + sizeof (UINT16); | |
| Description = (CHAR16 *) TempPtr; | |
| TempPtr += StrSize ((CHAR16 *) TempPtr); | |
| OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; | |
| OptionDevicePathSize = GetDevicePathSize (OptionDevicePath); | |
| // | |
| // Check whether the device path match | |
| // | |
| if ((OptionDevicePathSize == DevicePathSize) && | |
| (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) { | |
| BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize); | |
| gBS->FreePool (BootOptionVar); | |
| break; | |
| } | |
| gBS->FreePool (BootOptionVar); | |
| Index++; | |
| } | |
| Status = gRT->SetVariable ( | |
| L"BootOrder", | |
| &gEfiGlobalVariableGuid, | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, | |
| BootOrderSize, | |
| BootOrder | |
| ); | |
| gBS->FreePool (BootOrder); | |
| return Status; | |
| } | |
| EFI_STATUS | |
| BdsDeleteAllInvalidEfiBootOption ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Delete all invalid EFI boot options. The probable invalid boot option could | |
| be Removable media or Network boot device. | |
| Arguments: | |
| VOID | |
| Returns: | |
| EFI_SUCCESS - Delete all invalid boot option success | |
| EFI_NOT_FOUND - Variable "BootOrder" is not found | |
| EFI_OUT_OF_RESOURCES - Lack of memory resource | |
| Other - Error return value from SetVariable() | |
| --*/ | |
| { | |
| UINT16 *BootOrder; | |
| UINT8 *BootOptionVar; | |
| UINTN BootOrderSize; | |
| UINTN BootOptionSize; | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| UINTN Index2; | |
| UINT16 BootOption[BOOT_OPTION_MAX_CHAR]; | |
| UINTN OptionDevicePathSize; | |
| EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode; | |
| EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath; | |
| UINT8 *TempPtr; | |
| CHAR16 *Description; | |
| EFI_HANDLE Handle; | |
| BOOLEAN NeedDelete; | |
| Status = EFI_SUCCESS; | |
| BootOrder = NULL; | |
| BootOrderSize = 0; | |
| BootOrder = BdsLibGetVariableAndSize ( | |
| L"BootOrder", | |
| &gEfiGlobalVariableGuid, | |
| &BootOrderSize | |
| ); | |
| if (NULL == BootOrder) { | |
| return EFI_NOT_FOUND; | |
| } | |
| Index = 0; | |
| while (Index < BootOrderSize / sizeof (UINT16)) { | |
| UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); | |
| BootOptionVar = BdsLibGetVariableAndSize ( | |
| BootOption, | |
| &gEfiGlobalVariableGuid, | |
| &BootOptionSize | |
| ); | |
| if (NULL == BootOptionVar) { | |
| gBS->FreePool (BootOrder); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| TempPtr = BootOptionVar; | |
| TempPtr += sizeof (UINT32) + sizeof (UINT16); | |
| Description = (CHAR16 *) TempPtr; | |
| TempPtr += StrSize ((CHAR16 *) TempPtr); | |
| OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; | |
| OptionDevicePathSize = GetDevicePathSize (OptionDevicePath); | |
| // | |
| // Skip legacy boot option (BBS boot device) | |
| // | |
| if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) && | |
| (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) { | |
| gBS->FreePool (BootOptionVar); | |
| Index++; | |
| continue; | |
| } | |
| TempDevicePath = OptionDevicePath; | |
| LastDeviceNode = OptionDevicePath; | |
| while (!EfiIsDevicePathEnd (TempDevicePath)) { | |
| LastDeviceNode = TempDevicePath; | |
| TempDevicePath = EfiNextDevicePathNode (TempDevicePath); | |
| } | |
| // | |
| // Skip the boot option that point to a file, since the device path in | |
| // removable media boot option doesn't contains a file name. | |
| // | |
| if (((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) && | |
| (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) || | |
| // | |
| // Skip boot option for internal Shell, it's always valid | |
| // | |
| (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL)) { | |
| gBS->FreePool (BootOptionVar); | |
| Index++; | |
| continue; | |
| } | |
| NeedDelete = TRUE; | |
| // | |
| // Check if it's a valid boot option for removable media | |
| // | |
| TempDevicePath = OptionDevicePath; | |
| Status = gBS->LocateDevicePath ( | |
| &gEfiSimpleFileSystemProtocolGuid, | |
| &TempDevicePath, | |
| &Handle | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| NeedDelete = FALSE; | |
| } | |
| // | |
| // Check if it's a valid boot option for network boot device | |
| // | |
| TempDevicePath = OptionDevicePath; | |
| Status = gBS->LocateDevicePath ( | |
| &gEfiLoadFileProtocolGuid, | |
| &TempDevicePath, | |
| &Handle | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| NeedDelete = FALSE; | |
| } | |
| if (NeedDelete) { | |
| // | |
| // Delete this invalid boot option "Boot####" | |
| // | |
| Status = gRT->SetVariable ( | |
| BootOption, | |
| &gEfiGlobalVariableGuid, | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, | |
| 0, | |
| NULL | |
| ); | |
| // | |
| // Mark this boot option in boot order as deleted | |
| // | |
| BootOrder[Index] = 0xffff; | |
| } | |
| gBS->FreePool (BootOptionVar); | |
| Index++; | |
| } | |
| // | |
| // Adjust boot order array | |
| // | |
| Index2 = 0; | |
| for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) { | |
| if (BootOrder[Index] != 0xffff) { | |
| BootOrder[Index2] = BootOrder[Index]; | |
| Index2 ++; | |
| } | |
| } | |
| Status = gRT->SetVariable ( | |
| L"BootOrder", | |
| &gEfiGlobalVariableGuid, | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, | |
| Index2 * sizeof (UINT16), | |
| BootOrder | |
| ); | |
| gBS->FreePool (BootOrder); | |
| return Status; | |
| } | |
| EFI_STATUS | |
| BdsLibEnumerateAllBootOption ( | |
| IN OUT LIST_ENTRY *BdsBootOptionList | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function will enumerate all possible boot device in the system, | |
| it will only excute once of every boot. | |
| Arguments: | |
| BdsBootOptionList - The header of the link list which indexed all | |
| current boot options | |
| Returns: | |
| EFI_SUCCESS - Finished all the boot device enumerate and create | |
| the boot option base on that boot device | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| UINT16 BootOptionNumber; | |
| UINTN NumberFileSystemHandles; | |
| EFI_HANDLE *FileSystemHandles; | |
| EFI_BLOCK_IO_PROTOCOL *BlkIo; | |
| UINTN Index; | |
| UINTN NumberLoadFileHandles; | |
| EFI_HANDLE *LoadFileHandles; | |
| VOID *ProtocolInstance; | |
| EFI_FIRMWARE_VOLUME_PROTOCOL *Fv; | |
| UINTN FvHandleCount; | |
| EFI_HANDLE *FvHandleBuffer; | |
| EFI_FV_FILETYPE Type; | |
| UINTN Size; | |
| EFI_FV_FILE_ATTRIBUTES Attributes; | |
| UINT32 AuthenticationStatus; | |
| EFI_DEVICE_PATH_PROTOCOL *FilePath; | |
| EFI_HANDLE ImageHandle; | |
| EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; | |
| BOOLEAN NeedDelete; | |
| BootOptionNumber = 0; | |
| // | |
| // If the boot device enumerate happened, just get the boot | |
| // device from the boot order variable | |
| // | |
| if (mEnumBootDevice) { | |
| BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder"); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Notes: this dirty code is to get the legacy boot option from the | |
| // BBS table and create to variable as the EFI boot option, it should | |
| // be removed after the CSM can provide legacy boot option directly | |
| // | |
| REFRESH_LEGACY_BOOT_OPTIONS; | |
| // | |
| // Delete invalid boot option | |
| // | |
| BdsDeleteAllInvalidEfiBootOption (); | |
| // | |
| // Parse removable media | |
| // | |
| gBS->LocateHandleBuffer ( | |
| ByProtocol, | |
| &gEfiSimpleFileSystemProtocolGuid, | |
| NULL, | |
| &NumberFileSystemHandles, | |
| &FileSystemHandles | |
| ); | |
| for (Index = 0; Index < NumberFileSystemHandles; Index++) { | |
| Status = gBS->HandleProtocol ( | |
| FileSystemHandles[Index], | |
| &gEfiBlockIoProtocolGuid, | |
| (VOID **) &BlkIo | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| if (!BlkIo->Media->RemovableMedia) { | |
| // | |
| // If the file system handle supports a BlkIo protocol, | |
| // skip the removable media devices | |
| // | |
| continue; | |
| } | |
| } | |
| // | |
| // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI | |
| // machinename is ia32, ia64, x64, ... | |
| // | |
| FilePath = FileDevicePath (FileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME); | |
| NeedDelete = TRUE; | |
| Status = gBS->LoadImage ( | |
| TRUE, | |
| mBdsImageHandle, | |
| FilePath, | |
| NULL, | |
| 0, | |
| &ImageHandle | |
| ); | |
| if (!EFI_ERROR(Status)) { | |
| // | |
| // Verify the image is a EFI application (and not a driver) | |
| // | |
| Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo); | |
| ASSERT (!EFI_ERROR(Status)); | |
| if (ImageInfo->ImageCodeType == EfiLoaderCode) { | |
| NeedDelete = FALSE; | |
| } | |
| } | |
| if (NeedDelete) { | |
| // | |
| // No such file or the file is not a EFI application, delete this boot option | |
| // | |
| BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]); | |
| } else { | |
| BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList); | |
| BootOptionNumber++; | |
| } | |
| } | |
| if (NumberFileSystemHandles) { | |
| gBS->FreePool (FileSystemHandles); | |
| } | |
| // | |
| // Parse Network Boot Device | |
| // | |
| gBS->LocateHandleBuffer ( | |
| ByProtocol, | |
| &gEfiSimpleNetworkProtocolGuid, | |
| NULL, | |
| &NumberLoadFileHandles, | |
| &LoadFileHandles | |
| ); | |
| for (Index = 0; Index < NumberLoadFileHandles; Index++) { | |
| Status = gBS->HandleProtocol ( | |
| LoadFileHandles[Index], | |
| &gEfiLoadFileProtocolGuid, | |
| (VOID **) &ProtocolInstance | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList); | |
| BootOptionNumber++; | |
| } | |
| if (NumberLoadFileHandles) { | |
| gBS->FreePool (LoadFileHandles); | |
| } | |
| // | |
| // Check if we have on flash shell | |
| // | |
| gBS->LocateHandleBuffer ( | |
| ByProtocol, | |
| &gEfiFirmwareVolumeProtocolGuid, | |
| NULL, | |
| &FvHandleCount, | |
| &FvHandleBuffer | |
| ); | |
| for (Index = 0; Index < FvHandleCount; Index++) { | |
| gBS->HandleProtocol ( | |
| FvHandleBuffer[Index], | |
| &gEfiFirmwareVolumeProtocolGuid, | |
| (VOID **) &Fv | |
| ); | |
| Status = Fv->ReadFile ( | |
| Fv, | |
| &gEfiShellFileGuid, | |
| NULL, | |
| &Size, | |
| &Type, | |
| &Attributes, | |
| &AuthenticationStatus | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Skip if no shell file in the FV | |
| // | |
| continue; | |
| } | |
| // | |
| // Build the shell boot option | |
| // | |
| BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList); | |
| BootOptionNumber++; | |
| } | |
| if (FvHandleCount) { | |
| gBS->FreePool (FvHandleBuffer); | |
| } | |
| // | |
| // Make sure every boot only have one time | |
| // boot device enumerate | |
| // | |
| BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder"); | |
| mEnumBootDevice = TRUE; | |
| return EFI_SUCCESS; | |
| } | |
| VOID | |
| BdsLibBuildOptionFromHandle ( | |
| IN EFI_HANDLE Handle, | |
| IN LIST_ENTRY *BdsBootOptionList | |
| ) | |
| /*++ | |
| Routine Description: | |
| Build the boot option with the handle parsed in | |
| Arguments: | |
| Handle - The handle which present the device path to create boot option | |
| BdsBootOptionList - The header of the link list which indexed all current | |
| boot options | |
| Returns: | |
| VOID | |
| --*/ | |
| { | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| CHAR16 *TempString; | |
| DevicePath = DevicePathFromHandle (Handle); | |
| TempString = DevicePathToStr (DevicePath); | |
| // | |
| // Create and register new boot option | |
| // | |
| BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, TempString, L"BootOrder"); | |
| } | |
| VOID | |
| BdsLibBuildOptionFromShell ( | |
| IN EFI_HANDLE Handle, | |
| IN OUT LIST_ENTRY *BdsBootOptionList | |
| ) | |
| /*++ | |
| Routine Description: | |
| Build the on flash shell boot option with the handle parsed in | |
| Arguments: | |
| Handle - The handle which present the device path to create on flash shell | |
| boot option | |
| BdsBootOptionList - The header of the link list which indexed all current | |
| boot options | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode; | |
| DevicePath = DevicePathFromHandle (Handle); | |
| // | |
| // Build the shell device path | |
| // | |
| EfiInitializeFwVolDevicepathNode (&ShellNode, &gEfiShellFileGuid); | |
| DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode); | |
| // | |
| // Create and register the shell boot option | |
| // | |
| BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"Internal EFI Shell", L"BootOrder"); | |
| } | |
| VOID | |
| BdsLibBootNext ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Boot from the EFI1.1 spec defined "BootNext" variable | |
| Arguments: | |
| None | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| UINT16 *BootNext; | |
| UINTN BootNextSize; | |
| CHAR16 Buffer[20]; | |
| BDS_COMMON_OPTION *BootOption; | |
| LIST_ENTRY TempList; | |
| UINTN ExitDataSize; | |
| CHAR16 *ExitData; | |
| // | |
| // Init the boot option name buffer and temp link list | |
| // | |
| InitializeListHead (&TempList); | |
| ZeroMem (Buffer, sizeof (Buffer)); | |
| BootNext = BdsLibGetVariableAndSize ( | |
| L"BootNext", | |
| &gEfiGlobalVariableGuid, | |
| &BootNextSize | |
| ); | |
| // | |
| // Clear the boot next variable first | |
| // | |
| if (BootNext != NULL) { | |
| gRT->SetVariable ( | |
| L"BootNext", | |
| &gEfiGlobalVariableGuid, | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, | |
| 0, | |
| BootNext | |
| ); | |
| // | |
| // Start to build the boot option and try to boot | |
| // | |
| UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext); | |
| BootOption = BdsLibVariableToOption (&TempList, Buffer); | |
| BdsLibConnectDevicePath (BootOption->DevicePath); | |
| BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData); | |
| } | |
| } |