11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  linux/arch/arm/kernel/module.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2002 Russell King.
56a570b28b5948e7bf54ea42ec3161bded0a1c460Hyok S. Choi *  Modified for nommu by Hyok S. Choi
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Module allocation method suggested by Andi Kleen.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
14f339ab3d6c59f8f898c165384aa2b6a0ae5d4c1cRussell King#include <linux/moduleloader.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
1627ac792ca0b0a1e7e65f20342260650516c95864Andrea Righi#include <linux/mm.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/elf.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
215a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
2437efe6427dd50e889473fb3c7fcec02dbbd098ebRussell King#include <asm/sections.h>
254a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King#include <asm/smp_plat.h>
262e1926e7b5d39eb31880152d636e8d8d011888cbCatalin Marinas#include <asm/unwind.h>
27f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks#include <asm/opcodes.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_XIP_KERNEL
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The XIP kernel text is mapped in the module area for modules and
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * some other stuff to work without any indirect relocations.
33ab4f2ee130d5ffcf35616e1f5c6ab75af5b463b6Russell King * MODULES_VADDR is redefined here and not in asm/memory.h to avoid
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * recompiling the whole kernel when CONFIG_XIP_KERNEL is turned on/off.
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
36ab4f2ee130d5ffcf35616e1f5c6ab75af5b463b6Russell King#undef MODULES_VADDR
37e73fc88e19d74fd4dd664cff45b88caab8cde45cCatalin Marinas#define MODULES_VADDR	(((unsigned long)_etext + ~PMD_MASK) & PMD_MASK)
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
406a570b28b5948e7bf54ea42ec3161bded0a1c460Hyok S. Choi#ifdef CONFIG_MMU
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid *module_alloc(unsigned long size)
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
43d0a21265dfb5fa8ae54e90d0fb6d1c215b10a28aDavid Rientjes	return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
4440c3baa7c66f1352521378ee83509fb8f4c465deJianguo Wu				GFP_KERNEL, PAGE_KERNEL_EXEC, NUMA_NO_NODE,
45d0a21265dfb5fa8ae54e90d0fb6d1c215b10a28aDavid Rientjes				__builtin_return_address(0));
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4766574cc05438dd0907029075d7e6ec5ac0036fbcJonas Bonn#endif
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsapply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       unsigned int relindex, struct module *module)
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Elf32_Shdr *symsec = sechdrs + symindex;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Elf32_Shdr *relsec = sechdrs + relindex;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Elf32_Shdr *dstsec = sechdrs + relsec->sh_info;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Elf32_Rel *rel = (void *)relsec->sh_addr;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int i;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) {
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long loc;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		Elf32_Sym *sym;
6268e6fad488ef21335529c65ca6c88c38be50cd3aRussell King		const char *symname;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		s32 offset;
64f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks		u32 tmp;
65b749315601b44a63634d1a38fd167b8cac0e9ad4Catalin Marinas#ifdef CONFIG_THUMB2_KERNEL
66adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas		u32 upper, lower, sign, j1, j2;
67b749315601b44a63634d1a38fd167b8cac0e9ad4Catalin Marinas#endif
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offset = ELF32_R_SYM(rel->r_info);
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) {
7168e6fad488ef21335529c65ca6c88c38be50cd3aRussell King			pr_err("%s: section %u reloc %u: bad relocation sym offset\n",
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				module->name, relindex, i);
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOEXEC;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sym = ((Elf32_Sym *)symsec->sh_addr) + offset;
7768e6fad488ef21335529c65ca6c88c38be50cd3aRussell King		symname = strtab + sym->st_name;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) {
8068e6fad488ef21335529c65ca6c88c38be50cd3aRussell King			pr_err("%s: section %u reloc %u sym '%s': out of bounds relocation, offset %d size %u\n",
8168e6fad488ef21335529c65ca6c88c38be50cd3aRussell King			       module->name, relindex, i, symname,
8268e6fad488ef21335529c65ca6c88c38be50cd3aRussell King			       rel->r_offset, dstsec->sh_size);
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOEXEC;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		loc = dstsec->sh_addr + rel->r_offset;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (ELF32_R_TYPE(rel->r_info)) {
892e1926e7b5d39eb31880152d636e8d8d011888cbCatalin Marinas		case R_ARM_NONE:
902e1926e7b5d39eb31880152d636e8d8d011888cbCatalin Marinas			/* ignore */
912e1926e7b5d39eb31880152d636e8d8d011888cbCatalin Marinas			break;
922e1926e7b5d39eb31880152d636e8d8d011888cbCatalin Marinas
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case R_ARM_ABS32:
9455f0fb6adb83a5883589e945cbce37e90615ea09Andrey Ryabinin		case R_ARM_TARGET1:
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*(u32 *)loc += sym->st_value;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case R_ARM_PC24:
99c2e2611425a956d25d2948c5d95d3848c4db1257Daniel Jacobowitz		case R_ARM_CALL:
100c2e2611425a956d25d2948c5d95d3848c4db1257Daniel Jacobowitz		case R_ARM_JUMP24:
101f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			offset = __mem_to_opcode_arm(*(u32 *)loc);
102f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			offset = (offset & 0x00ffffff) << 2;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (offset & 0x02000000)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				offset -= 0x04000000;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			offset += sym->st_value - loc;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (offset & 3 ||
108c5f125031f416ba6350e84462e9039737b6e2babKevin Welton			    offset <= (s32)0xfe000000 ||
109c5f125031f416ba6350e84462e9039737b6e2babKevin Welton			    offset >= (s32)0x02000000) {
11068e6fad488ef21335529c65ca6c88c38be50cd3aRussell King				pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
11168e6fad488ef21335529c65ca6c88c38be50cd3aRussell King				       module->name, relindex, i, symname,
11268e6fad488ef21335529c65ca6c88c38be50cd3aRussell King				       ELF32_R_TYPE(rel->r_info), loc,
11368e6fad488ef21335529c65ca6c88c38be50cd3aRussell King				       sym->st_value);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOEXEC;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			offset >>= 2;
118f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			offset &= 0x00ffffff;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
120f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			*(u32 *)loc &= __opcode_to_mem_arm(0xff000000);
121f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			*(u32 *)loc |= __opcode_to_mem_arm(offset);
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1244731f8b66dd34ebf0e67ca6ba9162b0e509bec06Daniel Silverstone	       case R_ARM_V4BX:
1254731f8b66dd34ebf0e67ca6ba9162b0e509bec06Daniel Silverstone		       /* Preserve Rm and the condition code. Alter
1264731f8b66dd34ebf0e67ca6ba9162b0e509bec06Daniel Silverstone			* other bits to re-code instruction as
1274731f8b66dd34ebf0e67ca6ba9162b0e509bec06Daniel Silverstone			* MOV PC,Rm.
1284731f8b66dd34ebf0e67ca6ba9162b0e509bec06Daniel Silverstone			*/
129f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks		       *(u32 *)loc &= __opcode_to_mem_arm(0xf000000f);
130f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks		       *(u32 *)loc |= __opcode_to_mem_arm(0x01a0f000);
1314731f8b66dd34ebf0e67ca6ba9162b0e509bec06Daniel Silverstone		       break;
1324731f8b66dd34ebf0e67ca6ba9162b0e509bec06Daniel Silverstone
1332e1926e7b5d39eb31880152d636e8d8d011888cbCatalin Marinas		case R_ARM_PREL31:
1342e1926e7b5d39eb31880152d636e8d8d011888cbCatalin Marinas			offset = *(u32 *)loc + sym->st_value - loc;
1352e1926e7b5d39eb31880152d636e8d8d011888cbCatalin Marinas			*(u32 *)loc = offset & 0x7fffffff;
1362e1926e7b5d39eb31880152d636e8d8d011888cbCatalin Marinas			break;
1372e1926e7b5d39eb31880152d636e8d8d011888cbCatalin Marinas
138ae51e609843f7d0aaeb1c2ad9f89d252a4899885Paul Gortmaker		case R_ARM_MOVW_ABS_NC:
139ae51e609843f7d0aaeb1c2ad9f89d252a4899885Paul Gortmaker		case R_ARM_MOVT_ABS:
140f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			offset = tmp = __mem_to_opcode_arm(*(u32 *)loc);
141ae51e609843f7d0aaeb1c2ad9f89d252a4899885Paul Gortmaker			offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);
142ae51e609843f7d0aaeb1c2ad9f89d252a4899885Paul Gortmaker			offset = (offset ^ 0x8000) - 0x8000;
143ae51e609843f7d0aaeb1c2ad9f89d252a4899885Paul Gortmaker
144ae51e609843f7d0aaeb1c2ad9f89d252a4899885Paul Gortmaker			offset += sym->st_value;
145ae51e609843f7d0aaeb1c2ad9f89d252a4899885Paul Gortmaker			if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_ABS)
146ae51e609843f7d0aaeb1c2ad9f89d252a4899885Paul Gortmaker				offset >>= 16;
147ae51e609843f7d0aaeb1c2ad9f89d252a4899885Paul Gortmaker
148f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			tmp &= 0xfff0f000;
149f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			tmp |= ((offset & 0xf000) << 4) |
150f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks				(offset & 0x0fff);
151f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks
152f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			*(u32 *)loc = __opcode_to_mem_arm(tmp);
153ae51e609843f7d0aaeb1c2ad9f89d252a4899885Paul Gortmaker			break;
154ae51e609843f7d0aaeb1c2ad9f89d252a4899885Paul Gortmaker
155b749315601b44a63634d1a38fd167b8cac0e9ad4Catalin Marinas#ifdef CONFIG_THUMB2_KERNEL
156adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas		case R_ARM_THM_CALL:
157adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas		case R_ARM_THM_JUMP24:
158f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			upper = __mem_to_opcode_thumb16(*(u16 *)loc);
159f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			lower = __mem_to_opcode_thumb16(*(u16 *)(loc + 2));
160adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas
161adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			/*
162adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			 * 25 bit signed address range (Thumb-2 BL and B.W
163adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			 * instructions):
164adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			 *   S:I1:I2:imm10:imm11:0
165adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			 * where:
166adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			 *   S     = upper[10]   = offset[24]
167adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			 *   I1    = ~(J1 ^ S)   = offset[23]
168adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			 *   I2    = ~(J2 ^ S)   = offset[22]
169adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			 *   imm10 = upper[9:0]  = offset[21:12]
170adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			 *   imm11 = lower[10:0] = offset[11:1]
171adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			 *   J1    = lower[13]
172adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			 *   J2    = lower[11]
173adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			 */
174adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			sign = (upper >> 10) & 1;
175adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			j1 = (lower >> 13) & 1;
176adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			j2 = (lower >> 11) & 1;
177adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			offset = (sign << 24) | ((~(j1 ^ sign) & 1) << 23) |
178adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas				((~(j2 ^ sign) & 1) << 22) |
179adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas				((upper & 0x03ff) << 12) |
180adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas				((lower & 0x07ff) << 1);
181adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			if (offset & 0x01000000)
182adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas				offset -= 0x02000000;
183adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			offset += sym->st_value - loc;
184adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas
1859a00318eadbb43db4e9c163c262a22a3c8b5a672Dave Martin			/*
1869a00318eadbb43db4e9c163c262a22a3c8b5a672Dave Martin			 * For function symbols, only Thumb addresses are
1879a00318eadbb43db4e9c163c262a22a3c8b5a672Dave Martin			 * allowed (no interworking).
1889a00318eadbb43db4e9c163c262a22a3c8b5a672Dave Martin			 *
1899a00318eadbb43db4e9c163c262a22a3c8b5a672Dave Martin			 * For non-function symbols, the destination
1909a00318eadbb43db4e9c163c262a22a3c8b5a672Dave Martin			 * has no specific ARM/Thumb disposition, so
1919a00318eadbb43db4e9c163c262a22a3c8b5a672Dave Martin			 * the branch is resolved under the assumption
1929a00318eadbb43db4e9c163c262a22a3c8b5a672Dave Martin			 * that interworking is not required.
1939a00318eadbb43db4e9c163c262a22a3c8b5a672Dave Martin			 */
1949a00318eadbb43db4e9c163c262a22a3c8b5a672Dave Martin			if ((ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&
1959a00318eadbb43db4e9c163c262a22a3c8b5a672Dave Martin				!(offset & 1)) ||
196adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			    offset <= (s32)0xff000000 ||
197adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			    offset >= (s32)0x01000000) {
19868e6fad488ef21335529c65ca6c88c38be50cd3aRussell King				pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
19968e6fad488ef21335529c65ca6c88c38be50cd3aRussell King				       module->name, relindex, i, symname,
20068e6fad488ef21335529c65ca6c88c38be50cd3aRussell King				       ELF32_R_TYPE(rel->r_info), loc,
20168e6fad488ef21335529c65ca6c88c38be50cd3aRussell King				       sym->st_value);
202adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas				return -ENOEXEC;
203adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			}
204adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas
205adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			sign = (offset >> 24) & 1;
206adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			j1 = sign ^ (~(offset >> 23) & 1);
207adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			j2 = sign ^ (~(offset >> 22) & 1);
208f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			upper = (u16)((upper & 0xf800) | (sign << 10) |
209adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas					    ((offset >> 12) & 0x03ff));
210f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			lower = (u16)((lower & 0xd000) |
211f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks				      (j1 << 13) | (j2 << 11) |
212f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks				      ((offset >> 1) & 0x07ff));
213f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks
214f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			*(u16 *)loc = __opcode_to_mem_thumb16(upper);
215f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			*(u16 *)(loc + 2) = __opcode_to_mem_thumb16(lower);
216adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas			break;
217adca6dc23bc620ea95392659625200a252b97be3Catalin Marinas
2188dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas		case R_ARM_THM_MOVW_ABS_NC:
2198dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas		case R_ARM_THM_MOVT_ABS:
220f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			upper = __mem_to_opcode_thumb16(*(u16 *)loc);
221f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			lower = __mem_to_opcode_thumb16(*(u16 *)(loc + 2));
2228dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas
2238dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			/*
2248dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			 * MOVT/MOVW instructions encoding in Thumb-2:
2258dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			 *
2268dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			 * i	= upper[10]
2278dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			 * imm4	= upper[3:0]
2288dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			 * imm3	= lower[14:12]
2298dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			 * imm8	= lower[7:0]
2308dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			 *
2318dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			 * imm16 = imm4:i:imm3:imm8
2328dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			 */
2338dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			offset = ((upper & 0x000f) << 12) |
2348dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas				((upper & 0x0400) << 1) |
2358dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas				((lower & 0x7000) >> 4) | (lower & 0x00ff);
2368dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			offset = (offset ^ 0x8000) - 0x8000;
2378dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			offset += sym->st_value;
2388dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas
2398dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS)
2408dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas				offset >>= 16;
2418dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas
242f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			upper = (u16)((upper & 0xfbf0) |
243f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks				      ((offset & 0xf000) >> 12) |
244f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks				      ((offset & 0x0800) >> 1));
245f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			lower = (u16)((lower & 0x8f00) |
246f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks				      ((offset & 0x0700) << 4) |
247f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks				      (offset & 0x00ff));
248f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			*(u16 *)loc = __opcode_to_mem_thumb16(upper);
249f592d323bc2353db871d1e840f05b27e0730fb10Ben Dooks			*(u16 *)(loc + 2) = __opcode_to_mem_thumb16(lower);
2508dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas			break;
251b749315601b44a63634d1a38fd167b8cac0e9ad4Catalin Marinas#endif
2528dd47741d191400c46173ed9fba9d14b4033ce23Catalin Marinas
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR "%s: unknown relocation: %u\n",
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       module->name, ELF32_R_TYPE(rel->r_info));
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOEXEC;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2628931360eb9c6ec8bd30efef579cef81917a2fcf3Russell Kingstruct mod_unwind_map {
2638931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King	const Elf_Shdr *unw_sec;
2648931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King	const Elf_Shdr *txt_sec;
2658931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King};
2668931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King
2674a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell Kingstatic const Elf_Shdr *find_mod_section(const Elf32_Ehdr *hdr,
2684a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King	const Elf_Shdr *sechdrs, const char *name)
2694a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King{
2704a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King	const Elf_Shdr *s, *se;
2714a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King	const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
2724a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King
2734a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King	for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++)
2744a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King		if (strcmp(name, secstrs + s->sh_name) == 0)
2754a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King			return s;
2764a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King
2774a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King	return NULL;
2784a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King}
2794a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King
280dc21af99fadcfa0ae65b52fd0895f85824f0c288Russell Kingextern void fixup_pv_table(const void *, unsigned long);
2814a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell Kingextern void fixup_smp(const void *, unsigned long);
2824a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King
2838931360eb9c6ec8bd30efef579cef81917a2fcf3Russell Kingint module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
2848931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King		    struct module *mod)
2852e1926e7b5d39eb31880152d636e8d8d011888cbCatalin Marinas{
286dc21af99fadcfa0ae65b52fd0895f85824f0c288Russell King	const Elf_Shdr *s = NULL;
2878931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King#ifdef CONFIG_ARM_UNWIND
2888931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King	const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
2894a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King	const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum;
2908931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King	struct mod_unwind_map maps[ARM_SEC_MAX];
291e5f7772eec3ec342ecfe686ab8330ef538af134bPhil Carmody	int i;
2928931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King
2938931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King	memset(maps, 0, sizeof(maps));
2948931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King
2958931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King	for (s = sechdrs; s < sechdrs_end; s++) {
2968931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King		const char *secname = secstrs + s->sh_name;
2978931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King
29850005a8deb38e5e6456ebd94e57adb321d4589deRussell King		if (!(s->sh_flags & SHF_ALLOC))
29950005a8deb38e5e6456ebd94e57adb321d4589deRussell King			continue;
30050005a8deb38e5e6456ebd94e57adb321d4589deRussell King
3018931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King		if (strcmp(".ARM.exidx.init.text", secname) == 0)
3028931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King			maps[ARM_SEC_INIT].unw_sec = s;
3038931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King		else if (strcmp(".ARM.exidx", secname) == 0)
3048931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King			maps[ARM_SEC_CORE].unw_sec = s;
3058931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King		else if (strcmp(".ARM.exidx.exit.text", secname) == 0)
3068931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King			maps[ARM_SEC_EXIT].unw_sec = s;
307849b882b52df0f276d9ffded01d85654aa0da422Douglas Anderson		else if (strcmp(".ARM.exidx.text.unlikely", secname) == 0)
308849b882b52df0f276d9ffded01d85654aa0da422Douglas Anderson			maps[ARM_SEC_UNLIKELY].unw_sec = s;
309849b882b52df0f276d9ffded01d85654aa0da422Douglas Anderson		else if (strcmp(".ARM.exidx.text.hot", secname) == 0)
310849b882b52df0f276d9ffded01d85654aa0da422Douglas Anderson			maps[ARM_SEC_HOT].unw_sec = s;
3118931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King		else if (strcmp(".init.text", secname) == 0)
3128931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King			maps[ARM_SEC_INIT].txt_sec = s;
3138931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King		else if (strcmp(".text", secname) == 0)
3148931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King			maps[ARM_SEC_CORE].txt_sec = s;
3158931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King		else if (strcmp(".exit.text", secname) == 0)
3168931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King			maps[ARM_SEC_EXIT].txt_sec = s;
317849b882b52df0f276d9ffded01d85654aa0da422Douglas Anderson		else if (strcmp(".text.unlikely", secname) == 0)
318849b882b52df0f276d9ffded01d85654aa0da422Douglas Anderson			maps[ARM_SEC_UNLIKELY].txt_sec = s;
319849b882b52df0f276d9ffded01d85654aa0da422Douglas Anderson		else if (strcmp(".text.hot", secname) == 0)
320849b882b52df0f276d9ffded01d85654aa0da422Douglas Anderson			maps[ARM_SEC_HOT].txt_sec = s;
321e5f7772eec3ec342ecfe686ab8330ef538af134bPhil Carmody	}
3222e1926e7b5d39eb31880152d636e8d8d011888cbCatalin Marinas
3238931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King	for (i = 0; i < ARM_SEC_MAX; i++)
3248931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King		if (maps[i].unw_sec && maps[i].txt_sec)
3258931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King			mod->arch.unwind[i] =
3268931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King				unwind_table_add(maps[i].unw_sec->sh_addr,
3278931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King					         maps[i].unw_sec->sh_size,
3288931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King					         maps[i].txt_sec->sh_addr,
3298931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King					         maps[i].txt_sec->sh_size);
3302e1926e7b5d39eb31880152d636e8d8d011888cbCatalin Marinas#endif
331dc21af99fadcfa0ae65b52fd0895f85824f0c288Russell King#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
332dc21af99fadcfa0ae65b52fd0895f85824f0c288Russell King	s = find_mod_section(hdr, sechdrs, ".pv_table");
333dc21af99fadcfa0ae65b52fd0895f85824f0c288Russell King	if (s)
334dc21af99fadcfa0ae65b52fd0895f85824f0c288Russell King		fixup_pv_table((void *)s->sh_addr, s->sh_size);
335dc21af99fadcfa0ae65b52fd0895f85824f0c288Russell King#endif
3364a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King	s = find_mod_section(hdr, sechdrs, ".alt.smp.init");
3374a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King	if (s && !is_smp())
33820feaab0323cc062b298c12e77869424df05f31fRussell King#ifdef CONFIG_SMP_ON_UP
3394a9cb360197684a861bc06f06d33d5fcc8ffcbf5Russell King		fixup_smp((void *)s->sh_addr, s->sh_size);
34020feaab0323cc062b298c12e77869424df05f31fRussell King#else
34120feaab0323cc062b298c12e77869424df05f31fRussell King		return -EINVAL;
34220feaab0323cc062b298c12e77869424df05f31fRussell King#endif
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_arch_cleanup(struct module *mod)
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3498931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King#ifdef CONFIG_ARM_UNWIND
3508931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King	int i;
3518931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King
3528931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King	for (i = 0; i < ARM_SEC_MAX; i++)
3538931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King		if (mod->arch.unwind[i])
3548931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King			unwind_table_del(mod->arch.unwind[i]);
3558931360eb9c6ec8bd30efef579cef81917a2fcf3Russell King#endif
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
357