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
41275520Sandrew	.syntax	unified
42275520Sandrew
43282763Sandrew#if __ARM_ARCH >= 6
44239268Sgonzo#define GET_PCB(tmp) \
45239268Sgonzo	mrc p15, 0, tmp, c13, c0, 4; \
46261415Scognet	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/*
55289372Skib * casueword32(volatile uint32_t *base, uint32_t oldval, uint32_t *oldvalp,
56289372Skib *    uint32_t newval);
57129198Scognet */
58129198Scognet
59289372SkibENTRY(casueword)
60289372SkibEENTRY_NP(casueword32)
61289372Skib	stmfd	sp!, {r4, r5, r6}
62137271Scognet
63289372Skib	ldr	r4, =(VM_MAXUSER_ADDRESS-3)
64289372Skib	cmp	r0, r4
65289372Skib	mvncs	r0, #0
66289372Skib	bcs	2f
67289372Skib
68289372Skib	GET_PCB(r6)
69289372Skib	ldr	r6, [r6]
70289372Skib
71137271Scognet#ifdef DIAGNOSTIC
72289372Skib	teq	r6, #0x00000000
73289372Skib	ldmfdeq	sp!, {r4, r5, r6}
74137271Scognet	beq	.Lfusupcbfault
75137271Scognet#endif
76289372Skib
77163449Sdavidxu	adr	r4, .Lcasuwordfault
78289372Skib	str	r4, [r6, #PCB_ONFAULT]
79289372Skib
80282763Sandrew#if __ARM_ARCH >= 6
81283366Sandrew1:
82289372Skib	ldrex	r4, [r0]
83289372Skib	cmp	r4, r1
84289372Skib	strexeq	r5, r3, [r0]
85289372Skib	cmpeq	r5, #1
86289372Skib	beq	1b
87256691Scognet#else
88289372Skib	ldrt	r4, [r0]
89289372Skib	cmp	r4, r1
90289372Skib	strteq	r3, [r0]
91256691Scognet#endif
92289372Skib	str	r4, [r2]
93289372Skib	mov	r0, #0
94289372Skib	str	r0, [r6, #PCB_ONFAULT]
95256691Scognet2:
96289372Skib	ldmfd	sp!, {r4, r5, r6}
97137463Scognet	RET
98289372SkibEEND(casueword32)
99289372SkibEND(casueword)
100137271Scognet
101137271Scognet/*
102163449Sdavidxu * Handle faults from casuword.  Clean up and return -1.
103145452Scognet */
104145452Scognet
105163449Sdavidxu.Lcasuwordfault:
106145452Scognet	mov	r0, #0x00000000
107289372Skib	str	r0, [r6, #PCB_ONFAULT]
108289372Skib	mvn	r0, #0
109289372Skib	ldmfd	sp!, {r4, r5, r6}
110283366Sandrew	RET
111248361Sandrew
112145452Scognet/*
113289372Skib * fueword(caddr_t uaddr, long *val);
114137271Scognet * Fetch an int from the user's address space.
115137271Scognet */
116137271Scognet
117289372SkibENTRY(fueword)
118289372SkibEENTRY_NP(fueword32)
119289372Skib	ldr	r3, =(VM_MAXUSER_ADDRESS-3)
120289372Skib	cmp	r0, r3
121289372Skib	mvncs	r0, #0
122289372Skib	RETc(cs)
123289372Skib
124239268Sgonzo	GET_PCB(r2)
125129198Scognet	ldr	r2, [r2]
126129198Scognet
127129198Scognet#ifdef DIAGNOSTIC
128129198Scognet	teq	r2, #0x00000000
129129198Scognet	beq	.Lfusupcbfault
130129198Scognet#endif
131129198Scognet
132289372Skib	adr	r3, .Lfusufault
133289372Skib	str	r3, [r2, #PCB_ONFAULT]
134129198Scognet
135129198Scognet	ldrt	r3, [r0]
136289372Skib	str	r3, [r1]
137129198Scognet
138289372Skib	mov	r0, #0x00000000
139289372Skib	str	r0, [r2, #PCB_ONFAULT]
140137463Scognet	RET
141293830SianEEND(fueword32)
142293830SianEND(fueword)
143129198Scognet
144129198Scognet/*
145129198Scognet * fusword(caddr_t uaddr);
146129198Scognet * Fetch a short from the user's address space.
147129198Scognet */
148129198Scognet
149129198ScognetENTRY(fusword)
150289372Skib	ldr	r3, =(VM_MAXUSER_ADDRESS-1)
151289372Skib	cmp	r0, r3
152289372Skib	mvncs	r0, #0
153289372Skib	RETc(cs)
154289372Skib
155239268Sgonzo	GET_PCB(r2)
156129198Scognet	ldr	r2, [r2]
157129198Scognet
158129198Scognet#ifdef DIAGNOSTIC
159129198Scognet	teq	r2, #0x00000000
160129198Scognet	beq	.Lfusupcbfault
161129198Scognet#endif
162129198Scognet
163129198Scognet	adr	r1, .Lfusufault
164129198Scognet	str	r1, [r2, #PCB_ONFAULT]
165129198Scognet
166129198Scognet	ldrbt	r3, [r0], #1
167129198Scognet	ldrbt	ip, [r0]
168129198Scognet#ifdef __ARMEB__
169129198Scognet	orr	r0, ip, r3, asl #8
170129198Scognet#else
171129198Scognet	orr	r0, r3, ip, asl #8
172129198Scognet#endif
173129198Scognet	mov	r1, #0x00000000
174129198Scognet	str	r1, [r2, #PCB_ONFAULT]
175137463Scognet	RET
176248361SandrewEND(fusword)
177129198Scognet
178129198Scognet/*
179129198Scognet * fuswintr(caddr_t uaddr);
180129198Scognet * Fetch a short from the user's address space.  Can be called during an
181129198Scognet * interrupt.
182129198Scognet */
183129198Scognet
184129198ScognetENTRY(fuswintr)
185295267Smmel	mov	r0, #-1
186137463Scognet	RET
187248361SandrewEND(fuswintr)
188129198Scognet
189129198Scognet/*
190129198Scognet * fubyte(caddr_t uaddr);
191129198Scognet * Fetch a byte from the user's address space.
192129198Scognet */
193129198Scognet
194129198ScognetENTRY(fubyte)
195289372Skib	ldr	r3, =VM_MAXUSER_ADDRESS
196289372Skib	cmp	r0, r3
197289372Skib	mvncs	r0, #0
198289372Skib	RETc(cs)
199289372Skib
200239268Sgonzo	GET_PCB(r2)
201129198Scognet	ldr	r2, [r2]
202129198Scognet
203129198Scognet#ifdef DIAGNOSTIC
204129198Scognet	teq	r2, #0x00000000
205129198Scognet	beq	.Lfusupcbfault
206129198Scognet#endif
207129198Scognet
208129198Scognet	adr	r1, .Lfusufault
209129198Scognet	str	r1, [r2, #PCB_ONFAULT]
210129198Scognet
211129198Scognet	ldrbt	r3, [r0]
212129198Scognet
213129198Scognet	mov	r1, #0x00000000
214129198Scognet	str	r1, [r2, #PCB_ONFAULT]
215129198Scognet	mov	r0, r3
216137463Scognet	RET
217248361SandrewEND(fubyte)
218129198Scognet
219129198Scognet/*
220129198Scognet * Handle faults from [fs]u*().  Clean up and return -1.
221129198Scognet */
222129198Scognet
223129198Scognet.Lfusufault:
224129198Scognet	mov	r0, #0x00000000
225129198Scognet	str	r0, [r2, #PCB_ONFAULT]
226129198Scognet	mvn	r0, #0x00000000
227137463Scognet	RET
228129198Scognet
229129198Scognet#ifdef DIAGNOSTIC
230129198Scognet/*
231129198Scognet * Handle earlier faults from [fs]u*(), due to no pcb
232129198Scognet */
233129198Scognet
234129198Scognet.Lfusupcbfault:
235129198Scognet	mov	r1, r0
236129198Scognet	adr	r0, fusupcbfaulttext
237129198Scognet	b	_C_LABEL(panic)
238129198Scognet
239129198Scognetfusupcbfaulttext:
240129198Scognet	.asciz	"Yikes - no valid PCB during fusuxxx() addr=%08x\n"
241275521Sandrew	.align	2
242129198Scognet#endif
243129198Scognet
244129198Scognet/*
245129198Scognet * suword(caddr_t uaddr, int x);
246129198Scognet * Store an int in the user's address space.
247129198Scognet */
248129198Scognet
249129198ScognetENTRY(suword)
250269390SianEENTRY_NP(suword32)
251289372Skib	ldr	r3, =(VM_MAXUSER_ADDRESS-3)
252289372Skib	cmp	r0, r3
253289372Skib	mvncs	r0, #0
254289372Skib	RETc(cs)
255289372Skib
256239268Sgonzo	GET_PCB(r2)
257129198Scognet	ldr	r2, [r2]
258129198Scognet
259129198Scognet#ifdef DIAGNOSTIC
260129198Scognet	teq	r2, #0x00000000
261129198Scognet	beq	.Lfusupcbfault
262129198Scognet#endif
263129198Scognet
264129198Scognet	adr	r3, .Lfusufault
265129198Scognet	str	r3, [r2, #PCB_ONFAULT]
266129198Scognet
267129198Scognet	strt	r1, [r0]
268129198Scognet
269129198Scognet	mov	r0, #0x00000000
270129198Scognet	str	r0, [r2, #PCB_ONFAULT]
271137463Scognet	RET
272275322SandrewEEND(suword32)
273248361SandrewEND(suword)
274129198Scognet
275129198Scognet/*
276129198Scognet * suswintr(caddr_t uaddr, short x);
277129198Scognet * Store a short in the user's address space.  Can be called during an
278129198Scognet * interrupt.
279129198Scognet */
280129198Scognet
281129198ScognetENTRY(suswintr)
282295267Smmel	mov	r0, #-1
283137463Scognet	RET
284248361SandrewEND(suswintr)
285129198Scognet
286129198Scognet/*
287129198Scognet * susword(caddr_t uaddr, short x);
288129198Scognet * Store a short in the user's address space.
289129198Scognet */
290129198Scognet
291129198ScognetENTRY(susword)
292289372Skib	ldr	r3, =(VM_MAXUSER_ADDRESS-1)
293289372Skib	cmp	r0, r3
294289372Skib	mvncs	r0, #0
295289372Skib	RETc(cs)
296289372Skib
297239268Sgonzo	GET_PCB(r2)
298129198Scognet	ldr	r2, [r2]
299129198Scognet
300129198Scognet#ifdef DIAGNOSTIC
301129198Scognet	teq	r2, #0x00000000
302129198Scognet	beq	.Lfusupcbfault
303129198Scognet#endif
304129198Scognet
305129198Scognet	adr	r3, .Lfusufault
306129198Scognet	str	r3, [r2, #PCB_ONFAULT]
307129198Scognet
308129198Scognet#ifdef __ARMEB__
309129198Scognet	mov	ip, r1, lsr #8
310129198Scognet	strbt	ip, [r0], #1
311129198Scognet#else
312129198Scognet	strbt	r1, [r0], #1
313129198Scognet	mov	r1, r1, lsr #8
314129198Scognet#endif
315129198Scognet	strbt	r1, [r0]
316129198Scognet
317129198Scognet	mov	r0, #0x00000000
318129198Scognet	str	r0, [r2, #PCB_ONFAULT]
319137463Scognet	RET
320248361SandrewEND(susword)
321129198Scognet
322129198Scognet/*
323129198Scognet * subyte(caddr_t uaddr, char x);
324129198Scognet * Store a byte in the user's address space.
325129198Scognet */
326129198Scognet
327129198ScognetENTRY(subyte)
328289372Skib	ldr	r3, =VM_MAXUSER_ADDRESS
329289372Skib	cmp	r0, r3
330289372Skib	mvncs	r0, #0
331289372Skib	RETc(cs)
332289372Skib
333239268Sgonzo	GET_PCB(r2)
334129198Scognet	ldr	r2, [r2]
335129198Scognet
336129198Scognet
337129198Scognet#ifdef DIAGNOSTIC
338129198Scognet	teq	r2, #0x00000000
339129198Scognet	beq	.Lfusupcbfault
340129198Scognet#endif
341129198Scognet
342129198Scognet	adr	r3, .Lfusufault
343129198Scognet	str	r3, [r2, #PCB_ONFAULT]
344129198Scognet
345129198Scognet	strbt	r1, [r0]
346129198Scognet	mov	r0, #0x00000000
347129198Scognet	str	r0, [r2, #PCB_ONFAULT]
348137463Scognet	RET
349248361SandrewEND(subyte)
350