]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_GCC/freedom-metal/gloss/crt0.S
Added the "full" demo to the RISC-V_RV32_SiFive_HiFive1_GCC demo - backup check in...
[freertos] / FreeRTOS / Demo / RISC-V_RV32_SiFive_HiFive1_GCC / 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   lw   a0, 0(t0)
84   addi t0, t0, 4
85   sw   a0, 0(t1)
86   addi t1, t1, 4
87   blt  t1, t2, 1b
88 2:
89
90   /* Copy the ITIM section */
91   la t0, metal_segment_itim_source_start
92   la t1, metal_segment_itim_target_start
93   la t2, metal_segment_itim_target_end
94
95   beq t0, t1, 2f
96   bge t1, t2, 2f
97
98 1:
99   lw   a0, 0(t0)
100   addi t0, t0, 4
101   sw   a0, 0(t1)
102   addi t1, t1, 4
103   blt  t1, t2, 1b
104 2:
105
106   /* Zero the BSS segment. */
107   la t1, metal_segment_bss_target_start
108   la t2, metal_segment_bss_target_end
109
110   bge t1, t2, 2f
111
112 1:
113   sw   x0, 0(t1)
114   addi t1, t1, 4
115   blt  t1, t2, 1b
116 2:
117
118   /* At this point we're in an environment that can execute C code.  The first
119    * thing to do is to make the callback to the parent environment if it's been
120    * requested to do so. */
121   beqz a2, 1f
122   jalr a2
123 1:
124
125   /* The RISC-V port only uses new-style constructors and destructors. */
126   la a0, __libc_fini_array
127   call atexit
128 /*_RB_  call __libc_init_array */
129
130 _skip_init:
131
132   /* Synchronize harts so that secondary harts wait until hart 0 finishes
133      initializing */
134   call _synchronize_harts
135
136   /* Check RISC-V isa and enable FS bits if Floating Point architecture. */
137   csrr a5, misa
138   li   a4, 0x10028
139   and  a5, a5, a4
140   beqz a5, 1f
141   csrr a5, mstatus
142   lui  a4, 0x2
143   or   a5, a5, a4
144   csrw mstatus, a5
145   csrwi fcsr, 0
146 1:
147
148   /* This is a C runtime, so main() is defined to have some arguments.  Since
149    * there's nothing sane the METAL can pass we don't bother with that but
150    * instead just setup as close to a NOP as we can. */
151   li a0, 1     /* argc=1 */
152   la a1, argv  /* argv = {"libgloss", NULL} */
153   la a2, envp  /* envp = {NULL} */
154   call secondary_main
155
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
162   /* And here's where we return.  Again, it's a bit odd but the METAL defines
163    * this as a bad idea (ie, as opposed to leaving it undefined) and at this
164    * point it's really the only thing left to do. */
165   mv ra, s0
166   ret
167
168 .cfi_endproc
169
170 /* RISC-V systems always use __libc_{init,fini}_array, but for compatibility we
171  * define _{init,fini} to do nothing. */
172 .global _init
173 .type   _init, @function
174 .global _fini
175 .type   _fini, @function
176 _init:
177 _fini:
178   ret
179 .size _init, .-_init
180 .size _fini, .-_fini
181
182 /* By default, secondary_main will cause secondary harts to spin forever.
183  * Users can redefine secondary_main themselves to run code on secondary harts */
184 .weak   secondary_main
185 .global secondary_main
186 .type   secondary_main, @function
187
188 secondary_main:
189   addi sp, sp, -16
190 #if __riscv_xlen == 32
191   sw ra, 4(sp)
192 #else
193   sd ra, 8(sp)
194 #endif
195   csrr t0, mhartid
196   la t1, __metal_boot_hart
197   beq t0, t1, 2f
198 1:
199   wfi
200   j 1b
201 2:
202   call main
203 #if __riscv_xlen == 32
204   lw ra, 4(sp)
205 #else
206   ld ra, 8(sp)
207 #endif
208   addi sp, sp, 16
209   ret
210
211 /* This shim allows main() to be passed a set of arguments that can satisfy the
212  * requirements of the C API. */
213 .section .rodata.libgloss.start
214 argv:
215 .dc.a name
216 envp:
217 .dc.a 0
218 name:
219 .asciz "libgloss"
220