dl-startup.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /* Copyright (C) 2010 Texas Instruments Incorporated
  2. * Contributed by Mark Salter <msalter@redhat.com>
  3. *
  4. * Borrowed heavily from frv arch:
  5. * Copyright (C) 2003 Red Hat, Inc.
  6. *
  7. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  8. */
  9. #undef DL_START
  10. #define DL_START(X) \
  11. static void * __attribute_used__ \
  12. _dl_start (unsigned placeholder, \
  13. struct elf32_dsbt_loadmap *dl_boot_progmap, \
  14. struct elf32_dsbt_loadmap *dl_boot_ldsomap, \
  15. Elf32_Dyn *dl_boot_ldso_dyn_pointer, \
  16. X)
  17. /*
  18. * On entry, the kernel has set up the stack thusly:
  19. *
  20. * 0(sp) pad0
  21. * 4(sp) pad1
  22. * 8(sp) argc
  23. * 12(sp) argv[0]
  24. * ...
  25. * (4*(argc+3))(sp) NULL
  26. * (4*(argc+4))(sp) envp[0]
  27. * ...
  28. * NULL
  29. *
  30. * Register values are unspecified, except:
  31. *
  32. * B4 --> executable loadmap address
  33. * A6 --> interpreter loadmap address
  34. * B6 --> dynamic section address
  35. *
  36. * NB: DSBT index is always 0 for the executable
  37. * and 1 for the interpreter
  38. */
  39. __asm__(" .text\n"
  40. ".globl _start\n"
  41. ".hidden _start\n"
  42. "_start:\n"
  43. /* Find interpreter DSBT base in dynamic section */
  44. " MV .S2 B6,B2\n"
  45. " || ADD .D1X B6,4,A2\n"
  46. " LDW .D2T2 *B2++[2],B0\n"
  47. " || LDW .D1T1 *A2++[2],A0\n"
  48. " MVKL .S2 " __stringify(DT_C6000_DSBT_BASE) ",B7\n"
  49. " MVKH .S2 " __stringify(DT_C6000_DSBT_BASE) ",B7\n"
  50. " NOP\n"
  51. " NOP\n"
  52. /*
  53. * B0 now holds dynamic tag and A0 holds tag value.
  54. * Loop through looking for DSBT base tag
  55. */
  56. "0:\n"
  57. " [B0] CMPEQ .L2 B0,B7,B1\n"
  58. " || [!B0] MVK .S2 1,B1\n"
  59. " [!B1] BNOP .S1 0b,5\n"
  60. " ||[!B1] LDW .D2T2 *B2++[2],B0\n"
  61. " ||[!B1] LDW .D1T1 *A2++[2],A0\n"
  62. /*
  63. * DSBT base in A0 needs to be relocated.
  64. * Search through our loadmap to find where it got loaded.
  65. *
  66. * struct elf32_dsbt_loadmap {
  67. * Elf32_Half version;
  68. * Elf32_Half nsegs;
  69. * struct {
  70. * Elf32_Addr addr;
  71. * Elf32_Addr p_vaddr;
  72. * Elf32_Word p_memsz;
  73. * } segments[];
  74. * }
  75. *
  76. */
  77. " MV .S1 A6,A1\n"
  78. " [!A1] MV .S1X B4,A1\n"
  79. " ADD .D1 A1,2,A3\n"
  80. " LDHU .D1T2 *A3++[1],B0\n" /* nsegs */
  81. " LDW .D1T1 *A3++[1],A10\n" /* addr */
  82. " LDW .D1T1 *A3++[1],A11\n" /* p_vaddr */
  83. " LDW .D1T1 *A3++[1],A12\n" /* p_memsz */
  84. " NOP\n"
  85. " NOP\n"
  86. /*
  87. * Here we have:
  88. * B0 -> number of segments to search.
  89. * A3 -> pointer to next segment to check
  90. * A10 -> segment load address
  91. * A11 -> ELF segment virt address
  92. * A12 -> ELF segment size
  93. */
  94. "0:\n"
  95. " [!B0] B .S2 0f\n"
  96. " SUB .D2 B0,1,B0\n"
  97. " CMPLTU .L1 A0,A11,A13\n"
  98. " || SUB .S1 A12,1,A12\n"
  99. " ADD .D1 A11,A12,A12\n"
  100. " CMPGTU .L1 A0,A12,A14\n"
  101. " OR .L1 A13,A14,A2\n"
  102. " [A2] B .S2 0b\n"
  103. " || [!A2] SUB .L1 A0,A11,A0\n"
  104. " [B0] LDW .D1T1 *A3++[1],A10\n" /* addr */
  105. " || [!A2] ADD .L1 A0,A10,A0\n"
  106. " [B0] LDW .D1T1 *A3++[1],A11\n" /* p_vaddr */
  107. " [B0] LDW .D1T1 *A3++[1],A12\n" /* p_memsz */
  108. " MV .S2X A0,B14\n"
  109. " NOP\n"
  110. "0:\n"
  111. " B .S2 _dl_start\n"
  112. " STW .D2T2 B14, *+B14[1]\n"
  113. " ADD .D1X B15,8,A8\n"
  114. " ADDKPC .S2 ret_from_dl,B3,2\n"
  115. "ret_from_dl:\n"
  116. " B .S2X A4\n"
  117. " || LDW .D2T2 *+B14[0],B14\n"
  118. " ADDKPC .S2 __dl_fini,B0,0\n"
  119. " MV .S1X B0,A4\n"
  120. " NOP\n"
  121. " NOP\n"
  122. " NOP\n"
  123. "__dl_fini:\n"
  124. " LDW .D2T2 *+B14[1],B14\n"
  125. " NOP 4\n"
  126. " LDW .D2T1 *+B14($GOT(_dl_fini)), A0\n"
  127. " NOP 4\n"
  128. " BNOP .S2X A0, 5\n");
  129. __asm__(" .text\n"
  130. "__c6x_cache_sync:\n"
  131. " MVK .S2 330,B0\n"
  132. " SWE\n"
  133. " NOP\n"
  134. " BNOP .S2 B3,5\n"
  135. " NOP\n"
  136. " NOP\n"
  137. " NOP\n"
  138. " NOP\n"
  139. "\n"
  140. );
  141. /*
  142. * Get a pointer to the argv array. On many platforms this can be just
  143. * the address of the first argument, on other platforms we need to
  144. * do something a little more subtle here.
  145. */
  146. #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*) ARGS) + 1)
  147. struct elf32_dsbt_loadmap;
  148. /*
  149. * Here is a macro to perform a relocation. This is only used when
  150. * bootstrapping the dynamic loader. RELP is the relocation that we
  151. * are performing, REL is the pointer to the address we are relocating.
  152. * SYMBOL is the symbol involved in the relocation, and LOAD is the
  153. * load address.
  154. */
  155. #define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB) \
  156. switch(ELF_R_TYPE((RELP)->r_info)){ \
  157. case R_C6000_ABS_L16: \
  158. { \
  159. unsigned int opcode = *(REL); \
  160. unsigned int v = (SYMBOL) + (RELP)->r_addend; \
  161. opcode &= ~0x7fff80; \
  162. opcode |= ((v & 0xffff) << 7); \
  163. *(REL) = opcode; \
  164. } \
  165. break; \
  166. case R_C6000_ABS_H16: \
  167. { \
  168. unsigned int opcode = *(REL); \
  169. unsigned int v = (SYMBOL) + (RELP)->r_addend; \
  170. opcode &= ~0x7fff80; \
  171. opcode |= ((v >> 9) & 0x7fff80); \
  172. *(REL) = opcode; \
  173. } \
  174. break; \
  175. case R_C6000_ABS32: \
  176. *(REL) = (SYMBOL) + (RELP)->r_addend; \
  177. break; \
  178. default: \
  179. _dl_exit(1); \
  180. }
  181. extern void __c6x_cache_sync(unsigned long start, unsigned long end)
  182. attribute_hidden;