1 /* Copyright (c) 2017-2018 SiFive Inc. All rights reserved.
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.
12 /* crt0.S: Entry point for RISC-V METAL programs. */
14 .section .text.libgloss.start
16 .type _start, @function
18 /* _start is defined by the METAL to have been called with the following
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
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. */
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. */
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". */
44 la gp, __global_pointer$
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
53 /* Increment by hartid number of stack sizes */
64 /* If we're not hart 0, skip the initialization work */
65 la t0, __metal_boot_hart
66 bne a0, t0, _skip_init
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
83 #if __riscv_xlen == 32
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
107 #if __riscv_xlen == 32
122 /* Fence all subsequent instruction fetches until after the ITIM writes
126 /* Zero the BSS segment. */
127 la t1, metal_segment_bss_target_start
128 la t2, metal_segment_bss_target_end
133 #if __riscv_xlen == 32
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. */
151 /* The RISC-V port only uses new-style constructors and destructors. */
152 la a0, __libc_fini_array
154 call __libc_init_array
158 /* Synchronize harts so that secondary harts wait until hart 0 finishes
160 call __metal_synchronize_harts
162 /* Check RISC-V isa and enable FS bits if Floating Point architecture. */
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} */
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
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. */
196 /* RISC-V systems always use __libc_{init,fini}_array, but for compatibility we
197 * define _{init,fini} to do nothing. */
199 .type _init, @function
201 .type _fini, @function
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 */
211 .global secondary_main
212 .type secondary_main, @function
216 #if __riscv_xlen == 32
222 la t1, __metal_boot_hart
229 #if __riscv_xlen == 32
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