X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FLibrary%2FUefiBootManagerLib%2FBmLoadOption.c;h=32918caf324ccdc98893149ccd9be4fc5320c7fe;hb=792ace0ac391c37c1299322340abdf74e2603795;hp=8201255484cf4a5c1e8403a121bdf74c61e64f9a;hpb=3dc5c1ae5c7575ba2d1714b40692b36fca56c120;p=mirror_edk2.git diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c b/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c index 8201255484..32918caf32 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c @@ -1,7 +1,7 @@ /** @file Load option library functions which relate with creating and processing load options. -Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.
(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -785,6 +785,8 @@ EfiBootManagerIsValidLoadOptionVariableName ( UINTN VariableNameLen; UINTN Index; UINTN Uint; + EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LocalOptionType; + UINT16 LocalOptionNumber; if (VariableName == NULL) { return FALSE; @@ -792,39 +794,52 @@ EfiBootManagerIsValidLoadOptionVariableName ( VariableNameLen = StrLen (VariableName); + // + // Return FALSE when the variable name length is too small. + // 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) + // + // Return FALSE when the variable name doesn't start with Driver/SysPrep/Boot/PlatformRecovery. + // + for (LocalOptionType = 0; LocalOptionType < ARRAY_SIZE (mBmLoadOptionName); LocalOptionType++) { + if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[LocalOptionType])) && + (StrnCmp (VariableName, mBmLoadOptionName[LocalOptionType], VariableNameLen - 4) == 0) ) { break; } } + if (LocalOptionType == ARRAY_SIZE (mBmLoadOptionName)) { + return FALSE; + } - if (Index == sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0])) { + // + // Return FALSE when the last four characters are not hex digits. + // + LocalOptionNumber = 0; + for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) { + Uint = BmCharToUint (VariableName[Index]); + if (Uint == -1) { + break; + } else { + LocalOptionNumber = (UINT16) Uint + LocalOptionNumber * 0x10; + } + } + if (Index != VariableNameLen) { return FALSE; } if (OptionType != NULL) { - *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index; + *OptionType = LocalOptionType; } if (OptionNumber != NULL) { - *OptionNumber = 0; - for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) { - Uint = BmCharToUint (VariableName[Index]); - if (Uint == -1) { - break; - } else { - *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10; - } - } + *OptionNumber = LocalOptionNumber; } - return (BOOLEAN) (Index == VariableNameLen); + return TRUE; } /** @@ -912,7 +927,7 @@ EfiBootManagerVariableToLoadOptionEx ( FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr; VariablePtr += FilePathSize; - OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable)); + OptionalDataSize = (UINT32) (VariableSize - ((UINTN) VariablePtr - (UINTN) Variable)); if (OptionalDataSize == 0) { OptionalData = NULL; } else { @@ -1167,6 +1182,10 @@ EfiBootManagerFreeLoadOptions ( Return whether the PE header of the load option is valid or not. @param[in] Type The load option type. + It's used to check whether the load option is valid. + When it's LoadOptionTypeMax, the routine only guarantees + the load option is a valid PE image but doesn't guarantee + the PE's subsystem type is valid. @param[in] FileBuffer The PE file buffer of the load option. @param[in] FileSize The size of the load option file. @@ -1217,7 +1236,8 @@ BmIsLoadOptionPeHeaderValid ( // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application // Subsystem = OptionalHeader->Subsystem; - if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || + if ((Type == LoadOptionTypeMax) || + (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) || @@ -1232,6 +1252,91 @@ BmIsLoadOptionPeHeaderValid ( return FALSE; } +/** + Return the next matched load option buffer. + The routine keeps calling BmGetNextLoadOptionDevicePath() until a valid + load option is read. + + @param Type The load option type. + It's used to check whether the load option is valid. + When it's LoadOptionTypeMax, the routine only guarantees + the load option is a valid PE image but doesn't guarantee + the PE's subsystem type is valid. + @param FilePath The device path pointing to a load option. + It could be a short-form device path. + @param FullPath Return the next full device path of the load option after + short-form device path expanding. + Caller is responsible to free it. + NULL to return the first matched full device path. + @param FileSize Return the load option size. + + @return The load option buffer. Caller is responsible to free the memory. +**/ +VOID * +BmGetNextLoadOptionBuffer ( + IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, + OUT UINTN *FileSize + ) +{ + VOID *FileBuffer; + EFI_DEVICE_PATH_PROTOCOL *PreFullPath; + EFI_DEVICE_PATH_PROTOCOL *CurFullPath; + UINTN LocalFileSize; + UINT32 AuthenticationStatus; + EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath; + + LocalFileSize = 0; + FileBuffer = NULL; + CurFullPath = *FullPath; + do { + PreFullPath = CurFullPath; + CurFullPath = BmGetNextLoadOptionDevicePath (FilePath, CurFullPath); + // + // Only free the full path created *inside* this routine + // + if ((PreFullPath != NULL) && (PreFullPath != *FullPath)) { + FreePool (PreFullPath); + } + if (CurFullPath == NULL) { + break; + } + FileBuffer = GetFileBufferByFilePath (TRUE, CurFullPath, &LocalFileSize, &AuthenticationStatus); + if ((FileBuffer != NULL) && !BmIsLoadOptionPeHeaderValid (Type, FileBuffer, LocalFileSize)) { + // + // Free the RAM disk file system if the load option is invalid. + // + RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath); + if (RamDiskDevicePath != NULL) { + BmDestroyRamDisk (RamDiskDevicePath); + FreePool (RamDiskDevicePath); + } + + // + // Free the invalid load option buffer. + // + FreePool (FileBuffer); + FileBuffer = NULL; + } + } while (FileBuffer == NULL); + + if (FileBuffer == NULL) { + CurFullPath = NULL; + LocalFileSize = 0; + } + + DEBUG ((DEBUG_INFO, "[Bds] Expand ")); + BmPrintDp (FilePath); + DEBUG ((DEBUG_INFO, " -> ")); + BmPrintDp (CurFullPath); + DEBUG ((DEBUG_INFO, "\n")); + + *FullPath = CurFullPath; + *FileSize = LocalFileSize; + return FileBuffer; +} + /** Process (load and execute) the load option. @@ -1249,7 +1354,8 @@ EfiBootManagerProcessLoadOption ( ) { EFI_STATUS Status; - EFI_DEVICE_PATH_PROTOCOL *FilePath; + EFI_DEVICE_PATH_PROTOCOL *PreFullPath; + EFI_DEVICE_PATH_PROTOCOL *CurFullPath; EFI_HANDLE ImageHandle; EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; VOID *FileBuffer; @@ -1271,64 +1377,71 @@ EfiBootManagerProcessLoadOption ( 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 + DEBUG_INFO | DEBUG_LOAD, "Process %s%04x (%s) ...\n", + mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, + LoadOption->Description )); 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")); + CurFullPath = NULL; + EfiBootManagerConnectDevicePath (LoadOption->FilePath, NULL); + + // + // while() loop is to keep starting next matched load option if the PlatformRecovery#### returns failure status. + // + while (TRUE) { + Status = EFI_INVALID_PARAMETER; + PreFullPath = CurFullPath; + FileBuffer = BmGetNextLoadOptionBuffer (LoadOption->OptionType, LoadOption->FilePath, &CurFullPath, &FileSize); + if (PreFullPath != NULL) { + FreePool (PreFullPath); + } + if (FileBuffer == NULL) { + break; } - ); - if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) { Status = gBS->LoadImage ( FALSE, gImageHandle, - FilePath, + CurFullPath, 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); + 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); + 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 + LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData); + DEBUG (( + DEBUG_INFO | DEBUG_LOAD, "%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); + // + // Clear the Watchdog Timer after the image returns + // + gBS->SetWatchdogTimer (0, 0, 0, NULL); + + if ((LoadOption->OptionType != LoadOptionTypePlatformRecovery) || (LoadOption->Status == EFI_SUCCESS)) { + break; + } + } + } + + if (CurFullPath != NULL) { + FreePool (CurFullPath); } return Status;