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