2 IA32 and X64 Specific relocation fixups
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
6 Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
7 Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Common/UefiBaseTypes.h>
13 #include <IndustryStandard/PeImage.h>
14 #include "PeCoffLib.h"
15 #include "CommonLib.h"
16 #include "EfiUtilityMsgs.h"
19 #define EXT_IMM64(Value, Address, Size, InstPos, ValPos) \
20 Value |= (((UINT64)((*(Address) >> InstPos) & (((UINT64)1 << Size) - 1))) << ValPos)
22 #define INS_IMM64(Value, Address, Size, InstPos, ValPos) \
23 *(UINT32*)Address = (*(UINT32*)Address & ~(((1 << Size) - 1) << InstPos)) | \
24 ((UINT32)((((UINT64)Value >> ValPos) & (((UINT64)1 << Size) - 1))) << InstPos)
26 #define IMM64_IMM7B_INST_WORD_X 3
27 #define IMM64_IMM7B_SIZE_X 7
28 #define IMM64_IMM7B_INST_WORD_POS_X 4
29 #define IMM64_IMM7B_VAL_POS_X 0
31 #define IMM64_IMM9D_INST_WORD_X 3
32 #define IMM64_IMM9D_SIZE_X 9
33 #define IMM64_IMM9D_INST_WORD_POS_X 18
34 #define IMM64_IMM9D_VAL_POS_X 7
36 #define IMM64_IMM5C_INST_WORD_X 3
37 #define IMM64_IMM5C_SIZE_X 5
38 #define IMM64_IMM5C_INST_WORD_POS_X 13
39 #define IMM64_IMM5C_VAL_POS_X 16
41 #define IMM64_IC_INST_WORD_X 3
42 #define IMM64_IC_SIZE_X 1
43 #define IMM64_IC_INST_WORD_POS_X 12
44 #define IMM64_IC_VAL_POS_X 21
46 #define IMM64_IMM41a_INST_WORD_X 1
47 #define IMM64_IMM41a_SIZE_X 10
48 #define IMM64_IMM41a_INST_WORD_POS_X 14
49 #define IMM64_IMM41a_VAL_POS_X 22
51 #define IMM64_IMM41b_INST_WORD_X 1
52 #define IMM64_IMM41b_SIZE_X 8
53 #define IMM64_IMM41b_INST_WORD_POS_X 24
54 #define IMM64_IMM41b_VAL_POS_X 32
56 #define IMM64_IMM41c_INST_WORD_X 2
57 #define IMM64_IMM41c_SIZE_X 23
58 #define IMM64_IMM41c_INST_WORD_POS_X 0
59 #define IMM64_IMM41c_VAL_POS_X 40
61 #define IMM64_SIGN_INST_WORD_X 3
62 #define IMM64_SIGN_SIZE_X 1
63 #define IMM64_SIGN_INST_WORD_POS_X 27
64 #define IMM64_SIGN_VAL_POS_X 63
66 UINT32
*RiscVHi20Fixup
= NULL
;
69 PeCoffLoaderRelocateIa32Image (
72 IN OUT CHAR8
**FixupData
,
79 Performs an IA-32 specific relocation fixup
83 Reloc - Pointer to the relocation record
85 Fixup - Pointer to the address to fix up
87 FixupData - Pointer to a buffer to log the fixups
89 Adjust - The offset to adjust the fixup
93 EFI_UNSUPPORTED - Unsupported now
97 return RETURN_UNSUPPORTED
;
104 Performs an RISC-V specific relocation fixup
108 Reloc - Pointer to the relocation record
110 Fixup - Pointer to the address to fix up
112 FixupData - Pointer to a buffer to log the fixups
114 Adjust - The offset to adjust the fixup
122 PeCoffLoaderRelocateRiscVImage (
125 IN OUT CHAR8
**FixupData
,
132 switch ((*Reloc
) >> 12) {
133 case EFI_IMAGE_REL_BASED_RISCV_HI20
:
134 RiscVHi20Fixup
= (UINT32
*) Fixup
;
137 case EFI_IMAGE_REL_BASED_RISCV_LOW12I
:
138 if (RiscVHi20Fixup
!= NULL
) {
139 Value
= (UINT32
)(RV_X(*RiscVHi20Fixup
, 12, 20) << 12);
140 Value2
= (UINT32
)(RV_X(*(UINT32
*)Fixup
, 20, 12));
141 if (Value2
& (RISCV_IMM_REACH
/2)) {
142 Value2
|= ~(RISCV_IMM_REACH
-1);
145 Value
+= (UINT32
)Adjust
;
146 Value2
= RISCV_CONST_HIGH_PART (Value
);
147 *(UINT32
*)RiscVHi20Fixup
= (RV_X (Value2
, 12, 20) << 12) | \
148 (RV_X (*(UINT32
*)RiscVHi20Fixup
, 0, 12));
149 *(UINT32
*)Fixup
= (RV_X (Value
, 0, 12) << 20) | \
150 (RV_X (*(UINT32
*)Fixup
, 0, 20));
152 RiscVHi20Fixup
= NULL
;
155 case EFI_IMAGE_REL_BASED_RISCV_LOW12S
:
156 if (RiscVHi20Fixup
!= NULL
) {
157 Value
= (UINT32
)(RV_X(*RiscVHi20Fixup
, 12, 20) << 12);
158 Value2
= (UINT32
)(RV_X(*(UINT32
*)Fixup
, 7, 5) | (RV_X(*(UINT32
*)Fixup
, 25, 7) << 5));
159 if (Value2
& (RISCV_IMM_REACH
/2)) {
160 Value2
|= ~(RISCV_IMM_REACH
-1);
163 Value
+= (UINT32
)Adjust
;
164 Value2
= RISCV_CONST_HIGH_PART (Value
);
165 *(UINT32
*)RiscVHi20Fixup
= (RV_X (Value2
, 12, 20) << 12) | \
166 (RV_X (*(UINT32
*)RiscVHi20Fixup
, 0, 12));
167 Value2
= *(UINT32
*)Fixup
& 0x01fff07f;
168 Value
&= RISCV_IMM_REACH
- 1;
169 *(UINT32
*)Fixup
= Value2
| (UINT32
)(((RV_X(Value
, 0, 5) << 7) | (RV_X(Value
, 5, 7) << 25)));
171 RiscVHi20Fixup
= NULL
;
175 return EFI_UNSUPPORTED
;
178 return RETURN_SUCCESS
;
182 Pass in a pointer to an ARM MOVT or MOVW immediate instruction and
183 return the immediate data encoded in the instruction
185 @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
187 @return Immediate address encoded in the instruction
191 ThumbMovtImmediateAddress (
192 IN UINT16
*Instruction
198 // Thumb2 is two 16-bit instructions working together. Not a single 32-bit instruction
199 // Example MOVT R0, #0 is 0x0000f2c0 or 0xf2c0 0x0000
200 Movt
= (*Instruction
<< 16) | (*(Instruction
+ 1));
202 // imm16 = imm4:i:imm3:imm8
203 // imm4 -> Bit19:Bit16
205 // imm3 -> Bit14:Bit12
207 Address
= (UINT16
)(Movt
& 0x000000ff); // imm8
208 Address
|= (UINT16
)((Movt
>> 4) & 0x0000f700); // imm4 imm3
209 Address
|= (((Movt
& BIT26
) != 0) ? BIT11
: 0); // i
215 Update an ARM MOVT or MOVW immediate instruction immediate data.
217 @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
218 @param Address New address to patch into the instruction
221 ThumbMovtImmediatePatch (
222 IN OUT UINT16
*Instruction
,
228 // First 16-bit chunk of instruction
229 Patch
= ((Address
>> 12) & 0x000f); // imm4
230 Patch
|= (((Address
& BIT11
) != 0) ? BIT10
: 0); // i
231 *Instruction
= (*Instruction
& ~0x040f) | Patch
;
233 // Second 16-bit chunk of instruction
234 Patch
= Address
& 0x000000ff; // imm8
235 Patch
|= ((Address
<< 4) & 0x00007000); // imm3
237 *Instruction
= (*Instruction
& ~0x70ff) | Patch
;
241 Pass in a pointer to an ARM MOVW/MOVT instruction pair and
242 return the immediate data encoded in the two` instruction
244 @param Instructions Pointer to ARM MOVW/MOVT instruction pair
246 @return Immediate address encoded in the instructions
251 ThumbMovwMovtImmediateAddress (
252 IN UINT16
*Instructions
258 Word
= Instructions
; // MOVW
259 Top
= Word
+ 2; // MOVT
261 return (ThumbMovtImmediateAddress (Top
) << 16) + ThumbMovtImmediateAddress (Word
);
266 Update an ARM MOVW/MOVT immediate instruction instruction pair.
268 @param Instructions Pointer to ARM MOVW/MOVT instruction pair
269 @param Address New address to patch into the instructions
273 ThumbMovwMovtImmediatePatch (
274 IN OUT UINT16
*Instructions
,
281 Word
= (UINT16
*)Instructions
; // MOVW
282 Top
= Word
+ 2; // MOVT
284 ThumbMovtImmediatePatch (Word
, (UINT16
)(Address
& 0xffff));
285 ThumbMovtImmediatePatch (Top
, (UINT16
)(Address
>> 16));
290 Performs an ARM-based specific relocation fixup and is a no-op on other
293 @param Reloc Pointer to the relocation record.
294 @param Fixup Pointer to the address to fix up.
295 @param FixupData Pointer to a buffer to log the fixups.
296 @param Adjust The offset to adjust the fixup.
302 PeCoffLoaderRelocateArmImage (
305 IN OUT CHAR8
**FixupData
,
312 Fixup16
= (UINT16
*) Fixup
;
314 switch ((**Reloc
) >> 12) {
316 case EFI_IMAGE_REL_BASED_ARM_MOV32T
:
317 FixupVal
= ThumbMovwMovtImmediateAddress (Fixup16
) + (UINT32
)Adjust
;
318 ThumbMovwMovtImmediatePatch (Fixup16
, FixupVal
);
321 if (*FixupData
!= NULL
) {
322 *FixupData
= ALIGN_POINTER(*FixupData
, sizeof(UINT64
));
323 CopyMem (*FixupData
, Fixup16
, sizeof (UINT64
));
324 *FixupData
= *FixupData
+ sizeof(UINT64
);
328 case EFI_IMAGE_REL_BASED_ARM_MOV32A
:
329 // break omitted - ARM instruction encoding not implemented
331 return RETURN_UNSUPPORTED
;
334 return RETURN_SUCCESS
;
338 Performs a LoongArch specific relocation fixup.
340 @param[in] Reloc Pointer to the relocation record.
341 @param[in, out] Fixup Pointer to the address to fix up.
342 @param[in, out] FixupData Pointer to a buffer to log the fixups.
343 @param[in] Adjust The offset to adjust the fixup.
348 PeCoffLoaderRelocateLoongArch64Image (
351 IN OUT CHAR8
**FixupData
,
360 RelocType
= ((*Reloc
) >> 12);
366 case EFI_IMAGE_REL_BASED_LOONGARCH64_MARK_LA
:
367 // The next four instructions are used to load a 64 bit address, relocate all of them
368 Value
= (*(UINT32
*)Fixup
& 0x1ffffe0) << 7 | // lu12i.w 20bits from bit5
369 (*((UINT32
*)Fixup
+ 1) & 0x3ffc00) >> 10; // ori 12bits from bit10
370 Tmp1
= *((UINT32
*)Fixup
+ 2) & 0x1ffffe0; // lu32i.d 20bits from bit5
371 Tmp2
= *((UINT32
*)Fixup
+ 3) & 0x3ffc00; // lu52i.d 12bits from bit10
372 Value
= Value
| (Tmp1
<< 27) | (Tmp2
<< 42);
375 *(UINT32
*)Fixup
= (*(UINT32
*)Fixup
& ~0x1ffffe0) | (((Value
>> 12) & 0xfffff) << 5);
376 if (*FixupData
!= NULL
) {
377 *FixupData
= ALIGN_POINTER (*FixupData
, sizeof (UINT32
));
378 *(UINT32
*)(*FixupData
) = *(UINT32
*)Fixup
;
379 *FixupData
= *FixupData
+ sizeof (UINT32
);
382 Fixup
+= sizeof (UINT32
);
383 *(UINT32
*)Fixup
= (*(UINT32
*)Fixup
& ~0x3ffc00) | ((Value
& 0xfff) << 10);
384 if (*FixupData
!= NULL
) {
385 *FixupData
= ALIGN_POINTER (*FixupData
, sizeof (UINT32
));
386 *(UINT32
*)(*FixupData
) = *(UINT32
*)Fixup
;
387 *FixupData
= *FixupData
+ sizeof (UINT32
);
390 Fixup
+= sizeof (UINT32
);
391 *(UINT32
*)Fixup
= (*(UINT32
*)Fixup
& ~0x1ffffe0) | (((Value
>> 32) & 0xfffff) << 5);
392 if (*FixupData
!= NULL
) {
393 *FixupData
= ALIGN_POINTER (*FixupData
, sizeof (UINT32
));
394 *(UINT32
*)(*FixupData
) = *(UINT32
*)Fixup
;
395 *FixupData
= *FixupData
+ sizeof (UINT32
);
398 Fixup
+= sizeof (UINT32
);
399 *(UINT32
*)Fixup
= (*(UINT32
*)Fixup
& ~0x3ffc00) | (((Value
>> 52) & 0xfff) << 10);
400 if (*FixupData
!= NULL
) {
401 *FixupData
= ALIGN_POINTER (*FixupData
, sizeof (UINT32
));
402 *(UINT32
*)(*FixupData
) = *(UINT32
*)Fixup
;
403 *FixupData
= *FixupData
+ sizeof (UINT32
);
408 Error (NULL
, 0, 3000, "", "PeCoffLoaderRelocateLoongArch64Image: Fixup[0x%x] Adjust[0x%llx] *Reloc[0x%x], type[0x%x].", *(UINT32
*)Fixup
, Adjust
, *Reloc
, RelocType
);
409 return RETURN_UNSUPPORTED
;
412 return RETURN_SUCCESS
;