fusu.S revision 256748
1129198Scognet/*	$NetBSD: fusu.S,v 1.10 2003/12/01 13:34:44 rearnsha Exp $	*/
2129198Scognet
3139735Simp/*-
4129198Scognet * Copyright (c) 1996-1998 Mark Brinicombe.
5129198Scognet * All rights reserved.
6129198Scognet *
7129198Scognet * Redistribution and use in source and binary forms, with or without
8129198Scognet * modification, are permitted provided that the following conditions
9129198Scognet * are met:
10129198Scognet * 1. Redistributions of source code must retain the above copyright
11129198Scognet *    notice, this list of conditions and the following disclaimer.
12129198Scognet * 2. Redistributions in binary form must reproduce the above copyright
13129198Scognet *    notice, this list of conditions and the following disclaimer in the
14129198Scognet *    documentation and/or other materials provided with the distribution.
15129198Scognet * 3. All advertising materials mentioning features or use of this software
16129198Scognet *    must display the following acknowledgement:
17129198Scognet *	This product includes software developed by Mark Brinicombe
18129198Scognet * 4. The name of the company nor the name of the author may be used to
19129198Scognet *    endorse or promote products derived from this software without specific
20129198Scognet *    prior written permission.
21129198Scognet *
22129198Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23129198Scognet * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24129198Scognet * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25129198Scognet * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
26129198Scognet * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27129198Scognet * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28129198Scognet * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32129198Scognet * SUCH DAMAGE.
33129198Scognet *
34129198Scognet */
35129198Scognet
36129198Scognet#include <machine/asm.h>
37129198Scognet#include <machine/asmacros.h>
38129198Scognet#include <machine/armreg.h>
39129198Scognet#include "assym.s"
40129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/fusu.S 256748 2013-10-18 17:21:47Z cognet $");
41129198Scognet
42239268Sgonzo#ifdef _ARM_ARCH_6
43239268Sgonzo#define GET_PCB(tmp) \
44239268Sgonzo	mrc p15, 0, tmp, c13, c0, 4; \
45239268Sgonzo	add	tmp, tmp, #(PC_CURPCB)
46129198Scognet#else
47129198Scognet.Lcurpcb:
48129198Scognet	.word	_C_LABEL(__pcpu) + PC_CURPCB
49239268Sgonzo#define GET_PCB(tmp) \
50239268Sgonzo	ldr	tmp, .Lcurpcb
51129198Scognet#endif
52129198Scognet
53129198Scognet/*
54129198Scognet * fuword(caddr_t uaddr);
55129198Scognet * Fetch an int from the user's address space.
56129198Scognet */
57129198Scognet
58161734ScognetENTRY_NP(casuword32)
59163449SdavidxuENTRY(casuword)
60239268Sgonzo	GET_PCB(r3)
61137271Scognet	ldr	r3, [r3]
62137271Scognet
63137271Scognet#ifdef DIAGNOSTIC
64137271Scognet	teq	r3, #0x00000000
65137271Scognet	beq	.Lfusupcbfault
66137271Scognet#endif
67145452Scognet	stmfd	sp!, {r4, r5}
68163449Sdavidxu	adr	r4, .Lcasuwordfault
69137271Scognet	str	r4, [r3, #PCB_ONFAULT]
70256691Scognet#ifdef _ARM_ARCH_6
71256691Scognet1:
72256691Scognet	cmp     r0, #KERNBASE
73256748Scognet	mvnhs   r0, #0
74256748Scognet	bhs     2f
75256691Scognet
76256691Scognet	ldrex   r5, [r0]
77256691Scognet	cmp     r5, r1
78256691Scognet	movne   r0, r5
79256691Scognet	bne     2f
80256691Scognet	strex   r5, r2, [r0]
81256691Scognet	cmp     r5, #0
82256691Scognet	bne     1b
83256691Scognet#else
84145452Scognet	ldrt	r5, [r0]
85145452Scognet	cmp	r5, r1
86145452Scognet	movne	r0, r5
87145452Scognet	streqt	r2, [r0]
88256691Scognet#endif
89145452Scognet	moveq	r0, r1
90256691Scognet2:
91145452Scognet	ldmfd	sp!, {r4, r5}
92137271Scognet	mov	r1, #0x00000000
93137271Scognet	str	r1, [r3, #PCB_ONFAULT]
94137463Scognet	RET
95248361SandrewEND(casuword32)
96248361SandrewEND(casuword)
97137271Scognet
98137271Scognet/*
99163449Sdavidxu * Handle faults from casuword.  Clean up and return -1.
100145452Scognet */
101145452Scognet
102163449Sdavidxu.Lcasuwordfault:
103145452Scognet	mov	r0, #0x00000000
104145452Scognet	str	r0, [r3, #PCB_ONFAULT]
105145452Scognet	mvn	r0, #0x00000000
106145452Scognet	ldmfd	sp!, {r4, r5}
107145452Scognet	RET
108248361Sandrew
109145452Scognet/*
110137271Scognet * fuword(caddr_t uaddr);
111137271Scognet * Fetch an int from the user's address space.
112137271Scognet */
113137271Scognet
114161734ScognetENTRY_NP(fuword32)
115129198ScognetENTRY(fuword)
116239268Sgonzo	GET_PCB(r2)
117129198Scognet	ldr	r2, [r2]
118129198Scognet
119129198Scognet#ifdef DIAGNOSTIC
120129198Scognet	teq	r2, #0x00000000
121129198Scognet	beq	.Lfusupcbfault
122129198Scognet#endif
123129198Scognet
124129198Scognet	adr	r1, .Lfusufault
125129198Scognet	str	r1, [r2, #PCB_ONFAULT]
126129198Scognet
127129198Scognet	ldrt	r3, [r0]
128129198Scognet
129129198Scognet	mov	r1, #0x00000000
130129198Scognet	str	r1, [r2, #PCB_ONFAULT]
131129198Scognet	mov	r0, r3
132137463Scognet	RET
133248361SandrewEND(fuword32)
134248361SandrewEND(fuword)
135129198Scognet
136129198Scognet/*
137129198Scognet * fusword(caddr_t uaddr);
138129198Scognet * Fetch a short from the user's address space.
139129198Scognet */
140129198Scognet
141129198ScognetENTRY(fusword)
142239268Sgonzo	GET_PCB(r2)
143129198Scognet	ldr	r2, [r2]
144129198Scognet
145129198Scognet#ifdef DIAGNOSTIC
146129198Scognet	teq	r2, #0x00000000
147129198Scognet	beq	.Lfusupcbfault
148129198Scognet#endif
149129198Scognet
150129198Scognet	adr	r1, .Lfusufault
151129198Scognet	str	r1, [r2, #PCB_ONFAULT]
152129198Scognet
153129198Scognet	ldrbt	r3, [r0], #1
154129198Scognet	ldrbt	ip, [r0]
155129198Scognet#ifdef __ARMEB__
156129198Scognet	orr	r0, ip, r3, asl #8
157129198Scognet#else
158129198Scognet	orr	r0, r3, ip, asl #8
159129198Scognet#endif
160129198Scognet	mov	r1, #0x00000000
161129198Scognet	str	r1, [r2, #PCB_ONFAULT]
162137463Scognet	RET
163248361SandrewEND(fusword)
164129198Scognet
165129198Scognet/*
166129198Scognet * fuswintr(caddr_t uaddr);
167129198Scognet * Fetch a short from the user's address space.  Can be called during an
168129198Scognet * interrupt.
169129198Scognet */
170129198Scognet
171129198ScognetENTRY(fuswintr)
172129198Scognet	ldr	r2, Lblock_userspace_access
173129198Scognet	ldr	r2, [r2]
174129198Scognet	teq	r2, #0
175129198Scognet	mvnne	r0, #0x00000000
176137463Scognet	RETne
177129198Scognet
178239268Sgonzo	GET_PCB(r2)
179129198Scognet	ldr	r2, [r2]
180129198Scognet
181129198Scognet#ifdef DIAGNOSTIC
182129198Scognet	teq	r2, #0x00000000
183129198Scognet	beq	.Lfusupcbfault
184129198Scognet#endif
185129198Scognet
186129198Scognet	adr	r1, _C_LABEL(fusubailout)
187129198Scognet	str	r1, [r2, #PCB_ONFAULT]
188129198Scognet
189129198Scognet	ldrbt	r3, [r0], #1
190129198Scognet	ldrbt	ip, [r0]
191129198Scognet#ifdef __ARMEB__
192129198Scognet	orr	r0, ip, r3, asl #8
193129198Scognet#else
194129198Scognet	orr	r0, r3, ip, asl #8
195129198Scognet#endif
196129198Scognet
197129198Scognet	mov	r1, #0x00000000
198129198Scognet	str	r1, [r2, #PCB_ONFAULT]
199137463Scognet	RET
200248361SandrewEND(fuswintr)
201129198Scognet
202129198ScognetLblock_userspace_access:
203129198Scognet	.word	_C_LABEL(block_userspace_access)
204129198Scognet
205129198Scognet	.data
206129198Scognet	.align	0
207129198Scognet	.global	_C_LABEL(block_userspace_access)
208129198Scognet_C_LABEL(block_userspace_access):
209129198Scognet	.word	0
210129198Scognet	.text
211129198Scognet
212129198Scognet/*
213129198Scognet * fubyte(caddr_t uaddr);
214129198Scognet * Fetch a byte from the user's address space.
215129198Scognet */
216129198Scognet
217129198ScognetENTRY(fubyte)
218239268Sgonzo	GET_PCB(r2)
219129198Scognet	ldr	r2, [r2]
220129198Scognet
221129198Scognet#ifdef DIAGNOSTIC
222129198Scognet	teq	r2, #0x00000000
223129198Scognet	beq	.Lfusupcbfault
224129198Scognet#endif
225129198Scognet
226129198Scognet	adr	r1, .Lfusufault
227129198Scognet	str	r1, [r2, #PCB_ONFAULT]
228129198Scognet
229129198Scognet	ldrbt	r3, [r0]
230129198Scognet
231129198Scognet	mov	r1, #0x00000000
232129198Scognet	str	r1, [r2, #PCB_ONFAULT]
233129198Scognet	mov	r0, r3
234137463Scognet	RET
235248361SandrewEND(fubyte)
236129198Scognet
237129198Scognet/*
238129198Scognet * Handle faults from [fs]u*().  Clean up and return -1.
239129198Scognet */
240129198Scognet
241129198Scognet.Lfusufault:
242129198Scognet	mov	r0, #0x00000000
243129198Scognet	str	r0, [r2, #PCB_ONFAULT]
244129198Scognet	mvn	r0, #0x00000000
245137463Scognet	RET
246129198Scognet
247129198Scognet/*
248129198Scognet * Handle faults from [fs]u*().  Clean up and return -1.  This differs from
249129198Scognet * fusufault() in that trap() will recognise it and return immediately rather
250129198Scognet * than trying to page fault.
251129198Scognet */
252129198Scognet
253129198Scognet/* label must be global as fault.c references it */
254129198Scognet	.global	_C_LABEL(fusubailout)
255129198Scognet_C_LABEL(fusubailout):
256129198Scognet	mov	r0, #0x00000000
257129198Scognet	str	r0, [r2, #PCB_ONFAULT]
258129198Scognet	mvn	r0, #0x00000000
259137463Scognet	RET
260129198Scognet
261129198Scognet#ifdef DIAGNOSTIC
262129198Scognet/*
263129198Scognet * Handle earlier faults from [fs]u*(), due to no pcb
264129198Scognet */
265129198Scognet
266129198Scognet.Lfusupcbfault:
267129198Scognet	mov	r1, r0
268129198Scognet	adr	r0, fusupcbfaulttext
269129198Scognet	b	_C_LABEL(panic)
270129198Scognet
271129198Scognetfusupcbfaulttext:
272129198Scognet	.asciz	"Yikes - no valid PCB during fusuxxx() addr=%08x\n"
273129198Scognet	.align	0
274129198Scognet#endif
275129198Scognet
276129198Scognet/*
277129198Scognet * suword(caddr_t uaddr, int x);
278129198Scognet * Store an int in the user's address space.
279129198Scognet */
280129198Scognet
281161734ScognetENTRY_NP(suword32)
282129198ScognetENTRY(suword)
283239268Sgonzo	GET_PCB(r2)
284129198Scognet	ldr	r2, [r2]
285129198Scognet
286129198Scognet#ifdef DIAGNOSTIC
287129198Scognet	teq	r2, #0x00000000
288129198Scognet	beq	.Lfusupcbfault
289129198Scognet#endif
290129198Scognet
291129198Scognet	adr	r3, .Lfusufault
292129198Scognet	str	r3, [r2, #PCB_ONFAULT]
293129198Scognet
294129198Scognet	strt	r1, [r0]
295129198Scognet
296129198Scognet	mov	r0, #0x00000000
297129198Scognet	str	r0, [r2, #PCB_ONFAULT]
298137463Scognet	RET
299248361SandrewEND(suword32)
300248361SandrewEND(suword)
301129198Scognet
302129198Scognet/*
303129198Scognet * suswintr(caddr_t uaddr, short x);
304129198Scognet * Store a short in the user's address space.  Can be called during an
305129198Scognet * interrupt.
306129198Scognet */
307129198Scognet
308129198ScognetENTRY(suswintr)
309129198Scognet	ldr	r2, Lblock_userspace_access
310129198Scognet	ldr	r2, [r2]
311129198Scognet	teq	r2, #0
312129198Scognet	mvnne	r0, #0x00000000
313137463Scognet	RETne
314129198Scognet
315239268Sgonzo	GET_PCB(r2)
316129198Scognet	ldr	r2, [r2]
317129198Scognet
318129198Scognet#ifdef DIAGNOSTIC
319129198Scognet	teq	r2, #0x00000000
320129198Scognet	beq	.Lfusupcbfault
321129198Scognet#endif
322129198Scognet
323129198Scognet	adr	r3, _C_LABEL(fusubailout)
324129198Scognet	str	r3, [r2, #PCB_ONFAULT]
325129198Scognet
326129198Scognet#ifdef __ARMEB__
327129198Scognet	mov	ip, r1, lsr #8
328129198Scognet	strbt	ip, [r0], #1
329129198Scognet#else
330129198Scognet	strbt	r1, [r0], #1
331129198Scognet	mov	r1, r1, lsr #8
332129198Scognet#endif
333129198Scognet	strbt	r1, [r0]
334129198Scognet
335129198Scognet	mov	r0, #0x00000000
336129198Scognet	str	r0, [r2, #PCB_ONFAULT]
337137463Scognet	RET
338248361SandrewEND(suswintr)
339129198Scognet
340129198Scognet/*
341129198Scognet * susword(caddr_t uaddr, short x);
342129198Scognet * Store a short in the user's address space.
343129198Scognet */
344129198Scognet
345129198ScognetENTRY(susword)
346239268Sgonzo	GET_PCB(r2)
347129198Scognet	ldr	r2, [r2]
348129198Scognet
349129198Scognet#ifdef DIAGNOSTIC
350129198Scognet	teq	r2, #0x00000000
351129198Scognet	beq	.Lfusupcbfault
352129198Scognet#endif
353129198Scognet
354129198Scognet	adr	r3, .Lfusufault
355129198Scognet	str	r3, [r2, #PCB_ONFAULT]
356129198Scognet
357129198Scognet#ifdef __ARMEB__
358129198Scognet	mov	ip, r1, lsr #8
359129198Scognet	strbt	ip, [r0], #1
360129198Scognet#else
361129198Scognet	strbt	r1, [r0], #1
362129198Scognet	mov	r1, r1, lsr #8
363129198Scognet#endif
364129198Scognet	strbt	r1, [r0]
365129198Scognet
366129198Scognet	mov	r0, #0x00000000
367129198Scognet	str	r0, [r2, #PCB_ONFAULT]
368137463Scognet	RET
369248361SandrewEND(susword)
370129198Scognet
371129198Scognet/*
372129198Scognet * subyte(caddr_t uaddr, char x);
373129198Scognet * Store a byte in the user's address space.
374129198Scognet */
375129198Scognet
376129198ScognetENTRY(subyte)
377239268Sgonzo	GET_PCB(r2)
378129198Scognet	ldr	r2, [r2]
379129198Scognet
380129198Scognet
381129198Scognet#ifdef DIAGNOSTIC
382129198Scognet	teq	r2, #0x00000000
383129198Scognet	beq	.Lfusupcbfault
384129198Scognet#endif
385129198Scognet
386129198Scognet	adr	r3, .Lfusufault
387129198Scognet	str	r3, [r2, #PCB_ONFAULT]
388129198Scognet
389129198Scognet	strbt	r1, [r0]
390129198Scognet	mov	r0, #0x00000000
391129198Scognet	str	r0, [r2, #PCB_ONFAULT]
392137463Scognet	RET
393248361SandrewEND(subyte)
394248361Sandrew
395