Merge tag 'efi-2019-10-rc3' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi
[oweals/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 <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
36 secondary_harts_relocation_error:
37         .ascii "Relocation of secondary harts has failed, error %d\n"
38
39 .section .text
40 .globl _start
41 _start:
42 #ifdef CONFIG_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 #ifdef CONFIG_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  */
76 call_board_init_f:
77         li      t0, -16
78         li      t1, CONFIG_SYS_INIT_SP_ADDR
79         and     sp, t1, t0              /* force 16 byte alignment */
80
81 call_board_init_f_0:
82         mv      a0, sp
83         jal     board_init_f_alloc_reserve
84
85         /*
86          * Set global data pointer here for all harts, uninitialized at this
87          * point.
88          */
89         mv      gp, a0
90
91         /* setup stack */
92 #ifdef CONFIG_SMP
93         /* tp: hart id */
94         slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
95         sub     sp, a0, t0
96 #else
97         mv      sp, a0
98 #endif
99
100 #ifndef CONFIG_XIP
101         /*
102          * Pick hart to initialize global data and run U-Boot. The other harts
103          * wait for initialization to complete.
104          */
105         la      t0, hart_lottery
106         li      s2, 1
107         amoswap.w s2, t1, 0(t0)
108         bnez    s2, wait_for_gd_init
109 #else
110         bnez    tp, secondary_hart_loop
111 #endif
112
113 #ifdef CONFIG_OF_PRIOR_STAGE
114         la      t0, prior_stage_fdt_address
115         SREG    s1, 0(t0)
116 #endif
117
118         jal     board_init_f_init_reserve
119
120         /* save the boot hart id to global_data */
121         SREG    tp, GD_BOOT_HART(gp)
122
123 #ifndef CONFIG_XIP
124         la      t0, available_harts_lock
125         fence   rw, w
126         amoswap.w zero, zero, 0(t0)
127
128 wait_for_gd_init:
129         la      t0, available_harts_lock
130         li      t1, 1
131 1:      amoswap.w t1, t1, 0(t0)
132         fence   r, rw
133         bnez    t1, 1b
134
135         /* register available harts in the available_harts mask */
136         li      t1, 1
137         sll     t1, t1, tp
138         LREG    t2, GD_AVAILABLE_HARTS(gp)
139         or      t2, t2, t1
140         SREG    t2, GD_AVAILABLE_HARTS(gp)
141
142         fence   rw, w
143         amoswap.w zero, zero, 0(t0)
144
145         /*
146          * Continue on hart lottery winner, others branch to
147          * secondary_hart_loop.
148          */
149         bnez    s2, secondary_hart_loop
150 #endif
151
152         /* Enable cache */
153         jal     icache_enable
154         jal     dcache_enable
155
156 #ifdef CONFIG_DEBUG_UART
157         jal     debug_uart_init
158 #endif
159
160         mv      a0, zero                /* a0 <-- boot_flags = 0 */
161         la      t5, board_init_f
162         jr      t5                      /* jump to board_init_f() */
163
164 /*
165  * void relocate_code (addr_sp, gd, addr_moni)
166  *
167  * This "function" does not return, instead it continues in RAM
168  * after relocating the monitor code.
169  *
170  */
171 .globl relocate_code
172 relocate_code:
173         mv      s2, a0                  /* save addr_sp */
174         mv      s3, a1                  /* save addr of gd */
175         mv      s4, a2                  /* save addr of destination */
176
177 /*
178  *Set up the stack
179  */
180 stack_setup:
181 #ifdef CONFIG_SMP
182         /* tp: hart id */
183         slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
184         sub     sp, s2, t0
185 #else
186         mv      sp, s2
187 #endif
188
189         la      t0, _start
190         sub     t6, s4, t0              /* t6 <- relocation offset */
191         beq     t0, s4, clear_bss       /* skip relocation */
192
193         mv      t1, s4                  /* t1 <- scratch for copy_loop */
194         la      t3, __bss_start
195         sub     t3, t3, t0              /* t3 <- __bss_start_ofs */
196         add     t2, t0, t3              /* t2 <- source end address */
197
198 copy_loop:
199         LREG    t5, 0(t0)
200         addi    t0, t0, REGBYTES
201         SREG    t5, 0(t1)
202         addi    t1, t1, REGBYTES
203         blt     t0, t2, copy_loop
204
205 /*
206  * Update dynamic relocations after board_init_f
207  */
208 fix_rela_dyn:
209         la      t1, __rel_dyn_start
210         la      t2, __rel_dyn_end
211         beq     t1, t2, clear_bss
212         add     t1, t1, t6              /* t1 <- rela_dyn_start in RAM */
213         add     t2, t2, t6              /* t2 <- rela_dyn_end in RAM */
214
215 /*
216  * skip first reserved entry: address, type, addend
217  */
218         bne     t1, t2, 7f
219
220 6:
221         LREG    t5, -(REGBYTES*2)(t1)   /* t5 <-- relocation info:type */
222         li      t3, R_RISCV_RELATIVE    /* reloc type R_RISCV_RELATIVE */
223         bne     t5, t3, 8f              /* skip non-RISCV_RELOC entries */
224         LREG    t3, -(REGBYTES*3)(t1)
225         LREG    t5, -(REGBYTES)(t1)     /* t5 <-- addend */
226         add     t5, t5, t6              /* t5 <-- location to fix up in RAM */
227         add     t3, t3, t6              /* t3 <-- location to fix up in RAM */
228         SREG    t5, 0(t3)
229 7:
230         addi    t1, t1, (REGBYTES*3)
231         ble     t1, t2, 6b
232
233 8:
234         la      t4, __dyn_sym_start
235         add     t4, t4, t6
236
237 9:
238         LREG    t5, -(REGBYTES*2)(t1)   /* t5 <-- relocation info:type */
239         srli    t0, t5, SYM_INDEX       /* t0 <--- sym table index */
240         andi    t5, t5, 0xFF            /* t5 <--- relocation type */
241         li      t3, RELOC_TYPE
242         bne     t5, t3, 10f             /* skip non-addned entries */
243
244         LREG    t3, -(REGBYTES*3)(t1)
245         li      t5, SYM_SIZE
246         mul     t0, t0, t5
247         add     s5, t4, t0
248         LREG    t5, REGBYTES(s5)
249         add     t5, t5, t6              /* t5 <-- location to fix up in RAM */
250         add     t3, t3, t6              /* t3 <-- location to fix up in RAM */
251         SREG    t5, 0(t3)
252 10:
253         addi    t1, t1, (REGBYTES*3)
254         ble     t1, t2, 9b
255
256 /*
257  * trap update
258 */
259         la      t0, trap_entry
260         add     t0, t0, t6
261         csrw    MODE_PREFIX(tvec), t0
262
263 clear_bss:
264         la      t0, __bss_start         /* t0 <- rel __bss_start in FLASH */
265         add     t0, t0, t6              /* t0 <- rel __bss_start in RAM */
266         la      t1, __bss_end           /* t1 <- rel __bss_end in FLASH */
267         add     t1, t1, t6              /* t1 <- rel __bss_end in RAM */
268         beq     t0, t1, relocate_secondary_harts
269
270 clbss_l:
271         SREG    zero, 0(t0)             /* clear loop... */
272         addi    t0, t0, REGBYTES
273         bne     t0, t1, clbss_l
274
275 relocate_secondary_harts:
276 #ifdef CONFIG_SMP
277         /* send relocation IPI */
278         la      t0, secondary_hart_relocate
279         add     a0, t0, t6
280
281         /* store relocation offset */
282         mv      s5, t6
283
284         mv      a1, s2
285         mv      a2, s3
286         jal     smp_call_function
287
288         /* hang if relocation of secondary harts has failed */
289         beqz    a0, 1f
290         mv      a1, a0
291         la      a0, secondary_harts_relocation_error
292         jal     printf
293         jal     hang
294
295         /* restore relocation offset */
296 1:      mv      t6, s5
297 #endif
298
299 /*
300  * We are done. Do not return, instead branch to second part of board
301  * initialization, now running from RAM.
302  */
303 call_board_init_r:
304         jal     invalidate_icache_all
305         jal     flush_dcache_all
306         la      t0, board_init_r
307         mv      t4, t0                  /* offset of board_init_r() */
308         add     t4, t4, t6              /* real address of board_init_r() */
309 /*
310  * setup parameters for board_init_r
311  */
312         mv      a0, s3                  /* gd_t */
313         mv      a1, s4                  /* dest_addr */
314
315 /*
316  * jump to it ...
317  */
318         jr      t4                      /* jump to board_init_r() */
319
320 #ifdef CONFIG_SMP
321 hart_out_of_bounds_loop:
322         /* Harts in this loop are out of bounds, increase CONFIG_NR_CPUS. */
323         wfi
324         j       hart_out_of_bounds_loop
325 #endif
326
327 #ifdef CONFIG_SMP
328 /* SMP relocation entry */
329 secondary_hart_relocate:
330         /* a1: new sp */
331         /* a2: new gd */
332         /* tp: hart id */
333
334         /* setup stack */
335         slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
336         sub     sp, a1, t0
337
338         /* update global data pointer */
339         mv      gp, a2
340 #endif
341
342 secondary_hart_loop:
343         wfi
344
345 #ifdef CONFIG_SMP
346         csrr    t0, MODE_PREFIX(ip)
347 #ifdef CONFIG_RISCV_MMODE
348         andi    t0, t0, MIE_MSIE
349 #else
350         andi    t0, t0, SIE_SSIE
351 #endif
352         beqz    t0, secondary_hart_loop
353
354         mv      a0, tp
355         jal     handle_ipi
356 #endif
357
358         j       secondary_hart_loop