• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/mn10300/kernel/
1/* MN10300 Kernel module helper routines
2 *
3 * Copyright (C) 2007, 2008, 2009 Red Hat, Inc. All Rights Reserved.
4 * Written by Mark Salter (msalter@redhat.com)
5 * - Derived from arch/i386/kernel/module.c
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public Licence as published by
9 * the Free Software Foundation; either version 2 of the Licence, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public Licence for more details.
16 *
17 * You should have received a copy of the GNU General Public Licence
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 */
21#include <linux/moduleloader.h>
22#include <linux/elf.h>
23#include <linux/vmalloc.h>
24#include <linux/fs.h>
25#include <linux/string.h>
26#include <linux/kernel.h>
27#include <linux/bug.h>
28
29#define DEBUGP(fmt, ...)
30
31/*
32 * allocate storage for a module
33 */
34void *module_alloc(unsigned long size)
35{
36	if (size == 0)
37		return NULL;
38	return vmalloc_exec(size);
39}
40
41/*
42 * free memory returned from module_alloc()
43 */
44void module_free(struct module *mod, void *module_region)
45{
46	vfree(module_region);
47}
48
49/*
50 * allow the arch to fix up the section table
51 * - we don't need anything special
52 */
53int module_frob_arch_sections(Elf_Ehdr *hdr,
54			      Elf_Shdr *sechdrs,
55			      char *secstrings,
56			      struct module *mod)
57{
58	return 0;
59}
60
61static void reloc_put16(uint8_t *p, uint32_t val)
62{
63	p[0] = val & 0xff;
64	p[1] = (val >> 8) & 0xff;
65}
66
67static void reloc_put24(uint8_t *p, uint32_t val)
68{
69	reloc_put16(p, val);
70	p[2] = (val >> 16) & 0xff;
71}
72
73static void reloc_put32(uint8_t *p, uint32_t val)
74{
75	reloc_put16(p, val);
76	reloc_put16(p+2, val >> 16);
77}
78
79/*
80 * apply a REL relocation
81 */
82int apply_relocate(Elf32_Shdr *sechdrs,
83		   const char *strtab,
84		   unsigned int symindex,
85		   unsigned int relsec,
86		   struct module *me)
87{
88	printk(KERN_ERR "module %s: RELOCATION unsupported\n",
89	       me->name);
90	return -ENOEXEC;
91}
92
93/*
94 * apply a RELA relocation
95 */
96int apply_relocate_add(Elf32_Shdr *sechdrs,
97		       const char *strtab,
98		       unsigned int symindex,
99		       unsigned int relsec,
100		       struct module *me)
101{
102	unsigned int i, sym_diff_seen = 0;
103	Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
104	Elf32_Sym *sym;
105	Elf32_Addr relocation, sym_diff_val = 0;
106	uint8_t *location;
107	uint32_t value;
108
109	DEBUGP("Applying relocate section %u to %u\n",
110	       relsec, sechdrs[relsec].sh_info);
111
112	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
113		/* this is where to make the change */
114		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
115			+ rel[i].r_offset;
116
117		/* this is the symbol the relocation is referring to (note that
118		 * all undefined symbols have been resolved by the caller) */
119		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
120			+ ELF32_R_SYM(rel[i].r_info);
121
122		/* this is the adjustment to be made */
123		relocation = sym->st_value + rel[i].r_addend;
124
125		if (sym_diff_seen) {
126			switch (ELF32_R_TYPE(rel[i].r_info)) {
127			case R_MN10300_32:
128			case R_MN10300_24:
129			case R_MN10300_16:
130			case R_MN10300_8:
131				relocation -= sym_diff_val;
132				sym_diff_seen = 0;
133				break;
134			default:
135				printk(KERN_ERR "module %s: Unexpected SYM_DIFF relocation: %u\n",
136				       me->name, ELF32_R_TYPE(rel[i].r_info));
137				return -ENOEXEC;
138			}
139		}
140
141		switch (ELF32_R_TYPE(rel[i].r_info)) {
142			/* for the first four relocation types, we simply
143			 * store the adjustment at the location given */
144		case R_MN10300_32:
145			reloc_put32(location, relocation);
146			break;
147		case R_MN10300_24:
148			reloc_put24(location, relocation);
149			break;
150		case R_MN10300_16:
151			reloc_put16(location, relocation);
152			break;
153		case R_MN10300_8:
154			*location = relocation;
155			break;
156
157			/* for the next three relocation types, we write the
158			 * adjustment with the address subtracted over the
159			 * value at the location given */
160		case R_MN10300_PCREL32:
161			value = relocation - (uint32_t) location;
162			reloc_put32(location, value);
163			break;
164		case R_MN10300_PCREL16:
165			value = relocation - (uint32_t) location;
166			reloc_put16(location, value);
167			break;
168		case R_MN10300_PCREL8:
169			*location = relocation - (uint32_t) location;
170			break;
171
172		case R_MN10300_SYM_DIFF:
173			/* This is used to adjust the next reloc as required
174			 * by relaxation. */
175			sym_diff_seen = 1;
176			sym_diff_val = sym->st_value;
177			break;
178
179		case R_MN10300_ALIGN:
180			/* Just ignore the ALIGN relocs.
181			 * Only interesting if kernel performed relaxation. */
182			continue;
183
184		default:
185			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
186			       me->name, ELF32_R_TYPE(rel[i].r_info));
187			return -ENOEXEC;
188		}
189	}
190	if (sym_diff_seen) {
191		printk(KERN_ERR "module %s: Nothing follows SYM_DIFF relocation: %u\n",
192				       me->name, ELF32_R_TYPE(rel[i].r_info));
193		return -ENOEXEC;
194	}
195	return 0;
196}
197
198/*
199 * finish loading the module
200 */
201int module_finalize(const Elf_Ehdr *hdr,
202		    const Elf_Shdr *sechdrs,
203		    struct module *me)
204{
205	return 0;
206}
207
208/*
209 * finish clearing the module
210 */
211void module_arch_cleanup(struct module *mod)
212{
213}
214