vma_map.c 7.9 KB

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