1/*	$NetBSD: fusu.S,v 1.10 2003/12/01 13:34:44 rearnsha Exp $	*/
2
3/*-
4 * Copyright (c) 1996-1998 Mark Brinicombe.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by Mark Brinicombe
18 * 4. The name of the company nor the name of the author may be used to
19 *    endorse or promote products derived from this software without specific
20 *    prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * 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
36#include <machine/asm.h>
37#include <machine/armreg.h>
38#include "assym.s"
39__FBSDID("$FreeBSD$");
40
41	.syntax	unified
42
43#if __ARM_ARCH >= 6
44#define GET_PCB(tmp) \
45	mrc p15, 0, tmp, c13, c0, 4; \
46	add	tmp, tmp, #(TD_PCB)
47#else
48.Lcurpcb:
49	.word	_C_LABEL(__pcpu) + PC_CURPCB
50#define GET_PCB(tmp) \
51	ldr	tmp, .Lcurpcb
52#endif
53
54/*
55 * casueword32(volatile uint32_t *base, uint32_t oldval, uint32_t *oldvalp,
56 *    uint32_t newval);
57 */
58
59ENTRY(casueword)
60EENTRY_NP(casueword32)
61	stmfd	sp!, {r4, r5, r6}
62
63	ldr	r4, =(VM_MAXUSER_ADDRESS-3)
64	cmp	r0, r4
65	mvncs	r0, #0
66	bcs	2f
67
68	GET_PCB(r6)
69	ldr	r6, [r6]
70
71#ifdef DIAGNOSTIC
72	teq	r6, #0x00000000
73	ldmfdeq	sp!, {r4, r5, r6}
74	beq	.Lfusupcbfault
75#endif
76
77	adr	r4, .Lcasuwordfault
78	str	r4, [r6, #PCB_ONFAULT]
79
80#if __ARM_ARCH >= 6
811:
82	ldrex	r4, [r0]
83	cmp	r4, r1
84	strexeq	r5, r3, [r0]
85	cmpeq	r5, #1
86	beq	1b
87#else
88	ldrt	r4, [r0]
89	cmp	r4, r1
90	strteq	r3, [r0]
91#endif
92	str	r4, [r2]
93	mov	r0, #0
94	str	r0, [r6, #PCB_ONFAULT]
952:
96	ldmfd	sp!, {r4, r5, r6}
97	RET
98EEND(casueword32)
99END(casueword)
100
101/*
102 * Handle faults from casuword.  Clean up and return -1.
103 */
104
105.Lcasuwordfault:
106	mov	r0, #0x00000000
107	str	r0, [r6, #PCB_ONFAULT]
108	mvn	r0, #0
109	ldmfd	sp!, {r4, r5, r6}
110	RET
111
112/*
113 * fueword(caddr_t uaddr, long *val);
114 * Fetch an int from the user's address space.
115 */
116
117ENTRY(fueword)
118EENTRY_NP(fueword32)
119	ldr	r3, =(VM_MAXUSER_ADDRESS-3)
120	cmp	r0, r3
121	mvncs	r0, #0
122	RETc(cs)
123
124	GET_PCB(r2)
125	ldr	r2, [r2]
126
127#ifdef DIAGNOSTIC
128	teq	r2, #0x00000000
129	beq	.Lfusupcbfault
130#endif
131
132	adr	r3, .Lfusufault
133	str	r3, [r2, #PCB_ONFAULT]
134
135	ldrt	r3, [r0]
136	str	r3, [r1]
137
138	mov	r0, #0x00000000
139	str	r0, [r2, #PCB_ONFAULT]
140	RET
141EEND(fueword32)
142END(fueword)
143
144/*
145 * fusword(caddr_t uaddr);
146 * Fetch a short from the user's address space.
147 */
148
149ENTRY(fusword)
150	ldr	r3, =(VM_MAXUSER_ADDRESS-1)
151	cmp	r0, r3
152	mvncs	r0, #0
153	RETc(cs)
154
155	GET_PCB(r2)
156	ldr	r2, [r2]
157
158#ifdef DIAGNOSTIC
159	teq	r2, #0x00000000
160	beq	.Lfusupcbfault
161#endif
162
163	adr	r1, .Lfusufault
164	str	r1, [r2, #PCB_ONFAULT]
165
166	ldrbt	r3, [r0], #1
167	ldrbt	ip, [r0]
168#ifdef __ARMEB__
169	orr	r0, ip, r3, asl #8
170#else
171	orr	r0, r3, ip, asl #8
172#endif
173	mov	r1, #0x00000000
174	str	r1, [r2, #PCB_ONFAULT]
175	RET
176END(fusword)
177
178/*
179 * fuswintr(caddr_t uaddr);
180 * Fetch a short from the user's address space.  Can be called during an
181 * interrupt.
182 */
183
184ENTRY(fuswintr)
185	mov	r0, #-1
186	RET
187END(fuswintr)
188
189/*
190 * fubyte(caddr_t uaddr);
191 * Fetch a byte from the user's address space.
192 */
193
194ENTRY(fubyte)
195	ldr	r3, =VM_MAXUSER_ADDRESS
196	cmp	r0, r3
197	mvncs	r0, #0
198	RETc(cs)
199
200	GET_PCB(r2)
201	ldr	r2, [r2]
202
203#ifdef DIAGNOSTIC
204	teq	r2, #0x00000000
205	beq	.Lfusupcbfault
206#endif
207
208	adr	r1, .Lfusufault
209	str	r1, [r2, #PCB_ONFAULT]
210
211	ldrbt	r3, [r0]
212
213	mov	r1, #0x00000000
214	str	r1, [r2, #PCB_ONFAULT]
215	mov	r0, r3
216	RET
217END(fubyte)
218
219/*
220 * Handle faults from [fs]u*().  Clean up and return -1.
221 */
222
223.Lfusufault:
224	mov	r0, #0x00000000
225	str	r0, [r2, #PCB_ONFAULT]
226	mvn	r0, #0x00000000
227	RET
228
229#ifdef DIAGNOSTIC
230/*
231 * Handle earlier faults from [fs]u*(), due to no pcb
232 */
233
234.Lfusupcbfault:
235	mov	r1, r0
236	adr	r0, fusupcbfaulttext
237	b	_C_LABEL(panic)
238
239fusupcbfaulttext:
240	.asciz	"Yikes - no valid PCB during fusuxxx() addr=%08x\n"
241	.align	2
242#endif
243
244/*
245 * suword(caddr_t uaddr, int x);
246 * Store an int in the user's address space.
247 */
248
249ENTRY(suword)
250EENTRY_NP(suword32)
251	ldr	r3, =(VM_MAXUSER_ADDRESS-3)
252	cmp	r0, r3
253	mvncs	r0, #0
254	RETc(cs)
255
256	GET_PCB(r2)
257	ldr	r2, [r2]
258
259#ifdef DIAGNOSTIC
260	teq	r2, #0x00000000
261	beq	.Lfusupcbfault
262#endif
263
264	adr	r3, .Lfusufault
265	str	r3, [r2, #PCB_ONFAULT]
266
267	strt	r1, [r0]
268
269	mov	r0, #0x00000000
270	str	r0, [r2, #PCB_ONFAULT]
271	RET
272EEND(suword32)
273END(suword)
274
275/*
276 * suswintr(caddr_t uaddr, short x);
277 * Store a short in the user's address space.  Can be called during an
278 * interrupt.
279 */
280
281ENTRY(suswintr)
282	mov	r0, #-1
283	RET
284END(suswintr)
285
286/*
287 * susword(caddr_t uaddr, short x);
288 * Store a short in the user's address space.
289 */
290
291ENTRY(susword)
292	ldr	r3, =(VM_MAXUSER_ADDRESS-1)
293	cmp	r0, r3
294	mvncs	r0, #0
295	RETc(cs)
296
297	GET_PCB(r2)
298	ldr	r2, [r2]
299
300#ifdef DIAGNOSTIC
301	teq	r2, #0x00000000
302	beq	.Lfusupcbfault
303#endif
304
305	adr	r3, .Lfusufault
306	str	r3, [r2, #PCB_ONFAULT]
307
308#ifdef __ARMEB__
309	mov	ip, r1, lsr #8
310	strbt	ip, [r0], #1
311#else
312	strbt	r1, [r0], #1
313	mov	r1, r1, lsr #8
314#endif
315	strbt	r1, [r0]
316
317	mov	r0, #0x00000000
318	str	r0, [r2, #PCB_ONFAULT]
319	RET
320END(susword)
321
322/*
323 * subyte(caddr_t uaddr, char x);
324 * Store a byte in the user's address space.
325 */
326
327ENTRY(subyte)
328	ldr	r3, =VM_MAXUSER_ADDRESS
329	cmp	r0, r3
330	mvncs	r0, #0
331	RETc(cs)
332
333	GET_PCB(r2)
334	ldr	r2, [r2]
335
336
337#ifdef DIAGNOSTIC
338	teq	r2, #0x00000000
339	beq	.Lfusupcbfault
340#endif
341
342	adr	r3, .Lfusufault
343	str	r3, [r2, #PCB_ONFAULT]
344
345	strbt	r1, [r0]
346	mov	r0, #0x00000000
347	str	r0, [r2, #PCB_ONFAULT]
348	RET
349END(subyte)
350