]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/riscv/riscv/locore.S
Get rid of sa->narg. It serves no purpose; use sa->callp->sy_narg instead.
[FreeBSD/FreeBSD.git] / sys / riscv / riscv / locore.S
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
78 1:
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          * Page tables setup
111          *  a0 - modulep or zero
112          *  a1 - zero or dtbp
113          */
114 pagetables:
115         /* Get the kernel's load address */
116         jal     get_physmem
117
118         /* Add L1 entry for kernel */
119         lla     s1, pagetable_l1
120         lla     s2, pagetable_l2        /* Link to next level PN */
121         srli    s2, s2, PAGE_SHIFT
122
123         li      a5, KERNBASE
124         srli    a5, a5, L1_SHIFT        /* >> L1_SHIFT */
125         andi    a5, a5, 0x1ff           /* & 0x1ff */
126         li      t4, PTE_V
127         slli    t5, s2, PTE_PPN0_S      /* (s2 << PTE_PPN0_S) */
128         or      t6, t4, t5
129
130         /* Store L1 PTE entry to position */
131         li      a6, PTE_SIZE
132         mulw    a5, a5, a6
133         add     t0, s1, a5
134         sd      t6, (t0)
135
136         /* Level 2 superpages (512 x 2MiB) */
137         lla     s1, pagetable_l2
138         srli    t4, s9, 21              /* Div physmem base by 2 MiB */
139         li      t2, 512                 /* Build 512 entries */
140         add     t3, t4, t2
141         li      t5, 0
142         li      t0, (PTE_KERN | PTE_X)
143 1:
144         slli    t2, t4, PTE_PPN1_S      /* << PTE_PPN1_S */
145         or      t5, t0, t2
146         sd      t5, (s1)                /* Store PTE entry to position */
147         addi    s1, s1, PTE_SIZE
148
149         addi    t4, t4, 1
150         bltu    t4, t3, 1b
151
152         /* Create an L1 page for early devmap */
153         lla     s1, pagetable_l1
154         lla     s2, pagetable_l2_devmap /* Link to next level PN */
155         srli    s2, s2, PAGE_SHIFT
156
157         li      a5, (VM_MAX_KERNEL_ADDRESS - L2_SIZE)
158         srli    a5, a5, L1_SHIFT        /* >> L1_SHIFT */
159         andi    a5, a5, 0x1ff           /* & 0x1ff */
160         li      t4, PTE_V
161         slli    t5, s2, PTE_PPN0_S      /* (s2 << PTE_PPN0_S) */
162         or      t6, t4, t5
163
164         /* Store single level1 PTE entry to position */
165         li      a6, PTE_SIZE
166         mulw    a5, a5, a6
167         add     t0, s1, a5
168         sd      t6, (t0)
169
170         /* Check if we have a DTB that needs to be mapped */
171         beqz    a1, 2f
172
173         /* Create an L2 page superpage for DTB */
174         lla     s1, pagetable_l2_devmap
175         mv      s2, a1
176         srli    s2, s2, PAGE_SHIFT
177         /* Mask off any bits that aren't aligned */
178         andi    s2, s2, ~((1 << (PTE_PPN1_S - PTE_PPN0_S)) - 1)
179
180         li      t0, (PTE_KERN)
181         slli    t2, s2, PTE_PPN0_S      /* << PTE_PPN0_S */
182         or      t0, t0, t2
183
184         /* Store PTE entry to position */
185         li      a6, PTE_SIZE
186         li      a5, 510
187         mulw    a5, a5, a6
188         add     t1, s1, a5
189         sd      t0, (t1)
190
191         /* Page tables END */
192
193         /* Setup supervisor trap vector */
194 2:
195         lla     t0, va
196         sub     t0, t0, s9
197         li      t1, KERNBASE
198         add     t0, t0, t1
199         csrw    stvec, t0
200
201         /* Set page tables base register */
202         lla     s2, pagetable_l1
203         srli    s2, s2, PAGE_SHIFT
204         li      t0, SATP_MODE_SV39
205         or      s2, s2, t0
206         sfence.vma
207         csrw    satp, s2
208
209         .align 2
210 va:
211         /* Set the global pointer again, this time with the virtual address. */
212 .option push
213 .option norelax
214         lla     gp, __global_pointer$
215 .option pop
216
217         /* Setup supervisor trap vector */
218         la      t0, cpu_exception_handler
219         csrw    stvec, t0
220
221         /* Ensure sscratch is zero */
222         li      t0, 0
223         csrw    sscratch, t0
224
225         /* Initialize stack pointer */
226         la      sp, initstack_end
227
228         /* Clear frame pointer */
229         mv      s0, zero
230
231         /* Allocate space for thread0 PCB and riscv_bootparams */
232         addi    sp, sp, -(PCB_SIZE + RISCV_BOOTPARAMS_SIZE) & ~STACKALIGNBYTES
233
234         /* Clear BSS */
235         la      t0, _C_LABEL(__bss_start)
236         la      t1, _C_LABEL(_end)
237 1:
238         sd      zero, 0(t0)
239         addi    t0, t0, 8
240         bltu    t0, t1, 1b
241
242         /* Fill riscv_bootparams */
243         la      t0, pagetable_l1
244         sd      t0, RISCV_BOOTPARAMS_KERN_L1PT(sp)
245         sd      s9, RISCV_BOOTPARAMS_KERN_PHYS(sp)
246
247         la      t0, initstack
248         sd      t0, RISCV_BOOTPARAMS_KERN_STACK(sp)
249
250         li      t0, (VM_EARLY_DTB_ADDRESS)
251         /* Add offset of DTB within superpage */
252         li      t1, (L2_OFFSET)
253         and     t1, a1, t1
254         add     t0, t0, t1
255         sd      t0, RISCV_BOOTPARAMS_DTBP_VIRT(sp)
256         sd      a1, RISCV_BOOTPARAMS_DTBP_PHYS(sp)
257
258         sd      a0, RISCV_BOOTPARAMS_MODULEP(sp)
259
260         mv      a0, sp
261         call    _C_LABEL(initriscv)     /* Off we go */
262         call    _C_LABEL(mi_startup)
263
264         /* We should never reach here, but if so just hang. */
265 2:
266         wfi
267         j       2b
268
269 /*
270  * Get the physical address the kernel is loaded to. Returned in s9.
271  */
272 get_physmem:
273         lla     t0, virt_map    /* physical address of virt_map */
274         ld      t1, 0(t0)       /* virtual address of virt_map */
275         sub     t1, t1, t0      /* calculate phys->virt delta */
276         li      t2, KERNBASE
277         sub     s9, t2, t1      /* s9 = physmem base */
278         ret
279
280         .align  4
281 initstack:
282         .space  (PAGE_SIZE * KSTACK_PAGES)
283 initstack_end:
284
285 ENTRY(sigcode)
286         mv      a0, sp
287         addi    a0, a0, SF_UC
288
289 1:
290         li      t0, SYS_sigreturn
291         ecall
292
293         /* sigreturn failed, exit */
294         li      t0, SYS_exit
295         ecall
296
297         j       1b
298 END(sigcode)
299         /* This may be copied to the stack, keep it 16-byte aligned */
300         .align  3
301 esigcode:
302
303         .data
304         .align  3
305         .global szsigcode
306 szsigcode:
307         .quad   esigcode - sigcode
308
309         .align  12
310 pagetable_l1:
311         .space  PAGE_SIZE
312 pagetable_l2:
313         .space  PAGE_SIZE
314 pagetable_l2_devmap:
315         .space  PAGE_SIZE
316
317         .align 3
318 virt_map:
319         .quad   virt_map
320 hart_lottery:
321         .space  4
322
323         .globl init_pt_va
324 init_pt_va:
325         .quad pagetable_l2      /* XXX: Keep page tables VA */
326
327 #ifndef SMP
328 ENTRY(mpentry)
329 1:
330         wfi
331         j       1b
332 END(mpentry)
333 #else
334 /*
335  * mpentry(unsigned long)
336  *
337  * Called by a core when it is being brought online.
338  */
339 ENTRY(mpentry)
340         /*
341          * Calculate the offset to __riscv_boot_ap
342          * for the current core, cpuid is in a0.
343          */
344         li      t1, 4
345         mulw    t1, t1, a0
346         /* Get the pointer */
347         lla     t0, __riscv_boot_ap
348         add     t0, t0, t1
349
350 1:
351         /* Wait the kernel to be ready */
352         lw      t1, 0(t0)
353         beqz    t1, 1b
354
355         /* Setup stack pointer */
356         lla     t0, bootstack
357         ld      sp, 0(t0)
358
359         /* Get the kernel's load address */
360         jal     get_physmem
361
362         /* Setup supervisor trap vector */
363         lla     t0, mpva
364         sub     t0, t0, s9
365         li      t1, KERNBASE
366         add     t0, t0, t1
367         csrw    stvec, t0
368
369         /* Set page tables base register */
370         lla     s2, pagetable_l1
371         srli    s2, s2, PAGE_SHIFT
372         li      t0, SATP_MODE_SV39
373         or      s2, s2, t0
374         sfence.vma
375         csrw    satp, s2
376
377         .align 2
378 mpva:
379         /* Set the global pointer again, this time with the virtual address. */
380 .option push
381 .option norelax
382         lla     gp, __global_pointer$
383 .option pop
384
385         /* Setup supervisor trap vector */
386         la      t0, cpu_exception_handler
387         csrw    stvec, t0
388
389         /* Ensure sscratch is zero */
390         li      t0, 0
391         csrw    sscratch, t0
392
393         call    init_secondary
394 END(mpentry)
395 #endif