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 <common.h> 15#include <elf.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 li t0, -16 94#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) 95 li t1, CONFIG_SPL_STACK 96#else 97 li t1, CONFIG_SYS_INIT_SP_ADDR 98#endif 99 and sp, t1, t0 /* force 16 byte alignment */ 100 101call_board_init_f_0: 102 mv a0, sp 103 jal board_init_f_alloc_reserve 104 105 /* 106 * Save global data pointer for later. We don't set it here because it 107 * is not initialized yet. 108 */ 109 mv s0, a0 110 111 /* setup stack */ 112#if CONFIG_IS_ENABLED(SMP) 113 /* tp: hart id */ 114 slli t0, tp, CONFIG_STACK_SIZE_SHIFT 115 sub sp, a0, t0 116#else 117 mv sp, a0 118#endif 119 120#ifndef CONFIG_XIP 121 /* 122 * Pick hart to initialize global data and run U-Boot. The other harts 123 * wait for initialization to complete. 124 */ 125 la t0, hart_lottery 126 li t1, 1 127 amoswap.w s2, t1, 0(t0) 128 bnez s2, wait_for_gd_init 129#else 130 /* 131 * FIXME: gp is set before it is initialized. If an XIP U-Boot ever 132 * encounters a pending IPI on boot it is liable to jump to whatever 133 * memory happens to be in ipi_data.addr on boot. It may also run into 134 * problems if it encounters an exception too early (because printf/puts 135 * accesses gd). 136 */ 137 mv gp, s0 138 bnez tp, secondary_hart_loop 139#endif 140 141#ifdef CONFIG_OF_PRIOR_STAGE 142 la t0, prior_stage_fdt_address 143 SREG s1, 0(t0) 144#endif 145 146 jal board_init_f_init_reserve 147 148 SREG s1, GD_FIRMWARE_FDT_ADDR(gp) 149 /* save the boot hart id to global_data */ 150 SREG tp, GD_BOOT_HART(gp) 151 152#ifndef CONFIG_XIP 153 la t0, available_harts_lock 154 amoswap.w.rl zero, zero, 0(t0) 155 156wait_for_gd_init: 157 la t0, available_harts_lock 158 li t1, 1 1591: amoswap.w.aq t1, t1, 0(t0) 160 bnez t1, 1b 161 162 /* 163 * Set the global data pointer only when gd_t has been initialized. 164 * This was already set by arch_setup_gd on the boot hart, but all other 165 * harts' global data pointers gets set here. 166 */ 167 mv gp, s0 168 169 /* register available harts in the available_harts mask */ 170 li t1, 1 171 sll t1, t1, tp 172 LREG t2, GD_AVAILABLE_HARTS(gp) 173 or t2, t2, t1 174 SREG t2, GD_AVAILABLE_HARTS(gp) 175 176 amoswap.w.rl zero, zero, 0(t0) 177 178 /* 179 * Continue on hart lottery winner, others branch to 180 * secondary_hart_loop. 181 */ 182 bnez s2, secondary_hart_loop 183#endif 184 185 /* Enable cache */ 186 jal icache_enable 187 jal dcache_enable 188 189#ifdef CONFIG_DEBUG_UART 190 jal debug_uart_init 191#endif 192 193 mv a0, zero /* a0 <-- boot_flags = 0 */ 194 la t5, board_init_f 195 jalr t5 /* jump to board_init_f() */ 196 197#ifdef CONFIG_SPL_BUILD 198spl_clear_bss: 199 la t0, __bss_start 200 la t1, __bss_end 201 beq t0, t1, spl_stack_gd_setup 202 203spl_clear_bss_loop: 204 SREG zero, 0(t0) 205 addi t0, t0, REGBYTES 206 blt t0, t1, spl_clear_bss_loop 207 208spl_stack_gd_setup: 209 jal spl_relocate_stack_gd 210 211 /* skip setup if we did not relocate */ 212 beqz a0, spl_call_board_init_r 213 mv s0, a0 214 215 /* setup stack on main hart */ 216#if CONFIG_IS_ENABLED(SMP) 217 /* tp: hart id */ 218 slli t0, tp, CONFIG_STACK_SIZE_SHIFT 219 sub sp, s0, t0 220#else 221 mv sp, s0 222#endif 223 224#if CONFIG_IS_ENABLED(SMP) 225 /* set new stack and global data pointer on secondary harts */ 226spl_secondary_hart_stack_gd_setup: 227 la a0, secondary_hart_relocate 228 mv a1, s0 229 mv a2, s0 230 mv a3, zero 231 jal smp_call_function 232 233 /* hang if relocation of secondary harts has failed */ 234 beqz a0, 1f 235 mv a1, a0 236 la a0, secondary_harts_relocation_error 237 jal printf 238 jal hang 239#endif 240 241 /* set new global data pointer on main hart */ 2421: mv gp, s0 243 244spl_call_board_init_r: 245 mv a0, zero 246 mv a1, zero 247 jal board_init_r 248#endif 249 250/* 251 * void relocate_code(addr_sp, gd, addr_moni) 252 * 253 * This "function" does not return, instead it continues in RAM 254 * after relocating the monitor code. 255 * 256 */ 257.globl relocate_code 258relocate_code: 259 mv s2, a0 /* save addr_sp */ 260 mv s3, a1 /* save addr of gd */ 261 mv s4, a2 /* save addr of destination */ 262 263/* 264 *Set up the stack 265 */ 266stack_setup: 267#if CONFIG_IS_ENABLED(SMP) 268 /* tp: hart id */ 269 slli t0, tp, CONFIG_STACK_SIZE_SHIFT 270 sub sp, s2, t0 271#else 272 mv sp, s2 273#endif 274 275 la t0, _start 276 sub t6, s4, t0 /* t6 <- relocation offset */ 277 beq t0, s4, clear_bss /* skip relocation */ 278 279 mv t1, s4 /* t1 <- scratch for copy_loop */ 280 la t3, __bss_start 281 sub t3, t3, t0 /* t3 <- __bss_start_ofs */ 282 add t2, t0, t3 /* t2 <- source end address */ 283 284copy_loop: 285 LREG t5, 0(t0) 286 addi t0, t0, REGBYTES 287 SREG t5, 0(t1) 288 addi t1, t1, REGBYTES 289 blt t0, t2, copy_loop 290 291/* 292 * Update dynamic relocations after board_init_f 293 */ 294fix_rela_dyn: 295 la t1, __rel_dyn_start 296 la t2, __rel_dyn_end 297 beq t1, t2, clear_bss 298 add t1, t1, t6 /* t1 <- rela_dyn_start in RAM */ 299 add t2, t2, t6 /* t2 <- rela_dyn_end in RAM */ 300 301/* 302 * skip first reserved entry: address, type, addend 303 */ 304 j 10f 305 3066: 307 LREG t5, -(REGBYTES*2)(t1) /* t5 <-- relocation info:type */ 308 li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */ 309 bne t5, t3, 8f /* skip non-RISCV_RELOC entries */ 310 LREG t3, -(REGBYTES*3)(t1) 311 LREG t5, -(REGBYTES)(t1) /* t5 <-- addend */ 312 add t5, t5, t6 /* t5 <-- location to fix up in RAM */ 313 add t3, t3, t6 /* t3 <-- location to fix up in RAM */ 314 SREG t5, 0(t3) 315 j 10f 316 3178: 318 la t4, __dyn_sym_start 319 add t4, t4, t6 320 3219: 322 LREG t5, -(REGBYTES*2)(t1) /* t5 <-- relocation info:type */ 323 srli t0, t5, SYM_INDEX /* t0 <--- sym table index */ 324 andi t5, t5, 0xFF /* t5 <--- relocation type */ 325 li t3, RELOC_TYPE 326 bne t5, t3, 10f /* skip non-addned entries */ 327 328 LREG t3, -(REGBYTES*3)(t1) 329 li t5, SYM_SIZE 330 mul t0, t0, t5 331 add s5, t4, t0 332 LREG t0, -(REGBYTES)(t1) /* t0 <-- addend */ 333 LREG t5, REGBYTES(s5) 334 add t5, t5, t0 335 add t5, t5, t6 /* t5 <-- location to fix up in RAM */ 336 add t3, t3, t6 /* t3 <-- location to fix up in RAM */ 337 SREG t5, 0(t3) 33810: 339 addi t1, t1, (REGBYTES*3) 340 ble t1, t2, 6b 341 342/* 343 * trap update 344*/ 345 la t0, trap_entry 346 add t0, t0, t6 347 csrw MODE_PREFIX(tvec), t0 348 349clear_bss: 350 la t0, __bss_start /* t0 <- rel __bss_start in FLASH */ 351 add t0, t0, t6 /* t0 <- rel __bss_start in RAM */ 352 la t1, __bss_end /* t1 <- rel __bss_end in FLASH */ 353 add t1, t1, t6 /* t1 <- rel __bss_end in RAM */ 354 beq t0, t1, relocate_secondary_harts 355 356clbss_l: 357 SREG zero, 0(t0) /* clear loop... */ 358 addi t0, t0, REGBYTES 359 blt t0, t1, clbss_l 360 361relocate_secondary_harts: 362#if CONFIG_IS_ENABLED(SMP) 363 /* send relocation IPI */ 364 la t0, secondary_hart_relocate 365 add a0, t0, t6 366 367 /* store relocation offset */ 368 mv s5, t6 369 370 mv a1, s2 371 mv a2, s3 372 mv a3, zero 373 jal smp_call_function 374 375 /* hang if relocation of secondary harts has failed */ 376 beqz a0, 1f 377 mv a1, a0 378 la a0, secondary_harts_relocation_error 379 jal printf 380 jal hang 381 382 /* restore relocation offset */ 3831: mv t6, s5 384#endif 385 386/* 387 * We are done. Do not return, instead branch to second part of board 388 * initialization, now running from RAM. 389 */ 390call_board_init_r: 391 jal invalidate_icache_all 392 jal flush_dcache_all 393 la t0, board_init_r /* offset of board_init_r() */ 394 add t4, t0, t6 /* real address of board_init_r() */ 395/* 396 * setup parameters for board_init_r 397 */ 398 mv a0, s3 /* gd_t */ 399 mv a1, s4 /* dest_addr */ 400 401/* 402 * jump to it ... 403 */ 404 jr t4 /* jump to board_init_r() */ 405 406#if CONFIG_IS_ENABLED(SMP) 407hart_out_of_bounds_loop: 408 /* Harts in this loop are out of bounds, increase CONFIG_NR_CPUS. */ 409 wfi 410 j hart_out_of_bounds_loop 411 412/* SMP relocation entry */ 413secondary_hart_relocate: 414 /* a1: new sp */ 415 /* a2: new gd */ 416 /* tp: hart id */ 417 418 /* setup stack */ 419 slli t0, tp, CONFIG_STACK_SIZE_SHIFT 420 sub sp, a1, t0 421 422 /* update global data pointer */ 423 mv gp, a2 424#endif 425 426/* 427 * Interrupts are disabled globally, but they can still be read from m/sip. The 428 * wfi function will wake us up if we get an IPI, even if we do not trap. 429 */ 430secondary_hart_loop: 431 wfi 432 433#if CONFIG_IS_ENABLED(SMP) 434 csrr t0, MODE_PREFIX(ip) 435#if CONFIG_IS_ENABLED(RISCV_MMODE) 436 andi t0, t0, MIE_MSIE 437#else 438 andi t0, t0, SIE_SSIE 439#endif 440 beqz t0, secondary_hart_loop 441 442 mv a0, tp 443 jal handle_ipi 444#endif 445 446 j secondary_hart_loop 447