VOID SetBreakpoint ( IN UINT32 Address ) { ARM_SOFTWARE_BREAKPOINT *Breakpoint; Breakpoint = SearchBreakpointList (Address); if (Breakpoint != NULL) { return; } // create and fill breakpoint structure Breakpoint = AllocatePool (sizeof(ARM_SOFTWARE_BREAKPOINT)); Breakpoint->Signature = ARM_SOFTWARE_BREAKPOINT_SIGNATURE; Breakpoint->Address = Address; Breakpoint->Instruction = *(UINT32 *)Address; // Add it to the list InsertTailList (&BreakpointList, &Breakpoint->Link); // Insert the software breakpoint *(UINT32 *)Address = GDB_ARM_BKPT; InvalidateInstructionCacheRange ((VOID *)Address, 4); //DEBUG((EFI_D_ERROR, "SetBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, Breakpoint->Instruction, *(UINT32 *)Address)); }
/** Initialize debug agent. This function is used to set up debug environment to support source level debugging. If certain Debug Agent Library instance has to save some private data in the stack, this function must work on the mode that doesn't return to the caller, then the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is responsible to invoke the passing-in function at the end of InitializeDebugAgent(). If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by passing in the Context to be its parameter. If Function() is NULL, Debug Agent Library instance will return after setup debug environment. @param[in] InitFlag Init flag is used to decide the initialize process. @param[in] Context Context needed according to InitFlag; it was optional. @param[in] Function Continue function called by debug agent library; it was optional. **/ VOID EFIAPI InitializeDebugAgent ( IN UINT32 InitFlag, IN VOID *Context, OPTIONAL IN DEBUG_AGENT_CONTINUE Function OPTIONAL ) { UINTN Offset; UINTN Length; BOOLEAN IrqEnabled; UINT64 *VectorBase; // // Disable interrupts // IrqEnabled = ArmGetInterruptState (); ArmDisableInterrupts (); ArmDisableFiq (); // // Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress. // Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart; // // Reserve space for the exception handlers // VectorBase = (UINT64 *)(UINTN)PcdGet64 (PcdCpuVectorBaseAddress); // Copy our assembly code into the page that contains the exception vectors. CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length); // // Patch in the common Assembly exception handler // Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart; *(UINTN *) (((UINT8 *)VectorBase) + Offset) = (UINTN)AsmCommonExceptionEntry; // Flush Caches since we updated executable stuff InvalidateInstructionCacheRange ((VOID *)PcdGet64(PcdCpuVectorBaseAddress), Length); // setup a timer so gdb can break in via ctrl-c DebugAgentTimerIntialize (); if (IrqEnabled) { ArmEnableInterrupts (); } if (Function != NULL) { Function (Context); } return; }
EFI_STATUS EFIAPI LoadPeCoffImage ( IN VOID *PeCoffImage, OUT EFI_PHYSICAL_ADDRESS *ImageAddress, OUT UINT64 *ImageSize, OUT EFI_PHYSICAL_ADDRESS *EntryPoint ) { RETURN_STATUS Status; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; VOID *Buffer; ZeroMem (&ImageContext, sizeof (ImageContext)); ImageContext.Handle = PeCoffImage; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; Status = PeCoffLoaderGetImageInfo (&ImageContext); ASSERT_EFI_ERROR (Status); // // Allocate Memory for the image // Buffer = AllocatePages (EFI_SIZE_TO_PAGES((UINT32)ImageContext.ImageSize)); ASSERT (Buffer != 0); ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer; // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); ASSERT_EFI_ERROR (Status); *ImageAddress = ImageContext.ImageAddress; *ImageSize = ImageContext.ImageSize; *EntryPoint = ImageContext.EntryPoint; // // Flush not needed for all architectures. We could have a processor specific // function in this library that does the no-op if needed. // InvalidateInstructionCacheRange ((VOID *)(UINTN)*ImageAddress, (UINTN)*ImageSize); return Status; }
/** Remove Single Step in the SystemContext @param SystemContext Register content at time of the exception **/ VOID RemoveSingleStep ( IN EFI_SYSTEM_CONTEXT SystemContext ) { if (!mSingleStepActive) { return; } if (mSingleStepDataSize == sizeof (UINT16)) { *(UINT16 *)mSingleStepPC = (UINT16)mSingleStepData; } else { //DEBUG((EFI_D_ERROR, "RemoveSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, *(UINT32 *)mSingleStepPC, mSingleStepData)); *(UINT32 *)mSingleStepPC = mSingleStepData; } InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize); mSingleStepActive = FALSE; }
/** Insert Single Step in the SystemContext @param SystemContext Register content at time of the exception **/ VOID AddSingleStep ( IN EFI_SYSTEM_CONTEXT SystemContext ) { if (mSingleStepActive) { // Currently don't support nesting return; } mSingleStepActive = TRUE; mSingleStepPC = SystemContext.SystemContextArm->PC; mSingleStepDataSize = sizeof (UINT32); mSingleStepData = (*(UINT32 *)mSingleStepPC); *(UINT32 *)mSingleStepPC = GDB_ARM_BKPT; if (*(UINT32 *)mSingleStepPC != GDB_ARM_BKPT) { // For some reason our breakpoint did not take mSingleStepActive = FALSE; } InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize); //DEBUG((EFI_D_ERROR, "AddSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, mSingleStepData, *(UINT32 *)mSingleStepPC)); }
VOID ClearBreakpoint ( IN UINT32 Address ) { ARM_SOFTWARE_BREAKPOINT *Breakpoint; Breakpoint = SearchBreakpointList (Address); if (Breakpoint == NULL) { return; } // Add it to the list RemoveEntryList (&Breakpoint->Link); // Restore the original instruction *(UINT32 *)Address = Breakpoint->Instruction; InvalidateInstructionCacheRange ((VOID *)Address, 4); //DEBUG((EFI_D_ERROR, "ClearBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, GDB_ARM_BKPT, *(UINT32 *)Address)); FreePool (Breakpoint); }
/** 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; }
/** Relocate this image under 4G memory for IPF. @param ImageHandle Handle of driver image. @param SystemTable Pointer to system table. @retval EFI_SUCCESS Image successfully relocated. @retval EFI_ABORTED Failed to relocate image. **/ EFI_STATUS RelocateImageUnder4GIfNeeded ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; UINTN NumberOfPages; EFI_PHYSICAL_ADDRESS LoadedImageBase; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; EFI_PHYSICAL_ADDRESS MemoryAddress; EFI_HANDLE NewImageHandle; Status = gBS->HandleProtocol ( ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID *) &LoadedImage ); if (!EFI_ERROR (Status)) { LoadedImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) LoadedImage->ImageBase; if (LoadedImageBase > 0xffffffff) { NumberOfPages = (UINTN) (DivU64x32(LoadedImage->ImageSize, EFI_PAGE_SIZE) + 1); // // Allocate buffer below 4GB here // Status = AllocateLegacyMemory ( AllocateMaxAddress, 0x7FFFFFFF, NumberOfPages, // do we have to convert this to pages?? &MemoryAddress ); if (EFI_ERROR (Status)) { return Status; } ZeroMem (&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)); ImageContext.Handle = (VOID *)(UINTN)LoadedImageBase; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } ImageContext.ImageAddress = (PHYSICAL_ADDRESS)MemoryAddress; // // Align buffer on section boundary // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~((PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { gBS->FreePages (MemoryAddress, NumberOfPages); return Status; } // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { gBS->FreePages (MemoryAddress, NumberOfPages); return Status; } // // Create a new handle with gEfiCallerIdGuid to be used as the ImageHandle fore the reloaded image // NewImageHandle = NULL; Status = gBS->InstallProtocolInterface ( &NewImageHandle, &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, NULL ); // // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable); if (EFI_ERROR (Status)) { gBS->FreePages (MemoryAddress, NumberOfPages); return Status; } // // return error directly the BS will unload this image // return EFI_ABORTED; } } 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 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; }
/** Entrypoint of Boot script exector driver, this function will be executed in normal boot phase and invoked by DXE dispatch. @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS The entry point is executed successfully. @retval other Some error occurs when executing this entry point. **/ EFI_STATUS EFIAPI BootScriptExecutorEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { UINT8 *Buffer; UINTN BufferSize; UINTN Pages; EFI_PHYSICAL_ADDRESS FfsBuffer; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable; EFI_PHYSICAL_ADDRESS BootScriptExecutorBuffer; EFI_STATUS Status; VOID *DevicePath; EFI_HANDLE NewImageHandle; // // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry // point is loaded by DXE code which is the first time loaded. or else, it is already // be reloaded be itself.This is a work-around // Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath); if (EFI_ERROR (Status)) { // // This is the first-time loaded by DXE core. reload itself to NVS mem // // // A workarouond: Here we install a dummy handle // NewImageHandle = NULL; Status = gBS->InstallProtocolInterface ( &NewImageHandle, &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, NULL ); Status = GetSectionFromAnyFv ( &gEfiCallerIdGuid, EFI_SECTION_PE32, 0, (VOID **) &Buffer, &BufferSize ); ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } Pages = EFI_SIZE_TO_PAGES(BufferSize + ImageContext.SectionAlignment); FfsBuffer = 0xFFFFFFFF; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiACPIMemoryNVS, Pages, &FfsBuffer ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer; // // 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)) { gBS->FreePages (FfsBuffer, Pages); return Status; } // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { PeCoffLoaderUnloadImage (&ImageContext); gBS->FreePages (FfsBuffer, Pages); return Status; } // // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable); if (EFI_ERROR (Status)) { gBS->FreePages (FfsBuffer, Pages); return Status; } // // Additional step for BootScript integrity // Save BootScriptExecutor image // Status = SaveLockBox ( &mBootScriptExecutorImageGuid, (VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize ); ASSERT_EFI_ERROR (Status); Status = SetLockBoxAttributes (&mBootScriptExecutorImageGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); ASSERT_EFI_ERROR (Status); } else { // // the entry point is invoked after reloading. following code only run in ACPI NVS // BufferSize = sizeof (BOOT_SCRIPT_EXECUTOR_VARIABLE); BootScriptExecutorBuffer = 0xFFFFFFFF; Pages = EFI_SIZE_TO_PAGES(BufferSize); Status = gBS->AllocatePages ( AllocateMaxAddress, EfiACPIMemoryNVS, Pages, &BootScriptExecutorBuffer ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *)(UINTN)BootScriptExecutorBuffer; EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = (UINTN) S3BootScriptExecutorEntryFunction ; Status = SaveLockBox ( &gEfiBootScriptExecutorVariableGuid, &BootScriptExecutorBuffer, sizeof(BootScriptExecutorBuffer) ); ASSERT_EFI_ERROR (Status); // // Additional step for BootScript integrity // Save BootScriptExecutor context // Status = SaveLockBox ( &gEfiBootScriptExecutorContextGuid, EfiBootScriptExecutorVariable, sizeof(*EfiBootScriptExecutorVariable) ); ASSERT_EFI_ERROR (Status); Status = SetLockBoxAttributes (&gEfiBootScriptExecutorContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); ASSERT_EFI_ERROR (Status); } 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; }
/** 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; }
/** This routine is entry point of ScriptSave driver. @param ImageHandle Handle for this drivers loaded image protocol. @param SystemTable EFI system table. @retval EFI_OUT_OF_RESOURCES No enough resource @retval EFI_SUCCESS Succesfully installed the ScriptSave driver. @retval other Errors occured. **/ EFI_STATUS EFIAPI InitializeScriptSaveOnS3SaveState ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { UINT8 *Buffer; UINTN BufferSize; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; BOOT_SCRIPT_THUNK_DATA *BootScriptThunkData; EFI_STATUS Status; VOID *DevicePath; EFI_PHYSICAL_ADDRESS MemoryAddress; UINTN PageNumber; EFI_HANDLE NewImageHandle; // // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry // point is loaded by DXE code which is the first time loaded. or else, it is already // be reloaded be itself.This is a work-around // Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath); if (EFI_ERROR (Status)) { // // This is the first-time loaded by DXE core. reload itself to RESERVED mem // // // A workaround: Here we install a dummy handle // NewImageHandle = NULL; Status = gBS->InstallProtocolInterface ( &NewImageHandle, &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, NULL ); ASSERT_EFI_ERROR (Status); Status = GetSectionFromAnyFv ( &gEfiCallerIdGuid, EFI_SECTION_PE32, 0, (VOID **) &Buffer, &BufferSize ); ASSERT_EFI_ERROR (Status); ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); ASSERT_EFI_ERROR (Status); MemoryAddress = SIZE_4GB - 1; if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { PageNumber = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment)); } else { PageNumber = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize); } Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, PageNumber, &MemoryAddress ); ASSERT_EFI_ERROR (Status); ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)MemoryAddress; // // 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); ASSERT_EFI_ERROR (Status); // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer // gBS->FreePool (Buffer); // // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); RegisterMemoryProfileImage ( &gEfiCallerIdGuid, ImageContext.ImageAddress, ImageContext.ImageSize, EFI_FV_FILETYPE_DRIVER ); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable); ASSERT_EFI_ERROR (Status); // // Additional step for BootScriptThunk integrity // // // Allocate BootScriptThunkData // BootScriptThunkData = AllocatePool (sizeof (BOOT_SCRIPT_THUNK_DATA)); ASSERT (BootScriptThunkData != NULL); BootScriptThunkData->BootScriptThunkBase = ImageContext.ImageAddress; BootScriptThunkData->BootScriptThunkLength = ImageContext.ImageSize; // // Set BootScriptThunkData // PcdSet64 (BootScriptThunkDataPtr, (UINT64)(UINTN)BootScriptThunkData); return EFI_SUCCESS; } else { // // the entry point is invoked after reloading. following code only run in RESERVED mem // // // Locate and cache PI S3 Save State Protocol. // Status = gBS->LocateProtocol ( &gEfiS3SaveStateProtocolGuid, NULL, (VOID **) &mS3SaveState ); ASSERT_EFI_ERROR (Status); return gBS->InstallProtocolInterface ( &mHandle, &gEfiBootScriptSaveProtocolGuid, EFI_NATIVE_INTERFACE, &mS3ScriptSave ); } }
/** 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; }
/** This is the Event notification function to reload BootScriptExecutor image to RESERVED mem and save it to LockBox. @param Event Pointer to this event @param Context Event handler private data **/ VOID EFIAPI ReadyToLockEventNotify ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; VOID *Interface; UINT8 *Buffer; UINTN BufferSize; EFI_HANDLE NewImageHandle; UINTN Pages; EFI_PHYSICAL_ADDRESS FfsBuffer; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface); if (EFI_ERROR (Status)) { return; } // // A workaround: Here we install a dummy handle // NewImageHandle = NULL; Status = gBS->InstallProtocolInterface ( &NewImageHandle, &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, NULL ); ASSERT_EFI_ERROR (Status); // // Reload BootScriptExecutor image itself to RESERVED mem // Status = GetSectionFromAnyFv ( &gEfiCallerIdGuid, EFI_SECTION_PE32, 0, (VOID **) &Buffer, &BufferSize ); ASSERT_EFI_ERROR (Status); ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); ASSERT_EFI_ERROR (Status); if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment)); } else { Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize); } FfsBuffer = 0xFFFFFFFF; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, Pages, &FfsBuffer ); ASSERT_EFI_ERROR (Status); ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer; // // Align buffer on section boundry // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1)); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer // gBS->FreePool (Buffer); // // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); RegisterMemoryProfileImage ( &gEfiCallerIdGuid, ImageContext.ImageAddress, ImageContext.ImageSize, EFI_FV_FILETYPE_DRIVER ); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST); ASSERT_EFI_ERROR (Status); // // Additional step for BootScript integrity // Save BootScriptExecutor image // Status = SaveLockBox ( &mBootScriptExecutorImageGuid, (VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize ); ASSERT_EFI_ERROR (Status); Status = SetLockBoxAttributes (&mBootScriptExecutorImageGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); ASSERT_EFI_ERROR (Status); gBS->CloseEvent (Event); }
/** Relocate this image under 4G memory. @param ImageHandle Handle of driver image. @param SystemTable Pointer to system table. @retval EFI_SUCCESS Image successfully relocated. @retval EFI_ABORTED Failed to relocate image. **/ EFI_STATUS RelocateImageUnder4GIfNeeded ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINT8 *Buffer; UINTN BufferSize; EFI_HANDLE NewImageHandle; UINTN Pages; EFI_PHYSICAL_ADDRESS FfsBuffer; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; VOID *Interface; // // If it is already <4G, no need do relocate // if ((UINTN)RelocateImageUnder4GIfNeeded < 0xFFFFFFFF) { return EFI_SUCCESS; } // // If locate gEfiCallerIdGuid success, it means 2nd entry. // Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &Interface); if (!EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "FspNotifyDxe - 2nd entry\n")); return EFI_SUCCESS; } DEBUG ((DEBUG_INFO, "FspNotifyDxe - 1st entry\n")); // // Here we install a dummy handle // NewImageHandle = NULL; Status = gBS->InstallProtocolInterface ( &NewImageHandle, &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, NULL ); ASSERT_EFI_ERROR (Status); // // Reload image itself to <4G mem // Status = GetSectionFromAnyFv ( &gEfiCallerIdGuid, EFI_SECTION_PE32, 0, (VOID **) &Buffer, &BufferSize ); ASSERT_EFI_ERROR (Status); ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); ASSERT_EFI_ERROR (Status); if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment)); } else { Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize); } FfsBuffer = 0xFFFFFFFF; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiBootServicesCode, Pages, &FfsBuffer ); ASSERT_EFI_ERROR (Status); ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer; // // Align buffer on section boundry // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1)); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer // gBS->FreePool (Buffer); // // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); DEBUG ((DEBUG_INFO, "Loading driver at 0x%08x EntryPoint=0x%08x\n", (UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.EntryPoint)); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Error: Image at 0x%08x start failed: %r\n", ImageContext.ImageAddress, Status)); gBS->FreePages (FfsBuffer, Pages); } // // return error to unload >4G copy, if we already relocate itself to <4G. // return EFI_ALREADY_STARTED; }
/** Changes the runtime addressing mode of EFI firmware from physical to virtual. @param MemoryMapSize The size in bytes of VirtualMap. @param DescriptorSize The size in bytes of an entry in the VirtualMap. @param DescriptorVersion The version of the structure entries in VirtualMap. @param VirtualMap An array of memory descriptors which contain new virtual address mapping information for all runtime ranges. @retval EFI_SUCCESS The virtual address map has been applied. @retval EFI_UNSUPPORTED EFI firmware is not at runtime, or the EFI firmware is already in virtual address mapped mode. @retval EFI_INVALID_PARAMETER DescriptorSize or DescriptorVersion is invalid. @retval EFI_NO_MAPPING A virtual address was not supplied for a range in the memory map that requires a mapping. @retval EFI_NOT_FOUND A virtual address was supplied for an address that is not found in the memory map. **/ EFI_STATUS EFIAPI RuntimeDriverSetVirtualAddressMap ( IN UINTN MemoryMapSize, IN UINTN DescriptorSize, IN UINT32 DescriptorVersion, IN EFI_MEMORY_DESCRIPTOR *VirtualMap ) { EFI_STATUS Status; EFI_RUNTIME_EVENT_ENTRY *RuntimeEvent; EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage; LIST_ENTRY *Link; EFI_PHYSICAL_ADDRESS VirtImageBase; // // Can only switch to virtual addresses once the memory map is locked down, // and can only set it once // if (!mRuntime.AtRuntime || mRuntime.VirtualMode) { return EFI_UNSUPPORTED; } // // Only understand the original descriptor format // if (DescriptorVersion != EFI_MEMORY_DESCRIPTOR_VERSION || DescriptorSize < sizeof (EFI_MEMORY_DESCRIPTOR)) { return EFI_INVALID_PARAMETER; } // // We are now committed to go to virtual mode, so lets get to it! // mRuntime.VirtualMode = TRUE; // // ConvertPointer() needs this mVirtualMap to do the conversion. So set up // globals we need to parse the virtual address map. // mVirtualMapDescriptorSize = DescriptorSize; mVirtualMapMaxIndex = MemoryMapSize / DescriptorSize; mVirtualMap = VirtualMap; // // ReporstStatusCodeLib will check and make sure this service can be called in runtime mode. // REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_EFI_RUNTIME_SERVICE | EFI_SW_RS_PC_SET_VIRTUAL_ADDRESS_MAP)); // // Signal all the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE events. // All runtime events are stored in a list in Runtime AP. // for (Link = mRuntime.EventHead.ForwardLink; Link != &mRuntime.EventHead; Link = Link->ForwardLink) { RuntimeEvent = BASE_CR (Link, EFI_RUNTIME_EVENT_ENTRY, Link); if ((RuntimeEvent->Type & EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) { RuntimeEvent->NotifyFunction ( RuntimeEvent->Event, RuntimeEvent->NotifyContext ); } } // // Relocate runtime images. All runtime images are stored in a list in Runtime AP. // for (Link = mRuntime.ImageHead.ForwardLink; Link != &mRuntime.ImageHead; Link = Link->ForwardLink) { RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link); // // We don't want to relocate our selves, as we only run in physical mode. // if (mMyImageBase != RuntimeImage->ImageBase) { VirtImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase; Status = RuntimeDriverConvertPointer (0, (VOID **) &VirtImageBase); ASSERT_EFI_ERROR (Status); PeCoffLoaderRelocateImageForRuntime ( (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase, VirtImageBase, (UINTN) RuntimeImage->ImageSize, RuntimeImage->RelocationData ); InvalidateInstructionCacheRange (RuntimeImage->ImageBase, (UINTN) RuntimeImage->ImageSize); } } // // Convert all the Runtime Services except ConvertPointer() and SetVirtualAddressMap() // and recompute the CRC-32 // RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetTime); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetTime); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetWakeupTime); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetWakeupTime); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->ResetSystem); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextHighMonotonicCount); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetVariable); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetVariable); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextVariableName); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryVariableInfo); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->UpdateCapsule); RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryCapsuleCapabilities); RuntimeDriverCalculateEfiHdrCrc (&gRT->Hdr); // // UEFI don't require System Configuration Tables Conversion. // // // Convert the runtime fields of the EFI System Table and recompute the CRC-32 // RuntimeDriverConvertInternalPointer ((VOID **) &gST->FirmwareVendor); RuntimeDriverConvertInternalPointer ((VOID **) &gST->ConfigurationTable); RuntimeDriverConvertInternalPointer ((VOID **) &gST->RuntimeServices); RuntimeDriverCalculateEfiHdrCrc (&gST->Hdr); // // At this point, gRT and gST are physical pointers, but the contents of these tables // have been converted to runtime. // // // mVirtualMap is only valid during SetVirtualAddressMap() call // mVirtualMap = NULL; return EFI_SUCCESS; }
/** Relocate this image to reserved memory. @param ImageHandle Handle of driver image. @param SystemTable Pointer to system table. @retval EFI_SUCCESS Image successfully relocated. @retval EFI_ABORTED Failed to relocate image. **/ EFI_STATUS RelocateImageToReserved ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; EFI_STATUS Status; UINT8 *Buffer; UINTN BufferSize; EFI_HANDLE NewImageHandle; UINTN Pages; EFI_PHYSICAL_ADDRESS FfsBuffer; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; VOID *Interface; // // If locate gEfiCallerIdGuid success, it means 2nd entry. // Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &Interface); if (!EFI_ERROR (Status)) { DEBUG ((EFI_D_INFO, "StmService - 2nd entry\n")); return EFI_SUCCESS; } DEBUG ((EFI_D_INFO, "StmService - 1st entry\n")); // // Reload image itself to <4G mem // Status = GetSectionFromAnyFv ( &gEfiCallerIdGuid, EFI_SECTION_PE32, 0, (VOID **) &Buffer, &BufferSize ); ASSERT_EFI_ERROR (Status); ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); ASSERT_EFI_ERROR (Status); if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment)); } else { Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize); } FfsBuffer = 0xFFFFFFFF; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, Pages, &FfsBuffer ); ASSERT_EFI_ERROR (Status); ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer; // // Align buffer on section boundry // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1)); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer // gBS->FreePool (Buffer); // // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); // // install loaded image // LoadedImage = AllocateZeroPool (sizeof(EFI_LOADED_IMAGE_PROTOCOL)); ASSERT (LoadedImage != NULL); LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; LoadedImage->ParentHandle = NULL; LoadedImage->SystemTable = gST; LoadedImage->DeviceHandle = NULL; LoadedImage->LoadOptionsSize = 0; LoadedImage->LoadOptions = NULL; LoadedImage->ImageBase = (VOID *)(UINTN)ImageContext.ImageAddress; LoadedImage->ImageSize = ImageContext.ImageSize; LoadedImage->ImageCodeType = EfiReservedMemoryType; LoadedImage->ImageDataType = EfiReservedMemoryType; LoadedImage->Unload = NULL; NewImageHandle = NULL; Status = gBS->InstallMultipleProtocolInterfaces ( &NewImageHandle, &gEfiCallerIdGuid, LoadedImage, NULL ); ASSERT_EFI_ERROR (Status); DEBUG ((EFI_D_INFO, "NewImageHandle - 0x%x\n", NewImageHandle)); // // Call entrypoint // DEBUG ((EFI_D_INFO, "Loading driver at 0x%08x EntryPoint=0x%08x\n", (UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.EntryPoint)); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Error: Image at 0x%08x start failed: %r\n", ImageContext.ImageAddress, Status)); gBS->FreePages (FfsBuffer, Pages); } // // return error to unload DXE copy, if we already relocate itself to reserved memory. // return EFI_ACCESS_DENIED; }