Title: [6857] trunk/arch/blackfin/kernel/module.c: module: fix reloc handling in different memory spaces (L1 inst for example)
Revision
6857
Author
vapier
Date
2009-06-25 19:49:51 -0500 (Thu, 25 Jun 2009)

Log Message

module: fix reloc handling in different memory spaces (L1 inst for example)

Modified Paths

Diff

Modified: trunk/arch/blackfin/kernel/module.c (6856 => 6857)


--- trunk/arch/blackfin/kernel/module.c	2009-06-26 00:48:33 UTC (rev 6856)
+++ trunk/arch/blackfin/kernel/module.c	2009-06-26 00:49:51 UTC (rev 6857)
@@ -37,6 +37,7 @@
 #include <linux/kernel.h>
 #include <asm/dma.h>
 #include <asm/cacheflush.h>
+#include <asm/uaccess.h>
 
 void *module_alloc(unsigned long size)
 {
@@ -199,26 +200,23 @@
 /*            gas does not generate it.                                  */
 /*************************************************************************/
 int
-apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
+apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
 		   unsigned int symindex, unsigned int relsec,
 		   struct module *mod)
 {
 	unsigned int i;
-	unsigned short tmp;
 	Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
 	Elf32_Sym *sym;
-	uint32_t *location32;
-	uint16_t *location16;
-	uint32_t value;
+	unsigned long location, value, size;
 
 	pr_debug("applying relocate section %u to %u\n", mod->name,
 		relsec, sechdrs[relsec].sh_info);
+
 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
 		/* This is where to make the change */
-		location16 =
-		    (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].sh_addr +
-				  rel[i].r_offset);
-		location32 = (uint32_t *) location16;
+		location = sechdrs[sechdrs[relsec].sh_info].sh_addr +
+		           rel[i].r_offset;
+
 		/* This is the symbol it is referring to. Note that all
 		   undefined symbols have been resolved. */
 		sym = (Elf32_Sym *) sechdrs[symindex].sh_addr
@@ -227,53 +225,69 @@
 		value += rel[i].r_addend;
 
 #ifdef CONFIG_SMP
-		if ((unsigned long)location16 >= COREB_L1_DATA_A_START) {
+		if (location >= COREB_L1_DATA_A_START) {
 			pr_err("cannot relocate in L1: %u (SMP kernel)",
 				mod->name, ELF32_R_TYPE(rel[i].r_info));
 			return -ENOEXEC;
 		}
 #endif
 
-		pr_debug("location is %lx, value is %x type is %d\n",
-			mod->name, (unsigned long)location32, value,
-			ELF32_R_TYPE(rel[i].r_info));
+		pr_debug("location is %lx, value is %lx type is %d\n",
+			mod->name, location, value, ELF32_R_TYPE(rel[i].r_info));
 
 		switch (ELF32_R_TYPE(rel[i].r_info)) {
 
+		case R_BFIN_HUIMM16:
+			value >>= 16;
 		case R_BFIN_LUIMM16:
-			tmp = (value & 0xffff);
-			if ((unsigned long)location16 >= L1_CODE_START) {
-				dma_memcpy(location16, &tmp, 2);
-			} else
-				*location16 = tmp;
-			break;
-		case R_BFIN_HUIMM16:
-			tmp = ((value >> 16) & 0xffff);
-			if ((unsigned long)location16 >= L1_CODE_START) {
-				dma_memcpy(location16, &tmp, 2);
-			} else
-				*location16 = tmp;
-			break;
 		case R_BFIN_RIMM16:
-			*location16 = (value & 0xffff);
+			size = 2;
 			break;
 		case R_BFIN_BYTE4_DATA:
-			*location32 = value;
+			size = 4;
 			break;
+
 		case R_BFIN_PCREL24:
 		case R_BFIN_PCREL24_JUMP_L:
+			/* annoyingly, the layout is RB OP RB RB so we can't
+			 * straight memcpy() the reloc into memory.  overlay
+			 * the first byte manually.  (RB = reloc byte)
+			 */
+			/*
+			uint8_t *rb = (void *)(location - 2);
+			*rb = value >> 16;
+			*/
 		case R_BFIN_PCREL12_JUMP:
 		case R_BFIN_PCREL12_JUMP_S:
 		case R_BFIN_PCREL10:
 			pr_err("unsupported relocation: %u (no -mlong-calls?)\n",
 				mod->name, ELF32_R_TYPE(rel[i].r_info));
 			return -ENOEXEC;
+
 		default:
 			pr_err("unknown relocation: %u\n", mod->name,
 				ELF32_R_TYPE(rel[i].r_info));
 			return -ENOEXEC;
 		}
+
+		switch (bfin_mem_access_type(location, size)) {
+		case BFIN_MEM_ACCESS_CORE:
+		case BFIN_MEM_ACCESS_CORE_ONLY:
+			memcpy((void *)location, &value, size);
+			break;
+		case BFIN_MEM_ACCESS_DMA:
+			dma_memcpy((void *)location, &value, size);
+			break;
+		case BFIN_MEM_ACCESS_ITEST:
+			isram_memcpy((void *)location, &value, size);
+			break;
+		default:
+			pr_err("invalid relocation for %#lx\n",
+				mod->name, location);
+			return -ENOEXEC;
+		}
 	}
+
 	return 0;
 }
 
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to