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