/** @file | |
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include <PrePi.h> | |
// | |
// Hack to work in NT32 | |
// | |
EFI_STATUS | |
EFIAPI | |
SecWinNtPeiLoadFile ( | |
IN VOID *Pe32Data, | |
IN EFI_PHYSICAL_ADDRESS *ImageAddress, | |
IN UINT64 *ImageSize, | |
IN EFI_PHYSICAL_ADDRESS *EntryPoint | |
); | |
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; | |
} | |
typedef | |
VOID | |
(EFIAPI *DXE_CORE_ENTRY_POINT) ( | |
IN VOID *HobStart | |
); | |
EFI_STATUS | |
EFIAPI | |
LoadDxeCoreFromFfsFile ( | |
IN EFI_PEI_FILE_HANDLE FileHandle, | |
IN UINTN StackSize | |
) | |
{ | |
EFI_STATUS Status; | |
VOID *PeCoffImage; | |
EFI_PHYSICAL_ADDRESS ImageAddress; | |
UINT64 ImageSize; | |
EFI_PHYSICAL_ADDRESS EntryPoint; | |
VOID *BaseOfStack; | |
VOID *TopOfStack; | |
VOID *Hob; | |
EFI_FV_FILE_INFO FvFileInfo; | |
Status = FfsFindSectionData (EFI_SECTION_PE32, FileHandle, &PeCoffImage); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = LoadPeCoffImage (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint); | |
// For NT32 Debug Status = SecWinNtPeiLoadFile (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// Extract the DxeCore GUID file name. | |
// | |
Status = FfsGetFileInfo (FileHandle, &FvFileInfo); | |
ASSERT_EFI_ERROR (Status); | |
BuildModuleHob (&FvFileInfo.FileName, (EFI_PHYSICAL_ADDRESS)(UINTN)ImageAddress, EFI_SIZE_TO_PAGES ((UINT32) ImageSize) * EFI_PAGE_SIZE, EntryPoint); | |
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading DxeCore at 0x%10p EntryPoint=0x%10p\n", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)EntryPoint)); | |
Hob = GetHobList (); | |
if (StackSize == 0) { | |
// User the current stack | |
((DXE_CORE_ENTRY_POINT)(UINTN)EntryPoint) (Hob); | |
} else { | |
// | |
// Allocate 128KB for the Stack | |
// | |
BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (StackSize)); | |
ASSERT (BaseOfStack != NULL); | |
// | |
// Compute the top of the stack we were allocated. Pre-allocate a UINTN | |
// for safety. | |
// | |
TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (StackSize) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT); | |
TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); | |
// | |
// Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. | |
// | |
UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, StackSize); | |
SwitchStack ( | |
(SWITCH_STACK_ENTRY_POINT)(UINTN)EntryPoint, | |
Hob, | |
NULL, | |
TopOfStack | |
); | |
} | |
// Should never get here as DXE Core does not return | |
DEBUG ((EFI_D_ERROR, "DxeCore returned\n")); | |
ASSERT (FALSE); | |
return EFI_DEVICE_ERROR; | |
} | |
EFI_STATUS | |
EFIAPI | |
LoadDxeCoreFromFv ( | |
IN UINTN *FvInstance, OPTIONAL | |
IN UINTN StackSize | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_PEI_FV_HANDLE VolumeHandle; | |
EFI_PEI_FILE_HANDLE FileHandle = NULL; | |
if (FvInstance != NULL) { | |
// | |
// Caller passed in a specific FV to try, so only try that one | |
// | |
Status = FfsFindNextVolume (*FvInstance, &VolumeHandle); | |
if (!EFI_ERROR (Status)) { | |
Status = FfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE, VolumeHandle, &FileHandle); | |
} | |
} else { | |
Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, &FileHandle); | |
} | |
if (!EFI_ERROR (Status)) { | |
return LoadDxeCoreFromFfsFile (FileHandle, StackSize); | |
} | |
return Status; | |
} | |
EFI_STATUS | |
EFIAPI | |
DecompressFirstFv ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_PEI_FV_HANDLE VolumeHandle; | |
EFI_PEI_FILE_HANDLE FileHandle; | |
Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, &VolumeHandle, &FileHandle); | |
if (!EFI_ERROR (Status)) { | |
Status = FfsProcessFvFile (FileHandle); | |
} | |
return Status; | |
} | |