/** Loads an EFI image into SMRAM. @param DriverEntry EFI_SMM_DRIVER_ENTRY instance @return EFI_STATUS **/ EFI_STATUS EFIAPI SmmLoadImage ( IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry ) { UINT32 AuthenticationStatus; UINTN FilePathSize; VOID *Buffer; UINTN Size; UINTN PageCount; EFI_GUID *NameGuid; EFI_STATUS Status; EFI_STATUS SecurityStatus; EFI_HANDLE DeviceHandle; EFI_PHYSICAL_ADDRESS DstBuffer; EFI_DEVICE_PATH_PROTOCOL *FilePath; EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath; EFI_DEVICE_PATH_PROTOCOL *HandleFilePath; EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; Buffer = NULL; Size = 0; Fv = DriverEntry->Fv; NameGuid = &DriverEntry->FileName; FilePath = DriverEntry->FvFileDevicePath; OriginalFilePath = FilePath; HandleFilePath = FilePath; DeviceHandle = NULL; SecurityStatus = EFI_SUCCESS; Status = EFI_SUCCESS; AuthenticationStatus = 0; // // Try to get the image device handle by checking the match protocol. // Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle); if (EFI_ERROR(Status)) { return Status; } // // If the Security Architectural Protocol has not been located yet, then attempt to locate it // if (mSecurity == NULL) { gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity); } // // Verify the Authentication Status through the Security Architectural Protocol // if ((mSecurity != NULL) && (OriginalFilePath != NULL)) { SecurityStatus = mSecurity->FileAuthenticationState ( mSecurity, AuthenticationStatus, OriginalFilePath ); if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) { Status = SecurityStatus; return Status; } } // // Pull out just the file portion of the DevicePath for the LoadedImage FilePath // FilePath = OriginalFilePath; Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath); if (!EFI_ERROR (Status)) { FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL); FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize ); } // // Try reading PE32 section firstly // Status = Fv->ReadSection ( Fv, NameGuid, EFI_SECTION_PE32, 0, &Buffer, &Size, &AuthenticationStatus ); if (EFI_ERROR (Status)) { // // Try reading TE section secondly // Buffer = NULL; Size = 0; Status = Fv->ReadSection ( Fv, NameGuid, EFI_SECTION_TE, 0, &Buffer, &Size, &AuthenticationStatus ); } if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } // // Initialize ImageContext // ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } // // if Loading module at Fixed Address feature is enabled, then cut out a memory range started from TESG BASE // to hold the Smm driver code // if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { // // Get the fixed loading address assigned by Build tool // Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext); if (!EFI_ERROR (Status)) { // // Since the memory range to load Smm core alreay been cut out, so no need to allocate and free this range // following statements is to bypass SmmFreePages // PageCount = 0; DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase; } else { DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); // // allocate the memory to load the SMM driver // PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); DstBuffer = (UINTN)(-1); Status = SmmAllocatePages ( AllocateMaxAddress, EfiRuntimeServicesCode, PageCount, &DstBuffer ); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; } } else { PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); DstBuffer = (UINTN)(-1); Status = SmmAllocatePages ( AllocateMaxAddress, EfiRuntimeServicesCode, PageCount, &DstBuffer ); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; } // // Align buffer on section boundry // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } // // Flush the instruction cache so the image data are written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize); // // Save Image EntryPoint in DriverEntry // DriverEntry->ImageEntryPoint = ImageContext.EntryPoint; DriverEntry->ImageBuffer = DstBuffer; DriverEntry->NumberOfPage = PageCount; // // Allocate a Loaded Image Protocol in EfiBootServicesData // Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } // // Fill in the remaining fields of the Loaded Image Protocol instance. // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed. // DriverEntry->LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; DriverEntry->LoadedImage->ParentHandle = gSmmCorePrivate->SmmIplImageHandle; DriverEntry->LoadedImage->SystemTable = gST; DriverEntry->LoadedImage->DeviceHandle = DeviceHandle; // // Make an EfiBootServicesData buffer copy of FilePath // Status = gBS->AllocatePool (EfiBootServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->LoadedImage->FilePath); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath)); DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)DriverEntry->ImageBuffer; DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize; DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode; DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData; // // Create a new image handle in the UEFI handle database for the SMM Driver // DriverEntry->ImageHandle = NULL; Status = gBS->InstallMultipleProtocolInterfaces ( &DriverEntry->ImageHandle, &gEfiLoadedImageProtocolGuid, DriverEntry->LoadedImage, NULL ); // // Print the load address and the PDB file name if it is available // DEBUG_CODE_BEGIN (); UINTN Index; UINTN StartIndex; CHAR8 EfiFileName[256]; DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading SMM driver at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN) ImageContext.ImageAddress, FUNCTION_ENTRY_POINT (ImageContext.EntryPoint))); // // Print Module Name by Pdb file path. // Windows and Unix style file path are all trimmed correctly. // if (ImageContext.PdbPointer != NULL) { StartIndex = 0; for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) { if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[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~255. // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary. // for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { EfiFileName[Index] = ImageContext.PdbPointer[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 ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex])); } DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n")); DEBUG_CODE_END (); // // Free buffer allocated by Fv->ReadSection. // // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection // used the UEFI Boot Services AllocatePool() function // Status = gBS->FreePool(Buffer); return Status; }
/** Loads and relocates a PE/COFF image into memory. If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image. @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated @param ImageAddress - The base address of the relocated PE/COFF image @param ImageSize - The size of the relocated PE/COFF image @param EntryPoint - The entry point of the relocated PE/COFF image @retval EFI_SUCCESS The file was loaded and relocated @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file @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 LoadAndRelocatePeCoffImage ( IN VOID *Pe32Data, OUT EFI_PHYSICAL_ADDRESS *ImageAddress, OUT UINT64 *ImageSize, OUT EFI_PHYSICAL_ADDRESS *EntryPoint ) { EFI_STATUS Status; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; PEI_CORE_INSTANCE *Private; UINT64 AlignImageSize; BOOLEAN IsXipImage; EFI_STATUS ReturnStatus; Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ()); ReturnStatus = EFI_SUCCESS; IsXipImage = FALSE; ZeroMem (&ImageContext, sizeof (ImageContext)); ImageContext.Handle = Pe32Data; Status = GetImageReadFunction (&ImageContext); ASSERT_EFI_ERROR (Status); Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // XIP image that ImageAddress is same to Image handle. // if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) { IsXipImage = TRUE; } // // When Image has no reloc section, it can't be relocated into memory. // if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) { DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data)); } // // Set default base address to current image address. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data; // // Allocate Memory for the image when memory is ready, boot mode is not S3, and image is relocatable. // if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) { // // Allocate more buffer to avoid buffer overflow. // if (ImageContext.IsTeImage) { AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); } else { AlignImageSize = ImageContext.ImageSize; } if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { AlignImageSize += ImageContext.SectionAlignment; } if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private); if (EFI_ERROR (Status)){ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); // // The PEIM is not assiged valid address, try to allocate page to load it. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize)); } } else { ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize)); } if (ImageContext.ImageAddress != 0) { // // Adjust the Image Address to make sure it is section alignment. // if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { ImageContext.ImageAddress = (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) & ~((UINTN)ImageContext.SectionAlignment - 1); } // // Fix alignment requirement when Load IPF TeImage into memory. // Skip the reserved space for the stripped PeHeader when load TeImage into memory. // if (ImageContext.IsTeImage) { ImageContext.ImageAddress = ImageContext.ImageAddress + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); } } else { // // No enough memory resource. // if (IsXipImage) { // // XIP image can still be invoked. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data; ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL; } else { // // Non XIP image can't be loaded because no enough memory is allocated. // ASSERT (FALSE); return EFI_OUT_OF_RESOURCES; } } } // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // Flush the instruction cache so the image data is written before we execute it // if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) { InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); } *ImageAddress = ImageContext.ImageAddress; *ImageSize = ImageContext.ImageSize; *EntryPoint = ImageContext.EntryPoint; return ReturnStatus; }
/** Loads and relocates a PE/COFF image into memory. If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image. @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated @param ImageAddress - The base address of the relocated PE/COFF image @param ImageSize - The size of the relocated PE/COFF image @param EntryPoint - The entry point of the relocated PE/COFF image @retval EFI_SUCCESS The file was loaded and relocated @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file **/ EFI_STATUS LoadAndRelocatePeCoffImage ( IN VOID *Pe32Data, OUT EFI_PHYSICAL_ADDRESS *ImageAddress, OUT UINT64 *ImageSize, OUT EFI_PHYSICAL_ADDRESS *EntryPoint ) { EFI_STATUS Status; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; PEI_CORE_INSTANCE *Private; Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ()); ZeroMem (&ImageContext, sizeof (ImageContext)); ImageContext.Handle = Pe32Data; Status = GetImageReadFunction (&ImageContext); ASSERT_EFI_ERROR (Status); Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // When Image has no reloc section, it can't be relocated into memory. // if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data)); } // // Set default base address to current image address. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data; // // Allocate Memory for the image when memory is ready, boot mode is not S3, and image is relocatable. // if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private); if (EFI_ERROR (Status)){ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); // // The PEIM is not assiged valid address, try to allocate page to load it. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize)); } } else { ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize)); } ASSERT (ImageContext.ImageAddress != 0); if (ImageContext.ImageAddress == 0) { return EFI_OUT_OF_RESOURCES; } // // Skip the reserved space for the stripped PeHeader when load TeImage into memory. // if (ImageContext.IsTeImage) { ImageContext.ImageAddress = ImageContext.ImageAddress + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); } } // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // Flush the instruction cache so the image data is written before we execute it // if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); } *ImageAddress = ImageContext.ImageAddress; *ImageSize = ImageContext.ImageSize; *EntryPoint = ImageContext.EntryPoint; return EFI_SUCCESS; }
/** Loads and relocates a PE/COFF image into memory. If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image. @param FileHandle - Pointer to the FFS file header of the image. @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated @param ImageAddress - The base address of the relocated PE/COFF image @param ImageSize - The size of the relocated PE/COFF image @param EntryPoint - The entry point of the relocated PE/COFF image @retval EFI_SUCCESS The file was loaded and relocated @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file @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 LoadAndRelocatePeCoffImage ( IN EFI_PEI_FILE_HANDLE FileHandle, IN VOID *Pe32Data, OUT EFI_PHYSICAL_ADDRESS *ImageAddress, OUT UINT64 *ImageSize, OUT EFI_PHYSICAL_ADDRESS *EntryPoint ) { EFI_STATUS Status; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; PEI_CORE_INSTANCE *Private; UINT64 AlignImageSize; BOOLEAN IsXipImage; EFI_STATUS ReturnStatus; BOOLEAN IsS3Boot; BOOLEAN IsPeiModule; BOOLEAN IsRegisterForShadow; EFI_FV_FILE_INFO FileInfo; Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ()); ReturnStatus = EFI_SUCCESS; IsXipImage = FALSE; ZeroMem (&ImageContext, sizeof (ImageContext)); ImageContext.Handle = Pe32Data; ImageContext.ImageRead = PeiImageRead; Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // Initilize local IsS3Boot and IsRegisterForShadow variable // IsS3Boot = FALSE; if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) { IsS3Boot = TRUE; } IsRegisterForShadow = FALSE; if ((Private->CurrentFileHandle == FileHandle) && (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW)) { IsRegisterForShadow = TRUE; } // // XIP image that ImageAddress is same to Image handle. // if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) { IsXipImage = TRUE; } // // Get file type first // Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo); ASSERT_EFI_ERROR (Status); // // Check whether the file type is PEI module. // IsPeiModule = FALSE; if (FileInfo.FileType == EFI_FV_FILETYPE_PEI_CORE || FileInfo.FileType == EFI_FV_FILETYPE_PEIM || FileInfo.FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER) { IsPeiModule = TRUE; } // // When Image has no reloc section, it can't be relocated into memory. // if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && ((!IsPeiModule) || (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) { DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data)); } // // Set default base address to current image address. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data; // // Allocate Memory for the image when memory is ready, and image is relocatable. // On normal boot, PcdShadowPeimOnBoot decides whether load PEIM or PeiCore into memory. // On S3 boot, PcdShadowPeimOnS3Boot decides whether load PEIM or PeiCore into memory. // if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && ((!IsPeiModule) || (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) { // // Allocate more buffer to avoid buffer overflow. // if (ImageContext.IsTeImage) { AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); } else { AlignImageSize = ImageContext.ImageSize; } if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { AlignImageSize += ImageContext.SectionAlignment; } if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private); if (EFI_ERROR (Status)){ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); // // The PEIM is not assiged valid address, try to allocate page to load it. // Status = PeiServicesAllocatePages (EfiBootServicesCode, EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize), &ImageContext.ImageAddress); } } else { Status = PeiServicesAllocatePages (EfiBootServicesCode, EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize), &ImageContext.ImageAddress); } if (!EFI_ERROR (Status)) { // // Adjust the Image Address to make sure it is section alignment. // if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { ImageContext.ImageAddress = (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) & ~((UINTN)ImageContext.SectionAlignment - 1); } // // Fix alignment requirement when Load IPF TeImage into memory. // Skip the reserved space for the stripped PeHeader when load TeImage into memory. // if (ImageContext.IsTeImage) { ImageContext.ImageAddress = ImageContext.ImageAddress + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); } } else { // // No enough memory resource. // if (IsXipImage) { // // XIP image can still be invoked. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data; ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL; } else { // // Non XIP image can't be loaded because no enough memory is allocated. // ASSERT (FALSE); return EFI_OUT_OF_RESOURCES; } } } // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { if (ImageContext.ImageError == IMAGE_ERROR_INVALID_SECTION_ALIGNMENT) { DEBUG ((DEBUG_ERROR, "PEIM Image Address 0x%11p doesn't meet with section alignment 0x%x.\n", (VOID*)(UINTN)ImageContext.ImageAddress, ImageContext.SectionAlignment)); } return Status; } // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // Flush the instruction cache so the image data is written before we execute it // if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) { InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); } *ImageAddress = ImageContext.ImageAddress; *ImageSize = ImageContext.ImageSize; *EntryPoint = ImageContext.EntryPoint; return ReturnStatus; }
/** Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM. @param[in] SmramRange Descriptor for the range of SMRAM to reload the currently executing image. @param[in] Context Context to pass into SMM Core @return EFI_STATUS **/ EFI_STATUS ExecuteSmmCoreFromSmram ( IN EFI_SMRAM_DESCRIPTOR *SmramRange, IN VOID *Context ) { EFI_STATUS Status; VOID *SourceBuffer; UINTN SourceSize; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; UINTN PageCount; EFI_PHYSICAL_ADDRESS DestinationBuffer; EFI_IMAGE_ENTRY_POINT EntryPoint; // // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE // Status = GetSectionFromAnyFvByFileType ( EFI_FV_FILETYPE_SMM_CORE, 0, EFI_SECTION_PE32, 0, &SourceBuffer, &SourceSize ); if (EFI_ERROR (Status)) { return Status; } // // Initilize ImageContext // ImageContext.Handle = SourceBuffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to // the address assigned by build tool. // if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { // // Get the fixed loading address assigned by Build tool // Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext); if (!EFI_ERROR (Status)) { // // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range // PageCount = 0; } else { DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR: Loading module at fixed address at address failed\n")); // // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR // specified by SmramRange // PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0); ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount)); SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount); DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize; // // Align buffer on section boundry // ImageContext.ImageAddress = DestinationBuffer; } } else { // // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR // specified by SmramRange // PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0); ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount)); SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount); DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize; // // Align buffer on section boundry // ImageContext.ImageAddress = DestinationBuffer; } ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); // // Print debug message showing SMM Core load address. // DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress)); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); if (!EFI_ERROR (Status)) { // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (!EFI_ERROR (Status)) { // // Flush the instruction cache so the image data are written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); // // Print debug message showing SMM Core entry point address. // DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint)); // // Execute image // EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint; Status = EntryPoint ((EFI_HANDLE)Context, gST); } } // // If the load operation, relocate operation, or the image execution return an // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR specified by // SmramRange // if (EFI_ERROR (Status)) { SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount); } // // Always free memory allocted by GetFileBufferByFilePath () // FreePool (SourceBuffer); return Status; }