|
|
1.1 root 1: /*
2: * E-UAE - The portable Amiga Emulator
3: *
4: * Support for traps
5: *
6: * Copyright Richard Drummond 2005
7: *
8: * Inspired by code from UAE:
9: * Copyright 1995, 1996 Bernd Schmidt
10: * Copyright 1996 Ed Hanway
11: */
12:
13: #include "sysconfig.h"
14: #include "sysdeps.h"
15:
16: #include "options.h"
17: #include "memory.h"
18: #include "custom.h"
19: #include "newcpu.h"
20: #include "threaddep/thread.h"
21: #include "autoconf.h"
22: #include "traps.h"
23:
24: /* We'll need a lot of these. */
25: #define MAX_TRAPS 4096
26: static TrapFunction traps[MAX_TRAPS];
27: static int trapmode[MAX_TRAPS];
28: static const char *trapstr[MAX_TRAPS];
29: static uaecptr trapoldfunc[MAX_TRAPS];
30:
31: static int max_trap = 0;
32:
33: /* Stack management */
34:
35: /* The mechanism for doing m68k calls from native code is as follows:
36: *
37: * m68k code executes, stack is main
38: * calltrap to execute_fn_on_extra_stack. new stack is allocated
39: * do_stack_magic is called for the first time
40: * current context is saved with setjmp [0]
41: * transfer_control is done
42: * native code executes on new stack
43: * native code calls call_m68k
44: * setjmp saves current context [1]
45: * longjmp back to execute_fn_on_extra_stack [0]
46: * pointer to new stack is saved on m68k stack. m68k return address set
47: * to RTAREA_BASE + 0xFF00. m68k PC set to called function
48: * m68k function executes, stack is main
49: * m68k function returns to RTAREA_BASE + 0xFF00
50: * calltrap to m68k_mode_return
51: * do_stack_magic is called again
52: * current context is saved again with setjmp [0]
53: * this time, transfer_control is _not_ done, instead a longjmp[1]
54: * to the previously saved context
55: * native code executes again on temp stack
56: * native function returns to stack_stub
57: * longjmp[0] back to old context
58: * back again!
59: *
60: * A bearded man enters the room, carrying a bowl of spaghetti.
61: */
62:
63: /* This _shouldn't_ crash with a stack size of 4096, but it does...
64: * might be a bug */
65: #ifndef EXTRA_STACK_SIZE
66: #define EXTRA_STACK_SIZE 65536
67: #endif
68:
69: static void *extra_stack_list = NULL;
70:
71: static void *get_extra_stack (void)
72: {
73: void *s = extra_stack_list;
74: if (s)
75: extra_stack_list = *(void **)s;
76: if (!s)
77: s = xmalloc (EXTRA_STACK_SIZE);
78: return s;
79: }
80:
81: static void free_extra_stack (void *s)
82: {
83: *(void **)s = extra_stack_list;
84: extra_stack_list = s;
85: }
86:
87: static void stack_stub (void *s, TrapFunction f, uae_u32 *retval)
88: {
89: #ifdef CAN_DO_STACK_MAGIC
90: /*printf("in stack_stub: %p %p %p %x\n", s, f, retval, (int)*retval);*/
91: *retval = f ();
92: /*write_log ("returning from stack_stub\n");*/
93: longjmp (((jmp_buf *)s)[0], 1);
94: #endif
95: }
96:
97: static void *current_extra_stack = NULL;
98: static uaecptr m68k_calladdr;
99:
100: static void do_stack_magic (TrapFunction f, void *s, int has_retval)
101: {
102: #ifdef CAN_DO_STACK_MAGIC
103: uaecptr a7;
104: jmp_buf *j = (jmp_buf *)s;
105: switch (setjmp (j[0])) {
106: case 0:
107: /* Returning directly */
108: current_extra_stack = s;
109: if (has_retval == -1) {
110: /*write_log ("finishing m68k mode return\n");*/
111: longjmp (j[1], 1);
112: }
113: /*write_log ("calling native function\n");*/
114: transfer_control (s, EXTRA_STACK_SIZE, stack_stub, f, has_retval);
115: /* not reached */
116: abort ();
117:
118: case 1:
119: /*write_log ("native function complete\n");*/
120: /* Returning normally. */
121: if (stack_has_retval (s, EXTRA_STACK_SIZE))
122: m68k_dreg (regs, 0) = get_retval_from_stack (s, EXTRA_STACK_SIZE);
123: free_extra_stack (s);
124: break;
125:
126: case 2:
127: /* Returning to do a m68k call. We're now back on the main stack. */
128: a7 = m68k_areg(regs, 7) -= (sizeof (void *) + 7) & ~3;
129: /* Save stack to restore */
130: *((void **)get_real_address (a7 + 4)) = s;
131: /* Save special return address: this address contains a
132: * calltrap that will longjmp to the right stack. */
133: put_long (m68k_areg (regs, 7), RTAREA_BASE + 0xFF00);
134: m68k_setpc (m68k_calladdr);
135: fill_prefetch_slow ();
136: /*write_log ("native function calls m68k\n");*/
137: break;
138: }
139: current_extra_stack = 0;
140: #endif
141: }
142:
143: static uae_u32 execute_fn_on_extra_stack (TrapFunction f, int has_retval)
144: {
145: #ifdef CAN_DO_STACK_MAGIC
146: void *s = get_extra_stack ();
147: do_stack_magic (f, s, has_retval);
148: #endif
149: return 0;
150: }
151:
152: uae_u32 m68k_mode_return (void)
153: {
154: #ifdef CAN_DO_STACK_MAGIC
155: uaecptr a7 = m68k_areg(regs, 7);
156: void *s = *(void **)get_real_address(a7);
157: m68k_areg(regs, 7) += (sizeof (void *) + 3) & ~3;
158: /*write_log ("doing m68k mode return\n");*/
159: do_stack_magic (NULL, s, -1);
160: #endif
161: return 0;
162: }
163:
164: static uae_u32 call_m68k (uaecptr addr, int saveregs)
165: {
166: volatile uae_u32 retval = 0;
167: volatile int do_save = saveregs;
168: if (current_extra_stack == NULL)
169: abort();
170: #ifdef CAN_DO_STACK_MAGIC
171: {
172: volatile struct regstruct saved_regs;
173: jmp_buf *j = (jmp_buf *)current_extra_stack;
174:
175: if (do_save)
176: saved_regs = regs;
177: m68k_calladdr = addr;
178: switch (setjmp(j[1])) {
179: case 0:
180: /*write_log ("doing call\n");*/
181: /* Returning directly: now switch to main stack and do the call */
182: longjmp (j[0], 2);
183: case 1:
184: /*write_log ("returning from call\n");*/
185: retval = m68k_dreg (regs, 0);
186: if (do_save)
187: regs = saved_regs;
188: /* Returning after the call. */
189: break;
190: }
191: }
192: #endif
193: return retval;
194: }
195:
196: uae_u32 CallLib (uaecptr base, uae_s16 offset)
197: {
198: int i;
199: uaecptr olda6 = m68k_areg(regs, 6);
200: uae_u32 retval;
201: #if 0
202: for (i = 0; i < n_libpatches; i++) {
203: if (libpatches[i].libbase == base && libpatches[i].functions[-offset/6] != NULL)
204: return (*libpatches[i].functions[-offset/6])();
205: }
206: #endif
207: m68k_areg(regs, 6) = base;
208: retval = call_m68k(base + offset, 1);
209: m68k_areg(regs, 6) = olda6;
210: return retval;
211: }
212:
213: static int trace_traps = 1;
214:
215: void REGPARAM2 call_calltrap(int func)
216: {
217: uae_u32 retval = 0;
218: int has_retval = (trapmode[func] & TRAPFLAG_NO_RETVAL) == 0;
219: int implicit_rts = (trapmode[func] & TRAPFLAG_DORET) != 0;
220:
221: if (*trapstr[func] != 0 && trace_traps)
222: write_log ("TRAP: %s\n", trapstr[func]);
223:
224: /* For monitoring only? */
225: if (traps[func] == NULL) {
226: m68k_setpc(trapoldfunc[func]);
227: fill_prefetch_slow ();
228: return;
229: }
230:
231: if (func < max_trap) {
232: if (trapmode[func] & TRAPFLAG_EXTRA_STACK) {
233: execute_fn_on_extra_stack(traps[func], has_retval);
234: return;
235: }
236: retval = (*traps[func])();
237: } else
238: write_log ("illegal emulator trap\n");
239:
240: if (has_retval)
241: m68k_dreg(regs, 0) = retval;
242: if (implicit_rts) {
243: m68k_do_rts ();
244: fill_prefetch_slow ();
245: }
246: }
247:
248: static volatile int four = 4;
249: uaecptr libemu_InstallFunctionFlags (TrapFunction f, uaecptr libbase, int offset,
250: int flags, const char *tracename)
251: {
252: int i;
253: uaecptr retval;
254: uaecptr execbase = get_long (four);
255: int trnum;
256: uaecptr addr = here();
257: calltrap (trnum = deftrap2 (f, flags, tracename));
258: dw (RTS);
259:
260: m68k_areg(regs, 1) = libbase;
261: m68k_areg(regs, 0) = offset;
262: m68k_dreg(regs, 0) = addr;
263: retval = CallLib (execbase, -420);
264:
265: trapoldfunc[trnum] = retval;
266: #if 0
267: for (i = 0; i < n_libpatches; i++) {
268: if (libpatches[i].libbase == libbase)
269: break;
270: }
271: if (i == n_libpatches) {
272: int j;
273: libpatches[i].libbase = libbase;
274: for (j = 0; j < 300; j++)
275: libpatches[i].functions[j] = NULL;
276: n_libpatches++;
277: }
278: libpatches[i].functions[-offset/6] = f;
279: #endif
280: return retval;
281: }
282:
283: int deftrap2 (TrapFunction func, int mode, const char *str)
284: {
285: int num = max_trap++;
286: traps[num] = func;
287: trapstr[num] = str;
288: trapmode[num] = mode;
289: return num;
290: }
291:
292: int deftrap (TrapFunction func)
293: {
294: return deftrap2 (func, 0, "");
295: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.