xref: /linux/arch/riscv/kernel/head.S (revision c9f289701540baeef9ac7c9977d67a7259f404db)
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * Copyright (C) 2012 Regents of the University of California
4 */
5
6#include <asm/thread_info.h>
7#include <asm/asm-offsets.h>
8#include <asm/asm.h>
9#include <linux/init.h>
10#include <linux/linkage.h>
11#include <asm/thread_info.h>
12#include <asm/page.h>
13#include <asm/csr.h>
14#include <asm/hwcap.h>
15#include <asm/image.h>
16
17__INIT
18ENTRY(_start)
19	/*
20	 * Image header expected by Linux boot-loaders. The image header data
21	 * structure is described in asm/image.h.
22	 * Do not modify it without modifying the structure and all bootloaders
23	 * that expects this header format!!
24	 */
25	/* jump to start kernel */
26	j _start_kernel
27	/* reserved */
28	.word 0
29	.balign 8
30#if __riscv_xlen == 64
31	/* Image load offset(2MB) from start of RAM */
32	.dword 0x200000
33#else
34	/* Image load offset(4MB) from start of RAM */
35	.dword 0x400000
36#endif
37	/* Effective size of kernel image */
38	.dword _end - _start
39	.dword __HEAD_FLAGS
40	.word RISCV_HEADER_VERSION
41	.word 0
42	.dword 0
43	.ascii RISCV_IMAGE_MAGIC
44	.balign 4
45	.ascii RISCV_IMAGE_MAGIC2
46	.word 0
47
48.global _start_kernel
49_start_kernel:
50	/* Mask all interrupts */
51	csrw CSR_IE, zero
52	csrw CSR_IP, zero
53
54#ifdef CONFIG_RISCV_M_MODE
55	/* flush the instruction cache */
56	fence.i
57
58	/* Reset all registers except ra, a0, a1 */
59	call reset_regs
60
61	/* Setup a PMP to permit access to all of memory. */
62	li a0, -1
63	csrw CSR_PMPADDR0, a0
64	li a0, (PMP_A_NAPOT | PMP_R | PMP_W | PMP_X)
65	csrw CSR_PMPCFG0, a0
66
67	/*
68	 * The hartid in a0 is expected later on, and we have no firmware
69	 * to hand it to us.
70	 */
71	csrr a0, CSR_MHARTID
72#endif /* CONFIG_RISCV_M_MODE */
73
74	/* Load the global pointer */
75.option push
76.option norelax
77	la gp, __global_pointer$
78.option pop
79
80	/*
81	 * Disable FPU to detect illegal usage of
82	 * floating point in kernel space
83	 */
84	li t0, SR_FS
85	csrc CSR_STATUS, t0
86
87#ifdef CONFIG_SMP
88	li t0, CONFIG_NR_CPUS
89	blt a0, t0, .Lgood_cores
90	tail .Lsecondary_park
91.Lgood_cores:
92#endif
93
94	/* Pick one hart to run the main boot sequence */
95	la a3, hart_lottery
96	li a2, 1
97	amoadd.w a3, a2, (a3)
98	bnez a3, .Lsecondary_start
99
100	/* Clear BSS for flat non-ELF images */
101	la a3, __bss_start
102	la a4, __bss_stop
103	ble a4, a3, clear_bss_done
104clear_bss:
105	REG_S zero, (a3)
106	add a3, a3, RISCV_SZPTR
107	blt a3, a4, clear_bss
108clear_bss_done:
109
110	/* Save hart ID and DTB physical address */
111	mv s0, a0
112	mv s1, a1
113	la a2, boot_cpu_hartid
114	REG_S a0, (a2)
115
116	/* Initialize page tables and relocate to virtual addresses */
117	la sp, init_thread_union + THREAD_SIZE
118	mv a0, s1
119	call setup_vm
120#ifdef CONFIG_MMU
121	la a0, early_pg_dir
122	call relocate
123#endif /* CONFIG_MMU */
124
125	/* Restore C environment */
126	la tp, init_task
127	sw zero, TASK_TI_CPU(tp)
128	la sp, init_thread_union + THREAD_SIZE
129
130#ifdef CONFIG_KASAN
131	call kasan_early_init
132#endif
133	/* Start the kernel */
134	call parse_dtb
135	tail start_kernel
136
137#ifdef CONFIG_MMU
138relocate:
139	/* Relocate return address */
140	li a1, PAGE_OFFSET
141	la a2, _start
142	sub a1, a1, a2
143	add ra, ra, a1
144
145	/* Point stvec to virtual address of intruction after satp write */
146	la a2, 1f
147	add a2, a2, a1
148	csrw CSR_TVEC, a2
149
150	/* Compute satp for kernel page tables, but don't load it yet */
151	srl a2, a0, PAGE_SHIFT
152	li a1, SATP_MODE
153	or a2, a2, a1
154
155	/*
156	 * Load trampoline page directory, which will cause us to trap to
157	 * stvec if VA != PA, or simply fall through if VA == PA.  We need a
158	 * full fence here because setup_vm() just wrote these PTEs and we need
159	 * to ensure the new translations are in use.
160	 */
161	la a0, trampoline_pg_dir
162	srl a0, a0, PAGE_SHIFT
163	or a0, a0, a1
164	sfence.vma
165	csrw CSR_SATP, a0
166.align 2
1671:
168	/* Set trap vector to spin forever to help debug */
169	la a0, .Lsecondary_park
170	csrw CSR_TVEC, a0
171
172	/* Reload the global pointer */
173.option push
174.option norelax
175	la gp, __global_pointer$
176.option pop
177
178	/*
179	 * Switch to kernel page tables.  A full fence is necessary in order to
180	 * avoid using the trampoline translations, which are only correct for
181	 * the first superpage.  Fetching the fence is guarnteed to work
182	 * because that first superpage is translated the same way.
183	 */
184	csrw CSR_SATP, a2
185	sfence.vma
186
187	ret
188#endif /* CONFIG_MMU */
189
190.Lsecondary_start:
191#ifdef CONFIG_SMP
192	/* Set trap vector to spin forever to help debug */
193	la a3, .Lsecondary_park
194	csrw CSR_TVEC, a3
195
196	slli a3, a0, LGREG
197	la a1, __cpu_up_stack_pointer
198	la a2, __cpu_up_task_pointer
199	add a1, a3, a1
200	add a2, a3, a2
201
202	/*
203	 * This hart didn't win the lottery, so we wait for the winning hart to
204	 * get far enough along the boot process that it should continue.
205	 */
206.Lwait_for_cpu_up:
207	/* FIXME: We should WFI to save some energy here. */
208	REG_L sp, (a1)
209	REG_L tp, (a2)
210	beqz sp, .Lwait_for_cpu_up
211	beqz tp, .Lwait_for_cpu_up
212	fence
213
214#ifdef CONFIG_MMU
215	/* Enable virtual memory and relocate to virtual address */
216	la a0, swapper_pg_dir
217	call relocate
218#endif
219
220	tail smp_callin
221#endif
222
223END(_start)
224
225#ifdef CONFIG_RISCV_M_MODE
226ENTRY(reset_regs)
227	li	sp, 0
228	li	gp, 0
229	li	tp, 0
230	li	t0, 0
231	li	t1, 0
232	li	t2, 0
233	li	s0, 0
234	li	s1, 0
235	li	a2, 0
236	li	a3, 0
237	li	a4, 0
238	li	a5, 0
239	li	a6, 0
240	li	a7, 0
241	li	s2, 0
242	li	s3, 0
243	li	s4, 0
244	li	s5, 0
245	li	s6, 0
246	li	s7, 0
247	li	s8, 0
248	li	s9, 0
249	li	s10, 0
250	li	s11, 0
251	li	t3, 0
252	li	t4, 0
253	li	t5, 0
254	li	t6, 0
255	csrw	CSR_SCRATCH, 0
256
257#ifdef CONFIG_FPU
258	csrr	t0, CSR_MISA
259	andi	t0, t0, (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)
260	beqz	t0, .Lreset_regs_done
261
262	li	t1, SR_FS
263	csrs	CSR_STATUS, t1
264	fmv.s.x	f0, zero
265	fmv.s.x	f1, zero
266	fmv.s.x	f2, zero
267	fmv.s.x	f3, zero
268	fmv.s.x	f4, zero
269	fmv.s.x	f5, zero
270	fmv.s.x	f6, zero
271	fmv.s.x	f7, zero
272	fmv.s.x	f8, zero
273	fmv.s.x	f9, zero
274	fmv.s.x	f10, zero
275	fmv.s.x	f11, zero
276	fmv.s.x	f12, zero
277	fmv.s.x	f13, zero
278	fmv.s.x	f14, zero
279	fmv.s.x	f15, zero
280	fmv.s.x	f16, zero
281	fmv.s.x	f17, zero
282	fmv.s.x	f18, zero
283	fmv.s.x	f19, zero
284	fmv.s.x	f20, zero
285	fmv.s.x	f21, zero
286	fmv.s.x	f22, zero
287	fmv.s.x	f23, zero
288	fmv.s.x	f24, zero
289	fmv.s.x	f25, zero
290	fmv.s.x	f26, zero
291	fmv.s.x	f27, zero
292	fmv.s.x	f28, zero
293	fmv.s.x	f29, zero
294	fmv.s.x	f30, zero
295	fmv.s.x	f31, zero
296	csrw	fcsr, 0
297	/* note that the caller must clear SR_FS */
298#endif /* CONFIG_FPU */
299.Lreset_regs_done:
300	ret
301END(reset_regs)
302#endif /* CONFIG_RISCV_M_MODE */
303
304.section ".text", "ax",@progbits
305.align 2
306.Lsecondary_park:
307	/* We lack SMP support or have too many harts, so park this hart */
308	wfi
309	j .Lsecondary_park
310
311__PAGE_ALIGNED_BSS
312	/* Empty zero page */
313	.balign PAGE_SIZE
314