xref: /openbmc/linux/arch/m68k/kernel/module.c (revision e3d786a3)
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file COPYING in the main directory of this archive
4  * for more details.
5  */
6 
7 #include <linux/moduleloader.h>
8 #include <linux/elf.h>
9 #include <linux/vmalloc.h>
10 #include <linux/fs.h>
11 #include <linux/string.h>
12 #include <linux/kernel.h>
13 
14 #if 0
15 #define DEBUGP(fmt, ...) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
16 #else
17 #define DEBUGP(fmt, ...) no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
18 #endif
19 
20 #ifdef CONFIG_MODULES
21 
22 int apply_relocate(Elf32_Shdr *sechdrs,
23 		   const char *strtab,
24 		   unsigned int symindex,
25 		   unsigned int relsec,
26 		   struct module *me)
27 {
28 	unsigned int i;
29 	Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
30 	Elf32_Sym *sym;
31 	uint32_t *location;
32 
33 	DEBUGP("Applying relocate section %u to %u\n", relsec,
34 	       sechdrs[relsec].sh_info);
35 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
36 		/* This is where to make the change */
37 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
38 			+ rel[i].r_offset;
39 		/* This is the symbol it is referring to.  Note that all
40 		   undefined symbols have been resolved.  */
41 		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
42 			+ ELF32_R_SYM(rel[i].r_info);
43 
44 		switch (ELF32_R_TYPE(rel[i].r_info)) {
45 		case R_68K_32:
46 			/* We add the value into the location given */
47 			*location += sym->st_value;
48 			break;
49 		case R_68K_PC32:
50 			/* Add the value, subtract its position */
51 			*location += sym->st_value - (uint32_t)location;
52 			break;
53 		default:
54 			pr_err("module %s: Unknown relocation: %u\n", me->name,
55 			       ELF32_R_TYPE(rel[i].r_info));
56 			return -ENOEXEC;
57 		}
58 	}
59 	return 0;
60 }
61 
62 int apply_relocate_add(Elf32_Shdr *sechdrs,
63 		       const char *strtab,
64 		       unsigned int symindex,
65 		       unsigned int relsec,
66 		       struct module *me)
67 {
68 	unsigned int i;
69 	Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
70 	Elf32_Sym *sym;
71 	uint32_t *location;
72 
73 	DEBUGP("Applying relocate_add section %u to %u\n", relsec,
74 	       sechdrs[relsec].sh_info);
75 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
76 		/* This is where to make the change */
77 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
78 			+ rel[i].r_offset;
79 		/* This is the symbol it is referring to.  Note that all
80 		   undefined symbols have been resolved.  */
81 		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
82 			+ ELF32_R_SYM(rel[i].r_info);
83 
84 		switch (ELF32_R_TYPE(rel[i].r_info)) {
85 		case R_68K_32:
86 			/* We add the value into the location given */
87 			*location = rel[i].r_addend + sym->st_value;
88 			break;
89 		case R_68K_PC32:
90 			/* Add the value, subtract its position */
91 			*location = rel[i].r_addend + sym->st_value - (uint32_t)location;
92 			break;
93 		default:
94 			pr_err("module %s: Unknown relocation: %u\n", me->name,
95 			       ELF32_R_TYPE(rel[i].r_info));
96 			return -ENOEXEC;
97 		}
98 	}
99 	return 0;
100 }
101 
102 int module_finalize(const Elf_Ehdr *hdr,
103 		    const Elf_Shdr *sechdrs,
104 		    struct module *mod)
105 {
106 	module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end);
107 	return 0;
108 }
109 
110 #endif /* CONFIG_MODULES */
111 
112 void module_fixup(struct module *mod, struct m68k_fixup_info *start,
113 		  struct m68k_fixup_info *end)
114 {
115 #ifdef CONFIG_MMU
116 	struct m68k_fixup_info *fixup;
117 
118 	for (fixup = start; fixup < end; fixup++) {
119 		switch (fixup->type) {
120 		case m68k_fixup_memoffset:
121 			*(u32 *)fixup->addr = m68k_memoffset;
122 			break;
123 		case m68k_fixup_vnode_shift:
124 			*(u16 *)fixup->addr += m68k_virt_to_node_shift;
125 			break;
126 		}
127 	}
128 #endif
129 }
130