]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/riscv/riscv/swtch.S
Upgrade Unbound to 1.7.2. More to follow.
[FreeBSD/FreeBSD.git] / sys / riscv / riscv / swtch.S
1 /*-
2  * Copyright (c) 2015-2017 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
35 #include "assym.inc"
36 #include "opt_sched.h"
37
38 #include <machine/param.h>
39 #include <machine/asm.h>
40 #include <machine/riscvreg.h>
41 #include <machine/pte.h>
42
43 __FBSDID("$FreeBSD$");
44
45 #ifdef FPE
46 .macro __fpe_state_save p
47         /*
48          * Enable FPE usage in supervisor mode,
49          * so we can access registers.
50          */
51         li      t0, SSTATUS_FS_INITIAL
52         csrs    sstatus, t0
53
54         /* Store registers */
55         frcsr   t0
56         sd      t0, (PCB_FCSR)(\p)
57         fsd     f0, (PCB_X + 0 * 16)(\p)
58         fsd     f1, (PCB_X + 1 * 16)(\p)
59         fsd     f2, (PCB_X + 2 * 16)(\p)
60         fsd     f3, (PCB_X + 3 * 16)(\p)
61         fsd     f4, (PCB_X + 4 * 16)(\p)
62         fsd     f5, (PCB_X + 5 * 16)(\p)
63         fsd     f6, (PCB_X + 6 * 16)(\p)
64         fsd     f7, (PCB_X + 7 * 16)(\p)
65         fsd     f8, (PCB_X + 8 * 16)(\p)
66         fsd     f9, (PCB_X + 9 * 16)(\p)
67         fsd     f10, (PCB_X + 10 * 16)(\p)
68         fsd     f11, (PCB_X + 11 * 16)(\p)
69         fsd     f12, (PCB_X + 12 * 16)(\p)
70         fsd     f13, (PCB_X + 13 * 16)(\p)
71         fsd     f14, (PCB_X + 14 * 16)(\p)
72         fsd     f15, (PCB_X + 15 * 16)(\p)
73         fsd     f16, (PCB_X + 16 * 16)(\p)
74         fsd     f17, (PCB_X + 17 * 16)(\p)
75         fsd     f18, (PCB_X + 18 * 16)(\p)
76         fsd     f19, (PCB_X + 19 * 16)(\p)
77         fsd     f20, (PCB_X + 20 * 16)(\p)
78         fsd     f21, (PCB_X + 21 * 16)(\p)
79         fsd     f22, (PCB_X + 22 * 16)(\p)
80         fsd     f23, (PCB_X + 23 * 16)(\p)
81         fsd     f24, (PCB_X + 24 * 16)(\p)
82         fsd     f25, (PCB_X + 25 * 16)(\p)
83         fsd     f26, (PCB_X + 26 * 16)(\p)
84         fsd     f27, (PCB_X + 27 * 16)(\p)
85         fsd     f28, (PCB_X + 28 * 16)(\p)
86         fsd     f29, (PCB_X + 29 * 16)(\p)
87         fsd     f30, (PCB_X + 30 * 16)(\p)
88         fsd     f31, (PCB_X + 31 * 16)(\p)
89
90         /* Disable FPE usage in supervisor mode. */
91         li      t0, SSTATUS_FS_MASK
92         csrc    sstatus, t0
93 .endm
94
95 .macro __fpe_state_load p
96         /*
97          * Enable FPE usage in supervisor mode,
98          * so we can access registers.
99          */
100         li      t0, SSTATUS_FS_INITIAL
101         csrs    sstatus, t0
102
103         /* Restore registers */
104         ld      t0, (PCB_FCSR)(\p)
105         fscsr   t0
106         fld     f0, (PCB_X + 0 * 16)(\p)
107         fld     f1, (PCB_X + 1 * 16)(\p)
108         fld     f2, (PCB_X + 2 * 16)(\p)
109         fld     f3, (PCB_X + 3 * 16)(\p)
110         fld     f4, (PCB_X + 4 * 16)(\p)
111         fld     f5, (PCB_X + 5 * 16)(\p)
112         fld     f6, (PCB_X + 6 * 16)(\p)
113         fld     f7, (PCB_X + 7 * 16)(\p)
114         fld     f8, (PCB_X + 8 * 16)(\p)
115         fld     f9, (PCB_X + 9 * 16)(\p)
116         fld     f10, (PCB_X + 10 * 16)(\p)
117         fld     f11, (PCB_X + 11 * 16)(\p)
118         fld     f12, (PCB_X + 12 * 16)(\p)
119         fld     f13, (PCB_X + 13 * 16)(\p)
120         fld     f14, (PCB_X + 14 * 16)(\p)
121         fld     f15, (PCB_X + 15 * 16)(\p)
122         fld     f16, (PCB_X + 16 * 16)(\p)
123         fld     f17, (PCB_X + 17 * 16)(\p)
124         fld     f18, (PCB_X + 18 * 16)(\p)
125         fld     f19, (PCB_X + 19 * 16)(\p)
126         fld     f20, (PCB_X + 20 * 16)(\p)
127         fld     f21, (PCB_X + 21 * 16)(\p)
128         fld     f22, (PCB_X + 22 * 16)(\p)
129         fld     f23, (PCB_X + 23 * 16)(\p)
130         fld     f24, (PCB_X + 24 * 16)(\p)
131         fld     f25, (PCB_X + 25 * 16)(\p)
132         fld     f26, (PCB_X + 26 * 16)(\p)
133         fld     f27, (PCB_X + 27 * 16)(\p)
134         fld     f28, (PCB_X + 28 * 16)(\p)
135         fld     f29, (PCB_X + 29 * 16)(\p)
136         fld     f30, (PCB_X + 30 * 16)(\p)
137         fld     f31, (PCB_X + 31 * 16)(\p)
138
139         /* Disable FPE usage in supervisor mode. */
140         li      t0, SSTATUS_FS_MASK
141         csrc    sstatus, t0
142 .endm
143
144 /*
145  * void
146  * fpe_state_save(struct thread *td)
147  */
148 ENTRY(fpe_state_save)
149         /* Get pointer to PCB */
150         ld      a0, TD_PCB(a0)
151         __fpe_state_save a0
152         ret
153 END(fpe_state_save)
154 #endif /* FPE */
155
156 /*
157  * void cpu_throw(struct thread *old, struct thread *new)
158  */
159 ENTRY(cpu_throw)
160         /* Store the new curthread */
161         sd      a1, PC_CURTHREAD(gp)
162         /* And the new pcb */
163         ld      x13, TD_PCB(a1)
164         sd      x13, PC_CURPCB(gp)
165
166         sfence.vma
167
168         /* Switch to the new pmap */
169         ld      t0, PCB_L1ADDR(x13)
170         srli    t0, t0, PAGE_SHIFT
171         li      t1, SATP_MODE_SV39
172         or      t0, t0, t1
173         csrw    sptbr, t0
174
175         /* TODO: Invalidate the TLB */
176
177         sfence.vma
178
179         /* Load registers */
180         ld      ra, (PCB_RA)(x13)
181         ld      sp, (PCB_SP)(x13)
182         ld      tp, (PCB_TP)(x13)
183
184         /* s[0-11] */
185         ld      s0, (PCB_S + 0 * 8)(x13)
186         ld      s1, (PCB_S + 1 * 8)(x13)
187         ld      s2, (PCB_S + 2 * 8)(x13)
188         ld      s3, (PCB_S + 3 * 8)(x13)
189         ld      s4, (PCB_S + 4 * 8)(x13)
190         ld      s5, (PCB_S + 5 * 8)(x13)
191         ld      s6, (PCB_S + 6 * 8)(x13)
192         ld      s7, (PCB_S + 7 * 8)(x13)
193         ld      s8, (PCB_S + 8 * 8)(x13)
194         ld      s9, (PCB_S + 9 * 8)(x13)
195         ld      s10, (PCB_S + 10 * 8)(x13)
196         ld      s11, (PCB_S + 11 * 8)(x13)
197
198 #ifdef FPE
199         /* Is FPE enabled for new thread? */
200         ld      t0, TD_FRAME(a1)
201         ld      t1, (TF_SSTATUS)(t0)
202         li      t2, SSTATUS_FS_MASK
203         and     t3, t1, t2
204         beqz    t3, 1f          /* No, skip. */
205
206         /* Restore registers. */
207         __fpe_state_load x13
208 1:
209 #endif
210
211         ret
212 END(cpu_throw)
213
214 /*
215  * void cpu_switch(struct thread *old, struct thread *new, struct mtx *mtx)
216  *
217  * a0 = old
218  * a1 = new
219  * a2 = mtx
220  * x3 to x7, x16 and x17 are caller saved
221  */
222 ENTRY(cpu_switch)
223         /* Store the new curthread */
224         sd      a1, PC_CURTHREAD(gp)
225         /* And the new pcb */
226         ld      x13, TD_PCB(a1)
227         sd      x13, PC_CURPCB(gp)
228
229         /* Save the old context. */
230         ld      x13, TD_PCB(a0)
231
232         /* Store ra, sp and the callee-saved registers */
233         sd      ra, (PCB_RA)(x13)
234         sd      sp, (PCB_SP)(x13)
235         sd      tp, (PCB_TP)(x13)
236
237         /* s[0-11] */
238         sd      s0, (PCB_S + 0 * 8)(x13)
239         sd      s1, (PCB_S + 1 * 8)(x13)
240         sd      s2, (PCB_S + 2 * 8)(x13)
241         sd      s3, (PCB_S + 3 * 8)(x13)
242         sd      s4, (PCB_S + 4 * 8)(x13)
243         sd      s5, (PCB_S + 5 * 8)(x13)
244         sd      s6, (PCB_S + 6 * 8)(x13)
245         sd      s7, (PCB_S + 7 * 8)(x13)
246         sd      s8, (PCB_S + 8 * 8)(x13)
247         sd      s9, (PCB_S + 9 * 8)(x13)
248         sd      s10, (PCB_S + 10 * 8)(x13)
249         sd      s11, (PCB_S + 11 * 8)(x13)
250
251 #ifdef FPE
252         /*
253          * Is FPE enabled and is it in dirty state
254          * for the old thread?
255          */
256         ld      t0, TD_FRAME(a0)
257         ld      t1, (TF_SSTATUS)(t0)
258         li      t2, SSTATUS_FS_MASK
259         and     t3, t1, t2
260         li      t2, SSTATUS_FS_DIRTY
261         bne     t3, t2, 1f              /* No, skip. */
262
263         /* Yes, mark FPE state clean and save registers. */
264         li      t2, ~SSTATUS_FS_MASK
265         and     t3, t1, t2
266         li      t2, SSTATUS_FS_CLEAN
267         or      t3, t3, t2
268         sd      t3, (TF_SSTATUS)(t0)
269
270         __fpe_state_save x13
271 1:
272 #endif
273
274         /*
275          * Restore the saved context.
276          */
277         ld      x13, TD_PCB(a1)
278
279         /*
280          * TODO: We may need to flush the cache here if switching
281          * to a user process.
282          */
283
284         sfence.vma
285
286         /* Switch to the new pmap */
287         ld      t0, PCB_L1ADDR(x13)
288         srli    t0, t0, PAGE_SHIFT
289         li      t1, SATP_MODE_SV39
290         or      t0, t0, t1
291         csrw    sptbr, t0
292
293         /* TODO: Invalidate the TLB */
294
295         sfence.vma
296
297         /* Release the old thread */
298         sd      a2, TD_LOCK(a0)
299 #if defined(SCHED_ULE) && defined(SMP)
300         /* Spin if TD_LOCK points to a blocked_lock */
301         la      a2, _C_LABEL(blocked_lock)
302 1:
303         ld      t0, TD_LOCK(a1)
304         beq     t0, a2, 1b
305 #endif
306
307         /* Restore the registers */
308         ld      tp, (PCB_TP)(x13)
309         ld      ra, (PCB_RA)(x13)
310         ld      sp, (PCB_SP)(x13)
311
312         /* s[0-11] */
313         ld      s0, (PCB_S + 0 * 8)(x13)
314         ld      s1, (PCB_S + 1 * 8)(x13)
315         ld      s2, (PCB_S + 2 * 8)(x13)
316         ld      s3, (PCB_S + 3 * 8)(x13)
317         ld      s4, (PCB_S + 4 * 8)(x13)
318         ld      s5, (PCB_S + 5 * 8)(x13)
319         ld      s6, (PCB_S + 6 * 8)(x13)
320         ld      s7, (PCB_S + 7 * 8)(x13)
321         ld      s8, (PCB_S + 8 * 8)(x13)
322         ld      s9, (PCB_S + 9 * 8)(x13)
323         ld      s10, (PCB_S + 10 * 8)(x13)
324         ld      s11, (PCB_S + 11 * 8)(x13)
325
326 #ifdef FPE
327         /* Is FPE enabled for new thread? */
328         ld      t0, TD_FRAME(a1)
329         ld      t1, (TF_SSTATUS)(t0)
330         li      t2, SSTATUS_FS_MASK
331         and     t3, t1, t2
332         beqz    t3, 1f          /* No, skip. */
333
334         /* Restore registers. */
335         __fpe_state_load x13
336 1:
337 #endif
338
339         ret
340 .Lcpu_switch_panic_str:
341         .asciz "cpu_switch: %p\0"
342 END(cpu_switch)
343
344 /*
345  * fork_exit(void (*callout)(void *, struct trapframe *), void *arg,
346  *  struct trapframe *frame)
347  */
348
349 ENTRY(fork_trampoline)
350         mv      a0, s0
351         mv      a1, s1
352         mv      a2, sp
353         call    _C_LABEL(fork_exit)
354
355         /* Restore sstatus */
356         ld      t0, (TF_SSTATUS)(sp)
357         /* Ensure interrupts disabled */
358         li      t1, ~SSTATUS_SIE
359         and     t0, t0, t1
360         csrw    sstatus, t0
361
362         /* Restore exception program counter */
363         ld      t0, (TF_SEPC)(sp)
364         csrw    sepc, t0
365
366         /* Restore the registers */
367         ld      t0, (TF_T + 0 * 8)(sp)
368         ld      t1, (TF_T + 1 * 8)(sp)
369         ld      t2, (TF_T + 2 * 8)(sp)
370         ld      t3, (TF_T + 3 * 8)(sp)
371         ld      t4, (TF_T + 4 * 8)(sp)
372         ld      t5, (TF_T + 5 * 8)(sp)
373         ld      t6, (TF_T + 6 * 8)(sp)
374
375         ld      s0, (TF_S + 0 * 8)(sp)
376         ld      s1, (TF_S + 1 * 8)(sp)
377         ld      s2, (TF_S + 2 * 8)(sp)
378         ld      s3, (TF_S + 3 * 8)(sp)
379         ld      s4, (TF_S + 4 * 8)(sp)
380         ld      s5, (TF_S + 5 * 8)(sp)
381         ld      s6, (TF_S + 6 * 8)(sp)
382         ld      s7, (TF_S + 7 * 8)(sp)
383         ld      s8, (TF_S + 8 * 8)(sp)
384         ld      s9, (TF_S + 9 * 8)(sp)
385         ld      s10, (TF_S + 10 * 8)(sp)
386         ld      s11, (TF_S + 11 * 8)(sp)
387
388         ld      a0, (TF_A + 0 * 8)(sp)
389         ld      a1, (TF_A + 1 * 8)(sp)
390         ld      a2, (TF_A + 2 * 8)(sp)
391         ld      a3, (TF_A + 3 * 8)(sp)
392         ld      a4, (TF_A + 4 * 8)(sp)
393         ld      a5, (TF_A + 5 * 8)(sp)
394         ld      a6, (TF_A + 6 * 8)(sp)
395         ld      a7, (TF_A + 7 * 8)(sp)
396
397         /* Load user ra and sp */
398         ld      ra, (TF_RA)(sp)
399
400         /*
401          * Store our pcpup on stack, we will load it back
402          * on kernel mode trap.
403          */
404         sd      gp, (TF_SIZE)(sp)
405         ld      gp, (TF_GP)(sp)
406
407         /* Save kernel stack so we can use it doing a user trap */
408         addi    sp, sp, TF_SIZE
409         csrw    sscratch, sp
410
411         /* Load user stack */
412         ld      sp, (TF_SP - TF_SIZE)(sp)
413
414         sret
415 END(fork_trampoline)
416
417 ENTRY(savectx)
418         /* Store ra, sp and the callee-saved registers */
419         sd      ra, (PCB_RA)(a0)
420         sd      sp, (PCB_SP)(a0)
421         sd      tp, (PCB_TP)(a0)
422
423         /* s[0-11] */
424         sd      s0, (PCB_S + 0 * 8)(a0)
425         sd      s1, (PCB_S + 1 * 8)(a0)
426         sd      s2, (PCB_S + 2 * 8)(a0)
427         sd      s3, (PCB_S + 3 * 8)(a0)
428         sd      s4, (PCB_S + 4 * 8)(a0)
429         sd      s5, (PCB_S + 5 * 8)(a0)
430         sd      s6, (PCB_S + 6 * 8)(a0)
431         sd      s7, (PCB_S + 7 * 8)(a0)
432         sd      s8, (PCB_S + 8 * 8)(a0)
433         sd      s9, (PCB_S + 9 * 8)(a0)
434         sd      s10, (PCB_S + 10 * 8)(a0)
435         sd      s11, (PCB_S + 11 * 8)(a0)
436
437 #ifdef FPE
438         __fpe_state_save a0
439 #endif
440         ret
441 END(savectx)