vma_map.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*
  2. * Cell Broadband Engine OProfile Support
  3. *
  4. * (C) Copyright IBM Corporation 2006
  5. *
  6. * Author: Maynard Johnson <maynardj@us.ibm.com>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version
  11. * 2 of the License, or (at your option) any later version.
  12. */
  13. /* The code in this source file is responsible for generating
  14. * vma-to-fileOffset maps for both overlay and non-overlay SPU
  15. * applications.
  16. */
  17. #include <linux/mm.h>
  18. #include <linux/string.h>
  19. #include <linux/uaccess.h>
  20. #include <linux/elf.h>
  21. #include <linux/slab.h>
  22. #include "pr_util.h"
  23. void vma_map_free(struct vma_to_fileoffset_map *map)
  24. {
  25. while (map) {
  26. struct vma_to_fileoffset_map *next = map->next;
  27. kfree(map);
  28. map = next;
  29. }
  30. }
  31. unsigned int
  32. vma_map_lookup(struct vma_to_fileoffset_map *map, unsigned int vma,
  33. const struct spu *aSpu, int *grd_val)
  34. {
  35. /*
  36. * Default the offset to the physical address + a flag value.
  37. * Addresses of dynamically generated code can't be found in the vma
  38. * map. For those addresses the flagged value will be sent on to
  39. * the user space tools so they can be reported rather than just
  40. * thrown away.
  41. */
  42. u32 offset = 0x10000000 + vma;
  43. u32 ovly_grd;
  44. for (; map; map = map->next) {
  45. if (vma < map->vma || vma >= map->vma + map->size)
  46. continue;
  47. if (map->guard_ptr) {
  48. ovly_grd = *(u32 *)(aSpu->local_store + map->guard_ptr);
  49. if (ovly_grd != map->guard_val)
  50. continue;
  51. *grd_val = ovly_grd;
  52. }
  53. offset = vma - map->vma + map->offset;
  54. break;
  55. }
  56. return offset;
  57. }
  58. static struct vma_to_fileoffset_map *
  59. vma_map_add(struct vma_to_fileoffset_map *map, unsigned int vma,
  60. unsigned int size, unsigned int offset, unsigned int guard_ptr,
  61. unsigned int guard_val)
  62. {
  63. struct vma_to_fileoffset_map *new =
  64. kzalloc(sizeof(struct vma_to_fileoffset_map), GFP_KERNEL);
  65. if (!new) {
  66. printk(KERN_ERR "SPU_PROF: %s, line %d: malloc failed\n",
  67. __func__, __LINE__);
  68. vma_map_free(map);
  69. return NULL;
  70. }
  71. new->next = map;
  72. new->vma = vma;
  73. new->size = size;
  74. new->offset = offset;
  75. new->guard_ptr = guard_ptr;
  76. new->guard_val = guard_val;
  77. return new;
  78. }
  79. /* Parse SPE ELF header and generate a list of vma_maps.
  80. * A pointer to the first vma_map in the generated list
  81. * of vma_maps is returned. */
  82. struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu,
  83. unsigned long __spu_elf_start)
  84. {
  85. static const unsigned char expected[EI_PAD] = {
  86. [EI_MAG0] = ELFMAG0,
  87. [EI_MAG1] = ELFMAG1,
  88. [EI_MAG2] = ELFMAG2,
  89. [EI_MAG3] = ELFMAG3,
  90. [EI_CLASS] = ELFCLASS32,
  91. [EI_DATA] = ELFDATA2MSB,
  92. [EI_VERSION] = EV_CURRENT,
  93. [EI_OSABI] = ELFOSABI_NONE
  94. };
  95. int grd_val;
  96. struct vma_to_fileoffset_map *map = NULL;
  97. void __user *spu_elf_start = (void __user *)__spu_elf_start;
  98. struct spu_overlay_info ovly;
  99. unsigned int overlay_tbl_offset = -1;
  100. Elf32_Phdr __user *phdr_start;
  101. Elf32_Shdr __user *shdr_start;
  102. Elf32_Ehdr ehdr;
  103. Elf32_Phdr phdr;
  104. Elf32_Shdr shdr, shdr_str;
  105. Elf32_Sym sym;
  106. int i, j;
  107. char name[32];
  108. unsigned int ovly_table_sym = 0;
  109. unsigned int ovly_buf_table_sym = 0;
  110. unsigned int ovly_table_end_sym = 0;
  111. unsigned int ovly_buf_table_end_sym = 0;
  112. struct spu_overlay_info __user *ovly_table;
  113. unsigned int n_ovlys;
  114. /* Get and validate ELF header. */
  115. if (copy_from_user(&ehdr, spu_elf_start, sizeof (ehdr)))
  116. goto fail;
  117. if (memcmp(ehdr.e_ident, expected, EI_PAD) != 0) {
  118. printk(KERN_ERR "SPU_PROF: "
  119. "%s, line %d: Unexpected e_ident parsing SPU ELF\n",
  120. __func__, __LINE__);
  121. goto fail;
  122. }
  123. if (ehdr.e_machine != EM_SPU) {
  124. printk(KERN_ERR "SPU_PROF: "
  125. "%s, line %d: Unexpected e_machine parsing SPU ELF\n",
  126. __func__, __LINE__);
  127. goto fail;
  128. }
  129. if (ehdr.e_type != ET_EXEC) {
  130. printk(KERN_ERR "SPU_PROF: "
  131. "%s, line %d: Unexpected e_type parsing SPU ELF\n",
  132. __func__, __LINE__);
  133. goto fail;
  134. }
  135. phdr_start = spu_elf_start + ehdr.e_phoff;
  136. shdr_start = spu_elf_start + ehdr.e_shoff;
  137. /* Traverse program headers. */
  138. for (i = 0; i < ehdr.e_phnum; i++) {
  139. if (copy_from_user(&phdr, phdr_start + i, sizeof(phdr)))
  140. goto fail;
  141. if (phdr.p_type != PT_LOAD)
  142. continue;
  143. if (phdr.p_flags & (1 << 27))
  144. continue;
  145. map = vma_map_add(map, phdr.p_vaddr, phdr.p_memsz,
  146. phdr.p_offset, 0, 0);
  147. if (!map)
  148. goto fail;
  149. }
  150. pr_debug("SPU_PROF: Created non-overlay maps\n");
  151. /* Traverse section table and search for overlay-related symbols. */
  152. for (i = 0; i < ehdr.e_shnum; i++) {
  153. if (copy_from_user(&shdr, shdr_start + i, sizeof(shdr)))
  154. goto fail;
  155. if (shdr.sh_type != SHT_SYMTAB)
  156. continue;
  157. if (shdr.sh_entsize != sizeof (sym))
  158. continue;
  159. if (copy_from_user(&shdr_str,
  160. shdr_start + shdr.sh_link,
  161. sizeof(shdr)))
  162. goto fail;
  163. if (shdr_str.sh_type != SHT_STRTAB)
  164. goto fail;
  165. for (j = 0; j < shdr.sh_size / sizeof (sym); j++) {
  166. if (copy_from_user(&sym, spu_elf_start +
  167. shdr.sh_offset +
  168. j * sizeof (sym),
  169. sizeof (sym)))
  170. goto fail;
  171. if (copy_from_user(name,
  172. spu_elf_start + shdr_str.sh_offset +
  173. sym.st_name,
  174. 20))
  175. goto fail;
  176. if (memcmp(name, "_ovly_table", 12) == 0)
  177. ovly_table_sym = sym.st_value;
  178. if (memcmp(name, "_ovly_buf_table", 16) == 0)
  179. ovly_buf_table_sym = sym.st_value;
  180. if (memcmp(name, "_ovly_table_end", 16) == 0)
  181. ovly_table_end_sym = sym.st_value;
  182. if (memcmp(name, "_ovly_buf_table_end", 20) == 0)
  183. ovly_buf_table_end_sym = sym.st_value;
  184. }
  185. }
  186. /* If we don't have overlays, we're done. */
  187. if (ovly_table_sym == 0 || ovly_buf_table_sym == 0
  188. || ovly_table_end_sym == 0 || ovly_buf_table_end_sym == 0) {
  189. pr_debug("SPU_PROF: No overlay table found\n");
  190. goto out;
  191. } else {
  192. pr_debug("SPU_PROF: Overlay table found\n");
  193. }
  194. /* The _ovly_table symbol represents a table with one entry
  195. * per overlay section. The _ovly_buf_table symbol represents
  196. * a table with one entry per overlay region.
  197. * The struct spu_overlay_info gives the structure of the _ovly_table
  198. * entries. The structure of _ovly_table_buf is simply one
  199. * u32 word per entry.
  200. */
  201. overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym,
  202. aSpu, &grd_val);
  203. if (overlay_tbl_offset > 0x10000000) {
  204. printk(KERN_ERR "SPU_PROF: "
  205. "%s, line %d: Error finding SPU overlay table\n",
  206. __func__, __LINE__);
  207. goto fail;
  208. }
  209. ovly_table = spu_elf_start + overlay_tbl_offset;
  210. n_ovlys = (ovly_table_end_sym -
  211. ovly_table_sym) / sizeof (ovly);
  212. /* Traverse overlay table. */
  213. for (i = 0; i < n_ovlys; i++) {
  214. if (copy_from_user(&ovly, ovly_table + i, sizeof (ovly)))
  215. goto fail;
  216. /* The ovly.vma/size/offset arguments are analogous to the same
  217. * arguments used above for non-overlay maps. The final two
  218. * args are referred to as the guard pointer and the guard
  219. * value.
  220. * The guard pointer is an entry in the _ovly_buf_table,
  221. * computed using ovly.buf as the index into the table. Since
  222. * ovly.buf values begin at '1' to reference the first (or 0th)
  223. * entry in the _ovly_buf_table, the computation subtracts 1
  224. * from ovly.buf.
  225. * The guard value is stored in the _ovly_buf_table entry and
  226. * is an index (starting at 1) back to the _ovly_table entry
  227. * that is pointing at this _ovly_buf_table entry. So, for
  228. * example, for an overlay scenario with one overlay segment
  229. * and two overlay sections:
  230. * - Section 1 points to the first entry of the
  231. * _ovly_buf_table, which contains a guard value
  232. * of '1', referencing the first (index=0) entry of
  233. * _ovly_table.
  234. * - Section 2 points to the second entry of the
  235. * _ovly_buf_table, which contains a guard value
  236. * of '2', referencing the second (index=1) entry of
  237. * _ovly_table.
  238. */
  239. map = vma_map_add(map, ovly.vma, ovly.size, ovly.offset,
  240. ovly_buf_table_sym + (ovly.buf-1) * 4, i+1);
  241. if (!map)
  242. goto fail;
  243. }
  244. goto out;
  245. fail:
  246. map = NULL;
  247. out:
  248. return map;
  249. }