/*++ Copyright (c) 2006 - 2007, 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 http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Module Name: Image.c Abstract: Pei Core Load Image Support --*/ #include EFI_STATUS PeiLoadImage ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_FFS_FILE_HEADER *PeimFileHeader, OUT VOID **EntryPoint ) /*++ Routine Description: Routine for loading file image. Arguments: PeiServices - The PEI core services table. PeimFileHeader - Pointer to the FFS file header of the image. EntryPoint - Pointer to entry point of specified image file for output. Returns: Status - EFI_SUCCESS - Image is successfully loaded. EFI_NOT_FOUND - Fail to locate necessary PPI Others - Fail to load file. --*/ { EFI_STATUS Status; VOID *Pe32Data; EFI_PEI_FV_FILE_LOADER_PPI *FvLoadFilePpi; EFI_PHYSICAL_ADDRESS ImageAddress; UINT64 ImageSize; EFI_PHYSICAL_ADDRESS ImageEntryPoint; EFI_TE_IMAGE_HEADER *TEImageHeader; UINT16 Machine; *EntryPoint = NULL; TEImageHeader = NULL; // // Try to find a PE32 section. // Status = PeiServicesFfsFindSectionData ( EFI_SECTION_PE32, PeimFileHeader, &Pe32Data ); // // If we didn't find a PE32 section, try to find a TE section. // if (EFI_ERROR (Status)) { Status = PeiServicesFfsFindSectionData ( EFI_SECTION_TE, PeimFileHeader, (VOID **) &TEImageHeader ); if (EFI_ERROR (Status) || TEImageHeader == NULL) { // // There was not a PE32 or a TE section, so assume that it's a Compressed section // and use the LoadFile // Status = PeiServicesLocatePpi ( &gEfiPeiFvFileLoaderPpiGuid, 0, NULL, (VOID **)&FvLoadFilePpi ); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } Status = FvLoadFilePpi->FvLoadFile ( FvLoadFilePpi, PeimFileHeader, &ImageAddress, &ImageSize, &ImageEntryPoint ); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } // // Got the entry point from ImageEntryPoint and ImageStartAddress // Pe32Data = (VOID *) ((UINTN) ImageAddress); *EntryPoint = (VOID *) ((UINTN) ImageEntryPoint); } else { // // Retrieve the entry point from the TE image header // ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) TEImageHeader; *EntryPoint = (VOID *)((UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) + TEImageHeader->AddressOfEntryPoint - TEImageHeader->StrippedSize); } } else { // // Retrieve the entry point from the PE/COFF image header // ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Pe32Data; Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } } if (((EFI_TE_IMAGE_HEADER *) (UINTN) ImageAddress)->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { TEImageHeader = (EFI_TE_IMAGE_HEADER *) (UINTN) ImageAddress; Machine = TEImageHeader->Machine; } else { Machine = PeCoffLoaderGetMachineType (Pe32Data); } if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) { return EFI_UNSUPPORTED; } // // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi // DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%08x EntryPoint=0x%08x ", (UINTN) ImageAddress, *EntryPoint)); DEBUG_CODE_BEGIN (); EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry; EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; UINTN DirCount; UINTN Index; UINTN Index1; BOOLEAN FileNameFound; CHAR8 *AsciiString; CHAR8 AsciiBuffer[512]; VOID *CodeViewEntryPointer; INTN TEImageAdjust; EFI_IMAGE_DOS_HEADER *DosHeader; EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; UINT32 NumberOfRvaAndSizes; Hdr.Pe32 = NULL; if (TEImageHeader == NULL) { DosHeader = (EFI_IMAGE_DOS_HEADER *)Pe32Data; if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) { // // DOS image header is present, so read the PE header after the DOS image header // Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHeader->e_lfanew) & 0x0ffff)); } else { // // DOS image header is not present, so PE header is at the image base // Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; } } // // Find the codeview info in the image and display the file name // being loaded. // // Per the PE/COFF spec, you can't assume that a given data directory // is present in the image. You have to check the NumberOfRvaAndSizes in // the optional header to verify a desired directory entry is there. // DebugEntry = NULL; DirectoryEntry = NULL; NumberOfRvaAndSizes = 0; TEImageAdjust = 0; if (TEImageHeader == NULL) { if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // // Use PE32 offset get Debug Directory Entry // NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress); } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { // // Use PE32+ offset get Debug Directory Entry // NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress); } if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { DirectoryEntry = NULL; DebugEntry = NULL; } } else { if (TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) { DirectoryEntry = &TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG]; TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize; DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) TEImageHeader + TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress + TEImageAdjust); } } if (DebugEntry != NULL && DirectoryEntry != NULL) { for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) { if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { if (DebugEntry->SizeOfData > 0) { CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + (UINTN) ImageAddress + (UINTN)TEImageAdjust); switch (* (UINT32 *) CodeViewEntryPointer) { case CODEVIEW_SIGNATURE_NB10: AsciiString = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY); break; case CODEVIEW_SIGNATURE_RSDS: AsciiString = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY); break; default: AsciiString = NULL; break; } if (AsciiString != NULL) { FileNameFound = FALSE; for (Index = 0, Index1 = 0; AsciiString[Index] != '\0'; Index++) { if (AsciiString[Index] == '\\') { Index1 = Index; FileNameFound = TRUE; } } if (FileNameFound) { for (Index = Index1 + 1; AsciiString[Index] != '.'; Index++) { AsciiBuffer[Index - (Index1 + 1)] = AsciiString[Index]; } AsciiBuffer[Index - (Index1 + 1)] = 0; DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a.efi", AsciiBuffer)); break; } } } } } } DEBUG_CODE_END (); DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n")); return EFI_SUCCESS; }