|
|
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.