vma_map.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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. __func__, __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. void __user *spu_elf_start = (void __user *)__spu_elf_start;
  97. struct spu_overlay_info ovly;
  98. unsigned int overlay_tbl_offset = -1;
  99. Elf32_Phdr __user *phdr_start;
  100. Elf32_Shdr __user *shdr_start;
  101. Elf32_Ehdr ehdr;
  102. Elf32_Phdr phdr;
  103. Elf32_Shdr shdr, shdr_str;
  104. Elf32_Sym sym;
  105. int i, j;
  106. char name[32];
  107. unsigned int ovly_table_sym = 0;
  108. unsigned int ovly_buf_table_sym = 0;
  109. unsigned int ovly_table_end_sym = 0;
  110. unsigned int ovly_buf_table_end_sym = 0;
  111. struct spu_overlay_info __user *ovly_table;
  112. unsigned int n_ovlys;
  113. /* Get and validate ELF header. */
  114. if (copy_from_user(&ehdr, spu_elf_start, sizeof (ehdr)))
  115. goto fail;
  116. if (memcmp(ehdr.e_ident, expected, EI_PAD) != 0) {
  117. printk(KERN_ERR "SPU_PROF: "
  118. "%s, line %d: Unexpected e_ident parsing SPU ELF\n",
  119. __func__, __LINE__);
  120. goto fail;
  121. }
  122. if (ehdr.e_machine != EM_SPU) {
  123. printk(KERN_ERR "SPU_PROF: "
  124. "%s, line %d: Unexpected e_machine parsing SPU ELF\n",
  125. __func__, __LINE__);
  126. goto fail;
  127. }
  128. if (ehdr.e_type != ET_EXEC) {
  129. printk(KERN_ERR "SPU_PROF: "
  130. "%s, line %d: Unexpected e_type parsing SPU ELF\n",
  131. __func__, __LINE__);
  132. goto fail;
  133. }
  134. phdr_start = spu_elf_start + ehdr.e_phoff;
  135. shdr_start = spu_elf_start + ehdr.e_shoff;
  136. /* Traverse program headers. */
  137. for (i = 0; i < ehdr.e_phnum; i++) {
  138. if (copy_from_user(&phdr, phdr_start + i, 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, shdr_start + i, sizeof(shdr)))
  153. goto fail;
  154. if (shdr.sh_type != SHT_SYMTAB)
  155. continue;
  156. if (shdr.sh_entsize != sizeof (sym))
  157. continue;
  158. if (copy_from_user(&shdr_str,
  159. shdr_start + shdr.sh_link,
  160. sizeof(shdr)))
  161. goto fail;
  162. if (shdr_str.sh_type != SHT_STRTAB)
  163. goto fail;;
  164. for (j = 0; j < shdr.sh_size / sizeof (sym); j++) {
  165. if (copy_from_user(&sym, spu_elf_start +
  166. shdr.sh_offset +
  167. j * sizeof (sym),
  168. sizeof (sym)))
  169. goto fail;
  170. if (copy_from_user(name,
  171. spu_elf_start + shdr_str.sh_offset +
  172. sym.st_name,
  173. 20))
  174. goto fail;
  175. if (memcmp(name, "_ovly_table", 12) == 0)
  176. ovly_table_sym = sym.st_value;
  177. if (memcmp(name, "_ovly_buf_table", 16) == 0)
  178. ovly_buf_table_sym = sym.st_value;
  179. if (memcmp(name, "_ovly_table_end", 16) == 0)
  180. ovly_table_end_sym = sym.st_value;
  181. if (memcmp(name, "_ovly_buf_table_end", 20) == 0)
  182. ovly_buf_table_end_sym = sym.st_value;
  183. }
  184. }
  185. /* If we don't have overlays, we're done. */
  186. if (ovly_table_sym == 0 || ovly_buf_table_sym == 0
  187. || ovly_table_end_sym == 0 || ovly_buf_table_end_sym == 0) {
  188. pr_debug("SPU_PROF: No overlay table found\n");
  189. goto out;
  190. } else {
  191. pr_debug("SPU_PROF: Overlay table found\n");
  192. }
  193. /* The _ovly_table symbol represents a table with one entry
  194. * per overlay section. The _ovly_buf_table symbol represents
  195. * a table with one entry per overlay region.
  196. * The struct spu_overlay_info gives the structure of the _ovly_table
  197. * entries. The structure of _ovly_table_buf is simply one
  198. * u32 word per entry.
  199. */
  200. overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym,
  201. aSpu, &grd_val);
  202. if (overlay_tbl_offset < 0) {
  203. printk(KERN_ERR "SPU_PROF: "
  204. "%s, line %d: Error finding SPU overlay table\n",
  205. __func__, __LINE__);
  206. goto fail;
  207. }
  208. ovly_table = spu_elf_start + overlay_tbl_offset;
  209. n_ovlys = (ovly_table_end_sym -
  210. ovly_table_sym) / sizeof (ovly);
  211. /* Traverse overlay table. */
  212. for (i = 0; i < n_ovlys; i++) {
  213. if (copy_from_user(&ovly, ovly_table + i, sizeof (ovly)))
  214. goto fail;
  215. /* The ovly.vma/size/offset arguments are analogous to the same
  216. * arguments used above for non-overlay maps. The final two
  217. * args are referred to as the guard pointer and the guard
  218. * value.
  219. * The guard pointer is an entry in the _ovly_buf_table,
  220. * computed using ovly.buf as the index into the table. Since
  221. * ovly.buf values begin at '1' to reference the first (or 0th)
  222. * entry in the _ovly_buf_table, the computation subtracts 1
  223. * from ovly.buf.
  224. * The guard value is stored in the _ovly_buf_table entry and
  225. * is an index (starting at 1) back to the _ovly_table entry
  226. * that is pointing at this _ovly_buf_table entry. So, for
  227. * example, for an overlay scenario with one overlay segment
  228. * and two overlay sections:
  229. * - Section 1 points to the first entry of the
  230. * _ovly_buf_table, which contains a guard value
  231. * of '1', referencing the first (index=0) entry of
  232. * _ovly_table.
  233. * - Section 2 points to the second entry of the
  234. * _ovly_buf_table, which contains a guard value
  235. * of '2', referencing the second (index=1) entry of
  236. * _ovly_table.
  237. */
  238. map = vma_map_add(map, ovly.vma, ovly.size, ovly.offset,
  239. ovly_buf_table_sym + (ovly.buf-1) * 4, i+1);
  240. if (!map)
  241. goto fail;
  242. }
  243. goto out;
  244. fail:
  245. map = NULL;
  246. out:
  247. return map;
  248. }