arch/m68k-all: Compiler delint (gcc 4.6.2)
[AROS.git] / arch / m68k-all / kernel / m68k_exception.c
blobd9b056f86ad302382bfa6ad88169f5533261e3fd
1 /*
2 copyright © 1995-2010, the aros development team. all rights reserved.
3 $id$
5 desc: m68k-amiga bootstrap to exec.
6 lang: english
7 */
9 #define DEBUG 0
10 #include <aros/kernel.h>
11 #include <aros/debug.h>
12 #include <exec/resident.h>
13 #include <exec/execbase.h>
14 #include <exec/memory.h>
16 #include "exec_intern.h"
18 #include "m68k_exception.h"
20 /* Here's how it's all laid out on the Amiga
21 * M68K Exception
22 * 0 Reset: Initial SP
23 * 1 Reset: Initial PC (NOTE: Really is SysBase!)
24 * 2 Bus Error
25 * 3 Address Error
26 * 4 Illegal Instruction
27 * 5 Divide by Zero
28 * 6 CHK Instruction
29 * 7 TRAPV Instruction
30 * 8 Privileged Instruction
31 * 9 Trace
32 * 10 Line 1010 Emulator
33 * 11 Line 1111 Emulator
34 * 12 -
35 * 13 -
36 * 14 Format Error
37 * 15 Uninitilaized Interrupt Vector
38 * 16 -
39 * ..
40 * 23 -
41 * 24 Spurious Interrupt
42 * 25 Level 1 Interrupt
43 * Paula 0: Serial TX
44 * Paula 1: Disk DMA done
45 * Paula 2: Software Int
46 * 26 Level 2 Interrupt
47 * Paula 3: CIA
48 * 27 Level 3 Interrupt
49 * Paula 4: Copper
50 * Paula 5: Vert Blank
51 * Paula 6: Blitter
52 * 28 Level 4 Interrupt
53 * Paula 7: Audio 0
54 * Paula 8: Audio 1
55 * Paula 9: Audio 2
56 * Paula 10: Audio 3
57 * 29 Level 5 Interrupt
58 * Paula 11: Serial RX
59 * Paula 12: Disk Sync
60 * 30 Level 6 Interrupt
61 * Paula 13: External
62 * Paula 14: Copper (special)
63 * 31 Level 7 Interrupt
64 * Paula 15: NMI
65 * 32 TRAP #0
66 * ..
67 * 47 TRAP #15
68 * 48 -
69 * ..
70 * 63 -
71 * 64 User 1
72 * ..
73 * 255 User 191
76 extern ULONG M68KFaultTable_00[];
77 asm (
78 " .text\n"
79 " .align 4\n"
80 " .globl M68KFaultTable_00\n"
81 "M68KFaultTable_00:\n"
82 ".Lfault_0: bsr.w .Lfault\n" // Placeholder
83 ".Lfault_1: bsr.w .Lfault\n" // Placeholder
84 ".Lfault_2: bsr.w .Lfault\n" // Bus Error
85 ".Lfault_3: bsr.w .Lfault\n" // Address Error
86 ".Lfault_4: bsr.w .Lfault\n" // Illegal instruction
87 ".Lfault_5: bsr.w .Lfault\n" // Zero divide
88 ".Lfault_6: bsr.w .Lfault\n" // CHK
89 ".Lfault_7: bsr.w .Lfault\n" // TRAPV
90 ".Lfault_8: bsr.w .Lfault\n" // Privilege violation
91 ".Lfault_9: bsr.w .Lfault\n" // Trace
92 ".Lfault_10: bsr.w .Lfault\n" // Line A
93 ".Lfault_11: bsr.w .Lfault\n" // Line F
94 ".Lfault_12: bsr.w .Lfault\n" // Placeholder
95 ".Lfault_13: bsr.w .Lfault\n" // Placeholder
96 ".Lfault_14: bsr.w .Lfault\n" // Placeholder
97 ".Lfault_15: bsr.w .Lfault\n" // Placeholder
98 ".Lfault_16: bsr.w .Lfault\n" // Placeholder
99 ".Lfault_17: bsr.w .Lfault\n" // Placeholder
100 ".Lfault_18: bsr.w .Lfault\n" // Placeholder
101 ".Lfault_19: bsr.w .Lfault\n" // Placeholder
102 ".Lfault_20: bsr.w .Lfault\n" // Placeholder
103 ".Lfault_21: bsr.w .Lfault\n" // Placeholder
104 ".Lfault_22: bsr.w .Lfault\n" // Placeholder
105 ".Lfault_23: bsr.w .Lfault\n" // Placeholder
106 ".Lfault: subi.l #(M68KFaultTable_00 + 1*4 - 0*4),%sp@\n"
107 " jmp M68KExceptionHelper\n"
110 extern ULONG M68KLevelTable_00[];
111 asm (
112 " .text\n"
113 " .align 4\n"
114 " .globl M68KLevelTable_00\n"
115 "M68KLevelTable_00:\n"
116 ".Llevel_0: bsr.w .Llevel\n" // Spurious Interrupt
117 ".Llevel_1: bsr.w .Llevel\n" // Level 1 Interrupt
118 ".Llevel_2: bsr.w .Llevel\n" // Level 2 Interrupt
119 ".Llevel_3: bsr.w .Llevel\n" // Level 3 Interrupt
120 ".Llevel_4: bsr.w .Llevel\n" // Level 4 Interrupt
121 ".Llevel_5: bsr.w .Llevel\n" // Level 5 Interrupt
122 ".Llevel_6: bsr.w .Llevel\n" // Level 6 Interrupt
123 ".Llevel_7: bsr.w .Llevel\n" // Level 7 Interrupt
124 ".Llevel: subi.l #(M68KLevelTable_00 + 1*4 - 24*4),%sp@\n"
125 " jmp M68KExceptionHelper\n"
128 extern ULONG M68KTrapTable_00[];
129 asm (
130 " .text\n"
131 " .align 4\n"
132 " .globl M68KTrapTable_00\n"
133 "M68KTrapTable_00:\n"
134 ".Ltrap_0: bsr.w .Ltrap\n" // TRAP #0
135 ".Ltrap_1: bsr.w .Ltrap\n" // TRAP #1
136 ".Ltrap_2: bsr.w .Ltrap\n" // ...
137 ".Ltrap_3: bsr.w .Ltrap\n" // ...
138 ".Ltrap_4: bsr.w .Ltrap\n" // ...
139 ".Ltrap_5: bsr.w .Ltrap\n" // ...
140 ".Ltrap_6: bsr.w .Ltrap\n" // ...
141 ".Ltrap_7: bsr.w .Ltrap\n" // ...
142 ".Ltrap_8: bsr.w .Ltrap\n" // ...
143 ".Ltrap_9: bsr.w .Ltrap\n" // ...
144 ".Ltrap_10: bsr.w .Ltrap\n" // ...
145 ".Ltrap_11: bsr.w .Ltrap\n" // ...
146 ".Ltrap_12: bsr.w .Ltrap\n" // ...
147 ".Ltrap_13: bsr.w .Ltrap\n" // ...
148 ".Ltrap_14: bsr.w .Ltrap\n" // ...
149 ".Ltrap_15: bsr.w .Ltrap\n" // TRAP #15
150 ".Ltrap: subi.l #(M68KTrapTable_00 + 1*4 - 32*4),%sp@\n"
151 " jmp M68KExceptionHelper\n"
154 /* 68000 Exceptions */
155 static void M68KExceptionInit_00(struct ExecBase *SysBase)
157 APTR *exception = (APTR *)0;
158 int i;
160 /* Faults */
161 for (i = 2; i < 24; i++)
162 exception[i] = &M68KFaultTable_00[i];
164 /* Level interrupts */
165 for (i = 0; i < 7; i++)
166 exception[i + 24] = &M68KLevelTable_00[i];
168 /* NMI (exception[31]) is left unset, for debuggers */
170 /* Traps */
171 for (i = 0; i < 16; i++)
172 exception[i + 32] = &M68KTrapTable_00[i];
175 /* 68010 Traps */
177 /* For the 68010+, the lower 12 bits of the UWORD
178 * at %sp@(6) contains the vector number.
179 * Convenience!
181 extern void M68KTrapHelper_10(void);
182 asm (
183 " .text\n"
184 " .align 4\n"
185 " .globl M68KTrapHelper_10\n"
186 "M68KTrapHelper_10:\n"
187 " move.w %sp@(6),%sp@-\n" // Copy the vector
188 " andi.w #0x0fff,%sp@\n" // Clear the upper bits
189 " clr.w %sp@-\n" // extend vector to long
190 " bra M68KExceptionHelper\n"
193 static void M68KExceptionInit_10(struct ExecBase *SysBase)
195 APTR *exception = (APTR *)0;
196 int i;
198 /* We can use the same code for all M68010+ traps */
199 for (i = 2; i < 64; i++) {
200 /* Don't touch the NMI exception (for debuggers) */
201 if (i == 31)
202 continue;
203 exception[i] = M68KTrapHelper_10;
207 /******************** Exceptions *****************/
209 /* The stack frame here:
210 * Return PC ULONG@(6)
211 * Return SR UWORD@(4)
212 * Exception Vector ULONG@(0)
213 * SP ->
215 * When we call M68KExceptionAction:
216 * Return PC (4)
217 * Return SR (2)
218 * D0-D7/A0-A7 (16 * 4) <= NO TOUCHING!
219 * SysBase (4) A6
220 * SP (4) D1
221 * Exception Vector (4) D0
223 * When we come back:
224 * Drop SysBase, SP, and Exception args
225 * Restore D0-D1/A0-A1/A6
226 * Drop the Exception # word
227 * RTE
229 extern void M68KExceptionHelper(void);
230 asm (
231 " .text\n"
232 " .globl M68KExceptionHelper\n"
233 "M68KExceptionHelper:\n"
234 " lea.l %sp@(-12),%sp\n" // Fix stack to below regs.a[6]
235 " move.l %a6,%sp@(0)\n" // Save A6 in regs.a[6]
236 " move.l %sp@(12),%a6\n" // Get Exception Id into A6
237 " clr.l %sp@(12)\n" // Clear TrapCode arg
238 " move.l #0f,%sp@(8)\n" // Save default TrapCode
239 " move.l %a6,%sp@(4)\n" // Save Exception ID to regs.a[7]
240 " movem.l %d0-%d7/%a0-%a5,%sp@-\n"// Push everything - SP is now 'regs_t'
241 " move.l %sp@(15*4),%d1\n" // Exception Id (regs.a[7])
242 " move.l %usp,%a0\n"
243 " move.l %a0,%sp@(4*15)\n" // Fix up SP in regs as USP
244 " move.l %sp,%d0\n" // regs_t
245 " move.l 4, %a6\n" // Global SysBase
246 " move.l %a6, %sp@-\n" // Push SysBase
247 " move.l %d1, %sp@-\n" // Push Exception Id
248 " move.l %d0, %sp@-\n" // Push regs_t *
249 " jsr M68KExceptionAction\n"
250 " lea %sp@(12),%sp\n" // Drop all stack args
251 " movem.l %sp@+,%d0-%d7/%a0-%a5\n" // Restore all but a6
252 " move.l %sp@(4),%a6\n" // Get USP from regs_t
253 " move.l %a6,%usp\n" // Set USP
254 " move.l %sp@+,%a6\n" // Restore A6
255 " addq.l #4,%sp\n" // Pop off A7
256 " tst.l %sp@\n" // New tasks have a NULL trapcode
257 " beq.s 1f\n"
258 " rts\n" // Execute tc_TrapCode
259 "1:\n"
260 " addq.l #4,%sp\n"
261 "0:\n"
262 " addq.l #4,%sp\n" // Drop TrapCode parameter
263 " rte\n" // And return
266 /* Default handler */
267 extern void Exec_MagicResetCode(void);
268 void M68KExceptionHandler(regs_t *regs, int id, struct ExecBase *SysBase)
270 VOID (*trapHandler)(ULONG, void *);
272 if (SysBase == NULL ||
273 KernelBase == NULL) {
274 volatile LONG *LastAlert = (volatile LONG *)(64 * sizeof(LONG));
275 /* SysBase has been corrupted! Mark the alert,
276 * and reboot.
278 LastAlert[0] = (LONG)(AT_DeadEnd | AN_LibChkSum);
279 /* LastAlert[1] was already set by
280 * Exec/Dispatch
282 LastAlert[1] = 0; /* No SysBase? No Task. */
283 LastAlert[2] = 0;
284 LastAlert[3] = 0;
286 /* Set LastAlert marker */
287 *(volatile ULONG *)0 = 0x48454c50; /* 'HELP' */
288 Exec_MagicResetCode();
289 return;
292 trapHandler = FindTask(NULL)->tc_TrapCode;
293 /* Call an AmigaOS trap handler, in supervisor
294 * mode, that *may* alter almost any of our
295 * registers, by abusing the stack frame
296 * via 'regs_t'. Whee!
298 regs->trapcode = (IPTR)trapHandler;
299 regs->traparg = (ULONG)id;
302 void M68KExceptionAction(regs_t *regs, ULONG vector, struct ExecBase *SysBase)
304 int Id;
305 BOOL (*Handler)(regs_t *regs, int id, struct ExecBase *SysBase);
307 if (vector & 1) {
308 /* vector is really a pointer to a M68KException table entry */
309 struct M68KException *Exception;
311 Exception = (APTR)(vector & ~1);
313 Id = Exception->Id;
314 Handler = Exception->Handler;
315 } else {
316 Id = vector >> 2;
317 Handler = NULL;
320 #ifdef AROS_DEBUG_STACK
321 if (KernelBase != NULL) { // Prevents early failure
322 if (regs->sr & 0x2000) {
323 if ((APTR)regs < (SysBase->SysStkLower+0x10) || (((APTR)regs)-1) > SysBase->SysStkUpper) {
324 D(bug("Supervisor: iStack overflow %p (%p-%p)\n", (APTR)regs, SysBase->SysStkLower, SysBase->SysStkUpper));
325 D(bug("Exception: %d\n", Id));
326 D(PRINT_CPU_CONTEXT(regs));
327 Alert(AT_DeadEnd | AN_StackProbe);
329 } else {
330 #if 0 /* can't do this, in old times if was popular to reallocate new stacks manually.. */
331 struct Task *t = SysBase->ThisTask;
332 if ((APTR)regs->a[7] < (t->tc_SPLower+0x10) || (APTR)(regs->a[7]-1) > t->tc_SPUpper) {
333 D(bug("[%s]: iStack overflow %p (%p-%p)\n", t->tc_Node.ln_Name, (APTR)regs->a[7], t->tc_SPLower, t->tc_SPUpper));
334 D(bug("Exception: %d\n", Id));
335 D(PRINT_CPU_CONTEXT(regs));
336 Alert(AT_DeadEnd | AN_StackProbe);
338 #endif
341 #endif
343 if (Handler == NULL || !Handler(regs, Id, SysBase))
344 M68KExceptionHandler(regs, Id, SysBase);
346 #ifdef AROS_DEBUG_STACK
347 if (KernelBase != NULL) {
348 if (regs->sr & 0x2000) {
349 if ((APTR)regs < (SysBase->SysStkLower+0x10) || (((APTR)regs)-1) > SysBase->SysStkUpper) {
350 D(bug("Supervisor: Stack overflow %p (%p-%p)\n", (APTR)regs, SysBase->SysStkLower, SysBase->SysStkUpper));
351 D(bug("Exception: %d\n", Id));
352 D(PRINT_CPU_CONTEXT(regs));
353 Alert(AT_DeadEnd | AN_StackProbe);
355 } else {
356 struct Task *t = SysBase->ThisTask;
357 if ((APTR)regs->a[7] < (t->tc_SPLower+0x10) || (APTR)(regs->a[7]-1) > t->tc_SPUpper) {
358 D(bug("[%s]: Stack overflow %p (%p-%p)\n", t->tc_Node.ln_Name, (APTR)regs->a[7], t->tc_SPLower, t->tc_SPUpper));
359 D(bug("Exception: %d\n", Id));
360 D(PRINT_CPU_CONTEXT(regs));
361 Alert(AT_DeadEnd | AN_StackProbe);
365 #endif
368 /* We assume that the caller has already set up
369 * the exceptions to a 'reasonable' default. These
370 * are only the overrides for AROS.
372 void M68KExceptionInit(const struct M68KException *Table, struct ExecBase *SysBase)
374 IPTR *exception = (IPTR *)0; /* Exception base is at 0 */
375 UWORD *jmptab;
376 int i;
377 int size;
379 /* Initialize the Well Known Traps */
380 if (SysBase->AttnFlags & AFF_68010) {
381 M68KExceptionInit_10(SysBase);
382 } else {
383 M68KExceptionInit_00(SysBase);
386 if ((ULONG)Table & 1) {
387 /* Exception Table must be UWORD aligned! */
388 return;
391 for (size = 0; Table[size].Id > 0; size++);
393 /* A little explanation. jmptab will be
394 * constructed as follows:
395 * move.l (i << 1) | 1, %sp@+
396 * 0x2f3c ((i << 1) | 1) >> 16) ((i << 1) | 1) & 0xffff)
397 * jmp %pc@(((size - 1) - i) * (5 * sizeof(UWORD)) + 2)
398 * 0x4efa (((size - 1) - i) * (5 * sizeof(UWORD)) + 2)
399 * ...
400 * ...
401 * jmp M68KExceptionHelper
402 * 0x4ef9 (M68KExceptionHelper >> 16) (M68KExceptionHelper & 0xffff)
404 * NOTICE: jmptab will never be freed! */
405 jmptab = AllocMem(size * (5 * sizeof(UWORD)) + 3 * sizeof(UWORD), 0);
407 for (i = 0; i < size; i++, jmptab += 5) {
408 /* This little trick is why we want
409 * the Table UWORD aligned.
411 * See the rest of this in M68KExceptionHelper
413 ULONG vecid = (ULONG)(&Table[i]) | 1;
415 jmptab[0] = 0x2f3c; // movel #...,%sp@-
416 jmptab[1] = ((IPTR)(vecid) >> 16) & 0xffff;
417 jmptab[2] = ((IPTR)(vecid) >> 0) & 0xffff;
418 jmptab[3] = 0x4efa; // jmp %pc@...
419 jmptab[4] = ((size - 1) - i) * (5 * sizeof(UWORD)) + 2;
420 exception[Table[i].Id] = (IPTR)(&jmptab[0]);
422 jmptab[0] = 0x4ef9; // jmp ....
423 jmptab[1] = ((IPTR)(M68KExceptionHelper) >> 16) & 0xffff;
424 jmptab[2] = ((IPTR)(M68KExceptionHelper) >> 0) & 0xffff;
426 /* We're all set up now! */