1/*  Kernel module help for sh64.
2
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2 of the License, or
6    (at your option) any later version.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17    Copyright 2004 SuperH (UK) Ltd
18    Author: Richard Curnow
19
20    Based on the sh version, and on code from the sh64-specific parts of
21    modutils, originally written by Richard Curnow and Ben Gaster.
22
23*/
24#include <linux/moduleloader.h>
25#include <linux/elf.h>
26#include <linux/vmalloc.h>
27#include <linux/fs.h>
28#include <linux/string.h>
29#include <linux/kernel.h>
30
31#define DEBUGP(fmt...)
32
33void *module_alloc(unsigned long size)
34{
35	if (size == 0)
36		return NULL;
37	return vmalloc(size);
38}
39
40
41/* Free memory returned from module_alloc */
42void module_free(struct module *mod, void *module_region)
43{
44	vfree(module_region);
45}
46
47/* We don't need anything special. */
48int module_frob_arch_sections(Elf_Ehdr *hdr,
49			      Elf_Shdr *sechdrs,
50			      char *secstrings,
51			      struct module *mod)
52{
53	return 0;
54}
55
56int apply_relocate_add(Elf32_Shdr *sechdrs,
57		   const char *strtab,
58		   unsigned int symindex,
59		   unsigned int relsec,
60		   struct module *me)
61{
62	unsigned int i;
63	Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
64	Elf32_Sym *sym;
65	Elf32_Addr relocation;
66	uint32_t *location;
67	int align;
68	int is_shmedia;
69
70	DEBUGP("Applying relocate section %u to %u\n", relsec,
71	       sechdrs[relsec].sh_info);
72	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
73		/* This is where to make the change */
74		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
75			+ rel[i].r_offset;
76		/* This is the symbol it is referring to.  Note that all
77		   undefined symbols have been resolved.  */
78		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
79			+ ELF32_R_SYM(rel[i].r_info);
80		relocation = sym->st_value + rel[i].r_addend;
81		align = (int)location & 3;
82
83		/* For text addresses, bit2 of the st_other field indicates
84		 * whether the symbol is SHmedia (1) or SHcompact (0).  If
85		 * SHmedia, the LSB of the symbol needs to be asserted
86		 * for the CPU to be in SHmedia mode when it starts executing
87		 * the branch target. */
88		is_shmedia = (sym->st_other & 4) ? 1 : 0;
89		if (is_shmedia) {
90			relocation |= 1;
91		}
92
93		switch (ELF32_R_TYPE(rel[i].r_info)) {
94		case R_SH_DIR32:
95			DEBUGP("R_SH_DIR32 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
96			*location += relocation;
97			break;
98		case R_SH_REL32:
99			DEBUGP("R_SH_REL32 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
100			relocation -= (Elf32_Addr) location;
101			*location += relocation;
102			break;
103		case R_SH_IMM_LOW16:
104			DEBUGP("R_SH_IMM_LOW16 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
105			*location = (*location & ~0x3fffc00) |
106				((relocation & 0xffff) << 10);
107			break;
108		case R_SH_IMM_MEDLOW16:
109			DEBUGP("R_SH_IMM_MEDLOW16 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
110			*location = (*location & ~0x3fffc00) |
111				(((relocation >> 16) & 0xffff) << 10);
112			break;
113		case R_SH_IMM_LOW16_PCREL:
114			DEBUGP("R_SH_IMM_LOW16_PCREL @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
115			relocation -= (Elf32_Addr) location;
116			*location = (*location & ~0x3fffc00) |
117				((relocation & 0xffff) << 10);
118			break;
119		case R_SH_IMM_MEDLOW16_PCREL:
120			DEBUGP("R_SH_IMM_MEDLOW16_PCREL @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation);
121			relocation -= (Elf32_Addr) location;
122			*location = (*location & ~0x3fffc00) |
123				(((relocation >> 16) & 0xffff) << 10);
124			break;
125		default:
126			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
127			       me->name, ELF32_R_TYPE(rel[i].r_info));
128			return -ENOEXEC;
129		}
130	}
131	return 0;
132}
133
134int apply_relocate(Elf32_Shdr *sechdrs,
135		       const char *strtab,
136		       unsigned int symindex,
137		       unsigned int relsec,
138		       struct module *me)
139{
140	printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
141	       me->name);
142	return -ENOEXEC;
143}
144
145int module_finalize(const Elf_Ehdr *hdr,
146		    const Elf_Shdr *sechdrs,
147		    struct module *me)
148{
149	return 0;
150}
151
152void module_arch_cleanup(struct module *mod)
153{
154}
155