crt0.S 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /* Copyright (c) 2017-2018 SiFive Inc. All rights reserved.
  2. This copyrighted material is made available to anyone wishing to use,
  3. modify, copy, or redistribute it subject to the terms and conditions
  4. of the FreeBSD License. This program is distributed in the hope that
  5. it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
  6. including the implied warranties of MERCHANTABILITY or FITNESS FOR
  7. A PARTICULAR PURPOSE. A copy of this license is available at
  8. http://www.opensource.org/licenses.
  9. */
  10. /* crt0.S: Entry point for RISC-V METAL programs. */
  11. .section .text.libgloss.start
  12. .global _start
  13. .type _start, @function
  14. /* _start is defined by the METAL to have been called with the following
  15. * arguments:
  16. * a0: the hart ID of the currently executing hart. Harts can start at
  17. * any arbitrary point, it's the C library's job to ensure the code is
  18. * safe.
  19. * a1: a pointer to a description of the machine on which this code is
  20. * currently executing. This is probably 0 on an embedded system
  21. * because they tend to not be dynamically portable. As such, newlib
  22. * ignores this argument.
  23. * a2: a pointer to a function that must be run after the envirnoment has
  24. * been initialized, but before user code can be expected to be run.
  25. * If this is 0 then there is no function to be run. */
  26. _start:
  27. .cfi_startproc
  28. .cfi_undefined ra
  29. /* This is a bit funky: it's not usually sane for _start to return, but in
  30. * this case we actually want to in order to signal an error to the METAL. */
  31. mv s0, ra
  32. /* Before doing anything we must initialize the global pointer, as we cannot
  33. * safely perform any access that may be relaxed without GP being set. This
  34. * is done with relaxation disabled to avoid relaxing the address calculation
  35. * to just "addi gp, gp, 0". */
  36. .option push
  37. .option norelax
  38. la gp, __global_pointer$
  39. .option pop
  40. /* The METAL is designed for a bare-metal environment and therefor is expected
  41. * to define its own stack pointer. We also align the stack pointer here
  42. * because the only RISC-V ABI that's currently defined mandates 16-byte
  43. * stack alignment. */
  44. la sp, _sp
  45. /* Increment by hartid number of stack sizes */
  46. li t0, 0
  47. la t1, __stack_size
  48. 1:
  49. beq t0, a0, 1f
  50. add sp, sp, t1
  51. addi t0, t0, 1
  52. j 1b
  53. 1:
  54. andi sp, sp, -16
  55. /* If we're not hart 0, skip the initialization work */
  56. la t0, __metal_boot_hart
  57. bne a0, t0, _skip_init
  58. /* Embedded systems frequently require relocating the data segment before C
  59. * code can be run -- for example, the data segment may exist in flash upon
  60. * boot and then need to get relocated into a non-persistant writable memory
  61. * before C code can execute. If this is the case we do so here. This step
  62. * is optional: if the METAL provides an environment in which this relocation
  63. * is not necessary then it must simply set metal_segment_data_source_start to
  64. * be equal to metal_segment_data_target_start. */
  65. la t0, metal_segment_data_source_start
  66. la t1, metal_segment_data_target_start
  67. la t2, metal_segment_data_target_end
  68. beq t0, t1, 2f
  69. bge t1, t2, 2f
  70. 1:
  71. #if __riscv_xlen == 32
  72. lw a0, 0(t0)
  73. addi t0, t0, 4
  74. sw a0, 0(t1)
  75. addi t1, t1, 4
  76. blt t1, t2, 1b
  77. #else
  78. ld a0, 0(t0)
  79. addi t0, t0, 8
  80. sd a0, 0(t1)
  81. addi t1, t1, 8
  82. blt t1, t2, 1b
  83. #endif
  84. 2:
  85. /* Copy the ITIM section */
  86. la t0, metal_segment_itim_source_start
  87. la t1, metal_segment_itim_target_start
  88. la t2, metal_segment_itim_target_end
  89. beq t0, t1, 2f
  90. bge t1, t2, 2f
  91. 1:
  92. #if __riscv_xlen == 32
  93. lw a0, 0(t0)
  94. addi t0, t0, 4
  95. sw a0, 0(t1)
  96. addi t1, t1, 4
  97. blt t1, t2, 1b
  98. #else
  99. ld a0, 0(t0)
  100. addi t0, t0, 8
  101. sd a0, 0(t1)
  102. addi t1, t1, 8
  103. blt t1, t2, 1b
  104. #endif
  105. 2:
  106. /* Fence all subsequent instruction fetches until after the ITIM writes
  107. complete */
  108. fence.i
  109. /* Zero the BSS segment. */
  110. la t1, metal_segment_bss_target_start
  111. la t2, metal_segment_bss_target_end
  112. bge t1, t2, 2f
  113. 1:
  114. #if __riscv_xlen == 32
  115. sw x0, 0(t1)
  116. addi t1, t1, 4
  117. blt t1, t2, 1b
  118. #else
  119. sd x0, 0(t1)
  120. addi t1, t1, 8
  121. blt t1, t2, 1b
  122. #endif
  123. 2:
  124. /* At this point we're in an environment that can execute C code. The first
  125. * thing to do is to make the callback to the parent environment if it's been
  126. * requested to do so. */
  127. beqz a2, 1f
  128. jalr a2
  129. 1:
  130. /* The RISC-V port only uses new-style constructors and destructors. */
  131. la a0, __libc_fini_array
  132. call atexit
  133. call __libc_init_array
  134. _skip_init:
  135. /* Synchronize harts so that secondary harts wait until hart 0 finishes
  136. initializing */
  137. call __metal_synchronize_harts
  138. /* Check RISC-V isa and enable FS bits if Floating Point architecture. */
  139. csrr a5, misa
  140. li a4, 0x10028
  141. and a5, a5, a4
  142. beqz a5, 1f
  143. csrr a5, mstatus
  144. lui a4, 0x2
  145. or a5, a5, a4
  146. csrw mstatus, a5
  147. csrwi fcsr, 0
  148. 1:
  149. /* This is a C runtime, so main() is defined to have some arguments. Since
  150. * there's nothing sane the METAL can pass we don't bother with that but
  151. * instead just setup as close to a NOP as we can. */
  152. li a0, 1 /* argc=1 */
  153. la a1, argv /* argv = {"libgloss", NULL} */
  154. la a2, envp /* envp = {NULL} */
  155. call secondary_main
  156. /* Call exit to handle libc's cleanup routines. Under normal contains this
  157. * shouldn't even get called, but I'm still not using a tail call here
  158. * because returning to the METAL is the right thing to do in pathological
  159. * situations. */
  160. call exit
  161. /* And here's where we return. Again, it's a bit odd but the METAL defines
  162. * this as a bad idea (ie, as opposed to leaving it undefined) and at this
  163. * point it's really the only thing left to do. */
  164. mv ra, s0
  165. ret
  166. .cfi_endproc
  167. /* RISC-V systems always use __libc_{init,fini}_array, but for compatibility we
  168. * define _{init,fini} to do nothing. */
  169. .global _init
  170. .type _init, @function
  171. .global _fini
  172. .type _fini, @function
  173. _init:
  174. _fini:
  175. ret
  176. .size _init, .-_init
  177. .size _fini, .-_fini
  178. /* By default, secondary_main will cause secondary harts to spin forever.
  179. * Users can redefine secondary_main themselves to run code on secondary harts */
  180. .weak secondary_main
  181. .global secondary_main
  182. .type secondary_main, @function
  183. secondary_main:
  184. addi sp, sp, -16
  185. #if __riscv_xlen == 32
  186. sw ra, 4(sp)
  187. #else
  188. sd ra, 8(sp)
  189. #endif
  190. csrr t0, mhartid
  191. la t1, __metal_boot_hart
  192. beq t0, t1, 2f
  193. 1:
  194. wfi
  195. j 1b
  196. 2:
  197. call main
  198. #if __riscv_xlen == 32
  199. lw ra, 4(sp)
  200. #else
  201. ld ra, 8(sp)
  202. #endif
  203. addi sp, sp, 16
  204. ret
  205. /* This shim allows main() to be passed a set of arguments that can satisfy the
  206. * requirements of the C API. */
  207. .section .rodata.libgloss.start
  208. argv:
  209. .dc.a name
  210. envp:
  211. .dc.a 0
  212. name:
  213. .asciz "libgloss"