X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FLibrary%2FUefiBootManagerLib%2FBmBoot.c;h=d6844823aa5519c72a182d033000ebd07fe744d4;hb=5e6e2dcc380dcd841f6f979fea8c302c80a87ec3;hp=fe09a041cf26ff22f8e806d3ce7937106d940494;hpb=7c69fbf20d409516c80355de9a40656ec55f5e21;p=mirror_edk2.git diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c index fe09a041cf..d6844823aa 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c @@ -1,7 +1,7 @@ /** @file Library functions which relates with booting. -Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.
(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -131,21 +131,16 @@ BmFindBootOptionInVariable ( } /** - Get the file buffer using a Memory Mapped Device Path. - + Return the correct FV file path. FV address may change across reboot. This routine promises the FV file device path is right. @param FilePath The Memory Mapped Device Path to get the file buffer. - @param FullPath Receive the updated FV Device Path pointint to the file. - @param FileSize Receive the file buffer size. - @return The file buffer. + @return The updated FV Device Path pointint to the file. **/ -VOID * -BmGetFileBufferByFvFilePath ( - IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, - OUT UINTN *FileSize +EFI_DEVICE_PATH_PROTOCOL * +BmAdjustFvFilePath ( + IN EFI_DEVICE_PATH_PROTOCOL *FilePath ) { EFI_STATUS Status; @@ -153,11 +148,10 @@ BmGetFileBufferByFvFilePath ( EFI_DEVICE_PATH_PROTOCOL *FvFileNode; EFI_HANDLE FvHandle; EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; - UINT32 AuthenticationStatus; UINTN FvHandleCount; EFI_HANDLE *FvHandles; EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; - VOID *FileBuffer; + EFI_DEVICE_PATH_PROTOCOL *FullPath; // // Get the file buffer by using the exactly FilePath. @@ -165,11 +159,7 @@ BmGetFileBufferByFvFilePath ( FvFileNode = FilePath; Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle); if (!EFI_ERROR (Status)) { - FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus); - if (FileBuffer != NULL) { - *FullPath = DuplicateDevicePath (FilePath); - } - return FileBuffer; + return DuplicateDevicePath (FilePath); } // @@ -190,11 +180,10 @@ BmGetFileBufferByFvFilePath ( (VOID **) &LoadedImage ); NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode); - FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize); + FullPath = BmAdjustFvFilePath (NewDevicePath); FreePool (NewDevicePath); - - if (FileBuffer != NULL) { - return FileBuffer; + if (FullPath != NULL) { + return FullPath; } // @@ -207,22 +196,25 @@ BmGetFileBufferByFvFilePath ( &FvHandleCount, &FvHandles ); - for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) { + for (Index = 0; Index < FvHandleCount; Index++) { if (FvHandles[Index] == LoadedImage->DeviceHandle) { // - // Skip current FV + // Skip current FV, it was handed in first step. // continue; } NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode); - FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize); + FullPath = BmAdjustFvFilePath (NewDevicePath); FreePool (NewDevicePath); + if (FullPath != NULL) { + break; + } } if (FvHandles != NULL) { FreePool (FvHandles); } - return FileBuffer; + return FullPath; } /** @@ -555,46 +547,64 @@ BmFindUsbDevice ( @param FilePath The device path pointing to a load option. It could be a short-form device path. - @param FullPath Return the full device path of the load option after - short-form device path expanding. - Caller is responsible to free it. - @param FileSize Return the load option size. + @param FullPath The full path returned by the routine in last call. + Set to NULL in first call. @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer. - @return The load option buffer. Caller is responsible to free the memory. + @return The next possible full path pointing to the load option. + Caller is responsible to free the memory. **/ -VOID * +EFI_DEVICE_PATH_PROTOCOL * BmExpandUsbDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, - OUT UINTN *FileSize, - IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode + IN EFI_DEVICE_PATH_PROTOCOL *FullPath, + IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode ) { UINTN ParentDevicePathSize; EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; - EFI_DEVICE_PATH_PROTOCOL *FullDevicePath; + EFI_DEVICE_PATH_PROTOCOL *NextFullPath; EFI_HANDLE *Handles; UINTN HandleCount; UINTN Index; - VOID *FileBuffer; + BOOLEAN GetNext; + NextFullPath = NULL; + GetNext = (BOOLEAN)(FullPath == NULL); ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath; RemainingDevicePath = NextDevicePathNode (ShortformNode); - FileBuffer = NULL; Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount); - for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) { - FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath); - FileBuffer = EfiBootManagerGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize); - FreePool (FullDevicePath); + for (Index = 0; Index < HandleCount; Index++) { + FilePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath); + if (FilePath == NULL) { + // + // Out of memory. + // + continue; + } + NextFullPath = BmGetNextLoadOptionDevicePath (FilePath, NULL); + FreePool (FilePath); + if (NextFullPath == NULL) { + // + // No BlockIo or SimpleFileSystem under FilePath. + // + continue; + } + if (GetNext) { + break; + } else { + GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0); + FreePool (NextFullPath); + NextFullPath = NULL; + } } if (Handles != NULL) { FreePool (Handles); } - return FileBuffer; + return NextFullPath; } /** @@ -602,18 +612,16 @@ BmExpandUsbDevicePath ( @param FilePath The device path pointing to a load option. It could be a short-form device path. - @param FullPath Return the full device path of the load option after - short-form device path expanding. - Caller is responsible to free it. - @param FileSize Return the load option size. + @param FullPath The full path returned by the routine in last call. + Set to NULL in first call. - @return The load option buffer. Caller is responsible to free the memory. + @return The next possible full path pointing to the load option. + Caller is responsible to free the memory. **/ -VOID * +EFI_DEVICE_PATH_PROTOCOL * BmExpandFileDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, - OUT UINTN *FileSize + IN EFI_DEVICE_PATH_PROTOCOL *FullPath ) { EFI_STATUS Status; @@ -622,9 +630,8 @@ BmExpandFileDevicePath ( EFI_HANDLE *Handles; EFI_BLOCK_IO_PROTOCOL *BlockIo; UINTN MediaType; - EFI_DEVICE_PATH_PROTOCOL *FullDevicePath; - VOID *FileBuffer; - UINT32 AuthenticationStatus; + EFI_DEVICE_PATH_PROTOCOL *NextFullPath; + BOOLEAN GetNext; EfiBootManagerConnectAll (); Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles); @@ -633,6 +640,8 @@ BmExpandFileDevicePath ( Handles = NULL; } + GetNext = (BOOLEAN)(FullPath == NULL); + NextFullPath = NULL; // // Enumerate all removable media devices followed by all fixed media devices, // followed by media devices which don't layer on block io. @@ -647,24 +656,26 @@ BmExpandFileDevicePath ( (MediaType == 1 && BlockIo != NULL && !BlockIo->Media->RemovableMedia) || (MediaType == 2 && BlockIo == NULL) ) { - FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath); - FileBuffer = GetFileBufferByFilePath (TRUE, FullDevicePath, FileSize, &AuthenticationStatus); - if (FileBuffer != NULL) { - *FullPath = FullDevicePath; - FreePool (Handles); - return FileBuffer; + NextFullPath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath); + if (GetNext) { + break; + } else { + GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0); + FreePool (NextFullPath); + NextFullPath = NULL; } - FreePool (FullDevicePath); } } + if (NextFullPath != NULL) { + break; + } } if (Handles != NULL) { FreePool (Handles); } - *FullPath = NULL; - return NULL; + return NextFullPath; } /** @@ -672,25 +683,25 @@ BmExpandFileDevicePath ( @param FilePath The device path pointing to a load option. It could be a short-form device path. - @param FullPath Return the full device path of the load option after - short-form device path expanding. - Caller is responsible to free it. - @param FileSize Return the load option size. + @param FullPath The full path returned by the routine in last call. + Set to NULL in first call. - @return The load option buffer. Caller is responsible to free the memory. + @return The next possible full path pointing to the load option. + Caller is responsible to free the memory. **/ -VOID * +EFI_DEVICE_PATH_PROTOCOL * BmExpandUriDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, - OUT UINTN *FileSize + IN EFI_DEVICE_PATH_PROTOCOL *FullPath ) { EFI_STATUS Status; UINTN Index; UINTN HandleCount; EFI_HANDLE *Handles; - VOID *FileBuffer; + EFI_DEVICE_PATH_PROTOCOL *NextFullPath; + EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath; + BOOLEAN GetNext; EfiBootManagerConnectAll (); Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles); @@ -699,11 +710,29 @@ BmExpandUriDevicePath ( Handles = NULL; } - FileBuffer = NULL; + NextFullPath = NULL; + GetNext = (BOOLEAN)(FullPath == NULL); for (Index = 0; Index < HandleCount; Index++) { - FileBuffer = BmGetFileBufferFromLoadFile (Handles[Index], FilePath, FullPath, FileSize); - if (FileBuffer != NULL) { + NextFullPath = BmExpandLoadFile (Handles[Index], FilePath); + + if (NextFullPath == NULL) { + continue; + } + + if (GetNext) { break; + } else { + GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0); + // + // Free the resource occupied by the RAM disk. + // + RamDiskDevicePath = BmGetRamDiskDevicePath (NextFullPath); + if (RamDiskDevicePath != NULL) { + BmDestroyRamDisk (RamDiskDevicePath); + FreePool (RamDiskDevicePath); + } + FreePool (NextFullPath); + NextFullPath = NULL; } } @@ -711,7 +740,7 @@ BmExpandUriDevicePath ( FreePool (Handles); } - return FileBuffer; + return NextFullPath; } /** @@ -781,35 +810,28 @@ BmCachePartitionDevicePath ( @param FilePath The device path pointing to a load option. It could be a short-form device path. - @param FullPath Return the full device path of the load option after - short-form device path expanding. - Caller is responsible to free it. - @param FileSize Return the load option size. - @return The load option buffer. Caller is responsible to free the memory. + @return The full device path pointing to the load option. **/ -VOID * +EFI_DEVICE_PATH_PROTOCOL * BmExpandPartitionDevicePath ( - IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, - OUT UINTN *FileSize + IN EFI_DEVICE_PATH_PROTOCOL *FilePath ) { EFI_STATUS Status; UINTN BlockIoHandleCount; EFI_HANDLE *BlockIoBuffer; - VOID *FileBuffer; EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath; UINTN Index; EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath; EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath; EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + EFI_DEVICE_PATH_PROTOCOL *FullPath; UINTN CachedDevicePathSize; BOOLEAN NeedAdjust; EFI_DEVICE_PATH_PROTOCOL *Instance; UINTN Size; - FileBuffer = NULL; // // Check if there is prestore 'HDDP' variable. // If exist, search the front path which point to partition node in the variable instants. @@ -833,6 +855,7 @@ BmExpandPartitionDevicePath ( ASSERT_EFI_ERROR (Status); } + FullPath = NULL; if (CachedDevicePath != NULL) { TempNewDevicePath = CachedDevicePath; NeedAdjust = FALSE; @@ -851,10 +874,20 @@ BmExpandPartitionDevicePath ( Status = EfiBootManagerConnectDevicePath (Instance, NULL); if (!EFI_ERROR (Status)) { TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath)); - FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize); + // + // TempDevicePath = ACPI()/PCI()/ATA()/Partition() + // or = ACPI()/PCI()/ATA()/Partition()/.../A.EFI + // + // When TempDevicePath = ACPI()/PCI()/ATA()/Partition(), + // it may expand to two potienal full paths (nested partition, rarely happen): + // 1. ACPI()/PCI()/ATA()/Partition()/Partition(A1)/EFI/BootX64.EFI + // 2. ACPI()/PCI()/ATA()/Partition()/Partition(A2)/EFI/BootX64.EFI + // For simplicity, only #1 is returned. + // + FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath, NULL); FreePool (TempDevicePath); - if (FileBuffer != NULL) { + if (FullPath != NULL) { // // Adjust the 'HDDP' instances sequence if the matched one is not first one. // @@ -875,7 +908,7 @@ BmExpandPartitionDevicePath ( FreePool (Instance); FreePool (CachedDevicePath); - return FileBuffer; + return FullPath; } } } @@ -911,10 +944,10 @@ BmExpandPartitionDevicePath ( // Find the matched partition device path // TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath)); - FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize); + FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath, NULL); FreePool (TempDevicePath); - if (FileBuffer != NULL) { + if (FullPath != NULL) { BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath); // @@ -940,7 +973,7 @@ BmExpandPartitionDevicePath ( if (BlockIoBuffer != NULL) { FreePool (BlockIoBuffer); } - return FileBuffer; + return FullPath; } /** @@ -948,16 +981,16 @@ BmExpandPartitionDevicePath ( by appending EFI_REMOVABLE_MEDIA_FILE_NAME. @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance. - @param FullPath Return the full device path pointing to the load option. - @param FileSize Return the size of the load option. + @param FullPath The full path returned by the routine in last call. + Set to NULL in first call. - @return The load option buffer. + @return The next possible full path pointing to the load option. + Caller is responsible to free the memory. **/ -VOID * +EFI_DEVICE_PATH_PROTOCOL * BmExpandMediaDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, - OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, - OUT UINTN *FileSize + IN EFI_DEVICE_PATH_PROTOCOL *FullPath ) { EFI_STATUS Status; @@ -965,14 +998,15 @@ BmExpandMediaDevicePath ( EFI_BLOCK_IO_PROTOCOL *BlockIo; VOID *Buffer; EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + EFI_DEVICE_PATH_PROTOCOL *NextFullPath; UINTN Size; UINTN TempSize; EFI_HANDLE *SimpleFileSystemHandles; UINTN NumberSimpleFileSystemHandles; UINTN Index; - VOID *FileBuffer; - UINT32 AuthenticationStatus; + BOOLEAN GetNext; + GetNext = (BOOLEAN)(FullPath == NULL); // // Check whether the device is connected // @@ -981,19 +1015,25 @@ BmExpandMediaDevicePath ( if (!EFI_ERROR (Status)) { ASSERT (IsDevicePathEnd (TempDevicePath)); - TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME); - FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus); - if (FileBuffer == NULL) { - FreePool (TempDevicePath); - TempDevicePath = NULL; + NextFullPath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME); + // + // For device path pointing to simple file system, it only expands to one full path. + // + if (GetNext) { + return NextFullPath; + } else { + FreePool (NextFullPath); + return NULL; } - *FullPath = TempDevicePath; - return FileBuffer; } + Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle); + ASSERT_EFI_ERROR (Status); + // - // For device boot option only pointing to the removable device handle, - // should make sure all its children handles (its child partion or media handles) are created and connected. + // For device boot option only pointing to the removable device handle, + // should make sure all its children handles (its child partion or media handles) + // are created and connected. // gBS->ConnectController (Handle, NULL, NULL, TRUE); @@ -1004,8 +1044,6 @@ BmExpandMediaDevicePath ( // returned. After the Block IO protocol is reinstalled, subsequent // Block IO read/write will success. // - Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle); - ASSERT_EFI_ERROR (Status); Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo); ASSERT_EFI_ERROR (Status); Buffer = AllocatePool (BlockIo->Media->BlockSize); @@ -1023,8 +1061,7 @@ BmExpandMediaDevicePath ( // // Detect the the default boot file from removable Media // - FileBuffer = NULL; - *FullPath = NULL; + NextFullPath = NULL; Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH; gBS->LocateHandleBuffer ( ByProtocol, @@ -1043,13 +1080,14 @@ BmExpandMediaDevicePath ( // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path // if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) { - TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME); - FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus); - if (FileBuffer != NULL) { - *FullPath = TempDevicePath; + NextFullPath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME); + if (GetNext) { break; + } else { + GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0); + FreePool (NextFullPath); + NextFullPath = NULL; } - FreePool (TempDevicePath); } } @@ -1057,7 +1095,7 @@ BmExpandMediaDevicePath ( FreePool (SimpleFileSystemHandles); } - return FileBuffer; + return NextFullPath; } /** @@ -1096,17 +1134,14 @@ BmMatchHttpBootDevicePath ( Get the file buffer from the file system produced by Load File instance. @param LoadFileHandle The handle of LoadFile instance. - @param FullPath Return the full device path pointing to the load option. - @param FileSize Return the size of the load option. @param RamDiskHandle Return the RAM Disk handle. - @return The load option buffer. + @return The next possible full path pointing to the load option. + Caller is responsible to free the memory. **/ -VOID * -BmGetFileBufferFromLoadFileSystem ( +EFI_DEVICE_PATH_PROTOCOL * +BmExpandNetworkFileSystem ( IN EFI_HANDLE LoadFileHandle, - OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, - OUT UINTN *FileSize, OUT EFI_HANDLE *RamDiskHandle ) { @@ -1136,6 +1171,9 @@ BmGetFileBufferFromLoadFileSystem ( if (!EFI_ERROR (Status) && (Handle == LoadFileHandle) && (DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) { + // + // Find the BlockIo instance populated from the LoadFile. + // Handle = Handles[Index]; break; } @@ -1152,13 +1190,16 @@ BmGetFileBufferFromLoadFileSystem ( *RamDiskHandle = Handle; if (Handle != NULL) { - return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), FullPath, FileSize); + // + // Re-use BmExpandMediaDevicePath() to get the full device path of load option. + // But assume only one SimpleFileSystem can be found under the BlockIo. + // + return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), NULL); } else { return NULL; } } - /** Return the RAM Disk device path created by LoadFile. @@ -1272,27 +1313,21 @@ BmDestroyRamDisk ( @param LoadFileHandle The specified Load File instance. @param FilePath The file path which will pass to LoadFile(). - @param FullPath Return the full device path pointing to the load option. - @param FileSize Return the size of the load option. - @return The load option buffer or NULL if fails. + @return The full device path pointing to the load option buffer. **/ -VOID * -BmGetFileBufferFromLoadFile ( +EFI_DEVICE_PATH_PROTOCOL * +BmExpandLoadFile ( IN EFI_HANDLE LoadFileHandle, - IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, - OUT UINTN *FileSize + IN EFI_DEVICE_PATH_PROTOCOL *FilePath ) { EFI_STATUS Status; EFI_LOAD_FILE_PROTOCOL *LoadFile; VOID *FileBuffer; - BOOLEAN LoadFileSystem; EFI_HANDLE RamDiskHandle; UINTN BufferSize; - - *FileSize = 0; + EFI_DEVICE_PATH_PROTOCOL *FullPath; Status = gBS->OpenProtocol ( LoadFileHandle, @@ -1311,52 +1346,60 @@ BmGetFileBufferFromLoadFile ( return NULL; } - LoadFileSystem = (BOOLEAN) (Status == EFI_WARN_FILE_SYSTEM); - FileBuffer = LoadFileSystem ? AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize)) : AllocatePool (BufferSize); + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // The load option buffer is directly returned by LoadFile. + // + return DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle)); + } + + // + // The load option resides in a RAM disk. + // + FileBuffer = AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize)); if (FileBuffer == NULL) { return NULL; } Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer); if (EFI_ERROR (Status)) { - if (LoadFileSystem) { - FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize)); - } else { - FreePool (FileBuffer); - } + FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize)); return NULL; } - if (LoadFileSystem) { - FileBuffer = BmGetFileBufferFromLoadFileSystem (LoadFileHandle, FullPath, FileSize, &RamDiskHandle); - if (FileBuffer == NULL) { - // - // If there is no bootable executable in the populated - // - BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle)); - } - } else { - *FileSize = BufferSize; - *FullPath = DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle)); + FullPath = BmExpandNetworkFileSystem (LoadFileHandle, &RamDiskHandle); + if (FullPath == NULL) { + // + // Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance. + // + BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle)); } - return FileBuffer; + return FullPath; } /** - Get the file buffer from all the Load File instances. + Return the full device path pointing to the load option. + + FilePath may: + 1. Exactly matches to a LoadFile instance. + 2. Cannot match to any LoadFile instance. Wide match is required. + In either case, the routine may return: + 1. A copy of FilePath when FilePath matches to a LoadFile instance and + the LoadFile returns a load option buffer. + 2. A new device path with IP and URI information updated when wide match + happens. + 3. A new device path pointing to a load option in RAM disk. + In either case, only one full device path is returned for a specified + FilePath. @param FilePath The media device path pointing to a LoadFile instance. - @param FullPath Return the full device path pointing to the load option. - @param FileSize Return the size of the load option. @return The load option buffer. **/ -VOID * -BmGetFileBufferFromLoadFiles ( - IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, - OUT UINTN *FileSize +EFI_DEVICE_PATH_PROTOCOL * +BmExpandLoadFiles ( + IN EFI_DEVICE_PATH_PROTOCOL *FilePath ) { EFI_STATUS Status; @@ -1409,7 +1452,7 @@ BmGetFileBufferFromLoadFiles ( return NULL; } - return BmGetFileBufferFromLoadFile (Handle, FilePath, FullPath, FileSize); + return BmExpandLoadFile (Handle, FilePath); } /** @@ -1431,20 +1474,38 @@ EfiBootManagerGetLoadOptionBuffer ( OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, OUT UINTN *FileSize ) +{ + *FullPath = NULL; + + EfiBootManagerConnectDevicePath (FilePath, NULL); + return BmGetNextLoadOptionBuffer (LoadOptionTypeMax, FilePath, FullPath, FileSize); +} + +/** + Get the next possible full path pointing to the load option. + The routine doesn't guarantee the returned full path points to an existing + file, and it also doesn't guarantee the existing file is a valid load option. + BmGetNextLoadOptionBuffer() guarantees. + + @param FilePath The device path pointing to a load option. + It could be a short-form device path. + @param FullPath The full path returned by the routine in last call. + Set to NULL in first call. + + @return The next possible full path pointing to the load option. + Caller is responsible to free the memory. +**/ +EFI_DEVICE_PATH_PROTOCOL * +BmGetNextLoadOptionDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN EFI_DEVICE_PATH_PROTOCOL *FullPath + ) { EFI_HANDLE Handle; - VOID *FileBuffer; - UINT32 AuthenticationStatus; EFI_DEVICE_PATH_PROTOCOL *Node; EFI_STATUS Status; - ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL)); - - EfiBootManagerConnectDevicePath (FilePath, NULL); - - *FullPath = NULL; - *FileSize = 0; - FileBuffer = NULL; + ASSERT (FilePath != NULL); // // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI @@ -1456,7 +1517,7 @@ EfiBootManagerGetLoadOptionBuffer ( } if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) { - return BmExpandMediaDevicePath (FilePath, FullPath, FileSize); + return BmExpandMediaDevicePath (FilePath, FullPath); } // @@ -1467,66 +1528,84 @@ EfiBootManagerGetLoadOptionBuffer ( // // Expand the Harddrive device path // - return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize); + if (FullPath == NULL) { + return BmExpandPartitionDevicePath (FilePath); + } else { + return NULL; + } } else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) { // // Expand the File-path device path // - return BmExpandFileDevicePath (FilePath, FullPath, FileSize); + return BmExpandFileDevicePath (FilePath, FullPath); } else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (FilePath) == MSG_URI_DP)) { // // Expand the URI device path // - return BmExpandUriDevicePath (FilePath, FullPath, FileSize); + return BmExpandUriDevicePath (FilePath, FullPath); } else { - for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) { - if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && - ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) { - break; + Node = FilePath; + Status = gBS->LocateDevicePath (&gEfiUsbIoProtocolGuid, &Node, &Handle); + if (EFI_ERROR (Status)) { + // + // Only expand the USB WWID/Class device path + // when FilePath doesn't point to a physical UsbIo controller. + // Otherwise, infinite recursion will happen. + // + for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) { + if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && + ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) { + break; + } } - } - if (!IsDevicePathEnd (Node)) { // // Expand the USB WWID/Class device path // - FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node); - if ((FileBuffer == NULL) && (FilePath == Node)) { - // - // Boot Option device path starts with USB Class or USB WWID device path. - // For Boot Option device path which doesn't begin with the USB Class or - // USB WWID device path, it's not needed to connect again here. - // - BmConnectUsbShortFormDevicePath (FilePath); - FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node); + if (!IsDevicePathEnd (Node)) { + if (FilePath == Node) { + // + // Boot Option device path starts with USB Class or USB WWID device path. + // For Boot Option device path which doesn't begin with the USB Class or + // USB WWID device path, it's not needed to connect again here. + // + BmConnectUsbShortFormDevicePath (FilePath); + } + return BmExpandUsbDevicePath (FilePath, FullPath, Node); } - return FileBuffer; } } // - // Get file buffer from FV file path. + // For the below cases, FilePath only expands to one Full path. + // So just handle the case when FullPath == NULL. + // + if (FullPath != NULL) { + return NULL; + } + + // + // Load option resides in FV. // if (BmIsFvFilePath (FilePath)) { - return BmGetFileBufferByFvFilePath (FilePath, FullPath, FileSize); + return BmAdjustFvFilePath (FilePath); } // - // Get file buffer from simple file system. + // Load option resides in Simple File System. // Node = FilePath; Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle); if (!EFI_ERROR (Status)) { - FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus); - if (FileBuffer != NULL) { - *FullPath = DuplicateDevicePath (FilePath); - } - return FileBuffer; + return DuplicateDevicePath (FilePath); } - return BmGetFileBufferFromLoadFiles (FilePath, FullPath, FileSize); + // + // Last chance to try: Load option may be loaded through LoadFile. + // + return BmExpandLoadFiles (FilePath); } /** @@ -1684,21 +1763,13 @@ EfiBootManagerBoot ( ImageHandle = NULL; RamDiskDevicePath = NULL; if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) { - Status = EFI_NOT_FOUND; - FileBuffer = EfiBootManagerGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize); + Status = EFI_NOT_FOUND; + FilePath = NULL; + EfiBootManagerConnectDevicePath (BootOption->FilePath, NULL); + FileBuffer = BmGetNextLoadOptionBuffer (LoadOptionTypeBoot, BootOption->FilePath, &FilePath, &FileSize); if (FileBuffer != NULL) { RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath); - } - DEBUG_CODE ( - if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) { - DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: ")); - BmPrintDp (BootOption->FilePath); - DEBUG ((EFI_D_INFO, " -> ")); - BmPrintDp (FilePath); - DEBUG ((EFI_D_INFO, "\n")); - } - ); - if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) { + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad)); Status = gBS->LoadImage ( TRUE, @@ -1940,7 +2011,6 @@ BmEnumerateBootOptions ( UINTN Removable; UINTN Index; CHAR16 *Description; - UINT32 BootAttributes; ASSERT (BootOptionCount != NULL); @@ -2070,6 +2140,12 @@ BmEnumerateBootOptions ( &Handles ); for (Index = 0; Index < HandleCount; Index++) { + // + // Ignore BootManagerMenu. its boot option will be created by EfiBootManagerGetBootManagerMenu(). + // + if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) { + continue; + } Description = BmGetBootDescription (Handles[Index]); BootOptions = ReallocatePool ( @@ -2079,19 +2155,11 @@ BmEnumerateBootOptions ( ); ASSERT (BootOptions != NULL); - // - // If LoadFile includes BootManagerMenu, its boot attribue will be set to APP and HIDDEN. - // - BootAttributes = LOAD_OPTION_ACTIVE; - if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) { - BootAttributes = LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN; - } - Status = EfiBootManagerInitializeLoadOption ( &BootOptions[(*BootOptionCount)++], LoadOptionNumberUnassigned, LoadOptionTypeBoot, - BootAttributes, + LOAD_OPTION_ACTIVE, Description, DevicePathFromHandle (Handles[Index]), NULL, @@ -2155,7 +2223,7 @@ EfiBootManagerRefreshAllBootOption ( // Only check those added by BDS // so that the boot options added by end-user or OS installer won't be deleted // - if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) { + if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == -1) { Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot); // // Deleting variable with current variable implementation shouldn't fail. @@ -2169,7 +2237,7 @@ EfiBootManagerRefreshAllBootOption ( // Add new EFI boot options to NV // for (Index = 0; Index < BootOptionCount; Index++) { - if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) { + if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == -1) { EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1); // // Try best to add the boot options so continue upon failure.