xref: /openbmc/u-boot/arch/riscv/cpu/start.S (revision 4c0411eb)
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
18#ifdef CONFIG_32BIT
19#define LREG			lw
20#define SREG			sw
21#define REGBYTES		4
22#define RELOC_TYPE		R_RISCV_32
23#define SYM_INDEX		0x8
24#define SYM_SIZE		0x10
25#else
26#define LREG			ld
27#define SREG			sd
28#define REGBYTES		8
29#define RELOC_TYPE		R_RISCV_64
30#define SYM_INDEX		0x20
31#define SYM_SIZE		0x18
32#endif
33
34.section .text
35.globl _start
36_start:
37	/* save hart id and dtb pointer */
38	mv	s0, a0
39	mv	s1, a1
40
41	la	t0, trap_entry
42	csrw	MODE_PREFIX(tvec), t0
43
44	/* mask all interrupts */
45	csrw	MODE_PREFIX(ie), zero
46
47	/* Enable cache */
48	jal	icache_enable
49	jal	dcache_enable
50
51/*
52 * Set stackpointer in internal/ex RAM to call board_init_f
53 */
54call_board_init_f:
55	li	t0, -16
56	li	t1, CONFIG_SYS_INIT_SP_ADDR
57	and	sp, t1, t0		/* force 16 byte alignment */
58
59#ifdef CONFIG_DEBUG_UART
60	jal	debug_uart_init
61#endif
62
63call_board_init_f_0:
64	mv	a0, sp
65	jal	board_init_f_alloc_reserve
66	mv	sp, a0
67
68	la	t0, prior_stage_fdt_address
69	SREG	s1, 0(t0)
70
71	jal	board_init_f_init_reserve
72
73	mv	a0, zero		/* a0 <-- boot_flags = 0 */
74	la	t5, board_init_f
75	jr	t5			/* jump to board_init_f() */
76
77/*
78 * void relocate_code (addr_sp, gd, addr_moni)
79 *
80 * This "function" does not return, instead it continues in RAM
81 * after relocating the monitor code.
82 *
83 */
84.globl relocate_code
85relocate_code:
86	mv	s2, a0			/* save addr_sp */
87	mv	s3, a1			/* save addr of gd */
88	mv	s4, a2			/* save addr of destination */
89
90/*
91 *Set up the stack
92 */
93stack_setup:
94	mv	sp, s2
95	la	t0, _start
96	sub	t6, s4, t0		/* t6 <- relocation offset */
97	beq	t0, s4, clear_bss	/* skip relocation */
98
99	mv	t1, s4			/* t1 <- scratch for copy_loop */
100	la	t3, __bss_start
101	sub	t3, t3, t0		/* t3 <- __bss_start_ofs */
102	add	t2, t0, t3		/* t2 <- source end address */
103
104copy_loop:
105	LREG	t5, 0(t0)
106	addi	t0, t0, REGBYTES
107	SREG	t5, 0(t1)
108	addi	t1, t1, REGBYTES
109	blt	t0, t2, copy_loop
110
111/*
112 * Update dynamic relocations after board_init_f
113 */
114fix_rela_dyn:
115	la	t1, __rel_dyn_start
116	la	t2, __rel_dyn_end
117	beq	t1, t2, clear_bss
118	add	t1, t1, t6		/* t1 <- rela_dyn_start in RAM */
119	add	t2, t2, t6		/* t2 <- rela_dyn_end in RAM */
120
121/*
122 * skip first reserved entry: address, type, addend
123 */
124	bne	t1, t2, 7f
125
1266:
127	LREG	t5, -(REGBYTES*2)(t1)	/* t5 <-- relocation info:type */
128	li	t3, R_RISCV_RELATIVE	/* reloc type R_RISCV_RELATIVE */
129	bne	t5, t3, 8f		/* skip non-RISCV_RELOC entries */
130	LREG	t3, -(REGBYTES*3)(t1)
131	LREG	t5, -(REGBYTES)(t1)	/* t5 <-- addend */
132	add	t5, t5, t6		/* t5 <-- location to fix up in RAM */
133	add	t3, t3, t6		/* t3 <-- location to fix up in RAM */
134	SREG	t5, 0(t3)
1357:
136	addi	t1, t1, (REGBYTES*3)
137	ble	t1, t2, 6b
138
1398:
140	la	t4, __dyn_sym_start
141	add	t4, t4, t6
142
1439:
144	LREG	t5, -(REGBYTES*2)(t1)	/* t5 <-- relocation info:type */
145	srli	t0, t5, SYM_INDEX	/* t0 <--- sym table index */
146	andi	t5, t5, 0xFF		/* t5 <--- relocation type */
147	li	t3, RELOC_TYPE
148	bne	t5, t3, 10f		/* skip non-addned entries */
149
150	LREG	t3, -(REGBYTES*3)(t1)
151	li	t5, SYM_SIZE
152	mul	t0, t0, t5
153	add	s5, t4, t0
154	LREG	t5, REGBYTES(s5)
155	add	t5, t5, t6		/* t5 <-- location to fix up in RAM */
156	add	t3, t3, t6		/* t3 <-- location to fix up in RAM */
157	SREG	t5, 0(t3)
15810:
159	addi	t1, t1, (REGBYTES*3)
160	ble	t1, t2, 9b
161
162/*
163 * trap update
164*/
165	la	t0, trap_entry
166	add	t0, t0, t6
167	csrw	MODE_PREFIX(tvec), t0
168
169clear_bss:
170	la	t0, __bss_start		/* t0 <- rel __bss_start in FLASH */
171	add	t0, t0, t6		/* t0 <- rel __bss_start in RAM */
172	la	t1, __bss_end		/* t1 <- rel __bss_end in FLASH */
173	add	t1, t1, t6		/* t1 <- rel __bss_end in RAM */
174	beq	t0, t1, call_board_init_r
175
176clbss_l:
177	SREG	zero, 0(t0)		/* clear loop... */
178	addi	t0, t0, REGBYTES
179	bne	t0, t1, clbss_l
180
181/*
182 * We are done. Do not return, instead branch to second part of board
183 * initialization, now running from RAM.
184 */
185call_board_init_r:
186	jal	invalidate_icache_all
187	jal	flush_dcache_all
188	la	t0, board_init_r
189	mv	t4, t0			/* offset of board_init_r() */
190	add	t4, t4, t6		/* real address of board_init_r() */
191/*
192 * setup parameters for board_init_r
193 */
194	mv	a0, s3			/* gd_t */
195	mv	a1, s4			/* dest_addr */
196
197/*
198 * jump to it ...
199 */
200	jr	t4			/* jump to board_init_r() */
201
202/*
203 * trap entry
204 */
205.align 2
206trap_entry:
207	addi	sp, sp, -32*REGBYTES
208	SREG	x1, 1*REGBYTES(sp)
209	SREG	x2, 2*REGBYTES(sp)
210	SREG	x3, 3*REGBYTES(sp)
211	SREG	x4, 4*REGBYTES(sp)
212	SREG	x5, 5*REGBYTES(sp)
213	SREG	x6, 6*REGBYTES(sp)
214	SREG	x7, 7*REGBYTES(sp)
215	SREG	x8, 8*REGBYTES(sp)
216	SREG	x9, 9*REGBYTES(sp)
217	SREG	x10, 10*REGBYTES(sp)
218	SREG	x11, 11*REGBYTES(sp)
219	SREG	x12, 12*REGBYTES(sp)
220	SREG	x13, 13*REGBYTES(sp)
221	SREG	x14, 14*REGBYTES(sp)
222	SREG	x15, 15*REGBYTES(sp)
223	SREG	x16, 16*REGBYTES(sp)
224	SREG	x17, 17*REGBYTES(sp)
225	SREG	x18, 18*REGBYTES(sp)
226	SREG	x19, 19*REGBYTES(sp)
227	SREG	x20, 20*REGBYTES(sp)
228	SREG	x21, 21*REGBYTES(sp)
229	SREG	x22, 22*REGBYTES(sp)
230	SREG	x23, 23*REGBYTES(sp)
231	SREG	x24, 24*REGBYTES(sp)
232	SREG	x25, 25*REGBYTES(sp)
233	SREG	x26, 26*REGBYTES(sp)
234	SREG	x27, 27*REGBYTES(sp)
235	SREG	x28, 28*REGBYTES(sp)
236	SREG	x29, 29*REGBYTES(sp)
237	SREG	x30, 30*REGBYTES(sp)
238	SREG	x31, 31*REGBYTES(sp)
239	csrr	a0, MODE_PREFIX(cause)
240	csrr	a1, MODE_PREFIX(epc)
241	mv	a2, sp
242	jal	handle_trap
243	csrw	MODE_PREFIX(epc), a0
244
245#ifdef CONFIG_RISCV_SMODE
246/*
247 * Remain in S-mode after sret
248 */
249	li	t0, SSTATUS_SPP
250#else
251/*
252 * Remain in M-mode after mret
253 */
254	li	t0, MSTATUS_MPP
255#endif
256	csrs	MODE_PREFIX(status), t0
257	LREG	x1, 1*REGBYTES(sp)
258	LREG	x2, 2*REGBYTES(sp)
259	LREG	x3, 3*REGBYTES(sp)
260	LREG	x4, 4*REGBYTES(sp)
261	LREG	x5, 5*REGBYTES(sp)
262	LREG	x6, 6*REGBYTES(sp)
263	LREG	x7, 7*REGBYTES(sp)
264	LREG	x8, 8*REGBYTES(sp)
265	LREG	x9, 9*REGBYTES(sp)
266	LREG	x10, 10*REGBYTES(sp)
267	LREG	x11, 11*REGBYTES(sp)
268	LREG	x12, 12*REGBYTES(sp)
269	LREG	x13, 13*REGBYTES(sp)
270	LREG	x14, 14*REGBYTES(sp)
271	LREG	x15, 15*REGBYTES(sp)
272	LREG	x16, 16*REGBYTES(sp)
273	LREG	x17, 17*REGBYTES(sp)
274	LREG	x18, 18*REGBYTES(sp)
275	LREG	x19, 19*REGBYTES(sp)
276	LREG	x20, 20*REGBYTES(sp)
277	LREG	x21, 21*REGBYTES(sp)
278	LREG	x22, 22*REGBYTES(sp)
279	LREG	x23, 23*REGBYTES(sp)
280	LREG	x24, 24*REGBYTES(sp)
281	LREG	x25, 25*REGBYTES(sp)
282	LREG	x26, 26*REGBYTES(sp)
283	LREG	x27, 27*REGBYTES(sp)
284	LREG	x28, 28*REGBYTES(sp)
285	LREG	x29, 29*REGBYTES(sp)
286	LREG	x30, 30*REGBYTES(sp)
287	LREG	x31, 31*REGBYTES(sp)
288	addi	sp, sp, 32*REGBYTES
289	MODE_PREFIX(ret)
290