]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/Common/PeCoffLoaderEx.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Source / C / Common / PeCoffLoaderEx.c
CommitLineData
30fdf114 1/** @file\r
8daa4278 2IA32 and X64 Specific relocation fixups\r
30fdf114 3\r
f7496d71 4Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
4afd3d04 5Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>\r
ad1db975 6Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>\r
1aa311d1 7Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.<BR>\r
2e351cbe 8SPDX-License-Identifier: BSD-2-Clause-Patent\r
30fdf114 9\r
30fdf114
LG
10--*/\r
11\r
12#include <Common/UefiBaseTypes.h>\r
13#include <IndustryStandard/PeImage.h>\r
14#include "PeCoffLib.h"\r
da92f276 15#include "CommonLib.h"\r
4afd3d04 16#include "EfiUtilityMsgs.h"\r
da92f276 17\r
30fdf114
LG
18\r
19#define EXT_IMM64(Value, Address, Size, InstPos, ValPos) \\r
20 Value |= (((UINT64)((*(Address) >> InstPos) & (((UINT64)1 << Size) - 1))) << ValPos)\r
21\r
22#define INS_IMM64(Value, Address, Size, InstPos, ValPos) \\r
23 *(UINT32*)Address = (*(UINT32*)Address & ~(((1 << Size) - 1) << InstPos)) | \\r
24 ((UINT32)((((UINT64)Value >> ValPos) & (((UINT64)1 << Size) - 1))) << InstPos)\r
25\r
f7496d71
LG
26#define IMM64_IMM7B_INST_WORD_X 3\r
27#define IMM64_IMM7B_SIZE_X 7\r
28#define IMM64_IMM7B_INST_WORD_POS_X 4\r
29#define IMM64_IMM7B_VAL_POS_X 0\r
30\r
31#define IMM64_IMM9D_INST_WORD_X 3\r
32#define IMM64_IMM9D_SIZE_X 9\r
33#define IMM64_IMM9D_INST_WORD_POS_X 18\r
34#define IMM64_IMM9D_VAL_POS_X 7\r
35\r
36#define IMM64_IMM5C_INST_WORD_X 3\r
37#define IMM64_IMM5C_SIZE_X 5\r
38#define IMM64_IMM5C_INST_WORD_POS_X 13\r
39#define IMM64_IMM5C_VAL_POS_X 16\r
40\r
41#define IMM64_IC_INST_WORD_X 3\r
42#define IMM64_IC_SIZE_X 1\r
43#define IMM64_IC_INST_WORD_POS_X 12\r
44#define IMM64_IC_VAL_POS_X 21\r
45\r
46#define IMM64_IMM41a_INST_WORD_X 1\r
47#define IMM64_IMM41a_SIZE_X 10\r
48#define IMM64_IMM41a_INST_WORD_POS_X 14\r
49#define IMM64_IMM41a_VAL_POS_X 22\r
50\r
51#define IMM64_IMM41b_INST_WORD_X 1\r
52#define IMM64_IMM41b_SIZE_X 8\r
53#define IMM64_IMM41b_INST_WORD_POS_X 24\r
54#define IMM64_IMM41b_VAL_POS_X 32\r
55\r
56#define IMM64_IMM41c_INST_WORD_X 2\r
57#define IMM64_IMM41c_SIZE_X 23\r
58#define IMM64_IMM41c_INST_WORD_POS_X 0\r
59#define IMM64_IMM41c_VAL_POS_X 40\r
60\r
61#define IMM64_SIGN_INST_WORD_X 3\r
62#define IMM64_SIGN_SIZE_X 1\r
63#define IMM64_SIGN_INST_WORD_POS_X 27\r
64#define IMM64_SIGN_VAL_POS_X 63\r
30fdf114 65\r
ad1db975
AC
66UINT32 *RiscVHi20Fixup = NULL;\r
67\r
30fdf114
LG
68RETURN_STATUS\r
69PeCoffLoaderRelocateIa32Image (\r
70 IN UINT16 *Reloc,\r
71 IN OUT CHAR8 *Fixup,\r
72 IN OUT CHAR8 **FixupData,\r
73 IN UINT64 Adjust\r
74 )\r
75/*++\r
76\r
77Routine Description:\r
78\r
79 Performs an IA-32 specific relocation fixup\r
80\r
81Arguments:\r
82\r
83 Reloc - Pointer to the relocation record\r
84\r
85 Fixup - Pointer to the address to fix up\r
86\r
87 FixupData - Pointer to a buffer to log the fixups\r
88\r
89 Adjust - The offset to adjust the fixup\r
90\r
91Returns:\r
92\r
93 EFI_UNSUPPORTED - Unsupported now\r
94\r
95--*/\r
96{\r
97 return RETURN_UNSUPPORTED;\r
98}\r
99\r
ad1db975
AC
100/*++\r
101\r
102Routine Description:\r
103\r
104 Performs an RISC-V specific relocation fixup\r
105\r
106Arguments:\r
107\r
108 Reloc - Pointer to the relocation record\r
109\r
110 Fixup - Pointer to the address to fix up\r
111\r
112 FixupData - Pointer to a buffer to log the fixups\r
113\r
114 Adjust - The offset to adjust the fixup\r
115\r
116Returns:\r
117\r
118 Status code\r
119\r
120--*/\r
121RETURN_STATUS\r
122PeCoffLoaderRelocateRiscVImage (\r
123 IN UINT16 *Reloc,\r
124 IN OUT CHAR8 *Fixup,\r
125 IN OUT CHAR8 **FixupData,\r
126 IN UINT64 Adjust\r
127 )\r
128{\r
129 UINT32 Value;\r
130 UINT32 Value2;\r
ad1db975 131\r
ad1db975
AC
132 switch ((*Reloc) >> 12) {\r
133 case EFI_IMAGE_REL_BASED_RISCV_HI20:\r
134 RiscVHi20Fixup = (UINT32 *) Fixup;\r
135 break;\r
136\r
137 case EFI_IMAGE_REL_BASED_RISCV_LOW12I:\r
138 if (RiscVHi20Fixup != NULL) {\r
139 Value = (UINT32)(RV_X(*RiscVHi20Fixup, 12, 20) << 12);\r
140 Value2 = (UINT32)(RV_X(*(UINT32 *)Fixup, 20, 12));\r
141 if (Value2 & (RISCV_IMM_REACH/2)) {\r
142 Value2 |= ~(RISCV_IMM_REACH-1);\r
143 }\r
144 Value += Value2;\r
145 Value += (UINT32)Adjust;\r
146 Value2 = RISCV_CONST_HIGH_PART (Value);\r
147 *(UINT32 *)RiscVHi20Fixup = (RV_X (Value2, 12, 20) << 12) | \\r
148 (RV_X (*(UINT32 *)RiscVHi20Fixup, 0, 12));\r
149 *(UINT32 *)Fixup = (RV_X (Value, 0, 12) << 20) | \\r
150 (RV_X (*(UINT32 *)Fixup, 0, 20));\r
151 }\r
152 RiscVHi20Fixup = NULL;\r
153 break;\r
154\r
155 case EFI_IMAGE_REL_BASED_RISCV_LOW12S:\r
156 if (RiscVHi20Fixup != NULL) {\r
157 Value = (UINT32)(RV_X(*RiscVHi20Fixup, 12, 20) << 12);\r
158 Value2 = (UINT32)(RV_X(*(UINT32 *)Fixup, 7, 5) | (RV_X(*(UINT32 *)Fixup, 25, 7) << 5));\r
159 if (Value2 & (RISCV_IMM_REACH/2)) {\r
160 Value2 |= ~(RISCV_IMM_REACH-1);\r
161 }\r
162 Value += Value2;\r
163 Value += (UINT32)Adjust;\r
164 Value2 = RISCV_CONST_HIGH_PART (Value);\r
165 *(UINT32 *)RiscVHi20Fixup = (RV_X (Value2, 12, 20) << 12) | \\r
166 (RV_X (*(UINT32 *)RiscVHi20Fixup, 0, 12));\r
167 Value2 = *(UINT32 *)Fixup & 0x01fff07f;\r
168 Value &= RISCV_IMM_REACH - 1;\r
169 *(UINT32 *)Fixup = Value2 | (UINT32)(((RV_X(Value, 0, 5) << 7) | (RV_X(Value, 5, 7) << 25)));\r
170 }\r
171 RiscVHi20Fixup = NULL;\r
172 break;\r
173\r
174 default:\r
175 return EFI_UNSUPPORTED;\r
176\r
177 }\r
178 return RETURN_SUCCESS;\r
179}\r
30fdf114 180\r
40d841f6 181/**\r
fb0b35e0 182 Pass in a pointer to an ARM MOVT or MOVW immediate instruction and\r
40d841f6
LG
183 return the immediate data encoded in the instruction\r
184\r
185 @param Instruction Pointer to ARM MOVT or MOVW immediate instruction\r
186\r
187 @return Immediate address encoded in the instruction\r
188\r
189**/\r
190UINT16\r
191ThumbMovtImmediateAddress (\r
192 IN UINT16 *Instruction\r
193 )\r
194{\r
195 UINT32 Movt;\r
196 UINT16 Address;\r
197\r
198 // Thumb2 is two 16-bit instructions working together. Not a single 32-bit instruction\r
199 // Example MOVT R0, #0 is 0x0000f2c0 or 0xf2c0 0x0000\r
f7496d71 200 Movt = (*Instruction << 16) | (*(Instruction + 1));\r
40d841f6
LG
201\r
202 // imm16 = imm4:i:imm3:imm8\r
203 // imm4 -> Bit19:Bit16\r
204 // i -> Bit26\r
205 // imm3 -> Bit14:Bit12\r
206 // imm8 -> Bit7:Bit0\r
207 Address = (UINT16)(Movt & 0x000000ff); // imm8\r
208 Address |= (UINT16)((Movt >> 4) & 0x0000f700); // imm4 imm3\r
209 Address |= (((Movt & BIT26) != 0) ? BIT11 : 0); // i\r
210 return Address;\r
211}\r
212\r
213\r
214/**\r
215 Update an ARM MOVT or MOVW immediate instruction immediate data.\r
216\r
217 @param Instruction Pointer to ARM MOVT or MOVW immediate instruction\r
fb0b35e0 218 @param Address New address to patch into the instruction\r
40d841f6
LG
219**/\r
220VOID\r
221ThumbMovtImmediatePatch (\r
222 IN OUT UINT16 *Instruction,\r
223 IN UINT16 Address\r
224 )\r
225{\r
226 UINT16 Patch;\r
227\r
fb0b35e0 228 // First 16-bit chunk of instruction\r
f7496d71 229 Patch = ((Address >> 12) & 0x000f); // imm4\r
40d841f6
LG
230 Patch |= (((Address & BIT11) != 0) ? BIT10 : 0); // i\r
231 *Instruction = (*Instruction & ~0x040f) | Patch;\r
232\r
233 // Second 16-bit chunk of instruction\r
234 Patch = Address & 0x000000ff; // imm8\r
235 Patch |= ((Address << 4) & 0x00007000); // imm3\r
236 Instruction++;\r
237 *Instruction = (*Instruction & ~0x70ff) | Patch;\r
238}\r
239\r
da92f276 240/**\r
fb0b35e0 241 Pass in a pointer to an ARM MOVW/MOVT instruction pair and\r
da92f276
LG
242 return the immediate data encoded in the two` instruction\r
243\r
fb0b35e0 244 @param Instructions Pointer to ARM MOVW/MOVT instruction pair\r
da92f276
LG
245\r
246 @return Immediate address encoded in the instructions\r
247\r
248**/\r
249UINT32\r
250EFIAPI\r
251ThumbMovwMovtImmediateAddress (\r
252 IN UINT16 *Instructions\r
253 )\r
254{\r
255 UINT16 *Word;\r
256 UINT16 *Top;\r
f7496d71 257\r
da92f276
LG
258 Word = Instructions; // MOVW\r
259 Top = Word + 2; // MOVT\r
f7496d71 260\r
da92f276
LG
261 return (ThumbMovtImmediateAddress (Top) << 16) + ThumbMovtImmediateAddress (Word);\r
262}\r
263\r
264\r
265/**\r
266 Update an ARM MOVW/MOVT immediate instruction instruction pair.\r
267\r
268 @param Instructions Pointer to ARM MOVW/MOVT instruction pair\r
fb0b35e0 269 @param Address New address to patch into the instructions\r
da92f276
LG
270**/\r
271VOID\r
272EFIAPI\r
273ThumbMovwMovtImmediatePatch (\r
274 IN OUT UINT16 *Instructions,\r
275 IN UINT32 Address\r
276 )\r
277{\r
278 UINT16 *Word;\r
279 UINT16 *Top;\r
f7496d71 280\r
da92f276
LG
281 Word = (UINT16 *)Instructions; // MOVW\r
282 Top = Word + 2; // MOVT\r
283\r
284 ThumbMovtImmediatePatch (Word, (UINT16)(Address & 0xffff));\r
285 ThumbMovtImmediatePatch (Top, (UINT16)(Address >> 16));\r
286}\r
287\r
288\r
40d841f6
LG
289/**\r
290 Performs an ARM-based specific relocation fixup and is a no-op on other\r
291 instruction sets.\r
292\r
293 @param Reloc Pointer to the relocation record.\r
294 @param Fixup Pointer to the address to fix up.\r
295 @param FixupData Pointer to a buffer to log the fixups.\r
296 @param Adjust The offset to adjust the fixup.\r
297\r
298 @return Status code.\r
299\r
300**/\r
301RETURN_STATUS\r
302PeCoffLoaderRelocateArmImage (\r
303 IN UINT16 **Reloc,\r
304 IN OUT CHAR8 *Fixup,\r
305 IN OUT CHAR8 **FixupData,\r
306 IN UINT64 Adjust\r
307 )\r
308{\r
309 UINT16 *Fixup16;\r
da92f276 310 UINT32 FixupVal;\r
40d841f6 311\r
da92f276 312 Fixup16 = (UINT16 *) Fixup;\r
40d841f6
LG
313\r
314 switch ((**Reloc) >> 12) {\r
f7496d71 315\r
da92f276
LG
316 case EFI_IMAGE_REL_BASED_ARM_MOV32T:\r
317 FixupVal = ThumbMovwMovtImmediateAddress (Fixup16) + (UINT32)Adjust;\r
318 ThumbMovwMovtImmediatePatch (Fixup16, FixupVal);\r
f7496d71
LG
319\r
320\r
40d841f6 321 if (*FixupData != NULL) {\r
da92f276 322 *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64));\r
da92f276 323 CopyMem (*FixupData, Fixup16, sizeof (UINT64));\r
94762dde 324 *FixupData = *FixupData + sizeof(UINT64);\r
40d841f6
LG
325 }\r
326 break;\r
f7496d71 327\r
da92f276
LG
328 case EFI_IMAGE_REL_BASED_ARM_MOV32A:\r
329 // break omitted - ARM instruction encoding not implemented\r
40d841f6
LG
330 default:\r
331 return RETURN_UNSUPPORTED;\r
332 }\r
333\r
334 return RETURN_SUCCESS;\r
335}\r
1aa311d1
CL
336\r
337/**\r
338 Performs a LoongArch specific relocation fixup.\r
339\r
340 @param[in] Reloc Pointer to the relocation record.\r
341 @param[in, out] Fixup Pointer to the address to fix up.\r
342 @param[in, out] FixupData Pointer to a buffer to log the fixups.\r
343 @param[in] Adjust The offset to adjust the fixup.\r
344\r
345 @return Status code.\r
346**/\r
347RETURN_STATUS\r
348PeCoffLoaderRelocateLoongArch64Image (\r
349 IN UINT16 *Reloc,\r
350 IN OUT CHAR8 *Fixup,\r
351 IN OUT CHAR8 **FixupData,\r
352 IN UINT64 Adjust\r
353 )\r
354{\r
355 UINT8 RelocType;\r
356 UINT64 Value;\r
357 UINT64 Tmp1;\r
358 UINT64 Tmp2;\r
359\r
360 RelocType = ((*Reloc) >> 12);\r
361 Value = 0;\r
362 Tmp1 = 0;\r
363 Tmp2 = 0;\r
364\r
365 switch (RelocType) {\r
366 case EFI_IMAGE_REL_BASED_LOONGARCH64_MARK_LA:\r
367 // The next four instructions are used to load a 64 bit address, relocate all of them\r
368 Value = (*(UINT32 *)Fixup & 0x1ffffe0) << 7 | // lu12i.w 20bits from bit5\r
369 (*((UINT32 *)Fixup + 1) & 0x3ffc00) >> 10; // ori 12bits from bit10\r
370 Tmp1 = *((UINT32 *)Fixup + 2) & 0x1ffffe0; // lu32i.d 20bits from bit5\r
371 Tmp2 = *((UINT32 *)Fixup + 3) & 0x3ffc00; // lu52i.d 12bits from bit10\r
372 Value = Value | (Tmp1 << 27) | (Tmp2 << 42);\r
373 Value += Adjust;\r
374\r
375 *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x1ffffe0) | (((Value >> 12) & 0xfffff) << 5);\r
376 if (*FixupData != NULL) {\r
377 *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32));\r
378 *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup;\r
379 *FixupData = *FixupData + sizeof (UINT32);\r
380 }\r
381\r
382 Fixup += sizeof (UINT32);\r
383 *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x3ffc00) | ((Value & 0xfff) << 10);\r
384 if (*FixupData != NULL) {\r
385 *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32));\r
386 *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup;\r
387 *FixupData = *FixupData + sizeof (UINT32);\r
388 }\r
389\r
390 Fixup += sizeof (UINT32);\r
391 *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x1ffffe0) | (((Value >> 32) & 0xfffff) << 5);\r
392 if (*FixupData != NULL) {\r
393 *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32));\r
394 *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup;\r
395 *FixupData = *FixupData + sizeof (UINT32);\r
396 }\r
397\r
398 Fixup += sizeof (UINT32);\r
399 *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x3ffc00) | (((Value >> 52) & 0xfff) << 10);\r
400 if (*FixupData != NULL) {\r
401 *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32));\r
402 *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup;\r
403 *FixupData = *FixupData + sizeof (UINT32);\r
404 }\r
405\r
406 break;\r
407 default:\r
408 Error (NULL, 0, 3000, "", "PeCoffLoaderRelocateLoongArch64Image: Fixup[0x%x] Adjust[0x%llx] *Reloc[0x%x], type[0x%x].", *(UINT32 *)Fixup, Adjust, *Reloc, RelocType);\r
409 return RETURN_UNSUPPORTED;\r
410 }\r
411\r
412 return RETURN_SUCCESS;\r
413}\r