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