Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
module.c
Go to the documentation of this file.
1 /*
2  * Copyright 2010 Tilera Corporation. All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation, version 2.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11  * NON INFRINGEMENT. See the GNU General Public License for
12  * more details.
13  *
14  * Based on i386 version, copyright (C) 2001 Rusty Russell.
15  */
16 
17 #include <linux/moduleloader.h>
18 #include <linux/elf.h>
19 #include <linux/vmalloc.h>
20 #include <linux/fs.h>
21 #include <linux/string.h>
22 #include <linux/kernel.h>
23 #include <asm/pgtable.h>
24 #include <asm/homecache.h>
25 #include <arch/opcode.h>
26 
27 #ifdef MODULE_DEBUG
28 #define DEBUGP printk
29 #else
30 #define DEBUGP(fmt...)
31 #endif
32 
33 /*
34  * Allocate some address space in the range MEM_MODULE_START to
35  * MEM_MODULE_END and populate it with memory.
36  */
37 void *module_alloc(unsigned long size)
38 {
39  struct page **pages;
41  struct vm_struct *area;
42  int i = 0;
43  int npages;
44 
45  if (size == 0)
46  return NULL;
47  npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
48  pages = kmalloc(npages * sizeof(struct page *), GFP_KERNEL);
49  if (pages == NULL)
50  return NULL;
51  for (; i < npages; ++i) {
53  if (!pages[i])
54  goto error;
55  }
56 
58  if (!area)
59  goto error;
60  area->nr_pages = npages;
61  area->pages = pages;
62 
63  if (map_vm_area(area, prot_rwx, &pages)) {
64  vunmap(area->addr);
65  goto error;
66  }
67 
68  return area->addr;
69 
70 error:
71  while (--i >= 0)
72  __free_page(pages[i]);
73  kfree(pages);
74  return NULL;
75 }
76 
77 
78 /* Free memory returned from module_alloc */
79 void module_free(struct module *mod, void *module_region)
80 {
81  vfree(module_region);
82 
83  /* Globally flush the L1 icache. */
85  0, 0, 0, NULL, NULL, 0);
86 
87  /*
88  * FIXME: If module_region == mod->module_init, trim exception
89  * table entries.
90  */
91 }
92 
93 #ifdef __tilegx__
94 /*
95  * Validate that the high 16 bits of "value" is just the sign-extension of
96  * the low 48 bits.
97  */
98 static int validate_hw2_last(long value, struct module *me)
99 {
100  if (((value << 16) >> 16) != value) {
101  pr_warning("module %s: Out of range HW2_LAST value %#lx\n",
102  me->name, value);
103  return 0;
104  }
105  return 1;
106 }
107 
108 /*
109  * Validate that "value" isn't too big to hold in a JumpOff relocation.
110  */
111 static int validate_jumpoff(long value)
112 {
113  /* Determine size of jump offset. */
114  int shift = __builtin_clzl(get_JumpOff_X1(create_JumpOff_X1(-1)));
115 
116  /* Check to see if it fits into the relocation slot. */
117  long f = get_JumpOff_X1(create_JumpOff_X1(value));
118  f = (f << shift) >> shift;
119 
120  return f == value;
121 }
122 #endif
123 
125  const char *strtab,
126  unsigned int symindex,
127  unsigned int relsec,
128  struct module *me)
129 {
130  unsigned int i;
131  Elf_Rela *rel = (void *)sechdrs[relsec].sh_addr;
132  Elf_Sym *sym;
133  u64 *location;
134  unsigned long value;
135 
136  DEBUGP("Applying relocate section %u to %u\n", relsec,
137  sechdrs[relsec].sh_info);
138  for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
139  /* This is where to make the change */
140  location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
141  + rel[i].r_offset;
142  /*
143  * This is the symbol it is referring to.
144  * Note that all undefined symbols have been resolved.
145  */
146  sym = (Elf_Sym *)sechdrs[symindex].sh_addr
147  + ELF_R_SYM(rel[i].r_info);
148  value = sym->st_value + rel[i].r_addend;
149 
150  switch (ELF_R_TYPE(rel[i].r_info)) {
151 
152 #ifdef __LITTLE_ENDIAN
153 # define MUNGE(func) \
154  (*location = ((*location & ~func(-1)) | func(value)))
155 #else
156 /*
157  * Instructions are always little-endian, so when we read them as data,
158  * we have to swap them around before and after modifying them.
159  */
160 # define MUNGE(func) \
161  (*location = swab64((swab64(*location) & ~func(-1)) | func(value)))
162 #endif
163 
164 #ifndef __tilegx__
165  case R_TILE_32:
166  *(uint32_t *)location = value;
167  break;
168  case R_TILE_IMM16_X0_HA:
169  value = (value + 0x8000) >> 16;
170  /*FALLTHROUGH*/
171  case R_TILE_IMM16_X0_LO:
172  MUNGE(create_Imm16_X0);
173  break;
174  case R_TILE_IMM16_X1_HA:
175  value = (value + 0x8000) >> 16;
176  /*FALLTHROUGH*/
177  case R_TILE_IMM16_X1_LO:
178  MUNGE(create_Imm16_X1);
179  break;
180  case R_TILE_JOFFLONG_X1:
181  value -= (unsigned long) location; /* pc-relative */
182  value = (long) value >> 3; /* count by instrs */
183  MUNGE(create_JOffLong_X1);
184  break;
185 #else
186  case R_TILEGX_64:
187  *location = value;
188  break;
189  case R_TILEGX_IMM16_X0_HW2_LAST:
190  if (!validate_hw2_last(value, me))
191  return -ENOEXEC;
192  value >>= 16;
193  /*FALLTHROUGH*/
194  case R_TILEGX_IMM16_X0_HW1:
195  value >>= 16;
196  /*FALLTHROUGH*/
197  case R_TILEGX_IMM16_X0_HW0:
198  MUNGE(create_Imm16_X0);
199  break;
200  case R_TILEGX_IMM16_X1_HW2_LAST:
201  if (!validate_hw2_last(value, me))
202  return -ENOEXEC;
203  value >>= 16;
204  /*FALLTHROUGH*/
205  case R_TILEGX_IMM16_X1_HW1:
206  value >>= 16;
207  /*FALLTHROUGH*/
208  case R_TILEGX_IMM16_X1_HW0:
209  MUNGE(create_Imm16_X1);
210  break;
211  case R_TILEGX_JUMPOFF_X1:
212  value -= (unsigned long) location; /* pc-relative */
213  value = (long) value >> 3; /* count by instrs */
214  if (!validate_jumpoff(value)) {
215  pr_warning("module %s: Out of range jump to"
216  " %#llx at %#llx (%p)\n", me->name,
217  sym->st_value + rel[i].r_addend,
218  rel[i].r_offset, location);
219  return -ENOEXEC;
220  }
221  MUNGE(create_JumpOff_X1);
222  break;
223 #endif
224 
225 #undef MUNGE
226 
227  default:
228  pr_err("module %s: Unknown relocation: %d\n",
229  me->name, (int) ELF_R_TYPE(rel[i].r_info));
230  return -ENOEXEC;
231  }
232  }
233  return 0;
234 }