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$");
40129198Scognet
41275767Sandrew	.syntax	unified
42275767Sandrew
43239268Sgonzo#ifdef _ARM_ARCH_6
44239268Sgonzo#define GET_PCB(tmp) \
45239268Sgonzo	mrc p15, 0, tmp, c13, c0, 4; \
46266159Sian	add	tmp, tmp, #(TD_PCB)
47129198Scognet#else
48129198Scognet.Lcurpcb:
49129198Scognet	.word	_C_LABEL(__pcpu) + PC_CURPCB
50239268Sgonzo#define GET_PCB(tmp) \
51239268Sgonzo	ldr	tmp, .Lcurpcb
52129198Scognet#endif
53129198Scognet
54129198Scognet/*
55129198Scognet * fuword(caddr_t uaddr);
56129198Scognet * Fetch an int from the user's address space.
57129198Scognet */
58129198Scognet
59163449SdavidxuENTRY(casuword)
60269796SianEENTRY_NP(casuword32)
61239268Sgonzo	GET_PCB(r3)
62137271Scognet	ldr	r3, [r3]
63137271Scognet
64137271Scognet#ifdef DIAGNOSTIC
65137271Scognet	teq	r3, #0x00000000
66137271Scognet	beq	.Lfusupcbfault
67137271Scognet#endif
68145452Scognet	stmfd	sp!, {r4, r5}
69163449Sdavidxu	adr	r4, .Lcasuwordfault
70137271Scognet	str	r4, [r3, #PCB_ONFAULT]
71269679Sian#ifdef _ARM_ARCH_6
72269679Sian1:
73269679Sian	cmp     r0, #KERNBASE
74269679Sian	mvnhs   r0, #0
75269679Sian	bhs     2f
76269679Sian
77269679Sian	ldrex   r5, [r0]
78269679Sian	cmp     r5, r1
79269679Sian	movne   r0, r5
80269679Sian	bne     2f
81269679Sian	strex   r5, r2, [r0]
82269679Sian	cmp     r5, #0
83269679Sian	bne     1b
84269679Sian#else
85145452Scognet	ldrt	r5, [r0]
86145452Scognet	cmp	r5, r1
87145452Scognet	movne	r0, r5
88275767Sandrew	strteq	r2, [r0]
89269679Sian#endif
90145452Scognet	moveq	r0, r1
91269679Sian2:
92145452Scognet	ldmfd	sp!, {r4, r5}
93137271Scognet	mov	r1, #0x00000000
94137271Scognet	str	r1, [r3, #PCB_ONFAULT]
95137463Scognet	RET
96269796SianEEND(casuword32)
97248361SandrewEND(casuword)
98137271Scognet
99137271Scognet/*
100163449Sdavidxu * Handle faults from casuword.  Clean up and return -1.
101145452Scognet */
102145452Scognet
103163449Sdavidxu.Lcasuwordfault:
104145452Scognet	mov	r0, #0x00000000
105145452Scognet	str	r0, [r3, #PCB_ONFAULT]
106145452Scognet	mvn	r0, #0x00000000
107145452Scognet	ldmfd	sp!, {r4, r5}
108145452Scognet	RET
109248361Sandrew
110145452Scognet/*
111137271Scognet * fuword(caddr_t uaddr);
112137271Scognet * Fetch an int from the user's address space.
113137271Scognet */
114137271Scognet
115129198ScognetENTRY(fuword)
116269796SianEENTRY_NP(fuword32)
117239268Sgonzo	GET_PCB(r2)
118129198Scognet	ldr	r2, [r2]
119129198Scognet
120129198Scognet#ifdef DIAGNOSTIC
121129198Scognet	teq	r2, #0x00000000
122129198Scognet	beq	.Lfusupcbfault
123129198Scognet#endif
124129198Scognet
125129198Scognet	adr	r1, .Lfusufault
126129198Scognet	str	r1, [r2, #PCB_ONFAULT]
127129198Scognet
128129198Scognet	ldrt	r3, [r0]
129129198Scognet
130129198Scognet	mov	r1, #0x00000000
131129198Scognet	str	r1, [r2, #PCB_ONFAULT]
132129198Scognet	mov	r0, r3
133137463Scognet	RET
134294686SianEEND(fueword32)
135294686SianEND(fueword)
136129198Scognet
137129198Scognet/*
138129198Scognet * fusword(caddr_t uaddr);
139129198Scognet * Fetch a short from the user's address space.
140129198Scognet */
141129198Scognet
142129198ScognetENTRY(fusword)
143239268Sgonzo	GET_PCB(r2)
144129198Scognet	ldr	r2, [r2]
145129198Scognet
146129198Scognet#ifdef DIAGNOSTIC
147129198Scognet	teq	r2, #0x00000000
148129198Scognet	beq	.Lfusupcbfault
149129198Scognet#endif
150129198Scognet
151129198Scognet	adr	r1, .Lfusufault
152129198Scognet	str	r1, [r2, #PCB_ONFAULT]
153129198Scognet
154129198Scognet	ldrbt	r3, [r0], #1
155129198Scognet	ldrbt	ip, [r0]
156129198Scognet#ifdef __ARMEB__
157129198Scognet	orr	r0, ip, r3, asl #8
158129198Scognet#else
159129198Scognet	orr	r0, r3, ip, asl #8
160129198Scognet#endif
161129198Scognet	mov	r1, #0x00000000
162129198Scognet	str	r1, [r2, #PCB_ONFAULT]
163137463Scognet	RET
164248361SandrewEND(fusword)
165129198Scognet
166129198Scognet/*
167129198Scognet * fuswintr(caddr_t uaddr);
168129198Scognet * Fetch a short from the user's address space.  Can be called during an
169129198Scognet * interrupt.
170129198Scognet */
171129198Scognet
172129198ScognetENTRY(fuswintr)
173129198Scognet	ldr	r2, Lblock_userspace_access
174129198Scognet	ldr	r2, [r2]
175129198Scognet	teq	r2, #0
176129198Scognet	mvnne	r0, #0x00000000
177137463Scognet	RETne
178129198Scognet
179239268Sgonzo	GET_PCB(r2)
180129198Scognet	ldr	r2, [r2]
181129198Scognet
182129198Scognet#ifdef DIAGNOSTIC
183129198Scognet	teq	r2, #0x00000000
184129198Scognet	beq	.Lfusupcbfault
185129198Scognet#endif
186129198Scognet
187129198Scognet	adr	r1, _C_LABEL(fusubailout)
188129198Scognet	str	r1, [r2, #PCB_ONFAULT]
189129198Scognet
190129198Scognet	ldrbt	r3, [r0], #1
191129198Scognet	ldrbt	ip, [r0]
192129198Scognet#ifdef __ARMEB__
193129198Scognet	orr	r0, ip, r3, asl #8
194129198Scognet#else
195129198Scognet	orr	r0, r3, ip, asl #8
196129198Scognet#endif
197129198Scognet
198129198Scognet	mov	r1, #0x00000000
199129198Scognet	str	r1, [r2, #PCB_ONFAULT]
200137463Scognet	RET
201248361SandrewEND(fuswintr)
202129198Scognet
203129198ScognetLblock_userspace_access:
204129198Scognet	.word	_C_LABEL(block_userspace_access)
205129198Scognet
206129198Scognet	.data
207278652Sian	.align	2
208129198Scognet	.global	_C_LABEL(block_userspace_access)
209129198Scognet_C_LABEL(block_userspace_access):
210129198Scognet	.word	0
211129198Scognet	.text
212129198Scognet
213129198Scognet/*
214129198Scognet * fubyte(caddr_t uaddr);
215129198Scognet * Fetch a byte from the user's address space.
216129198Scognet */
217129198Scognet
218129198ScognetENTRY(fubyte)
219239268Sgonzo	GET_PCB(r2)
220129198Scognet	ldr	r2, [r2]
221129198Scognet
222129198Scognet#ifdef DIAGNOSTIC
223129198Scognet	teq	r2, #0x00000000
224129198Scognet	beq	.Lfusupcbfault
225129198Scognet#endif
226129198Scognet
227129198Scognet	adr	r1, .Lfusufault
228129198Scognet	str	r1, [r2, #PCB_ONFAULT]
229129198Scognet
230129198Scognet	ldrbt	r3, [r0]
231129198Scognet
232129198Scognet	mov	r1, #0x00000000
233129198Scognet	str	r1, [r2, #PCB_ONFAULT]
234129198Scognet	mov	r0, r3
235137463Scognet	RET
236248361SandrewEND(fubyte)
237129198Scognet
238129198Scognet/*
239129198Scognet * Handle faults from [fs]u*().  Clean up and return -1.
240129198Scognet */
241129198Scognet
242129198Scognet.Lfusufault:
243129198Scognet	mov	r0, #0x00000000
244129198Scognet	str	r0, [r2, #PCB_ONFAULT]
245129198Scognet	mvn	r0, #0x00000000
246137463Scognet	RET
247129198Scognet
248129198Scognet/*
249129198Scognet * Handle faults from [fs]u*().  Clean up and return -1.  This differs from
250129198Scognet * fusufault() in that trap() will recognise it and return immediately rather
251129198Scognet * than trying to page fault.
252129198Scognet */
253129198Scognet
254129198Scognet/* label must be global as fault.c references it */
255129198Scognet	.global	_C_LABEL(fusubailout)
256129198Scognet_C_LABEL(fusubailout):
257129198Scognet	mov	r0, #0x00000000
258129198Scognet	str	r0, [r2, #PCB_ONFAULT]
259129198Scognet	mvn	r0, #0x00000000
260137463Scognet	RET
261129198Scognet
262129198Scognet#ifdef DIAGNOSTIC
263129198Scognet/*
264129198Scognet * Handle earlier faults from [fs]u*(), due to no pcb
265129198Scognet */
266129198Scognet
267129198Scognet.Lfusupcbfault:
268129198Scognet	mov	r1, r0
269129198Scognet	adr	r0, fusupcbfaulttext
270129198Scognet	b	_C_LABEL(panic)
271129198Scognet
272129198Scognetfusupcbfaulttext:
273129198Scognet	.asciz	"Yikes - no valid PCB during fusuxxx() addr=%08x\n"
274275767Sandrew	.align	2
275129198Scognet#endif
276129198Scognet
277129198Scognet/*
278129198Scognet * suword(caddr_t uaddr, int x);
279129198Scognet * Store an int in the user's address space.
280129198Scognet */
281129198Scognet
282129198ScognetENTRY(suword)
283269796SianEENTRY_NP(suword32)
284239268Sgonzo	GET_PCB(r2)
285129198Scognet	ldr	r2, [r2]
286129198Scognet
287129198Scognet#ifdef DIAGNOSTIC
288129198Scognet	teq	r2, #0x00000000
289129198Scognet	beq	.Lfusupcbfault
290129198Scognet#endif
291129198Scognet
292129198Scognet	adr	r3, .Lfusufault
293129198Scognet	str	r3, [r2, #PCB_ONFAULT]
294129198Scognet
295129198Scognet	strt	r1, [r0]
296129198Scognet
297129198Scognet	mov	r0, #0x00000000
298129198Scognet	str	r0, [r2, #PCB_ONFAULT]
299137463Scognet	RET
300275767SandrewEEND(suword32)
301248361SandrewEND(suword)
302129198Scognet
303129198Scognet/*
304129198Scognet * suswintr(caddr_t uaddr, short x);
305129198Scognet * Store a short in the user's address space.  Can be called during an
306129198Scognet * interrupt.
307129198Scognet */
308129198Scognet
309129198ScognetENTRY(suswintr)
310129198Scognet	ldr	r2, Lblock_userspace_access
311129198Scognet	ldr	r2, [r2]
312129198Scognet	teq	r2, #0
313129198Scognet	mvnne	r0, #0x00000000
314137463Scognet	RETne
315129198Scognet
316239268Sgonzo	GET_PCB(r2)
317129198Scognet	ldr	r2, [r2]
318129198Scognet
319129198Scognet#ifdef DIAGNOSTIC
320129198Scognet	teq	r2, #0x00000000
321129198Scognet	beq	.Lfusupcbfault
322129198Scognet#endif
323129198Scognet
324129198Scognet	adr	r3, _C_LABEL(fusubailout)
325129198Scognet	str	r3, [r2, #PCB_ONFAULT]
326129198Scognet
327129198Scognet#ifdef __ARMEB__
328129198Scognet	mov	ip, r1, lsr #8
329129198Scognet	strbt	ip, [r0], #1
330129198Scognet#else
331129198Scognet	strbt	r1, [r0], #1
332129198Scognet	mov	r1, r1, lsr #8
333129198Scognet#endif
334129198Scognet	strbt	r1, [r0]
335129198Scognet
336129198Scognet	mov	r0, #0x00000000
337129198Scognet	str	r0, [r2, #PCB_ONFAULT]
338137463Scognet	RET
339248361SandrewEND(suswintr)
340129198Scognet
341129198Scognet/*
342129198Scognet * susword(caddr_t uaddr, short x);
343129198Scognet * Store a short in the user's address space.
344129198Scognet */
345129198Scognet
346129198ScognetENTRY(susword)
347239268Sgonzo	GET_PCB(r2)
348129198Scognet	ldr	r2, [r2]
349129198Scognet
350129198Scognet#ifdef DIAGNOSTIC
351129198Scognet	teq	r2, #0x00000000
352129198Scognet	beq	.Lfusupcbfault
353129198Scognet#endif
354129198Scognet
355129198Scognet	adr	r3, .Lfusufault
356129198Scognet	str	r3, [r2, #PCB_ONFAULT]
357129198Scognet
358129198Scognet#ifdef __ARMEB__
359129198Scognet	mov	ip, r1, lsr #8
360129198Scognet	strbt	ip, [r0], #1
361129198Scognet#else
362129198Scognet	strbt	r1, [r0], #1
363129198Scognet	mov	r1, r1, lsr #8
364129198Scognet#endif
365129198Scognet	strbt	r1, [r0]
366129198Scognet
367129198Scognet	mov	r0, #0x00000000
368129198Scognet	str	r0, [r2, #PCB_ONFAULT]
369137463Scognet	RET
370248361SandrewEND(susword)
371129198Scognet
372129198Scognet/*
373129198Scognet * subyte(caddr_t uaddr, char x);
374129198Scognet * Store a byte in the user's address space.
375129198Scognet */
376129198Scognet
377129198ScognetENTRY(subyte)
378239268Sgonzo	GET_PCB(r2)
379129198Scognet	ldr	r2, [r2]
380129198Scognet
381129198Scognet
382129198Scognet#ifdef DIAGNOSTIC
383129198Scognet	teq	r2, #0x00000000
384129198Scognet	beq	.Lfusupcbfault
385129198Scognet#endif
386129198Scognet
387129198Scognet	adr	r3, .Lfusufault
388129198Scognet	str	r3, [r2, #PCB_ONFAULT]
389129198Scognet
390129198Scognet	strbt	r1, [r0]
391129198Scognet	mov	r0, #0x00000000
392129198Scognet	str	r0, [r2, #PCB_ONFAULT]
393137463Scognet	RET
394248361SandrewEND(subyte)
395