1295041Sbr/*-
2295972Sbr * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com>
3295041Sbr * All rights reserved.
4295041Sbr *
5295041Sbr * Portions of this software were developed by SRI International and the
6295041Sbr * University of Cambridge Computer Laboratory under DARPA/AFRL contract
7295041Sbr * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
8295041Sbr *
9295041Sbr * Portions of this software were developed by the University of Cambridge
10295041Sbr * Computer Laboratory as part of the CTSRD Project, with support from the
11295041Sbr * UK Higher Education Innovation Fund (HEIF).
12295041Sbr *
13295041Sbr * Redistribution and use in source and binary forms, with or without
14295041Sbr * modification, are permitted provided that the following conditions
15295041Sbr * are met:
16295041Sbr * 1. Redistributions of source code must retain the above copyright
17295041Sbr *    notice, this list of conditions and the following disclaimer.
18295041Sbr * 2. Redistributions in binary form must reproduce the above copyright
19295041Sbr *    notice, this list of conditions and the following disclaimer in the
20295041Sbr *    documentation and/or other materials provided with the distribution.
21295041Sbr *
22295041Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23295041Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24295041Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25295041Sbr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26295041Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27295041Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28295041Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29295041Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30295041Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31295041Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32295041Sbr * SUCH DAMAGE.
33295041Sbr */
34295041Sbr
35295041Sbr#include "assym.s"
36295041Sbr#include "opt_sched.h"
37295041Sbr
38295041Sbr#include <machine/param.h>
39295041Sbr#include <machine/asm.h>
40295041Sbr#include <machine/riscvreg.h>
41295041Sbr#include <machine/pte.h>
42295041Sbr
43295041Sbr__FBSDID("$FreeBSD: releng/11.0/sys/riscv/riscv/swtch.S 298580 2016-04-25 14:47:51Z br $");
44295041Sbr
45295041Sbr/*
46295041Sbr * void cpu_throw(struct thread *old, struct thread *new)
47295041Sbr */
48295041SbrENTRY(cpu_throw)
49295041Sbr	/* Store the new curthread */
50295258Sbr	sd	a1, PC_CURTHREAD(gp)
51295041Sbr	/* And the new pcb */
52295041Sbr	ld	x13, TD_PCB(a1)
53295258Sbr	sd	x13, PC_CURPCB(gp)
54295041Sbr
55295041Sbr	sfence.vm
56295041Sbr
57295041Sbr	/* Switch to the new pmap */
58298580Sbr	ld	t0, PCB_L1ADDR(x13)
59298580Sbr	csrw	sptbr, t0
60295041Sbr
61295041Sbr	/* TODO: Invalidate the TLB */
62295041Sbr
63295041Sbr	sfence.vm
64295041Sbr
65295041Sbr	/* Load registers */
66295041Sbr	ld	ra, (PCB_RA)(x13)
67295041Sbr	ld	sp, (PCB_SP)(x13)
68295041Sbr
69295041Sbr	/* s[0-11] */
70295041Sbr	ld	s0, (PCB_S + 0 * 8)(x13)
71295041Sbr	ld	s1, (PCB_S + 1 * 8)(x13)
72295041Sbr	ld	s2, (PCB_S + 2 * 8)(x13)
73295041Sbr	ld	s3, (PCB_S + 3 * 8)(x13)
74295041Sbr	ld	s4, (PCB_S + 4 * 8)(x13)
75295041Sbr	ld	s5, (PCB_S + 5 * 8)(x13)
76295041Sbr	ld	s6, (PCB_S + 6 * 8)(x13)
77295041Sbr	ld	s7, (PCB_S + 7 * 8)(x13)
78295041Sbr	ld	s8, (PCB_S + 8 * 8)(x13)
79295041Sbr	ld	s9, (PCB_S + 9 * 8)(x13)
80295041Sbr	ld	s10, (PCB_S + 10 * 8)(x13)
81295041Sbr	ld	s11, (PCB_S + 11 * 8)(x13)
82295041Sbr	ret
83295041Sbr
84295041Sbr.Lcpu_throw_panic_str:
85295041Sbr	.asciz "cpu_throw: %p\0"
86295041SbrEND(cpu_throw)
87295041Sbr
88295041Sbr/*
89295041Sbr * void cpu_switch(struct thread *old, struct thread *new, struct mtx *mtx)
90295041Sbr *
91295041Sbr * a0 = old
92295041Sbr * a1 = new
93295041Sbr * a2 = mtx
94295041Sbr * x3 to x7, x16 and x17 are caller saved
95295041Sbr */
96295041SbrENTRY(cpu_switch)
97295041Sbr	/* Store the new curthread */
98295258Sbr	sd	a1, PC_CURTHREAD(gp)
99295041Sbr	/* And the new pcb */
100295041Sbr	ld	x13, TD_PCB(a1)
101295258Sbr	sd	x13, PC_CURPCB(gp)
102295041Sbr
103295041Sbr	/* Save the old context. */
104295041Sbr	ld	x13, TD_PCB(a0)
105295041Sbr
106295697Sbr	/* Store ra, sp and the callee-saved registers */
107295041Sbr	sd	ra, (PCB_RA)(x13)
108295041Sbr	sd	sp, (PCB_SP)(x13)
109295041Sbr
110295041Sbr	/* s[0-11] */
111295041Sbr	sd	s0, (PCB_S + 0 * 8)(x13)
112295041Sbr	sd	s1, (PCB_S + 1 * 8)(x13)
113295041Sbr	sd	s2, (PCB_S + 2 * 8)(x13)
114295041Sbr	sd	s3, (PCB_S + 3 * 8)(x13)
115295041Sbr	sd	s4, (PCB_S + 4 * 8)(x13)
116295041Sbr	sd	s5, (PCB_S + 5 * 8)(x13)
117295041Sbr	sd	s6, (PCB_S + 6 * 8)(x13)
118295041Sbr	sd	s7, (PCB_S + 7 * 8)(x13)
119295041Sbr	sd	s8, (PCB_S + 8 * 8)(x13)
120295041Sbr	sd	s9, (PCB_S + 9 * 8)(x13)
121295041Sbr	sd	s10, (PCB_S + 10 * 8)(x13)
122295041Sbr	sd	s11, (PCB_S + 11 * 8)(x13)
123295041Sbr
124295041Sbr	/*
125295041Sbr	 * Restore the saved context.
126295041Sbr	 */
127295041Sbr	ld	x13, TD_PCB(a1)
128295041Sbr
129295041Sbr	/*
130295041Sbr	 * TODO: We may need to flush the cache here if switching
131295041Sbr	 * to a user process.
132295041Sbr	 */
133295041Sbr
134295041Sbr	sfence.vm
135295041Sbr
136295041Sbr	/* Switch to the new pmap */
137298580Sbr	ld	t0, PCB_L1ADDR(x13)
138298580Sbr	csrw	sptbr, t0
139295041Sbr
140295041Sbr	/* TODO: Invalidate the TLB */
141295041Sbr
142295041Sbr	sfence.vm
143295041Sbr
144295041Sbr	/* Release the old thread */
145295041Sbr	sd	a2, TD_LOCK(a0)
146295041Sbr#if defined(SCHED_ULE) && defined(SMP)
147295972Sbr	/* Spin if TD_LOCK points to a blocked_lock */
148295972Sbr	la	a2, _C_LABEL(blocked_lock)
149295972Sbr1:
150295972Sbr	ld	t0, TD_LOCK(a1)
151295972Sbr	beq	t0, a2, 1b
152295041Sbr#endif
153295041Sbr
154295041Sbr	/* Restore the registers */
155295041Sbr	ld	ra, (PCB_RA)(x13)
156295041Sbr	ld	sp, (PCB_SP)(x13)
157295041Sbr
158295041Sbr	/* s[0-11] */
159295041Sbr	ld	s0, (PCB_S + 0 * 8)(x13)
160295041Sbr	ld	s1, (PCB_S + 1 * 8)(x13)
161295041Sbr	ld	s2, (PCB_S + 2 * 8)(x13)
162295041Sbr	ld	s3, (PCB_S + 3 * 8)(x13)
163295041Sbr	ld	s4, (PCB_S + 4 * 8)(x13)
164295041Sbr	ld	s5, (PCB_S + 5 * 8)(x13)
165295041Sbr	ld	s6, (PCB_S + 6 * 8)(x13)
166295041Sbr	ld	s7, (PCB_S + 7 * 8)(x13)
167295041Sbr	ld	s8, (PCB_S + 8 * 8)(x13)
168295041Sbr	ld	s9, (PCB_S + 9 * 8)(x13)
169295041Sbr	ld	s10, (PCB_S + 10 * 8)(x13)
170295041Sbr	ld	s11, (PCB_S + 11 * 8)(x13)
171295041Sbr	ret
172295041Sbr.Lcpu_switch_panic_str:
173295041Sbr	.asciz "cpu_switch: %p\0"
174295041SbrEND(cpu_switch)
175295041Sbr
176295041Sbr/*
177295041Sbr * fork_exit(void (*callout)(void *, struct trapframe *), void *arg,
178295041Sbr *  struct trapframe *frame)
179295041Sbr */
180295041Sbr
181295041SbrENTRY(fork_trampoline)
182295697Sbr	mv	a0, s0
183295697Sbr	mv	a1, s1
184295041Sbr	mv	a2, sp
185295041Sbr	call	_C_LABEL(fork_exit)
186295041Sbr
187295041Sbr	/* Restore sstatus */
188295041Sbr	ld	t0, (TF_SSTATUS)(sp)
189295041Sbr	/* Ensure interrupts disabled */
190295041Sbr	li	t1, ~SSTATUS_IE
191295041Sbr	and	t0, t0, t1
192295041Sbr	csrw	sstatus, t0
193295041Sbr
194295041Sbr	/* Restore exception program counter */
195295041Sbr	ld	t0, (TF_SEPC)(sp)
196295041Sbr	csrw	sepc, t0
197295041Sbr
198295041Sbr	/* Restore the registers */
199295041Sbr	ld	t0, (TF_T + 0 * 8)(sp)
200295041Sbr	ld	t1, (TF_T + 1 * 8)(sp)
201295041Sbr	ld	t2, (TF_T + 2 * 8)(sp)
202295041Sbr	ld	t3, (TF_T + 3 * 8)(sp)
203295041Sbr	ld	t4, (TF_T + 4 * 8)(sp)
204295041Sbr	ld	t5, (TF_T + 5 * 8)(sp)
205295041Sbr	ld	t6, (TF_T + 6 * 8)(sp)
206295041Sbr
207295041Sbr	ld	s0, (TF_S + 0 * 8)(sp)
208295041Sbr	ld	s1, (TF_S + 1 * 8)(sp)
209295041Sbr	ld	s2, (TF_S + 2 * 8)(sp)
210295041Sbr	ld	s3, (TF_S + 3 * 8)(sp)
211295041Sbr	ld	s4, (TF_S + 4 * 8)(sp)
212295041Sbr	ld	s5, (TF_S + 5 * 8)(sp)
213295041Sbr	ld	s6, (TF_S + 6 * 8)(sp)
214295041Sbr	ld	s7, (TF_S + 7 * 8)(sp)
215295041Sbr	ld	s8, (TF_S + 8 * 8)(sp)
216295041Sbr	ld	s9, (TF_S + 9 * 8)(sp)
217295041Sbr	ld	s10, (TF_S + 10 * 8)(sp)
218295041Sbr	ld	s11, (TF_S + 11 * 8)(sp)
219295041Sbr
220295041Sbr	ld	a0, (TF_A + 0 * 8)(sp)
221295041Sbr	ld	a1, (TF_A + 1 * 8)(sp)
222295041Sbr	ld	a2, (TF_A + 2 * 8)(sp)
223295041Sbr	ld	a3, (TF_A + 3 * 8)(sp)
224295041Sbr	ld	a4, (TF_A + 4 * 8)(sp)
225295041Sbr	ld	a5, (TF_A + 5 * 8)(sp)
226295041Sbr	ld	a6, (TF_A + 6 * 8)(sp)
227295041Sbr	ld	a7, (TF_A + 7 * 8)(sp)
228295041Sbr
229295253Sbr	/* Load user ra and sp */
230295253Sbr	ld	tp, (TF_TP)(sp)
231295253Sbr	ld	ra, (TF_RA)(sp)
232295253Sbr
233295253Sbr	/*
234295253Sbr	 * Store our pcpup on stack, we will load it back
235295253Sbr	 * on kernel mode trap.
236295253Sbr	 */
237295253Sbr	sd	gp, (TF_SIZE)(sp)
238295253Sbr	ld	gp, (TF_GP)(sp)
239295253Sbr
240295041Sbr	/* Save kernel stack so we can use it doing a user trap */
241295253Sbr	addi	sp, sp, TF_SIZE
242295041Sbr	csrw	sscratch, sp
243295041Sbr
244295253Sbr	/* Load user stack */
245295253Sbr	ld	sp, (TF_SP - TF_SIZE)(sp)
246295041Sbr
247295041Sbr	eret
248295041SbrEND(fork_trampoline)
249295041Sbr
250295041SbrENTRY(savectx)
251295698Sbr	/* Store ra, sp and the callee-saved registers */
252295698Sbr	sd	ra, (PCB_RA)(a0)
253295698Sbr	sd	sp, (PCB_SP)(a0)
254295698Sbr
255295698Sbr	/* s[0-11] */
256295698Sbr	sd	s0, (PCB_S + 0 * 8)(a0)
257295698Sbr	sd	s1, (PCB_S + 1 * 8)(a0)
258295698Sbr	sd	s2, (PCB_S + 2 * 8)(a0)
259295698Sbr	sd	s3, (PCB_S + 3 * 8)(a0)
260295698Sbr	sd	s4, (PCB_S + 4 * 8)(a0)
261295698Sbr	sd	s5, (PCB_S + 5 * 8)(a0)
262295698Sbr	sd	s6, (PCB_S + 6 * 8)(a0)
263295698Sbr	sd	s7, (PCB_S + 7 * 8)(a0)
264295698Sbr	sd	s8, (PCB_S + 8 * 8)(a0)
265295698Sbr	sd	s9, (PCB_S + 9 * 8)(a0)
266295698Sbr	sd	s10, (PCB_S + 10 * 8)(a0)
267295698Sbr	sd	s11, (PCB_S + 11 * 8)(a0)
268295698Sbr
269295698Sbr	/* Store the VFP registers */
270295698Sbr#ifdef VFP
271295698Sbr	/* TODO */
272295698Sbr#endif
273295698Sbr	ret
274295041SbrEND(savectx)
275