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