fusu.S revision 275520
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: head/sys/arm/arm/fusu.S 275520 2014-12-05 19:08:36Z andrew $");
40
41	.syntax	unified
42
43#ifdef _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 * fuword(caddr_t uaddr);
56 * Fetch an int from the user's address space.
57 */
58
59ENTRY(casuword)
60EENTRY_NP(casuword32)
61	GET_PCB(r3)
62	ldr	r3, [r3]
63
64#ifdef DIAGNOSTIC
65	teq	r3, #0x00000000
66	beq	.Lfusupcbfault
67#endif
68	stmfd	sp!, {r4, r5}
69	adr	r4, .Lcasuwordfault
70	str	r4, [r3, #PCB_ONFAULT]
71#ifdef _ARM_ARCH_6
721:
73	cmp     r0, #KERNBASE
74	mvnhs   r0, #0
75	bhs     2f
76
77	ldrex   r5, [r0]
78	cmp     r5, r1
79	movne   r0, r5
80	bne     2f
81	strex   r5, r2, [r0]
82	cmp     r5, #0
83	bne     1b
84#else
85	ldrt	r5, [r0]
86	cmp	r5, r1
87	movne	r0, r5
88	strteq	r2, [r0]
89#endif
90	moveq	r0, r1
912:
92	ldmfd	sp!, {r4, r5}
93	mov	r1, #0x00000000
94	str	r1, [r3, #PCB_ONFAULT]
95	RET
96EEND(casuword32)
97END(casuword)
98
99/*
100 * Handle faults from casuword.  Clean up and return -1.
101 */
102
103.Lcasuwordfault:
104	mov	r0, #0x00000000
105	str	r0, [r3, #PCB_ONFAULT]
106	mvn	r0, #0x00000000
107	ldmfd	sp!, {r4, r5}
108	RET
109
110/*
111 * fuword(caddr_t uaddr);
112 * Fetch an int from the user's address space.
113 */
114
115ENTRY(fuword)
116EENTRY_NP(fuword32)
117	GET_PCB(r2)
118	ldr	r2, [r2]
119
120#ifdef DIAGNOSTIC
121	teq	r2, #0x00000000
122	beq	.Lfusupcbfault
123#endif
124
125	adr	r1, .Lfusufault
126	str	r1, [r2, #PCB_ONFAULT]
127
128	ldrt	r3, [r0]
129
130	mov	r1, #0x00000000
131	str	r1, [r2, #PCB_ONFAULT]
132	mov	r0, r3
133	RET
134EEND(fuword32)
135END(fuword)
136
137/*
138 * fusword(caddr_t uaddr);
139 * Fetch a short from the user's address space.
140 */
141
142ENTRY(fusword)
143	GET_PCB(r2)
144	ldr	r2, [r2]
145
146#ifdef DIAGNOSTIC
147	teq	r2, #0x00000000
148	beq	.Lfusupcbfault
149#endif
150
151	adr	r1, .Lfusufault
152	str	r1, [r2, #PCB_ONFAULT]
153
154	ldrbt	r3, [r0], #1
155	ldrbt	ip, [r0]
156#ifdef __ARMEB__
157	orr	r0, ip, r3, asl #8
158#else
159	orr	r0, r3, ip, asl #8
160#endif
161	mov	r1, #0x00000000
162	str	r1, [r2, #PCB_ONFAULT]
163	RET
164END(fusword)
165
166/*
167 * fuswintr(caddr_t uaddr);
168 * Fetch a short from the user's address space.  Can be called during an
169 * interrupt.
170 */
171
172ENTRY(fuswintr)
173	ldr	r2, Lblock_userspace_access
174	ldr	r2, [r2]
175	teq	r2, #0
176	mvnne	r0, #0x00000000
177	RETne
178
179	GET_PCB(r2)
180	ldr	r2, [r2]
181
182#ifdef DIAGNOSTIC
183	teq	r2, #0x00000000
184	beq	.Lfusupcbfault
185#endif
186
187	adr	r1, _C_LABEL(fusubailout)
188	str	r1, [r2, #PCB_ONFAULT]
189
190	ldrbt	r3, [r0], #1
191	ldrbt	ip, [r0]
192#ifdef __ARMEB__
193	orr	r0, ip, r3, asl #8
194#else
195	orr	r0, r3, ip, asl #8
196#endif
197
198	mov	r1, #0x00000000
199	str	r1, [r2, #PCB_ONFAULT]
200	RET
201END(fuswintr)
202
203Lblock_userspace_access:
204	.word	_C_LABEL(block_userspace_access)
205
206	.data
207	.align	0
208	.global	_C_LABEL(block_userspace_access)
209_C_LABEL(block_userspace_access):
210	.word	0
211	.text
212
213/*
214 * fubyte(caddr_t uaddr);
215 * Fetch a byte from the user's address space.
216 */
217
218ENTRY(fubyte)
219	GET_PCB(r2)
220	ldr	r2, [r2]
221
222#ifdef DIAGNOSTIC
223	teq	r2, #0x00000000
224	beq	.Lfusupcbfault
225#endif
226
227	adr	r1, .Lfusufault
228	str	r1, [r2, #PCB_ONFAULT]
229
230	ldrbt	r3, [r0]
231
232	mov	r1, #0x00000000
233	str	r1, [r2, #PCB_ONFAULT]
234	mov	r0, r3
235	RET
236END(fubyte)
237
238/*
239 * Handle faults from [fs]u*().  Clean up and return -1.
240 */
241
242.Lfusufault:
243	mov	r0, #0x00000000
244	str	r0, [r2, #PCB_ONFAULT]
245	mvn	r0, #0x00000000
246	RET
247
248/*
249 * Handle faults from [fs]u*().  Clean up and return -1.  This differs from
250 * fusufault() in that trap() will recognise it and return immediately rather
251 * than trying to page fault.
252 */
253
254/* label must be global as fault.c references it */
255	.global	_C_LABEL(fusubailout)
256_C_LABEL(fusubailout):
257	mov	r0, #0x00000000
258	str	r0, [r2, #PCB_ONFAULT]
259	mvn	r0, #0x00000000
260	RET
261
262#ifdef DIAGNOSTIC
263/*
264 * Handle earlier faults from [fs]u*(), due to no pcb
265 */
266
267.Lfusupcbfault:
268	mov	r1, r0
269	adr	r0, fusupcbfaulttext
270	b	_C_LABEL(panic)
271
272fusupcbfaulttext:
273	.asciz	"Yikes - no valid PCB during fusuxxx() addr=%08x\n"
274	.align	0
275#endif
276
277/*
278 * suword(caddr_t uaddr, int x);
279 * Store an int in the user's address space.
280 */
281
282ENTRY(suword)
283EENTRY_NP(suword32)
284	GET_PCB(r2)
285	ldr	r2, [r2]
286
287#ifdef DIAGNOSTIC
288	teq	r2, #0x00000000
289	beq	.Lfusupcbfault
290#endif
291
292	adr	r3, .Lfusufault
293	str	r3, [r2, #PCB_ONFAULT]
294
295	strt	r1, [r0]
296
297	mov	r0, #0x00000000
298	str	r0, [r2, #PCB_ONFAULT]
299	RET
300EEND(suword32)
301END(suword)
302
303/*
304 * suswintr(caddr_t uaddr, short x);
305 * Store a short in the user's address space.  Can be called during an
306 * interrupt.
307 */
308
309ENTRY(suswintr)
310	ldr	r2, Lblock_userspace_access
311	ldr	r2, [r2]
312	teq	r2, #0
313	mvnne	r0, #0x00000000
314	RETne
315
316	GET_PCB(r2)
317	ldr	r2, [r2]
318
319#ifdef DIAGNOSTIC
320	teq	r2, #0x00000000
321	beq	.Lfusupcbfault
322#endif
323
324	adr	r3, _C_LABEL(fusubailout)
325	str	r3, [r2, #PCB_ONFAULT]
326
327#ifdef __ARMEB__
328	mov	ip, r1, lsr #8
329	strbt	ip, [r0], #1
330#else
331	strbt	r1, [r0], #1
332	mov	r1, r1, lsr #8
333#endif
334	strbt	r1, [r0]
335
336	mov	r0, #0x00000000
337	str	r0, [r2, #PCB_ONFAULT]
338	RET
339END(suswintr)
340
341/*
342 * susword(caddr_t uaddr, short x);
343 * Store a short in the user's address space.
344 */
345
346ENTRY(susword)
347	GET_PCB(r2)
348	ldr	r2, [r2]
349
350#ifdef DIAGNOSTIC
351	teq	r2, #0x00000000
352	beq	.Lfusupcbfault
353#endif
354
355	adr	r3, .Lfusufault
356	str	r3, [r2, #PCB_ONFAULT]
357
358#ifdef __ARMEB__
359	mov	ip, r1, lsr #8
360	strbt	ip, [r0], #1
361#else
362	strbt	r1, [r0], #1
363	mov	r1, r1, lsr #8
364#endif
365	strbt	r1, [r0]
366
367	mov	r0, #0x00000000
368	str	r0, [r2, #PCB_ONFAULT]
369	RET
370END(susword)
371
372/*
373 * subyte(caddr_t uaddr, char x);
374 * Store a byte in the user's address space.
375 */
376
377ENTRY(subyte)
378	GET_PCB(r2)
379	ldr	r2, [r2]
380
381
382#ifdef DIAGNOSTIC
383	teq	r2, #0x00000000
384	beq	.Lfusupcbfault
385#endif
386
387	adr	r3, .Lfusufault
388	str	r3, [r2, #PCB_ONFAULT]
389
390	strbt	r1, [r0]
391	mov	r0, #0x00000000
392	str	r0, [r2, #PCB_ONFAULT]
393	RET
394END(subyte)
395