/** Support routine to get the Image read file function. @param ImageContext - The context of the image being loaded @retval EFI_SUCCESS - If Image function location is found **/ EFI_STATUS GetImageReadFunction ( IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext ) { PEI_CORE_INSTANCE *Private; VOID* MemoryBuffer; Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ()); if (Private->PeiMemoryInstalled && ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) || PcdGetBool (PcdShadowPeimOnS3Boot)) && (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64) || EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_IA32))) { // // Shadow algorithm makes lots of non ANSI C assumptions and only works for IA32 and X64 // compilers that have been tested // if (Private->ShadowedImageRead == NULL) { MemoryBuffer = AllocatePages (0x400 / EFI_PAGE_SIZE + 1); ASSERT (MemoryBuffer != NULL); CopyMem (MemoryBuffer, (CONST VOID *) (UINTN) PeiImageReadForShadow, 0x400); Private->ShadowedImageRead = (PE_COFF_LOADER_READ_FILE) (UINTN) MemoryBuffer; } ImageContext->ImageRead = Private->ShadowedImageRead; } else { ImageContext->ImageRead = PeiImageRead; } 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; }
/** Initialize all the stuff needed for on-demand paging hooks for PI<->Framework CpuSaveStates marshalling. @param[in] FrameworkSmst Framework SMM system table pointer. **/ VOID InitHook ( IN EFI_SMM_SYSTEM_TABLE *FrameworkSmst ) { UINTN NumCpuStatePages; UINTN CpuStatePage; UINTN Bottom2MPage; UINTN Top2MPage; mPageTableHookEnabled = FALSE; NumCpuStatePages = EFI_SIZE_TO_PAGES (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE)); // // Only hook page table for X64 image and less than 2MB needed to hold all CPU Save States // if (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64) && NumCpuStatePages <= EFI_SIZE_TO_PAGES (SIZE_2MB)) { // // Allocate double page size to make sure all CPU Save States are in one 2MB page. // CpuStatePage = (UINTN)AllocatePages (NumCpuStatePages * 2); ASSERT (CpuStatePage != 0); Bottom2MPage = CpuStatePage & ~(SIZE_2MB-1); Top2MPage = (CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages * 2) - 1) & ~(SIZE_2MB-1); if (Bottom2MPage == Top2MPage || CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages * 2) - Top2MPage >= EFI_PAGES_TO_SIZE (NumCpuStatePages) ) { // // If the allocated 4KB pages are within the same 2MB page or higher portion is larger, use higher portion pages. // FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)(CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages)); FreePages ((VOID*)CpuStatePage, NumCpuStatePages); } else { FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)CpuStatePage; FreePages ((VOID*)(CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages)), NumCpuStatePages); } // // Add temporary working buffer for hooking // mShadowSaveState = (EFI_SMM_CPU_SAVE_STATE*) AllocatePool (sizeof (EFI_SMM_CPU_SAVE_STATE)); ASSERT (mShadowSaveState != NULL); // // Allocate and initialize 4KB Page Table for hooking CpuSaveState. // Replace the original 2MB PDE with new 4KB page table. // mCpuStatePageTable = InitCpuStatePageTable (FrameworkSmst->CpuSaveState); // // Mark PTE for CpuSaveState as non-exist. // HookCpuStateMemory (FrameworkSmst->CpuSaveState); HookPageFaultHandler (); CpuFlushTlb (); mPageTableHookEnabled = TRUE; } mHookInitialized = TRUE; }
/** Routine to load image file for subsequent execution by LoadFile Ppi. If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE XIP image format is used. @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation @param FileHandle - Pointer to the FFS file header of the image. @param PeimState - The dispatch state of the input PEIM handle. @param EntryPoint - Pointer to entry point of specified image file for output. @param AuthenticationState - Pointer to attestation authentication state of image. @retval EFI_SUCCESS - Image is successfully loaded. @retval EFI_NOT_FOUND - Fail to locate necessary PPI @retval Others - Fail to load file. **/ EFI_STATUS PeiLoadImage ( IN CONST EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_FILE_HANDLE FileHandle, IN UINT8 PeimState, OUT EFI_PHYSICAL_ADDRESS *EntryPoint, OUT UINT32 *AuthenticationState ) { EFI_STATUS PpiStatus; EFI_STATUS Status; UINTN Index; EFI_PEI_LOAD_FILE_PPI *LoadFile; EFI_PHYSICAL_ADDRESS ImageAddress; UINT64 ImageSize; BOOLEAN IsStrip; IsStrip = FALSE; // // If any instances of PEI_LOAD_FILE_PPI are installed, they are called. // one at a time, until one reports EFI_SUCCESS. // Index = 0; do { PpiStatus = PeiServicesLocatePpi ( &gEfiPeiLoadFilePpiGuid, Index, NULL, (VOID **)&LoadFile ); if (!EFI_ERROR (PpiStatus)) { Status = LoadFile->LoadFile ( LoadFile, FileHandle, &ImageAddress, &ImageSize, EntryPoint, AuthenticationState ); if (!EFI_ERROR (Status) || Status == EFI_WARN_BUFFER_TOO_SMALL) { // // The shadowed PEIM must be relocatable. // if (PeimState == PEIM_STATE_REGISITER_FOR_SHADOW) { IsStrip = RelocationIsStrip ((VOID *) (UINTN) ImageAddress); ASSERT (!IsStrip); if (IsStrip) { return EFI_UNSUPPORTED; } } // // The image to be started must have the machine type supported by PeiCore. // ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress))); if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress))) { return EFI_UNSUPPORTED; } return EFI_SUCCESS; } } Index++; } while (!EFI_ERROR (PpiStatus)); return PpiStatus; }
/** Loads a PEIM into memory for subsequent execution. If there are compressed images or images that need to be relocated into memory for performance reasons, this service performs that transformation. @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation @param FileHandle Pointer to the FFS file header of the image. @param ImageAddressArg Pointer to PE/TE image. @param ImageSizeArg Size of PE/TE image. @param EntryPoint Pointer to entry point of specified image file for output. @param AuthenticationState - Pointer to attestation authentication state of image. @retval EFI_SUCCESS Image is successfully loaded. @retval EFI_NOT_FOUND Fail to locate necessary PPI. @retval EFI_UNSUPPORTED Image Machine Type is not supported. @retval EFI_WARN_BUFFER_TOO_SMALL There is not enough heap to allocate the requested size. This will not prevent the XIP image from being invoked. **/ EFI_STATUS PeiLoadImageLoadImage ( IN CONST EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_FILE_HANDLE FileHandle, OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL OUT UINT64 *ImageSizeArg, OPTIONAL OUT EFI_PHYSICAL_ADDRESS *EntryPoint, OUT UINT32 *AuthenticationState ) { EFI_STATUS Status; VOID *Pe32Data; EFI_PHYSICAL_ADDRESS ImageAddress; UINT64 ImageSize; EFI_PHYSICAL_ADDRESS ImageEntryPoint; UINT16 Machine; EFI_SECTION_TYPE SearchType1; EFI_SECTION_TYPE SearchType2; *EntryPoint = 0; ImageSize = 0; *AuthenticationState = 0; if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) { SearchType1 = EFI_SECTION_TE; SearchType2 = EFI_SECTION_PE32; } else { SearchType1 = EFI_SECTION_PE32; SearchType2 = EFI_SECTION_TE; } // // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst // is true, TE will be searched first). // Status = PeiServicesFfsFindSectionData3 ( SearchType1, 0, FileHandle, &Pe32Data, AuthenticationState ); // // If we didn't find a first exe section, try to find the second exe section. // if (EFI_ERROR (Status)) { Status = PeiServicesFfsFindSectionData3 ( SearchType2, 0, FileHandle, &Pe32Data, AuthenticationState ); if (EFI_ERROR (Status)) { // // PEI core only carry the loader function for TE and PE32 executables // If this two section does not exist, just return. // return Status; } } // // If memory is installed, perform the shadow operations // Status = LoadAndRelocatePeCoffImage ( Pe32Data, &ImageAddress, &ImageSize, &ImageEntryPoint ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } // // Got the entry point from the loaded Pe32Data // Pe32Data = (VOID *) ((UINTN) ImageAddress); *EntryPoint = ImageEntryPoint; Machine = PeCoffLoaderGetMachineType (Pe32Data); if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) { if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) { return EFI_UNSUPPORTED; } } if (ImageAddressArg != NULL) { *ImageAddressArg = ImageAddress; } if (ImageSizeArg != NULL) { *ImageSizeArg = ImageSize; } DEBUG_CODE_BEGIN (); CHAR8 *AsciiString; CHAR8 EfiFileName[512]; INT32 Index; INT32 StartIndex; // // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi // if (Machine != EFI_IMAGE_MACHINE_IA64) { DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint)); } else { // // For IPF Image, the real entry point should be print. // DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint))); } // // Print Module Name by PeImage PDB file name. // AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data); if (AsciiString != NULL) { StartIndex = 0; for (Index = 0; AsciiString[Index] != 0; Index++) { if (AsciiString[Index] == '\\' || AsciiString[Index] == '/') { StartIndex = Index + 1; } } // // Copy the PDB file name to our temporary string, and replace .pdb with .efi // The PDB file name is limited in the range of 0~511. // If the length is bigger than 511, trim the redudant characters to avoid overflow in array boundary. // for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { EfiFileName[Index] = AsciiString[Index + StartIndex]; if (EfiFileName[Index] == 0) { EfiFileName[Index] = '.'; } if (EfiFileName[Index] == '.') { EfiFileName[Index + 1] = 'e'; EfiFileName[Index + 2] = 'f'; EfiFileName[Index + 3] = 'i'; EfiFileName[Index + 4] = 0; break; } } if (Index == sizeof (EfiFileName) - 4) { EfiFileName[Index] = 0; } DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a", EfiFileName)); } DEBUG_CODE_END (); DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n")); return EFI_SUCCESS; }
/** Loads a PEIM into memory for subsequent execution. If there are compressed images or images that need to be relocated into memory for performance reasons, this service performs that transformation. @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation @param FileHandle Pointer to the FFS file header of the image. @param ImageAddressArg Pointer to PE/TE image. @param ImageSizeArg Size of PE/TE image. @param EntryPoint Pointer to entry point of specified image file for output. @param AuthenticationState - Pointer to attestation authentication state of image. @retval EFI_SUCCESS Image is successfully loaded. @retval EFI_NOT_FOUND Fail to locate necessary PPI. @retval EFI_UNSUPPORTED Image Machine Type is not supported. **/ EFI_STATUS PeiLoadImageLoadImage ( IN CONST EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_FILE_HANDLE FileHandle, OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL OUT UINT64 *ImageSizeArg, OPTIONAL OUT EFI_PHYSICAL_ADDRESS *EntryPoint, OUT UINT32 *AuthenticationState ) { EFI_STATUS Status; VOID *Pe32Data; EFI_PHYSICAL_ADDRESS ImageAddress; UINT64 ImageSize; EFI_PHYSICAL_ADDRESS ImageEntryPoint; UINT16 Machine; EFI_SECTION_TYPE SearchType1; EFI_SECTION_TYPE SearchType2; *EntryPoint = 0; ImageSize = 0; *AuthenticationState = 0; if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) { SearchType1 = EFI_SECTION_TE; SearchType2 = EFI_SECTION_PE32; } else { SearchType1 = EFI_SECTION_PE32; SearchType2 = EFI_SECTION_TE; } // // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst // is true, TE will be searched first). // Status = PeiServicesFfsFindSectionData ( SearchType1, FileHandle, &Pe32Data ); // // If we didn't find a first exe section, try to find the second exe section. // if (EFI_ERROR (Status)) { Status = PeiServicesFfsFindSectionData ( SearchType2, FileHandle, &Pe32Data ); if (EFI_ERROR (Status)) { // // PEI core only carry the loader function fro TE and PE32 executables // If this two section does not exist, just return. // return Status; } } // // If memory is installed, perform the shadow operations // Status = LoadAndRelocatePeCoffImage ( Pe32Data, &ImageAddress, &ImageSize, &ImageEntryPoint ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } // // Got the entry point from the loaded Pe32Data // Pe32Data = (VOID *) ((UINTN) ImageAddress); *EntryPoint = ImageEntryPoint; Machine = PeCoffLoaderGetMachineType (Pe32Data); if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) { if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) { return EFI_UNSUPPORTED; } } if (ImageAddressArg != NULL) { *ImageAddressArg = ImageAddress; } if (ImageSizeArg != NULL) { *ImageSizeArg = ImageSize; } DEBUG_CODE_BEGIN (); CHAR8 *AsciiString; CHAR8 AsciiBuffer[512]; INT32 Index; INT32 Index1; // // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi // if (Machine != EFI_IMAGE_MACHINE_IA64) { DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint)); } else { // // For IPF Image, the real entry point should be print. // DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint))); } // // Print Module Name by PeImage PDB file name. // AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data); if (AsciiString != NULL) { for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) { if (AsciiString[Index] == '\\') { break; } } if (Index != 0) { for (Index1 = 0; AsciiString[Index + 1 + Index1] != '.'; Index1 ++) { AsciiBuffer [Index1] = AsciiString[Index + 1 + Index1]; } AsciiBuffer [Index1] = '\0'; DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a.efi", AsciiBuffer)); } } DEBUG_CODE_END (); DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n")); return EFI_SUCCESS; }
/** Support routine to get the Image read file function. @param ImageContext - The context of the image being loaded @retval EFI_SUCCESS - If Image function location is found **/ EFI_STATUS GetImageReadFunction ( IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext ) { PEI_CORE_INSTANCE *Private; VOID* MemoryBuffer; Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ()); if (!Private->PeiMemoryInstalled || (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) || EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_IA64)) { ImageContext->ImageRead = PeiImageRead; } else { if (Private->ShadowedImageRead == NULL) { MemoryBuffer = AllocatePages (0x400 / EFI_PAGE_SIZE + 1); ASSERT (MemoryBuffer != NULL); CopyMem (MemoryBuffer, (CONST VOID *) (UINTN) PeiImageReadForShadow, 0x400); Private->ShadowedImageRead = (PE_COFF_LOADER_READ_FILE) (UINTN) MemoryBuffer; } ImageContext->ImageRead = Private->ShadowedImageRead; } return EFI_SUCCESS; }