#if __riscv_xlen == 64 # define STORE sd # define LOAD ld # define LOG_REGBYTES 3 #else # define STORE sw # define LOAD lw # define LOG_REGBYTES 2 #endif #define REGBYTES (1 << LOG_REGBYTES) /* Entry point of all programs (_start). It initializes DWARF call frame information, the stack pointer, the frame pointer (needed for closures to work in start_rust) and the global pointer. Then it calls _start_rust. */ .section .init, "ax" .global _start _start: /* Jump to the absolute address defined by the linker script. */ // for 32bit .if __riscv_xlen == 32 lui ra, %hi(_abs_start) jr %lo(_abs_start)(ra) .endif // for 64bit .if __riscv_xlen == 64 .option push .option norelax // to prevent an unsupported R_RISCV_ALIGN relocation from being generated 1: auipc ra, %pcrel_hi(1f) ld ra, %pcrel_lo(1b)(ra) jr ra .align 3 1: .dword _abs_start .option pop .endif _abs_start: .cfi_startproc .cfi_undefined ra #ifdef SMODE csrw sie, 0 // interrupt disable csrw sip, 0 // no pending interrupts #else csrw mie, 0 csrw mip, 0 #endif li x1, 0 li x2, 0 li x3, 0 li x4, 0 li x5, 0 li x6, 0 li x7, 0 li x8, 0 li x9, 0 // a0..a2 (x10..x12) skipped li x13,0 li x14,0 li x15,0 li x16,0 li x17,0 li x18,0 li x19,0 li x20,0 li x21,0 li x22,0 li x23,0 li x24,0 li x25,0 li x26,0 li x27,0 li x28,0 li x29,0 li x30,0 li x31,0 .option push .option norelax la gp, __global_pointer$ .option pop #ifdef SMODE // there is no equivalent of mhartid in supervisor mode. // instead, the hartid is passed as paramter by SMODE mv t2, a0 #else csrr t2, mhartid #endif lui t0, %hi(_max_hart_id) add t0, t0, %lo(_max_hart_id) bgtu t2, t0, abort // Allocate stacks la sp, _stack_start lui t0, %hi(_hart_stack_size) add t0, t0, %lo(_hart_stack_size) #ifdef __riscv_mul mul t0, t2, t0 #else beqz t2, 2f // Jump if single-hart mv t1, t2 mv t3, t0 1: add t0, t0, t3 addi t1, t1, -1 bnez t1, 1b 2: #endif sub sp, sp, t0 // Set frame pointer add s0, sp, zero jal zero, _start_rust .cfi_endproc /* Trap entry point (_start_trap) Saves caller saved registers ra, t0..6, a0..7, calls _start_trap_rust, restores caller saved registers and then returns. */ .section .trap, "ax" .global default_start_trap default_start_trap: addi sp, sp, -16*REGBYTES STORE ra, 0*REGBYTES(sp) STORE t0, 1*REGBYTES(sp) STORE t1, 2*REGBYTES(sp) STORE t2, 3*REGBYTES(sp) STORE t3, 4*REGBYTES(sp) STORE t4, 5*REGBYTES(sp) STORE t5, 6*REGBYTES(sp) STORE t6, 7*REGBYTES(sp) STORE a0, 8*REGBYTES(sp) STORE a1, 9*REGBYTES(sp) STORE a2, 10*REGBYTES(sp) STORE a3, 11*REGBYTES(sp) STORE a4, 12*REGBYTES(sp) STORE a5, 13*REGBYTES(sp) STORE a6, 14*REGBYTES(sp) STORE a7, 15*REGBYTES(sp) add a0, sp, zero jal ra, _start_trap_rust LOAD ra, 0*REGBYTES(sp) LOAD t0, 1*REGBYTES(sp) LOAD t1, 2*REGBYTES(sp) LOAD t2, 3*REGBYTES(sp) LOAD t3, 4*REGBYTES(sp) LOAD t4, 5*REGBYTES(sp) LOAD t5, 6*REGBYTES(sp) LOAD t6, 7*REGBYTES(sp) LOAD a0, 8*REGBYTES(sp) LOAD a1, 9*REGBYTES(sp) LOAD a2, 10*REGBYTES(sp) LOAD a3, 11*REGBYTES(sp) LOAD a4, 12*REGBYTES(sp) LOAD a5, 13*REGBYTES(sp) LOAD a6, 14*REGBYTES(sp) LOAD a7, 15*REGBYTES(sp) addi sp, sp, 16*REGBYTES #ifdef SMODE sret #else mret #endif /* Make sure there is an abort when linking */ .section .text.abort .globl abort abort: j abort