fusu.S revision 163449
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 163449 2006-10-17 02:24:47Z davidxu $");
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
55161734ScognetENTRY_NP(casuword32)
56163449SdavidxuENTRY(casuword)
57137271Scognet#ifdef MULTIPROCESSOR
58137271Scognet	/* XXX Probably not appropriate for non-Hydra SMPs */
59137271Scognet	stmfd	sp!, {r0, r14}
60137271Scognet	bl	_C_LABEL(cpu_number)
61137271Scognet	ldr	r2, .Lcpu_info
62137271Scognet	ldr	r2, [r2, r0, lsl #2]
63137271Scognet	ldr	r2, [r2, #CI_CURPCB]
64137271Scognet	ldmfd	sp!, {r0, r14}
65137271Scognet#else
66137271Scognet	ldr	r3, .Lcurpcb
67137271Scognet	ldr	r3, [r3]
68137271Scognet#endif
69137271Scognet
70137271Scognet#ifdef DIAGNOSTIC
71137271Scognet	teq	r3, #0x00000000
72137271Scognet	beq	.Lfusupcbfault
73137271Scognet#endif
74145452Scognet	stmfd	sp!, {r4, r5}
75163449Sdavidxu	adr	r4, .Lcasuwordfault
76137271Scognet	str	r4, [r3, #PCB_ONFAULT]
77145452Scognet	ldrt	r5, [r0]
78145452Scognet	cmp	r5, r1
79145452Scognet	movne	r0, r5
80145452Scognet	streqt	r2, [r0]
81145452Scognet	moveq	r0, r1
82145452Scognet	ldmfd	sp!, {r4, r5}
83137271Scognet	mov	r1, #0x00000000
84137271Scognet	str	r1, [r3, #PCB_ONFAULT]
85137463Scognet	RET
86137271Scognet
87137271Scognet/*
88163449Sdavidxu * Handle faults from casuword.  Clean up and return -1.
89145452Scognet */
90145452Scognet
91163449Sdavidxu.Lcasuwordfault:
92145452Scognet	mov	r0, #0x00000000
93145452Scognet	str	r0, [r3, #PCB_ONFAULT]
94145452Scognet	mvn	r0, #0x00000000
95145452Scognet	ldmfd	sp!, {r4, r5}
96145452Scognet	RET
97145452Scognet/*
98137271Scognet * fuword(caddr_t uaddr);
99137271Scognet * Fetch an int from the user's address space.
100137271Scognet */
101137271Scognet
102161734ScognetENTRY_NP(fuword32)
103129198ScognetENTRY(fuword)
104129198Scognet#ifdef MULTIPROCESSOR
105129198Scognet	/* XXX Probably not appropriate for non-Hydra SMPs */
106129198Scognet	stmfd	sp!, {r0, r14}
107129198Scognet	bl	_C_LABEL(cpu_number)
108129198Scognet	ldr	r2, .Lcpu_info
109129198Scognet	ldr	r2, [r2, r0, lsl #2]
110129198Scognet	ldr	r2, [r2, #CI_CURPCB]
111129198Scognet	ldmfd	sp!, {r0, r14}
112129198Scognet#else
113129198Scognet	ldr	r2, .Lcurpcb
114129198Scognet	ldr	r2, [r2]
115129198Scognet#endif
116129198Scognet
117129198Scognet#ifdef DIAGNOSTIC
118129198Scognet	teq	r2, #0x00000000
119129198Scognet	beq	.Lfusupcbfault
120129198Scognet#endif
121129198Scognet
122129198Scognet	adr	r1, .Lfusufault
123129198Scognet	str	r1, [r2, #PCB_ONFAULT]
124129198Scognet
125129198Scognet	ldrt	r3, [r0]
126129198Scognet
127129198Scognet	mov	r1, #0x00000000
128129198Scognet	str	r1, [r2, #PCB_ONFAULT]
129129198Scognet	mov	r0, r3
130137463Scognet	RET
131129198Scognet
132129198Scognet/*
133129198Scognet * fusword(caddr_t uaddr);
134129198Scognet * Fetch a short from the user's address space.
135129198Scognet */
136129198Scognet
137129198ScognetENTRY(fusword)
138129198Scognet#ifdef MULTIPROCESSOR
139129198Scognet	/* XXX Probably not appropriate for non-Hydra SMPs */
140129198Scognet	stmfd	sp!, {r0, r14}
141129198Scognet	bl	_C_LABEL(cpu_number)
142129198Scognet	ldr	r2, .Lcpu_info
143129198Scognet	ldr	r2, [r2, r0, lsl #2]
144129198Scognet	ldr	r2, [r2, #CI_CURPCB]
145129198Scognet	ldmfd	sp!, {r0, r14}
146129198Scognet#else
147129198Scognet	ldr	r2, .Lcurpcb
148129198Scognet	ldr	r2, [r2]
149129198Scognet#endif
150129198Scognet
151129198Scognet#ifdef DIAGNOSTIC
152129198Scognet	teq	r2, #0x00000000
153129198Scognet	beq	.Lfusupcbfault
154129198Scognet#endif
155129198Scognet
156129198Scognet	adr	r1, .Lfusufault
157129198Scognet	str	r1, [r2, #PCB_ONFAULT]
158129198Scognet
159129198Scognet	ldrbt	r3, [r0], #1
160129198Scognet	ldrbt	ip, [r0]
161129198Scognet#ifdef __ARMEB__
162129198Scognet	orr	r0, ip, r3, asl #8
163129198Scognet#else
164129198Scognet	orr	r0, r3, ip, asl #8
165129198Scognet#endif
166129198Scognet	mov	r1, #0x00000000
167129198Scognet	str	r1, [r2, #PCB_ONFAULT]
168137463Scognet	RET
169129198Scognet
170129198Scognet/*
171129198Scognet * fuswintr(caddr_t uaddr);
172129198Scognet * Fetch a short from the user's address space.  Can be called during an
173129198Scognet * interrupt.
174129198Scognet */
175129198Scognet
176129198ScognetENTRY(fuswintr)
177129198Scognet	ldr	r2, Lblock_userspace_access
178129198Scognet	ldr	r2, [r2]
179129198Scognet	teq	r2, #0
180129198Scognet	mvnne	r0, #0x00000000
181137463Scognet	RETne
182129198Scognet
183129198Scognet#ifdef MULTIPROCESSOR
184129198Scognet	/* XXX Probably not appropriate for non-Hydra SMPs */
185129198Scognet	stmfd	sp!, {r0, r14}
186129198Scognet	bl	_C_LABEL(cpu_number)
187129198Scognet	ldr	r2, .Lcpu_info
188129198Scognet	ldr	r2, [r2, r0, lsl #2]
189129198Scognet	ldr	r2, [r2, #CI_CURPCB]
190129198Scognet	ldmfd	sp!, {r0, r14}
191129198Scognet#else
192129198Scognet	ldr	r2, .Lcurpcb
193129198Scognet	ldr	r2, [r2]
194129198Scognet#endif
195129198Scognet
196129198Scognet#ifdef DIAGNOSTIC
197129198Scognet	teq	r2, #0x00000000
198129198Scognet	beq	.Lfusupcbfault
199129198Scognet#endif
200129198Scognet
201129198Scognet	adr	r1, _C_LABEL(fusubailout)
202129198Scognet	str	r1, [r2, #PCB_ONFAULT]
203129198Scognet
204129198Scognet	ldrbt	r3, [r0], #1
205129198Scognet	ldrbt	ip, [r0]
206129198Scognet#ifdef __ARMEB__
207129198Scognet	orr	r0, ip, r3, asl #8
208129198Scognet#else
209129198Scognet	orr	r0, r3, ip, asl #8
210129198Scognet#endif
211129198Scognet
212129198Scognet	mov	r1, #0x00000000
213129198Scognet	str	r1, [r2, #PCB_ONFAULT]
214137463Scognet	RET
215129198Scognet
216129198ScognetLblock_userspace_access:
217129198Scognet	.word	_C_LABEL(block_userspace_access)
218129198Scognet
219129198Scognet	.data
220129198Scognet	.align	0
221129198Scognet	.global	_C_LABEL(block_userspace_access)
222129198Scognet_C_LABEL(block_userspace_access):
223129198Scognet	.word	0
224129198Scognet	.text
225129198Scognet
226129198Scognet/*
227129198Scognet * fubyte(caddr_t uaddr);
228129198Scognet * Fetch a byte from the user's address space.
229129198Scognet */
230129198Scognet
231129198ScognetENTRY(fubyte)
232129198Scognet#ifdef MULTIPROCESSOR
233129198Scognet	/* XXX Probably not appropriate for non-Hydra SMPs */
234129198Scognet	stmfd	sp!, {r0, r14}
235129198Scognet	bl	_C_LABEL(cpu_number)
236129198Scognet	ldr	r2, .Lcpu_info
237129198Scognet	ldr	r2, [r2, r0, lsl #2]
238129198Scognet	ldr	r2, [r2, #CI_CURPCB]
239129198Scognet	ldmfd	sp!, {r0, r14}
240129198Scognet#else
241129198Scognet	ldr	r2, .Lcurpcb
242129198Scognet	ldr	r2, [r2]
243129198Scognet#endif
244129198Scognet
245129198Scognet#ifdef DIAGNOSTIC
246129198Scognet	teq	r2, #0x00000000
247129198Scognet	beq	.Lfusupcbfault
248129198Scognet#endif
249129198Scognet
250129198Scognet	adr	r1, .Lfusufault
251129198Scognet	str	r1, [r2, #PCB_ONFAULT]
252129198Scognet
253129198Scognet	ldrbt	r3, [r0]
254129198Scognet
255129198Scognet	mov	r1, #0x00000000
256129198Scognet	str	r1, [r2, #PCB_ONFAULT]
257129198Scognet	mov	r0, r3
258137463Scognet	RET
259129198Scognet
260129198Scognet/*
261129198Scognet * Handle faults from [fs]u*().  Clean up and return -1.
262129198Scognet */
263129198Scognet
264129198Scognet.Lfusufault:
265129198Scognet	mov	r0, #0x00000000
266129198Scognet	str	r0, [r2, #PCB_ONFAULT]
267129198Scognet	mvn	r0, #0x00000000
268137463Scognet	RET
269129198Scognet
270129198Scognet/*
271129198Scognet * Handle faults from [fs]u*().  Clean up and return -1.  This differs from
272129198Scognet * fusufault() in that trap() will recognise it and return immediately rather
273129198Scognet * than trying to page fault.
274129198Scognet */
275129198Scognet
276129198Scognet/* label must be global as fault.c references it */
277129198Scognet	.global	_C_LABEL(fusubailout)
278129198Scognet_C_LABEL(fusubailout):
279129198Scognet	mov	r0, #0x00000000
280129198Scognet	str	r0, [r2, #PCB_ONFAULT]
281129198Scognet	mvn	r0, #0x00000000
282137463Scognet	RET
283129198Scognet
284129198Scognet#ifdef DIAGNOSTIC
285129198Scognet/*
286129198Scognet * Handle earlier faults from [fs]u*(), due to no pcb
287129198Scognet */
288129198Scognet
289129198Scognet.Lfusupcbfault:
290129198Scognet	mov	r1, r0
291129198Scognet	adr	r0, fusupcbfaulttext
292129198Scognet	b	_C_LABEL(panic)
293129198Scognet
294129198Scognetfusupcbfaulttext:
295129198Scognet	.asciz	"Yikes - no valid PCB during fusuxxx() addr=%08x\n"
296129198Scognet	.align	0
297129198Scognet#endif
298129198Scognet
299129198Scognet/*
300129198Scognet * suword(caddr_t uaddr, int x);
301129198Scognet * Store an int in the user's address space.
302129198Scognet */
303129198Scognet
304161734ScognetENTRY_NP(suword32)
305129198ScognetENTRY(suword)
306129198Scognet#ifdef MULTIPROCESSOR
307129198Scognet	/* XXX Probably not appropriate for non-Hydra SMPs */
308129198Scognet	stmfd	sp!, {r0, r1, r14}
309129198Scognet	bl	_C_LABEL(cpu_number)
310129198Scognet	ldr	r2, .Lcpu_info
311129198Scognet	ldr	r2, [r2, r0, lsl #2]
312129198Scognet	ldr	r2, [r2, #CI_CURPCB]
313129198Scognet	ldmfd	sp!, {r0, r1, r14}
314129198Scognet#else
315129198Scognet	ldr	r2, .Lcurpcb
316129198Scognet	ldr	r2, [r2]
317129198Scognet#endif
318129198Scognet
319129198Scognet#ifdef DIAGNOSTIC
320129198Scognet	teq	r2, #0x00000000
321129198Scognet	beq	.Lfusupcbfault
322129198Scognet#endif
323129198Scognet
324129198Scognet	adr	r3, .Lfusufault
325129198Scognet	str	r3, [r2, #PCB_ONFAULT]
326129198Scognet
327129198Scognet	strt	r1, [r0]
328129198Scognet
329129198Scognet	mov	r0, #0x00000000
330129198Scognet	str	r0, [r2, #PCB_ONFAULT]
331137463Scognet	RET
332129198Scognet
333129198Scognet/*
334129198Scognet * suswintr(caddr_t uaddr, short x);
335129198Scognet * Store a short in the user's address space.  Can be called during an
336129198Scognet * interrupt.
337129198Scognet */
338129198Scognet
339129198ScognetENTRY(suswintr)
340129198Scognet	ldr	r2, Lblock_userspace_access
341129198Scognet	ldr	r2, [r2]
342129198Scognet	teq	r2, #0
343129198Scognet	mvnne	r0, #0x00000000
344137463Scognet	RETne
345129198Scognet
346129198Scognet#ifdef MULTIPROCESSOR
347129198Scognet	stmfd	sp!, {r0, r1, r14}
348129198Scognet	bl	_C_LABEL(cpu_number)
349129198Scognet	ldr	r2, .Lcpu_info
350129198Scognet	ldr	r2, [r2, r0, lsl #2]
351129198Scognet	ldr	r2, [r2, #CI_CURPCB]
352129198Scognet	ldmfd	sp!, {r0, r1, r14}
353129198Scognet#else
354129198Scognet	ldr	r2, .Lcurpcb
355129198Scognet	ldr	r2, [r2]
356129198Scognet#endif
357129198Scognet
358129198Scognet#ifdef DIAGNOSTIC
359129198Scognet	teq	r2, #0x00000000
360129198Scognet	beq	.Lfusupcbfault
361129198Scognet#endif
362129198Scognet
363129198Scognet	adr	r3, _C_LABEL(fusubailout)
364129198Scognet	str	r3, [r2, #PCB_ONFAULT]
365129198Scognet
366129198Scognet#ifdef __ARMEB__
367129198Scognet	mov	ip, r1, lsr #8
368129198Scognet	strbt	ip, [r0], #1
369129198Scognet#else
370129198Scognet	strbt	r1, [r0], #1
371129198Scognet	mov	r1, r1, lsr #8
372129198Scognet#endif
373129198Scognet	strbt	r1, [r0]
374129198Scognet
375129198Scognet	mov	r0, #0x00000000
376129198Scognet	str	r0, [r2, #PCB_ONFAULT]
377137463Scognet	RET
378129198Scognet
379129198Scognet/*
380129198Scognet * susword(caddr_t uaddr, short x);
381129198Scognet * Store a short in the user's address space.
382129198Scognet */
383129198Scognet
384129198ScognetENTRY(susword)
385129198Scognet#ifdef MULTIPROCESSOR
386129198Scognet	stmfd	sp!, {r0, r1, r14}
387129198Scognet	bl	_C_LABEL(cpu_number)
388129198Scognet	ldr	r2, .Lcpu_info
389129198Scognet	ldr	r2, [r2, r0, lsl #2]
390129198Scognet	ldr	r2, [r2, #CI_CURPCB]
391129198Scognet	ldmfd	sp!, {r0, r1, r14}
392129198Scognet#else
393129198Scognet	ldr	r2, .Lcurpcb
394129198Scognet	ldr	r2, [r2]
395129198Scognet#endif
396129198Scognet
397129198Scognet#ifdef DIAGNOSTIC
398129198Scognet	teq	r2, #0x00000000
399129198Scognet	beq	.Lfusupcbfault
400129198Scognet#endif
401129198Scognet
402129198Scognet	adr	r3, .Lfusufault
403129198Scognet	str	r3, [r2, #PCB_ONFAULT]
404129198Scognet
405129198Scognet#ifdef __ARMEB__
406129198Scognet	mov	ip, r1, lsr #8
407129198Scognet	strbt	ip, [r0], #1
408129198Scognet#else
409129198Scognet	strbt	r1, [r0], #1
410129198Scognet	mov	r1, r1, lsr #8
411129198Scognet#endif
412129198Scognet	strbt	r1, [r0]
413129198Scognet
414129198Scognet	mov	r0, #0x00000000
415129198Scognet	str	r0, [r2, #PCB_ONFAULT]
416137463Scognet	RET
417129198Scognet
418129198Scognet/*
419129198Scognet * subyte(caddr_t uaddr, char x);
420129198Scognet * Store a byte in the user's address space.
421129198Scognet */
422129198Scognet
423129198ScognetENTRY(subyte)
424129198Scognet#ifdef MULTIPROCESSOR
425129198Scognet	stmfd	sp!, {r0, r1, r14}
426129198Scognet	bl	_C_LABEL(cpu_number)
427129198Scognet	ldr	r2, .Lcpu_info
428129198Scognet	ldr	r2, [r2, r0, lsl #2]
429129198Scognet	ldr	r2, [r2, #CI_CURPCB]
430129198Scognet	ldmfd	sp!, {r0, r1, r14}
431129198Scognet#else
432129198Scognet	ldr	r2, .Lcurpcb
433129198Scognet	ldr	r2, [r2]
434129198Scognet#endif
435129198Scognet
436129198Scognet
437129198Scognet#ifdef DIAGNOSTIC
438129198Scognet	teq	r2, #0x00000000
439129198Scognet	beq	.Lfusupcbfault
440129198Scognet#endif
441129198Scognet
442129198Scognet	adr	r3, .Lfusufault
443129198Scognet	str	r3, [r2, #PCB_ONFAULT]
444129198Scognet
445129198Scognet	strbt	r1, [r0]
446129198Scognet	mov	r0, #0x00000000
447129198Scognet	str	r0, [r2, #PCB_ONFAULT]
448137463Scognet	RET
449