2 copyright © 1995-2010, the aros development team. all rights reserved.
5 desc: m68k-amiga bootstrap to exec.
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
23 * 1 Reset: Initial PC (NOTE: Really is SysBase!)
26 * 4 Illegal Instruction
30 * 8 Privileged Instruction
32 * 10 Line 1010 Emulator
33 * 11 Line 1111 Emulator
37 * 15 Uninitilaized Interrupt Vector
41 * 24 Spurious Interrupt
42 * 25 Level 1 Interrupt
44 * Paula 1: Disk DMA done
45 * Paula 2: Software Int
46 * 26 Level 2 Interrupt
48 * 27 Level 3 Interrupt
52 * 28 Level 4 Interrupt
57 * 29 Level 5 Interrupt
60 * 30 Level 6 Interrupt
62 * Paula 14: Copper (special)
63 * 31 Level 7 Interrupt
76 extern ULONG M68KFaultTable_00
[];
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
[];
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
[];
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;
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 */
171 for (i
= 0; i
< 16; i
++)
172 exception
[i
+ 32] = &M68KTrapTable_00
[i
];
177 /* For the 68010+, the lower 12 bits of the UWORD
178 * at %sp@(6) contains the vector number.
181 extern void M68KTrapHelper_10(void);
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;
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) */
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)
215 * When we call M68KExceptionAction:
218 * D0-D7/A0-A7 (16 * 4) <= NO TOUCHING!
221 * Exception Vector (4) D0
224 * Drop SysBase, SP, and Exception args
225 * Restore D0-D1/A0-A1/A6
226 * Drop the Exception # word
229 extern void M68KExceptionHelper(void);
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])
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
258 " rts\n" // Execute tc_TrapCode
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,
278 LastAlert
[0] = (LONG
)(AT_DeadEnd
| AN_LibChkSum
);
279 /* LastAlert[1] was already set by
282 LastAlert
[1] = 0; /* No SysBase? No Task. */
286 /* Set LastAlert marker */
287 *(volatile ULONG
*)0 = 0x48454c50; /* 'HELP' */
288 Exec_MagicResetCode();
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
)
305 BOOL (*Handler
)(regs_t
*regs
, int id
, struct ExecBase
*SysBase
);
308 /* vector is really a pointer to a M68KException table entry */
309 struct M68KException
*Exception
;
311 Exception
= (APTR
)(vector
& ~1);
314 Handler
= Exception
->Handler
;
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
);
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
);
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
);
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
);
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 */
379 /* Initialize the Well Known Traps */
380 if (SysBase
->AttnFlags
& AFF_68010
) {
381 M68KExceptionInit_10(SysBase
);
383 M68KExceptionInit_00(SysBase
);
386 if ((ULONG
)Table
& 1) {
387 /* Exception Table must be UWORD aligned! */
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)
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! */