fusu.S revision 137463
1129198Scognet/*	$NetBSD: fusu.S,v 1.10 2003/12/01 13:34:44 rearnsha Exp $	*/
2129198Scognet
3129198Scognet/*
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 137463 2004-11-09 16:47:47Z cognet $");
41129198Scognet
42129198Scognet#ifdef MULTIPROCESSOR
43129198Scognet.Lcpu_info:
44129198Scognet	.word	_C_LABEL(cpu_info)
45129198Scognet#else
46129198Scognet.Lcurpcb:
47129198Scognet	.word	_C_LABEL(__pcpu) + PC_CURPCB
48129198Scognet#endif
49129198Scognet
50129198Scognet/*
51129198Scognet * fuword(caddr_t uaddr);
52129198Scognet * Fetch an int from the user's address space.
53129198Scognet */
54129198Scognet
55137271ScognetENTRY(casuptr)
56137271Scognet#ifdef MULTIPROCESSOR
57137271Scognet	/* XXX Probably not appropriate for non-Hydra SMPs */
58137271Scognet	stmfd	sp!, {r0, r14}
59137271Scognet	bl	_C_LABEL(cpu_number)
60137271Scognet	ldr	r2, .Lcpu_info
61137271Scognet	ldr	r2, [r2, r0, lsl #2]
62137271Scognet	ldr	r2, [r2, #CI_CURPCB]
63137271Scognet	ldmfd	sp!, {r0, r14}
64137271Scognet#else
65137271Scognet	ldr	r3, .Lcurpcb
66137271Scognet	ldr	r3, [r3]
67137271Scognet#endif
68137271Scognet
69137271Scognet#ifdef DIAGNOSTIC
70137271Scognet	teq	r3, #0x00000000
71137271Scognet	beq	.Lfusupcbfault
72137271Scognet#endif
73137271Scognet	stmfd	sp!, {r4}
74137271Scognet	adr	r4, .Lfusufault
75137271Scognet	str	r4, [r3, #PCB_ONFAULT]
76137271Scognet	ldmfd	sp!, {r4}
77137271Scognet	ldrt	r3, [r0]
78137271Scognet	cmp	r3, r1
79137271Scognet	movne	r0, r3
80137463Scognet	RETne
81137271Scognet	strt	r2, [r0]
82137271Scognet	mov	r0, r1
83137271Scognet#ifdef MULTIPROCESSOR
84137271Scognet	/* XXX Probably not appropriate for non-Hydra SMPs */
85137271Scognet	stmfd	sp!, {r0, r14}
86137271Scognet	bl	_C_LABEL(cpu_number)
87137271Scognet	ldr	r2, .Lcpu_info
88137271Scognet	ldr	r2, [r2, r0, lsl #2]
89137271Scognet	ldr	r2, [r2, #CI_CURPCB]
90137271Scognet	ldmfd	sp!, {r0, r14}
91137271Scognet#else
92137271Scognet	ldr	r3, .Lcurpcb
93137271Scognet	ldr	r3, [r3]
94137271Scognet#endif
95137271Scognet	mov	r1, #0x00000000
96137271Scognet	str	r1, [r3, #PCB_ONFAULT]
97137463Scognet	RET
98137271Scognet
99137271Scognet
100137271Scognet/*
101137271Scognet * fuword(caddr_t uaddr);
102137271Scognet * Fetch an int from the user's address space.
103137271Scognet */
104137271Scognet
105135881ScognetENTRY(fuword32)
106129198ScognetENTRY(fuword)
107129198Scognet#ifdef MULTIPROCESSOR
108129198Scognet	/* XXX Probably not appropriate for non-Hydra SMPs */
109129198Scognet	stmfd	sp!, {r0, r14}
110129198Scognet	bl	_C_LABEL(cpu_number)
111129198Scognet	ldr	r2, .Lcpu_info
112129198Scognet	ldr	r2, [r2, r0, lsl #2]
113129198Scognet	ldr	r2, [r2, #CI_CURPCB]
114129198Scognet	ldmfd	sp!, {r0, r14}
115129198Scognet#else
116129198Scognet	ldr	r2, .Lcurpcb
117129198Scognet	ldr	r2, [r2]
118129198Scognet#endif
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
134129198Scognet
135129198Scognet/*
136129198Scognet * fusword(caddr_t uaddr);
137129198Scognet * Fetch a short from the user's address space.
138129198Scognet */
139129198Scognet
140129198ScognetENTRY(fusword)
141129198Scognet#ifdef MULTIPROCESSOR
142129198Scognet	/* XXX Probably not appropriate for non-Hydra SMPs */
143129198Scognet	stmfd	sp!, {r0, r14}
144129198Scognet	bl	_C_LABEL(cpu_number)
145129198Scognet	ldr	r2, .Lcpu_info
146129198Scognet	ldr	r2, [r2, r0, lsl #2]
147129198Scognet	ldr	r2, [r2, #CI_CURPCB]
148129198Scognet	ldmfd	sp!, {r0, r14}
149129198Scognet#else
150129198Scognet	ldr	r2, .Lcurpcb
151129198Scognet	ldr	r2, [r2]
152129198Scognet#endif
153129198Scognet
154129198Scognet#ifdef DIAGNOSTIC
155129198Scognet	teq	r2, #0x00000000
156129198Scognet	beq	.Lfusupcbfault
157129198Scognet#endif
158129198Scognet
159129198Scognet	adr	r1, .Lfusufault
160129198Scognet	str	r1, [r2, #PCB_ONFAULT]
161129198Scognet
162129198Scognet	ldrbt	r3, [r0], #1
163129198Scognet	ldrbt	ip, [r0]
164129198Scognet#ifdef __ARMEB__
165129198Scognet	orr	r0, ip, r3, asl #8
166129198Scognet#else
167129198Scognet	orr	r0, r3, ip, asl #8
168129198Scognet#endif
169129198Scognet	mov	r1, #0x00000000
170129198Scognet	str	r1, [r2, #PCB_ONFAULT]
171137463Scognet	RET
172129198Scognet
173129198Scognet/*
174129198Scognet * fuswintr(caddr_t uaddr);
175129198Scognet * Fetch a short from the user's address space.  Can be called during an
176129198Scognet * interrupt.
177129198Scognet */
178129198Scognet
179129198ScognetENTRY(fuswintr)
180129198Scognet	ldr	r2, Lblock_userspace_access
181129198Scognet	ldr	r2, [r2]
182129198Scognet	teq	r2, #0
183129198Scognet	mvnne	r0, #0x00000000
184137463Scognet	RETne
185129198Scognet
186129198Scognet#ifdef MULTIPROCESSOR
187129198Scognet	/* XXX Probably not appropriate for non-Hydra SMPs */
188129198Scognet	stmfd	sp!, {r0, r14}
189129198Scognet	bl	_C_LABEL(cpu_number)
190129198Scognet	ldr	r2, .Lcpu_info
191129198Scognet	ldr	r2, [r2, r0, lsl #2]
192129198Scognet	ldr	r2, [r2, #CI_CURPCB]
193129198Scognet	ldmfd	sp!, {r0, r14}
194129198Scognet#else
195129198Scognet	ldr	r2, .Lcurpcb
196129198Scognet	ldr	r2, [r2]
197129198Scognet#endif
198129198Scognet
199129198Scognet#ifdef DIAGNOSTIC
200129198Scognet	teq	r2, #0x00000000
201129198Scognet	beq	.Lfusupcbfault
202129198Scognet#endif
203129198Scognet
204129198Scognet	adr	r1, _C_LABEL(fusubailout)
205129198Scognet	str	r1, [r2, #PCB_ONFAULT]
206129198Scognet
207129198Scognet	ldrbt	r3, [r0], #1
208129198Scognet	ldrbt	ip, [r0]
209129198Scognet#ifdef __ARMEB__
210129198Scognet	orr	r0, ip, r3, asl #8
211129198Scognet#else
212129198Scognet	orr	r0, r3, ip, asl #8
213129198Scognet#endif
214129198Scognet
215129198Scognet	mov	r1, #0x00000000
216129198Scognet	str	r1, [r2, #PCB_ONFAULT]
217137463Scognet	RET
218129198Scognet
219129198ScognetLblock_userspace_access:
220129198Scognet	.word	_C_LABEL(block_userspace_access)
221129198Scognet
222129198Scognet	.data
223129198Scognet	.align	0
224129198Scognet	.global	_C_LABEL(block_userspace_access)
225129198Scognet_C_LABEL(block_userspace_access):
226129198Scognet	.word	0
227129198Scognet	.text
228129198Scognet
229129198Scognet/*
230129198Scognet * fubyte(caddr_t uaddr);
231129198Scognet * Fetch a byte from the user's address space.
232129198Scognet */
233129198Scognet
234129198ScognetENTRY(fubyte)
235129198Scognet#ifdef MULTIPROCESSOR
236129198Scognet	/* XXX Probably not appropriate for non-Hydra SMPs */
237129198Scognet	stmfd	sp!, {r0, r14}
238129198Scognet	bl	_C_LABEL(cpu_number)
239129198Scognet	ldr	r2, .Lcpu_info
240129198Scognet	ldr	r2, [r2, r0, lsl #2]
241129198Scognet	ldr	r2, [r2, #CI_CURPCB]
242129198Scognet	ldmfd	sp!, {r0, r14}
243129198Scognet#else
244129198Scognet	ldr	r2, .Lcurpcb
245129198Scognet	ldr	r2, [r2]
246129198Scognet#endif
247129198Scognet
248129198Scognet#ifdef DIAGNOSTIC
249129198Scognet	teq	r2, #0x00000000
250129198Scognet	beq	.Lfusupcbfault
251129198Scognet#endif
252129198Scognet
253129198Scognet	adr	r1, .Lfusufault
254129198Scognet	str	r1, [r2, #PCB_ONFAULT]
255129198Scognet
256129198Scognet	ldrbt	r3, [r0]
257129198Scognet
258129198Scognet	mov	r1, #0x00000000
259129198Scognet	str	r1, [r2, #PCB_ONFAULT]
260129198Scognet	mov	r0, r3
261137463Scognet	RET
262129198Scognet
263129198Scognet/*
264129198Scognet * Handle faults from [fs]u*().  Clean up and return -1.
265129198Scognet */
266129198Scognet
267129198Scognet.Lfusufault:
268129198Scognet	mov	r0, #0x00000000
269129198Scognet	str	r0, [r2, #PCB_ONFAULT]
270129198Scognet	mvn	r0, #0x00000000
271137463Scognet	RET
272129198Scognet
273129198Scognet/*
274129198Scognet * Handle faults from [fs]u*().  Clean up and return -1.  This differs from
275129198Scognet * fusufault() in that trap() will recognise it and return immediately rather
276129198Scognet * than trying to page fault.
277129198Scognet */
278129198Scognet
279129198Scognet/* label must be global as fault.c references it */
280129198Scognet	.global	_C_LABEL(fusubailout)
281129198Scognet_C_LABEL(fusubailout):
282129198Scognet	mov	r0, #0x00000000
283129198Scognet	str	r0, [r2, #PCB_ONFAULT]
284129198Scognet	mvn	r0, #0x00000000
285137463Scognet	RET
286129198Scognet
287129198Scognet#ifdef DIAGNOSTIC
288129198Scognet/*
289129198Scognet * Handle earlier faults from [fs]u*(), due to no pcb
290129198Scognet */
291129198Scognet
292129198Scognet.Lfusupcbfault:
293129198Scognet	mov	r1, r0
294129198Scognet	adr	r0, fusupcbfaulttext
295129198Scognet	b	_C_LABEL(panic)
296129198Scognet
297129198Scognetfusupcbfaulttext:
298129198Scognet	.asciz	"Yikes - no valid PCB during fusuxxx() addr=%08x\n"
299129198Scognet	.align	0
300129198Scognet#endif
301129198Scognet
302129198Scognet/*
303129198Scognet * suword(caddr_t uaddr, int x);
304129198Scognet * Store an int in the user's address space.
305129198Scognet */
306129198Scognet
307137271ScognetENTRY(suword32)
308129198ScognetENTRY(suword)
309129198Scognet#ifdef MULTIPROCESSOR
310129198Scognet	/* XXX Probably not appropriate for non-Hydra SMPs */
311129198Scognet	stmfd	sp!, {r0, r1, r14}
312129198Scognet	bl	_C_LABEL(cpu_number)
313129198Scognet	ldr	r2, .Lcpu_info
314129198Scognet	ldr	r2, [r2, r0, lsl #2]
315129198Scognet	ldr	r2, [r2, #CI_CURPCB]
316129198Scognet	ldmfd	sp!, {r0, r1, r14}
317129198Scognet#else
318129198Scognet	ldr	r2, .Lcurpcb
319129198Scognet	ldr	r2, [r2]
320129198Scognet#endif
321129198Scognet
322129198Scognet#ifdef DIAGNOSTIC
323129198Scognet	teq	r2, #0x00000000
324129198Scognet	beq	.Lfusupcbfault
325129198Scognet#endif
326129198Scognet
327129198Scognet	adr	r3, .Lfusufault
328129198Scognet	str	r3, [r2, #PCB_ONFAULT]
329129198Scognet
330129198Scognet	strt	r1, [r0]
331129198Scognet
332129198Scognet	mov	r0, #0x00000000
333129198Scognet	str	r0, [r2, #PCB_ONFAULT]
334137463Scognet	RET
335129198Scognet
336129198Scognet/*
337129198Scognet * suswintr(caddr_t uaddr, short x);
338129198Scognet * Store a short in the user's address space.  Can be called during an
339129198Scognet * interrupt.
340129198Scognet */
341129198Scognet
342129198ScognetENTRY(suswintr)
343129198Scognet	ldr	r2, Lblock_userspace_access
344129198Scognet	ldr	r2, [r2]
345129198Scognet	teq	r2, #0
346129198Scognet	mvnne	r0, #0x00000000
347137463Scognet	RETne
348129198Scognet
349129198Scognet#ifdef MULTIPROCESSOR
350129198Scognet	stmfd	sp!, {r0, r1, r14}
351129198Scognet	bl	_C_LABEL(cpu_number)
352129198Scognet	ldr	r2, .Lcpu_info
353129198Scognet	ldr	r2, [r2, r0, lsl #2]
354129198Scognet	ldr	r2, [r2, #CI_CURPCB]
355129198Scognet	ldmfd	sp!, {r0, r1, r14}
356129198Scognet#else
357129198Scognet	ldr	r2, .Lcurpcb
358129198Scognet	ldr	r2, [r2]
359129198Scognet#endif
360129198Scognet
361129198Scognet#ifdef DIAGNOSTIC
362129198Scognet	teq	r2, #0x00000000
363129198Scognet	beq	.Lfusupcbfault
364129198Scognet#endif
365129198Scognet
366129198Scognet	adr	r3, _C_LABEL(fusubailout)
367129198Scognet	str	r3, [r2, #PCB_ONFAULT]
368129198Scognet
369129198Scognet#ifdef __ARMEB__
370129198Scognet	mov	ip, r1, lsr #8
371129198Scognet	strbt	ip, [r0], #1
372129198Scognet#else
373129198Scognet	strbt	r1, [r0], #1
374129198Scognet	mov	r1, r1, lsr #8
375129198Scognet#endif
376129198Scognet	strbt	r1, [r0]
377129198Scognet
378129198Scognet	mov	r0, #0x00000000
379129198Scognet	str	r0, [r2, #PCB_ONFAULT]
380137463Scognet	RET
381129198Scognet
382129198Scognet/*
383129198Scognet * susword(caddr_t uaddr, short x);
384129198Scognet * Store a short in the user's address space.
385129198Scognet */
386129198Scognet
387129198ScognetENTRY(susword)
388129198Scognet#ifdef MULTIPROCESSOR
389129198Scognet	stmfd	sp!, {r0, r1, r14}
390129198Scognet	bl	_C_LABEL(cpu_number)
391129198Scognet	ldr	r2, .Lcpu_info
392129198Scognet	ldr	r2, [r2, r0, lsl #2]
393129198Scognet	ldr	r2, [r2, #CI_CURPCB]
394129198Scognet	ldmfd	sp!, {r0, r1, r14}
395129198Scognet#else
396129198Scognet	ldr	r2, .Lcurpcb
397129198Scognet	ldr	r2, [r2]
398129198Scognet#endif
399129198Scognet
400129198Scognet#ifdef DIAGNOSTIC
401129198Scognet	teq	r2, #0x00000000
402129198Scognet	beq	.Lfusupcbfault
403129198Scognet#endif
404129198Scognet
405129198Scognet	adr	r3, .Lfusufault
406129198Scognet	str	r3, [r2, #PCB_ONFAULT]
407129198Scognet
408129198Scognet#ifdef __ARMEB__
409129198Scognet	mov	ip, r1, lsr #8
410129198Scognet	strbt	ip, [r0], #1
411129198Scognet#else
412129198Scognet	strbt	r1, [r0], #1
413129198Scognet	mov	r1, r1, lsr #8
414129198Scognet#endif
415129198Scognet	strbt	r1, [r0]
416129198Scognet
417129198Scognet	mov	r0, #0x00000000
418129198Scognet	str	r0, [r2, #PCB_ONFAULT]
419137463Scognet	RET
420129198Scognet
421129198Scognet/*
422129198Scognet * subyte(caddr_t uaddr, char x);
423129198Scognet * Store a byte in the user's address space.
424129198Scognet */
425129198Scognet
426129198ScognetENTRY(subyte)
427129198Scognet#ifdef MULTIPROCESSOR
428129198Scognet	stmfd	sp!, {r0, r1, r14}
429129198Scognet	bl	_C_LABEL(cpu_number)
430129198Scognet	ldr	r2, .Lcpu_info
431129198Scognet	ldr	r2, [r2, r0, lsl #2]
432129198Scognet	ldr	r2, [r2, #CI_CURPCB]
433129198Scognet	ldmfd	sp!, {r0, r1, r14}
434129198Scognet#else
435129198Scognet	ldr	r2, .Lcurpcb
436129198Scognet	ldr	r2, [r2]
437129198Scognet#endif
438129198Scognet
439129198Scognet
440129198Scognet#ifdef DIAGNOSTIC
441129198Scognet	teq	r2, #0x00000000
442129198Scognet	beq	.Lfusupcbfault
443129198Scognet#endif
444129198Scognet
445129198Scognet	adr	r3, .Lfusufault
446129198Scognet	str	r3, [r2, #PCB_ONFAULT]
447129198Scognet
448129198Scognet	strbt	r1, [r0]
449129198Scognet	mov	r0, #0x00000000
450129198Scognet	str	r0, [r2, #PCB_ONFAULT]
451137463Scognet	RET
452