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