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 /* save hart id and dtb pointer */ 47 mv tp, a0 48 mv s1, a1 49 50 la t0, trap_entry 51 csrw MODE_PREFIX(tvec), t0 52 53 /* mask all interrupts */ 54 csrw MODE_PREFIX(ie), zero 55 56#ifdef CONFIG_SMP 57 /* check if hart is within range */ 58 /* tp: hart id */ 59 li t0, CONFIG_NR_CPUS 60 bge tp, t0, hart_out_of_bounds_loop 61#endif 62 63#ifdef CONFIG_SMP 64 /* set xSIE bit to receive IPIs */ 65#if CONFIG_IS_ENABLED(RISCV_MMODE) 66 li t0, MIE_MSIE 67#else 68 li t0, SIE_SSIE 69#endif 70 csrs MODE_PREFIX(ie), t0 71#endif 72 73/* 74 * Set stackpointer in internal/ex RAM to call board_init_f 75 */ 76call_board_init_f: 77 li t0, -16 78#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) 79 li t1, CONFIG_SPL_STACK 80#else 81 li t1, CONFIG_SYS_INIT_SP_ADDR 82#endif 83 and sp, t1, t0 /* force 16 byte alignment */ 84 85call_board_init_f_0: 86 mv a0, sp 87 jal board_init_f_alloc_reserve 88 89 /* 90 * Set global data pointer here for all harts, uninitialized at this 91 * point. 92 */ 93 mv gp, a0 94 95 /* setup stack */ 96#ifdef CONFIG_SMP 97 /* tp: hart id */ 98 slli t0, tp, CONFIG_STACK_SIZE_SHIFT 99 sub sp, a0, t0 100#else 101 mv sp, a0 102#endif 103 104#ifndef CONFIG_XIP 105 /* 106 * Pick hart to initialize global data and run U-Boot. The other harts 107 * wait for initialization to complete. 108 */ 109 la t0, hart_lottery 110 li s2, 1 111 amoswap.w s2, t1, 0(t0) 112 bnez s2, wait_for_gd_init 113#else 114 bnez tp, secondary_hart_loop 115#endif 116 117#ifdef CONFIG_OF_PRIOR_STAGE 118 la t0, prior_stage_fdt_address 119 SREG s1, 0(t0) 120#endif 121 122 jal board_init_f_init_reserve 123 124 /* save the boot hart id to global_data */ 125 SREG tp, GD_BOOT_HART(gp) 126 127#ifndef CONFIG_XIP 128 la t0, available_harts_lock 129 fence rw, w 130 amoswap.w zero, zero, 0(t0) 131 132wait_for_gd_init: 133 la t0, available_harts_lock 134 li t1, 1 1351: amoswap.w t1, t1, 0(t0) 136 fence r, rw 137 bnez t1, 1b 138 139 /* register available harts in the available_harts mask */ 140 li t1, 1 141 sll t1, t1, tp 142 LREG t2, GD_AVAILABLE_HARTS(gp) 143 or t2, t2, t1 144 SREG t2, GD_AVAILABLE_HARTS(gp) 145 146 fence rw, w 147 amoswap.w zero, zero, 0(t0) 148 149 /* 150 * Continue on hart lottery winner, others branch to 151 * secondary_hart_loop. 152 */ 153 bnez s2, secondary_hart_loop 154#endif 155 156 /* Enable cache */ 157 jal icache_enable 158 jal dcache_enable 159 160#ifdef CONFIG_DEBUG_UART 161 jal debug_uart_init 162#endif 163 164 mv a0, zero /* a0 <-- boot_flags = 0 */ 165 la t5, board_init_f 166 jalr t5 /* jump to board_init_f() */ 167 168#ifdef CONFIG_SPL_BUILD 169spl_clear_bss: 170 la t0, __bss_start 171 la t1, __bss_end 172 beq t0, t1, spl_stack_gd_setup 173 174spl_clear_bss_loop: 175 SREG zero, 0(t0) 176 addi t0, t0, REGBYTES 177 blt t0, t1, spl_clear_bss_loop 178 179spl_stack_gd_setup: 180 jal spl_relocate_stack_gd 181 182 /* skip setup if we did not relocate */ 183 beqz a0, spl_call_board_init_r 184 mv s0, a0 185 186 /* setup stack on main hart */ 187#ifdef CONFIG_SMP 188 /* tp: hart id */ 189 slli t0, tp, CONFIG_STACK_SIZE_SHIFT 190 sub sp, s0, t0 191#else 192 mv sp, s0 193#endif 194 195 /* set new stack and global data pointer on secondary harts */ 196spl_secondary_hart_stack_gd_setup: 197 la a0, secondary_hart_relocate 198 mv a1, s0 199 mv a2, s0 200 mv a3, zero 201 jal smp_call_function 202 203 /* hang if relocation of secondary harts has failed */ 204 beqz a0, 1f 205 mv a1, a0 206 la a0, secondary_harts_relocation_error 207 jal printf 208 jal hang 209 210 /* set new global data pointer on main hart */ 2111: mv gp, s0 212 213spl_call_board_init_r: 214 mv a0, zero 215 mv a1, zero 216 jal board_init_r 217#endif 218 219/* 220 * void relocate_code (addr_sp, gd, addr_moni) 221 * 222 * This "function" does not return, instead it continues in RAM 223 * after relocating the monitor code. 224 * 225 */ 226.globl relocate_code 227relocate_code: 228 mv s2, a0 /* save addr_sp */ 229 mv s3, a1 /* save addr of gd */ 230 mv s4, a2 /* save addr of destination */ 231 232/* 233 *Set up the stack 234 */ 235stack_setup: 236#ifdef CONFIG_SMP 237 /* tp: hart id */ 238 slli t0, tp, CONFIG_STACK_SIZE_SHIFT 239 sub sp, s2, t0 240#else 241 mv sp, s2 242#endif 243 244 la t0, _start 245 sub t6, s4, t0 /* t6 <- relocation offset */ 246 beq t0, s4, clear_bss /* skip relocation */ 247 248 mv t1, s4 /* t1 <- scratch for copy_loop */ 249 la t3, __bss_start 250 sub t3, t3, t0 /* t3 <- __bss_start_ofs */ 251 add t2, t0, t3 /* t2 <- source end address */ 252 253copy_loop: 254 LREG t5, 0(t0) 255 addi t0, t0, REGBYTES 256 SREG t5, 0(t1) 257 addi t1, t1, REGBYTES 258 blt t0, t2, copy_loop 259 260/* 261 * Update dynamic relocations after board_init_f 262 */ 263fix_rela_dyn: 264 la t1, __rel_dyn_start 265 la t2, __rel_dyn_end 266 beq t1, t2, clear_bss 267 add t1, t1, t6 /* t1 <- rela_dyn_start in RAM */ 268 add t2, t2, t6 /* t2 <- rela_dyn_end in RAM */ 269 270/* 271 * skip first reserved entry: address, type, addend 272 */ 273 j 10f 274 2756: 276 LREG t5, -(REGBYTES*2)(t1) /* t5 <-- relocation info:type */ 277 li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */ 278 bne t5, t3, 8f /* skip non-RISCV_RELOC entries */ 279 LREG t3, -(REGBYTES*3)(t1) 280 LREG t5, -(REGBYTES)(t1) /* t5 <-- addend */ 281 add t5, t5, t6 /* t5 <-- location to fix up in RAM */ 282 add t3, t3, t6 /* t3 <-- location to fix up in RAM */ 283 SREG t5, 0(t3) 284 j 10f 285 2868: 287 la t4, __dyn_sym_start 288 add t4, t4, t6 289 2909: 291 LREG t5, -(REGBYTES*2)(t1) /* t5 <-- relocation info:type */ 292 srli t0, t5, SYM_INDEX /* t0 <--- sym table index */ 293 andi t5, t5, 0xFF /* t5 <--- relocation type */ 294 li t3, RELOC_TYPE 295 bne t5, t3, 10f /* skip non-addned entries */ 296 297 LREG t3, -(REGBYTES*3)(t1) 298 li t5, SYM_SIZE 299 mul t0, t0, t5 300 add s5, t4, t0 301 LREG t0, -(REGBYTES)(t1) /* t0 <-- addend */ 302 LREG t5, REGBYTES(s5) 303 add t5, t5, t0 304 add t5, t5, t6 /* t5 <-- location to fix up in RAM */ 305 add t3, t3, t6 /* t3 <-- location to fix up in RAM */ 306 SREG t5, 0(t3) 30710: 308 addi t1, t1, (REGBYTES*3) 309 ble t1, t2, 6b 310 311/* 312 * trap update 313*/ 314 la t0, trap_entry 315 add t0, t0, t6 316 csrw MODE_PREFIX(tvec), t0 317 318clear_bss: 319 la t0, __bss_start /* t0 <- rel __bss_start in FLASH */ 320 add t0, t0, t6 /* t0 <- rel __bss_start in RAM */ 321 la t1, __bss_end /* t1 <- rel __bss_end in FLASH */ 322 add t1, t1, t6 /* t1 <- rel __bss_end in RAM */ 323 beq t0, t1, relocate_secondary_harts 324 325clbss_l: 326 SREG zero, 0(t0) /* clear loop... */ 327 addi t0, t0, REGBYTES 328 blt t0, t1, clbss_l 329 330relocate_secondary_harts: 331#ifdef CONFIG_SMP 332 /* send relocation IPI */ 333 la t0, secondary_hart_relocate 334 add a0, t0, t6 335 336 /* store relocation offset */ 337 mv s5, t6 338 339 mv a1, s2 340 mv a2, s3 341 mv a3, zero 342 jal smp_call_function 343 344 /* hang if relocation of secondary harts has failed */ 345 beqz a0, 1f 346 mv a1, a0 347 la a0, secondary_harts_relocation_error 348 jal printf 349 jal hang 350 351 /* restore relocation offset */ 3521: mv t6, s5 353#endif 354 355/* 356 * We are done. Do not return, instead branch to second part of board 357 * initialization, now running from RAM. 358 */ 359call_board_init_r: 360 jal invalidate_icache_all 361 jal flush_dcache_all 362 la t0, board_init_r 363 mv t4, t0 /* offset of board_init_r() */ 364 add t4, t4, t6 /* real address of board_init_r() */ 365/* 366 * setup parameters for board_init_r 367 */ 368 mv a0, s3 /* gd_t */ 369 mv a1, s4 /* dest_addr */ 370 371/* 372 * jump to it ... 373 */ 374 jr t4 /* jump to board_init_r() */ 375 376#ifdef CONFIG_SMP 377hart_out_of_bounds_loop: 378 /* Harts in this loop are out of bounds, increase CONFIG_NR_CPUS. */ 379 wfi 380 j hart_out_of_bounds_loop 381#endif 382 383#ifdef CONFIG_SMP 384/* SMP relocation entry */ 385secondary_hart_relocate: 386 /* a1: new sp */ 387 /* a2: new gd */ 388 /* tp: hart id */ 389 390 /* setup stack */ 391 slli t0, tp, CONFIG_STACK_SIZE_SHIFT 392 sub sp, a1, t0 393 394 /* update global data pointer */ 395 mv gp, a2 396#endif 397 398secondary_hart_loop: 399 wfi 400 401#ifdef CONFIG_SMP 402 csrr t0, MODE_PREFIX(ip) 403#if CONFIG_IS_ENABLED(RISCV_MMODE) 404 andi t0, t0, MIE_MSIE 405#else 406 andi t0, t0, SIE_SSIE 407#endif 408 beqz t0, secondary_hart_loop 409 410 mv a0, tp 411 jal handle_ipi 412#endif 413 414 j secondary_hart_loop 415