1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * Boot entry point and assembler functions for riscv. 4 * 5 * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com> 6 */ 7#include <asm/asm-offsets.h> 8#include <asm/csr.h> 9 10#if __riscv_xlen == 64 11#define __REG_SEL(a, b) a 12#elif __riscv_xlen == 32 13#define __REG_SEL(a, b) b 14#else 15#error "Unexpected __riscv_xlen" 16#endif 17 18#define REG_L __REG_SEL(ld, lw) 19#define REG_S __REG_SEL(sd, sw) 20#define SZREG __REG_SEL(8, 4) 21 22#define FP_SIZE 16 23 24.macro push_fp, ra=ra 25 addi sp, sp, -FP_SIZE 26 REG_S \ra, (FP_SIZE - SZREG)(sp) 27 REG_S fp, (FP_SIZE - 2*SZREG)(sp) 28 addi fp, sp, FP_SIZE 29.endm 30 31.macro pop_fp 32 REG_L ra, (FP_SIZE - SZREG)(sp) 33 REG_L fp, (FP_SIZE - 2*SZREG)(sp) 34 addi sp, sp, FP_SIZE 35.endm 36 37.macro zero_range, tmp1, tmp2 389998: beq \tmp1, \tmp2, 9997f 39 REG_S zero, 0(\tmp1) 40 addi \tmp1, \tmp1, 8 41 j 9998b 429997: 43.endm 44 45#ifdef CONFIG_EFI 46#include "efi/crt0-efi-riscv64.S" 47#else 48 .section .init 49 50/* 51 * The hartid of the current core is in a0 52 * The address of the devicetree is in a1 53 * 54 * See Linux kernel doc Documentation/riscv/boot.rst 55 */ 56.global start 57start: 58 /* 59 * Stash the hartid in scratch and shift the dtb address into a0. 60 * thread_info_init() will later promote scratch to point at thread 61 * local storage. 62 */ 63 csrw CSR_SSCRATCH, a0 64 mv a0, a1 65 66 /* 67 * Update all R_RISCV_RELATIVE relocations using the table 68 * of Elf32_Rela/Elf64_Rela entries between reloc_start/end. 69 * The build will not emit other relocation types. 70 */ 71 la a1, reloc_start 72 la a2, reloc_end 73 la a3, start // base 741: 75 bge a1, a2, 1f 76 REG_L a4, ELF_RELA_OFFSET(a1) // r_offset 77 REG_L a5, ELF_RELA_ADDEND(a1) // r_addend 78 add a4, a3, a4 // addr = base + r_offset 79 add a5, a3, a5 // val = base + r_addend 80 REG_S a5, 0(a4) // *addr = val 81 addi a1, a1, ELF_RELA_SIZE 82 j 1b 83 841: 85 /* zero BSS */ 86 la a1, bss 87 la a2, ebss 88 zero_range a1, a2 89 90 /* zero and set up stack */ 91 la sp, stacktop 92 li a1, -8192 93 add a1, sp, a1 94 zero_range a1, sp 95 mv fp, zero // Ensure fp starts out as zero 96 97 /* set up exception handling */ 98 la a1, exception_vectors 99 csrw CSR_STVEC, a1 100 101 /* complete setup */ 102 la a1, stacktop // a1 is the base of free memory 103 mv a2, zero // clear a2 for xlen=32 104 call setup // a0 is the addr of the dtb 105 106 /* run the test */ 107 la a0, __argc 108 REG_L a0, 0(a0) 109 la a1, __argv 110 la a2, __environ 111 call main 112 call exit 113 j halt 114 115#endif /* !CONFIG_EFI */ 116 .text 117 118.balign 4 119.global halt 120halt: 1211: wfi 122 j 1b 123 124.balign 4 125.global secondary_entry 126secondary_entry: 127 /* 128 * From the "HSM Hart Start Register State" table of the SBI spec: 129 * satp 0 130 * sstatus.SIE 0 131 * a0 hartid 132 * a1 opaque parameter 133 * 134 * __smp_boot_secondary() sets the opaque parameter (a1) to the physical 135 * address of the stack and the stack contains the secondary data. 136 */ 137 csrw CSR_SSCRATCH, a0 138 mv sp, a1 139 mv fp, zero 140 REG_L a0, SECONDARY_STVEC(sp) 141 csrw CSR_STVEC, a0 142 mv a0, sp 143 call secondary_cinit 144 addi sp, sp, SECONDARY_DATA_SIZE 145 jr a0 146 la a0, do_idle 147 jr a0 148 149/* 150 * Save context to address in a0. 151 * For a0, sets PT_A0(a0) to the contents of PT_ORIG_A0(a0). 152 * Clobbers a1. 153 */ 154.macro save_context 155 REG_S ra, PT_RA(a0) // x1 156 REG_S sp, PT_SP(a0) // x2 157 REG_S gp, PT_GP(a0) // x3 158 REG_S tp, PT_TP(a0) // x4 159 REG_S t0, PT_T0(a0) // x5 160 REG_S t1, PT_T1(a0) // x6 161 REG_S t2, PT_T2(a0) // x7 162 REG_S s0, PT_S0(a0) // x8 / fp 163 REG_S s1, PT_S1(a0) // x9 164 /* a0 */ // x10 165 REG_S a1, PT_A1(a0) // x11 166 REG_S a2, PT_A2(a0) // x12 167 REG_S a3, PT_A3(a0) // x13 168 REG_S a4, PT_A4(a0) // x14 169 REG_S a5, PT_A5(a0) // x15 170 REG_S a6, PT_A6(a0) // x16 171 REG_S a7, PT_A7(a0) // x17 172 REG_S s2, PT_S2(a0) // x18 173 REG_S s3, PT_S3(a0) // x19 174 REG_S s4, PT_S4(a0) // x20 175 REG_S s5, PT_S5(a0) // x21 176 REG_S s6, PT_S6(a0) // x22 177 REG_S s7, PT_S7(a0) // x23 178 REG_S s8, PT_S8(a0) // x24 179 REG_S s9, PT_S9(a0) // x25 180 REG_S s10, PT_S10(a0) // x26 181 REG_S s11, PT_S11(a0) // x27 182 REG_S t3, PT_T3(a0) // x28 183 REG_S t4, PT_T4(a0) // x29 184 REG_S t5, PT_T5(a0) // x30 185 REG_S t6, PT_T6(a0) // x31 186 csrr a1, CSR_SEPC 187 REG_S a1, PT_EPC(a0) 188 csrr a1, CSR_SSTATUS 189 REG_S a1, PT_STATUS(a0) 190 csrr a1, CSR_STVAL 191 REG_S a1, PT_BADADDR(a0) 192 csrr a1, CSR_SCAUSE 193 REG_S a1, PT_CAUSE(a0) 194 REG_L a1, PT_ORIG_A0(a0) 195 REG_S a1, PT_A0(a0) 196.endm 197 198/* 199 * Restore context from address in a0. 200 * Also restores a0. 201 */ 202.macro restore_context 203 REG_L ra, PT_RA(a0) // x1 204 REG_L sp, PT_SP(a0) // x2 205 REG_L gp, PT_GP(a0) // x3 206 REG_L tp, PT_TP(a0) // x4 207 REG_L t0, PT_T0(a0) // x5 208 REG_L t1, PT_T1(a0) // x6 209 REG_L t2, PT_T2(a0) // x7 210 REG_L s0, PT_S0(a0) // x8 / fp 211 REG_L s1, PT_S1(a0) // x9 212 /* a0 */ // x10 213 /* a1 */ // x11 214 REG_L a2, PT_A2(a0) // x12 215 REG_L a3, PT_A3(a0) // x13 216 REG_L a4, PT_A4(a0) // x14 217 REG_L a5, PT_A5(a0) // x15 218 REG_L a6, PT_A6(a0) // x16 219 REG_L a7, PT_A7(a0) // x17 220 REG_L s2, PT_S2(a0) // x18 221 REG_L s3, PT_S3(a0) // x19 222 REG_L s4, PT_S4(a0) // x20 223 REG_L s5, PT_S5(a0) // x21 224 REG_L s6, PT_S6(a0) // x22 225 REG_L s7, PT_S7(a0) // x23 226 REG_L s8, PT_S8(a0) // x24 227 REG_L s9, PT_S9(a0) // x25 228 REG_L s10, PT_S10(a0) // x26 229 REG_L s11, PT_S11(a0) // x27 230 REG_L t3, PT_T3(a0) // x28 231 REG_L t4, PT_T4(a0) // x29 232 REG_L t5, PT_T5(a0) // x30 233 REG_L t6, PT_T6(a0) // x31 234 REG_L a1, PT_EPC(a0) 235 csrw CSR_SEPC, a1 236 REG_L a1, PT_STATUS(a0) 237 csrw CSR_SSTATUS, a1 238 REG_L a1, PT_BADADDR(a0) 239 csrw CSR_STVAL, a1 240 REG_L a1, PT_CAUSE(a0) 241 csrw CSR_SCAUSE, a1 242 REG_L a1, PT_A1(a0) 243 REG_L a0, PT_A0(a0) 244.endm 245 246.balign 4 247.global exception_vectors 248exception_vectors: 249 REG_S a0, (-PT_SIZE - FP_SIZE + PT_ORIG_A0)(sp) 250 addi a0, sp, -PT_SIZE - FP_SIZE 251 save_context 252 /* 253 * Set a frame pointer "ra" which points to the last instruction. 254 * Add 1 to it, because pretty_print_stacks.py subtracts 1. 255 */ 256 REG_L a1, PT_EPC(a0) 257 addi a1, a1, 1 258 push_fp a1 259 mv sp, a0 260 call do_handle_exception 261 mv a0, sp 262 restore_context 263 sret 264