1 /** @file
2 Specific relocation fixups for ARM architecture.
3
4 Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2008 - 2010, Apple Inc. 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 "BasePeCoffLibInternals.h"
17 #include <Library/BaseLib.h>
18
19
20 /**
21 Pass in a pointer to an ARM MOVT or MOVW immediate instruciton and
22 return the immediate data encoded in the instruction.
23
24 @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
25
26 @return Immediate address encoded in the instruction
27
28 **/
29 UINT16
ThumbMovtImmediateAddress(IN UINT16 * Instruction)30 ThumbMovtImmediateAddress (
31 IN UINT16 *Instruction
32 )
33 {
34 UINT32 Movt;
35 UINT16 Address;
36
37 // Thumb2 is two 16-bit instructions working together. Not a single 32-bit instruction
38 // Example MOVT R0, #0 is 0x0000f2c0 or 0xf2c0 0x0000
39 Movt = (*Instruction << 16) | (*(Instruction + 1));
40
41 // imm16 = imm4:i:imm3:imm8
42 // imm4 -> Bit19:Bit16
43 // i -> Bit26
44 // imm3 -> Bit14:Bit12
45 // imm8 -> Bit7:Bit0
46 Address = (UINT16)(Movt & 0x000000ff); // imm8
47 Address |= (UINT16)((Movt >> 4) & 0x0000f700); // imm4 imm3
48 Address |= (((Movt & BIT26) != 0) ? BIT11 : 0); // i
49 return Address;
50 }
51
52
53 /**
54 Update an ARM MOVT or MOVW immediate instruction immediate data.
55
56 @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
57 @param Address New addres to patch into the instruction
58 **/
59 VOID
ThumbMovtImmediatePatch(IN OUT UINT16 * Instruction,IN UINT16 Address)60 ThumbMovtImmediatePatch (
61 IN OUT UINT16 *Instruction,
62 IN UINT16 Address
63 )
64 {
65 UINT16 Patch;
66
67 // First 16-bit chunk of instruciton
68 Patch = ((Address >> 12) & 0x000f); // imm4
69 Patch |= (((Address & BIT11) != 0) ? BIT10 : 0); // i
70 // Mask out instruction bits and or in address
71 *(Instruction) = (*Instruction & ~0x040f) | Patch;
72
73 // Second 16-bit chunk of instruction
74 Patch = Address & 0x000000ff; // imm8
75 Patch |= ((Address << 4) & 0x00007000); // imm3
76 // Mask out instruction bits and or in address
77 Instruction++;
78 *Instruction = (*Instruction & ~0x70ff) | Patch;
79 }
80
81
82
83 /**
84 Pass in a pointer to an ARM MOVW/MOVT instruciton pair and
85 return the immediate data encoded in the two` instruction.
86
87 @param Instructions Pointer to ARM MOVW/MOVT insturction pair
88
89 @return Immediate address encoded in the instructions
90
91 **/
92 UINT32
ThumbMovwMovtImmediateAddress(IN UINT16 * Instructions)93 ThumbMovwMovtImmediateAddress (
94 IN UINT16 *Instructions
95 )
96 {
97 UINT16 *Word;
98 UINT16 *Top;
99
100 Word = Instructions; // MOVW
101 Top = Word + 2; // MOVT
102
103 return (ThumbMovtImmediateAddress (Top) << 16) + ThumbMovtImmediateAddress (Word);
104 }
105
106
107 /**
108 Update an ARM MOVW/MOVT immediate instruction instruction pair.
109
110 @param Instructions Pointer to ARM MOVW/MOVT instruction pair
111 @param Address New addres to patch into the instructions
112 **/
113 VOID
ThumbMovwMovtImmediatePatch(IN OUT UINT16 * Instructions,IN UINT32 Address)114 ThumbMovwMovtImmediatePatch (
115 IN OUT UINT16 *Instructions,
116 IN UINT32 Address
117 )
118 {
119 UINT16 *Word;
120 UINT16 *Top;
121
122 Word = Instructions; // MOVW
123 Top = Word + 2; // MOVT
124
125 ThumbMovtImmediatePatch (Word, (UINT16)(Address & 0xffff));
126 ThumbMovtImmediatePatch (Top, (UINT16)(Address >> 16));
127 }
128
129
130
131 /**
132 Performs an ARM-based specific relocation fixup and is a no-op on other
133 instruction sets.
134
135 @param Reloc The pointer to the relocation record.
136 @param Fixup The pointer to the address to fix up.
137 @param FixupData The pointer to a buffer to log the fixups.
138 @param Adjust The offset to adjust the fixup.
139
140 @return Status code.
141
142 **/
143 RETURN_STATUS
PeCoffLoaderRelocateImageEx(IN UINT16 * Reloc,IN OUT CHAR8 * Fixup,IN OUT CHAR8 ** FixupData,IN UINT64 Adjust)144 PeCoffLoaderRelocateImageEx (
145 IN UINT16 *Reloc,
146 IN OUT CHAR8 *Fixup,
147 IN OUT CHAR8 **FixupData,
148 IN UINT64 Adjust
149 )
150 {
151 UINT16 *Fixup16;
152 UINT32 FixupVal;
153
154 Fixup16 = (UINT16 *) Fixup;
155
156 switch ((*Reloc) >> 12) {
157
158 case EFI_IMAGE_REL_BASED_ARM_MOV32T:
159 FixupVal = ThumbMovwMovtImmediateAddress (Fixup16) + (UINT32)Adjust;
160 ThumbMovwMovtImmediatePatch (Fixup16, FixupVal);
161
162 if (*FixupData != NULL) {
163 *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64));
164 // Fixup16 is not aligned so we must copy it. Thumb instructions are streams of 16 bytes.
165 CopyMem (*FixupData, Fixup16, sizeof (UINT64));
166 *FixupData = *FixupData + sizeof(UINT64);
167 }
168 break;
169
170 case EFI_IMAGE_REL_BASED_ARM_MOV32A:
171 ASSERT (FALSE);
172 // break omitted - ARM instruction encoding not implemented
173 default:
174 return RETURN_UNSUPPORTED;
175 }
176
177 return RETURN_SUCCESS;
178 }
179
180 /**
181 Returns TRUE if the machine type of PE/COFF image is supported. Supported
182 does not mean the image can be executed it means the PE/COFF loader supports
183 loading and relocating of the image type. It's up to the caller to support
184 the entry point.
185
186 @param Machine Machine type from the PE Header.
187
188 @return TRUE if this PE/COFF loader can load the image
189
190 **/
191 BOOLEAN
PeCoffLoaderImageFormatSupported(IN UINT16 Machine)192 PeCoffLoaderImageFormatSupported (
193 IN UINT16 Machine
194 )
195 {
196 if ((Machine == IMAGE_FILE_MACHINE_ARMTHUMB_MIXED) || (Machine == IMAGE_FILE_MACHINE_EBC)) {
197 return TRUE;
198 }
199
200 return FALSE;
201 }
202
203 /**
204 Performs an ARM-based specific re-relocation fixup and is a no-op on other
205 instruction sets. This is used to re-relocated the image into the EFI virtual
206 space for runtime calls.
207
208 @param Reloc The pointer to the relocation record.
209 @param Fixup The pointer to the address to fix up.
210 @param FixupData The pointer to a buffer to log the fixups.
211 @param Adjust The offset to adjust the fixup.
212
213 @return Status code.
214
215 **/
216 RETURN_STATUS
PeHotRelocateImageEx(IN UINT16 * Reloc,IN OUT CHAR8 * Fixup,IN OUT CHAR8 ** FixupData,IN UINT64 Adjust)217 PeHotRelocateImageEx (
218 IN UINT16 *Reloc,
219 IN OUT CHAR8 *Fixup,
220 IN OUT CHAR8 **FixupData,
221 IN UINT64 Adjust
222 )
223 {
224 UINT16 *Fixup16;
225 UINT32 FixupVal;
226
227 Fixup16 = (UINT16 *)Fixup;
228
229 switch ((*Reloc) >> 12) {
230
231 case EFI_IMAGE_REL_BASED_ARM_MOV32T:
232 *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT64));
233 if (*(UINT64 *) (*FixupData) == ReadUnaligned64 ((UINT64 *)Fixup16)) {
234 FixupVal = ThumbMovwMovtImmediateAddress (Fixup16) + (UINT32)Adjust;
235 ThumbMovwMovtImmediatePatch (Fixup16, FixupVal);
236 }
237 *FixupData = *FixupData + sizeof(UINT64);
238 break;
239
240 case EFI_IMAGE_REL_BASED_ARM_MOV32A:
241 ASSERT (FALSE);
242 // break omitted - ARM instruction encoding not implemented
243 default:
244 DEBUG ((EFI_D_ERROR, "PeHotRelocateEx:unknown fixed type\n"));
245 return RETURN_UNSUPPORTED;
246 }
247
248 return RETURN_SUCCESS;
249 }
250
251