X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FCore%2FDxe%2FImage%2FImage.c;h=c49ddfcc81d16cae42ff0f315dfe8fc405c8d6bf;hp=e51a9fe1743b8391e2d7bbf5c0341f84ffec7e4a;hb=471048388cda4935866f829365922cdf70a6a45c;hpb=28186d45660c92b8d98b8b19b5f8e6ff71ea5fba diff --git a/MdeModulePkg/Core/Dxe/Image/Image.c b/MdeModulePkg/Core/Dxe/Image/Image.c index e51a9fe174..c49ddfcc81 100644 --- a/MdeModulePkg/Core/Dxe/Image/Image.c +++ b/MdeModulePkg/Core/Dxe/Image/Image.c @@ -1,7 +1,7 @@ /** @file Core image handling services to load and unload PeImage. -Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -89,7 +89,8 @@ GLOBAL_REMOVE_IF_UNREFERENCED MACHINE_TYPE_INFO mMachineTypeInfo[] = { {EFI_IMAGE_MACHINE_IA32, L"IA32"}, {EFI_IMAGE_MACHINE_IA64, L"IA64"}, {EFI_IMAGE_MACHINE_X64, L"X64"}, - {EFI_IMAGE_MACHINE_ARMTHUMB_MIXED, L"ARM"} + {EFI_IMAGE_MACHINE_ARMTHUMB_MIXED, L"ARM"}, + {EFI_IMAGE_MACHINE_AARCH64, L"AARCH64"} }; UINT16 mDxeCoreImageMachineType = 0; @@ -203,6 +204,8 @@ CoreInitializeImageServices ( ); } + ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath); + return Status; } @@ -258,11 +261,11 @@ CoreReadImageFile ( return EFI_SUCCESS; } /** - To check memory usage bit map arry to figure out if the memory range the image will be loaded in is available or not. If - memory range is avaliable, the function will mark the correponding bits to 1 which indicates the memory range is used. + To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If + memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used. The function is only invoked when load modules at fixed address feature is enabled. - @param ImageBase The base addres the image will be loaded at. + @param ImageBase The base address the image will be loaded at. @param ImageSize The size of the image @retval EFI_SUCCESS The memory range the image will be loaded in is available @@ -311,8 +314,8 @@ CheckAndMarkFixLoadingMemoryUsageBitMap ( // // Test if the memory is avalaible or not. // - BaseOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase - DxeCodeBase)); - TopOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - DxeCodeBase)); + BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - DxeCodeBase)); + TopOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - DxeCodeBase)); for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) { if ((mDxeCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) { // @@ -332,13 +335,13 @@ CheckAndMarkFixLoadingMemoryUsageBitMap ( } /** - Get the fixed loadding address from image header assigned by build tool. This function only be called + Get the fixed loading address from image header assigned by build tool. This function only be called when Loading module at Fixed address feature enabled. @param ImageContext Pointer to the image context structure that describes the PE/COFF image that needs to be examined by this function. @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools . - @retval EFI_NOT_FOUND The image has no assigned fixed loadding address. + @retval EFI_NOT_FOUND The image has no assigned fixed loading address. **/ EFI_STATUS @@ -364,12 +367,10 @@ GetPeCoffImageFixLoadingAssignedAddress( // Handle = (IMAGE_FILE_HANDLE*)ImageContext->Handle; ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )Handle->Source + ImageContext->PeCoffHeaderOffset); - SectionHeaderOffset = (UINTN)( - ImageContext->PeCoffHeaderOffset + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + - ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader - ); + SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader; NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections; // @@ -389,7 +390,10 @@ GetPeCoffImageFixLoadingAssignedAddress( if (EFI_ERROR (Status)) { return Status; } - + if (Size != sizeof (EFI_IMAGE_SECTION_HEADER)) { + return EFI_NOT_FOUND; + } + Status = EFI_NOT_FOUND; if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) { @@ -397,7 +401,7 @@ GetPeCoffImageFixLoadingAssignedAddress( // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header // that doesn't point to code section in image header, as well as ImageBase field of image header. And there is an // assumption that when the feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations - // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fileds should be set to Zero + // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fields should be set to Zero // ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations); if (ValueInSectionHeader != 0) { @@ -410,7 +414,7 @@ GetPeCoffImageFixLoadingAssignedAddress( ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)(INTN)ImageContext->ImageAddress; } // - // Check if the memory range is avaliable. + // Check if the memory range is available. // Status = CheckAndMarkFixLoadingMemoryUsageBitMap (ImageContext->ImageAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment)); } @@ -504,7 +508,7 @@ CoreLoadPeImage ( } // - // Allocate memory of the correct memory type aligned on the required image boundry + // Allocate memory of the correct memory type aligned on the required image boundary // DstBufAlocated = FALSE; if (DstBuffer == 0) { @@ -707,6 +711,7 @@ CoreLoadPeImage ( Image->RuntimeData->RelocationData = Image->ImageContext.FixupData; Image->RuntimeData->Handle = Image->Handle; InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link); + InsertImageRecord (Image->RuntimeData); } } @@ -783,6 +788,8 @@ Done: if (DstBufAlocated) { CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages); + Image->ImageContext.ImageAddress = 0; + Image->ImageBasePage = 0; } if (Image->ImageContext.FixupData != NULL) { @@ -851,6 +858,15 @@ CoreUnloadAndCloseImage ( UINTN OpenInfoCount; UINTN OpenInfoIndex; + HandleBuffer = NULL; + ProtocolGuidArray = NULL; + + if (Image->Started) { + UnregisterMemoryProfileImage (Image); + } + + UnprotectUefiImage (&Image->Info, Image->LoadedImageDevicePath); + if (Image->Ebc != NULL) { // // If EBC protocol exists we must perform cleanups for this image. @@ -946,6 +962,7 @@ CoreUnloadAndCloseImage ( // Remove the Image from the Runtime Image list as we are about to Free it! // RemoveEntryList (&Image->RuntimeData->Link); + RemoveImageRecord (Image->RuntimeData); } CoreFreePool (Image->RuntimeData); } @@ -1043,7 +1060,11 @@ CoreLoadImageCommon ( UINT32 AuthenticationStatus; EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath; EFI_DEVICE_PATH_PROTOCOL *HandleFilePath; + EFI_DEVICE_PATH_PROTOCOL *InputFilePath; + EFI_DEVICE_PATH_PROTOCOL *Node; UINTN FilePathSize; + BOOLEAN ImageIsFromFv; + BOOLEAN ImageIsFromLoadFile; SecurityStatus = EFI_SUCCESS; @@ -1066,17 +1087,24 @@ CoreLoadImageCommon ( ZeroMem (&FHand, sizeof (IMAGE_FILE_HANDLE)); FHand.Signature = IMAGE_FILE_HANDLE_SIGNATURE; OriginalFilePath = FilePath; + InputFilePath = FilePath; HandleFilePath = FilePath; DeviceHandle = NULL; Status = EFI_SUCCESS; AuthenticationStatus = 0; + ImageIsFromFv = FALSE; + ImageIsFromLoadFile = FALSE; + // // If the caller passed a copy of the file, then just use it // if (SourceBuffer != NULL) { FHand.Source = SourceBuffer; FHand.SourceSize = SourceSize; - CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &HandleFilePath, &DeviceHandle); + Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &HandleFilePath, &DeviceHandle); + if (EFI_ERROR (Status)) { + DeviceHandle = NULL; + } if (SourceSize > 0) { Status = EFI_SUCCESS; } else { @@ -1086,6 +1114,33 @@ CoreLoadImageCommon ( if (FilePath == NULL) { return EFI_INVALID_PARAMETER; } + + // + // Try to get the image device handle by checking the match protocol. + // + Node = NULL; + Status = CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle); + if (!EFI_ERROR (Status)) { + ImageIsFromFv = TRUE; + } else { + HandleFilePath = FilePath; + Status = CoreLocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &HandleFilePath, &DeviceHandle); + if (EFI_ERROR (Status)) { + if (!BootPolicy) { + HandleFilePath = FilePath; + Status = CoreLocateDevicePath (&gEfiLoadFile2ProtocolGuid, &HandleFilePath, &DeviceHandle); + } + if (EFI_ERROR (Status)) { + HandleFilePath = FilePath; + Status = CoreLocateDevicePath (&gEfiLoadFileProtocolGuid, &HandleFilePath, &DeviceHandle); + if (!EFI_ERROR (Status)) { + ImageIsFromLoadFile = TRUE; + Node = HandleFilePath; + } + } + } + } + // // Get the source file buffer by its device path. // @@ -1098,65 +1153,82 @@ CoreLoadImageCommon ( if (FHand.Source == NULL) { Status = EFI_NOT_FOUND; } else { - // - // Try to get the image device handle by checking the match protocol. - // FHand.FreeBuffer = TRUE; - Status = CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle); - if (EFI_ERROR (Status)) { - HandleFilePath = FilePath; - Status = CoreLocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &HandleFilePath, &DeviceHandle); - if (EFI_ERROR (Status)) { - if (!BootPolicy) { - HandleFilePath = FilePath; - Status = CoreLocateDevicePath (&gEfiLoadFile2ProtocolGuid, &HandleFilePath, &DeviceHandle); - } - if (EFI_ERROR (Status)) { - HandleFilePath = FilePath; - Status = CoreLocateDevicePath (&gEfiLoadFileProtocolGuid, &HandleFilePath, &DeviceHandle); - } - } + if (ImageIsFromLoadFile) { + // + // LoadFile () may cause the device path of the Handle be updated. + // + OriginalFilePath = AppendDevicePath (DevicePathFromHandle (DeviceHandle), Node); } } } - if (Status == EFI_ALREADY_STARTED) { + if (EFI_ERROR (Status)) { Image = NULL; goto Done; - } else if (EFI_ERROR (Status)) { - return Status; } - // - // Verify the Authentication Status through the Security Architectural Protocol - // - if ((gSecurity != NULL) && (OriginalFilePath != NULL)) { + if (gSecurity2 != NULL) { + // + // Verify File Authentication through the Security2 Architectural Protocol + // + SecurityStatus = gSecurity2->FileAuthentication ( + gSecurity2, + OriginalFilePath, + FHand.Source, + FHand.SourceSize, + BootPolicy + ); + if (!EFI_ERROR (SecurityStatus) && ImageIsFromFv) { + // + // When Security2 is installed, Security Architectural Protocol must be published. + // + ASSERT (gSecurity != NULL); + + // + // Verify the Authentication Status through the Security Architectural Protocol + // Only on images that have been read using Firmware Volume protocol. + // + SecurityStatus = gSecurity->FileAuthenticationState ( + gSecurity, + AuthenticationStatus, + OriginalFilePath + ); + } + } else if ((gSecurity != NULL) && (OriginalFilePath != NULL)) { + // + // Verify the Authentication Status through the Security Architectural Protocol + // SecurityStatus = gSecurity->FileAuthenticationState ( gSecurity, AuthenticationStatus, OriginalFilePath ); - if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) { - if (SecurityStatus == EFI_ACCESS_DENIED) { - // - // Image was not loaded because the platform policy prohibits the image from being loaded. - // It's the only place we could meet EFI_ACCESS_DENIED. - // - *ImageHandle = NULL; - } - Status = SecurityStatus; - Image = NULL; - goto Done; - } } + // + // Check Security Status. + // + if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) { + if (SecurityStatus == EFI_ACCESS_DENIED) { + // + // Image was not loaded because the platform policy prohibits the image from being loaded. + // It's the only place we could meet EFI_ACCESS_DENIED. + // + *ImageHandle = NULL; + } + Status = SecurityStatus; + Image = NULL; + goto Done; + } // // Allocate a new image structure // Image = AllocateZeroPool (sizeof(LOADED_IMAGE_PRIVATE_DATA)); if (Image == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto Done; } // @@ -1274,6 +1346,7 @@ CoreLoadImageCommon ( goto Done; } } + ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath); // // Success. Return the image handle @@ -1288,6 +1361,9 @@ Done: if (FHand.FreeBuffer) { CoreFreePool (FHand.Source); } + if (OriginalFilePath != InputFilePath) { + CoreFreePool (OriginalFilePath); + } // // There was an error. If there's an Image structure, free it @@ -1295,11 +1371,19 @@ Done: if (EFI_ERROR (Status)) { if (Image != NULL) { CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0)); + Image = NULL; } } else if (EFI_ERROR (SecurityStatus)) { Status = SecurityStatus; } + // + // Track the return status from LoadImage. + // + if (Image != NULL) { + Image->LoadImageStatus = Status; + } + return Status; } @@ -1353,6 +1437,7 @@ CoreLoadImage ( { EFI_STATUS Status; UINT64 Tick; + EFI_HANDLE Handle; Tick = 0; PERF_CODE ( @@ -1372,8 +1457,16 @@ CoreLoadImage ( EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION ); - PERF_START (*ImageHandle, "LoadImage:", NULL, Tick); - PERF_END (*ImageHandle, "LoadImage:", NULL, 0); + Handle = NULL; + if (!EFI_ERROR (Status)) { + // + // ImageHandle will be valid only Status is success. + // + Handle = *ImageHandle; + } + + PERF_START (Handle, "LoadImage:", NULL, Tick); + PERF_END (Handle, "LoadImage:", NULL, 0); return Status; } @@ -1432,7 +1525,16 @@ CoreLoadImageEx ( IN UINT32 Attribute ) { - return CoreLoadImageCommon ( + EFI_STATUS Status; + UINT64 Tick; + EFI_HANDLE Handle; + + Tick = 0; + PERF_CODE ( + Tick = GetPerformanceCounter (); + ); + + Status = CoreLoadImageCommon ( TRUE, ParentImageHandle, FilePath, @@ -1444,6 +1546,19 @@ CoreLoadImageEx ( EntryPoint, Attribute ); + + Handle = NULL; + if (!EFI_ERROR (Status)) { + // + // ImageHandle will be valid only Status is success. + // + Handle = *ImageHandle; + } + + PERF_START (Handle, "LoadImage:", NULL, Tick); + PERF_END (Handle, "LoadImage:", NULL, 0); + + return Status; } @@ -1461,6 +1576,7 @@ CoreLoadImageEx ( @retval EFI_INVALID_PARAMETER Invalid parameter @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate + @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started. @retval EFI_SUCCESS Successfully transfer control to the image's entry point. @@ -1478,11 +1594,19 @@ CoreStartImage ( LOADED_IMAGE_PRIVATE_DATA *LastImage; UINT64 HandleDatabaseKey; UINTN SetJumpFlag; + UINT64 Tick; + EFI_HANDLE Handle; + + Tick = 0; + Handle = ImageHandle; Image = CoreLoadedImageInfo (ImageHandle); if (Image == NULL || Image->Started) { return EFI_INVALID_PARAMETER; } + if (EFI_ERROR (Image->LoadImageStatus)) { + return Image->LoadImageStatus; + } // // The image to be started must have the machine type supported by DxeCore. @@ -1497,10 +1621,9 @@ CoreStartImage ( return EFI_UNSUPPORTED; } - // - // Don't profile Objects or invalid start requests - // - PERF_START (ImageHandle, "StartImage:", NULL, 0); + PERF_CODE ( + Tick = GetPerformanceCounter (); + ); // @@ -1520,7 +1643,18 @@ CoreStartImage ( // Image->JumpBuffer = AllocatePool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT); if (Image->JumpBuffer == NULL) { - PERF_END (ImageHandle, "StartImage:", NULL, 0); + // + // Image may be unloaded after return with failure, + // then ImageHandle may be invalid, so use NULL handle to record perf log. + // + PERF_START (NULL, "StartImage:", NULL, Tick); + PERF_END (NULL, "StartImage:", NULL, 0); + + // + // Pop the current start image context + // + mCurrentImage = LastImage; + return EFI_OUT_OF_RESOURCES; } Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT); @@ -1531,6 +1665,7 @@ CoreStartImage ( // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump(). // if (SetJumpFlag == 0) { + RegisterMemoryProfileImage (Image, (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ? EFI_FV_FILETYPE_APPLICATION : EFI_FV_FILETYPE_DRIVER)); // // Call the image's entry point // @@ -1568,9 +1703,17 @@ CoreStartImage ( mCurrentImage = LastImage; // - // Go connect any handles that were created or modified while the image executed. + // UEFI Specification - StartImage() - EFI 1.10 Extension + // To maintain compatibility with UEFI drivers that are written to the EFI + // 1.02 Specification, StartImage() must monitor the handle database before + // and after each image is started. If any handles are created or modified + // when an image is started, then EFI_BOOT_SERVICES.ConnectController() must + // be called with the Recursive parameter set to TRUE for each of the newly + // created or modified handles before StartImage() returns. // - CoreConnectHandlesByKey (HandleDatabaseKey); + if (Image->Type != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) { + CoreConnectHandlesByKey (HandleDatabaseKey); + } // // Handle the image's returned ExitData @@ -1611,12 +1754,17 @@ CoreStartImage ( // if (EFI_ERROR (Image->Status) || Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) { CoreUnloadAndCloseImage (Image, TRUE); + // + // ImageHandle may be invalid after the image is unloaded, so use NULL handle to record perf log. + // + Handle = NULL; } // // Done // - PERF_END (ImageHandle, "StartImage:", NULL, 0); + PERF_START (Handle, "StartImage:", NULL, Tick); + PERF_END (Handle, "StartImage:", NULL, 0); return Status; } @@ -1729,7 +1877,7 @@ Done: unloaded. @retval EFI_SUCCESS The image has been unloaded. - @retval EFI_UNSUPPORTED The image has been sarted, and does not support + @retval EFI_UNSUPPORTED The image has been started, and does not support unload. @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.