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