blob: aba810ee8fa3b3a5eba47f279a7397d611cf88dd [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
/**
* Flash executable runtime initialization code.
*/
// NOTE: The "ax" flag below is necessary to ensure that this section
// is allocated space in ROM by the linker.
.section .crt, "ax"
.extern main
.extern crt_interrupt_vector
.extern kDeviceStopAddress
/**
* Callable entry point for flash.
*
* This sets up the stack, zeroes `.bss`, and sets up `.data`.
* It then jumps into main.
*/
_start:
.globl _start
// Set up the stack. We have no expectation that the rom that
// jumps here will have the correct stack start linked in.
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
// Set up the new interrupt vector.
la t0, crt_interrupt_vector
csrw mtvec, t0
// 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:
// Jump into the C program entry point. This is your standard
// C `main()`, so we need to pass dummy values for `argc` and `argv`.
li a0, 0x0 // argc = 0
li a1, 0x0 // argv = NULL
call main
// Load `kDeviceStopAddress` into `t0`. If it is non-zero, write the return
// value from `main` (in `a0`) into it, otherwise, skip to `wfi` loop.
lw t0, kDeviceStopAddress
beqz t0, wfi_loop
sw a0, 0(t0)
// Loop forever if main somehow returns.
wfi_loop:
wfi
j wfi_loop