fusu.S revision 269390
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/armreg.h>
38129198Scognet#include "assym.s"
39129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/fusu.S 269390 2014-08-01 18:24:44Z ian $");
40129198Scognet
41239268Sgonzo#ifdef _ARM_ARCH_6
42239268Sgonzo#define GET_PCB(tmp) \
43239268Sgonzo	mrc p15, 0, tmp, c13, c0, 4; \
44261415Scognet	add	tmp, tmp, #(TD_PCB)
45129198Scognet#else
46129198Scognet.Lcurpcb:
47129198Scognet	.word	_C_LABEL(__pcpu) + PC_CURPCB
48239268Sgonzo#define GET_PCB(tmp) \
49239268Sgonzo	ldr	tmp, .Lcurpcb
50129198Scognet#endif
51129198Scognet
52129198Scognet/*
53129198Scognet * fuword(caddr_t uaddr);
54129198Scognet * Fetch an int from the user's address space.
55129198Scognet */
56129198Scognet
57163449SdavidxuENTRY(casuword)
58269390SianEENTRY_NP(casuword32)
59239268Sgonzo	GET_PCB(r3)
60137271Scognet	ldr	r3, [r3]
61137271Scognet
62137271Scognet#ifdef DIAGNOSTIC
63137271Scognet	teq	r3, #0x00000000
64137271Scognet	beq	.Lfusupcbfault
65137271Scognet#endif
66145452Scognet	stmfd	sp!, {r4, r5}
67163449Sdavidxu	adr	r4, .Lcasuwordfault
68137271Scognet	str	r4, [r3, #PCB_ONFAULT]
69256691Scognet#ifdef _ARM_ARCH_6
70256691Scognet1:
71256691Scognet	cmp     r0, #KERNBASE
72256748Scognet	mvnhs   r0, #0
73256748Scognet	bhs     2f
74256691Scognet
75256691Scognet	ldrex   r5, [r0]
76256691Scognet	cmp     r5, r1
77256691Scognet	movne   r0, r5
78256691Scognet	bne     2f
79256691Scognet	strex   r5, r2, [r0]
80256691Scognet	cmp     r5, #0
81256691Scognet	bne     1b
82256691Scognet#else
83145452Scognet	ldrt	r5, [r0]
84145452Scognet	cmp	r5, r1
85145452Scognet	movne	r0, r5
86145452Scognet	streqt	r2, [r0]
87256691Scognet#endif
88145452Scognet	moveq	r0, r1
89256691Scognet2:
90145452Scognet	ldmfd	sp!, {r4, r5}
91137271Scognet	mov	r1, #0x00000000
92137271Scognet	str	r1, [r3, #PCB_ONFAULT]
93137463Scognet	RET
94269390SianEEND(casuword32)
95248361SandrewEND(casuword)
96137271Scognet
97137271Scognet/*
98163449Sdavidxu * Handle faults from casuword.  Clean up and return -1.
99145452Scognet */
100145452Scognet
101163449Sdavidxu.Lcasuwordfault:
102145452Scognet	mov	r0, #0x00000000
103145452Scognet	str	r0, [r3, #PCB_ONFAULT]
104145452Scognet	mvn	r0, #0x00000000
105145452Scognet	ldmfd	sp!, {r4, r5}
106145452Scognet	RET
107248361Sandrew
108145452Scognet/*
109137271Scognet * fuword(caddr_t uaddr);
110137271Scognet * Fetch an int from the user's address space.
111137271Scognet */
112137271Scognet
113129198ScognetENTRY(fuword)
114269390SianEENTRY_NP(fuword32)
115239268Sgonzo	GET_PCB(r2)
116129198Scognet	ldr	r2, [r2]
117129198Scognet
118129198Scognet#ifdef DIAGNOSTIC
119129198Scognet	teq	r2, #0x00000000
120129198Scognet	beq	.Lfusupcbfault
121129198Scognet#endif
122129198Scognet
123129198Scognet	adr	r1, .Lfusufault
124129198Scognet	str	r1, [r2, #PCB_ONFAULT]
125129198Scognet
126129198Scognet	ldrt	r3, [r0]
127129198Scognet
128129198Scognet	mov	r1, #0x00000000
129129198Scognet	str	r1, [r2, #PCB_ONFAULT]
130129198Scognet	mov	r0, r3
131137463Scognet	RET
132248361SandrewEND(fuword32)
133248361SandrewEND(fuword)
134129198Scognet
135129198Scognet/*
136129198Scognet * fusword(caddr_t uaddr);
137129198Scognet * Fetch a short from the user's address space.
138129198Scognet */
139129198Scognet
140129198ScognetENTRY(fusword)
141239268Sgonzo	GET_PCB(r2)
142129198Scognet	ldr	r2, [r2]
143129198Scognet
144129198Scognet#ifdef DIAGNOSTIC
145129198Scognet	teq	r2, #0x00000000
146129198Scognet	beq	.Lfusupcbfault
147129198Scognet#endif
148129198Scognet
149129198Scognet	adr	r1, .Lfusufault
150129198Scognet	str	r1, [r2, #PCB_ONFAULT]
151129198Scognet
152129198Scognet	ldrbt	r3, [r0], #1
153129198Scognet	ldrbt	ip, [r0]
154129198Scognet#ifdef __ARMEB__
155129198Scognet	orr	r0, ip, r3, asl #8
156129198Scognet#else
157129198Scognet	orr	r0, r3, ip, asl #8
158129198Scognet#endif
159129198Scognet	mov	r1, #0x00000000
160129198Scognet	str	r1, [r2, #PCB_ONFAULT]
161137463Scognet	RET
162248361SandrewEND(fusword)
163129198Scognet
164129198Scognet/*
165129198Scognet * fuswintr(caddr_t uaddr);
166129198Scognet * Fetch a short from the user's address space.  Can be called during an
167129198Scognet * interrupt.
168129198Scognet */
169129198Scognet
170129198ScognetENTRY(fuswintr)
171129198Scognet	ldr	r2, Lblock_userspace_access
172129198Scognet	ldr	r2, [r2]
173129198Scognet	teq	r2, #0
174129198Scognet	mvnne	r0, #0x00000000
175137463Scognet	RETne
176129198Scognet
177239268Sgonzo	GET_PCB(r2)
178129198Scognet	ldr	r2, [r2]
179129198Scognet
180129198Scognet#ifdef DIAGNOSTIC
181129198Scognet	teq	r2, #0x00000000
182129198Scognet	beq	.Lfusupcbfault
183129198Scognet#endif
184129198Scognet
185129198Scognet	adr	r1, _C_LABEL(fusubailout)
186129198Scognet	str	r1, [r2, #PCB_ONFAULT]
187129198Scognet
188129198Scognet	ldrbt	r3, [r0], #1
189129198Scognet	ldrbt	ip, [r0]
190129198Scognet#ifdef __ARMEB__
191129198Scognet	orr	r0, ip, r3, asl #8
192129198Scognet#else
193129198Scognet	orr	r0, r3, ip, asl #8
194129198Scognet#endif
195129198Scognet
196129198Scognet	mov	r1, #0x00000000
197129198Scognet	str	r1, [r2, #PCB_ONFAULT]
198137463Scognet	RET
199248361SandrewEND(fuswintr)
200129198Scognet
201129198ScognetLblock_userspace_access:
202129198Scognet	.word	_C_LABEL(block_userspace_access)
203129198Scognet
204129198Scognet	.data
205129198Scognet	.align	0
206129198Scognet	.global	_C_LABEL(block_userspace_access)
207129198Scognet_C_LABEL(block_userspace_access):
208129198Scognet	.word	0
209129198Scognet	.text
210129198Scognet
211129198Scognet/*
212129198Scognet * fubyte(caddr_t uaddr);
213129198Scognet * Fetch a byte from the user's address space.
214129198Scognet */
215129198Scognet
216129198ScognetENTRY(fubyte)
217239268Sgonzo	GET_PCB(r2)
218129198Scognet	ldr	r2, [r2]
219129198Scognet
220129198Scognet#ifdef DIAGNOSTIC
221129198Scognet	teq	r2, #0x00000000
222129198Scognet	beq	.Lfusupcbfault
223129198Scognet#endif
224129198Scognet
225129198Scognet	adr	r1, .Lfusufault
226129198Scognet	str	r1, [r2, #PCB_ONFAULT]
227129198Scognet
228129198Scognet	ldrbt	r3, [r0]
229129198Scognet
230129198Scognet	mov	r1, #0x00000000
231129198Scognet	str	r1, [r2, #PCB_ONFAULT]
232129198Scognet	mov	r0, r3
233137463Scognet	RET
234248361SandrewEND(fubyte)
235129198Scognet
236129198Scognet/*
237129198Scognet * Handle faults from [fs]u*().  Clean up and return -1.
238129198Scognet */
239129198Scognet
240129198Scognet.Lfusufault:
241129198Scognet	mov	r0, #0x00000000
242129198Scognet	str	r0, [r2, #PCB_ONFAULT]
243129198Scognet	mvn	r0, #0x00000000
244137463Scognet	RET
245129198Scognet
246129198Scognet/*
247129198Scognet * Handle faults from [fs]u*().  Clean up and return -1.  This differs from
248129198Scognet * fusufault() in that trap() will recognise it and return immediately rather
249129198Scognet * than trying to page fault.
250129198Scognet */
251129198Scognet
252129198Scognet/* label must be global as fault.c references it */
253129198Scognet	.global	_C_LABEL(fusubailout)
254129198Scognet_C_LABEL(fusubailout):
255129198Scognet	mov	r0, #0x00000000
256129198Scognet	str	r0, [r2, #PCB_ONFAULT]
257129198Scognet	mvn	r0, #0x00000000
258137463Scognet	RET
259129198Scognet
260129198Scognet#ifdef DIAGNOSTIC
261129198Scognet/*
262129198Scognet * Handle earlier faults from [fs]u*(), due to no pcb
263129198Scognet */
264129198Scognet
265129198Scognet.Lfusupcbfault:
266129198Scognet	mov	r1, r0
267129198Scognet	adr	r0, fusupcbfaulttext
268129198Scognet	b	_C_LABEL(panic)
269129198Scognet
270129198Scognetfusupcbfaulttext:
271129198Scognet	.asciz	"Yikes - no valid PCB during fusuxxx() addr=%08x\n"
272129198Scognet	.align	0
273129198Scognet#endif
274129198Scognet
275129198Scognet/*
276129198Scognet * suword(caddr_t uaddr, int x);
277129198Scognet * Store an int in the user's address space.
278129198Scognet */
279129198Scognet
280129198ScognetENTRY(suword)
281269390SianEENTRY_NP(suword32)
282239268Sgonzo	GET_PCB(r2)
283129198Scognet	ldr	r2, [r2]
284129198Scognet
285129198Scognet#ifdef DIAGNOSTIC
286129198Scognet	teq	r2, #0x00000000
287129198Scognet	beq	.Lfusupcbfault
288129198Scognet#endif
289129198Scognet
290129198Scognet	adr	r3, .Lfusufault
291129198Scognet	str	r3, [r2, #PCB_ONFAULT]
292129198Scognet
293129198Scognet	strt	r1, [r0]
294129198Scognet
295129198Scognet	mov	r0, #0x00000000
296129198Scognet	str	r0, [r2, #PCB_ONFAULT]
297137463Scognet	RET
298248361SandrewEND(suword32)
299248361SandrewEND(suword)
300129198Scognet
301129198Scognet/*
302129198Scognet * suswintr(caddr_t uaddr, short x);
303129198Scognet * Store a short in the user's address space.  Can be called during an
304129198Scognet * interrupt.
305129198Scognet */
306129198Scognet
307129198ScognetENTRY(suswintr)
308129198Scognet	ldr	r2, Lblock_userspace_access
309129198Scognet	ldr	r2, [r2]
310129198Scognet	teq	r2, #0
311129198Scognet	mvnne	r0, #0x00000000
312137463Scognet	RETne
313129198Scognet
314239268Sgonzo	GET_PCB(r2)
315129198Scognet	ldr	r2, [r2]
316129198Scognet
317129198Scognet#ifdef DIAGNOSTIC
318129198Scognet	teq	r2, #0x00000000
319129198Scognet	beq	.Lfusupcbfault
320129198Scognet#endif
321129198Scognet
322129198Scognet	adr	r3, _C_LABEL(fusubailout)
323129198Scognet	str	r3, [r2, #PCB_ONFAULT]
324129198Scognet
325129198Scognet#ifdef __ARMEB__
326129198Scognet	mov	ip, r1, lsr #8
327129198Scognet	strbt	ip, [r0], #1
328129198Scognet#else
329129198Scognet	strbt	r1, [r0], #1
330129198Scognet	mov	r1, r1, lsr #8
331129198Scognet#endif
332129198Scognet	strbt	r1, [r0]
333129198Scognet
334129198Scognet	mov	r0, #0x00000000
335129198Scognet	str	r0, [r2, #PCB_ONFAULT]
336137463Scognet	RET
337248361SandrewEND(suswintr)
338129198Scognet
339129198Scognet/*
340129198Scognet * susword(caddr_t uaddr, short x);
341129198Scognet * Store a short in the user's address space.
342129198Scognet */
343129198Scognet
344129198ScognetENTRY(susword)
345239268Sgonzo	GET_PCB(r2)
346129198Scognet	ldr	r2, [r2]
347129198Scognet
348129198Scognet#ifdef DIAGNOSTIC
349129198Scognet	teq	r2, #0x00000000
350129198Scognet	beq	.Lfusupcbfault
351129198Scognet#endif
352129198Scognet
353129198Scognet	adr	r3, .Lfusufault
354129198Scognet	str	r3, [r2, #PCB_ONFAULT]
355129198Scognet
356129198Scognet#ifdef __ARMEB__
357129198Scognet	mov	ip, r1, lsr #8
358129198Scognet	strbt	ip, [r0], #1
359129198Scognet#else
360129198Scognet	strbt	r1, [r0], #1
361129198Scognet	mov	r1, r1, lsr #8
362129198Scognet#endif
363129198Scognet	strbt	r1, [r0]
364129198Scognet
365129198Scognet	mov	r0, #0x00000000
366129198Scognet	str	r0, [r2, #PCB_ONFAULT]
367137463Scognet	RET
368248361SandrewEND(susword)
369129198Scognet
370129198Scognet/*
371129198Scognet * subyte(caddr_t uaddr, char x);
372129198Scognet * Store a byte in the user's address space.
373129198Scognet */
374129198Scognet
375129198ScognetENTRY(subyte)
376239268Sgonzo	GET_PCB(r2)
377129198Scognet	ldr	r2, [r2]
378129198Scognet
379129198Scognet
380129198Scognet#ifdef DIAGNOSTIC
381129198Scognet	teq	r2, #0x00000000
382129198Scognet	beq	.Lfusupcbfault
383129198Scognet#endif
384129198Scognet
385129198Scognet	adr	r3, .Lfusufault
386129198Scognet	str	r3, [r2, #PCB_ONFAULT]
387129198Scognet
388129198Scognet	strbt	r1, [r0]
389129198Scognet	mov	r0, #0x00000000
390129198Scognet	str	r0, [r2, #PCB_ONFAULT]
391137463Scognet	RET
392248361SandrewEND(subyte)
393