Annotation of sys/arch/m88k/m88k/eh_common.S, Revision 1.1.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