diff options
-rw-r--r-- | MdeModulePkg/Include/Library/UefiBootManagerLib.h | 46 | ||||
-rw-r--r-- | MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c | 814 | ||||
-rw-r--r-- | MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c | 23 | ||||
-rw-r--r-- | MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c | 30 | ||||
-rw-r--r-- | MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c | 776 | ||||
-rw-r--r-- | MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c | 159 | ||||
-rw-r--r-- | MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h | 83 | ||||
-rw-r--r-- | MdeModulePkg/Universal/BdsDxe/BdsEntry.c | 216 |
8 files changed, 1140 insertions, 1007 deletions
diff --git a/MdeModulePkg/Include/Library/UefiBootManagerLib.h b/MdeModulePkg/Include/Library/UefiBootManagerLib.h index 9b08364aaf..2ec80894ad 100644 --- a/MdeModulePkg/Include/Library/UefiBootManagerLib.h +++ b/MdeModulePkg/Include/Library/UefiBootManagerLib.h @@ -27,8 +27,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // Load Option Type // typedef enum { - LoadOptionTypeBoot, LoadOptionTypeDriver, + LoadOptionTypeSysPrep, + LoadOptionTypeBoot, LoadOptionTypeMax } EFI_BOOT_MANAGER_LOAD_OPTION_TYPE; @@ -51,6 +52,7 @@ typedef struct { EFI_DEVICE_PATH_PROTOCOL *FilePath; // Load Option Device Path UINT8 *OptionalData; // Load Option optional data to pass into image UINT32 OptionalDataSize; // Load Option size of OptionalData + EFI_GUID VendorGuid; // // Used at runtime @@ -172,11 +174,11 @@ EfiBootManagerLoadOptionToVariable ( ); /** - This function will update the Boot####/Driver#### and the BootOrder/DriverOrder - to add a new load option. + This function will update the Boot####/Driver####/SysPrep#### and the + BootOrder/DriverOrder/SysPrepOrder to add a new load option. @param Option Pointer to load option to add. - @param Position Position of the new load option to put in the BootOrder/DriverOrder. + @param Position Position of the new load option to put in the BootOrder/DriverOrder/SysPrepOrder. @retval EFI_SUCCESS The load option has been successfully added. @retval Others Error status returned by RT->SetVariable. @@ -458,17 +460,20 @@ EfiBootManagerConnectAll ( /** This function will create all handles associate with every device path node. If the handle associate with one device path node can not - be created successfully, then still give one chance to do the dispatch, + be created successfully, then still give chance to do the dispatch, which load the missing drivers if possible. - @param DevicePathToConnect The device path which will be connected, it CANNOT be + @param DevicePathToConnect The device path which will be connected, it can be a multi-instance device path @param MatchingHandle Return the controller handle closest to the DevicePathToConnect - @retval EFI_INVALID_PARAMETER DevicePathToConnect is NULL. - @retval EFI_NOT_FOUND Failed to create all handles associate with every device path node. - @retval EFI_SUCCESS Successful to create all handles associate with every device path node. - + @retval EFI_SUCCESS All handles associate with every device path node + have been created. + @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles. + @retval EFI_NOT_FOUND Create the handle associate with one device path + node failed. + @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device + drivers on the DevicePath. **/ EFI_STATUS EFIAPI @@ -508,8 +513,12 @@ typedef enum { /** This function will connect all the console devices base on the console device variable ConIn, ConOut and ErrOut. + + @retval EFI_DEVICE_ERROR All the consoles were not connected due to an error. + @retval EFI_SUCCESS Success connect any one instance of the console + device path base on the variable ConVarName. **/ -VOID +EFI_STATUS EFIAPI EfiBootManagerConnectAllDefaultConsoles ( VOID @@ -654,4 +663,19 @@ EfiBootManagerFreeDriverHealthInfo ( UINTN Count ); +/** + Process (load and execute) the load option. + + @param LoadOption Pointer to the load option. + + @retval EFI_INVALID_PARAMETER The load option type is invalid, + or the load option file path doesn't point to a valid file. + @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot. + @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed. +**/ +EFI_STATUS +EFIAPI +EfiBootManagerProcessLoadOption ( + EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption + ); #endif diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c index ddda9ae605..8d1a8c9d23 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c @@ -71,7 +71,7 @@ EfiBootManagerRegisterLegacyBootSupport ( **/ BM_BOOT_TYPE -BmBootTypeFromDevicePath ( +BmDevicePathType ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { @@ -145,22 +145,6 @@ BmBootTypeFromDevicePath ( } /** - Free old buffer and reuse the pointer to return new buffer. - - @param Orig Pointer to the old buffer. - @param New Pointer to the new buffer. -**/ -VOID -BmFreeAndSet ( - VOID **Orig, - VOID *New - ) -{ - FreePool (*Orig); - *Orig = New; -} - -/** Find the boot option in the NV storage and return the option number. @param OptionToFind Boot option to be checked. @@ -176,7 +160,7 @@ BmFindBootOptionInVariable ( EFI_STATUS Status; EFI_BOOT_MANAGER_LOAD_OPTION BootOption; UINTN OptionNumber; - CHAR16 OptionName[sizeof ("Boot####")]; + CHAR16 OptionName[BM_OPTION_NAME_LEN]; EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; UINTN BootOptionCount; UINTN Index; @@ -187,7 +171,10 @@ BmFindBootOptionInVariable ( // Try to match the variable exactly if the option number is assigned // if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) { - UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionToFind->OptionNumber); + UnicodeSPrint ( + OptionName, sizeof (OptionName), L"%s%04x", + mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber + ); Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption); if (!EFI_ERROR (Status)) { @@ -222,56 +209,45 @@ BmFindBootOptionInVariable ( } /** - According to a file guild, check a Fv file device path is valid. If it is invalid, - try to return the valid device path. - FV address maybe changes for memory layout adjust from time to time, use this function - could promise the Fv file device path is right. + Get the file buffer using a Memory Mapped Device Path. + + FV address may change across reboot. This routine promises the FV file device path is right. - @param DevicePath The Fv file device path to be fixed up. + @param DevicePath 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. **/ -VOID -BmFixupMemmapFvFilePath ( - IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath +VOID * +BmGetFileBufferByMemmapFv ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, + OUT UINTN *FileSize ) { EFI_STATUS Status; UINTN Index; - EFI_DEVICE_PATH_PROTOCOL *Node; + EFI_DEVICE_PATH_PROTOCOL *FvFileNode; EFI_HANDLE FvHandle; - EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; - UINTN Size; - EFI_FV_FILETYPE Type; - EFI_FV_FILE_ATTRIBUTES Attributes; UINT32 AuthenticationStatus; UINTN FvHandleCount; - EFI_HANDLE *FvHandleBuffer; + EFI_HANDLE *FvHandles; EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + VOID *FileBuffer; - Node = *DevicePath; - Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle); + FvFileNode = DevicePath; + Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle); if (!EFI_ERROR (Status)) { - Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &Fv); - ASSERT_EFI_ERROR (Status); - - Status = Fv->ReadFile ( - Fv, - EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node), - NULL, - &Size, - &Type, - &Attributes, - &AuthenticationStatus - ); - if (EFI_ERROR (Status)) { - BmFreeAndSet ((VOID **) DevicePath, NULL); + FileBuffer = GetFileBufferByFilePath (TRUE, DevicePath, FileSize, &AuthenticationStatus); + if (FileBuffer != NULL) { + *FullPath = DuplicateDevicePath (DevicePath); } - return; + return FileBuffer; } - - Node = NextDevicePathNode (DevicePath); + FvFileNode = NextDevicePathNode (DevicePath); // // Firstly find the FV file in current FV @@ -281,12 +257,12 @@ BmFixupMemmapFvFilePath ( &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage ); - NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), Node); - BmFixupMemmapFvFilePath (&NewDevicePath); + NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode); + FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize); + FreePool (NewDevicePath); - if (NewDevicePath != NULL) { - BmFreeAndSet ((VOID **) DevicePath, NewDevicePath); - return; + if (FileBuffer != NULL) { + return FileBuffer; } // @@ -297,34 +273,35 @@ BmFixupMemmapFvFilePath ( &gEfiFirmwareVolume2ProtocolGuid, NULL, &FvHandleCount, - &FvHandleBuffer + &FvHandles ); - for (Index = 0; Index < FvHandleCount; Index++) { - if (FvHandleBuffer[Index] == LoadedImage->DeviceHandle) { + for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) { + if (FvHandles[Index] == LoadedImage->DeviceHandle) { // // Skip current FV // continue; } - NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandleBuffer[Index]), Node); - BmFixupMemmapFvFilePath (&NewDevicePath); - - if (NewDevicePath != NULL) { - BmFreeAndSet ((VOID **) DevicePath, NewDevicePath); - return; - } + NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode); + FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize); + FreePool (NewDevicePath); } + + if (FvHandles != NULL) { + FreePool (FvHandles); + } + return FileBuffer; } /** - Check if it's of Fv file device path type. + Check if it's a Memory Mapped FV Device Path. - The function doesn't garentee the device path points to existing Fv file. + The function doesn't garentee the device path points to existing FV file. - @param DevicePath Input device path info. + @param DevicePath Input device path. - @retval TRUE The device path is of Fv file device path type. - @retval FALSE The device path isn't of Fv file device path type. + @retval TRUE The device path is a Memory Mapped FV Device Path. + @retval FALSE The device path is NOT a Memory Mapped FV Device Path. **/ BOOLEAN BmIsMemmapFvFilePath ( @@ -668,7 +645,7 @@ BmGetMiscDescription ( CHAR16 *Description; EFI_BLOCK_IO_PROTOCOL *BlockIo; - switch (BmBootTypeFromDevicePath (DevicePathFromHandle (Handle))) { + switch (BmDevicePathType (DevicePathFromHandle (Handle))) { case BmAcpiFloppyBoot: Description = L"Floppy"; break; @@ -825,26 +802,6 @@ BmMatchUsbWwid ( } /** - Print the device path info. - - @param DevicePath The device path need to print. - -**/ -VOID -BmPrintDp ( - EFI_DEVICE_PATH_PROTOCOL *DevicePath - ) -{ - CHAR16 *Str; - - Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE); - DEBUG ((EFI_D_INFO, "%s", Str)); - if (Str != NULL) { - FreePool (Str); - } -} - -/** Find a USB device which match the specified short-form device path start with USB Class or USB WWID device path. If ParentDevicePath is NULL, this function will search in all USB devices of the platform. If ParentDevicePath is not NULL, @@ -944,97 +901,105 @@ BmFindUsbDevice ( contains a USB Class or USB WWID device path node, and ended with Media FilePath device path. - @param DevicePath On input, a pointer to an allocated buffer that contains the - file device path. - On output, a pointer to an reallocated buffer that contains - the expanded device path. It would point to NULL if the file - cannot be read. + @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 ShortformNode Pointer to the USB short-form device path node in the FilePath buffer. - @param FileSize A pointer to the file size. - - @retval !NULL The file buffer. - @retval NULL The input device path doesn't point to a valid file. + @return The load option buffer. Caller is responsible to free the memory. **/ VOID * -BmExpandUsbShortFormDevicePath ( - IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, - OUT UINTN *FileSize +BmExpandUsbDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, + OUT UINTN *FileSize, + IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode ) { UINTN ParentDevicePathSize; - EFI_DEVICE_PATH_PROTOCOL *ShortformNode; EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; EFI_DEVICE_PATH_PROTOCOL *FullDevicePath; - EFI_HANDLE *UsbIoHandles; - UINTN UsbIoHandleCount; + EFI_HANDLE *Handles; + UINTN HandleCount; UINTN Index; VOID *FileBuffer; - - // - // Search for USB Class or USB WWID device path node. - // - for ( ShortformNode = *DevicePath - ; !IsDevicePathEnd (ShortformNode) - ; ShortformNode = NextDevicePathNode (ShortformNode) - ) { - if ((DevicePathType (ShortformNode) == MESSAGING_DEVICE_PATH) && - ((DevicePathSubType (ShortformNode) == MSG_USB_CLASS_DP) || - (DevicePathSubType (ShortformNode) == MSG_USB_WWID_DP))) { - break; - } + + 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 = BmGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize); + FreePool (FullDevicePath); } - ASSERT (!IsDevicePathEnd (ShortformNode)); - FullDevicePath = NULL; - ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) *DevicePath; - RemainingDevicePath = NextDevicePathNode (ShortformNode); - FileBuffer = NULL; - UsbIoHandles = BmFindUsbDevice (*DevicePath, ParentDevicePathSize, &UsbIoHandleCount); + if (Handles != NULL) { + FreePool (Handles); + } - for (Index = 0; Index < UsbIoHandleCount; Index++) { - FullDevicePath = AppendDevicePath (DevicePathFromHandle (UsbIoHandles[Index]), RemainingDevicePath); - DEBUG ((EFI_D_INFO, "[Bds] FullDp1[%d]:", Index)); DEBUG_CODE (BmPrintDp (FullDevicePath); ); DEBUG ((EFI_D_INFO, "\n")); - FileBuffer = BmLoadEfiBootOption (&FullDevicePath, FileSize); - if (FileBuffer != NULL) { - DEBUG ((EFI_D_INFO, "-->")); DEBUG_CODE (BmPrintDp (FullDevicePath); ); DEBUG ((EFI_D_INFO, FileBuffer != NULL ? " - Found\n" : "\n")); - break; - } + return FileBuffer; +} + +/** + Save the partition DevicePath to the CachedDevicePath as the first instance. + + @param CachedDevicePath The device path cache. + @param DevicePath The partition device path to be cached. +**/ +VOID +BmCachePartitionDevicePath ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + UINTN Count; + + if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) { + TempDevicePath = *CachedDevicePath; + *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath); + FreePool (TempDevicePath); } - if (UsbIoHandles != NULL) { - FreePool (UsbIoHandles); + if (*CachedDevicePath == NULL) { + *CachedDevicePath = DuplicateDevicePath (DevicePath); + return; } - if (FileBuffer == NULL) { + TempDevicePath = *CachedDevicePath; + *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath); + if (TempDevicePath != NULL) { + FreePool (TempDevicePath); + } + + // + // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller + // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger. + // + Count = 0; + TempDevicePath = *CachedDevicePath; + while (!IsDevicePathEnd (TempDevicePath)) { + TempDevicePath = NextDevicePathNode (TempDevicePath); // - // 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. + // Parse one instance // - if ((DevicePathType (*DevicePath) == MESSAGING_DEVICE_PATH) && - ((DevicePathSubType (*DevicePath) == MSG_USB_CLASS_DP) || - (DevicePathSubType (*DevicePath) == MSG_USB_WWID_DP))) { - BmConnectUsbShortFormDevicePath (*DevicePath); - - UsbIoHandles = BmFindUsbDevice (*DevicePath, ParentDevicePathSize, &UsbIoHandleCount); - for (Index = 0; Index < UsbIoHandleCount; Index++) { - FullDevicePath = AppendDevicePath (DevicePathFromHandle (UsbIoHandles[Index]), RemainingDevicePath); - DEBUG ((EFI_D_INFO, "[Bds] FullDp2[%d]:", Index)); DEBUG_CODE (BmPrintDp (FullDevicePath); ); DEBUG ((EFI_D_INFO, "\n")); - FileBuffer = BmLoadEfiBootOption (&FullDevicePath, FileSize); - if (FileBuffer != NULL) { - DEBUG ((EFI_D_INFO, "-->")); DEBUG_CODE (BmPrintDp (FullDevicePath); ); DEBUG ((EFI_D_INFO, FileBuffer != NULL ? " - Found\n" : "\n")); - break; - } - } - - if (UsbIoHandles != NULL) { - FreePool (UsbIoHandles); - } + while (!IsDevicePathEndType (TempDevicePath)) { + TempDevicePath = NextDevicePathNode (TempDevicePath); + } + Count++; + // + // If the CachedDevicePath variable contain too much instance, only remain 12 instances. + // + if (Count == 12) { + SetDevicePathEndNode (TempDevicePath); + break; } } - - BmFreeAndSet ((VOID **) DevicePath, FullDevicePath); - return FileBuffer; } /** @@ -1045,34 +1010,37 @@ BmExpandUsbShortFormDevicePath ( so a connect all is not required on every boot. All successful history device path which point to partition node (the front part) will be saved. - @param DevicePath On input, a pointer to an allocated buffer that contains the - file device path. - On output, a pointer to an reallocated buffer that contains - the expanded device path. It would point to NULL if the file - cannot be read. + @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. **/ -VOID -BmExpandPartitionShortFormDevicePath ( - IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath +VOID * +BmExpandPartitionDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, + OUT UINTN *FileSize ) { EFI_STATUS Status; UINTN BlockIoHandleCount; EFI_HANDLE *BlockIoBuffer; - EFI_DEVICE_PATH_PROTOCOL *FullDevicePath; + VOID *FileBuffer; EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath; UINTN Index; - UINTN InstanceNum; EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath; EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; UINTN CachedDevicePathSize; - BOOLEAN DeviceExist; BOOLEAN NeedAdjust; EFI_DEVICE_PATH_PROTOCOL *Instance; UINTN Size; - FullDevicePath = NULL; + FileBuffer = NULL; // // Check if there is prestore 'HDDP' variable. // If exist, search the front path which point to partition node in the variable instants. @@ -1098,7 +1066,6 @@ BmExpandPartitionShortFormDevicePath ( if (CachedDevicePath != NULL) { TempNewDevicePath = CachedDevicePath; - DeviceExist = FALSE; NeedAdjust = FALSE; do { // @@ -1107,15 +1074,40 @@ BmExpandPartitionShortFormDevicePath ( // partial partition boot option. Second, check whether the instance could be connected. // Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size); - if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) *DevicePath)) { + if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) { // // Connect the device path instance, the device path point to hard drive media device path node // e.g. ACPI() /PCI()/ATA()/Partition() // Status = EfiBootManagerConnectDevicePath (Instance, NULL); if (!EFI_ERROR (Status)) { - DeviceExist = TRUE; - break; + TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath)); + FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize); + FreePool (TempDevicePath); + + if (FileBuffer != NULL) { + // + // Adjust the 'HDDP' instances sequence if the matched one is not first one. + // + if (NeedAdjust) { + BmCachePartitionDevicePath (&CachedDevicePath, Instance); + // + // Save the matching Device Path so we don't need to do a connect all next time + // Failing to save only impacts performance next time expanding the short-form device path + // + Status = gRT->SetVariable ( + L"HDDP", + &mBmHardDriveBootVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + GetDevicePathSize (CachedDevicePath), + CachedDevicePath + ); + } + + FreePool (Instance); + FreePool (CachedDevicePath); + return FileBuffer; + } } } // @@ -1124,50 +1116,6 @@ BmExpandPartitionShortFormDevicePath ( NeedAdjust = TRUE; FreePool(Instance); } while (TempNewDevicePath != NULL); - - if (DeviceExist) { - // - // Find the matched device path. - // Append the file path information from the boot option and return the fully expanded device path. - // - FullDevicePath = AppendDevicePath (Instance, NextDevicePathNode (*DevicePath)); - - // - // Adjust the 'HDDP' instances sequence if the matched one is not first one. - // - if (NeedAdjust) { - // - // First delete the matched instance. - // - TempNewDevicePath = CachedDevicePath; - CachedDevicePath = BmDelPartMatchInstance (CachedDevicePath, Instance); - FreePool (TempNewDevicePath); - - // - // Second, append the remaining path after the matched instance - // - TempNewDevicePath = CachedDevicePath; - CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath ); - FreePool (TempNewDevicePath); - // - // Save the matching Device Path so we don't need to do a connect all next time - // Failing to save only impacts performance next time expanding the short-form device path - // - Status = gRT->SetVariable ( - L"HDDP", - &mBmHardDriveBootVariableGuid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, - GetDevicePathSize (CachedDevicePath), - CachedDevicePath - ); - } - - FreePool (Instance); - FreePool (CachedDevicePath); - FreePool (*DevicePath); - *DevicePath = FullDevicePath; - return; - } } // @@ -1184,80 +1132,36 @@ BmExpandPartitionShortFormDevicePath ( // 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) { + BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]); + if (BlockIoDevicePath == NULL) { continue; } - if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) *DevicePath)) { + if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) { // // Find the matched partition device path // - FullDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (*DevicePath)); + TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath)); + FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize); + FreePool (TempDevicePath); - // - // Save the matched partition device path in 'HDDP' variable - // - if (CachedDevicePath != NULL) { - // - // Save the matched partition device path as first instance of 'HDDP' variable - // - if (BmMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) { - TempNewDevicePath = CachedDevicePath; - CachedDevicePath = BmDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath); - FreePool(TempNewDevicePath); - } - - if (CachedDevicePath != NULL) { - TempNewDevicePath = CachedDevicePath; - CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath); - FreePool(TempNewDevicePath); - } else { - CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath); - } + if (FileBuffer != NULL) { + BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath); // - // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller - // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger. + // Save the matching Device Path so we don't need to do a connect all next time + // Failing to save only impacts performance next time expanding the short-form device path // - InstanceNum = 0; - ASSERT (CachedDevicePath != NULL); - TempNewDevicePath = CachedDevicePath; - while (!IsDevicePathEnd (TempNewDevicePath)) { - TempNewDevicePath = NextDevicePathNode (TempNewDevicePath); - // - // Parse one instance - // - while (!IsDevicePathEndType (TempNewDevicePath)) { - TempNewDevicePath = NextDevicePathNode (TempNewDevicePath); - } - InstanceNum++; - // - // If the CachedDevicePath variable contain too much instance, only remain 12 instances. - // - if (InstanceNum >= 12) { - SetDevicePathEndNode (TempNewDevicePath); - break; - } - } - } else { - CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath); - } - - // - // Save the matching Device Path so we don't need to do a connect all next time - // Failing to save only impacts performance next time expanding the short-form device path - // - Status = gRT->SetVariable ( - L"HDDP", - &mBmHardDriveBootVariableGuid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, - GetDevicePathSize (CachedDevicePath), - CachedDevicePath - ); + Status = gRT->SetVariable ( + L"HDDP", + &mBmHardDriveBootVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + GetDevicePathSize (CachedDevicePath), + CachedDevicePath + ); - break; + break; + } } } @@ -1267,92 +1171,92 @@ BmExpandPartitionShortFormDevicePath ( if (BlockIoBuffer != NULL) { FreePool (BlockIoBuffer); } - BmFreeAndSet ((VOID **) DevicePath, FullDevicePath); + return FileBuffer; } /** - Algorithm follows the UEFI Spec chapter 3.4 Boot Mechanisms. - - @param DevicePath Device Path to a bootable device + Expand the media device path which points to a BlockIo or SimpleFileSystem instance + by appending EFI_REMOVABLE_MEDIA_FILE_NAME. - @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return. + @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. + @return The load option buffer. **/ -EFI_HANDLE -BmGetBootableDeviceHandle ( - IN EFI_DEVICE_PATH_PROTOCOL *DevicePath +VOID * +BmExpandMediaDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, + OUT UINTN *FileSize ) { EFI_STATUS Status; - EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath; EFI_HANDLE Handle; EFI_BLOCK_IO_PROTOCOL *BlockIo; VOID *Buffer; EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; UINTN Size; UINTN TempSize; - EFI_HANDLE ReturnHandle; EFI_HANDLE *SimpleFileSystemHandles; UINTN NumberSimpleFileSystemHandles; UINTN Index; - EFI_IMAGE_DOS_HEADER DosHeader; - EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData; - EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; - - ReturnHandle = NULL; - UpdatedDevicePath = DevicePath; + VOID *FileBuffer; + UINT32 AuthenticationStatus; // // Check whether the device is connected // - Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle); - if (EFI_ERROR (Status)) { - // - // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol, - // - Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle); - if (EFI_ERROR (Status)) { - // - // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly - // - UpdatedDevicePath = DevicePath; - Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle); - gBS->ConnectController (Handle, NULL, NULL, TRUE); - } - } else { - // - // For removable device boot option, its contained device path only point 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); - // - // Get BlockIo protocol and check removable attribute - // - Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo); - // - // 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. - // - Buffer = AllocatePool (BlockIo->Media->BlockSize); - if (Buffer != NULL) { - BlockIo->ReadBlocks ( - BlockIo, - BlockIo->Media->MediaId, - 0, - BlockIo->Media->BlockSize, - Buffer - ); - FreePool(Buffer); + TempDevicePath = DevicePath; + Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle); + 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; } + *FullPath = TempDevicePath; + return FileBuffer; + } + + // + // 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); + + // + // 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->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle); + ASSERT_EFI_ERROR (Status); + Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo); + ASSERT_EFI_ERROR (Status); + Buffer = AllocatePool (BlockIo->Media->BlockSize); + if (Buffer != NULL) { + BlockIo->ReadBlocks ( + BlockIo, + BlockIo->Media->MediaId, + 0, + BlockIo->Media->BlockSize, + Buffer + ); + FreePool (Buffer); } // // Detect the the default boot file from removable Media // - Size = GetDevicePathSize(DevicePath) - END_DEVICE_PATH_LENGTH; + FileBuffer = NULL; + *FullPath = NULL; + Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH; gBS->LocateHandleBuffer ( ByProtocol, &gEfiSimpleFileSystemProtocolGuid, @@ -1365,87 +1269,87 @@ BmGetBootableDeviceHandle ( // Get the device path size of SimpleFileSystem handle // TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]); - TempSize = GetDevicePathSize (TempDevicePath)- END_DEVICE_PATH_LENGTH; + TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH; // // 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)) { - // - // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media - // machinename is ia32, ia64, x64, ... - // - Hdr.Union = &HdrData; - Status = BmGetImageHeader ( - SimpleFileSystemHandles[Index], - EFI_REMOVABLE_MEDIA_FILE_NAME, - &DosHeader, - Hdr - ); - if (!EFI_ERROR (Status) && EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) && - (Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) - ) { - ReturnHandle = SimpleFileSystemHandles[Index]; + TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME); + FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus); + if (FileBuffer != NULL) { + *FullPath = TempDevicePath; break; } + FreePool (TempDevicePath); } } if (SimpleFileSystemHandles != NULL) { - FreePool(SimpleFileSystemHandles); + FreePool (SimpleFileSystemHandles); } - return ReturnHandle; + return FileBuffer; } /** - Get the image file buffer data and buffer size by its device path. - - @param FilePath On input, a pointer to an allocated buffer that contains the - file device path. - On output the device path pointer could be modified to point to - a new allocated buffer that contains the full device path. - It could be caused by either short-form device path expanding, - or default boot file path appending. - @param FileSize A pointer to the size of the file buffer. - - @retval NULL The file can't be found. - @retval other The file buffer. The caller is responsible to free memory. + Get the load option by its device path. + + @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. **/ VOID * -BmLoadEfiBootOption ( - IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, - OUT UINTN *FileSize +BmGetLoadOptionBuffer ( + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, + OUT UINTN *FileSize ) { EFI_HANDLE Handle; VOID *FileBuffer; UINT32 AuthenticationStatus; EFI_DEVICE_PATH_PROTOCOL *Node; + EFI_STATUS Status; - ASSERT ((FilePath != NULL) && (*FilePath != NULL) && (FileSize != NULL)); + ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL)); - EfiBootManagerConnectDevicePath (*FilePath, NULL); + EfiBootManagerConnectDevicePath (FilePath, NULL); + *FullPath = NULL; *FileSize = 0; FileBuffer = NULL; + + // + // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI + // + Node = FilePath; + Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle); + if (EFI_ERROR (Status)) { + Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle); + } + + if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) { + return BmExpandMediaDevicePath (FilePath, FullPath, FileSize); + } + // // Expand the short-form device path to full device path // - if ((DevicePathType (*FilePath) == MEDIA_DEVICE_PATH) && - (DevicePathSubType (*FilePath) == MEDIA_HARDDRIVE_DP)) { + if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) && + (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) { // // Expand the Harddrive device path // - BmExpandPartitionShortFormDevicePath (FilePath); - if (*FilePath == NULL) { - return NULL; - } - + return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize); } else { - for (Node = *FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) { + 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))) { + ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) { break; } } @@ -1454,50 +1358,34 @@ BmLoadEfiBootOption ( // // Expand the USB WWID/Class device path // - FileBuffer = BmExpandUsbShortFormDevicePath (FilePath, FileSize); - if (FileBuffer == NULL) { - return NULL; + 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); } + return FileBuffer; } } // // Fix up the boot option path if it points to a FV in memory map style of device path // - if (BmIsMemmapFvFilePath (*FilePath)) { - BmFixupMemmapFvFilePath (FilePath); - if (*FilePath == NULL) { - return NULL; - } - } - - if (FileBuffer == NULL) { - FileBuffer = GetFileBufferByFilePath (TRUE, *FilePath, FileSize, &AuthenticationStatus); + if (BmIsMemmapFvFilePath (FilePath)) { + return BmGetFileBufferByMemmapFv (FilePath, FullPath, FileSize); } // - // If we didn't find an image directly, we need to try as if it is a removable device boot option - // and load the image according to the default boot behavior. + // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2), + // or it directly points to a file in simple file system instance. // - if (FileBuffer == NULL) { - // - // check if there is a bootable media could be found in this device path, - // and get the bootable media handle - // - Handle = BmGetBootableDeviceHandle (*FilePath); - if (Handle != NULL) { - // - // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from the media - // machinename is ia32, ia64, x64, ... - // - BmFreeAndSet ((VOID **) FilePath, FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME)); - ASSERT (*FilePath != NULL); - FileBuffer = GetFileBufferByFilePath (TRUE, *FilePath, FileSize, &AuthenticationStatus); - } - } - - if (FileBuffer == NULL) { - BmFreeAndSet ((VOID **) FilePath, NULL); + FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus); + if (FileBuffer != NULL) { + *FullPath = DuplicateDevicePath (FilePath); } return FileBuffer; @@ -1547,7 +1435,7 @@ EfiBootManagerBoot ( return; } - if (BootOption->FilePath == NULL) { + if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) { BootOption->Status = EFI_INVALID_PARAMETER; return; } @@ -1557,7 +1445,7 @@ EfiBootManagerBoot ( // OptionNumber = BmFindBootOptionInVariable (BootOption); if (OptionNumber == LoadOptionNumberUnassigned) { - Status = BmGetFreeOptionNumber (L"BootOrder", &Uint16); + Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16); if (!EFI_ERROR (Status)) { // // Save the BootOption->OptionNumber to restore later @@ -1601,9 +1489,12 @@ EfiBootManagerBoot ( DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n")); BmStopHotkeyService (NULL, NULL); } else { - REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT)); EfiSignalEventReadyToBoot(); // + // Report Status Code to indicate ReadyToBoot was signalled + // + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT)); + // // 4. Repair system through DriverHealth protocol // BmRepairAllControllers (); @@ -1615,14 +1506,20 @@ EfiBootManagerBoot ( // 5. Load EFI boot option to ImageHandle // ImageHandle = NULL; - if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) { + if (BmDevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) { Status = EFI_NOT_FOUND; - FilePath = DuplicateDevicePath (BootOption->FilePath); - FileBuffer = BmLoadEfiBootOption (&FilePath, &FileSize); - if (FileBuffer != NULL) { - + FileBuffer = BmGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize); + 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, gImageHandle, @@ -1631,7 +1528,11 @@ EfiBootManagerBoot ( FileSize, &ImageHandle ); + } + if (FileBuffer != NULL) { FreePool (FileBuffer); + } + if (FilePath != NULL) { FreePool (FilePath); } @@ -1790,63 +1691,44 @@ BmMatchPartitionDevicePathNode ( IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath ) { - HARDDRIVE_DEVICE_PATH *TmpHdPath; - EFI_DEVICE_PATH_PROTOCOL *DevicePath; - BOOLEAN Match; - EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePathNode; + HARDDRIVE_DEVICE_PATH *Node; if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) { return FALSE; } // - // Make PreviousDevicePath == the device path node before the end node - // - DevicePath = BlockIoDevicePath; - BlockIoHdDevicePathNode = NULL; - - // // find the partition device path node // - while (!IsDevicePathEnd (DevicePath)) { - if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && - (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP) + while (!IsDevicePathEnd (BlockIoDevicePath)) { + if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) && + (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP) ) { - BlockIoHdDevicePathNode = DevicePath; break; } - DevicePath = NextDevicePathNode (DevicePath); + BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath); } - if (BlockIoHdDevicePathNode == NULL) { + if (IsDevicePathEnd (BlockIoDevicePath)) { return FALSE; } + // // See if the harddrive device path in blockio matches the orig Hard Drive Node // - TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode; - Match = FALSE; + Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath; // - // Check for the match + // Match Signature and PartitionNumber. + // Unused bytes in Signature are initiaized with zeros. // - if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) && - (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) { - switch (TmpHdPath->SignatureType) { - case SIGNATURE_TYPE_GUID: - Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)HardDriveDevicePath->Signature); - break; - case SIGNATURE_TYPE_MBR: - Match = (BOOLEAN) (*((UINT32 *) (&(TmpHdPath->Signature[0]))) == ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0])))); - break; - default: - Match = FALSE; - break; - } - } - - return Match; + return (BOOLEAN) ( + (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) && + (Node->MBRType == HardDriveDevicePath->MBRType) && + (Node->SignatureType == HardDriveDevicePath->SignatureType) && + (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0) + ); } /** diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c b/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c index 0172f959d7..9e3a683e25 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c @@ -102,12 +102,13 @@ EfiBootManagerConnectAll ( a multi-instance device path @param MatchingHandle Return the controller handle closest to the DevicePathToConnect - @retval EFI_SUCCESS All handles associate with every device path node - have been created - @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles - @retval EFI_NOT_FOUND Create the handle associate with one device path - node failed - + @retval EFI_SUCCESS All handles associate with every device path node + have been created. + @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles. + @retval EFI_NOT_FOUND Create the handle associate with one device path + node failed. + @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device + drivers on the DevicePath. **/ EFI_STATUS EFIAPI @@ -166,9 +167,8 @@ EfiBootManagerConnectDevicePath ( // Connect all drivers that apply to Handle and RemainingDevicePath, // the Recursive flag is FALSE so only one level will be expanded. // - // Do not check the connect status here, if the connect controller fail, - // then still give the chance to do dispatch, because partial - // RemainingDevicepath may be in the new FV + // If ConnectController fails to find a driver, then still give the chance to + // do dispatch, because partial RemainingDevicePath may be in the new FV // // 1. If the connect fail, RemainingDevicepath and handle will not // change, so next time will do the dispatch, then dispatch's status @@ -177,7 +177,10 @@ EfiBootManagerConnectDevicePath ( // change, then avoid the dispatch, we have chance to continue the // next connection // - gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE); + Status = gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE); + if (Status == EFI_NOT_FOUND) { + Status = EFI_SUCCESS; + } if (MatchingHandle != NULL) { *MatchingHandle = Handle; } diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c b/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c index 49b99957e0..4f5c8b04c2 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c @@ -695,28 +695,42 @@ EfiBootManagerConnectAllConsoles ( /** This function will connect all the console devices base on the console device variable ConIn, ConOut and ErrOut. + + @retval EFI_DEVICE_ERROR All the consoles were not connected due to an error. + @retval EFI_SUCCESS Success connect any one instance of the console + device path base on the variable ConVarName. **/ -VOID +EFI_STATUS EFIAPI EfiBootManagerConnectAllDefaultConsoles ( VOID ) { + EFI_STATUS Status; + BOOLEAN OneConnected; BOOLEAN SystemTableUpdated; - EfiBootManagerConnectConsoleVariable (ConOut); + OneConnected = FALSE; + + Status = EfiBootManagerConnectConsoleVariable (ConOut); + if (!EFI_ERROR (Status)) { + OneConnected = TRUE; + } PERF_START (NULL, "ConOutReady", "BDS", 1); PERF_END (NULL, "ConOutReady", "BDS", 0); - EfiBootManagerConnectConsoleVariable (ConIn); + Status = EfiBootManagerConnectConsoleVariable (ConIn); + if (!EFI_ERROR (Status)) { + OneConnected = TRUE; + } PERF_START (NULL, "ConInReady", "BDS", 1); PERF_END (NULL, "ConInReady", "BDS", 0); - // - // The _ModuleEntryPoint err out var is legal. - // - EfiBootManagerConnectConsoleVariable (ErrOut); + Status = EfiBootManagerConnectConsoleVariable (ErrOut); + if (!EFI_ERROR (Status)) { + OneConnected = TRUE; + } PERF_START (NULL, "ErrOutReady", "BDS", 1); PERF_END (NULL, "ErrOutReady", "BDS", 0); @@ -745,4 +759,6 @@ EfiBootManagerConnectAllDefaultConsoles ( &gST->Hdr.CRC32 ); } + + return OneConnected ? EFI_SUCCESS : EFI_DEVICE_ERROR; } diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c b/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c index fc3e29a62e..27a8db733e 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c @@ -14,21 +14,77 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "InternalBm.h" +GLOBAL_REMOVE_IF_UNREFERENCED + CHAR16 *mBmLoadOptionName[] = { + L"Driver", + L"SysPrep", + L"Boot" + }; + +GLOBAL_REMOVE_IF_UNREFERENCED + CHAR16 *mBmLoadOptionOrderName[] = { + EFI_DRIVER_ORDER_VARIABLE_NAME, + EFI_SYS_PREP_ORDER_VARIABLE_NAME, + EFI_BOOT_ORDER_VARIABLE_NAME + }; + +/** + Call Visitor function for each variable in variable storage. + + @param Visitor Visitor function. + @param Context The context passed to Visitor function. +**/ +VOID +BmForEachVariable ( + VARIABLE_VISITOR Visitor, + VOID *Context + ) +{ + EFI_STATUS Status; + CHAR16 *Name; + EFI_GUID Guid; + UINTN NameSize; + UINTN NewNameSize; + + NameSize = sizeof (CHAR16); + Name = AllocateZeroPool (NameSize); + ASSERT (Name != NULL); + while (TRUE) { + NewNameSize = NameSize; + Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid); + if (Status == EFI_BUFFER_TOO_SMALL) { + Name = ReallocatePool (NameSize, NewNameSize, Name); + ASSERT (Name != NULL); + Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid); + NameSize = NewNameSize; + } + + if (Status == EFI_NOT_FOUND) { + break; + } + ASSERT_EFI_ERROR (Status); + + Visitor (Name, &Guid, Context); + } + + FreePool (Name); +} + /** Get the Option Number that wasn't used. - @param OrderVariableName Could be L"BootOrder" or L"DriverOrder". - @param FreeOptionNumber To receive the minimal free option number. + @param LoadOptionType The load option type. + @param FreeOptionNumber Return the minimal free option number. - @retval EFI_SUCCESS The option number is found + @retval EFI_SUCCESS The option number is found and will be returned. @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used. @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL **/ EFI_STATUS BmGetFreeOptionNumber ( - IN CHAR16 *OrderVariableName, - OUT UINT16 *FreeOptionNumber + IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType, + OUT UINT16 *FreeOptionNumber ) { @@ -38,13 +94,14 @@ BmGetFreeOptionNumber ( UINTN OptionOrderSize; UINT16 *BootNext; - if (FreeOptionNumber == NULL) { - return EFI_INVALID_PARAMETER; - } + ASSERT (FreeOptionNumber != NULL); + ASSERT (LoadOptionType == LoadOptionTypeDriver || + LoadOptionType == LoadOptionTypeBoot || + LoadOptionType == LoadOptionTypeSysPrep); - GetEfiGlobalVariable2 (OrderVariableName, (VOID **) &OptionOrder, &OptionOrderSize); + GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize); BootNext = NULL; - if (*OrderVariableName == L'B') { + if (LoadOptionType == LoadOptionTypeBoot) { GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL); } @@ -94,72 +151,7 @@ BmGetFreeOptionNumber ( } /** - Update order variable . - - @param OptionOrderName Order variable name which need to be updated. - @param OptionNumber Option number for the new option. - @param Position Position of the new load option to put in the ****Order variable. - - @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered. - @retval EFI_ALREADY_STARTED The option number of Option is being used already. - @retval EFI_STATUS Return the status of gRT->SetVariable (). - -**/ -EFI_STATUS -BmAddOptionNumberToOrderVariable ( - IN CHAR16 *OptionOrderName, - IN UINT16 OptionNumber, - IN UINTN Position - ) -{ - EFI_STATUS Status; - UINTN Index; - UINT16 *OptionOrder; - UINT16 *NewOptionOrder; - UINTN OptionOrderSize; - // - // Update the option order variable - // - GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize); - - Status = EFI_SUCCESS; - for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) { - if (OptionOrder[Index] == OptionNumber) { - Status = EFI_ALREADY_STARTED; - break; - } - } - - if (!EFI_ERROR (Status)) { - Position = MIN (Position, OptionOrderSize / sizeof (UINT16)); - - NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16)); - ASSERT (NewOptionOrder != NULL); - if (OptionOrderSize != 0) { - CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16)); - CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16)); - } - NewOptionOrder[Position] = OptionNumber; - - Status = gRT->SetVariable ( - OptionOrderName, - &gEfiGlobalVariableGuid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, - OptionOrderSize + sizeof (UINT16), - NewOptionOrder - ); - FreePool (NewOptionOrder); - } - - if (OptionOrder != NULL) { - FreePool (OptionOrder); - } - - return Status; -} - -/** - Create the Boot#### or Driver#### variable from the load option. + Create the Boot####, Driver####, SysPrep####, variable from the load option. @param LoadOption Pointer to the load option. @@ -175,13 +167,14 @@ EfiBootManagerLoadOptionToVariable ( UINTN VariableSize; UINT8 *Variable; UINT8 *Ptr; - CHAR16 OptionName[sizeof ("Driver####")]; + CHAR16 OptionName[BM_OPTION_NAME_LEN]; CHAR16 *Description; CHAR16 NullChar; + UINT32 VariableAttributes; if ((Option->OptionNumber == LoadOptionNumberUnassigned) || (Option->FilePath == NULL) || - (Option->OptionType >= LoadOptionTypeMax) + ((UINT32) Option->OptionType >= LoadOptionTypeMax) ) { return EFI_INVALID_PARAMETER; } @@ -218,42 +211,108 @@ structure. Variable = AllocatePool (VariableSize); ASSERT (Variable != NULL); - + Ptr = Variable; - *(UINT32 *) Ptr = Option->Attributes; + WriteUnaligned32 ((UINT32 *) Ptr, Option->Attributes); Ptr += sizeof (Option->Attributes); - *(UINT16 *) Ptr = (UINT16) GetDevicePathSize (Option->FilePath); + + WriteUnaligned16 ((UINT16 *) Ptr, (UINT16) GetDevicePathSize (Option->FilePath)); Ptr += sizeof (UINT16); + CopyMem (Ptr, Description, StrSize (Description)); Ptr += StrSize (Description); + CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath)); Ptr += GetDevicePathSize (Option->FilePath); + CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize); - UnicodeSPrint ( - OptionName, - sizeof (OptionName), - (Option->OptionType == LoadOptionTypeBoot) ? L"Boot%04x" : L"Driver%04x", - Option->OptionNumber - ); + UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[Option->OptionType], Option->OptionNumber); + + VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE; return gRT->SetVariable ( OptionName, &gEfiGlobalVariableGuid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + VariableAttributes, VariableSize, Variable ); } /** - This function will register the new boot#### or driver#### option. - After the boot#### or driver#### updated, the BootOrder or DriverOrder will also be updated. + Update order variable . + + @param OptionOrderName Order variable name which need to be updated. + @param OptionNumber Option number for the new option. + @param Position Position of the new load option to put in the ****Order variable. + + @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered. + @retval EFI_ALREADY_STARTED The option number of Option is being used already. + @retval EFI_STATUS Return the status of gRT->SetVariable (). + +**/ +EFI_STATUS +BmAddOptionNumberToOrderVariable ( + IN CHAR16 *OptionOrderName, + IN UINT16 OptionNumber, + IN UINTN Position + ) +{ + EFI_STATUS Status; + UINTN Index; + UINT16 *OptionOrder; + UINT16 *NewOptionOrder; + UINTN OptionOrderSize; + // + // Update the option order variable + // + GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize); + + Status = EFI_SUCCESS; + for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) { + if (OptionOrder[Index] == OptionNumber) { + Status = EFI_ALREADY_STARTED; + break; + } + } + + if (!EFI_ERROR (Status)) { + Position = MIN (Position, OptionOrderSize / sizeof (UINT16)); + + NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16)); + ASSERT (NewOptionOrder != NULL); + if (OptionOrderSize != 0) { + CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16)); + CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16)); + } + NewOptionOrder[Position] = OptionNumber; + + Status = gRT->SetVariable ( + OptionOrderName, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + OptionOrderSize + sizeof (UINT16), + NewOptionOrder + ); + FreePool (NewOptionOrder); + } + + if (OptionOrder != NULL) { + FreePool (OptionOrder); + } + + return Status; +} + +/** + This function will register the new Boot####, Driver#### or SysPrep#### option. + After the *#### is updated, the *Order will also be updated. @param Option Pointer to load option to add. @param Position Position of the new load option to put in the ****Order variable. - @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered. + @retval EFI_SUCCESS The *#### have been successfully registered. @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF. @retval EFI_ALREADY_STARTED The option number of Option is being used already. Note: this API only adds new load option, no replacement support. @@ -276,14 +335,18 @@ EfiBootManagerAddLoadOptionVariable ( return EFI_INVALID_PARAMETER; } + if (Option->OptionType != LoadOptionTypeDriver && + Option->OptionType != LoadOptionTypeSysPrep && + Option->OptionType != LoadOptionTypeBoot + ) { + return EFI_INVALID_PARAMETER; + } + // // Get the free option number if the option number is unassigned // if (Option->OptionNumber == LoadOptionNumberUnassigned) { - Status = BmGetFreeOptionNumber ( - Option->OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder", - &OptionNumber - ); + Status = BmGetFreeOptionNumber (Option->OptionType, &OptionNumber); if (EFI_ERROR (Status)) { return Status; } @@ -294,11 +357,7 @@ EfiBootManagerAddLoadOptionVariable ( return EFI_INVALID_PARAMETER; } - Status = BmAddOptionNumberToOrderVariable ( - Option->OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder", - (UINT16) Option->OptionNumber, - Position - ); + Status = BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName[Option->OptionType], (UINT16) Option->OptionNumber, Position); if (!EFI_ERROR (Status)) { // // Save the Boot#### or Driver#### variable @@ -306,7 +365,7 @@ EfiBootManagerAddLoadOptionVariable ( Status = EfiBootManagerLoadOptionToVariable (Option); if (EFI_ERROR (Status)) { // - // Remove the #### from *Order variable when the Boot####/Driver#### cannot be saved. + // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved. // EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType); } @@ -357,7 +416,7 @@ EfiBootManagerSortLoadOptionVariable ( } Status = gRT->SetVariable ( - OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder", + mBmLoadOptionOrderName[OptionType], &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, LoadOptionCount * sizeof (UINT16), @@ -409,6 +468,10 @@ EfiBootManagerInitializeLoadOption ( return EFI_INVALID_PARAMETER; } + if ((UINT32) OptionType >= LoadOptionTypeMax) { + return EFI_INVALID_PARAMETER; + } + ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION)); Option->OptionNumber = OptionNumber; Option->OptionType = OptionType; @@ -461,58 +524,15 @@ BmFindLoadOption ( } /** - Update the BootOrder or DriverOrder to delete OptionNumber . - - @param OptionOrderVariable Order variable name which need to be updated. - @param OptionNumber Indicate the option number of load option - - @retval EFI_NOT_FOUND The load option cannot be found - @retval EFI_SUCCESS The load option was deleted - @retval others Status of RT->SetVariable() -**/ -EFI_STATUS -BmDeleteOptionVariable ( - IN CHAR16 *OptionOrderVariable, - IN UINT16 OptionNumber - ) -{ - UINT16 *OptionOrder; - UINTN OptionOrderSize; - EFI_STATUS Status; - UINTN Index; - - Status = EFI_NOT_FOUND; - GetEfiGlobalVariable2 (OptionOrderVariable, (VOID **) &OptionOrder, &OptionOrderSize); - for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) { - if (OptionOrder[Index] == OptionNumber) { - OptionOrderSize -= sizeof (UINT16); - CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16)); - Status = gRT->SetVariable ( - OptionOrderVariable, - &gEfiGlobalVariableGuid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, - OptionOrderSize, - OptionOrder - ); - break; - } - } - if (OptionOrder != NULL) { - FreePool (OptionOrder); - } - - return Status; -} + Delete the load option. -/** - Update the BootOrder or DriverOrder according to the OptionType to delete OptionNumber . - @param OptionNumber Indicate the option number of load option @param OptionType Indicate the type of load option @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid. @retval EFI_NOT_FOUND The load option cannot be found @retval EFI_SUCCESS The load option was deleted + @retval others Status of RT->SetVariable() **/ EFI_STATUS EFIAPI @@ -521,14 +541,42 @@ EfiBootManagerDeleteLoadOptionVariable ( IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType ) { - if ((OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) { + UINT16 *OptionOrder; + UINTN OptionOrderSize; + EFI_STATUS Status; + UINTN Index; + + if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) { return EFI_INVALID_PARAMETER; } - return BmDeleteOptionVariable ( - OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder", - (UINT16) OptionNumber - ); + Status = EFI_NOT_FOUND; + + if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) { + // + // If the associated *Order exists, just remove the reference in *Order. + // + GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], &OptionOrder, &OptionOrderSize); + for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) { + if (OptionOrder[Index] == OptionNumber) { + OptionOrderSize -= sizeof (UINT16); + CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16)); + Status = gRT->SetVariable ( + mBmLoadOptionOrderName[OptionType], + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + OptionOrderSize, + OptionOrder + ); + break; + } + } + if (OptionOrder != NULL) { + FreePool (OptionOrder); + } + } + + return Status; } /** @@ -551,7 +599,7 @@ BmCharToUint ( } ASSERT (FALSE); - return 0; + return (UINTN) -1; } /** @@ -645,10 +693,10 @@ BmStrSizeEx ( } /** - Validate the EFI Boot#### variable (VendorGuid/Name) + Validate the Boot####, Driver####, SysPrep#### variable (VendorGuid/Name) - @param Variable Boot#### variable data. - @param VariableSize Returns the size of the EFI variable that was read + @param Variable The variable data. + @param VariableSize The variable size. @retval TRUE The variable data is correct. @retval FALSE The variable data is corrupted. @@ -661,9 +709,8 @@ BmValidateOption ( ) { UINT16 FilePathSize; - UINT8 *TempPtr; EFI_DEVICE_PATH_PROTOCOL *DevicePath; - UINTN TempSize; + UINTN DescriptionSize; if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) { return FALSE; @@ -672,35 +719,33 @@ BmValidateOption ( // // Skip the option attribute // - TempPtr = Variable; - TempPtr += sizeof (UINT32); + Variable += sizeof (UINT32); // // Get the option's device path size // - FilePathSize = *(UINT16 *) TempPtr; - TempPtr += sizeof (UINT16); + FilePathSize = ReadUnaligned16 ((UINT16 *) Variable); + Variable += sizeof (UINT16); // // Get the option's description string size // - TempSize = BmStrSizeEx ((CHAR16 *) TempPtr, VariableSize - sizeof (UINT16) - sizeof (UINT32)); - TempPtr += TempSize; + DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32)); + Variable += DescriptionSize; // // Get the option's device path // - DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; - TempPtr += FilePathSize; + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable; // // Validation boot option variable. // - if ((FilePathSize == 0) || (TempSize == 0)) { + if ((FilePathSize == 0) || (DescriptionSize == 0)) { return FALSE; } - if (TempSize + FilePathSize + sizeof (UINT16) + sizeof (UINT32) > VariableSize) { + if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) { return FALSE; } @@ -708,11 +753,66 @@ BmValidateOption ( } /** + Check whether the VariableName is a valid load option variable name + and return the load option type and option number. + + @param VariableName The name of the load option variable. + @param OptionType Return the load option type. + @param OptionNumber Return the load option number. + + @retval TRUE The variable name is valid; The load option type and + load option number is returned. + @retval FALSE The variable name is NOT valid. +**/ +BOOLEAN +BmIsValidLoadOptionVariableName ( + IN CHAR16 *VariableName, + OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType, + OUT UINT16 *OptionNumber + ) +{ + UINTN VariableNameLen; + UINTN Index; + UINTN Uint; + + VariableNameLen = StrLen (VariableName); + + if (VariableNameLen <= 4) { + return FALSE; + } + + for (Index = 0; Index < sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0]); Index++) { + if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) && + (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) == 0) + ) { + break; + } + } + + if (Index == sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0])) { + return FALSE; + } + + *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index; + *OptionNumber = 0; + for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) { + Uint = BmCharToUint (VariableName[Index]); + if (Uint == -1) { + break; + } else { + *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10; + } + } + + return (BOOLEAN) (Index == VariableNameLen); +} + +/** Build the Boot#### or Driver#### option from the VariableName. - @param VariableName EFI Variable name indicate if it is Boot#### or - Driver#### - @param Option Return the Boot#### or Driver#### option. + @param VariableName Variable name of the load option + @param VendorGuid Variable GUID of the load option + @param Option Return the load option. @retval EFI_SUCCESS Get the option just been created @retval EFI_NOT_FOUND Failed to get the new option @@ -720,22 +820,22 @@ BmValidateOption ( **/ EFI_STATUS EFIAPI -EfiBootManagerVariableToLoadOption ( - IN CHAR16 *VariableName, - IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option +EfiBootManagerVariableToLoadOptionEx ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option ) { EFI_STATUS Status; UINT32 Attribute; UINT16 FilePathSize; UINT8 *Variable; - UINT8 *TempPtr; + UINT8 *VariablePtr; UINTN VariableSize; EFI_DEVICE_PATH_PROTOCOL *FilePath; UINT8 *OptionalData; UINT32 OptionalDataSize; CHAR16 *Description; - UINT8 NumOff; EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType; UINT16 OptionNumber; @@ -743,16 +843,20 @@ EfiBootManagerVariableToLoadOption ( return EFI_INVALID_PARAMETER; } + if (!BmIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) { + return EFI_INVALID_PARAMETER; + } + // // Read the variable // - GetEfiGlobalVariable2 (VariableName, (VOID **) &Variable, &VariableSize); + GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize); if (Variable == NULL) { return EFI_NOT_FOUND; } // - // Validate Boot#### variable data. + // Validate *#### variable data. // if (!BmValidateOption(Variable, VariableSize)) { FreePool (Variable); @@ -760,63 +864,41 @@ EfiBootManagerVariableToLoadOption ( } // - // Notes: careful defined the variable of Boot#### or - // Driver####, consider use some macro to abstract the code - // - // // Get the option attribute // - TempPtr = Variable; - Attribute = *(UINT32 *) Variable; - TempPtr += sizeof (UINT32); + VariablePtr = Variable; + Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr); + VariablePtr += sizeof (UINT32); // // Get the option's device path size // - FilePathSize = *(UINT16 *) TempPtr; - TempPtr += sizeof (UINT16); + FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr); + VariablePtr += sizeof (UINT16); // // Get the option's description string // - Description = (CHAR16 *) TempPtr; + Description = (CHAR16 *) VariablePtr; // // Get the option's description string size // - TempPtr += StrSize ((CHAR16 *) TempPtr); + VariablePtr += StrSize ((CHAR16 *) VariablePtr); // // Get the option's device path // - FilePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; - TempPtr += FilePathSize; + FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr; + VariablePtr += FilePathSize; - OptionalDataSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable)); + OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable)); if (OptionalDataSize == 0) { OptionalData = NULL; } else { - OptionalData = TempPtr; + OptionalData = VariablePtr; } - if (*VariableName == L'B') { - OptionType = LoadOptionTypeBoot; - NumOff = (UINT8) (sizeof (L"Boot") / sizeof (CHAR16) - 1); - } else { - OptionType = LoadOptionTypeDriver; - NumOff = (UINT8) (sizeof (L"Driver") / sizeof (CHAR16) - 1); - } - - // - // Get the value from VariableName Unicode string - // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this - // Unicode stream to ASCII without any loss in meaning. - // - OptionNumber = (UINT16) (BmCharToUint (VariableName[NumOff+0]) * 0x1000) - + (UINT16) (BmCharToUint (VariableName[NumOff+1]) * 0x100) - + (UINT16) (BmCharToUint (VariableName[NumOff+2]) * 0x10) - + (UINT16) (BmCharToUint (VariableName[NumOff+3]) * 0x1); - Status = EfiBootManagerInitializeLoadOption ( Option, OptionNumber, @@ -828,12 +910,33 @@ EfiBootManagerVariableToLoadOption ( OptionalDataSize ); ASSERT_EFI_ERROR (Status); - + + CopyGuid (&Option->VendorGuid, VendorGuid); + FreePool (Variable); return Status; } /** +Build the Boot#### or Driver#### option from the VariableName. + +@param VariableName EFI Variable name indicate if it is Boot#### or Driver#### +@param Option Return the Boot#### or Driver#### option. + +@retval EFI_SUCCESS Get the option just been created +@retval EFI_NOT_FOUND Failed to get the new option +**/ +EFI_STATUS +EFIAPI +EfiBootManagerVariableToLoadOption ( + IN CHAR16 *VariableName, + IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option + ) +{ + return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option); +} + +/** Returns an array of load options based on the EFI variable L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it. #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry. @@ -857,63 +960,56 @@ EfiBootManagerGetLoadOptions ( UINTN OptionOrderSize; UINTN Index; UINTN OptionIndex; - EFI_BOOT_MANAGER_LOAD_OPTION *Option; - CHAR16 OptionName[sizeof ("Driver####")]; + EFI_BOOT_MANAGER_LOAD_OPTION *Options; + CHAR16 OptionName[BM_OPTION_NAME_LEN]; UINT16 OptionNumber; *OptionCount = 0; - // - // Read the BootOrder, or DriverOrder variable. - // - GetEfiGlobalVariable2 ( - (LoadOptionType == LoadOptionTypeBoot) ? L"BootOrder" : L"DriverOrder", - (VOID **) &OptionOrder, - &OptionOrderSize - ); - if (OptionOrder == NULL) { - return NULL; - } + if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) { + // + // Read the BootOrder, or DriverOrder variable. + // + GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize); + if (OptionOrder == NULL) { + return NULL; + } - *OptionCount = OptionOrderSize / sizeof (UINT16); + *OptionCount = OptionOrderSize / sizeof (UINT16); - Option = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION)); - ASSERT (Option != NULL); + Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION)); + ASSERT (Options != NULL); - OptionIndex = 0; - for (Index = 0; Index < *OptionCount; Index++) { - OptionNumber = OptionOrder[Index]; - if (LoadOptionType == LoadOptionTypeBoot) { - UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionNumber); - } else { - UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionNumber); + OptionIndex = 0; + for (Index = 0; Index < *OptionCount; Index++) { + OptionNumber = OptionOrder[Index]; + UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber); + + Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName)); + EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType); + } else { + ASSERT (Options[OptionIndex].OptionNumber == OptionNumber); + OptionIndex++; + } } - Status = EfiBootManagerVariableToLoadOption (OptionName, &Option[OptionIndex]); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName)); - EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionTypeBoot); - } else { - ASSERT (Option[OptionIndex].OptionNumber == OptionNumber); - OptionIndex++; + if (OptionOrder != NULL) { + FreePool (OptionOrder); } - } - if (OptionOrder != NULL) { - FreePool (OptionOrder); - } + if (OptionIndex < *OptionCount) { + Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options); + ASSERT (Options != NULL); + *OptionCount = OptionIndex; + } - if (OptionIndex < *OptionCount) { - Option = ReallocatePool ( - *OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), - OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), - Option - ); - ASSERT (Option != NULL); - *OptionCount = OptionIndex; + } else { + return NULL; } - return Option; + return Options; } /** @@ -980,3 +1076,173 @@ EfiBootManagerFreeLoadOptions ( return EFI_SUCCESS; } + +/** + Return whether the PE header of the load option is valid or not. + + @param[in] Type The load option type. + @param[in] FileBuffer The PE file buffer of the load option. + @param[in] FileSize The size of the load option file. + + @retval TRUE The PE header of the load option is valid. + @retval FALSE The PE header of the load option is not valid. +**/ +BOOLEAN +BmIsLoadOptionPeHeaderValid ( + IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type, + IN VOID *FileBuffer, + IN UINTN FileSize + ) +{ + EFI_IMAGE_DOS_HEADER *DosHeader; + EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHeader; + EFI_IMAGE_OPTIONAL_HEADER32 *OptionalHeader; + UINT16 Subsystem; + + if (FileBuffer == NULL || FileSize == 0) { + return FALSE; + } + + // + // Read dos header + // + DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer; + if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) && + FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE + ) { + // + // Read and check PE signature + // + PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew); + if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) && + PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE + ) { + // + // Check PE32 or PE32+ magic, and machine type + // + OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader; + if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC || + OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) && + EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine) + ) { + // + // Check the Subsystem: + // Driver#### must be of type BootServiceDriver or RuntimeDriver + // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application + // + Subsystem = OptionalHeader->Subsystem; + if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || + (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) || + (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) || + (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) + ) { + return TRUE; + } + } + } + } + + return FALSE; +} + +/** + Process (load and execute) the load option. + + @param LoadOption Pointer to the load option. + + @retval EFI_INVALID_PARAMETER The load option type is invalid, + or the load option file path doesn't point to a valid file. + @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot. + @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed. +**/ +EFI_STATUS +EFIAPI +EfiBootManagerProcessLoadOption ( + IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + EFI_HANDLE ImageHandle; + EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; + VOID *FileBuffer; + UINTN FileSize; + + if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) { + return EFI_INVALID_PARAMETER; + } + + if (LoadOption->OptionType == LoadOptionTypeBoot) { + return EFI_UNSUPPORTED; + } + + // + // If a load option is not marked as LOAD_OPTION_ACTIVE, + // the boot manager will not automatically load the option. + // + if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) { + return EFI_SUCCESS; + } + + Status = EFI_INVALID_PARAMETER; + + // + // Load and start the load option. + // + DEBUG (( + DEBUG_INFO | DEBUG_LOAD, "Process Load Option (%s%04x) ...\n", + mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber + )); + ImageHandle = NULL; + FileBuffer = BmGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize); + DEBUG_CODE ( + if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) { + DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: ")); + BmPrintDp (LoadOption->FilePath); + DEBUG ((EFI_D_INFO, " -> ")); + BmPrintDp (FilePath); + DEBUG ((EFI_D_INFO, "\n")); + } + ); + if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) { + Status = gBS->LoadImage ( + FALSE, + gImageHandle, + FilePath, + FileBuffer, + FileSize, + &ImageHandle + ); + } + if (FilePath != NULL) { + FreePool (FilePath); + } + if (FileBuffer != NULL) { + FreePool (FileBuffer); + } + + if (!EFI_ERROR (Status)) { + Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo); + ASSERT_EFI_ERROR (Status); + + ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize; + ImageInfo->LoadOptions = LoadOption->OptionalData; + // + // Before calling the image, enable the Watchdog Timer for the 5-minute period + // + gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL); + + LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData); + DEBUG (( + DEBUG_INFO | DEBUG_LOAD, "Load Option (%s%04x) Return Status = %r\n", + mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status + )); + + // + // Clear the Watchdog Timer after the image returns + // + gBS->SetWatchdogTimer (0, 0, 0, NULL); + } + + return Status; +} diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c b/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c index 1cfb4bb039..30d955111e 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c @@ -121,146 +121,6 @@ BmMatchDevicePaths ( } /** - Get the headers (dos, image, optional header) from an image - - @param Device SimpleFileSystem device handle - @param FileName File name for the image - @param DosHeader Pointer to dos header - @param Hdr The buffer in which to return the PE32, PE32+, or TE header. - - @retval EFI_SUCCESS Successfully get the machine type. - @retval EFI_NOT_FOUND The file is not found. - @retval EFI_LOAD_ERROR File is not a valid image file. - -**/ -EFI_STATUS -BmGetImageHeader ( - IN EFI_HANDLE Device, - IN CHAR16 *FileName, - OUT EFI_IMAGE_DOS_HEADER *DosHeader, - OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr - ) -{ - EFI_STATUS Status; - EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; - EFI_FILE_HANDLE Root; - EFI_FILE_HANDLE ThisFile; - UINTN BufferSize; - UINT64 FileSize; - EFI_FILE_INFO *Info; - - Root = NULL; - ThisFile = NULL; - // - // Handle the file system interface to the device - // - Status = gBS->HandleProtocol ( - Device, - &gEfiSimpleFileSystemProtocolGuid, - (VOID *) &Volume - ); - if (EFI_ERROR (Status)) { - goto Done; - } - - Status = Volume->OpenVolume ( - Volume, - &Root - ); - if (EFI_ERROR (Status)) { - Root = NULL; - goto Done; - } - ASSERT (Root != NULL); - Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0); - if (EFI_ERROR (Status)) { - goto Done; - } - ASSERT (ThisFile != NULL); - - // - // Get file size - // - BufferSize = SIZE_OF_EFI_FILE_INFO + 200; - do { - Info = NULL; - Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) &Info); - if (EFI_ERROR (Status)) { - goto Done; - } - Status = ThisFile->GetInfo ( - ThisFile, - &gEfiFileInfoGuid, - &BufferSize, - Info - ); - if (!EFI_ERROR (Status)) { - break; - } - if (Status != EFI_BUFFER_TOO_SMALL) { - FreePool (Info); - goto Done; - } - FreePool (Info); - } while (TRUE); - - FileSize = Info->FileSize; - FreePool (Info); - - // - // Read dos header - // - BufferSize = sizeof (EFI_IMAGE_DOS_HEADER); - Status = ThisFile->Read (ThisFile, &BufferSize, DosHeader); - if (EFI_ERROR (Status) || - BufferSize < sizeof (EFI_IMAGE_DOS_HEADER) || - FileSize <= DosHeader->e_lfanew || - DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) { - Status = EFI_LOAD_ERROR; - goto Done; - } - - // - // Move to PE signature - // - Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew); - if (EFI_ERROR (Status)) { - Status = EFI_LOAD_ERROR; - goto Done; - } - - // - // Read and check PE signature - // - BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION); - Status = ThisFile->Read (ThisFile, &BufferSize, Hdr.Pe32); - if (EFI_ERROR (Status) || - BufferSize < sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) || - Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { - Status = EFI_LOAD_ERROR; - goto Done; - } - - // - // Check PE32 or PE32+ magic - // - if (Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC && - Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { - Status = EFI_LOAD_ERROR; - goto Done; - } - - Done: - if (ThisFile != NULL) { - ThisFile->Close (ThisFile); - } - if (Root != NULL) { - Root->Close (Root); - } - return Status; -} - -/** This routine adjust the memory information for different memory type and save them into the variables for next boot. **/ @@ -505,3 +365,22 @@ BmSetVariableAndReportStatusCodeOnError ( return Status; } + +/** + Print the device path info. + + @param DevicePath The device path need to print. +**/ +VOID +BmPrintDp ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + CHAR16 *Str; + + Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE); + DEBUG ((EFI_D_INFO, "%s", Str)); + if (Str != NULL) { + FreePool (Str); + } +} diff --git a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h index c8dc226058..c362d8d7cc 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h +++ b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h @@ -100,6 +100,37 @@ CHAR16 * IN EFI_HANDLE Handle ); +#define BM_OPTION_NAME_LEN sizeof ("SysPrep####") +extern CHAR16 *mBmLoadOptionName[]; + +typedef +VOID +(*VARIABLE_VISITOR) ( + CHAR16 *Name, + EFI_GUID *Guid, + VOID *Context + ); + +/** + Call Visitor function for each variable in variable storage. + + @param Visitor Visitor function. + @param Context The context passed to Visitor function. +**/ +VOID +ForEachVariable ( + VARIABLE_VISITOR Visitor, + VOID *Context + ); + +/** + Repair all the controllers according to the Driver Health status queried. +**/ +VOID +BmRepairAllControllers ( + VOID + ); + #define BM_HOTKEY_SIGNATURE SIGNATURE_32 ('b', 'm', 'h', 'k') typedef struct { UINT32 Signature; @@ -139,7 +170,7 @@ BmLoadEfiBootOption ( /** Get the Option Number that wasn't used. - @param OrderVariableName Could be L"BootOrder" or L"DriverOrder". + @param LoadOptionType Load option type. @param FreeOptionNumber To receive the minimal free option number. @retval EFI_SUCCESS The option number is found @@ -149,8 +180,8 @@ BmLoadEfiBootOption ( **/ EFI_STATUS BmGetFreeOptionNumber ( - IN CHAR16 *OrderVariableName, - OUT UINT16 *FreeOptionNumber + IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType, + OUT UINT16 *FreeOptionNumber ); /** @@ -295,6 +326,42 @@ BmSetVariableAndReportStatusCodeOnError ( ); /** + Get the load option by its device path. + + @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. +**/ +VOID * +BmGetLoadOptionBuffer ( + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, + OUT UINTN *FileSize + ); + +/** + Return whether the PE header of the load option is valid or not. + + @param[in] Type The load option type. + @param[in] FileBuffer The PE file buffer of the load option. + @param[in] FileSize The size of the load option file. + + @retval TRUE The PE header of the load option is valid. + @retval FALSE The PE header of the load option is not valid. +**/ +BOOLEAN +BmIsLoadOptionPeHeaderValid ( + IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type, + IN VOID *FileBuffer, + IN UINTN FileSize + ); + +/** Function compares a device path data structure to that of all the nodes of a second device path instance. @@ -361,4 +428,14 @@ BmRepairAllControllers ( VOID ); +/** + Print the device path info. + + @param DevicePath The device path need to print. +**/ +VOID +BmPrintDp ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + #endif // _INTERNAL_BM_H_ diff --git a/MdeModulePkg/Universal/BdsDxe/BdsEntry.c b/MdeModulePkg/Universal/BdsDxe/BdsEntry.c index 7eebe84021..020f18d48c 100644 --- a/MdeModulePkg/Universal/BdsDxe/BdsEntry.c +++ b/MdeModulePkg/Universal/BdsDxe/BdsEntry.c @@ -47,6 +47,12 @@ CHAR16 *mReadOnlyVariables[] = { EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME
};
+CHAR16 *mBdsLoadOptionName[] = {
+ L"Driver",
+ L"SysPrep",
+ L"Boot"
+};
+
CHAR16 mRecoveryBoot[] = L"Recovery Boot";
/**
Event to Connect ConIn.
@@ -75,7 +81,7 @@ BdsDxeOnConnectConInCallBack ( // Should not enter this case, if enter, the keyboard will not work.
// May need platfrom policy to connect keyboard.
//
- DEBUG ((EFI_D_WARN, "[Bds] ASSERT Connect ConIn failed!!!\n"));
+ DEBUG ((EFI_D_WARN, "[Bds] Connect ConIn failed - %r!!!\n", Status));
}
}
@@ -553,103 +559,55 @@ DefaultBootBehavior ( }
/**
- The function will go through the driver option link list, load and start
- every driver the driver option device path point to.
+ The function will load and start every Driver####/SysPrep####.
- @param DriverOption Input driver option array.
- @param DriverOptionCount Input driver option count.
+ @param LoadOptions Load option array.
+ @param LoadOptionCount Load option count.
**/
VOID
-LoadDrivers (
- IN EFI_BOOT_MANAGER_LOAD_OPTION *DriverOption,
- IN UINTN DriverOptionCount
+ProcessLoadOptions (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions,
+ IN UINTN LoadOptionCount
)
{
- EFI_STATUS Status;
- UINTN Index;
- EFI_HANDLE ImageHandle;
- EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
- BOOLEAN ReconnectAll;
+ EFI_STATUS Status;
+ UINTN Index;
+ BOOLEAN ReconnectAll;
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;
ReconnectAll = FALSE;
+ LoadOptionType = LoadOptionTypeMax;
//
// Process the driver option
//
- for (Index = 0; Index < DriverOptionCount; Index++) {
+ for (Index = 0; Index < LoadOptionCount; Index++) {
//
- // If a load option is not marked as LOAD_OPTION_ACTIVE,
- // the boot manager will not automatically load the option.
+ // All the load options in the array should be of the same type.
//
- if ((DriverOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {
- continue;
- }
-
- //
- // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
- // then all of the EFI drivers in the system will be disconnected and
- // reconnected after the last driver load option is processed.
- //
- if ((DriverOption[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {
- ReconnectAll = TRUE;
+ if (LoadOptionType == LoadOptionTypeMax) {
+ LoadOptionType = LoadOptions[Index].OptionType;
}
-
- //
- // Make sure the driver path is connected.
- //
- EfiBootManagerConnectDevicePath (DriverOption[Index].FilePath, NULL);
+ ASSERT (LoadOptionType == LoadOptions[Index].OptionType);
+ ASSERT (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep);
- //
- // Load and start the image that Driver#### describes
- //
- Status = gBS->LoadImage (
- FALSE,
- gImageHandle,
- DriverOption[Index].FilePath,
- NULL,
- 0,
- &ImageHandle
- );
+ Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);
- if (!EFI_ERROR (Status)) {
- gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
-
- //
- // Verify whether this image is a driver, if not,
- // exit it and continue to parse next load option
- //
- if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {
- gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);
- continue;
- }
-
- ImageInfo->LoadOptionsSize = DriverOption[Index].OptionalDataSize;
- ImageInfo->LoadOptions = DriverOption[Index].OptionalData;
- //
- // Before calling the image, enable the Watchdog Timer for
- // the 5 Minute period
- //
- gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
-
- DriverOption[Index].Status = gBS->StartImage (ImageHandle, &DriverOption[Index].ExitDataSize, &DriverOption[Index].ExitData);
- DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", DriverOption[Index].Status));
-
- //
- // Clear the Watchdog Timer after the image returns
- //
- gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+ if (!EFI_ERROR (Status) && ((LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0)) {
+ ReconnectAll = TRUE;
}
}
-
+
//
- // Process the LOAD_OPTION_FORCE_RECONNECT driver option
+ // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
+ // then all of the EFI drivers in the system will be disconnected and
+ // reconnected after the last driver load option is processed.
//
- if (ReconnectAll) {
+ if (ReconnectAll && LoadOptionType == LoadOptionTypeDriver) {
EfiBootManagerDisconnectAll ();
EfiBootManagerConnectAll ();
}
-
}
/**
@@ -855,9 +813,8 @@ BdsEntry ( IN EFI_BDS_ARCH_PROTOCOL *This
)
{
- EFI_BOOT_MANAGER_LOAD_OPTION *DriverOption;
- EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
- UINTN DriverOptionCount;
+ EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions;
+ UINTN LoadOptionCount;
CHAR16 *FirmwareVendor;
EFI_EVENT HotkeyTriggered;
UINT64 OsIndication;
@@ -867,8 +824,11 @@ BdsEntry ( UINT16 BootTimeOut;
EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
UINTN Index;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
UINT16 *BootNext;
CHAR16 BootNextVariableName[sizeof ("Boot####")];
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
+ BOOLEAN BootFwUi;
HotkeyTriggered = NULL;
Status = EFI_SUCCESS;
@@ -939,7 +899,7 @@ BdsEntry ( // Initialize L"BootOptionSupport" EFI global variable.
// Lazy-ConIn implictly disables BDS hotkey.
//
- BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP;
+ BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;
if (!PcdGetBool (PcdConInConnectOnDemand)) {
BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;
SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);
@@ -1010,11 +970,11 @@ BdsEntry ( EfiBootManagerStartHotkeyService (&HotkeyTriggered);
//
- // Load Driver Options
+ // Execute Driver Options
//
- DriverOption = EfiBootManagerGetLoadOptions (&DriverOptionCount, LoadOptionTypeDriver);
- LoadDrivers (DriverOption, DriverOptionCount);
- EfiBootManagerFreeLoadOptions (DriverOption, DriverOptionCount);
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);
+ ProcessLoadOptions (LoadOptions, LoadOptionCount);
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
//
// Connect consoles
@@ -1059,23 +1019,28 @@ BdsEntry ( PERF_END (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);
DEBUG_CODE (
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
- UINTN BootOptionCount;
- UINTN Index;
-
- BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
- DEBUG ((EFI_D_INFO, "[Bds]=============Dumping Boot Options=============\n"));
- for (Index = 0; Index < BootOptionCount; Index++) {
+ UINTN Index;
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;
+ DEBUG ((EFI_D_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));
+ for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {
DEBUG ((
- EFI_D_INFO, "[Bds]Boot%04x: %s \t\t 0x%04x\n",
- BootOptions[Index].OptionNumber,
- BootOptions[Index].Description,
- BootOptions[Index].Attributes
+ EFI_D_INFO, " %s Options:\n",
+ mBdsLoadOptionName[LoadOptionType]
));
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);
+ for (Index = 0; Index < LoadOptionCount; Index++) {
+ DEBUG ((
+ EFI_D_INFO, " %s%04x: %s \t\t 0x%04x\n",
+ mBdsLoadOptionName[LoadOptionType],
+ LoadOptions[Index].OptionNumber,
+ LoadOptions[Index].Description,
+ LoadOptions[Index].Attributes
+ ));
+ }
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
}
- DEBUG ((EFI_D_INFO, "[Bds]=============Dumping Boot Options Finished====\n"));
- EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
- );
+ DEBUG ((EFI_D_INFO, "[Bds]=============End Load Options Dumping=============\n"));
+ );
//
// Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
@@ -1088,10 +1053,15 @@ BdsEntry ( &DataSize,
&OsIndication
);
- if (!EFI_ERROR(Status) && ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0)) {
- //
- // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
- //
+ if (EFI_ERROR (Status)) {
+ OsIndication = 0;
+ }
+
+ BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);
+ //
+ // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
+ //
+ if (BootFwUi) {
OsIndication &= ~((UINT64) EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
Status = gRT->SetVariable (
L"OsIndications",
@@ -1104,7 +1074,12 @@ BdsEntry ( // Changing the content without increasing its size with current variable implementation shouldn't fail.
//
ASSERT_EFI_ERROR (Status);
+ }
+ //
+ // Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
+ //
+ if (BootFwUi) {
//
// Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI
//
@@ -1113,25 +1088,36 @@ BdsEntry ( }
//
- // Directly boot to Boot Manager Menu.
+ // Directly enter the setup page.
+ // BootManagerMenu always contains the correct information even call fails.
//
- EfiBootManagerGetBootManagerMenu (&BootOption);
- EfiBootManagerBoot (&BootOption);
- EfiBootManagerFreeLoadOption (&BootOption);
- } else {
- PERF_START (NULL, "BdsWait", "BDS", 0);
- BdsWait (HotkeyTriggered);
- PERF_END (NULL, "BdsWait", "BDS", 0);
-
- //
- // BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback.
- //
- BdsReadKeys ();
-
- EfiBootManagerHotkeyBoot ();
+ EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
+ EfiBootManagerBoot (&BootManagerMenu);
+ EfiBootManagerFreeLoadOption (&BootManagerMenu);
}
//
+ // Execute SysPrep####
+ //
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);
+ ProcessLoadOptions (LoadOptions, LoadOptionCount);
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
+
+ //
+ // Execute Key####
+ //
+ PERF_START (NULL, "BdsWait", "BDS", 0);
+ BdsWait (HotkeyTriggered);
+ PERF_END (NULL, "BdsWait", "BDS", 0);
+
+ //
+ // BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback.
+ //
+ BdsReadKeys ();
+
+ EfiBootManagerHotkeyBoot ();
+
+ //
// Boot to "BootNext"
//
if (BootNext != NULL) {
|