crt0.S 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * Copyright (C) Paul Mackerras 1997.
  3. *
  4. * Adapted for 64 bit LE PowerPC by Andrew Tauferner
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. *
  11. */
  12. #include "ppc_asm.h"
  13. RELA = 7
  14. RELACOUNT = 0x6ffffff9
  15. .text
  16. /* A procedure descriptor used when booting this as a COFF file.
  17. * When making COFF, this comes first in the link and we're
  18. * linked at 0x500000.
  19. */
  20. .globl _zimage_start_opd
  21. _zimage_start_opd:
  22. .long 0x500000, 0, 0, 0
  23. #ifdef __powerpc64__
  24. .balign 8
  25. p_start: .llong _start
  26. p_etext: .llong _etext
  27. p_bss_start: .llong __bss_start
  28. p_end: .llong _end
  29. p_toc: .llong __toc_start + 0x8000 - p_base
  30. p_dyn: .llong __dynamic_start - p_base
  31. p_rela: .llong __rela_dyn_start - p_base
  32. p_prom: .llong 0
  33. .weak _platform_stack_top
  34. p_pstack: .llong _platform_stack_top
  35. #else
  36. p_start: .long _start
  37. p_etext: .long _etext
  38. p_bss_start: .long __bss_start
  39. p_end: .long _end
  40. .weak _platform_stack_top
  41. p_pstack: .long _platform_stack_top
  42. #endif
  43. .weak _zimage_start
  44. .globl _zimage_start
  45. _zimage_start:
  46. .globl _zimage_start_lib
  47. _zimage_start_lib:
  48. /* Work out the offset between the address we were linked at
  49. and the address where we're running. */
  50. bl .+4
  51. p_base: mflr r10 /* r10 now points to runtime addr of p_base */
  52. #ifndef __powerpc64__
  53. /* grab the link address of the dynamic section in r11 */
  54. addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha
  55. lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11)
  56. cmpwi r11,0
  57. beq 3f /* if not linked -pie */
  58. /* get the runtime address of the dynamic section in r12 */
  59. .weak __dynamic_start
  60. addis r12,r10,(__dynamic_start-p_base)@ha
  61. addi r12,r12,(__dynamic_start-p_base)@l
  62. subf r11,r11,r12 /* runtime - linktime offset */
  63. /* The dynamic section contains a series of tagged entries.
  64. * We need the RELA and RELACOUNT entries. */
  65. li r9,0
  66. li r0,0
  67. 9: lwz r8,0(r12) /* get tag */
  68. cmpwi r8,0
  69. beq 10f /* end of list */
  70. cmpwi r8,RELA
  71. bne 11f
  72. lwz r9,4(r12) /* get RELA pointer in r9 */
  73. b 12f
  74. 11: addis r8,r8,(-RELACOUNT)@ha
  75. cmpwi r8,RELACOUNT@l
  76. bne 12f
  77. lwz r0,4(r12) /* get RELACOUNT value in r0 */
  78. 12: addi r12,r12,8
  79. b 9b
  80. /* The relocation section contains a list of relocations.
  81. * We now do the R_PPC_RELATIVE ones, which point to words
  82. * which need to be initialized with addend + offset.
  83. * The R_PPC_RELATIVE ones come first and there are RELACOUNT
  84. * of them. */
  85. 10: /* skip relocation if we don't have both */
  86. cmpwi r0,0
  87. beq 3f
  88. cmpwi r9,0
  89. beq 3f
  90. add r9,r9,r11 /* Relocate RELA pointer */
  91. mtctr r0
  92. 2: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */
  93. cmpwi r0,22 /* R_PPC_RELATIVE */
  94. bne 3f
  95. lwz r12,0(r9) /* reloc->r_offset */
  96. lwz r0,8(r9) /* reloc->r_addend */
  97. add r0,r0,r11
  98. stwx r0,r11,r12
  99. addi r9,r9,12
  100. bdnz 2b
  101. /* Do a cache flush for our text, in case the loader didn't */
  102. 3: lwz r9,p_start-p_base(r10) /* note: these are relocated now */
  103. lwz r8,p_etext-p_base(r10)
  104. 4: dcbf r0,r9
  105. icbi r0,r9
  106. addi r9,r9,0x20
  107. cmplw cr0,r9,r8
  108. blt 4b
  109. sync
  110. isync
  111. /* Clear the BSS */
  112. lwz r9,p_bss_start-p_base(r10)
  113. lwz r8,p_end-p_base(r10)
  114. li r0,0
  115. 5: stw r0,0(r9)
  116. addi r9,r9,4
  117. cmplw cr0,r9,r8
  118. blt 5b
  119. /* Possibly set up a custom stack */
  120. lwz r8,p_pstack-p_base(r10)
  121. cmpwi r8,0
  122. beq 6f
  123. lwz r1,0(r8)
  124. li r0,0
  125. stwu r0,-16(r1) /* establish a stack frame */
  126. 6:
  127. #else /* __powerpc64__ */
  128. /* Save the prom pointer at p_prom. */
  129. std r5,(p_prom-p_base)(r10)
  130. /* Set r2 to the TOC. */
  131. ld r2,(p_toc-p_base)(r10)
  132. add r2,r2,r10
  133. /* Grab the link address of the dynamic section in r11. */
  134. ld r11,-32768(r2)
  135. cmpwi r11,0
  136. beq 3f /* if not linked -pie then no dynamic section */
  137. ld r11,(p_dyn-p_base)(r10)
  138. add r11,r11,r10
  139. ld r9,(p_rela-p_base)(r10)
  140. add r9,r9,r10
  141. li r13,0
  142. li r8,0
  143. 9: ld r12,0(r11) /* get tag */
  144. cmpdi r12,0
  145. beq 12f /* end of list */
  146. cmpdi r12,RELA
  147. bne 10f
  148. ld r13,8(r11) /* get RELA pointer in r13 */
  149. b 11f
  150. 10: addis r12,r12,(-RELACOUNT)@ha
  151. cmpdi r12,RELACOUNT@l
  152. bne 11f
  153. ld r8,8(r11) /* get RELACOUNT value in r8 */
  154. 11: addi r11,r11,16
  155. b 9b
  156. 12:
  157. cmpdi r13,0 /* check we have both RELA and RELACOUNT */
  158. cmpdi cr1,r8,0
  159. beq 3f
  160. beq cr1,3f
  161. /* Calcuate the runtime offset. */
  162. subf r13,r13,r9
  163. /* Run through the list of relocations and process the
  164. * R_PPC64_RELATIVE ones. */
  165. mtctr r8
  166. 13: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */
  167. cmpdi r0,22 /* R_PPC64_RELATIVE */
  168. bne 3f
  169. ld r12,0(r9) /* reloc->r_offset */
  170. ld r0,16(r9) /* reloc->r_addend */
  171. add r0,r0,r13
  172. stdx r0,r13,r12
  173. addi r9,r9,24
  174. bdnz 13b
  175. /* Do a cache flush for our text, in case the loader didn't */
  176. 3: ld r9,p_start-p_base(r10) /* note: these are relocated now */
  177. ld r8,p_etext-p_base(r10)
  178. 4: dcbf r0,r9
  179. icbi r0,r9
  180. addi r9,r9,0x20
  181. cmpld cr0,r9,r8
  182. blt 4b
  183. sync
  184. isync
  185. /* Clear the BSS */
  186. ld r9,p_bss_start-p_base(r10)
  187. ld r8,p_end-p_base(r10)
  188. li r0,0
  189. 5: std r0,0(r9)
  190. addi r9,r9,8
  191. cmpld cr0,r9,r8
  192. blt 5b
  193. /* Possibly set up a custom stack */
  194. ld r8,p_pstack-p_base(r10)
  195. cmpdi r8,0
  196. beq 6f
  197. ld r1,0(r8)
  198. li r0,0
  199. stdu r0,-112(r1) /* establish a stack frame */
  200. 6:
  201. #endif /* __powerpc64__ */
  202. /* Call platform_init() */
  203. bl platform_init
  204. /* Call start */
  205. b start
  206. #ifdef __powerpc64__
  207. #define PROM_FRAME_SIZE 512
  208. #define SAVE_GPR(n, base) std n,8*(n)(base)
  209. #define REST_GPR(n, base) ld n,8*(n)(base)
  210. #define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base)
  211. #define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
  212. #define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
  213. #define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
  214. #define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base)
  215. #define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base)
  216. #define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
  217. #define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
  218. /* prom handles the jump into and return from firmware. The prom args pointer
  219. is loaded in r3. */
  220. .globl prom
  221. prom:
  222. mflr r0
  223. std r0,16(r1)
  224. stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
  225. SAVE_GPR(2, r1)
  226. SAVE_GPR(13, r1)
  227. SAVE_8GPRS(14, r1)
  228. SAVE_10GPRS(22, r1)
  229. mfcr r10
  230. std r10,8*32(r1)
  231. mfmsr r10
  232. std r10,8*33(r1)
  233. /* remove MSR_LE from msr but keep MSR_SF */
  234. mfmsr r10
  235. rldicr r10,r10,0,62
  236. mtsrr1 r10
  237. /* Load FW address, set LR to label 1, and jump to FW */
  238. bl 0f
  239. 0: mflr r10
  240. addi r11,r10,(1f-0b)
  241. mtlr r11
  242. ld r10,(p_prom-0b)(r10)
  243. mtsrr0 r10
  244. rfid
  245. 1: /* Return from OF */
  246. FIXUP_ENDIAN
  247. /* Restore registers and return. */
  248. rldicl r1,r1,0,32
  249. /* Restore the MSR (back to 64 bits) */
  250. ld r10,8*(33)(r1)
  251. mtmsr r10
  252. isync
  253. /* Restore other registers */
  254. REST_GPR(2, r1)
  255. REST_GPR(13, r1)
  256. REST_8GPRS(14, r1)
  257. REST_10GPRS(22, r1)
  258. ld r10,8*32(r1)
  259. mtcr r10
  260. addi r1,r1,PROM_FRAME_SIZE
  261. ld r0,16(r1)
  262. mtlr r0
  263. blr
  264. #endif