| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| /** |
| * Boot ROM runtime initialization code. |
| */ |
| |
| // NOTE: The "ax" flag below is necessary to ensure that this section |
| // is allocated executable space in ROM by the linker. |
| .section .crt, "ax" |
| |
| /** |
| * Entry point after reset. This symbol is jumped to from the handler |
| * for IRQ 0x80. |
| * |
| * Sets up the stack, then jumps to `_start`. |
| */ |
| _reset_start: |
| .globl _reset_start |
| // Clobber all writeable registers. |
| li x1, 0x0 |
| li x2, 0x0 |
| li x3, 0x0 |
| li x4, 0x0 |
| li x5, 0x0 |
| li x6, 0x0 |
| li x7, 0x0 |
| li x8, 0x0 |
| li x9, 0x0 |
| li x10, 0x0 |
| li x11, 0x0 |
| li x12, 0x0 |
| li x13, 0x0 |
| li x14, 0x0 |
| li x15, 0x0 |
| li x16, 0x0 |
| li x17, 0x0 |
| li x18, 0x0 |
| li x19, 0x0 |
| li x20, 0x0 |
| li x21, 0x0 |
| li x22, 0x0 |
| li x23, 0x0 |
| li x24, 0x0 |
| li x25, 0x0 |
| li x26, 0x0 |
| li x27, 0x0 |
| li x28, 0x0 |
| li x29, 0x0 |
| li x30, 0x0 |
| li x31, 0x0 |
| |
| // Set up the stack. |
| la sp, _stack_start |
| |
| // Set up the global pointer. This requires that we disable linker relaxations |
| // (or it will be relaxed to `mv gp, gp`). |
| .option push |
| .option norelax |
| la gp, __global_pointer$ |
| .option pop |
| |
| // Explicit fall-through to `_start`. |
| |
| /** |
| * Callable entry point for the boot rom. |
| * |
| * Currently, this zeroes the `.bss` section, copies initial data to |
| * `.data`, and then jumps to the program entry point. |
| */ |
| _start: |
| .globl _start |
| |
| // Zero out the `.bss` segment. |
| // |
| // We use `t0` and `t1` to represent the start and end pointers |
| // of `.bss`. |
| la t0, _bss_start |
| la t1, _bss_end |
| bgeu t0, t1, bss_zero_loop_end |
| bss_zero_loop: |
| sw zero, 0(t0) |
| addi t0, t0, 0x4 |
| bltu t0, t1, bss_zero_loop |
| bss_zero_loop_end: |
| |
| // Zero out the stack |
| // |
| // We use `t0` and `t1` to represent the start and end pointers of the stack. |
| // As the stack grows downwards and we zero going forwards the start pointer |
| // starts as _stack_end and the end pointer at _stack_start |
| la t0, _stack_end |
| la t1, _stack_start |
| bgeu t0, t1, stack_zero_loop_end |
| stack_zero_loop: |
| sw zero, 0(t0) |
| addi t0, t0, 0x4 |
| bltu t0, t1, stack_zero_loop |
| stack_zero_loop_end: |
| |
| // Initialize the `.data` segment from the `.idata` segment. |
| // |
| // We use `t0` and `t1` to represent the start and end pointers |
| // of `.data`, `t2` to represent the start pointer of `.idata` |
| // (which has the same length as `.data`) and `t3` is a scratch |
| // register for the copy. |
| la t0, _data_start |
| la t1, _data_end |
| la t2, _data_init_start |
| bgeu t0, t1, data_copy_loop_end |
| data_copy_loop: |
| lw t3, 0(t2) |
| sw t3, 0(t0) |
| addi t0, t0, 0x4 |
| addi t2, t2, 0x4 |
| bltu t0, t1, data_copy_loop |
| data_copy_loop_end: |
| |
| // Re-clobber all of the registers from above. |
| li t0, 0x0 |
| li t1, 0x0 |
| li t2, 0x0 |
| li t3, 0x0 |
| |
| // Jump into the C program entry point. |
| call _boot_start |
| |
| // Loop forever if _boot_start somehow returns. |
| 1: |
| wfi |
| j 1b |