xref: /freebsd/sys/riscv/riscv/locore.S (revision 9768746b)
1/*-
2 * Copyright (c) 2015-2018 Ruslan Bukin <br@bsdpad.com>
3 * All rights reserved.
4 *
5 * Portions of this software were developed by SRI International and the
6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract
7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Portions of this software were developed by the University of Cambridge
10 * Computer Laboratory as part of the CTSRD Project, with support from the
11 * UK Higher Education Innovation Fund (HEIF).
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * $FreeBSD$
35 */
36
37#include "assym.inc"
38
39#include <sys/syscall.h>
40#include <machine/asm.h>
41#include <machine/param.h>
42#include <machine/trap.h>
43#include <machine/riscvreg.h>
44#include <machine/pte.h>
45
46	.globl	kernbase
47	.set	kernbase, KERNBASE
48
49	.text
50/*
51 * Alternate entry point. Used when booting via SBI firmware. It must be placed
52 * at the beginning of the .text section. Arguments are as follows:
53 *  - a0 = hart ID
54 *  - a1 = dtbp
55 *
56 * Multiple CPUs might enter from this point, so we perform a hart lottery and
57 * send the losers to mpentry.
58 */
59	.globl _alt_start
60_alt_start:
61	/* Set the global pointer */
62.option push
63.option norelax
64	lla	gp, __global_pointer$
65.option pop
66
67	/* Pick a hart to run the boot process. */
68	lla	t0, hart_lottery
69	li	t1, 1
70	amoadd.w t0, t1, 0(t0)
71
72	/*
73	 * We must jump to mpentry in the non-BSP case because the offset is
74	 * too large to fit in a 12-bit branch immediate.
75	 */
76	beqz	t0, 1f
77	j	mpentry
781:
79	/* Store the boot hart */
80	lla	t0, boot_hart
81	sw	a0, 0(t0)
82
83	/* Load zero as modulep */
84	mv	a0, zero
85	j	pagetables
86
87/*
88 * Main entry point. This routine is marked as the ELF entry, and is where
89 * loader(8) will enter the kernel. Arguments are as follows:
90 *  - a0 = modulep
91 *  - a1 = ???
92 *
93 * It is expected that only a single CPU will enter here.
94 */
95	.globl _start
96_start:
97	/* Set the global pointer */
98.option push
99.option norelax
100	lla	gp, __global_pointer$
101.option pop
102
103	/*
104	 * Zero a1 to indicate that we have no DTB pointer. It is already
105	 * included in the loader(8) metadata.
106	 */
107	mv	a1, zero
108
109	/*
110	 * Set up page tables: map a 1GB region starting at KERNBASE using 2MB
111	 * superpages, starting from the first 2MB physical page into which the
112	 * kernel was loaded.  Also reserve an L2 page for the early device map
113	 * and map the DTB, if any, using the second-last entry of that L2
114	 * page.  This is hopefully enough to get us to pmap_bootstrap().
115	 *
116	 * Implementations are required to provide SV39 mode, so we use that
117	 * initially and will optionally enable SV48 mode during kernel pmap
118	 * initialization.
119	 *
120	 *  a0 - modulep or zero
121	 *  a1 - zero or dtbp
122	 */
123pagetables:
124	/* Get the kernel's load address */
125	jal	get_physmem
126
127	/* Add L1 entry for kernel */
128	lla	s1, pagetable_l1
129	lla	s2, pagetable_l2	/* Link to next level PN */
130	srli	s2, s2, PAGE_SHIFT
131
132	li	a5, KERNBASE
133	srli	a5, a5, L1_SHIFT	/* >> L1_SHIFT */
134	andi	a5, a5, Ln_ADDR_MASK	/* & Ln_ADDR_MASK */
135	li	t4, PTE_V
136	slli	t5, s2, PTE_PPN0_S	/* (s2 << PTE_PPN0_S) */
137	or	t6, t4, t5
138
139	/* Store L1 PTE entry to position */
140	li	a6, PTE_SIZE
141	mulw	a5, a5, a6
142	add	t0, s1, a5
143	sd	t6, (t0)
144
145	/* Level 2 superpages (512 x 2MiB) */
146	lla	s1, pagetable_l2
147	srli	t4, s9, L2_SHIFT	/* Div physmem base by 2 MiB */
148	li	t2, 512			/* Build 512 entries */
149	add	t3, t4, t2
150	li	t0, (PTE_KERN | PTE_X)
1511:
152	slli	t2, t4, PTE_PPN1_S	/* << PTE_PPN1_S */
153	or	t5, t0, t2
154	sd	t5, (s1)		/* Store PTE entry to position */
155	addi	s1, s1, PTE_SIZE
156
157	addi	t4, t4, 1
158	bltu	t4, t3, 1b
159
160	/* Create an L1 table entry for early devmap */
161	lla	s1, pagetable_l1
162	lla	s2, pagetable_l2_devmap	/* Link to next level PN */
163	srli	s2, s2, PAGE_SHIFT
164
165	li	a5, (VM_MAX_KERNEL_ADDRESS - L2_SIZE)
166	srli	a5, a5, L1_SHIFT	/* >> L1_SHIFT */
167	andi	a5, a5, Ln_ADDR_MASK	/* & Ln_ADDR_MASK */
168	li	t4, PTE_V
169	slli	t5, s2, PTE_PPN0_S	/* (s2 << PTE_PPN0_S) */
170	or	t6, t4, t5
171
172	/* Store the L1 table entry */
173	li	a6, PTE_SIZE
174	mulw	a5, a5, a6
175	add	t0, s1, a5
176	sd	t6, (t0)
177
178	/* Check if we have a DTB that needs to be mapped */
179	beqz	a1, 2f
180
181	/* Create an L2 mapping for the DTB */
182	lla	s1, pagetable_l2_devmap
183	mv	s2, a1
184	srli	s2, s2, PAGE_SHIFT
185	/* Mask off any bits that aren't aligned */
186	andi	s2, s2, ~((1 << (PTE_PPN1_S - PTE_PPN0_S)) - 1)
187
188	li	t0, (PTE_KERN)
189	slli	t2, s2, PTE_PPN0_S	/* << PTE_PPN0_S */
190	or	t0, t0, t2
191
192	/* Store the L2 table entry for the DTB */
193	li	a6, PTE_SIZE
194	li	a5, 510
195	mulw	a5, a5, a6
196	add	t1, s1, a5
197	sd	t0, (t1)
198
199	/* Page tables END */
200
201	/* Setup supervisor trap vector */
2022:
203	lla	t0, va
204	sub	t0, t0, s9
205	li	t1, KERNBASE
206	add	t0, t0, t1
207	csrw	stvec, t0
208
209	/* Set page tables base register */
210	lla	s2, pagetable_l1
211	srli	s2, s2, PAGE_SHIFT
212	li	t0, SATP_MODE_SV39
213	or	s2, s2, t0
214	sfence.vma
215	csrw	satp, s2
216
217	.align 2
218va:
219	/* Set the global pointer again, this time with the virtual address. */
220.option push
221.option norelax
222	lla	gp, __global_pointer$
223.option pop
224
225	/* Setup supervisor trap vector */
226	la	t0, cpu_exception_handler
227	csrw	stvec, t0
228
229	/* Ensure sscratch is zero */
230	li	t0, 0
231	csrw	sscratch, t0
232
233	/* Initialize stack pointer */
234	la	sp, initstack_end
235
236	/* Clear frame pointer */
237	mv	s0, zero
238
239	/* Allocate space for thread0 PCB and riscv_bootparams */
240	addi	sp, sp, -(PCB_SIZE + RISCV_BOOTPARAMS_SIZE) & ~STACKALIGNBYTES
241
242	/* Clear BSS */
243	la	t0, _C_LABEL(__bss_start)
244	la	t1, _C_LABEL(_end)
2451:
246	sd	zero, 0(t0)
247	addi	t0, t0, 8
248	bltu	t0, t1, 1b
249
250	/* Fill riscv_bootparams */
251	la	t0, pagetable_l1
252	sd	t0, RISCV_BOOTPARAMS_KERN_L1PT(sp)
253	sd	s9, RISCV_BOOTPARAMS_KERN_PHYS(sp)
254
255	la	t0, initstack
256	sd	t0, RISCV_BOOTPARAMS_KERN_STACK(sp)
257
258	li	t0, (VM_EARLY_DTB_ADDRESS)
259	/* Add offset of DTB within superpage */
260	li	t1, (L2_OFFSET)
261	and	t1, a1, t1
262	add	t0, t0, t1
263	sd	t0, RISCV_BOOTPARAMS_DTBP_VIRT(sp)
264	sd	a1, RISCV_BOOTPARAMS_DTBP_PHYS(sp)
265
266	sd	a0, RISCV_BOOTPARAMS_MODULEP(sp)
267
268	mv	a0, sp
269	call	_C_LABEL(initriscv)	/* Off we go */
270	call	_C_LABEL(mi_startup)
271
272	/* We should never reach here, but if so just hang. */
2732:
274	wfi
275	j	2b
276
277/*
278 * Get the physical address the kernel is loaded to. Returned in s9.
279 */
280get_physmem:
281	lla	t0, virt_map	/* physical address of virt_map */
282	ld	t1, 0(t0)	/* virtual address of virt_map */
283	sub	t1, t1, t0	/* calculate phys->virt delta */
284	li	t2, KERNBASE
285	sub	s9, t2, t1	/* s9 = physmem base */
286	ret
287
288	.align  4
289initstack:
290	.space  (PAGE_SIZE * KSTACK_PAGES)
291initstack_end:
292
293ENTRY(sigcode)
294	mv	a0, sp
295	addi	a0, a0, SF_UC
296
2971:
298	li	t0, SYS_sigreturn
299	ecall
300
301	/* sigreturn failed, exit */
302	li	t0, SYS_exit
303	ecall
304
305	j	1b
306END(sigcode)
307	/* This may be copied to the stack, keep it 16-byte aligned */
308	.align	3
309esigcode:
310
311	.data
312	.align	3
313	.global	szsigcode
314szsigcode:
315	.quad	esigcode - sigcode
316
317	.align	12
318pagetable_l1:
319	.space	PAGE_SIZE
320pagetable_l2:
321	.space	PAGE_SIZE
322pagetable_l2_devmap:
323	.space	PAGE_SIZE
324
325	.align 3
326virt_map:
327	.quad   virt_map
328hart_lottery:
329	.space	4
330
331	.globl init_pt_va
332init_pt_va:
333	.quad pagetable_l2	/* XXX: Keep page tables VA */
334
335#ifndef SMP
336ENTRY(mpentry)
3371:
338	wfi
339	j	1b
340END(mpentry)
341#else
342/*
343 * mpentry(unsigned long)
344 *
345 * Called by a core when it is being brought online.
346 */
347ENTRY(mpentry)
348	/*
349	 * Calculate the offset to __riscv_boot_ap
350	 * for the current core, cpuid is in a0.
351	 */
352	li	t1, 4
353	mulw	t1, t1, a0
354	/* Get the pointer */
355	lla	t0, __riscv_boot_ap
356	add	t0, t0, t1
357
3581:
359	/* Wait the kernel to be ready */
360	lw	t1, 0(t0)
361	beqz	t1, 1b
362
363	/* Setup stack pointer */
364	lla	t0, bootstack
365	ld	sp, 0(t0)
366
367	/* Get the kernel's load address */
368	jal	get_physmem
369
370	/* Setup supervisor trap vector */
371	lla	t0, mpva
372	sub	t0, t0, s9
373	li	t1, KERNBASE
374	add	t0, t0, t1
375	csrw	stvec, t0
376
377	/* Set page tables base register */
378	lla	s2, pagetable_l1
379	srli	s2, s2, PAGE_SHIFT
380	li	t0, SATP_MODE_SV39
381	or	s2, s2, t0
382	sfence.vma
383	csrw	satp, s2
384
385	.align 2
386mpva:
387	/* Set the global pointer again, this time with the virtual address. */
388.option push
389.option norelax
390	lla	gp, __global_pointer$
391.option pop
392
393	/* Setup supervisor trap vector */
394	la	t0, cpu_exception_handler
395	csrw	stvec, t0
396
397	/* Ensure sscratch is zero */
398	li	t0, 0
399	csrw	sscratch, t0
400
401	call	init_secondary
402END(mpentry)
403#endif
404