1 /** @file
2 IA32 and X64 Specific relocation fixups
3
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 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 --*/
10
11 #include <Common/UefiBaseTypes.h>
12 #include <IndustryStandard/PeImage.h>
13 #include "PeCoffLib.h"
14 #include "CommonLib.h"
15 #include "EfiUtilityMsgs.h"
16
17
18 #define EXT_IMM64(Value, Address, Size, InstPos, ValPos) \
19 Value |= (((UINT64)((*(Address) >> InstPos) & (((UINT64)1 << Size) - 1))) << ValPos)
20
21 #define INS_IMM64(Value, Address, Size, InstPos, ValPos) \
22 *(UINT32*)Address = (*(UINT32*)Address & ~(((1 << Size) - 1) << InstPos)) | \
23 ((UINT32)((((UINT64)Value >> ValPos) & (((UINT64)1 << Size) - 1))) << InstPos)
24
25 #define IMM64_IMM7B_INST_WORD_X 3
26 #define IMM64_IMM7B_SIZE_X 7
27 #define IMM64_IMM7B_INST_WORD_POS_X 4
28 #define IMM64_IMM7B_VAL_POS_X 0
29
30 #define IMM64_IMM9D_INST_WORD_X 3
31 #define IMM64_IMM9D_SIZE_X 9
32 #define IMM64_IMM9D_INST_WORD_POS_X 18
33 #define IMM64_IMM9D_VAL_POS_X 7
34
35 #define IMM64_IMM5C_INST_WORD_X 3
36 #define IMM64_IMM5C_SIZE_X 5
37 #define IMM64_IMM5C_INST_WORD_POS_X 13
38 #define IMM64_IMM5C_VAL_POS_X 16
39
40 #define IMM64_IC_INST_WORD_X 3
41 #define IMM64_IC_SIZE_X 1
42 #define IMM64_IC_INST_WORD_POS_X 12
43 #define IMM64_IC_VAL_POS_X 21
44
45 #define IMM64_IMM41a_INST_WORD_X 1
46 #define IMM64_IMM41a_SIZE_X 10
47 #define IMM64_IMM41a_INST_WORD_POS_X 14
48 #define IMM64_IMM41a_VAL_POS_X 22
49
50 #define IMM64_IMM41b_INST_WORD_X 1
51 #define IMM64_IMM41b_SIZE_X 8
52 #define IMM64_IMM41b_INST_WORD_POS_X 24
53 #define IMM64_IMM41b_VAL_POS_X 32
54
55 #define IMM64_IMM41c_INST_WORD_X 2
56 #define IMM64_IMM41c_SIZE_X 23
57 #define IMM64_IMM41c_INST_WORD_POS_X 0
58 #define IMM64_IMM41c_VAL_POS_X 40
59
60 #define IMM64_SIGN_INST_WORD_X 3
61 #define IMM64_SIGN_SIZE_X 1
62 #define IMM64_SIGN_INST_WORD_POS_X 27
63 #define IMM64_SIGN_VAL_POS_X 63
64
65 UINT32 *RiscVHi20Fixup = NULL;
66
67 RETURN_STATUS
PeCoffLoaderRelocateIa32Image(IN UINT16 * Reloc,IN OUT CHAR8 * Fixup,IN OUT CHAR8 ** FixupData,IN UINT64 Adjust)68 PeCoffLoaderRelocateIa32Image (
69 IN UINT16 *Reloc,
70 IN OUT CHAR8 *Fixup,
71 IN OUT CHAR8 **FixupData,
72 IN UINT64 Adjust
73 )
74 /*++
75
76 Routine Description:
77
78 Performs an IA-32 specific relocation fixup
79
80 Arguments:
81
82 Reloc - Pointer to the relocation record
83
84 Fixup - Pointer to the address to fix up
85
86 FixupData - Pointer to a buffer to log the fixups
87
88 Adjust - The offset to adjust the fixup
89
90 Returns:
91
92 EFI_UNSUPPORTED - Unsupported now
93
94 --*/
95 {
96 return RETURN_UNSUPPORTED;
97 }
98
99 /*++
100
101 Routine Description:
102
103 Performs an RISC-V specific relocation fixup
104
105 Arguments:
106
107 Reloc - Pointer to the relocation record
108
109 Fixup - Pointer to the address to fix up
110
111 FixupData - Pointer to a buffer to log the fixups
112
113 Adjust - The offset to adjust the fixup
114
115 Returns:
116
117 Status code
118
119 --*/
120 RETURN_STATUS
PeCoffLoaderRelocateRiscVImage(IN UINT16 * Reloc,IN OUT CHAR8 * Fixup,IN OUT CHAR8 ** FixupData,IN UINT64 Adjust)121 PeCoffLoaderRelocateRiscVImage (
122 IN UINT16 *Reloc,
123 IN OUT CHAR8 *Fixup,
124 IN OUT CHAR8 **FixupData,
125 IN UINT64 Adjust
126 )
127 {
128 UINT32 Value;
129 UINT32 Value2;
130
131 switch ((*Reloc) >> 12) {
132 case EFI_IMAGE_REL_BASED_RISCV_HI20:
133 RiscVHi20Fixup = (UINT32 *) Fixup;
134 break;
135
136 case EFI_IMAGE_REL_BASED_RISCV_LOW12I:
137 if (RiscVHi20Fixup != NULL) {
138 Value = (UINT32)(RV_X(*RiscVHi20Fixup, 12, 20) << 12);
139 Value2 = (UINT32)(RV_X(*(UINT32 *)Fixup, 20, 12));
140 if (Value2 & (RISCV_IMM_REACH/2)) {
141 Value2 |= ~(RISCV_IMM_REACH-1);
142 }
143 Value += Value2;
144 Value += (UINT32)Adjust;
145 Value2 = RISCV_CONST_HIGH_PART (Value);
146 *(UINT32 *)RiscVHi20Fixup = (RV_X (Value2, 12, 20) << 12) | \
147 (RV_X (*(UINT32 *)RiscVHi20Fixup, 0, 12));
148 *(UINT32 *)Fixup = (RV_X (Value, 0, 12) << 20) | \
149 (RV_X (*(UINT32 *)Fixup, 0, 20));
150 }
151 RiscVHi20Fixup = NULL;
152 break;
153
154 case EFI_IMAGE_REL_BASED_RISCV_LOW12S:
155 if (RiscVHi20Fixup != NULL) {
156 Value = (UINT32)(RV_X(*RiscVHi20Fixup, 12, 20) << 12);
157 Value2 = (UINT32)(RV_X(*(UINT32 *)Fixup, 7, 5) | (RV_X(*(UINT32 *)Fixup, 25, 7) << 5));
158 if (Value2 & (RISCV_IMM_REACH/2)) {
159 Value2 |= ~(RISCV_IMM_REACH-1);
160 }
161 Value += Value2;
162 Value += (UINT32)Adjust;
163 Value2 = RISCV_CONST_HIGH_PART (Value);
164 *(UINT32 *)RiscVHi20Fixup = (RV_X (Value2, 12, 20) << 12) | \
165 (RV_X (*(UINT32 *)RiscVHi20Fixup, 0, 12));
166 Value2 = *(UINT32 *)Fixup & 0x01fff07f;
167 Value &= RISCV_IMM_REACH - 1;
168 *(UINT32 *)Fixup = Value2 | (UINT32)(((RV_X(Value, 0, 5) << 7) | (RV_X(Value, 5, 7) << 25)));
169 }
170 RiscVHi20Fixup = NULL;
171 break;
172
173 default:
174 return EFI_UNSUPPORTED;
175
176 }
177 return RETURN_SUCCESS;
178 }
179
180 /**
181 Pass in a pointer to an ARM MOVT or MOVW immediate instruction and
182 return the immediate data encoded in the instruction
183
184 @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
185
186 @return Immediate address encoded in the instruction
187
188 **/
189 UINT16
ThumbMovtImmediateAddress(IN UINT16 * Instruction)190 ThumbMovtImmediateAddress (
191 IN UINT16 *Instruction
192 )
193 {
194 UINT32 Movt;
195 UINT16 Address;
196
197 // Thumb2 is two 16-bit instructions working together. Not a single 32-bit instruction
198 // Example MOVT R0, #0 is 0x0000f2c0 or 0xf2c0 0x0000
199 Movt = (*Instruction << 16) | (*(Instruction + 1));
200
201 // imm16 = imm4:i:imm3:imm8
202 // imm4 -> Bit19:Bit16
203 // i -> Bit26
204 // imm3 -> Bit14:Bit12
205 // imm8 -> Bit7:Bit0
206 Address = (UINT16)(Movt & 0x000000ff); // imm8
207 Address |= (UINT16)((Movt >> 4) & 0x0000f700); // imm4 imm3
208 Address |= (((Movt & BIT26) != 0) ? BIT11 : 0); // i
209 return Address;
210 }
211
212
213 /**
214 Update an ARM MOVT or MOVW immediate instruction immediate data.
215
216 @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
217 @param Address New address to patch into the instruction
218 **/
219 VOID
ThumbMovtImmediatePatch(IN OUT UINT16 * Instruction,IN UINT16 Address)220 ThumbMovtImmediatePatch (
221 IN OUT UINT16 *Instruction,
222 IN UINT16 Address
223 )
224 {
225 UINT16 Patch;
226
227 // First 16-bit chunk of instruction
228 Patch = ((Address >> 12) & 0x000f); // imm4
229 Patch |= (((Address & BIT11) != 0) ? BIT10 : 0); // i
230 *Instruction = (*Instruction & ~0x040f) | Patch;
231
232 // Second 16-bit chunk of instruction
233 Patch = Address & 0x000000ff; // imm8
234 Patch |= ((Address << 4) & 0x00007000); // imm3
235 Instruction++;
236 *Instruction = (*Instruction & ~0x70ff) | Patch;
237 }
238
239 /**
240 Pass in a pointer to an ARM MOVW/MOVT instruction pair and
241 return the immediate data encoded in the two` instruction
242
243 @param Instructions Pointer to ARM MOVW/MOVT instruction pair
244
245 @return Immediate address encoded in the instructions
246
247 **/
248 UINT32
249 EFIAPI
ThumbMovwMovtImmediateAddress(IN UINT16 * Instructions)250 ThumbMovwMovtImmediateAddress (
251 IN UINT16 *Instructions
252 )
253 {
254 UINT16 *Word;
255 UINT16 *Top;
256
257 Word = Instructions; // MOVW
258 Top = Word + 2; // MOVT
259
260 return (ThumbMovtImmediateAddress (Top) << 16) + ThumbMovtImmediateAddress (Word);
261 }
262
263
264 /**
265 Update an ARM MOVW/MOVT immediate instruction instruction pair.
266
267 @param Instructions Pointer to ARM MOVW/MOVT instruction pair
268 @param Address New address to patch into the instructions
269 **/
270 VOID
271 EFIAPI
ThumbMovwMovtImmediatePatch(IN OUT UINT16 * Instructions,IN UINT32 Address)272 ThumbMovwMovtImmediatePatch (
273 IN OUT UINT16 *Instructions,
274 IN UINT32 Address
275 )
276 {
277 UINT16 *Word;
278 UINT16 *Top;
279
280 Word = (UINT16 *)Instructions; // MOVW
281 Top = Word + 2; // MOVT
282
283 ThumbMovtImmediatePatch (Word, (UINT16)(Address & 0xffff));
284 ThumbMovtImmediatePatch (Top, (UINT16)(Address >> 16));
285 }
286
287
288 /**
289 Performs an ARM-based specific relocation fixup and is a no-op on other
290 instruction sets.
291
292 @param Reloc Pointer to the relocation record.
293 @param Fixup Pointer to the address to fix up.
294 @param FixupData Pointer to a buffer to log the fixups.
295 @param Adjust The offset to adjust the fixup.
296
297 @return Status code.
298
299 **/
300 RETURN_STATUS
PeCoffLoaderRelocateArmImage(IN UINT16 ** Reloc,IN OUT CHAR8 * Fixup,IN OUT CHAR8 ** FixupData,IN UINT64 Adjust)301 PeCoffLoaderRelocateArmImage (
302 IN UINT16 **Reloc,
303 IN OUT CHAR8 *Fixup,
304 IN OUT CHAR8 **FixupData,
305 IN UINT64 Adjust
306 )
307 {
308 UINT16 *Fixup16;
309 UINT32 FixupVal;
310
311 Fixup16 = (UINT16 *) Fixup;
312
313 switch ((**Reloc) >> 12) {
314
315 case EFI_IMAGE_REL_BASED_ARM_MOV32T:
316 FixupVal = ThumbMovwMovtImmediateAddress (Fixup16) + (UINT32)Adjust;
317 ThumbMovwMovtImmediatePatch (Fixup16, FixupVal);
318
319
320 if (*FixupData != NULL) {
321 *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64));
322 CopyMem (*FixupData, Fixup16, sizeof (UINT64));
323 *FixupData = *FixupData + sizeof(UINT64);
324 }
325 break;
326
327 case EFI_IMAGE_REL_BASED_ARM_MOV32A:
328 // break omitted - ARM instruction encoding not implemented
329 default:
330 return RETURN_UNSUPPORTED;
331 }
332
333 return RETURN_SUCCESS;
334 }
335