xref: /OK3568_Linux_fs/kernel/arch/m68k/fpsp040/skeleton.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun|
2*4882a593Smuzhiyun|	skeleton.sa 3.2 4/26/91
3*4882a593Smuzhiyun|
4*4882a593Smuzhiyun|	This file contains code that is system dependent and will
5*4882a593Smuzhiyun|	need to be modified to install the FPSP.
6*4882a593Smuzhiyun|
7*4882a593Smuzhiyun|	Each entry point for exception 'xxxx' begins with a 'jmp fpsp_xxxx'.
8*4882a593Smuzhiyun|	Put any target system specific handling that must be done immediately
9*4882a593Smuzhiyun|	before the jump instruction.  If there no handling necessary, then
10*4882a593Smuzhiyun|	the 'fpsp_xxxx' handler entry point should be placed in the exception
11*4882a593Smuzhiyun|	table so that the 'jmp' can be eliminated. If the FPSP determines that the
12*4882a593Smuzhiyun|	exception is one that must be reported then there will be a
13*4882a593Smuzhiyun|	return from the package by a 'jmp real_xxxx'.  At that point
14*4882a593Smuzhiyun|	the machine state will be identical to the state before
15*4882a593Smuzhiyun|	the FPSP was entered.  In particular, whatever condition
16*4882a593Smuzhiyun|	that caused the exception will still be pending when the FPSP
17*4882a593Smuzhiyun|	package returns.  Thus, there will be system specific code
18*4882a593Smuzhiyun|	to handle the exception.
19*4882a593Smuzhiyun|
20*4882a593Smuzhiyun|	If the exception was completely handled by the package, then
21*4882a593Smuzhiyun|	the return will be via a 'jmp fpsp_done'.  Unless there is
22*4882a593Smuzhiyun|	OS specific work to be done (such as handling a context switch or
23*4882a593Smuzhiyun|	interrupt) the user program can be resumed via 'rte'.
24*4882a593Smuzhiyun|
25*4882a593Smuzhiyun|	In the following skeleton code, some typical 'real_xxxx' handling
26*4882a593Smuzhiyun|	code is shown.  This code may need to be moved to an appropriate
27*4882a593Smuzhiyun|	place in the target system, or rewritten.
28*4882a593Smuzhiyun|
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun|		Copyright (C) Motorola, Inc. 1990
31*4882a593Smuzhiyun|			All Rights Reserved
32*4882a593Smuzhiyun|
33*4882a593Smuzhiyun|       For details on the license for this file, please see the
34*4882a593Smuzhiyun|       file, README, in this same directory.
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun|
37*4882a593Smuzhiyun|	Modified for Linux-1.3.x by Jes Sorensen (jds@kom.auc.dk)
38*4882a593Smuzhiyun|
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun#include <linux/linkage.h>
41*4882a593Smuzhiyun#include <asm/entry.h>
42*4882a593Smuzhiyun#include <asm/asm-offsets.h>
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun|SKELETON	idnt    2,1 | Motorola 040 Floating Point Software Package
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun	|section 15
47*4882a593Smuzhiyun|
48*4882a593Smuzhiyun|	The following counters are used for standalone testing
49*4882a593Smuzhiyun|
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun	|section 8
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun#include "fpsp.h"
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun	|xref	b1238_fix
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun|
58*4882a593Smuzhiyun|	Divide by Zero exception
59*4882a593Smuzhiyun|
60*4882a593Smuzhiyun|	All dz exceptions are 'real', hence no fpsp_dz entry point.
61*4882a593Smuzhiyun|
62*4882a593Smuzhiyun	.global	dz
63*4882a593Smuzhiyun	.global	real_dz
64*4882a593Smuzhiyundz:
65*4882a593Smuzhiyunreal_dz:
66*4882a593Smuzhiyun	link		%a6,#-LOCAL_SIZE
67*4882a593Smuzhiyun	fsave		-(%sp)
68*4882a593Smuzhiyun	bclrb		#E1,E_BYTE(%a6)
69*4882a593Smuzhiyun	frestore	(%sp)+
70*4882a593Smuzhiyun	unlk		%a6
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun	SAVE_ALL_INT
73*4882a593Smuzhiyun	GET_CURRENT(%d0)
74*4882a593Smuzhiyun	movel	%sp,%sp@-		| stack frame pointer argument
75*4882a593Smuzhiyun	bsrl	trap_c
76*4882a593Smuzhiyun	addql	#4,%sp
77*4882a593Smuzhiyun	bral	ret_from_exception
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun|
80*4882a593Smuzhiyun|	Inexact exception
81*4882a593Smuzhiyun|
82*4882a593Smuzhiyun|	All inexact exceptions are real, but the 'real' handler
83*4882a593Smuzhiyun|	will probably want to clear the pending exception.
84*4882a593Smuzhiyun|	The provided code will clear the E3 exception (if pending),
85*4882a593Smuzhiyun|	otherwise clear the E1 exception.  The frestore is not really
86*4882a593Smuzhiyun|	necessary for E1 exceptions.
87*4882a593Smuzhiyun|
88*4882a593Smuzhiyun| Code following the 'inex' label is to handle bug #1232.  In this
89*4882a593Smuzhiyun| bug, if an E1 snan, ovfl, or unfl occurred, and the process was
90*4882a593Smuzhiyun| swapped out before taking the exception, the exception taken on
91*4882a593Smuzhiyun| return was inex, rather than the correct exception.  The snan, ovfl,
92*4882a593Smuzhiyun| and unfl exception to be taken must not have been enabled.  The
93*4882a593Smuzhiyun| fix is to check for E1, and the existence of one of snan, ovfl,
94*4882a593Smuzhiyun| or unfl bits set in the fpsr.  If any of these are set, branch
95*4882a593Smuzhiyun| to the appropriate  handler for the exception in the fpsr.  Note
96*4882a593Smuzhiyun| that this fix is only for d43b parts, and is skipped if the
97*4882a593Smuzhiyun| version number is not $40.
98*4882a593Smuzhiyun|
99*4882a593Smuzhiyun|
100*4882a593Smuzhiyun	.global	real_inex
101*4882a593Smuzhiyun	.global	inex
102*4882a593Smuzhiyuninex:
103*4882a593Smuzhiyun	link		%a6,#-LOCAL_SIZE
104*4882a593Smuzhiyun	fsave		-(%sp)
105*4882a593Smuzhiyun	cmpib		#VER_40,(%sp)		|test version number
106*4882a593Smuzhiyun	bnes		not_fmt40
107*4882a593Smuzhiyun	fmovel		%fpsr,-(%sp)
108*4882a593Smuzhiyun	btstb		#E1,E_BYTE(%a6)		|test for E1 set
109*4882a593Smuzhiyun	beqs		not_b1232
110*4882a593Smuzhiyun	btstb		#snan_bit,2(%sp) |test for snan
111*4882a593Smuzhiyun	beq		inex_ckofl
112*4882a593Smuzhiyun	addl		#4,%sp
113*4882a593Smuzhiyun	frestore	(%sp)+
114*4882a593Smuzhiyun	unlk		%a6
115*4882a593Smuzhiyun	bra		snan
116*4882a593Smuzhiyuninex_ckofl:
117*4882a593Smuzhiyun	btstb		#ovfl_bit,2(%sp) |test for ovfl
118*4882a593Smuzhiyun	beq		inex_ckufl
119*4882a593Smuzhiyun	addl		#4,%sp
120*4882a593Smuzhiyun	frestore	(%sp)+
121*4882a593Smuzhiyun	unlk		%a6
122*4882a593Smuzhiyun	bra		ovfl
123*4882a593Smuzhiyuninex_ckufl:
124*4882a593Smuzhiyun	btstb		#unfl_bit,2(%sp) |test for unfl
125*4882a593Smuzhiyun	beq		not_b1232
126*4882a593Smuzhiyun	addl		#4,%sp
127*4882a593Smuzhiyun	frestore	(%sp)+
128*4882a593Smuzhiyun	unlk		%a6
129*4882a593Smuzhiyun	bra		unfl
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun|
132*4882a593Smuzhiyun| We do not have the bug 1232 case.  Clean up the stack and call
133*4882a593Smuzhiyun| real_inex.
134*4882a593Smuzhiyun|
135*4882a593Smuzhiyunnot_b1232:
136*4882a593Smuzhiyun	addl		#4,%sp
137*4882a593Smuzhiyun	frestore	(%sp)+
138*4882a593Smuzhiyun	unlk		%a6
139*4882a593Smuzhiyun
140*4882a593Smuzhiyunreal_inex:
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun	link		%a6,#-LOCAL_SIZE
143*4882a593Smuzhiyun	fsave		-(%sp)
144*4882a593Smuzhiyunnot_fmt40:
145*4882a593Smuzhiyun	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
146*4882a593Smuzhiyun	beqs		inex_cke1
147*4882a593Smuzhiyun|
148*4882a593Smuzhiyun| Clear dirty bit on dest resister in the frame before branching
149*4882a593Smuzhiyun| to b1238_fix.
150*4882a593Smuzhiyun|
151*4882a593Smuzhiyun	moveml		%d0/%d1,USER_DA(%a6)
152*4882a593Smuzhiyun	bfextu		CMDREG1B(%a6){#6:#3},%d0		|get dest reg no
153*4882a593Smuzhiyun	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
154*4882a593Smuzhiyun	bsrl		b1238_fix		|test for bug1238 case
155*4882a593Smuzhiyun	moveml		USER_DA(%a6),%d0/%d1
156*4882a593Smuzhiyun	bras		inex_done
157*4882a593Smuzhiyuninex_cke1:
158*4882a593Smuzhiyun	bclrb		#E1,E_BYTE(%a6)
159*4882a593Smuzhiyuninex_done:
160*4882a593Smuzhiyun	frestore	(%sp)+
161*4882a593Smuzhiyun	unlk		%a6
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun	SAVE_ALL_INT
164*4882a593Smuzhiyun	GET_CURRENT(%d0)
165*4882a593Smuzhiyun	movel	%sp,%sp@-		| stack frame pointer argument
166*4882a593Smuzhiyun	bsrl	trap_c
167*4882a593Smuzhiyun	addql	#4,%sp
168*4882a593Smuzhiyun	bral	ret_from_exception
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun|
171*4882a593Smuzhiyun|	Overflow exception
172*4882a593Smuzhiyun|
173*4882a593Smuzhiyun	|xref	fpsp_ovfl
174*4882a593Smuzhiyun	.global	real_ovfl
175*4882a593Smuzhiyun	.global	ovfl
176*4882a593Smuzhiyunovfl:
177*4882a593Smuzhiyun	jmp	fpsp_ovfl
178*4882a593Smuzhiyunreal_ovfl:
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun	link		%a6,#-LOCAL_SIZE
181*4882a593Smuzhiyun	fsave		-(%sp)
182*4882a593Smuzhiyun	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
183*4882a593Smuzhiyun	bnes		ovfl_done
184*4882a593Smuzhiyun	bclrb		#E1,E_BYTE(%a6)
185*4882a593Smuzhiyunovfl_done:
186*4882a593Smuzhiyun	frestore	(%sp)+
187*4882a593Smuzhiyun	unlk		%a6
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun	SAVE_ALL_INT
190*4882a593Smuzhiyun	GET_CURRENT(%d0)
191*4882a593Smuzhiyun	movel	%sp,%sp@-		| stack frame pointer argument
192*4882a593Smuzhiyun	bsrl	trap_c
193*4882a593Smuzhiyun	addql	#4,%sp
194*4882a593Smuzhiyun	bral	ret_from_exception
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun|
197*4882a593Smuzhiyun|	Underflow exception
198*4882a593Smuzhiyun|
199*4882a593Smuzhiyun	|xref	fpsp_unfl
200*4882a593Smuzhiyun	.global	real_unfl
201*4882a593Smuzhiyun	.global	unfl
202*4882a593Smuzhiyununfl:
203*4882a593Smuzhiyun	jmp	fpsp_unfl
204*4882a593Smuzhiyunreal_unfl:
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun	link		%a6,#-LOCAL_SIZE
207*4882a593Smuzhiyun	fsave		-(%sp)
208*4882a593Smuzhiyun	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
209*4882a593Smuzhiyun	bnes		unfl_done
210*4882a593Smuzhiyun	bclrb		#E1,E_BYTE(%a6)
211*4882a593Smuzhiyununfl_done:
212*4882a593Smuzhiyun	frestore	(%sp)+
213*4882a593Smuzhiyun	unlk		%a6
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun	SAVE_ALL_INT
216*4882a593Smuzhiyun	GET_CURRENT(%d0)
217*4882a593Smuzhiyun	movel	%sp,%sp@-		| stack frame pointer argument
218*4882a593Smuzhiyun	bsrl	trap_c
219*4882a593Smuzhiyun	addql	#4,%sp
220*4882a593Smuzhiyun	bral	ret_from_exception
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun|
223*4882a593Smuzhiyun|	Signalling NAN exception
224*4882a593Smuzhiyun|
225*4882a593Smuzhiyun	|xref	fpsp_snan
226*4882a593Smuzhiyun	.global	real_snan
227*4882a593Smuzhiyun	.global	snan
228*4882a593Smuzhiyunsnan:
229*4882a593Smuzhiyun	jmp	fpsp_snan
230*4882a593Smuzhiyunreal_snan:
231*4882a593Smuzhiyun	link		%a6,#-LOCAL_SIZE
232*4882a593Smuzhiyun	fsave		-(%sp)
233*4882a593Smuzhiyun	bclrb		#E1,E_BYTE(%a6)	|snan is always an E1 exception
234*4882a593Smuzhiyun	frestore	(%sp)+
235*4882a593Smuzhiyun	unlk		%a6
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun	SAVE_ALL_INT
238*4882a593Smuzhiyun	GET_CURRENT(%d0)
239*4882a593Smuzhiyun	movel	%sp,%sp@-		| stack frame pointer argument
240*4882a593Smuzhiyun	bsrl	trap_c
241*4882a593Smuzhiyun	addql	#4,%sp
242*4882a593Smuzhiyun	bral	ret_from_exception
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun|
245*4882a593Smuzhiyun|	Operand Error exception
246*4882a593Smuzhiyun|
247*4882a593Smuzhiyun	|xref	fpsp_operr
248*4882a593Smuzhiyun	.global	real_operr
249*4882a593Smuzhiyun	.global	operr
250*4882a593Smuzhiyunoperr:
251*4882a593Smuzhiyun	jmp	fpsp_operr
252*4882a593Smuzhiyunreal_operr:
253*4882a593Smuzhiyun	link		%a6,#-LOCAL_SIZE
254*4882a593Smuzhiyun	fsave		-(%sp)
255*4882a593Smuzhiyun	bclrb		#E1,E_BYTE(%a6)	|operr is always an E1 exception
256*4882a593Smuzhiyun	frestore	(%sp)+
257*4882a593Smuzhiyun	unlk		%a6
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun	SAVE_ALL_INT
260*4882a593Smuzhiyun	GET_CURRENT(%d0)
261*4882a593Smuzhiyun	movel	%sp,%sp@-		| stack frame pointer argument
262*4882a593Smuzhiyun	bsrl	trap_c
263*4882a593Smuzhiyun	addql	#4,%sp
264*4882a593Smuzhiyun	bral	ret_from_exception
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun|
268*4882a593Smuzhiyun|	BSUN exception
269*4882a593Smuzhiyun|
270*4882a593Smuzhiyun|	This sample handler simply clears the nan bit in the FPSR.
271*4882a593Smuzhiyun|
272*4882a593Smuzhiyun	|xref	fpsp_bsun
273*4882a593Smuzhiyun	.global	real_bsun
274*4882a593Smuzhiyun	.global	bsun
275*4882a593Smuzhiyunbsun:
276*4882a593Smuzhiyun	jmp	fpsp_bsun
277*4882a593Smuzhiyunreal_bsun:
278*4882a593Smuzhiyun	link		%a6,#-LOCAL_SIZE
279*4882a593Smuzhiyun	fsave		-(%sp)
280*4882a593Smuzhiyun	bclrb		#E1,E_BYTE(%a6)	|bsun is always an E1 exception
281*4882a593Smuzhiyun	fmovel		%FPSR,-(%sp)
282*4882a593Smuzhiyun	bclrb		#nan_bit,(%sp)
283*4882a593Smuzhiyun	fmovel		(%sp)+,%FPSR
284*4882a593Smuzhiyun	frestore	(%sp)+
285*4882a593Smuzhiyun	unlk		%a6
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun	SAVE_ALL_INT
288*4882a593Smuzhiyun	GET_CURRENT(%d0)
289*4882a593Smuzhiyun	movel	%sp,%sp@-		| stack frame pointer argument
290*4882a593Smuzhiyun	bsrl	trap_c
291*4882a593Smuzhiyun	addql	#4,%sp
292*4882a593Smuzhiyun	bral	ret_from_exception
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun|
295*4882a593Smuzhiyun|	F-line exception
296*4882a593Smuzhiyun|
297*4882a593Smuzhiyun|	A 'real' F-line exception is one that the FPSP isn't supposed to
298*4882a593Smuzhiyun|	handle. E.g. an instruction with a co-processor ID that is not 1.
299*4882a593Smuzhiyun|
300*4882a593Smuzhiyun|
301*4882a593Smuzhiyun	|xref	fpsp_fline
302*4882a593Smuzhiyun	.global	real_fline
303*4882a593Smuzhiyun	.global	fline
304*4882a593Smuzhiyunfline:
305*4882a593Smuzhiyun	jmp	fpsp_fline
306*4882a593Smuzhiyunreal_fline:
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun	SAVE_ALL_INT
309*4882a593Smuzhiyun	GET_CURRENT(%d0)
310*4882a593Smuzhiyun	movel	%sp,%sp@-		| stack frame pointer argument
311*4882a593Smuzhiyun	bsrl	trap_c
312*4882a593Smuzhiyun	addql	#4,%sp
313*4882a593Smuzhiyun	bral	ret_from_exception
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun|
316*4882a593Smuzhiyun|	Unsupported data type exception
317*4882a593Smuzhiyun|
318*4882a593Smuzhiyun	|xref	fpsp_unsupp
319*4882a593Smuzhiyun	.global	real_unsupp
320*4882a593Smuzhiyun	.global	unsupp
321*4882a593Smuzhiyununsupp:
322*4882a593Smuzhiyun	jmp	fpsp_unsupp
323*4882a593Smuzhiyunreal_unsupp:
324*4882a593Smuzhiyun	link		%a6,#-LOCAL_SIZE
325*4882a593Smuzhiyun	fsave		-(%sp)
326*4882a593Smuzhiyun	bclrb		#E1,E_BYTE(%a6)	|unsupp is always an E1 exception
327*4882a593Smuzhiyun	frestore	(%sp)+
328*4882a593Smuzhiyun	unlk		%a6
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun	SAVE_ALL_INT
331*4882a593Smuzhiyun	GET_CURRENT(%d0)
332*4882a593Smuzhiyun	movel	%sp,%sp@-		| stack frame pointer argument
333*4882a593Smuzhiyun	bsrl	trap_c
334*4882a593Smuzhiyun	addql	#4,%sp
335*4882a593Smuzhiyun	bral	ret_from_exception
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun|
338*4882a593Smuzhiyun|	Trace exception
339*4882a593Smuzhiyun|
340*4882a593Smuzhiyun	.global	real_trace
341*4882a593Smuzhiyunreal_trace:
342*4882a593Smuzhiyun	|
343*4882a593Smuzhiyun	bral	trap
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun|
346*4882a593Smuzhiyun|	fpsp_fmt_error --- exit point for frame format error
347*4882a593Smuzhiyun|
348*4882a593Smuzhiyun|	The fpu stack frame does not match the frames existing
349*4882a593Smuzhiyun|	or planned at the time of this writing.  The fpsp is
350*4882a593Smuzhiyun|	unable to handle frame sizes not in the following
351*4882a593Smuzhiyun|	version:size pairs:
352*4882a593Smuzhiyun|
353*4882a593Smuzhiyun|	{4060, 4160} - busy frame
354*4882a593Smuzhiyun|	{4028, 4130} - unimp frame
355*4882a593Smuzhiyun|	{4000, 4100} - idle frame
356*4882a593Smuzhiyun|
357*4882a593Smuzhiyun|	This entry point simply holds an f-line illegal value.
358*4882a593Smuzhiyun|	Replace this with a call to your kernel panic code or
359*4882a593Smuzhiyun|	code to handle future revisions of the fpu.
360*4882a593Smuzhiyun|
361*4882a593Smuzhiyun	.global	fpsp_fmt_error
362*4882a593Smuzhiyunfpsp_fmt_error:
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun	.long	0xf27f0000	|f-line illegal
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun|
367*4882a593Smuzhiyun|	fpsp_done --- FPSP exit point
368*4882a593Smuzhiyun|
369*4882a593Smuzhiyun|	The exception has been handled by the package and we are ready
370*4882a593Smuzhiyun|	to return to user mode, but there may be OS specific code
371*4882a593Smuzhiyun|	to execute before we do.  If there is, do it now.
372*4882a593Smuzhiyun|
373*4882a593Smuzhiyun|
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun	.global	fpsp_done
376*4882a593Smuzhiyunfpsp_done:
377*4882a593Smuzhiyun	btst	#0x5,%sp@		| supervisor bit set in saved SR?
378*4882a593Smuzhiyun	beq	.Lnotkern
379*4882a593Smuzhiyun	rte
380*4882a593Smuzhiyun.Lnotkern:
381*4882a593Smuzhiyun	SAVE_ALL_INT
382*4882a593Smuzhiyun	GET_CURRENT(%d0)
383*4882a593Smuzhiyun	| deliver signals, reschedule etc..
384*4882a593Smuzhiyun	jra	ret_from_exception
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun|
387*4882a593Smuzhiyun|	mem_write --- write to user or supervisor address space
388*4882a593Smuzhiyun|
389*4882a593Smuzhiyun| Writes to memory while in supervisor mode.  copyout accomplishes
390*4882a593Smuzhiyun| this via a 'moves' instruction.  copyout is a UNIX SVR3 (and later) function.
391*4882a593Smuzhiyun| If you don't have copyout, use the local copy of the function below.
392*4882a593Smuzhiyun|
393*4882a593Smuzhiyun|	a0 - supervisor source address
394*4882a593Smuzhiyun|	a1 - user destination address
395*4882a593Smuzhiyun|	d0 - number of bytes to write (maximum count is 12)
396*4882a593Smuzhiyun|
397*4882a593Smuzhiyun| The supervisor source address is guaranteed to point into the supervisor
398*4882a593Smuzhiyun| stack.  The result is that a UNIX
399*4882a593Smuzhiyun| process is allowed to sleep as a consequence of a page fault during
400*4882a593Smuzhiyun| copyout.  The probability of a page fault is exceedingly small because
401*4882a593Smuzhiyun| the 68040 always reads the destination address and thus the page
402*4882a593Smuzhiyun| faults should have already been handled.
403*4882a593Smuzhiyun|
404*4882a593Smuzhiyun| If the EXC_SR shows that the exception was from supervisor space,
405*4882a593Smuzhiyun| then just do a dumb (and slow) memory move.  In a UNIX environment
406*4882a593Smuzhiyun| there shouldn't be any supervisor mode floating point exceptions.
407*4882a593Smuzhiyun|
408*4882a593Smuzhiyun	.global	mem_write
409*4882a593Smuzhiyunmem_write:
410*4882a593Smuzhiyun	btstb	#5,EXC_SR(%a6)	|check for supervisor state
411*4882a593Smuzhiyun	beqs	user_write
412*4882a593Smuzhiyunsuper_write:
413*4882a593Smuzhiyun	moveb	(%a0)+,(%a1)+
414*4882a593Smuzhiyun	subql	#1,%d0
415*4882a593Smuzhiyun	bnes	super_write
416*4882a593Smuzhiyun	rts
417*4882a593Smuzhiyunuser_write:
418*4882a593Smuzhiyun	movel	%d1,-(%sp)	|preserve d1 just in case
419*4882a593Smuzhiyun	movel	%d0,-(%sp)
420*4882a593Smuzhiyun	movel	%a1,-(%sp)
421*4882a593Smuzhiyun	movel	%a0,-(%sp)
422*4882a593Smuzhiyun	jsr		copyout
423*4882a593Smuzhiyun	addw	#12,%sp
424*4882a593Smuzhiyun	movel	(%sp)+,%d1
425*4882a593Smuzhiyun	rts
426*4882a593Smuzhiyun|
427*4882a593Smuzhiyun|	mem_read --- read from user or supervisor address space
428*4882a593Smuzhiyun|
429*4882a593Smuzhiyun| Reads from memory while in supervisor mode.  copyin accomplishes
430*4882a593Smuzhiyun| this via a 'moves' instruction.  copyin is a UNIX SVR3 (and later) function.
431*4882a593Smuzhiyun| If you don't have copyin, use the local copy of the function below.
432*4882a593Smuzhiyun|
433*4882a593Smuzhiyun| The FPSP calls mem_read to read the original F-line instruction in order
434*4882a593Smuzhiyun| to extract the data register number when the 'Dn' addressing mode is
435*4882a593Smuzhiyun| used.
436*4882a593Smuzhiyun|
437*4882a593Smuzhiyun|Input:
438*4882a593Smuzhiyun|	a0 - user source address
439*4882a593Smuzhiyun|	a1 - supervisor destination address
440*4882a593Smuzhiyun|	d0 - number of bytes to read (maximum count is 12)
441*4882a593Smuzhiyun|
442*4882a593Smuzhiyun| Like mem_write, mem_read always reads with a supervisor
443*4882a593Smuzhiyun| destination address on the supervisor stack.  Also like mem_write,
444*4882a593Smuzhiyun| the EXC_SR is checked and a simple memory copy is done if reading
445*4882a593Smuzhiyun| from supervisor space is indicated.
446*4882a593Smuzhiyun|
447*4882a593Smuzhiyun	.global	mem_read
448*4882a593Smuzhiyunmem_read:
449*4882a593Smuzhiyun	btstb	#5,EXC_SR(%a6)	|check for supervisor state
450*4882a593Smuzhiyun	beqs	user_read
451*4882a593Smuzhiyunsuper_read:
452*4882a593Smuzhiyun	moveb	(%a0)+,(%a1)+
453*4882a593Smuzhiyun	subql	#1,%d0
454*4882a593Smuzhiyun	bnes	super_read
455*4882a593Smuzhiyun	rts
456*4882a593Smuzhiyunuser_read:
457*4882a593Smuzhiyun	movel	%d1,-(%sp)	|preserve d1 just in case
458*4882a593Smuzhiyun	movel	%d0,-(%sp)
459*4882a593Smuzhiyun	movel	%a1,-(%sp)
460*4882a593Smuzhiyun	movel	%a0,-(%sp)
461*4882a593Smuzhiyun	jsr	copyin
462*4882a593Smuzhiyun	addw	#12,%sp
463*4882a593Smuzhiyun	movel	(%sp)+,%d1
464*4882a593Smuzhiyun	rts
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun|
467*4882a593Smuzhiyun| Use these routines if your kernel doesn't have copyout/copyin equivalents.
468*4882a593Smuzhiyun| Assumes that D0/D1/A0/A1 are scratch registers. copyout overwrites DFC,
469*4882a593Smuzhiyun| and copyin overwrites SFC.
470*4882a593Smuzhiyun|
471*4882a593Smuzhiyuncopyout:
472*4882a593Smuzhiyun	movel	4(%sp),%a0	| source
473*4882a593Smuzhiyun	movel	8(%sp),%a1	| destination
474*4882a593Smuzhiyun	movel	12(%sp),%d0	| count
475*4882a593Smuzhiyun	subl	#1,%d0		| dec count by 1 for dbra
476*4882a593Smuzhiyun	movel	#1,%d1
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun|	DFC is already set
479*4882a593Smuzhiyun|	movec	%d1,%DFC		| set dfc for user data space
480*4882a593Smuzhiyunmoreout:
481*4882a593Smuzhiyun	moveb	(%a0)+,%d1	| fetch supervisor byte
482*4882a593Smuzhiyunout_ea:
483*4882a593Smuzhiyun	movesb	%d1,(%a1)+	| write user byte
484*4882a593Smuzhiyun	dbf	%d0,moreout
485*4882a593Smuzhiyun	rts
486*4882a593Smuzhiyun
487*4882a593Smuzhiyuncopyin:
488*4882a593Smuzhiyun	movel	4(%sp),%a0	| source
489*4882a593Smuzhiyun	movel	8(%sp),%a1	| destination
490*4882a593Smuzhiyun	movel	12(%sp),%d0	| count
491*4882a593Smuzhiyun	subl	#1,%d0		| dec count by 1 for dbra
492*4882a593Smuzhiyun	movel	#1,%d1
493*4882a593Smuzhiyun|	SFC is already set
494*4882a593Smuzhiyun|	movec	%d1,%SFC		| set sfc for user space
495*4882a593Smuzhiyunmorein:
496*4882a593Smuzhiyunin_ea:
497*4882a593Smuzhiyun	movesb	(%a0)+,%d1	| fetch user byte
498*4882a593Smuzhiyun	moveb	%d1,(%a1)+	| write supervisor byte
499*4882a593Smuzhiyun	dbf	%d0,morein
500*4882a593Smuzhiyun	rts
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun	.section .fixup,#alloc,#execinstr
503*4882a593Smuzhiyun	.even
504*4882a593Smuzhiyun1:
505*4882a593Smuzhiyun	jbra	fpsp040_die
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun	.section __ex_table,#alloc
508*4882a593Smuzhiyun	.align	4
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun	.long	in_ea,1b
511*4882a593Smuzhiyun	.long	out_ea,1b
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun	|end
514