xref: /freebsd/sys/arm/arm/fusu.S (revision aa0a1e58)
1/*	$NetBSD: fusu.S,v 1.10 2003/12/01 13:34:44 rearnsha Exp $	*/
2
3/*-
4 * Copyright (c) 1996-1998 Mark Brinicombe.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by Mark Brinicombe
18 * 4. The name of the company nor the name of the author may be used to
19 *    endorse or promote products derived from this software without specific
20 *    prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35
36#include <machine/asm.h>
37#include <machine/asmacros.h>
38#include <machine/armreg.h>
39#include "assym.s"
40__FBSDID("$FreeBSD$");
41
42#ifdef MULTIPROCESSOR
43.Lcpu_info:
44	.word	_C_LABEL(cpu_info)
45#else
46.Lcurpcb:
47	.word	_C_LABEL(__pcpu) + PC_CURPCB
48#endif
49
50/*
51 * fuword(caddr_t uaddr);
52 * Fetch an int from the user's address space.
53 */
54
55ENTRY_NP(casuword32)
56ENTRY(casuword)
57#ifdef MULTIPROCESSOR
58	/* XXX Probably not appropriate for non-Hydra SMPs */
59	stmfd	sp!, {r0, r14}
60	bl	_C_LABEL(cpu_number)
61	ldr	r2, .Lcpu_info
62	ldr	r2, [r2, r0, lsl #2]
63	ldr	r2, [r2, #CI_CURPCB]
64	ldmfd	sp!, {r0, r14}
65#else
66	ldr	r3, .Lcurpcb
67	ldr	r3, [r3]
68#endif
69
70#ifdef DIAGNOSTIC
71	teq	r3, #0x00000000
72	beq	.Lfusupcbfault
73#endif
74	stmfd	sp!, {r4, r5}
75	adr	r4, .Lcasuwordfault
76	str	r4, [r3, #PCB_ONFAULT]
77	ldrt	r5, [r0]
78	cmp	r5, r1
79	movne	r0, r5
80	streqt	r2, [r0]
81	moveq	r0, r1
82	ldmfd	sp!, {r4, r5}
83	mov	r1, #0x00000000
84	str	r1, [r3, #PCB_ONFAULT]
85	RET
86
87/*
88 * Handle faults from casuword.  Clean up and return -1.
89 */
90
91.Lcasuwordfault:
92	mov	r0, #0x00000000
93	str	r0, [r3, #PCB_ONFAULT]
94	mvn	r0, #0x00000000
95	ldmfd	sp!, {r4, r5}
96	RET
97/*
98 * fuword(caddr_t uaddr);
99 * Fetch an int from the user's address space.
100 */
101
102ENTRY_NP(fuword32)
103ENTRY(fuword)
104#ifdef MULTIPROCESSOR
105	/* XXX Probably not appropriate for non-Hydra SMPs */
106	stmfd	sp!, {r0, r14}
107	bl	_C_LABEL(cpu_number)
108	ldr	r2, .Lcpu_info
109	ldr	r2, [r2, r0, lsl #2]
110	ldr	r2, [r2, #CI_CURPCB]
111	ldmfd	sp!, {r0, r14}
112#else
113	ldr	r2, .Lcurpcb
114	ldr	r2, [r2]
115#endif
116
117#ifdef DIAGNOSTIC
118	teq	r2, #0x00000000
119	beq	.Lfusupcbfault
120#endif
121
122	adr	r1, .Lfusufault
123	str	r1, [r2, #PCB_ONFAULT]
124
125	ldrt	r3, [r0]
126
127	mov	r1, #0x00000000
128	str	r1, [r2, #PCB_ONFAULT]
129	mov	r0, r3
130	RET
131
132/*
133 * fusword(caddr_t uaddr);
134 * Fetch a short from the user's address space.
135 */
136
137ENTRY(fusword)
138#ifdef MULTIPROCESSOR
139	/* XXX Probably not appropriate for non-Hydra SMPs */
140	stmfd	sp!, {r0, r14}
141	bl	_C_LABEL(cpu_number)
142	ldr	r2, .Lcpu_info
143	ldr	r2, [r2, r0, lsl #2]
144	ldr	r2, [r2, #CI_CURPCB]
145	ldmfd	sp!, {r0, r14}
146#else
147	ldr	r2, .Lcurpcb
148	ldr	r2, [r2]
149#endif
150
151#ifdef DIAGNOSTIC
152	teq	r2, #0x00000000
153	beq	.Lfusupcbfault
154#endif
155
156	adr	r1, .Lfusufault
157	str	r1, [r2, #PCB_ONFAULT]
158
159	ldrbt	r3, [r0], #1
160	ldrbt	ip, [r0]
161#ifdef __ARMEB__
162	orr	r0, ip, r3, asl #8
163#else
164	orr	r0, r3, ip, asl #8
165#endif
166	mov	r1, #0x00000000
167	str	r1, [r2, #PCB_ONFAULT]
168	RET
169
170/*
171 * fuswintr(caddr_t uaddr);
172 * Fetch a short from the user's address space.  Can be called during an
173 * interrupt.
174 */
175
176ENTRY(fuswintr)
177	ldr	r2, Lblock_userspace_access
178	ldr	r2, [r2]
179	teq	r2, #0
180	mvnne	r0, #0x00000000
181	RETne
182
183#ifdef MULTIPROCESSOR
184	/* XXX Probably not appropriate for non-Hydra SMPs */
185	stmfd	sp!, {r0, r14}
186	bl	_C_LABEL(cpu_number)
187	ldr	r2, .Lcpu_info
188	ldr	r2, [r2, r0, lsl #2]
189	ldr	r2, [r2, #CI_CURPCB]
190	ldmfd	sp!, {r0, r14}
191#else
192	ldr	r2, .Lcurpcb
193	ldr	r2, [r2]
194#endif
195
196#ifdef DIAGNOSTIC
197	teq	r2, #0x00000000
198	beq	.Lfusupcbfault
199#endif
200
201	adr	r1, _C_LABEL(fusubailout)
202	str	r1, [r2, #PCB_ONFAULT]
203
204	ldrbt	r3, [r0], #1
205	ldrbt	ip, [r0]
206#ifdef __ARMEB__
207	orr	r0, ip, r3, asl #8
208#else
209	orr	r0, r3, ip, asl #8
210#endif
211
212	mov	r1, #0x00000000
213	str	r1, [r2, #PCB_ONFAULT]
214	RET
215
216Lblock_userspace_access:
217	.word	_C_LABEL(block_userspace_access)
218
219	.data
220	.align	0
221	.global	_C_LABEL(block_userspace_access)
222_C_LABEL(block_userspace_access):
223	.word	0
224	.text
225
226/*
227 * fubyte(caddr_t uaddr);
228 * Fetch a byte from the user's address space.
229 */
230
231ENTRY(fubyte)
232#ifdef MULTIPROCESSOR
233	/* XXX Probably not appropriate for non-Hydra SMPs */
234	stmfd	sp!, {r0, r14}
235	bl	_C_LABEL(cpu_number)
236	ldr	r2, .Lcpu_info
237	ldr	r2, [r2, r0, lsl #2]
238	ldr	r2, [r2, #CI_CURPCB]
239	ldmfd	sp!, {r0, r14}
240#else
241	ldr	r2, .Lcurpcb
242	ldr	r2, [r2]
243#endif
244
245#ifdef DIAGNOSTIC
246	teq	r2, #0x00000000
247	beq	.Lfusupcbfault
248#endif
249
250	adr	r1, .Lfusufault
251	str	r1, [r2, #PCB_ONFAULT]
252
253	ldrbt	r3, [r0]
254
255	mov	r1, #0x00000000
256	str	r1, [r2, #PCB_ONFAULT]
257	mov	r0, r3
258	RET
259
260/*
261 * Handle faults from [fs]u*().  Clean up and return -1.
262 */
263
264.Lfusufault:
265	mov	r0, #0x00000000
266	str	r0, [r2, #PCB_ONFAULT]
267	mvn	r0, #0x00000000
268	RET
269
270/*
271 * Handle faults from [fs]u*().  Clean up and return -1.  This differs from
272 * fusufault() in that trap() will recognise it and return immediately rather
273 * than trying to page fault.
274 */
275
276/* label must be global as fault.c references it */
277	.global	_C_LABEL(fusubailout)
278_C_LABEL(fusubailout):
279	mov	r0, #0x00000000
280	str	r0, [r2, #PCB_ONFAULT]
281	mvn	r0, #0x00000000
282	RET
283
284#ifdef DIAGNOSTIC
285/*
286 * Handle earlier faults from [fs]u*(), due to no pcb
287 */
288
289.Lfusupcbfault:
290	mov	r1, r0
291	adr	r0, fusupcbfaulttext
292	b	_C_LABEL(panic)
293
294fusupcbfaulttext:
295	.asciz	"Yikes - no valid PCB during fusuxxx() addr=%08x\n"
296	.align	0
297#endif
298
299/*
300 * suword(caddr_t uaddr, int x);
301 * Store an int in the user's address space.
302 */
303
304ENTRY_NP(suword32)
305ENTRY(suword)
306#ifdef MULTIPROCESSOR
307	/* XXX Probably not appropriate for non-Hydra SMPs */
308	stmfd	sp!, {r0, r1, r14}
309	bl	_C_LABEL(cpu_number)
310	ldr	r2, .Lcpu_info
311	ldr	r2, [r2, r0, lsl #2]
312	ldr	r2, [r2, #CI_CURPCB]
313	ldmfd	sp!, {r0, r1, r14}
314#else
315	ldr	r2, .Lcurpcb
316	ldr	r2, [r2]
317#endif
318
319#ifdef DIAGNOSTIC
320	teq	r2, #0x00000000
321	beq	.Lfusupcbfault
322#endif
323
324	adr	r3, .Lfusufault
325	str	r3, [r2, #PCB_ONFAULT]
326
327	strt	r1, [r0]
328
329	mov	r0, #0x00000000
330	str	r0, [r2, #PCB_ONFAULT]
331	RET
332
333/*
334 * suswintr(caddr_t uaddr, short x);
335 * Store a short in the user's address space.  Can be called during an
336 * interrupt.
337 */
338
339ENTRY(suswintr)
340	ldr	r2, Lblock_userspace_access
341	ldr	r2, [r2]
342	teq	r2, #0
343	mvnne	r0, #0x00000000
344	RETne
345
346#ifdef MULTIPROCESSOR
347	stmfd	sp!, {r0, r1, r14}
348	bl	_C_LABEL(cpu_number)
349	ldr	r2, .Lcpu_info
350	ldr	r2, [r2, r0, lsl #2]
351	ldr	r2, [r2, #CI_CURPCB]
352	ldmfd	sp!, {r0, r1, r14}
353#else
354	ldr	r2, .Lcurpcb
355	ldr	r2, [r2]
356#endif
357
358#ifdef DIAGNOSTIC
359	teq	r2, #0x00000000
360	beq	.Lfusupcbfault
361#endif
362
363	adr	r3, _C_LABEL(fusubailout)
364	str	r3, [r2, #PCB_ONFAULT]
365
366#ifdef __ARMEB__
367	mov	ip, r1, lsr #8
368	strbt	ip, [r0], #1
369#else
370	strbt	r1, [r0], #1
371	mov	r1, r1, lsr #8
372#endif
373	strbt	r1, [r0]
374
375	mov	r0, #0x00000000
376	str	r0, [r2, #PCB_ONFAULT]
377	RET
378
379/*
380 * susword(caddr_t uaddr, short x);
381 * Store a short in the user's address space.
382 */
383
384ENTRY(susword)
385#ifdef MULTIPROCESSOR
386	stmfd	sp!, {r0, r1, r14}
387	bl	_C_LABEL(cpu_number)
388	ldr	r2, .Lcpu_info
389	ldr	r2, [r2, r0, lsl #2]
390	ldr	r2, [r2, #CI_CURPCB]
391	ldmfd	sp!, {r0, r1, r14}
392#else
393	ldr	r2, .Lcurpcb
394	ldr	r2, [r2]
395#endif
396
397#ifdef DIAGNOSTIC
398	teq	r2, #0x00000000
399	beq	.Lfusupcbfault
400#endif
401
402	adr	r3, .Lfusufault
403	str	r3, [r2, #PCB_ONFAULT]
404
405#ifdef __ARMEB__
406	mov	ip, r1, lsr #8
407	strbt	ip, [r0], #1
408#else
409	strbt	r1, [r0], #1
410	mov	r1, r1, lsr #8
411#endif
412	strbt	r1, [r0]
413
414	mov	r0, #0x00000000
415	str	r0, [r2, #PCB_ONFAULT]
416	RET
417
418/*
419 * subyte(caddr_t uaddr, char x);
420 * Store a byte in the user's address space.
421 */
422
423ENTRY(subyte)
424#ifdef MULTIPROCESSOR
425	stmfd	sp!, {r0, r1, r14}
426	bl	_C_LABEL(cpu_number)
427	ldr	r2, .Lcpu_info
428	ldr	r2, [r2, r0, lsl #2]
429	ldr	r2, [r2, #CI_CURPCB]
430	ldmfd	sp!, {r0, r1, r14}
431#else
432	ldr	r2, .Lcurpcb
433	ldr	r2, [r2]
434#endif
435
436
437#ifdef DIAGNOSTIC
438	teq	r2, #0x00000000
439	beq	.Lfusupcbfault
440#endif
441
442	adr	r3, .Lfusufault
443	str	r3, [r2, #PCB_ONFAULT]
444
445	strbt	r1, [r0]
446	mov	r0, #0x00000000
447	str	r0, [r2, #PCB_ONFAULT]
448	RET
449