1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
/** @file
Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PeCoffLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DxeServicesLib.h>
#include <Library/CacheMaintenanceLib.h>
#include <Library/UefiLib.h>
/**
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 boundary
//
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;
}
|