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