]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/Common/PeCoffLoaderEx.c
License header updated to match correct format.
[mirror_edk2.git] / BaseTools / Source / C / Common / PeCoffLoaderEx.c
1 /** @file
2 IA32, X64 and IPF Specific relocation fixups
3
4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
5 Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The 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 <Common/UefiBaseTypes.h>
17 #include <IndustryStandard/PeImage.h>
18 #include "PeCoffLib.h"
19 #include "CommonLib.h"
20 #include "EfiUtilityMsgs.h"
21
22
23 #define EXT_IMM64(Value, Address, Size, InstPos, ValPos) \
24 Value |= (((UINT64)((*(Address) >> InstPos) & (((UINT64)1 << Size) - 1))) << ValPos)
25
26 #define INS_IMM64(Value, Address, Size, InstPos, ValPos) \
27 *(UINT32*)Address = (*(UINT32*)Address & ~(((1 << Size) - 1) << InstPos)) | \
28 ((UINT32)((((UINT64)Value >> ValPos) & (((UINT64)1 << Size) - 1))) << InstPos)
29
30 #define IMM64_IMM7B_INST_WORD_X 3
31 #define IMM64_IMM7B_SIZE_X 7
32 #define IMM64_IMM7B_INST_WORD_POS_X 4
33 #define IMM64_IMM7B_VAL_POS_X 0
34
35 #define IMM64_IMM9D_INST_WORD_X 3
36 #define IMM64_IMM9D_SIZE_X 9
37 #define IMM64_IMM9D_INST_WORD_POS_X 18
38 #define IMM64_IMM9D_VAL_POS_X 7
39
40 #define IMM64_IMM5C_INST_WORD_X 3
41 #define IMM64_IMM5C_SIZE_X 5
42 #define IMM64_IMM5C_INST_WORD_POS_X 13
43 #define IMM64_IMM5C_VAL_POS_X 16
44
45 #define IMM64_IC_INST_WORD_X 3
46 #define IMM64_IC_SIZE_X 1
47 #define IMM64_IC_INST_WORD_POS_X 12
48 #define IMM64_IC_VAL_POS_X 21
49
50 #define IMM64_IMM41a_INST_WORD_X 1
51 #define IMM64_IMM41a_SIZE_X 10
52 #define IMM64_IMM41a_INST_WORD_POS_X 14
53 #define IMM64_IMM41a_VAL_POS_X 22
54
55 #define IMM64_IMM41b_INST_WORD_X 1
56 #define IMM64_IMM41b_SIZE_X 8
57 #define IMM64_IMM41b_INST_WORD_POS_X 24
58 #define IMM64_IMM41b_VAL_POS_X 32
59
60 #define IMM64_IMM41c_INST_WORD_X 2
61 #define IMM64_IMM41c_SIZE_X 23
62 #define IMM64_IMM41c_INST_WORD_POS_X 0
63 #define IMM64_IMM41c_VAL_POS_X 40
64
65 #define IMM64_SIGN_INST_WORD_X 3
66 #define IMM64_SIGN_SIZE_X 1
67 #define IMM64_SIGN_INST_WORD_POS_X 27
68 #define IMM64_SIGN_VAL_POS_X 63
69
70 RETURN_STATUS
71 PeCoffLoaderRelocateIa32Image (
72 IN UINT16 *Reloc,
73 IN OUT CHAR8 *Fixup,
74 IN OUT CHAR8 **FixupData,
75 IN UINT64 Adjust
76 )
77 /*++
78
79 Routine Description:
80
81 Performs an IA-32 specific relocation fixup
82
83 Arguments:
84
85 Reloc - Pointer to the relocation record
86
87 Fixup - Pointer to the address to fix up
88
89 FixupData - Pointer to a buffer to log the fixups
90
91 Adjust - The offset to adjust the fixup
92
93 Returns:
94
95 EFI_UNSUPPORTED - Unsupported now
96
97 --*/
98 {
99 return RETURN_UNSUPPORTED;
100 }
101
102 RETURN_STATUS
103 PeCoffLoaderRelocateIpfImage (
104 IN UINT16 *Reloc,
105 IN OUT CHAR8 *Fixup,
106 IN OUT CHAR8 **FixupData,
107 IN UINT64 Adjust
108 )
109 /*++
110
111 Routine Description:
112
113 Performs an Itanium-based specific relocation fixup
114
115 Arguments:
116
117 Reloc - Pointer to the relocation record
118
119 Fixup - Pointer to the address to fix up
120
121 FixupData - Pointer to a buffer to log the fixups
122
123 Adjust - The offset to adjust the fixup
124
125 Returns:
126
127 Status code
128
129 --*/
130 {
131 UINT64 *F64;
132 UINT64 FixupVal;
133
134 switch ((*Reloc) >> 12) {
135
136 case EFI_IMAGE_REL_BASED_DIR64:
137 F64 = (UINT64 *) Fixup;
138 *F64 = *F64 + (UINT64) Adjust;
139 if (*FixupData != NULL) {
140 *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64));
141 *(UINT64 *)(*FixupData) = *F64;
142 *FixupData = *FixupData + sizeof(UINT64);
143 }
144 break;
145
146 case EFI_IMAGE_REL_BASED_IA64_IMM64:
147
148 //
149 // Align it to bundle address before fixing up the
150 // 64-bit immediate value of the movl instruction.
151 //
152
153 Fixup = (CHAR8 *)((UINTN) Fixup & (UINTN) ~(15));
154 FixupVal = (UINT64)0;
155
156 //
157 // Extract the lower 32 bits of IMM64 from bundle
158 //
159 EXT_IMM64(FixupVal,
160 (UINT32 *)Fixup + IMM64_IMM7B_INST_WORD_X,
161 IMM64_IMM7B_SIZE_X,
162 IMM64_IMM7B_INST_WORD_POS_X,
163 IMM64_IMM7B_VAL_POS_X
164 );
165
166 EXT_IMM64(FixupVal,
167 (UINT32 *)Fixup + IMM64_IMM9D_INST_WORD_X,
168 IMM64_IMM9D_SIZE_X,
169 IMM64_IMM9D_INST_WORD_POS_X,
170 IMM64_IMM9D_VAL_POS_X
171 );
172
173 EXT_IMM64(FixupVal,
174 (UINT32 *)Fixup + IMM64_IMM5C_INST_WORD_X,
175 IMM64_IMM5C_SIZE_X,
176 IMM64_IMM5C_INST_WORD_POS_X,
177 IMM64_IMM5C_VAL_POS_X
178 );
179
180 EXT_IMM64(FixupVal,
181 (UINT32 *)Fixup + IMM64_IC_INST_WORD_X,
182 IMM64_IC_SIZE_X,
183 IMM64_IC_INST_WORD_POS_X,
184 IMM64_IC_VAL_POS_X
185 );
186
187 EXT_IMM64(FixupVal,
188 (UINT32 *)Fixup + IMM64_IMM41a_INST_WORD_X,
189 IMM64_IMM41a_SIZE_X,
190 IMM64_IMM41a_INST_WORD_POS_X,
191 IMM64_IMM41a_VAL_POS_X
192 );
193
194 //
195 // Update 64-bit address
196 //
197 FixupVal += Adjust;
198
199 //
200 // Insert IMM64 into bundle
201 //
202 INS_IMM64(FixupVal,
203 ((UINT32 *)Fixup + IMM64_IMM7B_INST_WORD_X),
204 IMM64_IMM7B_SIZE_X,
205 IMM64_IMM7B_INST_WORD_POS_X,
206 IMM64_IMM7B_VAL_POS_X
207 );
208
209 INS_IMM64(FixupVal,
210 ((UINT32 *)Fixup + IMM64_IMM9D_INST_WORD_X),
211 IMM64_IMM9D_SIZE_X,
212 IMM64_IMM9D_INST_WORD_POS_X,
213 IMM64_IMM9D_VAL_POS_X
214 );
215
216 INS_IMM64(FixupVal,
217 ((UINT32 *)Fixup + IMM64_IMM5C_INST_WORD_X),
218 IMM64_IMM5C_SIZE_X,
219 IMM64_IMM5C_INST_WORD_POS_X,
220 IMM64_IMM5C_VAL_POS_X
221 );
222
223 INS_IMM64(FixupVal,
224 ((UINT32 *)Fixup + IMM64_IC_INST_WORD_X),
225 IMM64_IC_SIZE_X,
226 IMM64_IC_INST_WORD_POS_X,
227 IMM64_IC_VAL_POS_X
228 );
229
230 INS_IMM64(FixupVal,
231 ((UINT32 *)Fixup + IMM64_IMM41a_INST_WORD_X),
232 IMM64_IMM41a_SIZE_X,
233 IMM64_IMM41a_INST_WORD_POS_X,
234 IMM64_IMM41a_VAL_POS_X
235 );
236
237 INS_IMM64(FixupVal,
238 ((UINT32 *)Fixup + IMM64_IMM41b_INST_WORD_X),
239 IMM64_IMM41b_SIZE_X,
240 IMM64_IMM41b_INST_WORD_POS_X,
241 IMM64_IMM41b_VAL_POS_X
242 );
243
244 INS_IMM64(FixupVal,
245 ((UINT32 *)Fixup + IMM64_IMM41c_INST_WORD_X),
246 IMM64_IMM41c_SIZE_X,
247 IMM64_IMM41c_INST_WORD_POS_X,
248 IMM64_IMM41c_VAL_POS_X
249 );
250
251 INS_IMM64(FixupVal,
252 ((UINT32 *)Fixup + IMM64_SIGN_INST_WORD_X),
253 IMM64_SIGN_SIZE_X,
254 IMM64_SIGN_INST_WORD_POS_X,
255 IMM64_SIGN_VAL_POS_X
256 );
257
258 F64 = (UINT64 *) Fixup;
259 if (*FixupData != NULL) {
260 *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64));
261 *(UINT64 *)(*FixupData) = *F64;
262 *FixupData = *FixupData + sizeof(UINT64);
263 }
264 break;
265
266 default:
267 return RETURN_UNSUPPORTED;
268 }
269
270 return RETURN_SUCCESS;
271 }
272
273 RETURN_STATUS
274 PeCoffLoaderRelocateX64Image (
275 IN UINT16 *Reloc,
276 IN OUT CHAR8 *Fixup,
277 IN OUT CHAR8 **FixupData,
278 IN UINT64 Adjust
279 )
280 /**
281 Performs an x64 specific relocation fixup
282
283 @param Reloc Pointer to the relocation record
284 @param Fixup Pointer to the address to fix up
285 @param FixupData Pointer to a buffer to log the fixups
286 @param Adjust The offset to adjust the fixup
287
288 @retval RETURN_SUCCESS Success to perform relocation
289 @retval RETURN_UNSUPPORTED Unsupported.
290 **/
291 {
292 UINT64 *F64;
293
294 switch ((*Reloc) >> 12) {
295
296 case EFI_IMAGE_REL_BASED_DIR64:
297 F64 = (UINT64 *) Fixup;
298 *F64 = *F64 + (UINT64) Adjust;
299 if (*FixupData != NULL) {
300 *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64));
301 *(UINT64 *)(*FixupData) = *F64;
302 *FixupData = *FixupData + sizeof(UINT64);
303 }
304 break;
305
306 default:
307 return RETURN_UNSUPPORTED;
308 }
309
310 return RETURN_SUCCESS;
311 }
312
313 /**
314 Pass in a pointer to an ARM MOVT or MOVW immediate instruciton and
315 return the immediate data encoded in the instruction
316
317 @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
318
319 @return Immediate address encoded in the instruction
320
321 **/
322 UINT16
323 ThumbMovtImmediateAddress (
324 IN UINT16 *Instruction
325 )
326 {
327 UINT32 Movt;
328 UINT16 Address;
329
330 // Thumb2 is two 16-bit instructions working together. Not a single 32-bit instruction
331 // Example MOVT R0, #0 is 0x0000f2c0 or 0xf2c0 0x0000
332 Movt = (*Instruction << 16) | (*(Instruction + 1));
333
334 // imm16 = imm4:i:imm3:imm8
335 // imm4 -> Bit19:Bit16
336 // i -> Bit26
337 // imm3 -> Bit14:Bit12
338 // imm8 -> Bit7:Bit0
339 Address = (UINT16)(Movt & 0x000000ff); // imm8
340 Address |= (UINT16)((Movt >> 4) & 0x0000f700); // imm4 imm3
341 Address |= (((Movt & BIT26) != 0) ? BIT11 : 0); // i
342 return Address;
343 }
344
345
346 /**
347 Update an ARM MOVT or MOVW immediate instruction immediate data.
348
349 @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
350 @param Address New addres to patch into the instruction
351 **/
352 VOID
353 ThumbMovtImmediatePatch (
354 IN OUT UINT16 *Instruction,
355 IN UINT16 Address
356 )
357 {
358 UINT16 Patch;
359
360 // First 16-bit chunk of instruciton
361 Patch = ((Address >> 12) & 0x000f); // imm4
362 Patch |= (((Address & BIT11) != 0) ? BIT10 : 0); // i
363 *Instruction = (*Instruction & ~0x040f) | Patch;
364
365 // Second 16-bit chunk of instruction
366 Patch = Address & 0x000000ff; // imm8
367 Patch |= ((Address << 4) & 0x00007000); // imm3
368 Instruction++;
369 *Instruction = (*Instruction & ~0x70ff) | Patch;
370 }
371
372 /**
373 Pass in a pointer to an ARM MOVW/MOVT instruciton pair and
374 return the immediate data encoded in the two` instruction
375
376 @param Instructions Pointer to ARM MOVW/MOVT insturction pair
377
378 @return Immediate address encoded in the instructions
379
380 **/
381 UINT32
382 EFIAPI
383 ThumbMovwMovtImmediateAddress (
384 IN UINT16 *Instructions
385 )
386 {
387 UINT16 *Word;
388 UINT16 *Top;
389
390 Word = Instructions; // MOVW
391 Top = Word + 2; // MOVT
392
393 return (ThumbMovtImmediateAddress (Top) << 16) + ThumbMovtImmediateAddress (Word);
394 }
395
396
397 /**
398 Update an ARM MOVW/MOVT immediate instruction instruction pair.
399
400 @param Instructions Pointer to ARM MOVW/MOVT instruction pair
401 @param Address New addres to patch into the instructions
402 **/
403 VOID
404 EFIAPI
405 ThumbMovwMovtImmediatePatch (
406 IN OUT UINT16 *Instructions,
407 IN UINT32 Address
408 )
409 {
410 UINT16 *Word;
411 UINT16 *Top;
412
413 Word = (UINT16 *)Instructions; // MOVW
414 Top = Word + 2; // MOVT
415
416 ThumbMovtImmediatePatch (Word, (UINT16)(Address & 0xffff));
417 ThumbMovtImmediatePatch (Top, (UINT16)(Address >> 16));
418 }
419
420
421 /**
422 Performs an ARM-based specific relocation fixup and is a no-op on other
423 instruction sets.
424
425 @param Reloc Pointer to the relocation record.
426 @param Fixup Pointer to the address to fix up.
427 @param FixupData Pointer to a buffer to log the fixups.
428 @param Adjust The offset to adjust the fixup.
429
430 @return Status code.
431
432 **/
433 RETURN_STATUS
434 PeCoffLoaderRelocateArmImage (
435 IN UINT16 **Reloc,
436 IN OUT CHAR8 *Fixup,
437 IN OUT CHAR8 **FixupData,
438 IN UINT64 Adjust
439 )
440 {
441 UINT16 *Fixup16;
442 UINT32 FixupVal;
443
444 Fixup16 = (UINT16 *) Fixup;
445
446 switch ((**Reloc) >> 12) {
447
448 case EFI_IMAGE_REL_BASED_ARM_MOV32T:
449 FixupVal = ThumbMovwMovtImmediateAddress (Fixup16) + (UINT32)Adjust;
450 ThumbMovwMovtImmediatePatch (Fixup16, FixupVal);
451
452
453 if (*FixupData != NULL) {
454 *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64));
455 *(UINT64 *)(*FixupData) = *Fixup16;
456 CopyMem (*FixupData, Fixup16, sizeof (UINT64));
457 }
458 break;
459
460 case EFI_IMAGE_REL_BASED_ARM_MOV32A:
461 // break omitted - ARM instruction encoding not implemented
462 default:
463 return RETURN_UNSUPPORTED;
464 }
465
466 return RETURN_SUCCESS;
467 }
468
469 RETURN_STATUS
470 PeCoffLoaderRelocateAArch64Image (
471 IN UINT16 *Reloc,
472 IN OUT CHAR8 *Fixup,
473 IN OUT CHAR8 **FixupData,
474 IN UINT64 Adjust
475 )
476 /**
477 Performs an AArch64 specific relocation fixup
478
479 @param Reloc Pointer to the relocation record
480 @param Fixup Pointer to the address to fix up
481 @param FixupData Pointer to a buffer to log the fixups
482 @param Adjust The offset to adjust the fixup
483
484 @retval RETURN_SUCCESS Success to perform relocation
485 @retval RETURN_UNSUPPORTED Unsupported.
486 **/
487 {
488 UINT64 *F64;
489
490 switch ((*Reloc) >> 12) {
491
492 case EFI_IMAGE_REL_BASED_DIR64:
493 F64 = (UINT64 *) Fixup;
494 *F64 = *F64 + (UINT64) Adjust;
495 if (*FixupData != NULL) {
496 *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64));
497 *(UINT64 *)(*FixupData) = *F64;
498 *FixupData = *FixupData + sizeof(UINT64);
499 }
500 break;
501
502 default:
503 return RETURN_UNSUPPORTED;
504 }
505
506 return RETURN_SUCCESS;
507 }