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