• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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