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     break;
238 
239   case EFI_IMAGE_REL_BASED_ARM_MOV32A:
240     ASSERT (FALSE);
241     // break omitted - ARM instruction encoding not implemented
242   default:
243     DEBUG ((EFI_D_ERROR, "PeHotRelocateEx:unknown fixed type\n"));
244     return RETURN_UNSUPPORTED;
245   }
246 
247   return RETURN_SUCCESS;
248 }
249 
250