1 /** @file
2
3 Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
4
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <Uefi.h>
10 #include <Library/BaseLib.h>
11 #include <Library/UefiDriverEntryPoint.h>
12 #include <Library/BaseMemoryLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/PeCoffLib.h>
15 #include <Library/UefiBootServicesTableLib.h>
16 #include <Library/DxeServicesLib.h>
17 #include <Library/CacheMaintenanceLib.h>
18 #include <Library/UefiLib.h>
19
20 /**
21 Relocate this image under 4G memory.
22
23 @param ImageHandle Handle of driver image.
24 @param SystemTable Pointer to system table.
25
26 @retval EFI_SUCCESS Image successfully relocated.
27 @retval EFI_ABORTED Failed to relocate image.
28
29 **/
30 EFI_STATUS
RelocateImageUnder4GIfNeeded(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)31 RelocateImageUnder4GIfNeeded (
32 IN EFI_HANDLE ImageHandle,
33 IN EFI_SYSTEM_TABLE *SystemTable
34 )
35 {
36 EFI_STATUS Status;
37 UINT8 *Buffer;
38 UINTN BufferSize;
39 EFI_HANDLE NewImageHandle;
40 UINTN Pages;
41 EFI_PHYSICAL_ADDRESS FfsBuffer;
42 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
43 VOID *Interface;
44
45 //
46 // If it is already <4G, no need do relocate
47 //
48 if ((UINTN)RelocateImageUnder4GIfNeeded < 0xFFFFFFFF) {
49 return EFI_SUCCESS;
50 }
51
52 //
53 // If locate gEfiCallerIdGuid success, it means 2nd entry.
54 //
55 Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &Interface);
56 if (!EFI_ERROR (Status)) {
57 DEBUG ((DEBUG_INFO, "FspNotifyDxe - 2nd entry\n"));
58 return EFI_SUCCESS;
59 }
60
61 DEBUG ((DEBUG_INFO, "FspNotifyDxe - 1st entry\n"));
62
63 //
64 // Here we install a dummy handle
65 //
66 NewImageHandle = NULL;
67 Status = gBS->InstallProtocolInterface (
68 &NewImageHandle,
69 &gEfiCallerIdGuid,
70 EFI_NATIVE_INTERFACE,
71 NULL
72 );
73 ASSERT_EFI_ERROR (Status);
74
75 //
76 // Reload image itself to <4G mem
77 //
78 Status = GetSectionFromAnyFv (
79 &gEfiCallerIdGuid,
80 EFI_SECTION_PE32,
81 0,
82 (VOID **) &Buffer,
83 &BufferSize
84 );
85 ASSERT_EFI_ERROR (Status);
86 ImageContext.Handle = Buffer;
87 ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
88 //
89 // Get information about the image being loaded
90 //
91 Status = PeCoffLoaderGetImageInfo (&ImageContext);
92 ASSERT_EFI_ERROR (Status);
93 if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
94 Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment));
95 } else {
96 Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize);
97 }
98 FfsBuffer = 0xFFFFFFFF;
99 Status = gBS->AllocatePages (
100 AllocateMaxAddress,
101 EfiBootServicesCode,
102 Pages,
103 &FfsBuffer
104 );
105 ASSERT_EFI_ERROR (Status);
106 ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;
107 //
108 // Align buffer on section boundary
109 //
110 ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
111 ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
112 //
113 // Load the image to our new buffer
114 //
115 Status = PeCoffLoaderLoadImage (&ImageContext);
116 ASSERT_EFI_ERROR (Status);
117
118 //
119 // Relocate the image in our new buffer
120 //
121 Status = PeCoffLoaderRelocateImage (&ImageContext);
122 ASSERT_EFI_ERROR (Status);
123
124 //
125 // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer
126 //
127 gBS->FreePool (Buffer);
128
129 //
130 // Flush the instruction cache so the image data is written before we execute it
131 //
132 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
133
134 DEBUG ((DEBUG_INFO, "Loading driver at 0x%08x EntryPoint=0x%08x\n", (UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.EntryPoint));
135 Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST);
136 if (EFI_ERROR (Status)) {
137 DEBUG ((DEBUG_ERROR, "Error: Image at 0x%08x start failed: %r\n", ImageContext.ImageAddress, Status));
138 gBS->FreePages (FfsBuffer, Pages);
139 }
140
141 //
142 // return error to unload >4G copy, if we already relocate itself to <4G.
143 //
144 return EFI_ALREADY_STARTED;
145 }
146