xref: /freebsd/sys/riscv/riscv/support.S (revision 6829dae12bb055451fa467da4589c43bd03b1e64)
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
35#include <machine/asm.h>
36__FBSDID("$FreeBSD$");
37
38#include <machine/setjmp.h>
39#include <machine/riscvreg.h>
40
41#include "assym.inc"
42
43/*
44 * One of the fu* or su* functions failed, return -1.
45 */
46ENTRY(fsu_fault)
47	SET_FAULT_HANDLER(x0, a1)	/* Reset the handler function */
48	EXIT_USER_ACCESS(a1)
49fsu_fault_nopcb:
50	li	a0, -1
51	ret
52END(fsu_fault)
53
54/*
55 * int casueword32(volatile uint32_t *, uint32_t, uint32_t *, uint32_t)
56 */
57ENTRY(casueword32)
58	li	a4, (VM_MAXUSER_ADDRESS-3)
59	bgt	a0, a4, fsu_fault_nopcb
60	la	a6, fsu_fault		/* Load the fault handler */
61	SET_FAULT_HANDLER(a6, a4)	/* And set it */
62	ENTER_USER_ACCESS(a4)
631:	lr.w	a4, 0(a0)		/* Load-exclusive the data */
64	bne	a4, a1, 2f		/* If not equal then exit */
65	sc.w	a5, a3, 0(a0)		/* Store the new data */
66	bnez	a5, 1b			/* Retry on failure */
672:	EXIT_USER_ACCESS(a5)
68	SET_FAULT_HANDLER(x0, a5)	/* Reset the fault handler */
69	sw	a4, 0(a2)		/* Store the read data */
70	li	a0, 0			/* Success */
71	ret				/* Return */
72END(casueword32)
73
74/*
75 * int casueword(volatile u_long *, u_long, u_long *, u_long)
76 */
77ENTRY(casueword)
78	li	a4, (VM_MAXUSER_ADDRESS-7)
79	bgt	a0, a4, fsu_fault_nopcb
80	la	a6, fsu_fault		/* Load the fault handler */
81	SET_FAULT_HANDLER(a6, a4)	/* And set it */
82	ENTER_USER_ACCESS(a4)
831:	lr.d	a4, 0(a0)		/* Load-exclusive the data */
84	bne	a4, a1, 2f		/* If not equal then exit */
85	sc.d	a5, a3, 0(a0)		/* Store the new data */
86	bnez	a5, 1b			/* Retry on failure */
872:	EXIT_USER_ACCESS(a5)
88	SET_FAULT_HANDLER(x0, a5)	/* Reset the fault handler */
89	sd	a4, 0(a2)		/* Store the read data */
90	li	a0, 0			/* Success */
91	ret				/* Return */
92END(casueword)
93
94/*
95 * int fubyte(volatile const void *)
96 */
97ENTRY(fubyte)
98	li	a1, VM_MAXUSER_ADDRESS
99	bgt	a0, a1, fsu_fault_nopcb
100	la	a6, fsu_fault		/* Load the fault handler */
101	SET_FAULT_HANDLER(a6, a1)	/* And set it */
102	ENTER_USER_ACCESS(a1)
103	lb	a0, 0(a0)		/* Try loading the data */
104	EXIT_USER_ACCESS(a1)
105	SET_FAULT_HANDLER(x0, a1)	/* Reset the fault handler */
106	ret				/* Return */
107END(fubyte)
108
109/*
110 * int fuword(volatile const void *)
111 */
112ENTRY(fuword16)
113	li	a1, (VM_MAXUSER_ADDRESS-1)
114	bgt	a0, a1, fsu_fault_nopcb
115	la	a6, fsu_fault		/* Load the fault handler */
116	SET_FAULT_HANDLER(a6, a1)	/* And set it */
117	ENTER_USER_ACCESS(a1)
118	lh	a0, 0(a0)		/* Try loading the data */
119	EXIT_USER_ACCESS(a1)
120	SET_FAULT_HANDLER(x0, a1)	/* Reset the fault handler */
121	ret				/* Return */
122END(fuword16)
123
124/*
125 * int32_t fueword32(volatile const void *, int32_t *)
126 */
127ENTRY(fueword32)
128	li	a2, (VM_MAXUSER_ADDRESS-3)
129	bgt	a0, a2, fsu_fault_nopcb
130	la	a6, fsu_fault		/* Load the fault handler */
131	SET_FAULT_HANDLER(a6, a2)	/* And set it */
132	ENTER_USER_ACCESS(a2)
133	lw	a0, 0(a0)		/* Try loading the data */
134	EXIT_USER_ACCESS(a2)
135	SET_FAULT_HANDLER(x0, a2)	/* Reset the fault handler */
136	sw	a0, 0(a1)		/* Save the data in kernel space */
137	li	a0, 0			/* Success */
138	ret				/* Return */
139END(fueword32)
140
141/*
142 * long fueword(volatile const void *, int64_t *)
143 * int64_t fueword64(volatile const void *, int64_t *)
144 */
145ENTRY(fueword)
146EENTRY(fueword64)
147	li	a2, (VM_MAXUSER_ADDRESS-7)
148	bgt	a0, a2, fsu_fault_nopcb
149	la	a6, fsu_fault		/* Load the fault handler */
150	SET_FAULT_HANDLER(a6, a2)	/* And set it */
151	ENTER_USER_ACCESS(a2)
152	ld	a0, 0(a0)		/* Try loading the data */
153	EXIT_USER_ACCESS(a2)
154	SET_FAULT_HANDLER(x0, a2)	/* Reset the fault handler */
155	sd	a0, 0(a1)		/* Save the data in kernel space */
156	li	a0, 0			/* Success */
157	ret				/* Return */
158EEND(fueword64)
159END(fueword)
160
161/*
162 * int subyte(volatile void *, int)
163 */
164ENTRY(subyte)
165	li	a2, VM_MAXUSER_ADDRESS
166	bgt	a0, a2, fsu_fault_nopcb
167	la	a6, fsu_fault		/* Load the fault handler */
168	SET_FAULT_HANDLER(a6, a2)	/* And set it */
169	ENTER_USER_ACCESS(a2)
170	sb	a1, 0(a0)		/* Try storing the data */
171	EXIT_USER_ACCESS(a2)
172	SET_FAULT_HANDLER(x0, a2)	/* Reset the fault handler */
173	li	a0, 0			/* Success */
174	ret				/* Return */
175END(subyte)
176
177/*
178 * int suword16(volatile void *, int)
179 */
180ENTRY(suword16)
181	li	a2, (VM_MAXUSER_ADDRESS-1)
182	bgt	a0, a2, fsu_fault_nopcb
183	la	a6, fsu_fault		/* Load the fault handler */
184	SET_FAULT_HANDLER(a6, a2)	/* And set it */
185	ENTER_USER_ACCESS(a2)
186	sh	a1, 0(a0)		/* Try storing the data */
187	EXIT_USER_ACCESS(a2)
188	SET_FAULT_HANDLER(x0, a2)	/* Reset the fault handler */
189	li	a0, 0			/* Success */
190	ret				/* Return */
191END(suword16)
192
193/*
194 * int suword32(volatile void *, int)
195 */
196ENTRY(suword32)
197	li	a2, (VM_MAXUSER_ADDRESS-3)
198	bgt	a0, a2, fsu_fault_nopcb
199	la	a6, fsu_fault		/* Load the fault handler */
200	SET_FAULT_HANDLER(a6, a2)	/* And set it */
201	ENTER_USER_ACCESS(a2)
202	sw	a1, 0(a0)		/* Try storing the data */
203	EXIT_USER_ACCESS(a2)
204	SET_FAULT_HANDLER(x0, a2)	/* Reset the fault handler */
205	li	a0, 0			/* Success */
206	ret				/* Return */
207END(suword32)
208
209/*
210 * int suword(volatile void *, long)
211 */
212ENTRY(suword)
213EENTRY(suword64)
214	li	a2, (VM_MAXUSER_ADDRESS-7)
215	bgt	a0, a2, fsu_fault_nopcb
216	la	a6, fsu_fault		/* Load the fault handler */
217	SET_FAULT_HANDLER(a6, a2)	/* And set it */
218	ENTER_USER_ACCESS(a2)
219	sd	a1, 0(a0)		/* Try storing the data */
220	EXIT_USER_ACCESS(a2)
221	SET_FAULT_HANDLER(x0, a2)	/* Reset the fault handler */
222	li	a0, 0			/* Success */
223	ret				/* Return */
224EEND(suword64)
225END(suword)
226
227ENTRY(setjmp)
228	/* Store the stack pointer */
229	sd	sp, 0(a0)
230	addi	a0, a0, 8
231
232	/* Store the general purpose registers and ra */
233	sd	s0, (0 * 8)(a0)
234	sd	s1, (1 * 8)(a0)
235	sd	s2, (2 * 8)(a0)
236	sd	s3, (3 * 8)(a0)
237	sd	s4, (4 * 8)(a0)
238	sd	s5, (5 * 8)(a0)
239	sd	s6, (6 * 8)(a0)
240	sd	s7, (7 * 8)(a0)
241	sd	s8, (8 * 8)(a0)
242	sd	s9, (9 * 8)(a0)
243	sd	s10, (10 * 8)(a0)
244	sd	s11, (11 * 8)(a0)
245	sd	ra, (12 * 8)(a0)
246
247	/* Return value */
248	li	a0, 0
249	ret
250END(setjmp)
251
252ENTRY(longjmp)
253	/* Restore the stack pointer */
254	ld	sp, 0(a0)
255	addi	a0, a0, 8
256
257	/* Restore the general purpose registers and ra */
258	ld	s0, (0 * 8)(a0)
259	ld	s1, (1 * 8)(a0)
260	ld	s2, (2 * 8)(a0)
261	ld	s3, (3 * 8)(a0)
262	ld	s4, (4 * 8)(a0)
263	ld	s5, (5 * 8)(a0)
264	ld	s6, (6 * 8)(a0)
265	ld	s7, (7 * 8)(a0)
266	ld	s8, (8 * 8)(a0)
267	ld	s9, (9 * 8)(a0)
268	ld	s10, (10 * 8)(a0)
269	ld	s11, (11 * 8)(a0)
270	ld	ra, (12 * 8)(a0)
271
272	/* Load the return value */
273	mv	a0, a1
274	ret
275END(longjmp)
276