[BACK]Return to eh_common.S CVS log [TXT][DIR] Up to [local] / sys / arch / m88k / m88k

Annotation of sys/arch/m88k/m88k/eh_common.S, Revision 1.1

1.1     ! nbrk        1: /*   $OpenBSD: eh_common.S,v 1.24 2007/05/18 16:35:54 miod Exp $       */
        !             2: /*
        !             3:  * Mach Operating System
        !             4:  * Copyright (c) 1993-1991 Carnegie Mellon University
        !             5:  * Copyright (c) 1991 OMRON Corporation
        !             6:  * Copyright (c) 1996 Nivas Madhur
        !             7:  * Copyright (c) 1998 Steve Murphree, Jr.
        !             8:  * All Rights Reserved.
        !             9:  *
        !            10:  * Permission to use, copy, modify and distribute this software and its
        !            11:  * documentation is hereby granted, provided that both the copyright
        !            12:  * notice and this permission notice appear in all copies of the
        !            13:  * software, derivative works or modified versions, and any portions
        !            14:  * thereof, and that both notices appear in supporting documentation.
        !            15:  *
        !            16:  * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            17:  * CONDITION.  CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
        !            18:  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            19:  *
        !            20:  * Carnegie Mellon requests users of this software to return to
        !            21:  *
        !            22:  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
        !            23:  *  School of Computer Science
        !            24:  *  Carnegie Mellon University
        !            25:  *  Pittsburgh PA 15213-3890
        !            26:  *
        !            27:  * any improvements or extensions that they make and grant Carnegie the
        !            28:  * rights to redistribute these changes.
        !            29:  */
        !            30:
        !            31: /*
        !            32:  * NOTICE: This is not a standalone file.  To use it, define the PFSR_SAVE
        !            33:  * macro and #include this file in your port's eh.S:
        !            34:  * #include <m88k/m88k/eh_common.S>
        !            35:  */
        !            36:
        !            37: /*
        !            38:  * In the following discussion, references are made to:
        !            39:  *    MC88100 - RISC MICROPROCESSOR USER'S MANUAL
        !            40:  * (second edition). Reference in []s refer to section numbers.
        !            41:  *
        !            42:  * This discussion assumes that you are at least vaguely familiar with 88100
        !            43:  * exception handling (chapter 6), the MACH kernel, and that you have a brain
        !            44:  * (and use it while reading this).
        !            45:  *
        !            46:  * I also assume (and hope) that you're not offended by frequent misspellings.
        !            47:  *
        !            48:  * Jeffrey Friedl
        !            49:  * jfriedl@rna.ncl.omron.co.jp
        !            50:  * December, 1989
        !            51:  *  -------------------------------------------------------------------
        !            52:  *
        !            53:  * EXCEPTIONS, INTERRUPTS, and TRAPS
        !            54:  * ---------------------------------
        !            55:  * This is the machine exception handler.
        !            56:  * In the MC88100, various "conditions" cause an exception, where
        !            57:  * processing momentarily jumps here to "service" the exception,
        !            58:  * and then continues where it left off.
        !            59:  *
        !            60:  * There are a number of different types of exceptions.
        !            61:  * For example, exception #6 is the privilege violation exception which
        !            62:  * is raised when the user tries to execute a supervisor-only instruction.
        !            63:  *
        !            64:  * Exception #1 is the interrupt exception, and is raised when an
        !            65:  * outside device raises the INT line on the CPU.  This happens,
        !            66:  * for example, when the clock signals that it is time for a context
        !            67:  * switch, or perhaps the disk drive signaling that some operation
        !            68:  * is complete.
        !            69:  *
        !            70:  * Traps are also exceptions.  Traps are ways for user programs to request
        !            71:  * kernel operations.  For example, "tcnd eq0, r0, 450" will raise
        !            72:  * exception 450, the system call exception.
        !            73:  *
        !            74:  *
        !            75:  * SERVICING AN EXCEPTION
        !            76:  * -----------------------
        !            77:  * When an exception occurs, each control register is saved in its
        !            78:  * respective shadow register and execution continues from the
        !            79:  * appropriate exception handler.  The exception handler must
        !            80:  *      - save the context from the time of the exception
        !            81:  *      - service the exception
        !            82:  *      - restore the context (registers, etc)
        !            83:  *      - pick up from where the exception occurred.
        !            84:  *
        !            85:  * The context is saved on a stack. Actually, in the user_state area
        !            86:  * in the PCB if the exception happens in user mode.
        !            87:  *
        !            88:  * Servicing the exception is usually straightforward and in fact not dealt
        !            89:  * with very much here.  Usually a C routine is called to handle it.
        !            90:  * For example, when a privilege exception is raised, the routine that sends
        !            91:  * an "illegal instruction" signal to the offending process is called.
        !            92:  *
        !            93:  * When the exception has been serviced, the context is restored from the
        !            94:  * stack and execution resumes from where it left off.
        !            95:  *
        !            96:  * In more detail:
        !            97:  *
        !            98:  * Saving the exception-time context.
        !            99:  * ---------------------------------
        !           100:  *     In saving the exception-time context, we copy the shadow and general
        !           101:  * purpose registers to memory.  Since one exception may occur while
        !           102:  * servicing another, the memory used to save the exception-time context may
        !           103:  * not be static (i.e. the same every time).  Thus, memory on a stack is set
        !           104:  * aside for the exception frame (area where the exception-time context is
        !           105:  * saved). The same stack is also used when C routines are called (to
        !           106:  * service the exception).
        !           107:  *
        !           108:  *    Each process has a stack in kernel space (called the "kernel stack",
        !           109:  * short for "process's kernel stack) as well as the user space stack.  When
        !           110:  * entering the kernel from user space, the kernel stack is unused.  On this
        !           111:  * stack we save the exception state and (most likely call a C routine to)
        !           112:  * service the exception.
        !           113:  *
        !           114:  * Before servicing an exception, several issues must be addressed.
        !           115:  *
        !           116:  * 1) When an interrupt is recognized by the hardware, the data pipeline is
        !           117:  *    allowed to clear.  However, if one of these data accesses faults (bad
        !           118:  *    reference, or a reference to a page which needs to be swapped in), that
        !           119:  *    reference, as well as any others in the pipeline at the time (at most
        !           120:  *    three total) are left there, to be taken care of by the exception
        !           121:  *    handler [6.4.1].  This involves swapping in the proper page and
        !           122:  *    manually doing the appropriate load or store.
        !           123:  *
        !           124:  *    The other (at most, two other) data accesses that might have been in
        !           125:  *    the pipeline must also be manually completed (even though they may not
        !           126:  *    be at fault [yes, that's a bad pun, thank you]).
        !           127:  *
        !           128:  * 2) If any of the (at most three) uncompleted data access in the pipeline
        !           129:  *    are loads (from memory to a register), then the bit for the destination
        !           130:  *    register is set in the SSBR.  Since the hardware will never complete
        !           131:  *    that load (since we do it manually), the hardware will never clear that
        !           132:  *    SSBR bit.  Thus, we must clear it manually.  If this isn't done, the
        !           133:  *    system will hang waiting for a bit to clear that will never.
        !           134:  *
        !           135:  * 3) If the exception is the privilege violation exception, the bounds
        !           136:  *    check exception, or the misaligned access exception, the
        !           137:  *    destination register bit in the SSBR may need to be cleared.
        !           138:  *
        !           139:  * 4) If the exception is one of the floating exceptions, then the
        !           140:  *    destination register for that floating process won't be written,
        !           141:  *    and the SSBR must be cleared explicitly.
        !           142:  *
        !           143:  * 5) The FPU must be enabled (as it is disabled by the exception processing
        !           144:  *    hardware) and allowed to complete actions in progress. This is
        !           145:  *    so that it may be used in the servicing of any instruction.
        !           146:  *    When the FPU is being restarted, operations attempting to complete
        !           147:  *    may themselves fault (raising another exception).
        !           148:  *
        !           149:  * More on Restarting the FPU
        !           150:  * --------------------------
        !           151:  *   The manual [section 6.4.3.4] gives only minor mention to this
        !           152:  * rather complex task.  Before the FPU is restarted all SSBR bits are
        !           153:  * cleared for actions that the exception handler completes (as mentioned
        !           154:  * above) so that the SSBR is clear unless there are FPU operations that
        !           155:  * have not actually been completed (and hence not written to the registers).
        !           156:  * Also, all control registers (at least all those that we care about) are
        !           157:  * saved to the stack exception frame before the FPU is restarted (this
        !           158:  * is important... the reason comes later).
        !           159:  *
        !           160:  * The FPU is restarted by doing an rte to a trap-not-taken (the rte
        !           161:  * actually enables the fpu because we ensure that the EPSR has the
        !           162:  * FPU-enable bit on; the trap-not-taken ensures anything in the FPU
        !           163:  * completes by waiting until scoreboard register is clear).
        !           164:  *
        !           165:  * At the time the FPU is restarted (the rte to the trap-not-taken) the FPU
        !           166:  * can write to ANY of the general registers.  Thus, we must make sure that
        !           167:  * all general registers (r1..r31) are in their pre-exception state so that
        !           168:  * when saved to the exception frame after the FPU is enabled, they properly
        !           169:  * reflect any changes made by the FPU in being restarted.
        !           170:  *
        !           171:  * Because we can't save the pointer to the exception frame in a general
        !           172:  * register during the FPU restart (it could get overwritten by the FPU!),
        !           173:  * we save it in a control register, SR3, during the restart.
        !           174:  *
        !           175:  * HOWEVER .....
        !           176:  *
        !           177:  * Because other uncompleted actions in the FPU may fault when the FPU is
        !           178:  * restarted, a new exception may be raised during the restart. This may
        !           179:  * happen recursively a number of times. Thus, during a restart, ANY register
        !           180:  * whatsoever may be modified, including control registers.  Because of this
        !           181:  * we must make sure that the exception handler preserves SR3 throughout
        !           182:  * servicing an exception so that, if the exception had been raised during
        !           183:  * an FPU restart, it is returned unmolested when control returns to the FPU
        !           184:  * restart.
        !           185:  *
        !           186:  * Thus: if an exception is from kernel space, we MUST preserve SR3.
        !           187:  * (if it from user space, no FPU-enable can be in progress and SR3 is
        !           188:  *  unimportant).
        !           189:  *
        !           190:  * Now is a good time to recap SR1..SR3 usage:
        !           191:  *   SR1 - CPU flags (exception handler flags)
        !           192:  *   SR2 - generally free
        !           193:  *   SR3 - free only if the exception is from user mode
        !           194:  *
        !           195:  * Once the FPU has been restarted, the general registers are saved to the
        !           196:  * exception frame.  If the exception is not the interrupt exception,
        !           197:  * interrupts are enabled and any faulted data accesses (see above) are
        !           198:  * serviced.  In either case, the exception is then serviced (usually by
        !           199:  * calling a C routine).  After servicing, any faulted data accesses are
        !           200:  * serviced (if it had been the interrupt exception).  The context is then
        !           201:  * restored and control returns to where the exception occurred.
        !           202:  *
        !           203:  */
        !           204:
        !           205: #include "assym.h"
        !           206:
        !           207: #include <machine/param.h>
        !           208: #include <machine/asm.h>
        !           209: #include <machine/trap.h>
        !           210:
        !           211: /*
        !           212:  * SR1 - CPU FLAGS REGISTER
        !           213:  *
        !           214:  * SR1 contains flags about the current CPU status.
        !           215:  *
        !           216:  * The bit FLAG_IGNORE_DATA_EXCEPTION indicates that any data exceptions
        !           217:  *     should be ignored (well, at least treated in a special way).
        !           218:  * The bit FLAG_ENABLING_FPU indicates that the exception handler is
        !           219:  *     in the process of enabling the FPU (so that an exception can
        !           220:  *     be serviced).  This is needed because enabling the FPU can
        !           221:  *     cause other exceptions to happen, and the whole system is
        !           222:  *     in a rather precarious state and so special cautions must
        !           223:  *     be taken.
        !           224:  */
        !           225: #define FLAG_IGNORE_DATA_EXCEPTION     0
        !           226: #define FLAG_ENABLING_FPU              1
        !           227: #define FLAG_FROM_KERNEL               2
        !           228:
        !           229: /* REGister OFFset into the E.F. (exception frame) */
        !           230: #define REG_OFF(reg_num)  ((reg_num) * 4) /* (num * sizeof(register_t))  */
        !           231: #define GENREG_OFF(num)        (REG_OFF(EF_R0 + (num))) /* GENeral REGister OFFset */
        !           232:
        !           233: /* Invoke a C function with 2 arguments */
        !           234: #define        CALL(NAME, ARG1, ARG2) \
        !           235:        or      r2, r0, ARG1; \
        !           236:        bsr.n   _C_LABEL(NAME); \
        !           237:         or     r3, r0, ARG2
        !           238:
        !           239: /* Invoke a function and return elsewhere */
        !           240: /* CAREFUL: needs to have `RET' after the XCALL in memory */
        !           241: #define        XCALL(NAME, RET) \
        !           242:        bsr.n   NAME; \
        !           243:         addu   r1, r1, RET - . - 4
        !           244:
        !           245: /*
        !           246:  * Some registers used during the setting up of the new exception frame.
        !           247:  * Don't choose r1, r30, or r31 for any of them.
        !           248:  *
        !           249:  * Also, if any are 'r2' or 'r3', be careful using with CALL above!
        !           250:  */
        !           251: #define        FLAGS           r2
        !           252: #define        TMP             r3
        !           253: #define        TMP2            r10
        !           254: #define        TMP3            r11
        !           255: #define        SAVE_TMP2       st      r10, r31, GENREG_OFF(10)
        !           256: #define        SAVE_TMP3       st      r11, r31, GENREG_OFF(11)
        !           257: #define        RESTORE_TMP2    ld      r10, r31, GENREG_OFF(10)
        !           258: #define        RESTORE_TMP3    ld      r11, r31, GENREG_OFF(11)
        !           259:
        !           260: /*
        !           261:  * EF_SR3
        !           262:  *   A place to save the exception-time SR3 from just after the
        !           263:  *   time when an exception is raised until just after the FPU
        !           264:  *   has been restarted.  This does not necessarly conflict with
        !           265:  *   the general registers (though it can if you're not careful)
        !           266:  *   and so we can use a spot later used to save a general register.
        !           267:  *
        !           268:  * EF_FLAGS
        !           269:  *   This is just the old EF_MODE. "EF_MODE" isn't a very good name.
        !           270:  */
        !           271: #define        EF_SR3          (EF_R0 + 5)
        !           272: #define        EF_FLAGS        EF_MODE
        !           273:
        !           274:        text
        !           275:        align 8
        !           276:
        !           277: #ifdef M88110
        !           278: #define SAVE_CTX \
        !           279:        stcr    r31, SRX                        ; \
        !           280:        or.u    r31, r0,  hi16(_ASM_LABEL(save_frame))  ; \
        !           281:        or      r31, r31, lo16(_ASM_LABEL(save_frame))  ; \
        !           282:        /* save old R31 and other R registers */; \
        !           283:        st.d    r0 , r31, GENREG_OFF(0)         ; \
        !           284:        st.d    r2 , r31, GENREG_OFF(2)         ; \
        !           285:        st.d    r4 , r31, GENREG_OFF(4)         ; \
        !           286:        st.d    r6 , r31, GENREG_OFF(6)         ; \
        !           287:        st.d    r8 , r31, GENREG_OFF(8)         ; \
        !           288:        st.d    r10, r31, GENREG_OFF(10)        ; \
        !           289:        st.d    r12, r31, GENREG_OFF(12)        ; \
        !           290:        st.d    r14, r31, GENREG_OFF(14)        ; \
        !           291:        st.d    r16, r31, GENREG_OFF(16)        ; \
        !           292:        st.d    r18, r31, GENREG_OFF(18)        ; \
        !           293:        st.d    r20, r31, GENREG_OFF(20)        ; \
        !           294:        st.d    r22, r31, GENREG_OFF(22)        ; \
        !           295:        st.d    r24, r31, GENREG_OFF(24)        ; \
        !           296:        st.d    r26, r31, GENREG_OFF(26)        ; \
        !           297:        st.d    r28, r31, GENREG_OFF(28)        ; \
        !           298:        st      r30, r31, GENREG_OFF(30)        ; \
        !           299:        ldcr    r1,  SRX                        ; \
        !           300:        st      r1,  r31, GENREG_OFF(31)        ; \
        !           301:        ldcr    r1,  EPSR                       ; \
        !           302:        ldcr    r2,  EXIP                       ; \
        !           303:        ldcr    r3,  ENIP                       ; \
        !           304:        st      r1,  r31, REG_OFF(EF_EPSR)      ; \
        !           305:        st      r2,  r31, REG_OFF(EF_EXIP)      ; \
        !           306:        st      r3,  r31, REG_OFF(EF_ENIP)      ; \
        !           307:        ldcr    r1,  DSR                        ; \
        !           308:        ldcr    r2,  DLAR                       ; \
        !           309:        ldcr    r3,  DPAR                       ; \
        !           310:        st      r1,  r31, REG_OFF(EF_DSR)       ; \
        !           311:        st      r2,  r31, REG_OFF(EF_DLAR)      ; \
        !           312:        st      r3,  r31, REG_OFF(EF_DPAR)      ; \
        !           313:        ldcr    r1,  ISR                        ; \
        !           314:        ldcr    r2,  ILAR                       ; \
        !           315:        ldcr    r3,  IPAR                       ; \
        !           316:        st      r1,  r31, REG_OFF(EF_ISR)       ; \
        !           317:        st      r2,  r31, REG_OFF(EF_ILAR)      ; \
        !           318:        st      r3,  r31, REG_OFF(EF_IPAR)      ; \
        !           319:        ldcr    r1, DSAP                        ; \
        !           320:        ldcr    r2, DUAP                        ; \
        !           321:        st      r1,  r31, REG_OFF(EF_DSAP)      ; \
        !           322:        st      r2,  r31, REG_OFF(EF_DUAP)      ; \
        !           323:        ldcr    r1, ISAP                        ; \
        !           324:        ldcr    r2, IUAP                        ; \
        !           325:        st      r1,  r31, REG_OFF(EF_ISAP)      ; \
        !           326:        st      r2,  r31, REG_OFF(EF_IUAP)      ; \
        !           327:        /* Restore r1, r2, r3, and r31 */       ; \
        !           328:        ld      r1 , r31, GENREG_OFF(1)         ; \
        !           329:        ld      r2 , r31, GENREG_OFF(2)         ; \
        !           330:        ld      r3 , r31, GENREG_OFF(3)         ; \
        !           331:        ld      r31, r31, GENREG_OFF(31)        ;
        !           332: #endif
        !           333:
        !           334: /*
        !           335:  *
        !           336:  * #define PREP881x0(NAME, NUM, SSBR_STUFF, FLAG_CHECK)
        !           337:  *
        !           338:  * This is the "exception processing preparation" common to all exception
        !           339:  * processing.  It is used in the following manner:
        !           340:  *
        !           341:  *     ASGLOBAL(foo_handler)
        !           342:  *             PREP881x0("foo", 11, SSBR_Stuff, Precheck_Stuff)
        !           343:  *             or      r2, r0, T_FOO_FAULT
        !           344:  *             or      r3, r0, r30
        !           345:  *             XCALL(trapXXX, check_ast)
        !           346:  *
        !           347:  * This defines the exception handler for the "foo" exception.
        !           348:  * The arguments are:
        !           349:  * NAME
        !           350:  *     String for debugging (more info later)
        !           351:  * NUM
        !           352:  *     The exception number [see the manual, Table 6-1]
        !           353:  * SSBR_STUFF
        !           354:  *     If the exception might leave some bits in the SSBR set,
        !           355:  *     this should indicate how they are cleared.
        !           356:  * FLAG_PRECHECK
        !           357:  *     This is for the data access exception only. See it for
        !           358:  *     more info.
        !           359:  *
        !           360:  * What's in between PREP881x0() and check_ast (usually a XCALL)
        !           361:  * is the actual servicing of the interrupt.  During this time, any
        !           362:  * register may be used freely as they've all been saved in the
        !           363:  * exception frame (which is pointed to by r30).
        !           364:  */
        !           365:
        !           366: #ifdef M88100
        !           367: #define PREP88100(NAME, NUM, SSBR_STUFF, FLAG_PRECHECK) \
        !           368:        xcr     FLAGS, FLAGS, SR1                       ; \
        !           369:        FLAG_PRECHECK                                     \
        !           370:        /* the bsr later clobbers r1, so save now */      \
        !           371:        stcr    r1, SR2 /* r1 now free */               ; \
        !           372:        /* set or clear the FLAG_FROM_KERNEL bit */       \
        !           373:        ldcr    r1, EPSR                                ; \
        !           374:        bb0.n   PSR_SUPERVISOR_MODE_BIT, r1, 1f         ; \
        !           375:         clr    FLAGS, FLAGS, 1<FLAG_FROM_KERNEL>       ; \
        !           376:        set     FLAGS, FLAGS, 1<FLAG_FROM_KERNEL>       ; \
        !           377:        /* get a stack (exception frame) */               \
        !           378: 1:     bsr     _ASM_LABEL(m88100_setup_phase_one)      ; \
        !           379:        /* TMP2 now free -- use to set EF_VECTOR */       \
        !           380:        or      TMP2, r0, NUM                           ; \
        !           381:        st      TMP2, r31, REG_OFF(EF_VECTOR)           ; \
        !           382:        /* Clear any bits in the SSBR (held in TMP) */    \
        !           383:        /* SSBR_STUFF may be empty, though.         */    \
        !           384:        SSBR_STUFF                                        \
        !           385:        /* call setup_phase_two to restart the FPU  */    \
        !           386:        /* and to save all general registers.       */    \
        !           387:        bsr     _ASM_LABEL(m88100_setup_phase_two)
        !           388: #endif
        !           389:
        !           390: #ifdef M88110
        !           391: #define PREP88110(NAME, NUM, FLAG_PRECHECK) \
        !           392:        SAVE_CTX                                          \
        !           393:        xcr     FLAGS, FLAGS, SR1                       ; \
        !           394:        FLAG_PRECHECK                                     \
        !           395:        /* the bsr later clobbers r1, so save now */    ; \
        !           396:        stcr    r1, SR2 /* r1 now free */               ; \
        !           397:        /* set or clear the FLAG_FROM_KERNEL bit */     ; \
        !           398:        ldcr    r1, EPSR                                ; \
        !           399:        bb0.n   PSR_SUPERVISOR_MODE_BIT, r1, 1f         ; \
        !           400:         clr    FLAGS, FLAGS, 1<FLAG_FROM_KERNEL>       ; \
        !           401:        set     FLAGS, FLAGS, 1<FLAG_FROM_KERNEL>       ; \
        !           402:        /* get a stack (exception frame) */             ; \
        !           403: 1:     bsr     _ASM_LABEL(m88110_setup_phase_one)      ; \
        !           404:        /* TMP2 now free -- use to set EF_VECTOR */     ; \
        !           405:        or      TMP2, r0, NUM                           ; \
        !           406:        st      TMP2, r31, REG_OFF(EF_VECTOR)           ; \
        !           407:        /* call setup_phase_two to restart the FPU  */  ; \
        !           408:        /* and to save all general registers.       */  ; \
        !           409:        bsr     _ASM_LABEL(m88110_setup_phase_two)
        !           410: #endif
        !           411:
        !           412: /* Some defines for use with PREP88100() */
        !           413: #define        Clear_SSBR_Dest \
        !           414:        bsr     _ASM_LABEL(clear_dest_ssbr_bit);
        !           415: #define        M88100_Data_Precheck \
        !           416:        bb1.n   FLAG_IGNORE_DATA_EXCEPTION, FLAGS, \
        !           417:            _ASM_LABEL(m88100_ignore_data_exception);
        !           418: #define        M88110_Data_Precheck \
        !           419:        bb1.n   FLAG_IGNORE_DATA_EXCEPTION, FLAGS, \
        !           420:            _ASM_LABEL(m88110_ignore_data_exception);
        !           421:
        !           422: #ifdef M88100
        !           423: /*
        !           424:  * 88100 exception handlers
        !           425:  */
        !           426:
        !           427: /* unknown exception handler */
        !           428: GLOBAL(unknown_handler)
        !           429:        PREP88100("unknown", 0,,)
        !           430:        or      r2, r0, T_UNKNOWNFLT
        !           431:        or      r3, r0, r30
        !           432:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           433:
        !           434: /* interrupt exception handler */
        !           435: GLOBAL(interrupt_handler)
        !           436:        PREP88100("interrupt", 1,,)
        !           437:        or      r2, r0, T_INT
        !           438:        or      r3, r0, r30
        !           439:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           440:
        !           441: /* instruction access exception handler */
        !           442: GLOBAL(instruction_access_handler)
        !           443:        PREP88100("inst", 2,,)
        !           444:        or      r2, r0, T_INSTFLT
        !           445:        or      r3, r0, r30
        !           446:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           447:
        !           448: /*
        !           449:  * data access exception handler --
        !           450:  *  See badaddr() below for info about Data_Precheck.
        !           451:  */
        !           452: GLOBAL(data_exception_handler)
        !           453:        PREP88100("data", 3,, M88100_Data_Precheck)
        !           454:        /* No need to call m88100_trap(T_DATAFLT) as PREP will do this for us */
        !           455:        br      _ASM_LABEL(check_ast)
        !           456:
        !           457: /* misaligned access exception handler */
        !           458: GLOBAL(misaligned_handler)
        !           459:        PREP88100("misalign", 4, Clear_SSBR_Dest,)
        !           460:        or      r2, r0, T_MISALGNFLT
        !           461:        or      r3, r0, r30
        !           462:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           463:
        !           464: /* unimplemented opcode exception handler */
        !           465: GLOBAL(unimplemented_handler)
        !           466:        PREP88100("unimp", 5,,)
        !           467:        or      r2, r0, T_ILLFLT
        !           468:        or      r3, r0, r30
        !           469:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           470:
        !           471: /*
        !           472:  * Some versions of the chip have a bug whereby false privilege
        !           473:  * violation exceptions are raised. If the valid bit in the SXIP is clear,
        !           474:  * it is false.  If so, just return.  The code before PREP handles this....
        !           475:  */
        !           476: GLOBAL(privilege_handler)
        !           477:        stcr    r1, SR2         /* hold r1 for a moment */
        !           478:        ldcr    r1, SXIP        /* look at the sxip... valid bit set? */
        !           479:        bb1.n   RTE_VALID_BIT, r1, 1f   /* skip over if a valid exception */
        !           480:         ldcr   r1, SR2         /* restore r1 */
        !           481:        RTE
        !           482: 1:     PREP88100("privilege", 6, Clear_SSBR_Dest,)
        !           483:        or      r2, r0, T_PRIVINFLT
        !           484:        or      r3, r0, r30
        !           485:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           486:
        !           487: /* bounds checking exception handler */
        !           488: GLOBAL(bounds_handler)
        !           489:        PREP88100("bounds", 7, Clear_SSBR_Dest,)
        !           490:        or      r2, r0, T_BNDFLT
        !           491:        or      r3, r0, r30
        !           492:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           493:
        !           494: /* integer divide-by-zero exception handler */
        !           495: GLOBAL(divide_handler)
        !           496:        PREP88100("divide", 8, Clear_SSBR_Dest,)
        !           497:        or      r2, r0, T_ZERODIV
        !           498:        or      r3, r0, r30
        !           499:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           500:
        !           501: /* integer overflow exception handler */
        !           502: GLOBAL(overflow_handler)
        !           503:        PREP88100("overflow", 9,,)
        !           504:        or      r2, r0, T_OVFFLT
        !           505:        or      r3, r0, r30
        !           506:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           507:
        !           508: /* Floating-point precise handler */
        !           509: #define        FPp_SSBR_STUFF \
        !           510:        bsr     _ASM_LABEL(clear_FPp_ssbr_bit);
        !           511: GLOBAL(fp_precise_handler)
        !           512:        PREP88100("FPU precise", 114, FPp_SSBR_STUFF,)
        !           513:        or      r3, r0, r30
        !           514:        XCALL(_ASM_LABEL(m88100_Xfp_precise), _ASM_LABEL(check_ast))
        !           515:
        !           516: /* Floating-point imprecise handler */
        !           517: #define        FPi_SSBR_STUFF \
        !           518:        bsr     _ASM_LABEL(clear_FPi_ssbr_bit);
        !           519: GLOBAL(fp_imprecise_handler)
        !           520:        PREP88100("FPU imprecise", 115, FPi_SSBR_STUFF,)
        !           521:        or      r3, r0, r30
        !           522:        XCALL(_ASM_LABEL(Xfp_imprecise), _ASM_LABEL(check_ast))
        !           523:
        !           524: /* trap 450: system calls */
        !           525: GLOBAL(syscall_handler)
        !           526:        PREP88100("syscall", 450,,)
        !           527:        ld      r2, r30, GENREG_OFF(13)
        !           528:        or      r3, r0, r30
        !           529:        XCALL(_C_LABEL(m88100_syscall), _ASM_LABEL(check_ast))
        !           530:
        !           531: /* trap 451: cache flush (necessary for trampolines) */
        !           532: GLOBAL(cache_flush_handler)
        !           533:        PREP88100("cache_flush", 451,,)
        !           534:        or      r2, r0, r30
        !           535:        XCALL(_C_LABEL(cache_flush), _ASM_LABEL(check_ast))
        !           536:
        !           537: GLOBAL(sigsys)
        !           538:        PREP88100("sigsys", 501,,)
        !           539:        or      r2, r0, T_SIGSYS
        !           540:        or      r3, r0, r30
        !           541:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           542:
        !           543: GLOBAL(stepbpt)
        !           544:        PREP88100("stepbpt", 504,,)
        !           545:        or      r2, r0, T_STEPBPT
        !           546:        or      r3, r0, r30
        !           547:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           548:
        !           549: GLOBAL(userbpt)
        !           550:        PREP88100("userbpt", 511,,)
        !           551:        or      r2, r0, T_USERBPT
        !           552:        or      r3, r0, r30
        !           553:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           554:
        !           555: #ifdef DDB
        !           556: GLOBAL(break)
        !           557:        PREP88100("break", 130,,)
        !           558:        or      r2, r0, T_KDB_BREAK
        !           559:        or      r3, r0, r30
        !           560:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           561:
        !           562: GLOBAL(trace)
        !           563:        PREP88100("trace", 131,,)
        !           564:        or      r2, r0, T_KDB_TRACE
        !           565:        or      r3, r0, r30
        !           566:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           567:
        !           568: GLOBAL(entry)
        !           569:        PREP88100("kdb", 132,,)
        !           570:        or      r2, r0, T_KDB_ENTRY
        !           571:        or      r3, r0, r30
        !           572:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(check_ast))
        !           573: #endif
        !           574:
        !           575: /*
        !           576:  * The error exception and reset exception handler.
        !           577:  *
        !           578:  * The error exception is raised when any other non-trap exception is raised
        !           579:  * while shadowing is off. This is Bad News.
        !           580:  *
        !           581:  * The reset exception is raised when the RST signal is asserted (machine
        !           582:  * is reset), the value of VBR is changed after exceptions are enabled,
        !           583:  * or when a jmp, br/bsr to addr 0 (accidents do happen :-)
        !           584:  * To tell the difference, you should check the value of r1 and the valid
        !           585:  * bit of SXIP.
        !           586:  * Upon a real reset, VBR is set to zero (0), so code must be at addr 0
        !           587:  * to handle it!!!
        !           588:  *
        !           589:  * The shadow registers are not valid in this case (shadowing was off, if this
        !           590:  * was an error exception, and may not be on, if this was a reset exception).
        !           591:  * R1-R31 may be interesting though, so we'll save them.
        !           592:  *
        !           593:  * We'll not worry about trashing r26-29 here,
        !           594:  * since they aren't generally used.
        !           595:  */
        !           596: GLOBAL(error_handler)
        !           597:        br.n    1f
        !           598:         or     r29, r0, 10
        !           599: GLOBAL(reset_handler)
        !           600:        or      r29, r0, 0
        !           601: 1:
        !           602:        or      r26, r0,  r31   /* save old stack */
        !           603:        or.u    r31, r0,  hi16(_ASM_LABEL(intstack_end))
        !           604:        or      r31, r31, lo16(_ASM_LABEL(intstack_end))
        !           605:
        !           606: #ifdef DEBUG
        !           607:        /* zero the stack, so we'll know what we're lookin' at */
        !           608:        or.u    r27, r0,  hi16(_ASM_LABEL(intstack))
        !           609:        or      r27, r27, lo16(_ASM_LABEL(intstack))
        !           610: 1:     cmp     r28, r27, r31
        !           611:        bb1     ge,  r28, 2f    /* branch if at the end of the stack */
        !           612:        st      r0,  r0,  r27
        !           613:        br.n    1b
        !           614:         addu   r27, r27, 4     /* bump up */
        !           615: 2:     /* stack has been cleared */
        !           616: #endif
        !           617:
        !           618:        /* ensure that stack is 8-byte aligned */
        !           619:        clr     r31, r31, 3<0>  /* round down to 8-byte boundary */
        !           620:
        !           621:        /* create exception frame on stack */
        !           622:        subu    r31, r31, SIZEOF_EF     /* r31 now our E.F. */
        !           623:
        !           624:        /* save old R31 and other R registers */
        !           625:        st.d    r0 , r31, GENREG_OFF(0)
        !           626:        st.d    r2 , r31, GENREG_OFF(2)
        !           627:        st.d    r4 , r31, GENREG_OFF(4)
        !           628:        st.d    r6 , r31, GENREG_OFF(6)
        !           629:        st.d    r8 , r31, GENREG_OFF(8)
        !           630:        st.d    r10, r31, GENREG_OFF(10)
        !           631:        st.d    r12, r31, GENREG_OFF(12)
        !           632:        st.d    r14, r31, GENREG_OFF(14)
        !           633:        st.d    r16, r31, GENREG_OFF(16)
        !           634:        st.d    r18, r31, GENREG_OFF(18)
        !           635:        st.d    r20, r31, GENREG_OFF(20)
        !           636:        st.d    r22, r31, GENREG_OFF(22)
        !           637:        st.d    r24, r31, GENREG_OFF(24)
        !           638:        st      r30, r31, GENREG_OFF(30)
        !           639:        st      r26, r31, GENREG_OFF(31)
        !           640:
        !           641:        /* save shadow registers (are OLD if error_handler, though) */
        !           642:        ldcr    r10, EPSR
        !           643:        st      r10, r31, REG_OFF(EF_EPSR)
        !           644:        ldcr    r10, SXIP
        !           645:        st      r10, r31, REG_OFF(EF_SXIP)
        !           646:        ldcr    r10, SNIP
        !           647:        st      r10, r31, REG_OFF(EF_SNIP)
        !           648:        ldcr    r10, SR1
        !           649:        st      r10, r31, REG_OFF(EF_MODE)
        !           650:        ldcr    r10, SFIP
        !           651:        st      r10, r31, REG_OFF(EF_SFIP)
        !           652:        ldcr    r10, SSBR
        !           653:        st      r10, r31, REG_OFF(EF_SSBR)
        !           654:        stcr    r0,  SSBR       /* won't want shadow bits bothering us later */
        !           655:
        !           656:        ldcr    r10, DMT0
        !           657:        st      r10, r31, REG_OFF(EF_DMT0)
        !           658:        ldcr    r11, DMD0
        !           659:        st      r11, r31, REG_OFF(EF_DMD0)
        !           660:        ldcr    r12, DMA0
        !           661:
        !           662:        st      r12, r31, REG_OFF(EF_DMA0)
        !           663:        ldcr    r10, DMT1
        !           664:        st      r10, r31, REG_OFF(EF_DMT1)
        !           665:        FLUSH_PIPELINE
        !           666:        ldcr    r11, DMD1
        !           667:        st      r11, r31, REG_OFF(EF_DMD1)
        !           668:        ldcr    r12, DMA1
        !           669:        st      r12, r31, REG_OFF(EF_DMA1)
        !           670:
        !           671:        ldcr    r10, DMT2
        !           672:        st      r10, r31, REG_OFF(EF_DMT2)
        !           673:        ldcr    r11, DMD2
        !           674:        st      r11, r31, REG_OFF(EF_DMD2)
        !           675:        ldcr    r12, DMA2
        !           676:        st      r12, r31, REG_OFF(EF_DMA2)
        !           677:
        !           678:        /* shove sr2 into EF_FPLS1 */
        !           679:        ldcr    r10, SR2
        !           680:        st      r10, r31, REG_OFF(EF_FPLS1)
        !           681:
        !           682:        /* shove sr3 into EF_FPHS2 */
        !           683:        ldcr    r10, SR3
        !           684:        st      r10, r31, REG_OFF(EF_FPHS2)
        !           685:
        !           686:        /* save error vector */
        !           687:        st      r29, r31, REG_OFF(EF_VECTOR)
        !           688:
        !           689:        /*
        !           690:         * Cheap way to enable FPU and start shadowing again.
        !           691:         */
        !           692:        ldcr    r10, PSR
        !           693:        clr     r10, r10, 1<PSR_FPU_DISABLE_BIT>        /* enable the FPU */
        !           694:        clr     r10, r10, 1<PSR_SHADOW_FREEZE_BIT>      /* and shadowing */
        !           695:        stcr    r10, PSR
        !           696:        FLUSH_PIPELINE
        !           697:
        !           698:        /* put pointer to regs into r30... r31 will become a simple stack */
        !           699:        or      r30, r31, r0
        !           700:
        !           701:        subu    r31, r31, 0x10  /* make some breathing space */
        !           702:        st      r30, r31, 0x0c  /* store frame pointer on the stack */
        !           703: #ifdef DDB
        !           704:        st      r30, r31, 0x08  /* store again for the debugger to recognize */
        !           705:        or.u    r20,  r0, hi16(0x87654321)
        !           706:        or      r20, r20, lo16(0x87654321)
        !           707:        st      r20, r31, 0x04
        !           708:        st      r20, r31, 0x00
        !           709: #endif
        !           710:
        !           711:        bsr.n   _C_LABEL(error_fatal)
        !           712:         or     r2, r0, r30
        !           713:
        !           714:        /* turn interrupts back on */
        !           715:        ldcr    r1, PSR
        !           716:        clr     r1, r1, 1<PSR_INTERRUPT_DISABLE_BIT>
        !           717:        stcr    r1, PSR
        !           718:        FLUSH_PIPELINE
        !           719:
        !           720: 1:
        !           721:        br      1b
        !           722:        /* NOTREACHED */
        !           723: #endif /* M88100 */
        !           724:
        !           725: /*
        !           726:  * This is part of baddadr (below).
        !           727:  */
        !           728: #ifdef M88100
        !           729: ASLOCAL(m88100_ignore_data_exception)
        !           730:        /*
        !           731:         * SR1: previous FLAGS reg
        !           732:         * SR2: free
        !           733:         * SR3: must preserve
        !           734:         * FLAGS: CPU status flags
        !           735:         */
        !           736:        xcr     FLAGS, FLAGS, SR1       /* replace SR1, FLAGS */
        !           737:
        !           738:        /*
        !           739:         * For more info, see badaddr() below.
        !           740:         *
        !           741:         * We just want to jump to "badaddr__return_nonzero" below.
        !           742:         *
        !           743:         * We don't worry about trashing r2 here because we're
        !           744:         * jumping back to the function badaddr() where we're allowed
        !           745:         * to blast r2..r9 as we see fit.
        !           746:         */
        !           747:
        !           748:        /* the "+2" below is to set the VALID bit. */
        !           749:        or.u    r2, r0, hi16(_ASM_LABEL(badaddr__return_nonzero) + 2)
        !           750:        or      r2, r2, lo16(_ASM_LABEL(badaddr__return_nonzero) + 2)
        !           751:        stcr    r2, SNIP        /* Make it the next instruction to execute */
        !           752:        addu    r2, r2, 4
        !           753:        stcr    r2, SFIP        /* and the next one after that, too. */
        !           754:        stcr    r0, SSBR        /* make the scoreboard happy. */
        !           755:        RTE
        !           756: #endif /* M88100 */
        !           757:
        !           758: #ifdef M88110
        !           759: /*
        !           760:  * This is part of baddadr (below).
        !           761:  */
        !           762: ASLOCAL(m88110_ignore_data_exception)
        !           763:        /*
        !           764:         * SR1: previous FLAGS reg
        !           765:         * SR2: free
        !           766:         * SR3: must preserve
        !           767:         * FLAGS: CPU status flags
        !           768:         */
        !           769:        xcr     FLAGS, FLAGS, SR1       /* replace SR1, FLAGS */
        !           770:
        !           771:        /*
        !           772:         * For more info, see badaddr() below.
        !           773:         *
        !           774:         * We just want to jump to "badaddr__return_nonzero" below.
        !           775:         *
        !           776:         * We don't worry about trashing R2 here because we're
        !           777:         * jumping back to the function badaddr() where we're allowed
        !           778:         * to blast r2..r9 as we see fit.
        !           779:         */
        !           780:
        !           781:        or.u    r2, r0, hi16(_ASM_LABEL(badaddr__return_nonzero))
        !           782:        or      r2, r2, lo16(_ASM_LABEL(badaddr__return_nonzero))
        !           783:        stcr    r2, EXIP        /* Make it the next instruction to execute */
        !           784:        stcr    r0, DSR         /* Clear exception status */
        !           785:        RTE
        !           786: #endif /* M88110 */
        !           787:
        !           788: /*
        !           789:  * extern boolean_t badaddr(unsigned addr, unsigned len)
        !           790:  *
        !           791:  * Returns true (non-zero) if the given LEN bytes starting at ADDR are
        !           792:  * not all currently accessible by the kernel.
        !           793:  *
        !           794:  * If all LEN bytes starting at ADDR are accessible, zero is returned.
        !           795:  *
        !           796:  * Len may be be 1, 2, or 4.
        !           797:  *
        !           798:  * This is implemented by setting a special flag in SR1 before trying to access
        !           799:  * the given address. If a data access exception is raised, the address
        !           800:  * is inaccessible. The exception handler will notice the special CPU flag
        !           801:  * and not try to swap the address in. Rather, it will return to
        !           802:  * "badaddr__return_nonzero" in this routine so that we may return non-zero
        !           803:  * to the calling routine.
        !           804:  *
        !           805:  * If no fault is raised, we continue to where we return zero to the calling
        !           806:  * routine (after removing the special CPU flag).
        !           807:  */
        !           808:
        !           809: GLOBAL(badaddr)
        !           810:        /*
        !           811:         * Disable interrupts ... don't want a context switch while we're
        !           812:         * doing this! Also, save the old PSR in R8 to restore later.
        !           813:         */
        !           814:        ldcr    r8, PSR
        !           815:        set     r4, r8, 1<PSR_INTERRUPT_DISABLE_BIT>
        !           816:        stcr    r4, PSR
        !           817:        FLUSH_PIPELINE
        !           818:
        !           819:        ldcr    r5, SR1
        !           820:        set     r5, r5, 1<FLAG_IGNORE_DATA_EXCEPTION>
        !           821:        /* resetting r5 to SR1 done in the delay slot below. */
        !           822:
        !           823:        /*
        !           824:         * If it's a word we're doing, do that here. Otherwise,
        !           825:         * see if it's a halfword.....
        !           826:         */
        !           827:        sub     r6,  r3, 4
        !           828:        bcnd.n  ne0, r6, _ASM_LABEL(badaddr__maybe_halfword)
        !           829:         stcr   r5,  SR1
        !           830:        FLUSH_PIPELINE
        !           831:
        !           832:        /*
        !           833:         * It's a bad address if it's misaligned.
        !           834:         */
        !           835:        bb1     0, r2, _ASM_LABEL(badaddr__return_nonzero)
        !           836:        bb1     1, r2, _ASM_LABEL(badaddr__return_nonzero)
        !           837:        /*
        !           838:         * The next line will either fault or not. If it faults, execution
        !           839:         * will go to:  data_access_handler (see above)
        !           840:         * and then to: ignore_data_exception (see above)
        !           841:         * and then to: badaddr__return_nonzero (see below)
        !           842:         * which will return to the calling function.
        !           843:         *
        !           844:         * If there is no fault, execution just continues as normal.
        !           845:         */
        !           846:        ld      r5, r2, 0
        !           847:        FLUSH_PIPELINE
        !           848:        br.n    _ASM_LABEL(badaddr__return)
        !           849:         or     r2, r0, r0      /* indicate a zero (address not bad) return.*/
        !           850:
        !           851: ASLOCAL(badaddr__maybe_halfword)
        !           852:        /* More or less like the code for checking a word above */
        !           853:        sub     r6, r3, 2
        !           854:        bcnd    ne0, r6, _ASM_LABEL(badaddr__maybe_byte)
        !           855:
        !           856:        /* it's bad if it's misaligned */
        !           857:        bb1     0, r2, _ASM_LABEL(badaddr__return_nonzero)
        !           858:
        !           859:        FLUSH_PIPELINE
        !           860:        ld.h    r5, r2, 0
        !           861:        FLUSH_PIPELINE
        !           862:        br.n    _ASM_LABEL(badaddr__return)
        !           863:         or     r2, r0, r0
        !           864:
        !           865: ASLOCAL(badaddr__maybe_byte)
        !           866: #ifdef DEBUG
        !           867:        /* More or less like the code for checking a word above */
        !           868:        sub     r6, r3, 1
        !           869:        bcnd    ne0, r6, _ASM_LABEL(badaddr__unknown_size)
        !           870: #endif
        !           871:        FLUSH_PIPELINE
        !           872:        ld.b    r5, r2, 0
        !           873:        FLUSH_PIPELINE
        !           874:        br.n    _ASM_LABEL(badaddr__return)
        !           875:         or     r2, r0, r0
        !           876: ASLOCAL(badaddr__unknown_size)
        !           877: #ifdef DEBUG
        !           878:        data
        !           879: 1:     string "bad length (%d) to badaddr() from 0x%x\000"
        !           880:        text
        !           881:        or.u    r2, r0, hi16(1b)
        !           882:        or      r2, r2, lo16(1b)
        !           883:        bsr.n   _C_LABEL(panic)
        !           884:         or     r4, r0, r1
        !           885:        /*NOTREACHED*/
        !           886: #endif
        !           887:
        !           888: ASLOCAL(badaddr__return_nonzero)
        !           889:        or      r2, r0, 1
        !           890:        /* FALLTHROUGH */
        !           891:
        !           892: ASLOCAL(badaddr__return)
        !           893:        ldcr    r4, SR1
        !           894:        clr     r4, r4, 1<FLAG_IGNORE_DATA_EXCEPTION>
        !           895:        stcr    r4, SR1
        !           896:
        !           897:        /*
        !           898:         * Restore the PSR to what it was before.
        !           899:         * The only difference is that we might be enabling interrupts
        !           900:         * (which we turned off above).  If interrupts were already off,
        !           901:         * we do not want to turn them on now, so we just restore from
        !           902:         * where we saved it.
        !           903:         */
        !           904:        stcr    r8, PSR
        !           905:        FLUSH_PIPELINE
        !           906:        jmp     r1
        !           907:
        !           908: #ifdef M88100
        !           909: ASLOCAL(m88100_setup_phase_one)
        !           910:        /*
        !           911:         * SR1: saved copy of exception-time register now holding FLAGS
        !           912:         * SR2: saved copy of exception-time r1
        !           913:         * SR3: must be preserved .. may be the exception-time stack
        !           914:         * r1: return address to calling exception handler
        !           915:         * FLAGS: CPU status flags
        !           916:         *
        !           917:         * immediate goal:
        !           918:         *   Decide where we're going to put the exception frame.
        !           919:         *   Might be at the end of R31, SR3, or the process pcb.
        !           920:         */
        !           921:
        !           922:        /* Check if we are coming in from a FPU restart exception.
        !           923:           If so, the pcb will be in SR3 */
        !           924:        NOP
        !           925:        xcr     r1,   r1,   SR2
        !           926:        NOP
        !           927:        NOP
        !           928:        NOP
        !           929:
        !           930:        bb1     FLAG_ENABLING_FPU, FLAGS, _ASM_LABEL(m88100_use_SR3_pcb)
        !           931:        /* are we coming in from user mode? If so, pick up process pcb */
        !           932:        bb0     FLAG_FROM_KERNEL, FLAGS, _ASM_LABEL(m88100_pickup_stack)
        !           933:
        !           934:        /* Interrupt in kernel mode, not FPU restart */
        !           935:        /*
        !           936:         * SR1: saved copy of exception-time register now holding FLAGS
        !           937:         * SR2: return address to the calling exception handler
        !           938:         * SR3: must be preserved; may be important for other exceptions
        !           939:         * FLAGS: CPU status flags
        !           940:         *
        !           941:         * immediate goal:
        !           942:         *   We're already on the kernel stack, but not having
        !           943:         *   needed to use SR3. We can just make room on the
        !           944:         *   stack (r31) for our exception frame.
        !           945:         */
        !           946:        subu    r31,  r31,  SIZEOF_EF           /* r31 now our E.F. */
        !           947:        st      FLAGS,r31,  REG_OFF(EF_FLAGS)   /* save flags */
        !           948:        st      r1,   r31,  GENREG_OFF(1)       /* save prev. r1 (now free)*/
        !           949:
        !           950:        ldcr    r1,   SR3                       /* save previous SR3 */
        !           951:        st      r1,   r31,  REG_OFF(EF_SR3)
        !           952:
        !           953:        addu    r1,   r31,  SIZEOF_EF           /* save previous r31 */
        !           954:        br.n    _ASM_LABEL(m88100_have_pcb)
        !           955:         st     r1,   r31,  GENREG_OFF(31)
        !           956:
        !           957: ASLOCAL(m88100_use_SR3_pcb)
        !           958:        /*
        !           959:         * SR1: saved copy of exception-time register now holding FLAGS
        !           960:         * SR2: return address to the calling exception handler
        !           961:         * SR3: must be preserved; exception-time stack pointer
        !           962:         * FLAGS: CPU status flags
        !           963:         *
        !           964:         * immediate goal:
        !           965:         *   An exception occurred while enabling the FPU. Since r31
        !           966:         *   is the user's r31 while enabling the FPU, we had put
        !           967:         *   our pcb pointer into SR3, so make room from
        !           968:         *   there for our stack pointer.
        !           969:         *   We need to check if SR3 is the old stack pointer or the
        !           970:         *   pointer off to the user pcb. If it pointing to the user
        !           971:         *   pcb, we need to pick up the kernel stack. Otherwise
        !           972:         *   we need to allocate a frame upon it.
        !           973:         *   We look at the EPSR to see if it was from user mode
        !           974:         *   Unfortunately, we have no registers free at the moment
        !           975:         *   But we know register 0 in the pcb frame will always be
        !           976:         *   zero, so we can use it as scratch storage.
        !           977:         */
        !           978:        xcr     r30,  r30,  SR3                 /* r30 = old exception frame */
        !           979:        st      r1,   r30,  GENREG_OFF(0)       /* free up r1 */
        !           980:        ld      r1,   r30,  REG_OFF(EF_EPSR)    /* get back the epsr */
        !           981:        bb0.n   PSR_SUPERVISOR_MODE_BIT, r1, 1f /* if user mode */
        !           982:         ld     r1,   r30,  GENREG_OFF(0)       /* restore r1 */
        !           983:        /* we were in kernel mode - dump frame upon the stack */
        !           984:        st      r0,   r30,  GENREG_OFF(0)       /* repair old frame */
        !           985:        subu    r30,  r30,  SIZEOF_EF           /* r30 now our E.F. */
        !           986:        st      FLAGS,r30,  REG_OFF(EF_FLAGS)   /* save flags */
        !           987:        st      r1,   r30,  GENREG_OFF(1)       /* save prev r1 (now free) */
        !           988:
        !           989:        st      r31,  r30,  GENREG_OFF(31)      /* save previous r31 */
        !           990:        or      r31,  r0,   r30                 /* make r31 our pointer. */
        !           991:        addu    r30,  r30,  SIZEOF_EF           /* r30 now has previous SR3 */
        !           992:        st      r30,  r31,  REG_OFF(EF_SR3)     /* save previous SR3 */
        !           993:        br.n    _ASM_LABEL(m88100_have_pcb)
        !           994:         xcr    r30,  r30,  SR3                 /* restore r30 */
        !           995: 1:
        !           996:        /* we took an exception while restarting the FPU from user space.
        !           997:         * Consequently, we never picked up a stack. Do so now.
        !           998:         * R1 is currently free (saved in the exception frame pointed at by
        !           999:         * r30) */
        !          1000:        ldcr    r1,   CPU
        !          1001:        ld      r1,   r1,   CI_CURPCB
        !          1002:        addu    r1,   r1,   USIZE - SIZEOF_EF
        !          1003:        st      FLAGS,r1,   REG_OFF(EF_FLAGS)   /* store flags */
        !          1004:        st      r31,  r1,   GENREG_OFF(31)      /* store r31 - now free */
        !          1005:        st      r30,  r1,   REG_OFF(EF_SR3)     /* store old SR3 (pcb) */
        !          1006:        or      r31,  r1,   r0                  /* make r31 our exception fp */
        !          1007:        ld      r1,   r30,  GENREG_OFF(0)       /* restore old r1 */
        !          1008:        st      r0,   r30,  GENREG_OFF(0)       /* repair that frame */
        !          1009:        st      r1,   r31,  GENREG_OFF(1)       /* store r1 */
        !          1010:        br.n    _ASM_LABEL(m88100_have_pcb)
        !          1011:         xcr    r30,  r30,  SR3                 /* restore r30 */
        !          1012:
        !          1013: ASLOCAL(m88100_pickup_stack)
        !          1014:        /*
        !          1015:         * SR1: saved copy of exception-time register now holding FLAGS
        !          1016:         * SR2: return address to the calling exception handler
        !          1017:         * SR3: free
        !          1018:         * FLAGS: CPU status flags
        !          1019:         *
        !          1020:         * immediate goal:
        !          1021:         *   Since we're servicing an exception from user mode, we
        !          1022:         *   know that SR3 is free.  We use it to free up a temp.
        !          1023:         *   register to be used in getting the process pcb
        !          1024:         */
        !          1025:        stcr    r31,  SR3       /* save previous r31 */
        !          1026:
        !          1027:        /* switch to the process kernel stack. */
        !          1028:        ldcr    r31,  CPU
        !          1029:        ld      r31,  r31,  CI_CURPCB
        !          1030:        addu    r31,  r31,  PCB_USER_STATE      /* point to user save area */
        !          1031:
        !          1032:        /*
        !          1033:         * WARNING! Using pcb->user_state as the exception frame
        !          1034:         * AND stack pointer, means we can not afford using the stack
        !          1035:         * until we have saved enough and can go back to the top of the u area,
        !          1036:         * after the FPU is enabled.
        !          1037:         */
        !          1038:
        !          1039:        st      FLAGS,r31,  REG_OFF(EF_FLAGS)   /* save flags */
        !          1040:        st      r1,   r31,  GENREG_OFF(1)       /* save prev. r1 (now free) */
        !          1041:        ldcr    r1,   SR3                       /* save previous r31 */
        !          1042:        st      r1,   r31,  GENREG_OFF(31)
        !          1043:        /* FALLTHROUGH */
        !          1044:
        !          1045: ASLOCAL(m88100_have_pcb)
        !          1046:        /*
        !          1047:         * SR1: saved copy of exception-time register now holding FLAGS
        !          1048:         * SR2: return address to the calling exception handler
        !          1049:         * SR3: free
        !          1050:         * r1:  free
        !          1051:         * FLAGS: CPU status flags
        !          1052:         * r31: our exception frame
        !          1053:         * Valid in the exception frame:
        !          1054:         *   Exception-time r1, r31, FLAGS.
        !          1055:         *   Exception SR3, if appropriate.
        !          1056:         *
        !          1057:         * immediate goal:
        !          1058:         *   Save the shadow registers that need to be saved to
        !          1059:         *   the exception frame.
        !          1060:         */
        !          1061:        stcr    TMP, SR3        /* free up TMP, TMP2, TMP3 */
        !          1062:        SAVE_TMP2
        !          1063:        SAVE_TMP3
        !          1064:
        !          1065:        /* save some exception-time registers to the exception frame */
        !          1066:        ldcr    TMP,  EPSR
        !          1067:        st      TMP,  r31,  REG_OFF(EF_EPSR)
        !          1068:        ldcr    TMP3, SNIP
        !          1069:        st      TMP3, r31,  REG_OFF(EF_SNIP)
        !          1070:        ldcr    TMP2, SFIP
        !          1071:        st      TMP2, r31,  REG_OFF(EF_SFIP)
        !          1072:        /* get and store the cpu_info pointer */
        !          1073:        ldcr    TMP,  CPU
        !          1074:        st      TMP,  r31,  REG_OFF(EF_CPU)
        !          1075:
        !          1076:        /*
        !          1077:         * Save Pbus fault status register from data and inst CMMU.
        !          1078:         * We can afford calling a function since r1 is safe to use here.
        !          1079:         */
        !          1080: GLOBAL(pfsr_save)
        !          1081:        PFSR_SAVE
        !          1082: ASLOCAL(pfsr_done)
        !          1083:
        !          1084:        ldcr    TMP,  SSBR
        !          1085:        ldcr    TMP2, SXIP
        !          1086:        ldcr    TMP3, DMT0
        !          1087:        st      TMP2, r31,  REG_OFF(EF_SXIP)
        !          1088:
        !          1089: /*
        !          1090:  * The above shadow registers are obligatory for any and all
        !          1091:  * exceptions.  Now, if the data access pipeline is not clear,
        !          1092:  * we must save the DMx shadow registers, as well as clear
        !          1093:  * the appropriate SSBR bits for the destination registers of
        !          1094:  * loads or xmems.
        !          1095:  */
        !          1096:        bb0.n   DMT_VALID_BIT, TMP3, 8f
        !          1097:         st     TMP3, r31,  REG_OFF(EF_DMT0)
        !          1098:
        !          1099:        ldcr    TMP2, DMT1
        !          1100:        ldcr    TMP3, DMT2
        !          1101:        st      TMP2, r31,  REG_OFF(EF_DMT1)
        !          1102:        st      TMP3, r31,  REG_OFF(EF_DMT2)
        !          1103:
        !          1104:        ldcr    TMP2, DMA0
        !          1105:        ldcr    TMP3, DMA1
        !          1106:        st      TMP2, r31,  REG_OFF(EF_DMA0)
        !          1107:        st      TMP3, r31,  REG_OFF(EF_DMA1)
        !          1108:
        !          1109:        ldcr    TMP2, DMA2
        !          1110:        ldcr    TMP3, DMD0
        !          1111:        st      TMP2, r31,  REG_OFF(EF_DMA2)
        !          1112:        st      TMP3, r31,  REG_OFF(EF_DMD0)
        !          1113:
        !          1114:        FLUSH_PIPELINE
        !          1115:        ldcr    TMP2, DMD1
        !          1116:        ldcr    TMP3, DMD2
        !          1117:        st      TMP2, r31,  REG_OFF(EF_DMD1)
        !          1118:        st      TMP3, r31,  REG_OFF(EF_DMD2)
        !          1119:
        !          1120: /*
        !          1121:  * need to clear "appropriate" bits in the SSBR before
        !          1122:  * we restart the FPU
        !          1123:  */
        !          1124:
        !          1125:        ldcr    TMP2, DMT0
        !          1126:        bb0.n   DMT_VALID_BIT, TMP2, 8f
        !          1127:        /* make sure an exception in fpu_enable will not see our DMT0 */
        !          1128:         stcr   r0,   DMT0
        !          1129:        bb1     DMT_LOCK_BIT,  TMP2, 1f
        !          1130:        bb1     DMT_WRITE_BIT, TMP2, 2f
        !          1131: 1:
        !          1132:        extu    TMP2, TMP2, DMT_DREG_WIDTH <DMT_DREG_OFFSET>
        !          1133:        set     TMP2, TMP2, 1<5>
        !          1134:        clr     TMP,  TMP,  TMP2
        !          1135: 2:
        !          1136:        ldcr    TMP2, DMT1
        !          1137:        bb0     DMT_VALID_BIT, TMP2, 4f
        !          1138:        bb1     DMT_LOCK_BIT,  TMP2, 3f
        !          1139:        bb1     DMT_WRITE_BIT, TMP2, 4f
        !          1140: 3:
        !          1141:        extu    TMP2, TMP2, DMT_DREG_WIDTH <DMT_DREG_OFFSET>
        !          1142:        set     TMP2, TMP2, 1<5>
        !          1143:        clr     TMP,  TMP,  TMP2
        !          1144: 4:
        !          1145:        ldcr    TMP2, DMT2
        !          1146:        bb0     DMT_VALID_BIT, TMP2, 8f
        !          1147:        bb1     DMT_LOCK_BIT,  TMP2, 5f
        !          1148:        bb1     DMT_WRITE_BIT, TMP2, 8f
        !          1149:        bb1     DMT_DOUBLE_BIT,TMP2, 6f
        !          1150: 5:
        !          1151:        extu    TMP2, TMP2, DMT_DREG_WIDTH <DMT_DREG_OFFSET>
        !          1152:        br.n    7f
        !          1153:         set    TMP2, TMP2, 1<5>        /* single */
        !          1154: 6:
        !          1155:        extu    TMP2, TMP2, DMT_DREG_WIDTH <DMT_DREG_OFFSET>
        !          1156:        set     TMP2, TMP2, 1<6>        /* double */
        !          1157: 7:
        !          1158:        clr     TMP,  TMP,  TMP2
        !          1159: 8:
        !          1160:        /*
        !          1161:         * SR1: saved copy of exception-time register now holding FLAGS
        !          1162:         * SR2: return address to the calling exception handler
        !          1163:         * SR3: saved TMP
        !          1164:         * r1:  free
        !          1165:         * TMP: possibly revised SSBR
        !          1166:         * TMP2: free
        !          1167:         * TMP3: free
        !          1168:         * FLAGS: CPU status flags
        !          1169:         * r31: exception frame
        !          1170:         * Valid in the exception frame:
        !          1171:         *   Exception-time r1, r31, FLAGS.
        !          1172:         *   Exception-time TMP2, TMP3.
        !          1173:         *   Exception-time espr, sfip, snip, sxip.
        !          1174:         *   Dmt0.
        !          1175:         *   Other data pipeline control registers, if appropriate.
        !          1176:         *   Exception SR3, if appropriate.
        !          1177:         */
        !          1178:        ldcr    r1,   SR2
        !          1179:        jmp     r1      /* allow the handler to clear more SSBR bits */
        !          1180:
        !          1181: ASLOCAL(clear_FPi_ssbr_bit)
        !          1182:        /*
        !          1183:         * Clear floatingpoint-imprecise ssbr bits.
        !          1184:         * Also, save appropriate FPU control registers to the E.F.
        !          1185:         *
        !          1186:         * r1:  return address to calling exception handler
        !          1187:         * TMP: (possibly) revised ssbr
        !          1188:         * TMP2: free
        !          1189:         * TMP3: free
        !          1190:         */
        !          1191:        fldcr   TMP2, FPSR
        !          1192:        fldcr   TMP3, FPCR
        !          1193:        st      TMP2, r31,  REG_OFF(EF_FPSR)
        !          1194:        st      TMP3, r31,  REG_OFF(EF_FPCR)
        !          1195:
        !          1196:        fldcr   TMP2, FPECR
        !          1197:        fldcr   TMP3, FPRH
        !          1198:        st      TMP2, r31,  REG_OFF(EF_FPECR)
        !          1199:        st      TMP3, r31,  REG_OFF(EF_FPRH)
        !          1200:
        !          1201:        fldcr   TMP2, FPIT
        !          1202:        fldcr   TMP3, FPRL
        !          1203:        st      TMP2, r31,  REG_OFF(EF_FPIT)
        !          1204:        st      TMP3, r31,  REG_OFF(EF_FPRL)
        !          1205:
        !          1206:        /*
        !          1207:         * We only need clear the bit in the SSBR for the
        !          1208:         * 2nd reg of a double result [see section 6.8.5]
        !          1209:         */
        !          1210: #define FPIT_SIZE_BIT   10
        !          1211:        bb0     FPIT_SIZE_BIT, TMP2, 1f
        !          1212:        extu    TMP2, TMP2, 5<0>        /* get the reg. */
        !          1213:        set     TMP2, TMP2, 1<6>        /* set width */
        !          1214:        clr     TMP,  TMP,  TMP2
        !          1215: 1:
        !          1216:        jmp     r1
        !          1217:
        !          1218:
        !          1219: ASLOCAL(clear_FPp_ssbr_bit)
        !          1220:        /*
        !          1221:         * Clear floating pont precise ssbr bits.
        !          1222:         * Also, save appropriate FPU control registers to the E.F.
        !          1223:         *
        !          1224:         * r1:  return address to calling exception handler
        !          1225:         * TMP: (possibly) revised ssbr
        !          1226:         * TMP2: free
        !          1227:         * TMP3: free
        !          1228:         */
        !          1229:        fldcr   TMP2, FPSR
        !          1230:        fldcr   TMP3, FPCR
        !          1231:        st      TMP2, r31,  REG_OFF(EF_FPSR)
        !          1232:        st      TMP3, r31,  REG_OFF(EF_FPCR)
        !          1233:
        !          1234:        fldcr   TMP3, FPECR
        !          1235:        st      TMP3, r31,  REG_OFF(EF_FPECR)
        !          1236:        fldcr   TMP2, FPHS1
        !          1237:        fldcr   TMP3, FPHS2
        !          1238:        st      TMP2, r31,  REG_OFF(EF_FPHS1)
        !          1239:        st      TMP3, r31,  REG_OFF(EF_FPHS2)
        !          1240:
        !          1241:        fldcr   TMP2, FPLS1
        !          1242:        fldcr   TMP3, FPLS2
        !          1243:        st      TMP2, r31,  REG_OFF(EF_FPLS1)
        !          1244:        st      TMP3, r31,  REG_OFF(EF_FPLS2)
        !          1245:
        !          1246:        fldcr   TMP2, FPPT
        !          1247:        st      TMP2, r31,  REG_OFF(EF_FPPT)
        !          1248:
        !          1249: #define FPPT_SIZE_BIT   5
        !          1250:        bb1.n   FPPT_SIZE_BIT, TMP2, 2f
        !          1251:         extu   TMP3, TMP2, 5<0>        /* get FP operation dest reg */
        !          1252:        br.n    3f
        !          1253:         set    TMP3, TMP3, 1<5>        /* size=1 - clear one bit for float */
        !          1254: 2:
        !          1255:        set     TMP3, TMP3, 1<6>        /* size=2 - clear two bit for double */
        !          1256: 3:
        !          1257:        jmp.n   r1
        !          1258:         clr    TMP,  TMP,  TMP3        /* clear bit(s) in ssbr. */
        !          1259:
        !          1260:
        !          1261: ASLOCAL(clear_dest_ssbr_bit)
        !          1262:        /*
        !          1263:         * There are various cases where an exception can leave the
        !          1264:         * destination register's bit in the SB set.
        !          1265:         * Examples:
        !          1266:         *   misaligned or privilege exception on a LD or XMEM
        !          1267:         *   DIV or DIVU by zero.
        !          1268:         *
        !          1269:         * I think that if the instruction is LD.D, then two bits must
        !          1270:         * be cleared.
        !          1271:         *
        !          1272:         * Even though there are a number of instructions/exception
        !          1273:         * combinations that could fire this code up, it's only required
        !          1274:         * to be run for the above cases.  However, I don't think it'll
        !          1275:         * ever be a problem to run this in other cases (ST instructions,
        !          1276:         * for example), so I don't bother checking.  If we had to check
        !          1277:         * for every possible instruction, this code would be much larger.
        !          1278:         *
        !          1279:         * The only checking, then, is to see if it's a LD.D or not.
        !          1280:         *
        !          1281:         * At the moment....
        !          1282:         *  r1:  return address to calling exception handler
        !          1283:         *  TMP: (possibly) revised ssbr
        !          1284:         *  TMP2: free
        !          1285:         *  TMP3: free
        !          1286:         */
        !          1287:
        !          1288:        ldcr    TMP3, EPSR      /* going to check: user or system memory? */
        !          1289:        ldcr    TMP2, SXIP      /* get the instruction's address */
        !          1290:        bb1.n   PSR_SUPERVISOR_MODE_BIT, TMP3, 2f
        !          1291:         clr    TMP2, TMP2, 2<0>        /* get rid of valid and error bits. */
        !          1292:
        !          1293:        /* user space load here */
        !          1294: #if ERRATA__XXX_USR
        !          1295:        NOP
        !          1296:        ld.usr  TMP2,TMP2, r0   /* get the instruction itself */
        !          1297:        NOP
        !          1298:        NOP
        !          1299:        NOP
        !          1300:        br    3f
        !          1301: #else
        !          1302:        br.n  3f
        !          1303:         ld.usr TMP2,TMP2, r0   /* get the instruction itself */
        !          1304: #endif
        !          1305:
        !          1306: 2:     /* system space load here */
        !          1307:        ld      TMP2, TMP2, r0  /* get the instruction itself */
        !          1308:
        !          1309: 3:     /* now we have the instruction..... */
        !          1310:        /*
        !          1311:         * Now see if it's a double load
        !          1312:         * There are three forms of double load [IMM16, scaled, unscaled],
        !          1313:         * which can be checked by matching against two templates:
        !          1314:         *          -- 77776666555544443333222211110000 --
        !          1315:         *   if (((instruction & 11111100000000000000000000000000) ==
        !          1316:         *             00010000000000000000000000000000) ;;
        !          1317:         *       ((instruction & 11111100000000001111110011100000) ==
        !          1318:         *             11110100000000000001000000000000))
        !          1319:         *   {
        !          1320:         *      It's a load double, so
        !          1321:         *      clear two SSBR bits.
        !          1322:         *   } else {
        !          1323:         *      It's not a load double.
        !          1324:         *      Must be a load single, xmem, or st
        !          1325:         *      Thus, clear one SSBR bit.
        !          1326:         *   }
        !          1327:         */
        !          1328:        /* check the first pattern for ld.d */
        !          1329:        extu    TMP3, TMP2, 16<16>      /* get the upper 16 bits */
        !          1330:        mask    TMP3, TMP3, 0xFC00      /* apply the mask */
        !          1331:        cmp     TMP3, TMP3, 0x1000      /* if equal, it's a load double */
        !          1332:        bb1     eq,   TMP3, 2f
        !          1333:
        !          1334:        /* still could be -- check the second pattern for ld.d */
        !          1335:        /* look at the upper 16 bits first */
        !          1336:        extu    TMP3, TMP2, 16<16>      /* get the upper 16 bits */
        !          1337:        mask    TMP3, TMP3, 0xFC00      /* apply the mask */
        !          1338:        cmp     TMP3, TMP3, 0xF400      /* if equal, might be a load double */
        !          1339:        bb1     ne,   TMP3, 1f          /* not equal, must be single */
        !          1340:
        !          1341:        /* now look at the lower 16 bits */
        !          1342:        extu    TMP3, TMP2, 16<0>       /* get the lower 16 bits */
        !          1343:        mask    TMP3, TMP3, 0xFCE0      /* apply the mask */
        !          1344:        cmp     TMP3, TMP3, 0x1000      /* if equal, it's a load double */
        !          1345:        bb1     eq,   TMP3, 2f
        !          1346:
        !          1347: 1:     /* misaligned single */
        !          1348:        extu    TMP2, TMP2, 5<21>       /* get the destination register */
        !          1349:        br.n    3f
        !          1350:         set    TMP2, TMP2, 1<5>        /* set size=1 */
        !          1351:
        !          1352: 2:     /* misaligned double */
        !          1353:        extu    TMP2, TMP2, 5<21>       /* get the destination register */
        !          1354:        set     TMP2, TMP2, 1<6>        /* set size=2 -- clear two bits */
        !          1355: 3:
        !          1356:        jmp.n   r1
        !          1357:         clr    TMP,  TMP,  TMP2        /* clear bit(s) in ssbr. */
        !          1358:
        !          1359: ASLOCAL(m88100_setup_phase_two)
        !          1360:        /*
        !          1361:         * SR1: saved copy of exception-time register now holding FLAGS
        !          1362:         * SR2: free
        !          1363:         * SR3: saved TMP
        !          1364:         * r1:  return address to calling exception handler
        !          1365:         * TMP: possibly revised SSBR
        !          1366:         * TMP2: free
        !          1367:         * TMP3: free
        !          1368:         * FLAGS: CPU status flags
        !          1369:         * r31: our exception frame
        !          1370:         *    Valid in the exception frame:
        !          1371:         *   Exception-time r1, r31, FLAGS.
        !          1372:         *   Exception-time TMP2, TMP3.
        !          1373:         *   Exception-time espr, sfip, snip, sxip.
        !          1374:         *   Exception number (EF_VECTOR).
        !          1375:         *   Dmt0
        !          1376:         *   Other data pipeline control registers, if appropriate.
        !          1377:         *   FPU control registers, if appropriate.
        !          1378:         *   Exception SR3, if appropriate.
        !          1379:         *
        !          1380:         * immediate goal:
        !          1381:         *   restore the system to the exception-time state (except
        !          1382:         *   SR3 will be OUR stack pointer) so that we may resart the FPU.
        !          1383:         */
        !          1384:
        !          1385:        stcr    TMP,  SSBR      /* done with SSBR, TMP now free */
        !          1386:        RESTORE_TMP2    /* done with extra temp regs */
        !          1387:        RESTORE_TMP3    /* done with extra temp regs */
        !          1388:
        !          1389:        /* Get the current PSR and modify for the rte to enable the FPU */
        !          1390:        ldcr    TMP,  PSR
        !          1391:        clr     TMP,  TMP,  1<PSR_FPU_DISABLE_BIT>      /* enable the FPU */
        !          1392:        clr     TMP,  TMP,  1<PSR_SHADOW_FREEZE_BIT>    /* and shadowing */
        !          1393:        stcr    TMP,  EPSR
        !          1394:
        !          1395:        /* the "+2" below is to set the VALID_BIT */
        !          1396:        or.u    TMP,  r0,   hi16(_ASM_LABEL(m88100_fpu_enable) + 2)
        !          1397:        or      TMP,  TMP,  lo16(_ASM_LABEL(m88100_fpu_enable) + 2)
        !          1398:        stcr    TMP,  SNIP
        !          1399:        addu    TMP,  TMP,  4
        !          1400:        stcr    TMP,  SFIP
        !          1401:
        !          1402:        set     FLAGS, FLAGS, 1<FLAG_ENABLING_FPU>
        !          1403:        xcr     FLAGS, FLAGS, SR1
        !          1404:        st      r1,   r31,  REG_OFF(EF_RET)     /* save the return address */
        !          1405:        ld      r1,   r31,  GENREG_OFF(1)       /* get original r1 */
        !          1406:
        !          1407:        xcr     TMP,  r31,  SR3 /* TMP now restored. R31 now saved in SR3 */
        !          1408:        ld      r31,  r31,  GENREG_OFF(31)      /* get original r31 */
        !          1409:
        !          1410:        /*
        !          1411:         * SR1: CPU flags
        !          1412:         * SR2: free
        !          1413:         * SR3: pointer to our exception frame (our stack pointer)
        !          1414:         * r1 through r31: original exception-time values
        !          1415:         *
        !          1416:         * Valid in the exception frame:
        !          1417:         *   Exception-time FLAGS.
        !          1418:         *   Exception-time espr, sfip, snip, sxip.
        !          1419:         *   Exception number (EF_VECTOR).
        !          1420:         *   Dmt0
        !          1421:         *   Other data pipeline control registers, if appropriate.
        !          1422:         *   FPU control registers, if appropriate.
        !          1423:         *   Exception SR3, if appropriate.
        !          1424:         *   Held temporarly in the exception frame:
        !          1425:         *   Return address to the calling exception handler.
        !          1426:         *
        !          1427:         * immediate goal:
        !          1428:         *   Do an RTE to restart the fpu and jump to "fpu_enable"
        !          1429:         *   Another exception (or exceptions) may be raised in
        !          1430:         *   this, which is why FLAG_ENABLING_FPU is set in SR1.
        !          1431:         */
        !          1432:
        !          1433:        RTE     /* jumps to "m88100_fpu_enable" to enable the FPU. */
        !          1434:
        !          1435: ASLOCAL(m88100_fpu_enable)
        !          1436:        FLUSH_PIPELINE
        !          1437:        xcr     TMP,  TMP,  SR3                 /* get E.F. pointer */
        !          1438:        st      r30,  TMP,  GENREG_OFF(30)      /* save previous r30, r31 */
        !          1439:        st      r31,  TMP,  GENREG_OFF(31)      /* save previous r30, r31 */
        !          1440:        or      r31,  TMP,  r0                  /* transfer E.F. pointer to r31 */
        !          1441:        ld      TMP,  r31,  REG_OFF(EF_SR3)     /* get previous SR3 */
        !          1442:
        !          1443:        /* make sure that the FLAG_ENABLING_FPU bit is off */
        !          1444:        xcr     FLAGS,FLAGS,SR1
        !          1445:        clr     FLAGS,FLAGS,1<FLAG_ENABLING_FPU>
        !          1446:        xcr     FLAGS,FLAGS,SR1
        !          1447:
        !          1448:        xcr     TMP,  TMP,  SR3 /* replace TMP, SR3 */
        !          1449:
        !          1450:        /* now save all regs to the exception frame. */
        !          1451:        st      r0 ,  r31,  GENREG_OFF(0)
        !          1452:        st      r1 ,  r31,  GENREG_OFF(1)
        !          1453:        st      r2 ,  r31,  GENREG_OFF(2)
        !          1454:        st      r3 ,  r31,  GENREG_OFF(3)
        !          1455:        st      r4 ,  r31,  GENREG_OFF(4)
        !          1456:        st      r5 ,  r31,  GENREG_OFF(5)
        !          1457:        st      r6 ,  r31,  GENREG_OFF(6)
        !          1458:        st      r7 ,  r31,  GENREG_OFF(7)
        !          1459:        st      r8 ,  r31,  GENREG_OFF(8)
        !          1460:        st      r9 ,  r31,  GENREG_OFF(9)
        !          1461:        st      r10,  r31,  GENREG_OFF(10)
        !          1462:        st      r11,  r31,  GENREG_OFF(11)
        !          1463:        st      r12,  r31,  GENREG_OFF(12)
        !          1464:        st      r13,  r31,  GENREG_OFF(13)
        !          1465:        st      r14,  r31,  GENREG_OFF(14)
        !          1466:        st      r15,  r31,  GENREG_OFF(15)
        !          1467:        st      r16,  r31,  GENREG_OFF(16)
        !          1468:        st      r17,  r31,  GENREG_OFF(17)
        !          1469:        st      r18,  r31,  GENREG_OFF(18)
        !          1470:        st      r19,  r31,  GENREG_OFF(19)
        !          1471:        st      r20,  r31,  GENREG_OFF(20)
        !          1472:        st      r21,  r31,  GENREG_OFF(21)
        !          1473:        st      r22,  r31,  GENREG_OFF(22)
        !          1474:        st      r23,  r31,  GENREG_OFF(23)
        !          1475:        st      r24,  r31,  GENREG_OFF(24)
        !          1476:        st      r25,  r31,  GENREG_OFF(25)
        !          1477:        st      r26,  r31,  GENREG_OFF(26)
        !          1478:        st      r27,  r31,  GENREG_OFF(27)
        !          1479:        st      r28,  r31,  GENREG_OFF(28)
        !          1480:
        !          1481:        /* get and save IPL */
        !          1482:        bsr.n   _C_LABEL(getipl)
        !          1483:         st     r29,  r31,  GENREG_OFF(29)
        !          1484:        st      r2, r31, REG_OFF(EF_MASK)
        !          1485:
        !          1486:        /*
        !          1487:         * SR1: free
        !          1488:         * SR2: free
        !          1489:         * SR3: previous exception-time SR3
        !          1490:         * r1: return address to the calling exception handler
        !          1491:         * r2 through r30: free
        !          1492:         * r31: our exception frame
        !          1493:         *
        !          1494:         * Valid in the exception frame:
        !          1495:         *   Exception-time r0 through r31.
        !          1496:         *   Exception-time FLAGS.
        !          1497:         *   Exception-time espr, sfip, snip, sxip.
        !          1498:         *   Exception number (EF_VECTOR).
        !          1499:         *   Dmt0
        !          1500:         *   Other data pipeline control registers, if appropriate.
        !          1501:         *   FPU control registers, if appropriate.
        !          1502:         *   Exception SR3, if appropriate.
        !          1503:         *
        !          1504:         * immediate goal:
        !          1505:         *   Pick up a stack if we came in from user mode.
        !          1506:         *   Put a copy of the exception frame pointer into r30
        !          1507:         *   Bump the stack a doubleword and write the exception frame pointer.
        !          1508:         *   If not an interrupt exception, turn on interrupts and service any
        !          1509:         *     outstanding data access exceptions.
        !          1510:         *   Return to calling exception handler to service the exception.
        !          1511:         */
        !          1512:
        !          1513:        /*
        !          1514:         * If it's not the interrupt exception, enable interrupts and
        !          1515:         * take care of any data access exceptions......
        !          1516:         */
        !          1517:        or      r30,  r0,   r31         /* get a copy of the e.f. pointer */
        !          1518:        ld      r2,   r31,  REG_OFF(EF_EPSR)
        !          1519:        bb1     PSR_SUPERVISOR_MODE_BIT, r2, 1f /* if in kernel mode */
        !          1520:
        !          1521:        ldcr    r31,  CPU
        !          1522:        ld      r31,  r31,  CI_CURPCB
        !          1523:        addu    r31,  r31,  USIZE       /* point at proper end */
        !          1524: 1:
        !          1525:
        !          1526:        /*
        !          1527:         * here - r30 holds a pointer to the exception frame.
        !          1528:         * r31 is a pointer to the kernel stack/interrupt stack.
        !          1529:         */
        !          1530:        subu    r31,  r31,  8   /* make some breathing space */
        !          1531:        st      r30,  r31,  0   /* store frame pointer on the stack */
        !          1532: #ifdef DDB
        !          1533:        st      r30,  r31,  4   /* store it for the debugger to recognize */
        !          1534: #endif
        !          1535:
        !          1536:        ld      r2,   r30,  REG_OFF(EF_VECTOR)
        !          1537:        bcnd.n  eq0,  r2,   8f                  /* error exception */
        !          1538:         ld     r14,  r30,  REG_OFF(EF_RET)
        !          1539:
        !          1540:        /*
        !          1541:         * Do not process possible data exceptions here if this is an interrupt.
        !          1542:         * Instead, the interrupt handler will take care of this by itself.
        !          1543:         */
        !          1544:        cmp     r3,   r2,   1                   /* is an interrupt? */
        !          1545:        bb1.n   eq,   r3,   8f                  /* skip if so */
        !          1546:
        !          1547: #ifdef DDB
        !          1548:         cmp    r3,   r2,   130 /* DDB break exception */
        !          1549:        bb1.n   eq,   r3,   8f
        !          1550:         cmp    r3,   r2,   132 /* DDB entry exception */
        !          1551:        bb1.n   eq,   r3,   8f
        !          1552: #endif
        !          1553:
        !          1554:        /* turn interrupts back on */
        !          1555:         ldcr   r2,   PSR
        !          1556:        clr     r2,   r2,   1<PSR_INTERRUPT_DISABLE_BIT>
        !          1557:        stcr    r2,   PSR
        !          1558:        FLUSH_PIPELINE
        !          1559:
        !          1560:        /* service any outstanding data pipeline stuff */
        !          1561:        ld      r3,   r30,  REG_OFF(EF_DMT0)
        !          1562:        bb0     DMT_VALID_BIT, r3, 8f
        !          1563:
        !          1564:        /*
        !          1565:         * r30 can be clobbered by calls. So stuff its value into a preserved
        !          1566:         * register, say r15. R14 is in use (see return_to_... below).
        !          1567:         */
        !          1568:        or      r15,  r0,   r30
        !          1569:        CALL(m88100_trap, T_DATAFLT, r15)
        !          1570:        or      r30,  r0,   r15
        !          1571:
        !          1572: 8:
        !          1573:        jmp     r14     /* loaded above */
        !          1574: #endif /* M88100 */
        !          1575:
        !          1576: #ifdef M88110
        !          1577: /*
        !          1578:  * 88110 exception handlers
        !          1579:  */
        !          1580:
        !          1581: /* unknown exception handler */
        !          1582: GLOBAL(m88110_unknown_handler)
        !          1583:        PREP88110("unknown", 0,)
        !          1584:        or      r2, r0, T_UNKNOWNFLT
        !          1585:        or      r3, r0, r30
        !          1586:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1587:
        !          1588: /* interrupt exception handler */
        !          1589: GLOBAL(m88110_interrupt_handler)
        !          1590:        PREP88110("interrupt", 1,)
        !          1591:        or      r2, r0, T_INT
        !          1592:        or      r3, r0, r30
        !          1593:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1594:
        !          1595: /* instruction access exception handler */
        !          1596: GLOBAL(m88110_instruction_access_handler)
        !          1597:        PREP88110("inst", 2,)
        !          1598:        or      r2, r0, T_INSTFLT
        !          1599:        or      r3, r0, r30
        !          1600:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1601: /*
        !          1602:  * data access exception handler --
        !          1603:  *  See badaddr() below for info about Data_Precheck.
        !          1604:  */
        !          1605: GLOBAL(m88110_data_exception_handler)
        !          1606:        PREP88110("data", 3, M88110_Data_Precheck)
        !          1607:        or      r2, r0, T_DATAFLT
        !          1608:        or      r3, r0, r30
        !          1609:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1610:
        !          1611: /* misaligned access exception handler */
        !          1612: GLOBAL(m88110_misaligned_handler)
        !          1613:        PREP88110("misalign", 4,)
        !          1614:        or      r2, r0, T_MISALGNFLT
        !          1615:        or      r3, r0, r30
        !          1616:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1617:
        !          1618: /* unimplemented opcode exception handler */
        !          1619: GLOBAL(m88110_unimplemented_handler)
        !          1620:        PREP88110("unimp", 5,)
        !          1621:        or      r2, r0, T_ILLFLT
        !          1622:        or      r3, r0, r30
        !          1623:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1624:
        !          1625: /* privilege exception handler */
        !          1626: GLOBAL(m88110_privilege_handler)
        !          1627:        PREP88110("privilege", 6,)
        !          1628:        or      r2, r0, T_PRIVINFLT
        !          1629:        or      r3, r0, r30
        !          1630:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1631:
        !          1632: /* bounds checking exception handler */
        !          1633: GLOBAL(m88110_bounds_handler)
        !          1634:        PREP88110("bounds", 7,)
        !          1635:        or      r2, r0, T_BNDFLT
        !          1636:        or      r3, r0, r30
        !          1637:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1638:
        !          1639: /* integer divide-by-zero exception handler */
        !          1640: GLOBAL(m88110_divide_handler)
        !          1641:        PREP88110("divide", 8,)
        !          1642:        or      r2, r0, T_ZERODIV
        !          1643:        or      r3, r0, r30
        !          1644:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1645:
        !          1646: /* integer overflow exception handler */
        !          1647: GLOBAL(m88110_overflow_handler)
        !          1648:        PREP88110("overflow", 9,)
        !          1649:        or      r2, r0, T_OVFFLT
        !          1650:        or      r3, r0, r30
        !          1651:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1652:
        !          1653: /* Floating-point precise handler */
        !          1654: GLOBAL(m88110_fp_precise_handler)
        !          1655:        PREP88110("FPU precise", 114,)
        !          1656:        or      r3, r0, r30
        !          1657:        XCALL(_ASM_LABEL(m88110_Xfp_precise), _ASM_LABEL(check_ast))
        !          1658:
        !          1659: /* MVME197 non-maskable interrupt handler (ABORT button) */
        !          1660: GLOBAL(m88110_nonmaskable)
        !          1661:        PREP88110("NMI", 11,)
        !          1662:        or      r2, r0, T_NON_MASK
        !          1663:        or      r3, r0, r30
        !          1664:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1665:
        !          1666: /* software walk data MMU read miss handler */
        !          1667: GLOBAL(m88110_data_read_miss)
        !          1668:        PREP88110("88110 data read miss", 12,)
        !          1669:        or      r2, r0, T_110_DRM
        !          1670:        or      r3, r0, r30
        !          1671:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1672:
        !          1673: /* software walk data MMU write miss handler */
        !          1674: GLOBAL(m88110_data_write_miss)
        !          1675:        PREP88110("88110 data write miss", 13,)
        !          1676:        or      r2, r0, T_110_DWM
        !          1677:        or      r3, r0, r30
        !          1678:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1679:
        !          1680: /* software walk inst MMU ATC miss handler */
        !          1681: GLOBAL(m88110_inst_atc_miss)
        !          1682:        PREP88110("88110 inst ATC miss", 14,)
        !          1683:        or      r2, r0, T_110_IAM
        !          1684:        or      r3, r0, r30
        !          1685:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1686:
        !          1687: /* trap 450: system calls */
        !          1688: GLOBAL(m88110_syscall_handler)
        !          1689:        PREP88110("syscall", 450,)
        !          1690:        ld      r2, r30, GENREG_OFF(13)
        !          1691:        or      r3, r0, r30
        !          1692:        XCALL(_C_LABEL(m88110_syscall), _ASM_LABEL(check_ast))
        !          1693:
        !          1694: /* trap 451: cache flush (necessary for trampolines) */
        !          1695: GLOBAL(m88110_cache_flush_handler)
        !          1696:        PREP88110("cache_flush", 451,)
        !          1697:        or      r2, r0, r30
        !          1698:        XCALL(_C_LABEL(cache_flush), _ASM_LABEL(check_ast))
        !          1699:
        !          1700: GLOBAL(m88110_sigsys)
        !          1701:        PREP88110("sigsys", 501,)
        !          1702:        or      r2, r0, T_SIGSYS
        !          1703:        or      r3, r0, r30
        !          1704:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1705:
        !          1706: GLOBAL(m88110_stepbpt)
        !          1707:        PREP88110("stepbpt", 504,)
        !          1708:        or      r2, r0, T_STEPBPT
        !          1709:        or      r3, r0, r30
        !          1710:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1711:
        !          1712: GLOBAL(m88110_userbpt)
        !          1713:        PREP88110("userbpt", 511,)
        !          1714:        or      r2, r0, T_USERBPT
        !          1715:        or      r3, r0, r30
        !          1716:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1717:
        !          1718: #ifdef DDB
        !          1719: GLOBAL(m88110_break)
        !          1720:        PREP88110("break", 130,)
        !          1721:        or      r2, r0, T_KDB_BREAK
        !          1722:        or      r3, r0, r30
        !          1723:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1724:
        !          1725: GLOBAL(m88110_trace)
        !          1726:        PREP88110("trace", 131,)
        !          1727:        or      r2, r0, T_KDB_TRACE
        !          1728:        or      r3, r0, r30
        !          1729:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1730:
        !          1731: GLOBAL(m88110_entry)
        !          1732:        PREP88110("kdb", 132,)
        !          1733:        or      r2, r0, T_KDB_ENTRY
        !          1734:        or      r3, r0, r30
        !          1735:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(check_ast))
        !          1736: #endif
        !          1737:
        !          1738: /*
        !          1739:  * The error exception and reset exception handler.
        !          1740:  *
        !          1741:  * The error exception is raised when any other non-trap exception is raised
        !          1742:  * while shadowing is off. This is Bad News.
        !          1743:  *
        !          1744:  * The reset exception is raised when the RST signal is asserted (machine
        !          1745:  * is reset), the value of VBR is changed after exceptions are enabled,
        !          1746:  * or when a jmp, br/bsr to addr 0 (accidents do happen :-)
        !          1747:  * Upon a real reset, VBR is set to zero (0), so code must be at addr 0
        !          1748:  * to handle it!!!
        !          1749:  *
        !          1750:  * The shadow registers are not valid in this case (shadowing was off, if this
        !          1751:  * was an error exception, and may not be on, if this was a reset exception).
        !          1752:  * R1-R31 may be interesting though, so we'll save them.
        !          1753:  *
        !          1754:  * We'll not worry about trashing r26-29 here,
        !          1755:  * since they aren't generally used.
        !          1756:  */
        !          1757: GLOBAL(m88110_error_handler)
        !          1758:        br.n    1f
        !          1759:         or     r29, r0, 10
        !          1760: GLOBAL(m88110_reset_handler)
        !          1761:        or      r29, r0, 0
        !          1762: 1:
        !          1763:        or      r26, r0, r31    /* save old stack */
        !          1764:        or.u    r31, r0,  hi16(_ASM_LABEL(intstack_end))
        !          1765:        or      r31, r31, lo16(_ASM_LABEL(intstack_end))
        !          1766:
        !          1767: #ifdef DEBUG
        !          1768:        /* zero the stack, so we'll know what we're lookin' at */
        !          1769:        or.u    r27, r0,  hi16(_ASM_LABEL(intstack))
        !          1770:        or      r27, r27, lo16(_ASM_LABEL(intstack))
        !          1771: 1:     cmp     r28, r27, r31
        !          1772:        bb1     ge,  r28, 2f    /* branch if at the end of the stack */
        !          1773:        st      r0,  r0,  r27
        !          1774:        br.n    1b
        !          1775:         addu   r27, r27, 4     /* bump up */
        !          1776: 2:     /* stack has been cleared */
        !          1777: #endif
        !          1778:
        !          1779:        /* ensure that stack is 8-byte aligned */
        !          1780:        clr     r31, r31, 3<0>  /* round down to 8-byte boundary */
        !          1781:
        !          1782:        /* create exception frame on stack */
        !          1783:        subu    r31, r31, SIZEOF_EF             /* r31 now our E.F. */
        !          1784:
        !          1785:        /* save old R31 and other R registers */
        !          1786:        st.d    r0 , r31, GENREG_OFF(0)
        !          1787:        st.d    r2 , r31, GENREG_OFF(2)
        !          1788:        st.d    r4 , r31, GENREG_OFF(4)
        !          1789:        st.d    r6 , r31, GENREG_OFF(6)
        !          1790:        st.d    r8 , r31, GENREG_OFF(8)
        !          1791:        st.d    r10, r31, GENREG_OFF(10)
        !          1792:        st.d    r12, r31, GENREG_OFF(12)
        !          1793:        st.d    r14, r31, GENREG_OFF(14)
        !          1794:        st.d    r16, r31, GENREG_OFF(16)
        !          1795:        st.d    r18, r31, GENREG_OFF(18)
        !          1796:        st.d    r20, r31, GENREG_OFF(20)
        !          1797:        st.d    r22, r31, GENREG_OFF(22)
        !          1798:        st.d    r24, r31, GENREG_OFF(24)
        !          1799:        st      r30, r31, GENREG_OFF(30)
        !          1800:        st      r26, r31, GENREG_OFF(31)
        !          1801:
        !          1802:        /* vector is put in SRO (either 0 or 10 at this point) */
        !          1803:        st      r29, r31, REG_OFF(EF_VECTOR)
        !          1804:        cmp     r29, r29, 0     /* is it the reset exception? */
        !          1805:        bb1.n   ne,  r29, 1f    /* if not, skip */
        !          1806:
        !          1807:        /* save shadow registers (are OLD if error_handler, though) */
        !          1808:         ldcr   r10, EPSR
        !          1809:        st      r10, r31, REG_OFF(EF_EPSR)
        !          1810:        ldcr    r10, EXIP
        !          1811:        st      r10, r31, REG_OFF(EF_EXIP)
        !          1812:        ldcr    r10, ENIP
        !          1813:        st      r10, r31, REG_OFF(EF_ENIP)
        !          1814:        ldcr    r10, DSR
        !          1815:        st      r10, r31, REG_OFF(EF_DSR)
        !          1816:        ldcr    r10, DLAR
        !          1817:        st      r10, r31, REG_OFF(EF_DLAR)
        !          1818:        ldcr    r10, DPAR
        !          1819:        st      r10, r31, REG_OFF(EF_DPAR)
        !          1820:        ldcr    r10, ISR
        !          1821:        st      r10, r31, REG_OFF(EF_ISR)
        !          1822:        ldcr    r10, ILAR
        !          1823:        st      r10, r31, REG_OFF(EF_ILAR)
        !          1824:        ldcr    r10, IPAR
        !          1825:        st      r10, r31, REG_OFF(EF_IPAR)
        !          1826:        ldcr    r10, SR1
        !          1827:        br.n    2f
        !          1828:         st     r10, r31, REG_OFF(EF_MODE)
        !          1829:
        !          1830: 1:
        !          1831:        /* retrieve saved shadow registers for error_handler */
        !          1832:        or.u    r30, r0,  hi16(_ASM_LABEL(save_frame))
        !          1833:        or      r30, r30, lo16(_ASM_LABEL(save_frame))
        !          1834:        ld      r10, r30, REG_OFF(EF_EPSR)
        !          1835:        st      r10, r31, REG_OFF(EF_EPSR)
        !          1836:        ld      r10, r30, REG_OFF(EF_EXIP)
        !          1837:        st      r10, r31, REG_OFF(EF_EXIP)
        !          1838:        ld      r10, r30, REG_OFF(EF_ENIP)
        !          1839:        st      r10, r31, REG_OFF(EF_ENIP)
        !          1840:        ld      r10, r30, REG_OFF(EF_DSR)
        !          1841:        st      r10, r31, REG_OFF(EF_DSR)
        !          1842:        ld      r10, r30, REG_OFF(EF_DLAR)
        !          1843:        st      r10, r31, REG_OFF(EF_DLAR)
        !          1844:        ld      r10, r30, REG_OFF(EF_DPAR)
        !          1845:        st      r10, r31, REG_OFF(EF_DPAR)
        !          1846:        ld      r10, r30, REG_OFF(EF_ISR)
        !          1847:        st      r10, r31, REG_OFF(EF_ISR)
        !          1848:        ld      r10, r30, REG_OFF(EF_ILAR)
        !          1849:        st      r10, r31, REG_OFF(EF_ILAR)
        !          1850:        ld      r10, r30, REG_OFF(EF_IPAR)
        !          1851:        st      r10, r31, REG_OFF(EF_IPAR)
        !          1852:        ld      r10, r30, REG_OFF(EF_ISAP)
        !          1853:        st      r10, r31, REG_OFF(EF_ISAP)
        !          1854:        ld      r10, r30, REG_OFF(EF_DSAP)
        !          1855:        st      r10, r31, REG_OFF(EF_DSAP)
        !          1856:        ld      r10, r30, REG_OFF(EF_IUAP)
        !          1857:        st      r10, r31, REG_OFF(EF_IUAP)
        !          1858:        ld      r10, r30, REG_OFF(EF_DUAP)
        !          1859:        st      r10, r31, REG_OFF(EF_DUAP)
        !          1860:        ldcr    r10, SR1
        !          1861:        st      r10, r31, REG_OFF(EF_MODE)
        !          1862: 2:
        !          1863:        /* shove sr2 into EF_FPLS1 */
        !          1864:        ldcr    r10, SR2
        !          1865:        st      r10, r31, REG_OFF(EF_FPLS1)
        !          1866:
        !          1867:        /* shove sr3 into EF_FPHS2 */
        !          1868:        ldcr    r10, SR3
        !          1869:        st      r10, r31, REG_OFF(EF_FPHS2)
        !          1870:
        !          1871:        /*
        !          1872:         * Cheap way to enable FPU and start shadowing again.
        !          1873:         */
        !          1874:        ldcr    r10, PSR
        !          1875:        clr     r10, r10, 1<PSR_FPU_DISABLE_BIT>        /* enable the FPU */
        !          1876:        clr     r10, r10, 1<PSR_SHADOW_FREEZE_BIT>      /* and shadowing */
        !          1877:        stcr    r10, PSR
        !          1878:        FLUSH_PIPELINE
        !          1879:
        !          1880:        /* put pointer to regs into r30... r31 will become a simple stack */
        !          1881:        or      r30, r31, r0
        !          1882:
        !          1883:        subu    r31, r31, 0x10  /* make some breathing space */
        !          1884:        st      r30, r31, 0x0c  /* store frame pointer on the stack */
        !          1885: #ifdef DDB
        !          1886:        st      r30, r31, 0x08  /* store again for the debugger to recognize */
        !          1887:        or.u    r20,  r0, hi16(0x87654321)
        !          1888:        or      r20, r20, lo16(0x87654321)
        !          1889:        st      r20, r31, 0x04
        !          1890:        st      r20, r31, 0x00
        !          1891: #endif
        !          1892:
        !          1893:        bsr.n   _C_LABEL(error_fatal)
        !          1894:         or     r2, r0, r30
        !          1895:
        !          1896:        /* turn interrupts back on */
        !          1897:        ldcr    r1, PSR
        !          1898:        clr     r1, r1, 1<PSR_INTERRUPT_DISABLE_BIT>
        !          1899:        stcr    r1, PSR
        !          1900:        FLUSH_PIPELINE
        !          1901:
        !          1902: 1:
        !          1903:        br      1b
        !          1904:        /* NOTREACHED */
        !          1905:
        !          1906: ASLOCAL(m88110_setup_phase_one)
        !          1907:        /*
        !          1908:         * SR1: saved copy of exception-time register now holding FLAGS
        !          1909:         * SR2: saved copy of exception-time r1
        !          1910:         * SR3: must be preserved .. may be the exception-time stack
        !          1911:         * r1: return address to calling exception handler
        !          1912:         * FLAGS: CPU status flags
        !          1913:         *
        !          1914:         * immediate goal:
        !          1915:         *   Decide where we're going to put the exception frame.
        !          1916:         *   Might be at the end of R31, SR3, or the process pcb.
        !          1917:         */
        !          1918:
        !          1919:        /* Check if we are coming in from a FPU restart exception.
        !          1920:           If so, the pcb will be in SR3 */
        !          1921:        NOP
        !          1922:        xcr     r1,   r1,   SR2
        !          1923:        NOP
        !          1924:        NOP
        !          1925:        NOP
        !          1926:
        !          1927:        bb1     FLAG_ENABLING_FPU, FLAGS, _ASM_LABEL(m88110_use_SR3_pcb)
        !          1928:        /* are we coming in from user mode? If so, pick up process pcb */
        !          1929:        bb0     FLAG_FROM_KERNEL, FLAGS, _ASM_LABEL(m88110_pickup_stack)
        !          1930:
        !          1931:        /* Interrupt in kernel mode, not FPU restart */
        !          1932:        /*
        !          1933:         * SR1: saved copy of exception-time register now holding FLAGS
        !          1934:         * SR2: return address to the calling exception handler
        !          1935:         * SR3: must be preserved; may be important for other exceptions
        !          1936:         * FLAGS: CPU status flags
        !          1937:         *
        !          1938:         * immediate goal:
        !          1939:         *   We're already on the kernel stack, but not having
        !          1940:         *   needed to use SR3. We can just make room on the
        !          1941:         *   stack (r31) for our exception frame.
        !          1942:         */
        !          1943:        subu    r31,  r31,  SIZEOF_EF           /* r31 now our E.F. */
        !          1944:        st      FLAGS,r31,  REG_OFF(EF_FLAGS)   /* save flags */
        !          1945:        st      r1,   r31,  GENREG_OFF(1)       /* save prev. r1 (now free) */
        !          1946:
        !          1947:        ldcr    r1,   SR3                       /* save previous SR3 */
        !          1948:        st      r1,   r31,  REG_OFF(EF_SR3)
        !          1949:
        !          1950:        addu    r1,   r31,  SIZEOF_EF           /* save previous r31 */
        !          1951:        br.n    _ASM_LABEL(m88110_have_pcb)
        !          1952:         st     r1,   r31,  GENREG_OFF(31)
        !          1953:
        !          1954: ASLOCAL(m88110_use_SR3_pcb)
        !          1955:        /*
        !          1956:         * SR1: saved copy of exception-time register now holding FLAGS
        !          1957:         * SR2: return address to the calling exception handler
        !          1958:         * SR3: must be preserved; exception-time stack pointer
        !          1959:         * FLAGS: CPU status flags
        !          1960:         *
        !          1961:         * immediate goal:
        !          1962:         *   An exception occurred while enabling the FPU. Since r31 is the
        !          1963:         *   user's r31 while enabling the FPU, we had put our pcb pointer
        !          1964:         *   into SR3, so make room from there for our stack pointer.
        !          1965:         *   We need to check if SR3 is the old stack pointer or the pointer
        !          1966:         *   off to the user pcb. If it pointing to the user pcb, we need to
        !          1967:         *   pick up the kernel stack. Otherwise we need to allocate a frame
        !          1968:         *   upon it.
        !          1969:         *   We look at the EPSR to see if it was from user mode
        !          1970:         *   Unfortunately, we have no registers free at the moment, but we
        !          1971:         *   know register 0 in the pcb frame will always be zero, so we can
        !          1972:         *   use it as scratch storage.
        !          1973:         */
        !          1974: #if 1
        !          1975:        ldcr    TMP,  PSR
        !          1976:        clr     TMP,  TMP,  1<PSR_FPU_DISABLE_BIT>      /* enable the FPU */
        !          1977:        clr     TMP,  TMP,  1<PSR_SHADOW_FREEZE_BIT>    /* and shadowing */
        !          1978:        stcr    TMP,  EPSR
        !          1979:
        !          1980:        or.u    TMP,  r0,   hi16(_C_LABEL(m88110_error_handler))
        !          1981:        or      TMP,  TMP,  lo16(_C_LABEL(m88110_error_handler))
        !          1982:        stcr    TMP,  EXIP
        !          1983:
        !          1984:        RTE
        !          1985: #else
        !          1986:        /* Testing!!! */
        !          1987:        xcr     r30,  r30,  SR3                 /* r30 = old exception frame */
        !          1988:        st      r1,   r30,  GENREG_OFF(0)       /* free up r1 */
        !          1989:        ld      r1,   r30,  REG_OFF(EF_EPSR)    /* get back the epsr */
        !          1990:        bb0.n   PSR_SUPERVISOR_MODE_BIT, r1, 1f /* if user mode */
        !          1991:         ld     r1,   r30,  GENREG_OFF(0)       /* restore r1 */
        !          1992:        /* we were in kernel mode - dump frame upon the stack */
        !          1993:        st      r0,   r30,  GENREG_OFF(0)       /* repair old frame */
        !          1994:        subu    r30,  r30,  SIZEOF_EF           /* r30 now our E.F. */
        !          1995:        st      FLAGS,r30,  REG_OFF(EF_FLAGS)   /* save flags */
        !          1996:        st      r1,   r30,  GENREG_OFF(1)       /* save prev. r1 (now free) */
        !          1997:
        !          1998:        st      r31,  r30,  GENREG_OFF(31)      /* save previous r31 */
        !          1999:        or      r31,  r0,   r30                 /* make r31 our pointer. */
        !          2000:        addu    r30,  r30,  SIZEOF_EF           /* r30 now has previous SR3 */
        !          2001:        st      r30,  r31,  REG_OFF(EF_SR3)     /* save previous SR3 */
        !          2002:        br.n    _ASM_LABEL(m88110_have_pcb)
        !          2003:         xcr    r30,  r30,  SR3                 /* restore r30 */
        !          2004: 1:
        !          2005:        /*
        !          2006:         * We took an exception while restarting the FPU from user space.
        !          2007:         * Consequently, we never picked up a stack. Do so now.
        !          2008:         * R1 is currently free (saved in the exception frame pointed at by
        !          2009:         * r30)
        !          2010:         */
        !          2011:        ldcr    r1,   CPU
        !          2012:        ld      r1,   r1,   CI_CURPCB
        !          2013:        addu    r1,   r1,   USIZE - SIZEOF_EF
        !          2014:        st      FLAGS,r1,   REG_OFF(EF_FLAGS)   /* store flags */
        !          2015:        st      r31,  r1,   GENREG_OFF(31)      /* store r31 - now free */
        !          2016:        st      r30,  r1,   REG_OFF(EF_SR3)     /* store old SR3 (pcb) */
        !          2017:        or      r31,  r1,   r0                  /* make r31 our exception fp */
        !          2018:        ld      r1,   r30,  GENREG_OFF(0)       /* restore old r1 */
        !          2019:        st      r0,   r30,  GENREG_OFF(0)       /* repair that frame */
        !          2020:        st      r1,   r31,  GENREG_OFF(1)       /* store r1 */
        !          2021:        br.n    _ASM_LABEL(m88110_have_pcb)
        !          2022:         xcr    r30,  r30,  SR3                 /* restore r30 */
        !          2023: #endif
        !          2024:
        !          2025: ASLOCAL(m88110_pickup_stack)
        !          2026:        /*
        !          2027:         * SR1: saved copy of exception-time register now holding FLAGS
        !          2028:         * SR2: return address to the calling exception handler
        !          2029:         * SR3: free
        !          2030:         * FLAGS: CPU status flags
        !          2031:         *
        !          2032:         * immediate goal:
        !          2033:         *   Since we're servicing an exception from user mode, we
        !          2034:         *   know that SR3 is free.  We use it to free up a temporary
        !          2035:         *   register to be used in getting the process pcb.
        !          2036:         */
        !          2037:        stcr    r31,  SR3       /* save previous r31 */
        !          2038:
        !          2039:        /* switch to the process kernel stack. */
        !          2040:        ldcr    r31,  CPU
        !          2041:        ld      r31,  r31,  CI_CURPCB
        !          2042:        addu    r31,  r31,  PCB_USER_STATE      /* point to user save area */
        !          2043:
        !          2044:        /*
        !          2045:         * WARNING! Using pcb->user_state as the exception frame
        !          2046:         * AND stack pointer, means we can not afford using the stack
        !          2047:         * until we have saved enough and can go back to the top of the u area,
        !          2048:         * after the FPU is enabled.
        !          2049:         */
        !          2050:
        !          2051:        st      FLAGS,r31,  REG_OFF(EF_FLAGS)   /* save flags */
        !          2052:        st      r1,   r31,  GENREG_OFF(1)       /* save prev. r1 (now free)*/
        !          2053:        ldcr    r1,   SR3                       /* save previous r31 */
        !          2054:        st      r1,   r31,  GENREG_OFF(31)
        !          2055:        /* FALLTHROUGH */
        !          2056:
        !          2057: ASLOCAL(m88110_have_pcb)
        !          2058:        /*
        !          2059:         * SR1: saved copy of exception-time register now holding FLAGS
        !          2060:         * SR2: return address to the calling exception handler
        !          2061:         * SR3: free
        !          2062:         * r1:  free
        !          2063:         * FLAGS: CPU status flags
        !          2064:         * r31: our exception frame
        !          2065:         * Valid in the exception frame:
        !          2066:         *   Exception-time r1, r31, FLAGS.
        !          2067:         *   Exception SR3, if appropriate.
        !          2068:         *
        !          2069:         * immediate goal:
        !          2070:         *   Save the shadow registers that need to be saved to
        !          2071:         *   the exception frame.
        !          2072:         */
        !          2073:        stcr    TMP, SR3        /* free up TMP, TMP2, TMP3 */
        !          2074:        SAVE_TMP2
        !          2075:        SAVE_TMP3
        !          2076:
        !          2077:        /* save some exception-time registers to the exception frame */
        !          2078:        ldcr    TMP,  EPSR
        !          2079:        st      TMP,  r31,  REG_OFF(EF_EPSR)
        !          2080:        ldcr    TMP2, EXIP
        !          2081:        ldcr    TMP3, ENIP
        !          2082:        st      TMP2, r31,  REG_OFF(EF_EXIP)
        !          2083:        st      TMP3, r31,  REG_OFF(EF_ENIP)
        !          2084:
        !          2085:        /* get and store the cpu_info pointer */
        !          2086:        ldcr    TMP,  CPU
        !          2087:        st      TMP,  r31,  REG_OFF(EF_CPU)
        !          2088:
        !          2089:        /*
        !          2090:         * Save fault status registers from CMMU.
        !          2091:         */
        !          2092:        ldcr    TMP,  ISR
        !          2093:        ldcr    TMP2, ILAR
        !          2094:        ldcr    TMP3, IPAR
        !          2095:        st      TMP,  r31,  REG_OFF(EF_ISR)
        !          2096:        st      TMP2, r31,  REG_OFF(EF_ILAR)
        !          2097:        st      TMP3, r31,  REG_OFF(EF_IPAR)
        !          2098:        ldcr    TMP,  ISAP
        !          2099:        ldcr    TMP2, IUAP
        !          2100:        st      TMP,  r31,  REG_OFF(EF_ISAP)
        !          2101:        st      TMP2, r31,  REG_OFF(EF_IUAP)
        !          2102:        ldcr    TMP,  DSR
        !          2103:        ldcr    TMP2, DLAR
        !          2104:        ldcr    TMP3, DPAR
        !          2105:        st      TMP,  r31,  REG_OFF(EF_DSR)
        !          2106:        st      TMP2, r31,  REG_OFF(EF_DLAR)
        !          2107:        st      TMP3, r31,  REG_OFF(EF_DPAR)
        !          2108:        ldcr    TMP,  DSAP
        !          2109:        ldcr    TMP2, DUAP
        !          2110:        st      TMP,  r31,  REG_OFF(EF_DSAP)
        !          2111:        st      TMP2, r31,  REG_OFF(EF_DUAP)
        !          2112:
        !          2113:        stcr    r0, ISR
        !          2114:        stcr    r0, DSR
        !          2115:
        !          2116:        ldcr    r1,   SR2
        !          2117:        jmp     r1
        !          2118:
        !          2119: ASLOCAL(m88110_setup_phase_two)
        !          2120:        /*
        !          2121:         * SR1: saved copy of exception-time register now holding FLAGS
        !          2122:         * SR2: free
        !          2123:         * SR3: saved TMP
        !          2124:         * r1:  return address to calling exception handler
        !          2125:         * TMP2: free
        !          2126:         * TMP3: free
        !          2127:         * FLAGS: CPU status flags
        !          2128:         * r31: our exception frame
        !          2129:         * Valid in the exception frame:
        !          2130:         *   Exception-time r1, r31, FLAGS.
        !          2131:         *   Exception-time TMP2, TMP3.
        !          2132:         *   Exception-time espr, enip, exip.
        !          2133:         *   Exception number (EF_VECTOR).
        !          2134:         *   Dmt0
        !          2135:         *   Other data pipeline control registers, if appropriate.
        !          2136:         *   FPU control registers, if appropriate.
        !          2137:         *   Exception SR3, if appropriate.
        !          2138:         *
        !          2139:         * immediate goal:
        !          2140:         *   restore the system to the exception-time state (except SR3 will
        !          2141:         *   be OUR stack pointer) so that we may resart the FPU.
        !          2142:         */
        !          2143:
        !          2144:        RESTORE_TMP2    /* done with extra temp regs */
        !          2145:        RESTORE_TMP3    /* done with extra temp regs */
        !          2146:
        !          2147:        ldcr    TMP,  PSR
        !          2148:        clr     TMP,  TMP,  1<PSR_FPU_DISABLE_BIT>      /* enable the FPU */
        !          2149:        clr     TMP,  TMP,  1<PSR_SHADOW_FREEZE_BIT>    /* and shadowing */
        !          2150:        stcr    TMP,  EPSR
        !          2151:
        !          2152:        or.u    TMP,  r0,   hi16(_ASM_LABEL(m88110_fpu_enable))
        !          2153:        or      TMP,  TMP,  lo16(_ASM_LABEL(m88110_fpu_enable))
        !          2154:        stcr    TMP,  EXIP
        !          2155:
        !          2156:        set     FLAGS, FLAGS, 1<FLAG_ENABLING_FPU>
        !          2157:        xcr     FLAGS, FLAGS, SR1
        !          2158:        st      r1,   r31,  REG_OFF(EF_RET)     /* save the return address */
        !          2159:        ld      r1,   r31,  GENREG_OFF(1)       /* get original r1 */
        !          2160:
        !          2161:        xcr     TMP,  r31, SR3  /* TMP now restored. R31 now saved in SR3 */
        !          2162:        ld      r31,  r31,  GENREG_OFF(31)      /* get original r31 */
        !          2163:
        !          2164:        /*
        !          2165:         * SR1: CPU flags
        !          2166:         * SR2: free
        !          2167:         * SR3: pointer to our exception frame (our stack pointer)
        !          2168:         * r1 through r31: original exception-time values
        !          2169:         *
        !          2170:         * Valid in the exception frame:
        !          2171:         *   Exception-time FLAGS.
        !          2172:         *   Exception-time espr, sfip, enip, exip.
        !          2173:         *   Exception number (EF_VECTOR).
        !          2174:         *   Dmt0
        !          2175:         *   Other data pipeline control registers, if appropriate.
        !          2176:         *   FPU control registers, if appropriate.
        !          2177:         *   Exception SR3, if appropriate.
        !          2178:         * Held temporarily in the exception frame:
        !          2179:         *   Return address to the calling exception handler.
        !          2180:         *
        !          2181:         * immediate goal:
        !          2182:         *   Do an RTE to restart the fpu and jump to "fpu_enable"
        !          2183:         *   Another exception (or exceptions) may be raised in
        !          2184:         *   this, which is why FLAG_ENABLING_FPU is set in SR1.
        !          2185:         */
        !          2186:        RTE     /* jumps to "m88110_fpu_enable" to enable the FPU. */
        !          2187:
        !          2188: ASLOCAL(m88110_fpu_enable)
        !          2189:        FLUSH_PIPELINE
        !          2190:
        !          2191:        xcr     TMP,  TMP,  SR3                 /* get E.F. pointer */
        !          2192:        st      r30,  TMP,  GENREG_OFF(30)      /* save previous r30, r31 */
        !          2193:        st      r31,  TMP,  GENREG_OFF(31)      /* save previous r30, r31 */
        !          2194:        or      r31,  TMP,  r0                  /* transfer E.F. pointer */
        !          2195:        ld      TMP,  r31,  REG_OFF(EF_SR3)     /* get previous SR3 */
        !          2196:
        !          2197:        /* make sure that the FLAG_ENABLING_FPU bit is off */
        !          2198:        xcr     FLAGS,FLAGS,SR1
        !          2199:        clr     FLAGS,FLAGS,1<FLAG_ENABLING_FPU>
        !          2200:        xcr     FLAGS,FLAGS,SR1
        !          2201:
        !          2202:        xcr     TMP,  TMP,  SR3 /* replace TMP, SR3 */
        !          2203:
        !          2204:        /* now save all regs to the exception frame. */
        !          2205:        st      r0 ,  r31,  GENREG_OFF(0)
        !          2206:        st      r1 ,  r31,  GENREG_OFF(1)
        !          2207:        st      r2 ,  r31,  GENREG_OFF(2)
        !          2208:        st      r3 ,  r31,  GENREG_OFF(3)
        !          2209:        st      r4 ,  r31,  GENREG_OFF(4)
        !          2210:        st      r5 ,  r31,  GENREG_OFF(5)
        !          2211:        st      r6 ,  r31,  GENREG_OFF(6)
        !          2212:        st      r7 ,  r31,  GENREG_OFF(7)
        !          2213:        st      r8 ,  r31,  GENREG_OFF(8)
        !          2214:        st      r9 ,  r31,  GENREG_OFF(9)
        !          2215:        st      r10,  r31,  GENREG_OFF(10)
        !          2216:        st      r11,  r31,  GENREG_OFF(11)
        !          2217:        st      r12,  r31,  GENREG_OFF(12)
        !          2218:        st      r13,  r31,  GENREG_OFF(13)
        !          2219:        st      r14,  r31,  GENREG_OFF(14)
        !          2220:        st      r15,  r31,  GENREG_OFF(15)
        !          2221:        st      r16,  r31,  GENREG_OFF(16)
        !          2222:        st      r17,  r31,  GENREG_OFF(17)
        !          2223:        st      r18,  r31,  GENREG_OFF(18)
        !          2224:        st      r19,  r31,  GENREG_OFF(19)
        !          2225:        st      r20,  r31,  GENREG_OFF(20)
        !          2226:        st      r21,  r31,  GENREG_OFF(21)
        !          2227:        st      r22,  r31,  GENREG_OFF(22)
        !          2228:        st      r23,  r31,  GENREG_OFF(23)
        !          2229:        st      r24,  r31,  GENREG_OFF(24)
        !          2230:        st      r25,  r31,  GENREG_OFF(25)
        !          2231:        st      r26,  r31,  GENREG_OFF(26)
        !          2232:        st      r27,  r31,  GENREG_OFF(27)
        !          2233:        st      r28,  r31,  GENREG_OFF(28)
        !          2234:
        !          2235:        /* get and save IPL */
        !          2236:        bsr.n   _C_LABEL(getipl)
        !          2237:         st     r29,  r31,  GENREG_OFF(29)
        !          2238:        st      r2, r31, REG_OFF(EF_MASK)
        !          2239:
        !          2240:        /*
        !          2241:         * SR1: free
        !          2242:         * SR2: free
        !          2243:         * SR3: previous exception-time SR3
        !          2244:         * r1: return address to the calling exception handler
        !          2245:         * r2 through r30: free
        !          2246:         * r31: our exception frame
        !          2247:         *
        !          2248:         * Valid in the exception frame:
        !          2249:         *   Exception-time r0 through r31.
        !          2250:         *   Exception-time FLAGS.
        !          2251:         *   Exception-time espr, enip, exip.
        !          2252:         *   Exception number (EF_VECTOR).
        !          2253:         *   DSR
        !          2254:         *   Other data pipeline control registers, if appropriate.
        !          2255:         *   FPU control registers, if appropriate.
        !          2256:         *   Exception SR3, if appropriate.
        !          2257:         *
        !          2258:         * immediate goal:
        !          2259:         *   Pick up a stack if we came in from user mode.
        !          2260:         *   Put a copy of the exception frame pointer into r30
        !          2261:         *   Bump the stack a doubleword and write the exception frame pointer.
        !          2262:         *   If not an interrupt exception, turn on interrupts and service any
        !          2263:         *     outstanding data access exceptions.
        !          2264:         *   Return to calling exception handler to service the exception.
        !          2265:         */
        !          2266:
        !          2267:        /*
        !          2268:         * If it's not the interrupt exception, enable interrupts and
        !          2269:         * take care of any data access exceptions......
        !          2270:         */
        !          2271:        or      r30,  r0,   r31         /* get a copy of the e.f. pointer */
        !          2272:        ld      r2,   r31,  REG_OFF(EF_EPSR)
        !          2273:        bb1     PSR_SUPERVISOR_MODE_BIT, r2, 1f /* if in kernel mode */
        !          2274:
        !          2275:        ldcr    r31,  CPU
        !          2276:        ld      r31,  r31,  CI_CURPCB
        !          2277:        addu    r31,  r31,  USIZE               /* point at proper end */
        !          2278: 1:
        !          2279:
        !          2280:        /*
        !          2281:         * here - r30 holds a pointer to the exception frame.
        !          2282:         * r31 is a pointer to the kernel stack/interrupt stack.
        !          2283:         */
        !          2284:        subu    r31,  r31,  8   /* make some breathing space */
        !          2285:        st      r30,  r31,  0   /* store frame pointer on the stack */
        !          2286: #ifdef DDB
        !          2287:        st      r30,  r31,  4   /* store it again for the debugger */
        !          2288: #endif
        !          2289:
        !          2290:        ld      r2,   r30,  REG_OFF(EF_VECTOR)
        !          2291:        bcnd.n  eq0,  r2,   8f
        !          2292:         ld     r14,  r30,  REG_OFF(EF_RET)     /* load return value XXX!!! */
        !          2293:        cmp     r3,   r2,   1   /* is an interrupt? */
        !          2294:        bb1.n   eq,   r3,   8f
        !          2295:         cmp    r3,   r2,   11  /* or NMI? */
        !          2296:        bb1.n   eq,   r3,   8f
        !          2297:
        !          2298: #ifdef DDB
        !          2299:         cmp    r3,   r2,   130 /* DDB break exception */
        !          2300:        bb1.n   eq,   r3,   8f
        !          2301:
        !          2302:         cmp    r3,   r2,   132 /* DDB entry exception */
        !          2303:        bb1.n   eq,   r3,   8f
        !          2304: #endif
        !          2305:
        !          2306:        /* turn interrupts back on */
        !          2307:         ldcr   r2,   PSR
        !          2308:        clr     r2,   r2,   1<PSR_INTERRUPT_DISABLE_BIT>
        !          2309:        stcr    r2,   PSR
        !          2310:        FLUSH_PIPELINE
        !          2311:
        !          2312: 8:
        !          2313:        jmp     r14             /* loaded above */
        !          2314:
        !          2315:        data
        !          2316:        .align 8                /* needs align 8 for ld.d/st.d */
        !          2317: ASLOCAL(save_frame)
        !          2318:        space SIZEOF_EF
        !          2319: #endif /* M88110 */
        !          2320:
        !          2321: /*
        !          2322:  * void proc_trampoline(void (*func)(void *), void *proc)
        !          2323:   *
        !          2324:  * When a process setup by cpu_fork() resumes, it will find itself in
        !          2325:  * proc_trampoline, with r31 pointing to a ksigframe. proc_trampoline will
        !          2326:  * load func and proc values from ksigframe, call the function, and on return
        !          2327:  * pop off the ksigframe. Then, it will load pc from the switchframe and
        !          2328:  * jump there (the pc will usually be proc_do_uret).
        !          2329:  */
        !          2330:
        !          2331: ENTRY(proc_trampoline)
        !          2332: #ifdef MULTIPROCESSOR
        !          2333:        bsr     _C_LABEL(proc_trampoline_mp)
        !          2334: #endif
        !          2335:        ld      r1, r31, 0              /* load func */
        !          2336:        ld      r2, r31, 4              /* load proc pointer */
        !          2337:        jsr.n   r1
        !          2338:         addu   r31, r31, 8             /* release ksigframe */
        !          2339:        ld      r1,  r31, 0             /* load pc */
        !          2340:        ld      r2,  r31, 4             /* & proc pointer from switch frame */
        !          2341:        jsr.n   r1
        !          2342:         addu   r31, r31, 8
        !          2343:
        !          2344: #define        FPTR    r14
        !          2345:
        !          2346:
        !          2347: ASLOCAL(check_ast)
        !          2348:        /*
        !          2349:         * Regs r1-r30 are free. r31 is pointing at the word
        !          2350:         * on the kernel stack where our pointer to the exception frame
        !          2351:         * it stored. Reload it now.
        !          2352:         *
        !          2353:         * We load it into r14 since it is preserved across function
        !          2354:         * calls, and we may have to call some routines from within here.
        !          2355:         *
        !          2356:         * Control is transferred here from obvious places in this file.
        !          2357:         */
        !          2358:        ld      FPTR, r31, 0    /* grab exception frame pointer */
        !          2359:        /*
        !          2360:         * If the saved ipl is 0, then call dosoftint() to process soft
        !          2361:         * interrupts.
        !          2362:         * If returning to userland, look for ASTs.
        !          2363:         */
        !          2364:        /* do not service soft interrupts if interrupts were disabled... */
        !          2365:        ld      r2, FPTR, REG_OFF(EF_EPSR)
        !          2366:        bb1     PSR_INTERRUPT_DISABLE_BIT, r2, _ASM_LABEL(no_softint)
        !          2367:        /* ...or we were not at spl0 */
        !          2368:        ld      r2, FPTR, REG_OFF(EF_MASK)
        !          2369:        bcnd    ne0, r2, _ASM_LABEL(no_softint)
        !          2370:
        !          2371:        /* do an inline spl0() */
        !          2372:        bsr.n   _C_LABEL(setipl)
        !          2373:         or     r2, r0, IPL_SOFTCLOCK
        !          2374:        bsr     _C_LABEL(dosoftint)
        !          2375:        bsr.n   _C_LABEL(setipl)
        !          2376:         or     r2, r0, IPL_NONE
        !          2377:
        !          2378: ASLOCAL(no_softint)
        !          2379:        /* do not service AST if not returning to user mode */
        !          2380:        ld      r2, FPTR, REG_OFF(EF_EPSR)
        !          2381:        bb1     PSR_SUPERVISOR_MODE_BIT, r2, _ASM_LABEL(no_ast)
        !          2382:
        !          2383:        ldcr    r2,  CPU
        !          2384:        ld      r3,  r2, CI_CURPROC
        !          2385:        bcnd    eq0, r3, _ASM_LABEL(no_ast)     /* no AST if no process! */
        !          2386:        ld      r2,  r3, P_ASTPENDING
        !          2387:        bcnd.n  eq0, r2, _ASM_LABEL(no_ast)     /* .n safe since the first
        !          2388:                                                   instruction of CALL() is
        !          2389:                                                   safe in a delay slot. */
        !          2390:        /*
        !          2391:         * trap(AST,...) will service ast's.
        !          2392:         */
        !          2393:         or     r3, r0, FPTR
        !          2394:        or      r2, r0, T_ASTFLT
        !          2395: #if defined(M88110) && defined(M88100)
        !          2396:        or.u    r4, r0, hi16(_C_LABEL(cputyp))
        !          2397:        ld      r5, r4, lo16(_C_LABEL(cputyp))
        !          2398:        cmp     r4, r5, CPU_88110
        !          2399:        bb0     eq, r4, 2f
        !          2400: #endif
        !          2401: #if defined(M88110)
        !          2402:        XCALL(_C_LABEL(m88110_trap), _ASM_LABEL(no_ast))
        !          2403: #endif
        !          2404: #if defined(M88110) && defined(M88100)
        !          2405: 2:
        !          2406: #endif
        !          2407: #ifdef M88100
        !          2408:        XCALL(_C_LABEL(m88100_trap), _ASM_LABEL(no_ast))
        !          2409: #endif
        !          2410:
        !          2411: /*
        !          2412:  * void proc_do_uret(struct proc *p)
        !          2413:  *
        !          2414:  * This is called as proc_do_uret(proc) from proc_trampoline(). This function
        !          2415:  * loads FPTR with a pointer to the trap frame for the given proc and continues
        !          2416:  * near the end of check_ast, bypassing soft interrupts and AST checks, to
        !          2417:  * load all the registers and do an RTE.
        !          2418:  */
        !          2419:
        !          2420: ENTRY(proc_do_uret)
        !          2421:        ld      FPTR, r2,   P_ADDR              /* p->p_addr */
        !          2422:        addu    FPTR, FPTR, PCB_USER_STATE      /* p->p_addr.u_pcb.user_state */
        !          2423:        /* FALLTHROUGH */
        !          2424:
        !          2425: ASLOCAL(no_ast)
        !          2426:        /* disable interrupts */
        !          2427:        ldcr    r1, PSR
        !          2428:        set     r1, r1, 1<PSR_INTERRUPT_DISABLE_BIT>
        !          2429:        stcr    r1, PSR
        !          2430:        FLUSH_PIPELINE
        !          2431:
        !          2432:        /* now ready to return....*/
        !          2433:        bsr.n   _C_LABEL(setipl)
        !          2434:         ld     r2, FPTR, REG_OFF(EF_MASK)      /* get pre-exception ipl */
        !          2435:
        !          2436:        /*
        !          2437:         * Transfer the frame pointer to r31, since we no longer need a stack.
        !          2438:         * No page faults here, and interrupts are disabled.
        !          2439:         */
        !          2440:        or      r31, r0,  FPTR
        !          2441:        /* restore r1 later */
        !          2442:        ld      r2 , r31, GENREG_OFF(2)
        !          2443:        ld      r3 , r31, GENREG_OFF(3)
        !          2444:        ld      r4 , r31, GENREG_OFF(4)
        !          2445:        ld      r5 , r31, GENREG_OFF(5)
        !          2446:        ld      r6 , r31, GENREG_OFF(6)
        !          2447:        ld      r7 , r31, GENREG_OFF(7)
        !          2448:        ld      r8 , r31, GENREG_OFF(8)
        !          2449:        ld      r9 , r31, GENREG_OFF(9)
        !          2450:        ld      r10, r31, GENREG_OFF(10)
        !          2451:        ld      r11, r31, GENREG_OFF(11)
        !          2452:        ld      r12, r31, GENREG_OFF(12)
        !          2453:        ld      r13, r31, GENREG_OFF(13)
        !          2454:        ld      r14, r31, GENREG_OFF(14)
        !          2455:        ld      r15, r31, GENREG_OFF(15)
        !          2456:        ld      r16, r31, GENREG_OFF(16)
        !          2457:        ld      r17, r31, GENREG_OFF(17)
        !          2458:        ld      r18, r31, GENREG_OFF(18)
        !          2459:        ld      r19, r31, GENREG_OFF(19)
        !          2460:        ld      r20, r31, GENREG_OFF(20)
        !          2461:        ld      r21, r31, GENREG_OFF(21)
        !          2462:        ld      r22, r31, GENREG_OFF(22)
        !          2463:        ld      r23, r31, GENREG_OFF(23)
        !          2464:        ld      r24, r31, GENREG_OFF(24)
        !          2465:        ld      r25, r31, GENREG_OFF(25)
        !          2466:        ld      r26, r31, GENREG_OFF(26)
        !          2467:        ld      r27, r31, GENREG_OFF(27)
        !          2468:        ld      r28, r31, GENREG_OFF(28)
        !          2469:        ld      r29, r31, GENREG_OFF(29)
        !          2470:        /* restore r1, r30, r31 later */
        !          2471:
        !          2472:        /* disable shadowing */
        !          2473:        ldcr    r1, PSR
        !          2474:        set     r1, r1, 1<PSR_SHADOW_FREEZE_BIT>
        !          2475:        stcr    r1, PSR
        !          2476:        FLUSH_PIPELINE
        !          2477:
        !          2478:        /* reload the control regs*/
        !          2479: #ifdef M88110
        !          2480: #ifdef M88100
        !          2481:        or.u    r1, r0, hi16(_C_LABEL(cputyp))
        !          2482:        ld      r30, r1, lo16(_C_LABEL(cputyp))
        !          2483:        cmp     r1, r30, CPU_88110
        !          2484:        bb1     ne, r1, 1f
        !          2485: #endif
        !          2486:        ld      r30, r31, REG_OFF(EF_ENIP)
        !          2487:        ld      r1,  r31, REG_OFF(EF_EXIP)
        !          2488:        stcr    r30, ENIP
        !          2489:        stcr    r1,  EXIP
        !          2490: #ifdef M88100
        !          2491:        br      2f
        !          2492: 1:
        !          2493: #endif
        !          2494: #endif
        !          2495: #ifdef M88100
        !          2496:        /*
        !          2497:         * RTE will cause execution to continue first with the
        !          2498:         * instruction pointed to by the NIP and then the FIP;
        !          2499:         * it is not necessary to restore XIP.
        !          2500:         */
        !          2501:        stcr    r0,  SSBR
        !          2502:        ld      r30, r31, REG_OFF(EF_SNIP)
        !          2503:        ld      r1,  r31, REG_OFF(EF_SFIP)
        !          2504:        stcr    r30, SNIP
        !          2505:        stcr    r1,  SFIP
        !          2506: 2:
        !          2507: #endif
        !          2508:        ld      r30, r31, REG_OFF(EF_EPSR)
        !          2509:        stcr    r30, EPSR
        !          2510:
        !          2511:        /* Now restore r1, r30, and r31 */
        !          2512:        ld      r1,  r31, GENREG_OFF(1)
        !          2513:        ld      r30, r31, GENREG_OFF(30)
        !          2514:        ld      r31, r31, GENREG_OFF(31)
        !          2515:
        !          2516:        RTE

CVSweb