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