1/* SPDX-License-Identifier: GPL-2.0+ */ 2/* 3 * Startup Code for RISC-V Core 4 * 5 * Copyright (c) 2017 Microsemi Corporation. 6 * Copyright (c) 2017 Padmarao Begari <Padmarao.Begari@microsemi.com> 7 * 8 * Copyright (C) 2017 Andes Technology Corporation 9 * Rick Chen, Andes Technology Corporation <rick@andestech.com> 10 */ 11 12#include <asm-offsets.h> 13#include <config.h> 14#include <elf.h> 15#include <system-constants.h> 16#include <asm/encoding.h> 17#include <generated/asm-offsets.h> 18 19#ifdef CONFIG_32BIT 20#define LREG lw 21#define SREG sw 22#define REGBYTES 4 23#define RELOC_TYPE R_RISCV_32 24#define SYM_INDEX 0x8 25#define SYM_SIZE 0x10 26#else 27#define LREG ld 28#define SREG sd 29#define REGBYTES 8 30#define RELOC_TYPE R_RISCV_64 31#define SYM_INDEX 0x20 32#define SYM_SIZE 0x18 33#endif 34 35.section .data 36secondary_harts_relocation_error: 37 .ascii "Relocation of secondary harts has failed, error %d\n" 38 39.section .text 40.globl _start 41_start: 42#if CONFIG_IS_ENABLED(RISCV_MMODE) 43 csrr a0, CSR_MHARTID 44#endif 45 46 /* 47 * Save hart id and dtb pointer. The thread pointer register is not 48 * modified by C code. It is used by secondary_hart_loop. 49 */ 50 mv tp, a0 51 mv s1, a1 52 53 /* 54 * Set the global data pointer to a known value in case we get a very 55 * early trap. The global data pointer will be set its actual value only 56 * after it has been initialized. 57 */ 58 mv gp, zero 59 60 /* 61 * Set the trap handler. This must happen after initializing gp because 62 * the handler may use it. 63 */ 64 la t0, trap_entry 65 csrw MODE_PREFIX(tvec), t0 66 67 /* 68 * Mask all interrupts. Interrupts are disabled globally (in m/sstatus) 69 * for U-Boot, but we will need to read m/sip to determine if we get an 70 * IPI 71 */ 72 csrw MODE_PREFIX(ie), zero 73 74#if CONFIG_IS_ENABLED(SMP) 75 /* check if hart is within range */ 76 /* tp: hart id */ 77 li t0, CONFIG_NR_CPUS 78 bge tp, t0, hart_out_of_bounds_loop 79 80 /* set xSIE bit to receive IPIs */ 81#if CONFIG_IS_ENABLED(RISCV_MMODE) 82 li t0, MIE_MSIE 83#else 84 li t0, SIE_SSIE 85#endif 86 csrs MODE_PREFIX(ie), t0 87#endif 88 89/* 90 * Set stackpointer in internal/ex RAM to call board_init_f 91 */ 92call_board_init_f: 93#if CONFIG_IS_ENABLED(HAVE_INIT_STACK) 94 li t0, CONFIG_VAL(STACK) 95#else 96 li t0, SYS_INIT_SP_ADDR 97#endif 98 and t0, t0, -16 /* force 16 byte alignment */ 99 100 /* setup stack */ 101#if CONFIG_IS_ENABLED(SMP) 102 /* tp: hart id */ 103 slli t1, tp, CONFIG_STACK_SIZE_SHIFT 104 sub sp, t0, t1 105#else 106 mv sp, t0 107#endif 108/* 109 * Now sp points to the right stack belonging to current CPU. 110 * It's essential before any function call, otherwise, we get data-race. 111 */ 112 113/* clear stack if necessary */ 114#if CONFIG_IS_ENABLED(ZERO_MEM_BEFORE_USE) 115clear_stack: 116 li t1, 1 117 slli t1, t1, CONFIG_STACK_SIZE_SHIFT 118 sub t1, sp, t1 119clear_stack_loop: 120 SREG zero, 0(t1) /* t1 is always 16 byte aligned */ 121 addi t1, t1, REGBYTES 122 blt t1, sp, clear_stack_loop 123#endif 124 125call_board_init_f_0: 126 /* find top of reserve space */ 127#if CONFIG_IS_ENABLED(SMP) 128 li t1, CONFIG_NR_CPUS 129#else 130 li t1, 1 131#endif 132 slli t1, t1, CONFIG_STACK_SIZE_SHIFT 133 sub a0, t0, t1 /* t1 -> size of all CPU stacks */ 134 jal board_init_f_alloc_reserve 135 136 /* 137 * Save global data pointer for later. We don't set it here because it 138 * is not initialized yet. 139 */ 140 mv s0, a0 141 142 143 /* Configure proprietary settings and customized CSRs of harts */ 144call_harts_early_init: 145 jal harts_early_init 146 147#if !CONFIG_IS_ENABLED(XIP) 148 /* 149 * Pick hart to initialize global data and run U-Boot. The other harts 150 * wait for initialization to complete. 151 */ 152 la t0, hart_lottery 153 li t1, 1 154 amoswap.w s2, t1, 0(t0) 155 bnez s2, wait_for_gd_init 156#else 157 /* 158 * FIXME: gp is set before it is initialized. If an XIP U-Boot ever 159 * encounters a pending IPI on boot it is liable to jump to whatever 160 * memory happens to be in ipi_data.addr on boot. It may also run into 161 * problems if it encounters an exception too early (because printf/puts 162 * accesses gd). 163 */ 164 mv gp, s0 165#if CONFIG_IS_ENABLED(RISCV_MMODE) 166 bnez tp, secondary_hart_loop 167#endif 168#endif 169 170 mv a0, s0 171 jal board_init_f_init_reserve 172 173 SREG s1, GD_FIRMWARE_FDT_ADDR(gp) 174 /* save the boot hart id to global_data */ 175 SREG tp, GD_BOOT_HART(gp) 176 177#if !CONFIG_IS_ENABLED(XIP) 178#ifdef CONFIG_AVAILABLE_HARTS 179 la t0, available_harts_lock 180 amoswap.w.rl zero, zero, 0(t0) 181#endif 182 183wait_for_gd_init: 184 /* 185 * Set the global data pointer only when gd_t has been initialized. 186 * This was already set by arch_setup_gd on the boot hart, but all other 187 * harts' global data pointers gets set here. 188 */ 189 mv gp, s0 190#ifdef CONFIG_AVAILABLE_HARTS 191 la t0, available_harts_lock 192 li t1, 1 1931: amoswap.w.aq t1, t1, 0(t0) 194 bnez t1, 1b 195 196 /* register available harts in the available_harts mask */ 197 li t1, 1 198 sll t1, t1, tp 199 LREG t2, GD_AVAILABLE_HARTS(gp) 200 or t2, t2, t1 201 SREG t2, GD_AVAILABLE_HARTS(gp) 202 203 amoswap.w.rl zero, zero, 0(t0) 204#endif 205 206 /* 207 * Continue on hart lottery winner, others branch to 208 * secondary_hart_loop. 209 */ 210 bnez s2, secondary_hart_loop 211#endif 212 213#ifdef CONFIG_DEBUG_UART 214 jal debug_uart_init 215#endif 216 217 mv a0, zero /* a0 <-- boot_flags = 0 */ 218 la t5, board_init_f 219 jalr t5 /* jump to board_init_f() */ 220 221#ifdef CONFIG_XPL_BUILD 222spl_clear_bss: 223 la t0, __bss_start 224 la t1, __bss_end 225 beq t0, t1, spl_stack_gd_setup 226 227spl_clear_bss_loop: 228 SREG zero, 0(t0) 229 addi t0, t0, REGBYTES 230 blt t0, t1, spl_clear_bss_loop 231 232spl_stack_gd_setup: 233 jal spl_relocate_stack_gd 234 235 /* skip setup if we did not relocate */ 236 beqz a0, spl_call_board_init_r 237 mv s0, a0 238 239 /* setup stack on main hart */ 240#if CONFIG_IS_ENABLED(SMP) 241 /* tp: hart id */ 242 slli t0, tp, CONFIG_STACK_SIZE_SHIFT 243 sub sp, s0, t0 244#else 245 mv sp, s0 246#endif 247 248#if CONFIG_IS_ENABLED(SMP) 249 /* set new stack and global data pointer on secondary harts */ 250spl_secondary_hart_stack_gd_setup: 251 la a0, secondary_hart_relocate 252 mv a1, s0 253 mv a2, s0 254 mv a3, zero 255 jal smp_call_function 256 257 /* hang if relocation of secondary harts has failed */ 258 beqz a0, 1f 259 mv a1, a0 260 la a0, secondary_harts_relocation_error 261 jal printf 262 jal hang 263#endif 264 265 /* set new global data pointer on main hart */ 2661: mv gp, s0 267 268spl_call_board_init_r: 269 mv a0, zero 270 mv a1, zero 271 j board_init_r 272#endif 273 274#if !defined(CONFIG_XPL_BUILD) 275/* 276 * void relocate_code(addr_sp, gd, addr_moni) 277 * 278 * This "function" does not return, instead it continues in RAM 279 * after relocating the monitor code. 280 * 281 */ 282.globl relocate_code 283relocate_code: 284 mv s2, a0 /* save addr_sp */ 285 mv s3, a1 /* save addr of gd */ 286 mv s4, a2 /* save addr of destination */ 287 288/* 289 *Set up the stack 290 */ 291stack_setup: 292#if CONFIG_IS_ENABLED(SMP) 293 /* tp: hart id */ 294 slli t0, tp, CONFIG_STACK_SIZE_SHIFT 295 sub sp, s2, t0 296#else 297 mv sp, s2 298#endif 299 300 la t0, _start 301 sub t6, s4, t0 /* t6 <- relocation offset */ 302 beq t0, s4, clear_bss /* skip relocation */ 303 304 mv t1, s4 /* t1 <- scratch for copy_loop */ 305 la t2, __bss_start /* t2 <- source end address */ 306 307copy_loop: 308 LREG t5, 0(t0) 309 addi t0, t0, REGBYTES 310 SREG t5, 0(t1) 311 addi t1, t1, REGBYTES 312 blt t0, t2, copy_loop 313 314/* 315 * Update dynamic relocations after board_init_f 316 */ 317fix_rela_dyn: 318 la t1, __rel_dyn_start 319 la t2, __rel_dyn_end 320 beq t1, t2, clear_bss 321 add t1, t1, t6 /* t1 <- rela_dyn_start in RAM */ 322 add t2, t2, t6 /* t2 <- rela_dyn_end in RAM */ 323 3246: 325 LREG t5, REGBYTES(t1) /* t5 <-- relocation info:type */ 326 li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */ 327 bne t5, t3, 8f /* skip non-RISCV_RELOC entries */ 328 LREG t3, 0(t1) 329 LREG t5, (REGBYTES * 2)(t1) /* t5 <-- addend */ 330 add t5, t5, t6 /* t5 <-- location to fix up in RAM */ 331 add t3, t3, t6 /* t3 <-- location to fix up in RAM */ 332 SREG t5, 0(t3) 333 j 10f 334 3358: 336 la t4, __dyn_sym_start 337 add t4, t4, t6 338 3399: 340 srli t0, t5, SYM_INDEX /* t0 <--- sym table index */ 341 andi t5, t5, 0xFF /* t5 <--- relocation type */ 342 li t3, RELOC_TYPE 343 bne t5, t3, 10f /* skip non-addned entries */ 344 345 LREG t3, 0(t1) 346 li t5, SYM_SIZE 347 mul t0, t0, t5 348 add s5, t4, t0 349 LREG t0, (REGBYTES * 2)(t1) /* t0 <-- addend */ 350 LREG t5, REGBYTES(s5) 351 add t5, t5, t0 352 add t5, t5, t6 /* t5 <-- location to fix up in RAM */ 353 add t3, t3, t6 /* t3 <-- location to fix up in RAM */ 354 SREG t5, 0(t3) 35510: 356 addi t1, t1, (REGBYTES * 3) 357 blt t1, t2, 6b 358 359/* 360 * trap update 361*/ 362 la t0, trap_entry 363 add t0, t0, t6 364 csrw MODE_PREFIX(tvec), t0 365 366clear_bss: 367 la t0, __bss_start /* t0 <- rel __bss_start in FLASH */ 368 add t0, t0, t6 /* t0 <- rel __bss_start in RAM */ 369 la t1, __bss_end /* t1 <- rel __bss_end in FLASH */ 370 add t1, t1, t6 /* t1 <- rel __bss_end in RAM */ 371 beq t0, t1, relocate_secondary_harts 372 373clbss_l: 374 SREG zero, 0(t0) /* clear loop... */ 375 addi t0, t0, REGBYTES 376 blt t0, t1, clbss_l 377 378relocate_secondary_harts: 379#if CONFIG_IS_ENABLED(SMP) 380 /* send relocation IPI */ 381 la t0, secondary_hart_relocate 382 add a0, t0, t6 383 384 /* store relocation offset */ 385 mv s5, t6 386 387 mv a1, s2 388 mv a2, s3 389 mv a3, zero 390 jal smp_call_function 391 392 /* hang if relocation of secondary harts has failed */ 393 beqz a0, 1f 394 mv a1, a0 395 la a0, secondary_harts_relocation_error 396 jal printf 397 jal hang 398 399 /* restore relocation offset */ 4001: mv t6, s5 401#endif 402 403/* 404 * We are done. Do not return, instead branch to second part of board 405 * initialization, now running from RAM. 406 */ 407call_board_init_r: 408 jal invalidate_icache_all 409 jal flush_dcache_all 410 la t0, board_init_r /* offset of board_init_r() */ 411 add t4, t0, t6 /* real address of board_init_r() */ 412/* 413 * setup parameters for board_init_r 414 */ 415 mv a0, s3 /* gd_t */ 416 mv a1, s4 /* dest_addr */ 417 mv s0, zero /* fp == NULL */ 418 419/* 420 * jump to it ... 421 */ 422 jr t4 /* jump to board_init_r() */ 423#endif /* !defined(CONFIG_XPL_BUILD) */ 424 425#if CONFIG_IS_ENABLED(SMP) 426hart_out_of_bounds_loop: 427 /* Harts in this loop are out of bounds, increase CONFIG_NR_CPUS. */ 428 wfi 429 j hart_out_of_bounds_loop 430 431/* SMP relocation entry */ 432secondary_hart_relocate: 433 /* a1: new sp */ 434 /* a2: new gd */ 435 /* tp: hart id */ 436 437 /* setup stack */ 438 slli t0, tp, CONFIG_STACK_SIZE_SHIFT 439 sub sp, a1, t0 440 441 /* update global data pointer */ 442 mv gp, a2 443#endif 444 445/* 446 * Interrupts are disabled globally, but they can still be read from m/sip. The 447 * wfi function will wake us up if we get an IPI, even if we do not trap. 448 */ 449secondary_hart_loop: 450 wfi 451 452#if CONFIG_IS_ENABLED(SMP) 453 csrr t0, MODE_PREFIX(ip) 454#if CONFIG_IS_ENABLED(RISCV_MMODE) 455 andi t0, t0, MIE_MSIE 456#else 457 andi t0, t0, SIE_SSIE 458#endif 459 beqz t0, secondary_hart_loop 460 461 mv a0, tp 462 jal handle_ipi 463#endif 464 465 j secondary_hart_loop 466