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