diff options
Diffstat (limited to 'arch/arm/kernel/module.c')
-rw-r--r-- | arch/arm/kernel/module.c | 57 |
1 files changed, 34 insertions, 23 deletions
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 084dc8896986..5fdb4038f969 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <asm/sections.h> | 24 | #include <asm/sections.h> |
25 | #include <asm/smp_plat.h> | 25 | #include <asm/smp_plat.h> |
26 | #include <asm/unwind.h> | 26 | #include <asm/unwind.h> |
27 | #include <asm/opcodes.h> | ||
27 | 28 | ||
28 | #ifdef CONFIG_XIP_KERNEL | 29 | #ifdef CONFIG_XIP_KERNEL |
29 | /* | 30 | /* |
@@ -60,6 +61,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
60 | Elf32_Sym *sym; | 61 | Elf32_Sym *sym; |
61 | const char *symname; | 62 | const char *symname; |
62 | s32 offset; | 63 | s32 offset; |
64 | u32 tmp; | ||
63 | #ifdef CONFIG_THUMB2_KERNEL | 65 | #ifdef CONFIG_THUMB2_KERNEL |
64 | u32 upper, lower, sign, j1, j2; | 66 | u32 upper, lower, sign, j1, j2; |
65 | #endif | 67 | #endif |
@@ -95,7 +97,8 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
95 | case R_ARM_PC24: | 97 | case R_ARM_PC24: |
96 | case R_ARM_CALL: | 98 | case R_ARM_CALL: |
97 | case R_ARM_JUMP24: | 99 | case R_ARM_JUMP24: |
98 | offset = (*(u32 *)loc & 0x00ffffff) << 2; | 100 | offset = __mem_to_opcode_arm(*(u32 *)loc); |
101 | offset = (offset & 0x00ffffff) << 2; | ||
99 | if (offset & 0x02000000) | 102 | if (offset & 0x02000000) |
100 | offset -= 0x04000000; | 103 | offset -= 0x04000000; |
101 | 104 | ||
@@ -111,9 +114,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
111 | } | 114 | } |
112 | 115 | ||
113 | offset >>= 2; | 116 | offset >>= 2; |
117 | offset &= 0x00ffffff; | ||
114 | 118 | ||
115 | *(u32 *)loc &= 0xff000000; | 119 | *(u32 *)loc &= __opcode_to_mem_arm(0xff000000); |
116 | *(u32 *)loc |= offset & 0x00ffffff; | 120 | *(u32 *)loc |= __opcode_to_mem_arm(offset); |
117 | break; | 121 | break; |
118 | 122 | ||
119 | case R_ARM_V4BX: | 123 | case R_ARM_V4BX: |
@@ -121,8 +125,8 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
121 | * other bits to re-code instruction as | 125 | * other bits to re-code instruction as |
122 | * MOV PC,Rm. | 126 | * MOV PC,Rm. |
123 | */ | 127 | */ |
124 | *(u32 *)loc &= 0xf000000f; | 128 | *(u32 *)loc &= __opcode_to_mem_arm(0xf000000f); |
125 | *(u32 *)loc |= 0x01a0f000; | 129 | *(u32 *)loc |= __opcode_to_mem_arm(0x01a0f000); |
126 | break; | 130 | break; |
127 | 131 | ||
128 | case R_ARM_PREL31: | 132 | case R_ARM_PREL31: |
@@ -132,7 +136,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
132 | 136 | ||
133 | case R_ARM_MOVW_ABS_NC: | 137 | case R_ARM_MOVW_ABS_NC: |
134 | case R_ARM_MOVT_ABS: | 138 | case R_ARM_MOVT_ABS: |
135 | offset = *(u32 *)loc; | 139 | offset = tmp = __mem_to_opcode_arm(*(u32 *)loc); |
136 | offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff); | 140 | offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff); |
137 | offset = (offset ^ 0x8000) - 0x8000; | 141 | offset = (offset ^ 0x8000) - 0x8000; |
138 | 142 | ||
@@ -140,16 +144,18 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
140 | if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_ABS) | 144 | if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_ABS) |
141 | offset >>= 16; | 145 | offset >>= 16; |
142 | 146 | ||
143 | *(u32 *)loc &= 0xfff0f000; | 147 | tmp &= 0xfff0f000; |
144 | *(u32 *)loc |= ((offset & 0xf000) << 4) | | 148 | tmp |= ((offset & 0xf000) << 4) | |
145 | (offset & 0x0fff); | 149 | (offset & 0x0fff); |
150 | |||
151 | *(u32 *)loc = __opcode_to_mem_arm(tmp); | ||
146 | break; | 152 | break; |
147 | 153 | ||
148 | #ifdef CONFIG_THUMB2_KERNEL | 154 | #ifdef CONFIG_THUMB2_KERNEL |
149 | case R_ARM_THM_CALL: | 155 | case R_ARM_THM_CALL: |
150 | case R_ARM_THM_JUMP24: | 156 | case R_ARM_THM_JUMP24: |
151 | upper = *(u16 *)loc; | 157 | upper = __mem_to_opcode_thumb16(*(u16 *)loc); |
152 | lower = *(u16 *)(loc + 2); | 158 | lower = __mem_to_opcode_thumb16(*(u16 *)(loc + 2)); |
153 | 159 | ||
154 | /* | 160 | /* |
155 | * 25 bit signed address range (Thumb-2 BL and B.W | 161 | * 25 bit signed address range (Thumb-2 BL and B.W |
@@ -198,17 +204,20 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
198 | sign = (offset >> 24) & 1; | 204 | sign = (offset >> 24) & 1; |
199 | j1 = sign ^ (~(offset >> 23) & 1); | 205 | j1 = sign ^ (~(offset >> 23) & 1); |
200 | j2 = sign ^ (~(offset >> 22) & 1); | 206 | j2 = sign ^ (~(offset >> 22) & 1); |
201 | *(u16 *)loc = (u16)((upper & 0xf800) | (sign << 10) | | 207 | upper = (u16)((upper & 0xf800) | (sign << 10) | |
202 | ((offset >> 12) & 0x03ff)); | 208 | ((offset >> 12) & 0x03ff)); |
203 | *(u16 *)(loc + 2) = (u16)((lower & 0xd000) | | 209 | lower = (u16)((lower & 0xd000) | |
204 | (j1 << 13) | (j2 << 11) | | 210 | (j1 << 13) | (j2 << 11) | |
205 | ((offset >> 1) & 0x07ff)); | 211 | ((offset >> 1) & 0x07ff)); |
212 | |||
213 | *(u16 *)loc = __opcode_to_mem_thumb16(upper); | ||
214 | *(u16 *)(loc + 2) = __opcode_to_mem_thumb16(lower); | ||
206 | break; | 215 | break; |
207 | 216 | ||
208 | case R_ARM_THM_MOVW_ABS_NC: | 217 | case R_ARM_THM_MOVW_ABS_NC: |
209 | case R_ARM_THM_MOVT_ABS: | 218 | case R_ARM_THM_MOVT_ABS: |
210 | upper = *(u16 *)loc; | 219 | upper = __mem_to_opcode_thumb16(*(u16 *)loc); |
211 | lower = *(u16 *)(loc + 2); | 220 | lower = __mem_to_opcode_thumb16(*(u16 *)(loc + 2)); |
212 | 221 | ||
213 | /* | 222 | /* |
214 | * MOVT/MOVW instructions encoding in Thumb-2: | 223 | * MOVT/MOVW instructions encoding in Thumb-2: |
@@ -229,12 +238,14 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
229 | if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS) | 238 | if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS) |
230 | offset >>= 16; | 239 | offset >>= 16; |
231 | 240 | ||
232 | *(u16 *)loc = (u16)((upper & 0xfbf0) | | 241 | upper = (u16)((upper & 0xfbf0) | |
233 | ((offset & 0xf000) >> 12) | | 242 | ((offset & 0xf000) >> 12) | |
234 | ((offset & 0x0800) >> 1)); | 243 | ((offset & 0x0800) >> 1)); |
235 | *(u16 *)(loc + 2) = (u16)((lower & 0x8f00) | | 244 | lower = (u16)((lower & 0x8f00) | |
236 | ((offset & 0x0700) << 4) | | 245 | ((offset & 0x0700) << 4) | |
237 | (offset & 0x00ff)); | 246 | (offset & 0x00ff)); |
247 | *(u16 *)loc = __opcode_to_mem_thumb16(upper); | ||
248 | *(u16 *)(loc + 2) = __opcode_to_mem_thumb16(lower); | ||
238 | break; | 249 | break; |
239 | #endif | 250 | #endif |
240 | 251 | ||