From c587fa4b280c7d2439729a8d4f20784e95d1c9cb Mon Sep 17 00:00:00 2001 From: xli24 Date: Fri, 8 Dec 2006 07:33:23 +0000 Subject: [PATCH 1/1] Support adding boot option from removable media, and removing invalid EFI boot option git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2078 6f19259b-4bc3-4df7-8a09-765794883524 --- EdkNt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c | 401 +++++++++++++++--- 1 file changed, 350 insertions(+), 51 deletions(-) diff --git a/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c b/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c index c9b1eede1c..05e1b26348 100644 --- a/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c +++ b/EdkNt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c @@ -120,6 +120,8 @@ Returns: EFI_DEVICE_PATH_PROTOCOL *FilePath; EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + VOID *Buffer; *ExitDataSize = 0; *ExitData = NULL; @@ -209,6 +211,32 @@ Returns: 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, @@ -429,6 +457,290 @@ Returns: 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 @@ -456,11 +768,8 @@ Returns: UINT16 BootOptionNumber; UINTN NumberFileSystemHandles; EFI_HANDLE *FileSystemHandles; - UINTN NumberBlkIoHandles; - EFI_HANDLE *BlkIoHandles; EFI_BLOCK_IO_PROTOCOL *BlkIo; UINTN Index; - EFI_DEVICE_PATH_PROTOCOL *DevicePath; UINTN NumberLoadFileHandles; EFI_HANDLE *LoadFileHandles; VOID *ProtocolInstance; @@ -471,6 +780,10 @@ Returns: 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; @@ -490,49 +803,11 @@ Returns: REFRESH_LEGACY_BOOT_OPTIONS; // - // Check all the block IO to create boot option + // Delete invalid boot option // - gBS->LocateHandleBuffer ( - ByProtocol, - &gEfiBlockIoProtocolGuid, - NULL, - &NumberBlkIoHandles, - &BlkIoHandles - ); - for (Index = 0; Index < NumberBlkIoHandles; Index++) { - Status = gBS->HandleProtocol ( - BlkIoHandles[Index], - &gEfiBlockIoProtocolGuid, - (VOID **) &BlkIo - ); - if (EFI_ERROR (Status)) { - continue; - } - - if (!BlkIo->Media->RemovableMedia) { - // - // Skip fixed Media device on first loop interration - // - continue; - } - - DevicePath = DevicePathFromHandle (BlkIoHandles[Index]); - if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && - (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP) - ) { - // - // Build the boot option - // - BdsLibBuildOptionFromHandle (BlkIoHandles[Index], BdsBootOptionList); - BootOptionNumber++; - } - } - - if (NumberBlkIoHandles) { - gBS->FreePool (BlkIoHandles); - } + BdsDeleteAllInvalidEfiBootOption (); // - // Parse Fixed Disk Devices. + // Parse removable media // gBS->LocateHandleBuffer ( ByProtocol, @@ -548,7 +823,7 @@ Returns: (VOID **) &BlkIo ); if (!EFI_ERROR (Status)) { - if (BlkIo->Media->RemovableMedia) { + if (!BlkIo->Media->RemovableMedia) { // // If the file system handle supports a BlkIo protocol, // skip the removable media devices @@ -557,14 +832,38 @@ Returns: } } - DevicePath = DevicePathFromHandle (FileSystemHandles[Index]); - if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && - (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP) - ) { + // + // 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) { // - // If the FileSystem protocol does not contain a BlkIo protocol, - // then build it + // No such file or the file is not a EFI application, delete this boot option // + BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]); + } else { BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList); BootOptionNumber++; } -- 2.39.2