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