executor/src/executor.c
2009-06-14 20:58:21 -06:00

717 lines
18 KiB
C

/* Copyright 1992-1995 by Abacus Research and
* Development, Inc. All rights reserved.
*/
#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_executor[] =
"$Id: executor.c 88 2005-05-25 03:59:37Z ctm $";
#endif
#define DEBUG
#include "rsys/common.h"
#include "QuickDraw.h"
#include "CQuickDraw.h"
#include "ResourceMgr.h"
#include "SegmentLdr.h"
#include "MemoryMgr.h"
#include "StdFilePkg.h"
#include "EventMgr.h"
#include "VRetraceMgr.h"
#include "OSUtil.h"
#include "FontMgr.h"
#include "ScrapMgr.h"
#include "ToolboxUtil.h"
#include "FileMgr.h"
#include "ControlMgr.h"
#include "DeviceMgr.h"
#include "SoundDvr.h"
#include "PrintMgr.h"
#include "StartMgr.h"
#include "CommTool.h"
#include "rsys/trapglue.h"
#include "rsys/cquick.h"
#include "rsys/file.h"
#include "rsys/next.h"
#include "rsys/soundopts.h"
#include "rsys/pstuff.h"
#include "rsys/jumpvectors.h"
#include "rsys/prefs.h"
#include "rsys/aboutpanel.h"
#include "rsys/segment.h"
#include "rsys/misc.h"
#include "rsys/host.h"
#include "rsys/executor.h"
#include "rsys/hfs.h"
#include "rsys/float.h"
#include "rsys/vdriver.h"
#include "rsys/trapname.h"
#include "rsys/options.h"
#include "rsys/suffix_maps.h"
#include "rsys/string.h"
#include "rsys/custom.h"
#undef PRIVATE
#define PRIVATE
#define PUBLIC
#define FASTALINETRAPS
/*
* For now the NEXT handles A-line traps differently than on the Sun.
* The NEXT will bypass the A-line and priv instruction dispatches if
* possible (meaning if there's no page fault during the dispatch). If
* not possible, we get here and are expected to force the page fault
* ourselves so we can go back into kernel mode. Pretty bizzare, eh?
*/
#if defined(NEXT) && !defined(SYN68K)
PRIVATE void emthandler(LONGINT wsignal, LONGINT code, struct sigcontext *scp)
{
LONGINT saved2;
volatile LONGINT temp;
static int beenhere = 0;
if (!beenhere) {
ROMlib_load_ardi_mods();
beenhere = 1;
}
asm("movel d2, %0" : "=g" (saved2));
temp = *(volatile LONGINT *) 0x5C; /* will get page 0 and the stack */
asm("movel %0, d2" : : "g" (saved2));
}
#endif /* NEXT && !SYN68K */
LONGINT debugnumber, debugtable[1<<12], cutoff = 20;
#if !defined (MSDOS) && !defined (NDEBUG)
typedef struct
{
unsigned trapno;
int32 when;
} trap_when_t;
static int
compare_trap_when (const void *p1, const void *p2)
{
return ((const trap_when_t *)p1)->when - ((const trap_when_t *) p2)->when;
}
/* Prints out the traps executed within the last NUM_TRAPS_BACK traps. */
void
dump_recent_traps (int num_traps_back)
{
trap_when_t traps[0x1000];
int i, num_interesting_traps;
/* Record all the traps that are recent enough. */
for (i = 0, num_interesting_traps = 0; i < (int) NELEM (traps); i++)
{
int32 when;
when = debugtable[i];
if (when != 0 && when >= debugnumber - num_traps_back)
{
traps[num_interesting_traps].trapno = 0xA000 + i;
traps[num_interesting_traps].when = when;
num_interesting_traps++;
}
}
/* Sort them by time, oldest first. */
qsort (traps, num_interesting_traps, sizeof traps[0], compare_trap_when);
/* Print them out. */
for (i = 0; i < num_interesting_traps; i++)
printf ("0x%04X\t%ld\t%s\n", traps[i].trapno, (long) traps[i].when,
trap_name (traps[i].trapno));
}
#endif /* !MSDOS && !NDEBUG */
#if !defined (NDEBUG)
char trap_watchpoint_data[1024];
char *trap_watchpoint_name[1024];
struct
{
/* pointer to actual memory */
int handle_p;
char *x;
/* pointer to our `orignal' copy */
char *orig;
int size;
} trap_watchpoints[1024];
int trap_watchpoint_next_data;
int trap_watchpoint_next;
/* make a per-trap watchpoint of the data at `x', of size `size' */
void
trap_watch (char *name, void *x, int size)
{
char *trap_data;
if (trap_watchpoint_next == 1024)
{
fprintf (stderr, "all available trap watchpoints used\n");
return;
}
trap_watchpoints[trap_watchpoint_next].size = size;
trap_watchpoints[trap_watchpoint_next].handle_p = FALSE;
trap_watchpoints[trap_watchpoint_next].x = x;
trap_data
= trap_watchpoints[trap_watchpoint_next].orig
= &trap_watchpoint_data[trap_watchpoint_next_data];
trap_watchpoint_next ++;
trap_watchpoint_next_data += size;
memcpy (trap_data, x, size);
}
void
trap_watch_handle (char *name, Handle x, int size)
{
char *trap_data;
if (trap_watchpoint_next == 1024)
{
fprintf (stderr, "all available trap watchpoints used\n");
return;
}
trap_watchpoints[trap_watchpoint_next].size = size;
trap_watchpoints[trap_watchpoint_next].handle_p = TRUE;
trap_watchpoints[trap_watchpoint_next].x = (void *) x;
trap_data
= trap_watchpoints[trap_watchpoint_next].orig
= &trap_watchpoint_data[trap_watchpoint_next_data];
trap_watchpoint_next ++;
trap_watchpoint_next_data += size;
memcpy (trap_data, STARH ((Handle) x), size);
}
void
trap_break_me (void)
{
}
void
trap_dump_bits (char *msg, char *data, int size)
{
int i;
fprintf (stderr, "%s: ", msg);
for (i = 0; i < size; i ++)
fprintf (stderr, "%x%x",
(int) ((data[i] >> 4) & 0xF),
(int) (data[i] & 0xF));
fprintf (stderr, "\n");
}
int check_trap_watchpoints_p = FALSE;
void
check_trap_watchpoints (char *msg)
{
int size, i;
for (i = 0; i < 1024; i ++)
{
if (trap_watchpoints[i].x)
{
void *x;
x = (trap_watchpoints[i].handle_p
? (void *) STARH ((Handle) trap_watchpoints[i].x)
: trap_watchpoints[i].x);
size = trap_watchpoints[i].size;
if (memcmp (x, trap_watchpoints[i].orig,
size))
{
/* differs */
fprintf (stderr, "%s", msg);
trap_dump_bits ("old", trap_watchpoints[i].orig, size);
trap_dump_bits ("new", x, size);
memcpy (trap_watchpoints[i].orig, x, size);
trap_break_me ();
}
}
}
}
#endif /* !NDEBUG */
PRIVATE void setup28( void )
{
#if defined (NEXT) && !defined (SYN68K)
#if 1
static LONGINT trap_dispatcher_callback = -1;
if (trap_dispatcher_callback == -1)
trap_dispatcher_callback = callback_install (aline_stub, NULL);
*(LONGINT *) 0x28 = trap_dispatcher_callback;
#else
*(LONGINT *) 0x28 = (LONGINT) trapdispatcher;
#endif
*(LONGINT *) 0x20 = (LONGINT) privdispatcher;
*(LONGINT *) 0x5C = (LONGINT) T('A','R','D','I');
#endif /* NEXT && !SYN68K */
}
PUBLIC void setupsignals( void )
{
#if defined (NEXT)
LONGINT tocatch[] = {
SIGHUP,
SIGINT,
SIGQUIT,
SIGILL,
SIGTRAP,
SIGIOT,
SIGEMT,
SIGFPE,
SIGBUS,
SIGSEGV,
SIGSYS,
SIGPIPE,
SIGTERM,
SIGXCPU,
SIGXFSZ,
SIGVTALRM,
SIGPROF,
SIGUSR1,
SIGUSR2,
0
}, *tocatchp;
#endif /* NEXT */
#if !defined (FASTALINETRAPS) || defined (NEXT)
#if defined(USE_BSD_SIGNALS)
typedef struct sigvec sigvec_t;
typedef struct sigstack sigstack_t;
#endif
#endif /* FASTALINETRAPS || NEXT */
#if (!defined (FASTALINETRAPS) || defined (NEXT)) && !defined (SYN68K)
{
sigstack_t sigstackarg;
sigvec_t sigvecarg;
static char signalstack[3*1024];
sigstackarg.ss_sp = signalstack + sizeof(signalstack);
sigstackarg.ss_onstack = 0;
sigstack(&sigstackarg, (sigstack_t *) 0);
sigvecarg.sv_handler = (void *) emthandler;
sigvecarg.sv_mask = 0;
sigvecarg.sv_flags = SV_ONSTACK;
sigvec(SIGEMT, &sigvecarg, (sigvec_t *) 0);
}
#endif /* (FASTALINETRAPS || NEXT) && !SYN68K */
setup28();
}
#define TOOLMASK (0x3FF)
#define OSMASK (0xFF)
#define DONTSAVEA0BIT (0x100)
#define POPBIT (0x400)
#define LOADSEGTRAPWORD (0xA9F0)
#define EXITTOSHELLTRAPWORD (0xA9F4)
enum { MODESWITCHTRAPWORD = 0xaafe };
#define ALINEEXCEPTIONFRAMESIZE 8
#define WEIRDMAGIC (0x1F52)
/*
* FAKEPascalToCCall pushes a phoney return address and then calls
* PascalToCCall and throws away the return value. It will be something
* like:
*
*/
#define FAKEPascalToCCall(xxx) \
do {PUSHADDR(0xEACE4321); (void) PascalToCCall(0x87654231, xxx); } while (0)
unsigned short mostrecenttrap;
/* #define MEMORY_WATCH */
#include "rsys/mman_private.h"
#if defined (MEMORY_WATCH)
int memory_watch = 0;
PRIVATE void
dump_difference (uint16 trapn, int i,
zone_info_t *currentp, const zone_info_t *newp)
{
fprintf (stderr, "%d %s(%d): D#rel = %d, D#nrel = %d, D#free = %d, Dtotal = %d\n",
debugnumber, trap_name (trapn), i, newp->n_rel - currentp->n_rel,
newp->n_nrel - currentp->n_nrel, newp->n_free - currentp->n_free,
newp->total_free - currentp->total_free);
*currentp = *newp;
}
PRIVATE void
compare_zone_infos (uint16 trapn, zone_info_t current[3], zone_info_t new[3])
{
int i;
for (i = 0; i < 2; ++i)
{
if ((ABS (current[i].n_rel - new[i].n_rel ) > 2) ||
(ABS (current[i].n_nrel - new[i].n_nrel) > 2) ||
(ABS (current[i].total_free - new[i].total_free) > 12 * 1024))
dump_difference (trapn, i, &current[i], &new[i]);
}
}
#endif
PUBLIC syn68k_addr_t alinehandler(syn68k_addr_t pc, void *ignored)
{
syn68k_addr_t retval;
unsigned short trapno, status;
uint32 savea0, savea1, savea2, saved1, saved2;
unsigned short trapword;
void *togoto; /* FIXME: really a syn68k_addr_t */
#if defined (MEMORY_WATCH)
zone_info_t current_zone_infos[3];
zone_info_t new_zone_infos[3];
#endif
#if defined (MEMORY_WATCH)
if (memory_watch)
{
ROMlib_sledgehammer_zones (__PRETTY_FUNCTION__, __FILE__, __LINE__,
"after aline", current_zone_infos);
}
#endif
mostrecenttrap = trapword = READUW(pc);
retval = pc + 2;
#if !defined (NDEBUG)
if (check_trap_watchpoints_p)
check_trap_watchpoints ("entering `alinehandler ()'\n");
#endif
/*
* Code for debugging
*/
#if !defined (NDEBUG)
debugtable[trapword&0xFFF] = ++debugnumber;
#endif /* !NDEBUG */
#if 0
warning_trace_info ("in trapword = 0x%x, pc = 0x%x", trapword, pc);
#endif
status = READUW(EM_A7);
EM_A7 += ALINEEXCEPTIONFRAMESIZE;
if (trapword & TOOLBIT) {
trapno = trapword & TOOLMASK;
togoto = tooltraptable[trapno];
if (trapword & POPBIT)
retval = POPADDR();
if (togoto == toolstuff[trapno].orig) {
if (toolstuff[trapno].ptoc.magic == (ULONGINT) -1) {
syn68k_addr_t new_addr;
PUSHADDR(0x80014321); /* better not use this */
new_addr =
(*(callback_handler_t)toolstuff[trapno].ptoc.wheretogo)
(pc, (void *) 0);
if (trapword == LOADSEGTRAPWORD)
retval -= 6;
else if (trapword == MODESWITCHTRAPWORD)
retval = new_addr;
} else
FAKEPascalToCCall(&toolstuff[trapno].ptoc);
} else {
PUSHADDR(retval); /* Where they'll return to */
retval = (syn68k_addr_t) togoto; /* Where they have patched */
/* us to go to */
}
} else {
trapno = trapword & OSMASK;
togoto = ostraptable[trapno];
if (togoto == osstuff[trapno].orig) {
saved1 = EM_D1;
saved2 = EM_D2;
savea1 = EM_A1;
savea2 = EM_A2;
EM_D1 = trapword;
EM_D2 = (trapword & 0xFF) << 2;
EM_A2 = (LONGINT) togoto;
savea0 = EM_A0;
PUSHADDR(0x88A84321); /* better not use this */
(*(callback_handler_t)osstuff[trapno].func)(pc,
callback_argument((syn68k_addr_t) togoto));
if (!(trapword & DONTSAVEA0BIT))
EM_A0 = savea0;
EM_D1 = saved1;
EM_D2 = saved2;
EM_A1 = savea1;
EM_A2 = savea2;
} else {
PUSHADDR(retval);
PUSHUW(status);
PUSHUW(WEIRDMAGIC);
PUSHUL(EM_A2);
PUSHUL(EM_D2);
PUSHUL(EM_D1);
PUSHUL(EM_A1);
EM_D1 = trapword;
EM_D2 = (trapword & 0xFF) << 2;
EM_A2 = (LONGINT) togoto;
if (!(trapword & DONTSAVEA0BIT))
PUSHUL(EM_A0);
CALL_EMULATOR((syn68k_addr_t) togoto);
if (!(trapword & DONTSAVEA0BIT))
EM_A0 = POPUL();
EM_A1 = POPUL();
EM_D1 = POPUL();
EM_D2 = POPUL();
EM_A2 = POPUL();
EM_A7 += 4;
retval = POPADDR();
}
cpu_state.ccc = 0;
cpu_state.ccn = (cpu_state.regs[0].sw.n < 0);
cpu_state.ccv = 0;
cpu_state.ccx = cpu_state.ccx; /* unchanged */
cpu_state.ccnz = (cpu_state.regs[0].sw.n != 0);
}
#if defined (MEMORY_WATCH)
if (memory_watch)
{
ROMlib_sledgehammer_zones (__PRETTY_FUNCTION__, __FILE__, __LINE__,
"after aline", new_zone_infos);
compare_zone_infos (trapword, current_zone_infos, new_zone_infos);
}
#endif
#if !defined (NDEBUG)
if (check_trap_watchpoints_p)
check_trap_watchpoints ("exiting `alinehandler ()'\n");
#endif
#if 0
warning_trace_info ("out retval = 0x%x", retval);
#endif
return retval;
}
PUBLIC void executor_main( void )
{
char quickbytes[grafSize];
LONGINT tmpA5;
INTEGER mess, count, exevrefnum, toskip; AppFile thefile;
Byte *p;
int i;
WDPBRec wdpb;
CInfoPBRec hpb;
Str255 name;
StringPtr fName;
SCSIFlags = CWC (0xEC00); /* scsi+clock+xparam+mmu+adb
(no fpu,aux or pwrmgr) */
MCLKPCmiss1 = 0; /* &MCLKPCmiss1 = 0x358 + 72 (MacLinkPC starts
adding the 72 byte offset to VCB pointers too
soon, starting with 0x358, which is not the
address of a VCB) */
MCLKPCmiss2 = 0; /* &MCLKPCmiss1 = 0x358 + 78 (MacLinkPC misses) */
AuxCtlHead = 0;
CurDeactive = 0;
CurActivate = 0;
macfpstate[0] = 0;
fondid = 0;
PrintErr = 0;
mouseoffset = 0;
heapcheck = 0;
DefltStack = CLC(0x2000); /* nobody really cares about these two */
MinStack = CLC(0x400); /* values ... */
IAZNotify = 0;
CurPitch = 0;
JSwapFont = (ProcPtr) RM(P_FMSwapFont);
JInitCrsr = (ProcPtr) RM(P_InitCursor);
Key1Trans = (Ptr) RM(P_Key1Trans);
Key2Trans = (Ptr) RM(P_Key2Trans);
JFLUSH = (ProcPtr) RM(P_flushcache);
JResUnknown1 = JFLUSH; /* I don't know what these are supposed to */
JResUnknown2 = JFLUSH; /* do, but they're not called enough for
us to worry about the cache flushing
overhead */
#if !defined (NEXT) && !defined (SYN68K)
CPUFlag = 2; /* mc68020 */
#else /* NEXT || SYN68K */
CPUFlag = 4; /* mc68040 */
#endif /* NEXT || SYN68K */
UnitNtryCnt = 0; /* how many units in the table */
TheZone = SysZone;
VIA = RM(NewPtr(16 * 512)); /* IMIII-43 */
memset(MR(VIA), 0, (LONGINT) 16 * 512);
*(char *)MR(VIA) = 0x80; /* Sound Off */
#define SCC_SIZE 1024
SCCRd_H.p = RM(NewPtrSysClear (SCC_SIZE));
SCCWr_H.p = RM(NewPtrSysClear (SCC_SIZE));
setup28();
SoundBase = RM(NewPtr(370 * sizeof(INTEGER)));
#if 0
memset(CL(SoundBase), 0, (LONGINT) 370 * sizeof(INTEGER));
#else /* !0 */
for (i = 0; i < 370; ++i)
((INTEGER *) MR(SoundBase))[i] = CWC (0x8000); /* reference 0 sound */
#endif /* !0 */
TheZone = ApplZone;
HiliteMode = CB(0xFF);
/* Mac II has 0x3FFF here */
ROM85 = CWC(0x3FFF);
a5 = US_TO_SYN68K((LONGINT) &tmpA5);
CurrentA5 = (Ptr) CL(a5);
InitGraf((Ptr) quickbytes + sizeof(quickbytes) - 4);
InitFonts();
InitCRM ();
FlushEvents( everyEvent, 0 );
InitWindows();
TEInit();
InitDialogs((ProcPtr)0);
InitCursor();
loadtrap = 0;
#if defined (MSDOS)
ROMlib_WriteWhen(WriteInBltrgn);
#endif /* MSDOS */
/* ROMlib_WriteWhen(WriteInOSEvent); */
FinderName[0] = MIN(strlen(BROWSER_NAME), sizeof(FinderName)-1);
memcpy(FinderName+1, BROWSER_NAME, FinderName[0]);
CountAppFiles(&mess, &count);
count = CW (count);
if (count > 0)
GetAppFiles(1, &thefile);
else
thefile.fType = 0;
#if defined (DISPLAY_SPLASH_SCREEN)
/* Reset the CLUT since it may have gotten changed by the splash screen. */
gd_set_bpp (MR (MainDevice), !vdriver_grayscale_p, vdriver_fixed_clut_p,
vdriver_bpp);
#endif /* DISPLAY_SPLASH_SCREEN */
#if defined (SYN68K)
#define ALINETRAPNUMBER 0xA
trap_install_handler( ALINETRAPNUMBER, alinehandler, (void *) 0);
#endif
if (thefile.fType == CLC(T('A','P','P','L')))
{
ClrAppFiles(1);
Munger(MR(AppParmHandle), 2L*sizeof(INTEGER), (Ptr) 0,
(LONGINT) sizeof(AppFile), (Ptr) "", 0L);
}
hpb.hFileInfo.ioNamePtr = RM(&thefile.fName[0]);
hpb.hFileInfo.ioVRefNum = thefile.vRefNum;
hpb.hFileInfo.ioFDirIndex = CWC (0);
hpb.hFileInfo.ioDirID = CLC (0);
PBGetCatInfo(&hpb, FALSE);
if (thefile.fType == CLC(T('A','P','P','L')))
fName = thefile.fName;
else
{
const char *p;
if (count > 0)
{
p = ROMlib_find_best_creator_type_match
(CL (hpb.hFileInfo.ioFlFndrInfo.fdCreator),
CL (hpb.hFileInfo.ioFlFndrInfo.fdType));
}
else
{
if (!ROMlib_default_appp)
p = NULL;
else
p = (char *) ROMlib_default_appp->chars;
}
fName = name;
if (!p)
ExitToShell ();
else
{
ROMlib_exit = TRUE;
str255_from_c_string (fName, p);
hpb.hFileInfo.ioNamePtr = RM(fName);
hpb.hFileInfo.ioVRefNum = CWC (0);
hpb.hFileInfo.ioFDirIndex = CWC (0);
hpb.hFileInfo.ioDirID = CLC (0);
PBGetCatInfo(&hpb, FALSE);
{
HParamBlockRec hp;
Str255 fName2;
memset (&hp, 0, sizeof hp);
str255assign (fName2, fName);
hp.ioParam.ioNamePtr = RM ((StringPtr) fName2);
hp.volumeParam.ioVolIndex = CWC (-1);
PBHGetVInfo (&hp, FALSE);
hpb.hFileInfo.ioVRefNum = hp.ioParam.ioVRefNum;
}
}
}
for (p = fName + fName[0] + 1;
p > fName && *--p != ':';)
;
toskip = p - fName;
CurApName[0] = MIN(fName[0]-toskip, 31);
BlockMove((Ptr) fName+1+toskip, (Ptr) CurApName+1,
(Size) CurApName[0]);
wdpb.ioVRefNum = hpb.hFileInfo.ioVRefNum;
wdpb.ioWDDirID = hpb.hFileInfo.ioFlParID;
SFSaveDisk_Update (CW (hpb.hFileInfo.ioVRefNum), fName);
CurDirStore = hpb.hFileInfo.ioFlParID;
wdpb.ioWDProcID = CLC (T('X','c','t','r'));
wdpb.ioNamePtr = 0;
PBOpenWD(&wdpb, FALSE);
exevrefnum = CW(wdpb.ioVRefNum);
Launch (CurApName, exevrefnum);
}