1 /* Copyright 2018 SiFive, Inc */
2 /* SPDX-License-Identifier: Apache-2.0 */
4 /* This code executes before _start, which is contained inside the C library.
5 * In embedded systems we want to ensure that _enter, which contains the first
6 * code to be executed, can be loaded at a specific address. To enable this
7 * feature we provide the '.text.metal.init.enter' section, which is
8 * defined to have the first address being where execution should start. */
9 .section .text.metal.init.enter
14 /* Inform the debugger that there is nowhere to backtrace past _enter. */
17 /* The absolute first thing that must happen is configuring the global
18 * pointer register, which must be done with relaxation disabled because
19 * it's not valid to obtain the address of any symbol without GP
20 * configured. The C environment might go ahead and do this again, but
21 * that's safe as it's a fixed register. */
24 la gp, __global_pointer$
27 /* Set up a simple trap vector to catch anything that goes wrong early in
28 * the boot process. */
29 la t0, early_trap_vector
31 /* enable chicken bit if core is bullet series*/
32 la t0, __metal_chicken_bit
37 /* There may be pre-initialization routines inside the MBI code that run in
38 * C, so here we set up a C environment. First we set up a stack pointer,
39 * which is left as a weak reference in order to allow initialization
40 * routines that do not need a stack to be set up to transparently be
42 .weak __metal_stack_pointer
43 la sp, __metal_stack_pointer
45 /* Check for an initialization routine and call it if one exists, otherwise
46 * just skip over the call entirely. Note that __metal_initialize isn't
47 * actually a full C function, as it doesn't end up with the .bss or .data
48 * segments having been initialized. This is done to avoid putting a
49 * burden on systems that can be initialized without having a C environment
51 .weak __metal_before_start
52 la ra, __metal_before_start
57 /* At this point we can enter the C runtime's startup file. The arguments
58 * to this function are designed to match those provided to the SEE, just
59 * so we don't have to write another ABI. */
65 /* If we've made it back here then there's probably something wrong. We
66 * allow the METAL to register a handler here. */
67 .weak __metal_after_main
68 la ra, __metal_after_main
73 /* If that handler returns then there's not a whole lot we can do. Just
74 * try to make some noise. */
83 /* For sanity's sake we set up an early trap vector that just does nothing. If
84 * you end up here then there's a bug in the early boot code somewhere. */
85 .section .text.metal.init.trapvec
95 /* The GCC port might not emit a __register_frame_info symbol, which eventually
96 * results in a weak undefined reference that eventually causes crash when it
97 * is dereference early in boot. We really shouldn't need to put this here,
98 * but to deal with what I think is probably a bug in the linker script I'm
99 * going to leave this in for now. At least it's fairly cheap :) */
100 .weak __register_frame_info
101 .global __register_frame_info
102 .section .text.metal.init.__register_frame_info
103 __register_frame_info: