]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/Runtime/RuntimeDxe/PeHotRelocate.c
4c2aeff78e45a454a7612cf5faff12e4b11d3649
[mirror_edk2.git] / EdkModulePkg / Universal / Runtime / RuntimeDxe / PeHotRelocate.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 PeHotRelocate.c
15
16 Abstract:
17
18
19 --*/
20
21 #include "Runtime.h"
22
23 STATIC
24 VOID *
25 RuntimePeImageAddress (
26 IN RUNTIME_IMAGE_RELOCATION_DATA *Image,
27 IN UINTN Address
28 )
29 /*++
30
31 Routine Description:
32
33 Converts an image address to the loaded address
34
35 Arguments:
36
37 Image - The relocation data of the image being loaded
38
39 Address - The address to be converted to the loaded address
40
41 Returns:
42
43 NULL if the address can not be converted, otherwise, the converted address
44
45 --*/
46 {
47 if (Address >= (Image->ImageSize) << EFI_PAGE_SHIFT) {
48 return NULL;
49 }
50
51 return (CHAR8 *) ((UINTN) Image->ImageBase + Address);
52 }
53
54 VOID
55 RelocatePeImageForRuntime (
56 RUNTIME_IMAGE_RELOCATION_DATA *Image
57 )
58 {
59 CHAR8 *OldBase;
60 CHAR8 *NewBase;
61 EFI_IMAGE_DOS_HEADER *DosHdr;
62 EFI_IMAGE_NT_HEADERS *PeHdr;
63 UINT32 NumberOfRvaAndSizes;
64 EFI_IMAGE_DATA_DIRECTORY *DataDirectory;
65 EFI_IMAGE_DATA_DIRECTORY *RelocDir;
66 EFI_IMAGE_BASE_RELOCATION *RelocBase;
67 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
68 UINT16 *Reloc;
69 UINT16 *RelocEnd;
70 CHAR8 *Fixup;
71 CHAR8 *FixupBase;
72 UINT16 *F16;
73 UINT32 *F32;
74 CHAR8 *FixupData;
75 UINTN Adjust;
76 EFI_STATUS Status;
77
78 OldBase = (CHAR8 *) ((UINTN) Image->ImageBase);
79 NewBase = (CHAR8 *) ((UINTN) Image->ImageBase);
80
81 Status = RuntimeDriverConvertPointer (0, (VOID **) &NewBase);
82 ASSERT_EFI_ERROR (Status);
83
84 Adjust = (UINTN) NewBase - (UINTN) OldBase;
85
86 //
87 // Find the image's relocate dir info
88 //
89 DosHdr = (EFI_IMAGE_DOS_HEADER *) OldBase;
90 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
91 //
92 // Valid DOS header so get address of PE header
93 //
94 PeHdr = (EFI_IMAGE_NT_HEADERS *) (((CHAR8 *) DosHdr) + DosHdr->e_lfanew);
95 } else {
96 //
97 // No Dos header so assume image starts with PE header.
98 //
99 PeHdr = (EFI_IMAGE_NT_HEADERS *) OldBase;
100 }
101
102 if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {
103 //
104 // Not a valid PE image so Exit
105 //
106 return ;
107 }
108 //
109 // Get some data from the PE type dependent data
110 //
111 NumberOfRvaAndSizes = PeHdr->OptionalHeader.NumberOfRvaAndSizes;
112 DataDirectory = &PeHdr->OptionalHeader.DataDirectory[0];
113
114 //
115 // Find the relocation block
116 //
117 // Per the PE/COFF spec, you can't assume that a given data directory
118 // is present in the image. You have to check the NumberOfRvaAndSizes in
119 // the optional header to verify a desired directory entry is there.
120 //
121 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
122 RelocDir = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
123 RelocBase = RuntimePeImageAddress (Image, RelocDir->VirtualAddress);
124 RelocBaseEnd = RuntimePeImageAddress (Image, RelocDir->VirtualAddress + RelocDir->Size);
125 } else {
126 //
127 // Cannot find relocations, cannot continue
128 //
129 ASSERT (FALSE);
130 return ;
131 }
132
133 ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);
134
135 //
136 // Run the whole relocation block. And re-fixup data that has not been
137 // modified. The FixupData is used to see if the image has been modified
138 // since it was relocated. This is so data sections that have been updated
139 // by code will not be fixed up, since that would set them back to
140 // defaults.
141 //
142 FixupData = Image->RelocationData;
143 while (RelocBase < RelocBaseEnd) {
144
145 Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
146 RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);
147 FixupBase = (CHAR8 *) ((UINTN) Image->ImageBase) + RelocBase->VirtualAddress;
148
149 //
150 // Run this relocation record
151 //
152 while (Reloc < RelocEnd) {
153
154 Fixup = FixupBase + (*Reloc & 0xFFF);
155 switch ((*Reloc) >> 12) {
156
157 case EFI_IMAGE_REL_BASED_ABSOLUTE:
158 break;
159
160 case EFI_IMAGE_REL_BASED_HIGH:
161 F16 = (UINT16 *) Fixup;
162 if (*(UINT16 *) FixupData == *F16) {
163 *F16 = (UINT16) ((*F16 << 16) + ((UINT16) Adjust & 0xffff));
164 }
165
166 FixupData = FixupData + sizeof (UINT16);
167 break;
168
169 case EFI_IMAGE_REL_BASED_LOW:
170 F16 = (UINT16 *) Fixup;
171 if (*(UINT16 *) FixupData == *F16) {
172 *F16 = (UINT16) (*F16 + ((UINT16) Adjust & 0xffff));
173 }
174
175 FixupData = FixupData + sizeof (UINT16);
176 break;
177
178 case EFI_IMAGE_REL_BASED_HIGHLOW:
179 F32 = (UINT32 *) Fixup;
180 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
181 if (*(UINT32 *) FixupData == *F32) {
182 *F32 = *F32 + (UINT32) Adjust;
183 }
184
185 FixupData = FixupData + sizeof (UINT32);
186 break;
187
188 case EFI_IMAGE_REL_BASED_HIGHADJ:
189 //
190 // Not implemented, but not used in EFI 1.0
191 //
192 ASSERT (FALSE);
193 break;
194
195 default:
196 //
197 // Only Itanium requires ConvertPeImage_Ex
198 //
199 Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
200 if (EFI_ERROR (Status)) {
201 return ;
202 }
203 }
204 //
205 // Next relocation record
206 //
207 Reloc += 1;
208 }
209 //
210 // next reloc block
211 //
212 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
213 }
214
215 FlushCpuCache (Image->ImageBase, (UINT64) Image->ImageSize);
216 }