diff --git a/TheIcon b/TheIcon new file mode 100644 index 0000000..e69de29 diff --git a/TheIcon.rdump b/TheIcon.rdump new file mode 100644 index 0000000..9cc2ef4 --- /dev/null +++ b/TheIcon.rdump @@ -0,0 +1,30 @@ +data 'ICN#' (128) { + $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */ + $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */ + $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */ + $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */ + $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */ + $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */ + $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */ + $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */ + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */ + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */ + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */ + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */ + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */ + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */ + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */ + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */ +}; + +data 'ICON' (128) { + $"7FFF FFFE 8000 0001 8000 0001 8000 0001" /* ................ */ + $"8000 0001 8000 0001 8C00 0001 8000 2801" /* ..............(. */ + $"8000 2801 7FFF 7DFE 0000 4400 0000 4400" /* ..(...}...D...D. */ + $"0000 7C00 0000 5400 BFFF 93FD 0000 2800" /* ..|...T.......(. */ + $"BFFF C7FD 0000 0000 0000 0000 0000 0000" /* ................ */ + $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */ + $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */ + $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */ +}; + diff --git a/romdrv 0.9.6/CDEV.rsrc b/romdrv 0.9.6/CDEV.rsrc new file mode 100644 index 0000000..e69de29 diff --git a/romdrv 0.9.6/ROMDisk b/romdrv 0.9.6/ROMDisk new file mode 100644 index 0000000..e69de29 diff --git a/romdrv 0.9.6/RomDiskCP b/romdrv 0.9.6/RomDiskCP new file mode 100644 index 0000000..e69de29 diff --git a/romdrv 0.9.6/RomDiskCP.SYM b/romdrv 0.9.6/RomDiskCP.SYM new file mode 100644 index 0000000..2e36aae Binary files /dev/null and b/romdrv 0.9.6/RomDiskCP.SYM differ diff --git a/romdrv 0.9.6/RomDiskCP.c b/romdrv 0.9.6/RomDiskCP.c new file mode 100644 index 0000000..4b6f97a --- /dev/null +++ b/romdrv 0.9.6/RomDiskCP.c @@ -0,0 +1 @@ +#include #include #define kOnButton 2 #define kOffButton 3 #define kRAMButton 6 #define kROMButton 7 #pragma parameter __D0 ReadXPRam(__D0, __D1, __A0) short ReadXPRam(short size, short offset, char *where) = {0x4840, 0x3001, _ReadXPRam}; #pragma parameter __D0 WriteXPRam(__D0, __D1, __A0) short WriteXPRam(short size, short offset, char *where) = {0x4840, 0x3001, _WriteXPRam}; void updateDisplay(DialogPtr d, short numItems, char startup, char ram, char grayed); void updateDisplay(DialogPtr d, short numItems, char startup, char ram, char grayed) { GrafPtr savePort; Handle h; Rect r; short type; GetPort(&savePort); SetPort(d); GetDItem(d, kOnButton+numItems, &type, &h, &r); SetCtlValue((ControlHandle)h, startup); GetDItem(d, kOffButton+numItems, &type, &h, &r); SetCtlValue((ControlHandle)h, !startup); GetDItem(d, kRAMButton+numItems, &type, &h, &r); SetCtlValue((ControlHandle)h, ram); GetDItem(d, kROMButton+numItems, &type, &h, &r); SetCtlValue((ControlHandle)h, !ram); SetPort(savePort); return; } pascal long main(short message,short item,short numItems,short /*privateValue*/, EventRecord *e, void *cdev, DialogPtr d) { EnterCodeResource(); long result; Handle h; Rect r; short type; GrafPtr savePort; unsigned char **via1ptr = (unsigned char**)0x01D4; unsigned char data, dir; char startup = 0; char ram = 0; result = (long)cdev; switch (message) { case initDev: cdev = (Handle)cdevUnset; ReadXPRam(1, 4, &startup); ReadXPRam(1, 5, &ram); result = (long)cdev; break; case closeDev: cdev = (Handle)cdevUnset; result = cdevUnset; break; case macDev: result = 1L; break; case updateDev: case activDev: ReadXPRam(1, 4, &startup); ReadXPRam(1, 5, &ram); updateDisplay(d, numItems, startup, ram, 0); break; case deactivDev: ReadXPRam(1, 4, &startup); ReadXPRam(1, 5, &ram); updateDisplay(d, numItems, startup, ram, 1); break; case hitDev: ReadXPRam(1, 4, &startup); ReadXPRam(1, 5, &ram); switch(item-numItems) { case kOnButton: startup = 1; break; case kOffButton: startup = 0; break; case kRAMButton: ram = 1; break; case kROMButton: ram = 0; break; default: break; }; updateDisplay(d, numItems, startup, ram, 0); WriteXPRam(1, 4, &startup); WriteXPRam(1, 5, &ram); break; default: break; }; ExitCodeResource(); return result; } \ No newline at end of file diff --git a/romdrv 0.9.6/RomDiskCP.proj b/romdrv 0.9.6/RomDiskCP.proj new file mode 100644 index 0000000..4183eb9 Binary files /dev/null and b/romdrv 0.9.6/RomDiskCP.proj differ diff --git a/romdrv 0.9.6/netBOOT b/romdrv 0.9.6/netBOOT new file mode 100644 index 0000000..e69de29 diff --git a/romdrv 0.9.6/romdrv b/romdrv 0.9.6/romdrv new file mode 100644 index 0000000..3c67a61 Binary files /dev/null and b/romdrv 0.9.6/romdrv differ diff --git a/romdrv 0.9.6/romdrv inrom b/romdrv 0.9.6/romdrv inrom new file mode 100644 index 0000000..c021a3d Binary files /dev/null and b/romdrv 0.9.6/romdrv inrom differ diff --git a/romdrv 0.9.6/romdrv.c b/romdrv 0.9.6/romdrv.c new file mode 100644 index 0000000..afc7a37 --- /dev/null +++ b/romdrv 0.9.6/romdrv.c @@ -0,0 +1 @@ +#include #include #include #include #include #include #include #define NEED_DRVSTAT 1 #define NEED_ACCRUN 1 /* If NEED_ACCRUN is set, the dNeedTime (0x60) flag should be set in the header, and the * delayticks field in the header should be set to something sensible. */ //#define kRomDrvSize ((long)(524288L)) //#define kRomDrvSize ((long)(0x00700000L)) //#define kRomDrvLocation 0x40880000 unsigned long kRomDrvSize = 0x00780000L; Ptr kRomDrvLocation = (Ptr)0x40880000; Ptr* BufPtr = (Ptr*)0x10C; Ptr* MemTop = (Ptr*)0x108; #pragma parameter __D0 ReadXPRam(__D0, __D1, __A0) short ReadXPRam(short size, short offset, char *where) = {0x4840, 0x3001, _ReadXPRam}; typedef void (*RomDrvCopyFunc)(unsigned char *, unsigned char *, unsigned long); struct RomDrvContext { DrvSts2 drvsts; Ptr origcopyfunc; Ptr origdisk; /* keep unstripped pointers for Dispose*/ RomDrvCopyFunc copyfunc; unsigned char * disk; char initialized; char useram; char ram24; char alreadyalloced; }; typedef struct RomDrvContext RomDrvContext; const unsigned char DiskIcon[258] = { 0xf, 0xff, 0xff, 0xe0, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x11, 0xff, 0xff, 0x10, 0x12, 0x1, 0x00, 0x90, 0x12, 0x00, 0x81, 0x90, 0x12, 0x00, 0x7e, 0x90, 0x12, 0x11, 0x3c, 0x90, 0x12, 0x11, 0x3c, 0x90, 0x12, 0x1, 0x18, 0x90, 0x12, 0x1, 0x00, 0x90, 0x12, 0x3, 0x00, 0x90, 0x12, 0x00, 0x00, 0x90, 0x12, 0x8, 0x40, 0x90, 0x12, 0x7, 0x80, 0x90, 0x12, 0x00, 0x00, 0x90, 0x12, 0x00, 0x00, 0x90, 0x11, 0xff, 0xff, 0x10, 0x10, 0x00, 0x00, 0x10, 0x8, 0x00, 0x00, 0x20, 0x3f, 0xff, 0xff, 0xf8, 0x20, 0x00, 0x00, 0x8, 0x2f, 0xff, 0xff, 0xe8, 0x20, 0x00, 0x00, 0x8, 0x2f, 0xff, 0xff, 0xe8, 0x20, 0x00, 0x00, 0x8, 0x20, 0x00, 0x00, 0x8, 0x20, 0x00, 0xf, 0xe8, 0x2c, 0x00, 0x00, 0x8, 0x20, 0x00, 0x00, 0x68, 0x20, 0x00, 0x00, 0x8, 0x3f, 0xff, 0xff, 0xf8, // mask 0xf, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0xf, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0, 0}; /* AddDrive is declared in Files.h, but it's defined in MacOS.lib, which we don't want, * so just shortcut the whole thing here. */ asm void RomDrvAddDrive(short drvrRefNum, short drvNum, DrvQElPtr dq) { fralloc + CLR.L D0 MOVE.W drvNum, D0 SWAP D0 MOVE.W drvrRefNum, D0 MOVEA.L dq, A0 0xA04E frfree RTS } #pragma parameter __D0 RomDrvStripAddress(__D0) pascal Ptr RomDrvStripAddress(void *addr) = 0xA055; void RomDrvCopy(unsigned char *source, unsigned char *dest, unsigned long count) { signed char mode = true32b; SwapMMUMode(&mode); BlockMove(source, dest, count); SwapMMUMode(&mode); } short RomDrvOpen(IOParamPtr p, DCtlPtr d) { DrvSts2 *dsptr; DrvQElPtr dq; int drvnum = 1; RomDrvContext *ctx; for(dq = (DrvQElPtr)(GetDrvQHdr())->qHead; dq; dq = (DrvQElPtr)dq->qLink) { if(dq->dQDrive >= drvnum) drvnum = dq->dQDrive+1; } d->dCtlStorage = NewHandleSysClear(sizeof(RomDrvContext)); HLock(d->dCtlStorage); ctx = *(RomDrvContext**)d->dCtlStorage; ctx->origcopyfunc = NewPtrSys(64); if(!ctx->origcopyfunc) { SysBeep(8); return openErr; } BlockMove(&RomDrvCopy, ctx->origcopyfunc, 64); ctx->copyfunc = (RomDrvCopyFunc)RomDrvStripAddress(ctx->origcopyfunc); dsptr = &ctx->drvsts; dsptr->writeProt = 0xF0; dsptr->diskInPlace = 8; dsptr->dQDrive = drvnum; dsptr->dQRefNum = d->dCtlRefNum; dsptr->driveSize = (kRomDrvSize/512L) & 0xFFFF; dsptr->driveS1 = ((kRomDrvSize/512L) & 0xFFFF0000) >> 16; RomDrvAddDrive(dsptr->dQRefNum, drvnum, (DrvQElPtr)&dsptr->qLink); return noErr; } short RomDrvPrime(IOParamPtr p, DCtlPtr d) { long off; RomDrvContext *ctx; char startup; char ram; if(!d->dCtlStorage) return offLinErr; ctx = *(RomDrvContext**)d->dCtlStorage; ReadXPRam(1, 4, &startup); ReadXPRam(1, 5, &ram); if(!ctx->initialized && startup) { ctx->initialized = 1; ctx->drvsts.writeProt = 0xFF; ctx->origdisk = NULL; ctx->disk = (unsigned char *)kRomDrvLocation; if(ram) { // Delay allocation until boot ctx->useram = 1; ctx->drvsts.writeProt = 0; if (*((unsigned char *)0x0CB2)) { if(((unsigned long)*BufPtr - kRomDrvSize) <= (( ((unsigned long)*MemTop) / 2) - (1024*1024))) { d->dCtlFlags |= dNeedTimeMask; d->dCtlDelay = 0x10; } else { *BufPtr -= kRomDrvSize; ctx->origdisk = *BufPtr; ctx->alreadyalloced = 1; ctx->disk = (unsigned char *)ctx->origdisk; BlockMoveData((unsigned char *)kRomDrvLocation, ctx->disk, kRomDrvSize); } } else { d->dCtlFlags |= dNeedTimeMask; d->dCtlDelay = 0x10; } } } if(!ctx->initialized) { ctx->initialized = 1; // check for 'r' held down. if(!(*((unsigned char *)0x175) & 0x80)) { /* If 'r' is not held down, remove ourselves from the drive queue */ DrvQElPtr dq; QHdrPtr QHead = (QHdrPtr)0x308; dq = (DrvQElPtr)QHead->qHead; while((dq != (DrvQElPtr)(QHead->qTail)) && (dq->dQRefNum != d->dCtlRefNum)) dq = (DrvQElPtr)(dq->qLink); if(dq->dQRefNum == d->dCtlRefNum) { Dequeue((QElemPtr)dq, QHead); if(ctx->origdisk) { DisposePtr(ctx->origdisk); ctx->origdisk = NULL; } DisposePtr(ctx->origcopyfunc); HUnlock(d->dCtlStorage); DisposeHandle(d->dCtlStorage); } d->dCtlStorage = NULL; return offLinErr; } ctx->drvsts.writeProt = 0xFF; ctx->origdisk = NULL; ctx->disk = (unsigned char *)kRomDrvLocation; // check if 'a' is also held down if(*((unsigned char *)0x174) & 0x01) { // Delay allocation until boot ctx->useram = 1; ctx->drvsts.writeProt = 0; if (*((unsigned char *)0x0CB2)) { if(((unsigned long)*BufPtr - kRomDrvSize) <= (( ((unsigned long)*MemTop) / 2) - (1024*1024))) { d->dCtlFlags |= dNeedTimeMask; d->dCtlDelay = 0x10; } else { *BufPtr -= kRomDrvSize; ctx->origdisk = *BufPtr; ctx->alreadyalloced = 1; ctx->disk = (unsigned char *)ctx->origdisk; BlockMoveData((unsigned char *)kRomDrvLocation, ctx->disk, kRomDrvSize); } } else { d->dCtlFlags |= dNeedTimeMask; d->dCtlDelay = 0x10; } } } switch(p->ioPosMode & 0x000F) { case fsAtMark: off = d->dCtlPosition; break; case fsFromStart: off = p->ioPosOffset; break; case fsFromMark: off = d->dCtlPosition + p->ioPosOffset; break; default: break; } if((p->ioTrap & 0x00ff) == aRdCmd) { /* bit 6 indicates this should be a verify operation */ if(!(p->ioPosMode & 0x40)) { unsigned long count = p->ioReqCount; if(ctx->drvsts.writeProt == 0 && ctx->origdisk) { // If the data is in RAM, we can access it in 24bit mode, and can // avoid the overhead of the extra function call and 2 MMU switches. if (!ctx->ram24) { BlockMoveData(ctx->disk + off, p->ioBuffer, count); } else { ctx->copyfunc((unsigned char *)(ctx->disk + off), (unsigned char *)RomDrvStripAddress(p->ioBuffer), count); } } else { ctx->copyfunc((unsigned char *)(ctx->disk + off), (unsigned char*)RomDrvStripAddress(p->ioBuffer), count); } p->ioActCount = count; d->dCtlPosition = off + count; p->ioPosOffset = d->dCtlPosition; } return noErr; } else if(((p->ioTrap & 0x00ff) == aWrCmd) && (ctx->drvsts.writeProt == 0)) { if (!ctx->ram24) { BlockMoveData(p->ioBuffer, ctx->disk + off, p->ioReqCount); } else { ctx->copyfunc((unsigned char *)RomDrvStripAddress(p->ioBuffer), (unsigned char *)(ctx->disk + off), p->ioReqCount); } p->ioActCount = p->ioReqCount; d->dCtlPosition = off + p->ioReqCount; p->ioPosOffset = d->dCtlPosition; return noErr; } return wPrErr; } short RomDrvClose(IOParamPtr p, DCtlPtr d) { RomDrvContext *ctx; if(!d->dCtlStorage) return noErr; ctx = *(RomDrvContext**)d->dCtlStorage; if(ctx->origdisk) DisposePtr(ctx->origdisk); DisposePtr(ctx->origcopyfunc); HUnlock(d->dCtlStorage); DisposeHandle(d->dCtlStorage); d->dCtlStorage = NULL; return noErr; } short main(IOParamPtr p, DCtlPtr d, short cmd) { switch(cmd) { case 0: return RomDrvOpen(p, d); case 1: return RomDrvPrime(p, d); case 2: if(((CntrlParamPtr)p)->csCode == 21) { *(Ptr*)&((CntrlParamPtr)p)->csParam = (Ptr)&DiskIcon; return noErr; } else if(((CntrlParamPtr)p)->csCode == 22) { *(Ptr*)&((CntrlParamPtr)p)->csParam = (Ptr)&DiskIcon; return noErr; } #if NEED_ACCRUN if(((CntrlParamPtr)p)->csCode == accRun) { RomDrvContext *ctx; if(!d->dCtlStorage) return noErr; ctx = *(RomDrvContext**)d->dCtlStorage; if(ctx->useram && !ctx->origdisk) { if (*((unsigned char *)0x0CB2)) { /* if we're already in 32-bit mode, allocate like this */ ctx->origdisk = NewPtrSys(kRomDrvSize); if(ctx->origdisk) { ctx->disk = (unsigned char *)RomDrvStripAddress((Ptr)ctx->origdisk); ctx->copyfunc((unsigned char *)kRomDrvLocation, ctx->disk, kRomDrvSize); } } else { ctx->ram24 = 1; ctx->origdisk = NewPtrSys(1); /* just a dummy pointer to make rest of code work */ ctx->disk = (unsigned char *)(8*1048576); ctx->copyfunc((unsigned char *)kRomDrvLocation, ctx->disk, kRomDrvSize); } } d->dCtlDelay = 0; d->dCtlFlags &= ~dNeedTimeMask; return noErr; } #endif return controlErr; case 3: #if NEED_DRVSTAT if(!d->dCtlStorage) return statusErr; if(((CntrlParamPtr)p)->csCode == drvStsCode) { BlockMove(*d->dCtlStorage, &((CntrlParamPtr)p)->csParam, sizeof(DrvSts2)); return noErr; } #endif return statusErr; case 4: return RomDrvClose(p, d); default: return noErr; } } \ No newline at end of file diff --git a/romdrv 0.9.6/romdrvinit b/romdrv 0.9.6/romdrvinit new file mode 100644 index 0000000..2eccc9c Binary files /dev/null and b/romdrv 0.9.6/romdrvinit differ diff --git a/romdrv 0.9.6/romdrvinit.c b/romdrv 0.9.6/romdrvinit.c new file mode 100644 index 0000000..c1b81e7 --- /dev/null +++ b/romdrv 0.9.6/romdrvinit.c @@ -0,0 +1 @@ +#include #include #include #include #include #include #include #include #include /* Name of driver to load */ #define kDrvrName "\p.Romdrv" #define UTableBase (*(DCtlHandle**) 0x11C) #define UnitNtryCnt (*(short*) 0x1D2) struct Driver { short drvrFlags; short drvrDelay; short drvrEMask; short drvrMenu; short drvrOpen; short drvrPrime; short drvrCtl; short drvrStatus; short drvrClose; Str255 drvrName; }; short MyFindSpaceInUnitTable(void); OSErr MyOpenDriver(void); /* Stolen nearly verbatim from IM: Devices */ short MyFindSpaceInUnitTable(void) { Ptr curUTableBase, newUTableBase; short curUTableEntries, newUTableEntries; short refNum, unitNum; long *entryarray; /* get current unit table values from low memory globals */ curUTableEntries = UnitNtryCnt; curUTableBase = (Ptr)UTableBase; entryarray = (long*)UTableBase; /* search for empty space in the current unit table */ for(unitNum = curUTableEntries-1; unitNum >= 48; unitNum--) { if(entryarray[unitNum] == 0) { return unitNum; } } /* no space in the current table, so make a new one */ /* increase the size of the table by 16 (an arbitrary value) */ newUTableEntries = curUTableEntries + 16; /* allocate space for the new table */ newUTableBase = NewPtrSysClear((long)newUTableEntries * sizeof(Handle)); if(newUTableBase == nil) return dsMemFullErr; /* copy the old table to the new table */ BlockMove(curUTableBase, newUTableBase, (long)curUTableEntries * sizeof(Handle)); /* set the new unit table values in low memory */ UTableBase = (void*)newUTableBase; UnitNtryCnt = newUTableEntries; unitNum = newUTableEntries - 1; return unitNum; } /* Stolen from IM: Devices */ OSErr MyOpenDriver(void) { Handle drvrHdl; short drvrID; short tempDrvrID; ResType drvrType; Str255 drvrName; OSErr myErr = noErr; struct IOParam pb; char hackname[8]; struct Driver *drvrPtr; DCtlHandle entryHdl; hackname[0] = 7; hackname[1] = '.'; hackname[2] = 'R'; hackname[3] = 'o'; hackname[4] = 'm'; hackname[5] = 'd'; hackname[6] = 'r'; hackname[7] = 'v'; tempDrvrID = MyFindSpaceInUnitTable(); if(tempDrvrID > 0) { drvrHdl = GetResource((ResType)'DRVR', 192); if(!drvrHdl) { //DebugStr("\pCould not get named resource"); return openErr; } GetResInfo(drvrHdl, &drvrID, &drvrType, drvrName); SetResInfo(drvrHdl, tempDrvrID, drvrName); LoadResource(drvrHdl); DetachResource(drvrHdl); entryHdl = (DCtlHandle)NewHandleSysClear(40); drvrPtr = *(struct Driver **)drvrHdl; drvrPtr->drvrFlags |= dRAMBased | dCtlEnable | dNeedTime | dNeedLock | dReadEnable | dStatEnable; drvrPtr->drvrDelay = 0x300; (*entryHdl)->dCtlDriver = (Ptr)drvrHdl; (*entryHdl)->dCtlFlags = drvrPtr->drvrFlags; (*entryHdl)->dCtlDelay = drvrPtr->drvrDelay; (*entryHdl)->dCtlEMask = drvrPtr->drvrEMask; (*entryHdl)->dCtlMenu = drvrPtr->drvrMenu; (*entryHdl)->dCtlPosition = 0; (*entryHdl)->dCtlRefNum = ~tempDrvrID; (*entryHdl)->dCtlWindow = NULL; (*((DCtlHandle**)0x11C))[tempDrvrID] = entryHdl; pb.ioCompletion = NULL; pb.ioNamePtr = (StringPtr)hackname; pb.ioPermssn = 0; myErr = PBOpen((ParmBlkPtr)&pb, false); if(myErr != noErr) { //DebugStr("\pError with pbopen"); } drvrHdl = GetResource((ResType)'DRVR', tempDrvrID); SetResInfo(drvrHdl, drvrID, drvrName); return(myErr); } else { return openErr; } } int main(void) { THz save, sys; save = GetZone(); sys = SystemZone(); SetZone(sys); if(MyOpenDriver() != 0) { //DebugStr("\pProblem loading driver"); } SetZone(save); } \ No newline at end of file diff --git a/romdrv1.2/ColorHappyMac.rsrc b/romdrv1.2/ColorHappyMac.rsrc new file mode 100644 index 0000000..e69de29 diff --git a/romdrv1.2/atBOOT b/romdrv1.2/atBOOT new file mode 100644 index 0000000..e69de29 diff --git a/romdrv1.2/fc8-decompress-68000.c b/romdrv1.2/fc8-decompress-68000.c new file mode 100644 index 0000000..f237993 --- /dev/null +++ b/romdrv1.2/fc8-decompress-68000.c @@ -0,0 +1 @@ +/* * FC8 compression by Steve Chamberlin * Derived from liblzg by Marcus Geelnard * 68000 decompressor by Steve Chamberlin */ #define FC8_DECODED_SIZE_OFFSET 4 #define FC8_HEADER_SIZE 8 //------------------------------------------------------------------------------- // fc8_decode - Decode a compressed memory block // a0 = in buffer // a1 = out buffer // d1 = outsize // d0 = result (1 if decompression was successful, or 0 upon failure) //------------------------------------------------------------------------------- #pragma parameter __D0 fc8_decode(__A0, __A1, __D1) asm unsigned short fc8_decode(unsigned char* in, unsigned char* out, unsigned long outsize) { machine 68020 movem.l d1-d7/a0-a6,-(sp) bra _Init_Decode // lookup table for decoding the copy length-1 parameter _FC8_LENGTH_DECODE_LUT: dc.b 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 dc.b 18,19,20,21,22,23,24,25,26,27,28,34,47,71,127,255 //------------------------------------------------------------------------------- // _GetUINT32 - alignment independent reader for 32-bit integers // a0 = in // d6 = offset // d7 = result //------------------------------------------------------------------------------- _GetUINT32: move.b (a0,d6.w),d7 asl.w #8,d7 move.b 1(a0,d6.w),d7 swap d7 move.b 2(a0,d6.w),d7 asl.w #8,d7 move.b 3(a0,d6.w),d7 rts _Init_Decode: // check magic ID cmp.b #'F',(a0) bne _fail cmp.b #'C',1(a0) bne _fail cmp.b #'8',2(a0) bne _fail cmp.b #'_',3(a0) bne _fail // check decoded size - enough space in the output buffer? moveq #FC8_DECODED_SIZE_OFFSET,d6 bsr.s _GetUINT32 cmp.l d7,d1 bhi _fail // advance a0 to start of compressed data lea FC8_HEADER_SIZE(a0), a0 // a5 = base of length decode lookup table //lea _FC8_LENGTH_DECODE_LUT(pc),a5 lea -110(pc),a5 // fix PC offset manually after assembly // helpful constants move.l #0x0000001F, d1 move.l #0x00000007, d2 move.l #0x00000001, d3 move.l #0x0000003F, d4 // Main decompression loop _mainloop: move.b (a0)+, d6 // d6 = next token bmi.s _BR1_BR2 // BR1 and BR2 tokens have the high bit set btst #6, d6 // check bit 6 to see if this is a BR0 or LIT token bne.s _BR0 // LIT 00aaaaaa - copy literal string of aaaaaa+1 bytes from input to output _LIT: move.l a0, a4 // a4 = source ptr for copy and.w d4, d6 // AND with 0x3F, d6 = length-1 word for copy lea 1(a0,d6.w), a0 // advance a0 to the end of the literal string bra.s _copyLoop // BR0 01baaaaa - copy b+3 bytes from output backref aaaaa to output _BR0: move.b d6, d5 and.l d1, d5 // AND with 0x1F, d5 = offset for copy = (long)(t0 & 0x1F) beq _done // BR0 with 0 offset means EOF move.l a1, a4 sub.l d5, a4 // a4 = source ptr for copy move.b (a4)+, (a1)+ // copy 3 bytes, can't use move.w. or move.l because src and dest may overlap move.b (a4)+, (a1)+ move.b (a4)+, (a1)+ btst #5, d6 // check b bit beq.s _mainloop move.b (a4)+, (a1)+ // copy 1 more byte bra.s _mainloop _BR1_BR2: btst #6, d6 // check bit 6 to see if this is a BR1 or BR2 token bne.s _BR2 // BR1 10bbbaaa'aaaaaaaa - copy bbb+3 bytes from output backref aaa'aaaaaaaa to output _BR1: move.b d6,d5 and.l d2, d5 // AND with 0x07 lsl.l #8, d5 move.b (a0)+, d5 // d5 = offset for copy = ((long)(t0 & 0x07) << 8) | t1 lsr.b #3, d6 and.w d2, d6 // AND with 0x07 addq.w #2, d6 // d6 = length-1 word for copy = ((word)(t0 >> 3) & 0x7) + 1 bra.s _copyBackref // BR2 11bbbbba'aaaaaaaa'aaaaaaaa - copy lookup_table[bbbbb] bytes from output backref a'aaaaaaaa'aaaaaaaa to output _BR2: move.b d6,d5 and.w d3, d5 // AND with 0x01 swap d5 move.w (a0)+, d5 // d5 = offset for copy = ((long)(t0 & 0x01) << 16) | (t1 << 8) | t2 lsr.b #1, d6 and.w d1, d6 // AND with 0x1F move.b (a5,d6.w),d6 // d6 = length-1 word for copy = ((word)(t0 >> 3) & 0x7) + 1 // fall through to _copyBackref // copy data from a previous location in the output buffer // d5 = offset from current buffer position _copyBackref: move.l a1, a4 sub.l d5, a4 // a4 = source ptr for copy cmpi.l #4, d5 blt.s _nearCopy // must copy byte-by-byte if offset < 4, to avoid overlapping long copies // Partially unrolled block copy. Requires 68020 or better. // Uses move.l and move.w where possible, even though both source and dest may be unaligned. // It's still faster than multiple move.b instructions // d6 = length-1 _copyLoop: cmpi.w #16, d6 bge.s _copy17orMore jmp _copy16orFewer(d6.w*2) _copy16orFewer: bra.s _copy1 bra.s _copy2 bra.s _copy3 bra.s _copy4 bra.s _copy5 bra.s _copy6 bra.s _copy7 bra.s _copy8 bra.s _copy9 bra.s _copy10 bra.s _copy11 bra.s _copy12 bra.s _copy13 bra.s _copy14 bra.s _copy15 bra.s _copy16 _copy15: move.l (a4)+, (a1)+ _copy11: move.l (a4)+, (a1)+ _copy7: move.l (a4)+, (a1)+ _copy3: move.w (a4)+, (a1)+ _copy1: move.b (a4)+, (a1)+ bra _mainloop _copy14: move.l (a4)+, (a1)+ _copy10: move.l (a4)+, (a1)+ _copy6: move.l (a4)+, (a1)+ _copy2: move.w (a4)+, (a1)+ bra _mainloop _copy13: move.l (a4)+, (a1)+ _copy9: move.l (a4)+, (a1)+ _copy5: move.l (a4)+, (a1)+ move.b (a4)+, (a1)+ bra _mainloop _copy16: move.l (a4)+, (a1)+ _copy12: move.l (a4)+, (a1)+ _copy8: move.l (a4)+, (a1)+ _copy4: move.l (a4)+, (a1)+ bra _mainloop _copy17orMore: move.l (a4)+, (a1)+ move.l (a4)+, (a1)+ move.l (a4)+, (a1)+ move.l (a4)+, (a1)+ subi.w #16, d6 cmpi.w #16, d6 bge.s _copy17orMore jmp _copy16orFewer(d6.w*2) _nearCopy: cmpi.l #1,d5 beq.s _copyRLE _nearLoop: move.b (a4)+, (a1)+ dbf d6, _nearLoop bra _mainloop _copyRLE: // assumes length is at least 3 move.b (a4), (a1)+ // copy first byte btst #0, d6 beq.s _doRLE // branch if copy length is odd (because d6 is length-1) move.b (a4), (a1)+ // copy second byte _doRLE: subq.w #2, d6 lsr.w #1, d6 // length = (length-2) / 2 move.w (a4), d5 _rleLoop: move.w d5, (a1)+ dbf d6, _rleLoop bra _mainloop _fail: moveq.w #0, d0 // result = 0 bra _exit _done: moveq.w #1, d0 // result = 1 _exit: movem.l (sp)+, d1-d7/a0-a6 rts } \ No newline at end of file diff --git a/romdrv1.2/fc8-decompress-68000.h b/romdrv1.2/fc8-decompress-68000.h new file mode 100644 index 0000000..904d815 --- /dev/null +++ b/romdrv1.2/fc8-decompress-68000.h @@ -0,0 +1 @@ +#ifndef _FC8_H_ #define _FC8_H_ #pragma parameter __D0 fc8_decode(__A0, __A1, __D1) asm unsigned short fc8_decode(unsigned char* in, unsigned char* out, unsigned long outsize); #endif \ No newline at end of file diff --git a/romdrv1.2/romdrv inrom v2 b/romdrv1.2/romdrv inrom v2 new file mode 100644 index 0000000..7f9f770 Binary files /dev/null and b/romdrv1.2/romdrv inrom v2 differ diff --git a/romdrv1.2/romdrv.c b/romdrv1.2/romdrv.c new file mode 100644 index 0000000..94bf3d9 --- /dev/null +++ b/romdrv1.2/romdrv.c @@ -0,0 +1 @@ +#include #include #include #include #include #include #include #include #include "fc8-decompress-68000.h" #define NUM_CACHE_BLOCKS 16 #define CACHE_BLOCK_SIZE (64L*1024) #define NEED_DRVSTAT 1 #define NEED_ACCRUN 0 /* If NEED_ACCRUN is set, the dNeedTime (0x60) flag should be set in the header, and the * delayticks field in the header should be set to something sensible. */ unsigned long kRomDrvSize = 0x00380000L; Ptr kRomDrvLocation = (Ptr)0x40880000; // Macintosh low-memory globals unsigned long* BufPtr = (unsigned long*)0x010C; unsigned long* MemTop = (unsigned long*)0x0108; unsigned char* MMU32Bit = (unsigned char*)0x0CB2; unsigned char* LLKeyMap = (unsigned char*)0x0174; #pragma parameter __D0 ReadXPRam(__D0, __D1, __A0) short ReadXPRam(short size, short offset, char *where) = {0x4840, 0x3001, _ReadXPRam}; typedef void (*RomDrvCopyFunc)(unsigned char *, unsigned char *, unsigned long); struct CacheRecord { unsigned int isValid : 1; unsigned int isModified : 1; unsigned short hitCount; unsigned long timestamp; unsigned long diskOffset; unsigned char* pData; }; typedef struct CacheRecord CacheRecord; struct RomDrvContext { DrvSts2 drvsts; Ptr origcopyfunc; Ptr ramdisk; RomDrvCopyFunc copyfunc; unsigned char * disk; char initialized; char useram; char ram24at8mb; char usecache; char showedFullError; unsigned short numModifiedBlocks; unsigned long marker; unsigned long ioCount; unsigned long blocksLoaded; unsigned long blocksFlushed; CacheRecord cacheRecords[NUM_CACHE_BLOCKS]; }; typedef struct RomDrvContext RomDrvContext; #define ICON_NONE 0 #define ICON_DISK 1 #define ICON_TITLE 2 const unsigned char DiskIcon[258] = { 0xf, 0xff, 0xff, 0xe0, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x11, 0xff, 0xff, 0x10, 0x12, 0x1, 0x00, 0x90, 0x12, 0x00, 0x81, 0x90, 0x12, 0x00, 0x7e, 0x90, 0x12, 0x11, 0x3c, 0x90, 0x12, 0x11, 0x3c, 0x90, 0x12, 0x1, 0x18, 0x90, 0x12, 0x1, 0x00, 0x90, 0x12, 0x3, 0x00, 0x90, 0x12, 0x00, 0x00, 0x90, 0x12, 0x8, 0x40, 0x90, 0x12, 0x7, 0x80, 0x90, 0x12, 0x00, 0x00, 0x90, 0x12, 0x00, 0x00, 0x90, 0x11, 0xff, 0xff, 0x10, 0x10, 0x00, 0x00, 0x10, 0x8, 0x00, 0x00, 0x20, 0x3f, 0xff, 0xff, 0xf8, 0x20, 0x00, 0x00, 0x8, 0x2f, 0xff, 0xff, 0xe8, 0x20, 0x00, 0x00, 0x8, 0x2f, 0xff, 0xff, 0xe8, 0x20, 0x00, 0x00, 0x8, 0x20, 0x00, 0x00, 0x8, 0x20, 0x00, 0xf, 0xe8, 0x2c, 0x00, 0x00, 0x8, 0x20, 0x00, 0x00, 0x68, 0x20, 0x00, 0x00, 0x8, 0x3f, 0xff, 0xff, 0xf8, // mask 0xf, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0xf, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0, 0}; const unsigned char bmow_title [] = { 0x7F, 0xFF, 0xFC, 0x00, 0x7F, 0x80, 0x00, 0x3F, 0x80, 0x07, 0xFF, 0xE0, 0x01, 0xFF, 0x80, 0x03, 0xFE, 0x7F, 0xFF, 0xFE, 0x00, 0x7F, 0xC0, 0x00, 0x7F, 0x80, 0x0F, 0xFF, 0xF0, 0x01, 0xFF, 0x80, 0x03, 0xFE, 0x7F, 0xFF, 0xFF, 0x00, 0x7F, 0xE0, 0x00, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0x80, 0x03, 0xFE, 0x7F, 0xFF, 0xFF, 0x80, 0x7F, 0xF0, 0x01, 0xFF, 0x80, 0x3F, 0xFF, 0xFC, 0x01, 0xFF, 0x80, 0x03, 0xFE, 0x7F, 0xE0, 0x1F, 0xC0, 0x7F, 0xF8, 0x03, 0xFF, 0x80, 0x7F, 0x00, 0xFE, 0x01, 0xFF, 0x80, 0x03, 0xFE, 0x7F, 0xE0, 0x1F, 0xE0, 0x7F, 0xFC, 0x07, 0xFF, 0x80, 0xFF, 0x00, 0xFF, 0x01, 0xFF, 0x80, 0x03, 0xFE, 0x7F, 0xE0, 0x1F, 0xF0, 0x7F, 0xFE, 0x0F, 0xFF, 0x81, 0xFF, 0x00, 0xFF, 0x81, 0xFF, 0x80, 0x03, 0xFE, 0x7F, 0xE0, 0x1F, 0xF0, 0x7F, 0xFF, 0x1F, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0xC1, 0xFF, 0x80, 0x03, 0xFE, 0x7F, 0xE0, 0x1F, 0xE0, 0x7F, 0xFF, 0xBF, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0xC1, 0xFF, 0x80, 0x03, 0xFE, 0x7F, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0xC1, 0xFF, 0x81, 0x03, 0xFE, 0x7F, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0xC1, 0xFF, 0x83, 0x83, 0xFE, 0x7F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0xC1, 0xFF, 0x87, 0xC3, 0xFE, 0x7F, 0xFF, 0xFF, 0x80, 0x7F, 0xEF, 0xFE, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0xC1, 0xFF, 0x8F, 0xE3, 0xFE, 0x7F, 0xE0, 0x1F, 0xC0, 0x7F, 0xE7, 0xFC, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0xC1, 0xFF, 0x9F, 0xF3, 0xFE, 0x7F, 0xE0, 0x1F, 0xE0, 0x7F, 0xE3, 0xF8, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0xC1, 0xFF, 0xBF, 0xFB, 0xFE, 0x7F, 0xE0, 0x1F, 0xF0, 0x7F, 0xE1, 0xF0, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xE0, 0x1F, 0xF0, 0x7F, 0xE0, 0xE0, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xE0, 0x1F, 0xF0, 0x7F, 0xE0, 0x40, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xE0, 0x1F, 0xF0, 0x7F, 0xE0, 0x00, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0xC1, 0xFF, 0xFE, 0xFF, 0xFE, 0x7F, 0xE0, 0x1F, 0xF0, 0x7F, 0xE0, 0x00, 0xFF, 0x83, 0xFF, 0x00, 0xFF, 0xC1, 0xFF, 0xFC, 0x7F, 0xFE, 0x7F, 0xE0, 0x1F, 0xF0, 0x7F, 0xE0, 0x00, 0xFF, 0x81, 0xFF, 0x00, 0xFF, 0x81, 0xFF, 0xF8, 0x3F, 0xFE, 0x7F, 0xE0, 0x1F, 0xE0, 0x7F, 0xE0, 0x00, 0xFF, 0x80, 0xFF, 0x00, 0xFF, 0x01, 0xFF, 0xF0, 0x1F, 0xFE, 0x7F, 0xE0, 0x1F, 0xC0, 0x7F, 0xE0, 0x00, 0xFF, 0x80, 0x7F, 0x00, 0xFE, 0x01, 0xFF, 0xE0, 0x0F, 0xFE, 0x7F, 0xFF, 0xFF, 0x80, 0x7F, 0xE0, 0x00, 0xFF, 0x80, 0x3F, 0xFF, 0xFC, 0x01, 0xFF, 0xC0, 0x07, 0xFE, 0x7F, 0xFF, 0xFF, 0x00, 0x7F, 0xE0, 0x00, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0x80, 0x03, 0xFE, 0x7F, 0xFF, 0xFE, 0x00, 0x7F, 0xE0, 0x00, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, 0x01, 0xFF, 0x00, 0x01, 0xFE, 0x7F, 0xFF, 0xFC, 0x00, 0x7F, 0xE0, 0x00, 0xFF, 0x80, 0x07, 0xFF, 0xE0, 0x01, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; /* AddDrive is declared in Files.h, but it's defined in MacOS.lib, which we don't want, * so just shortcut the whole thing here. */ asm void RomDrvAddDrive(short drvrRefNum, short drvNum, DrvQElPtr dq) { fralloc + CLR.L D0 MOVE.W drvNum, D0 SWAP D0 MOVE.W drvrRefNum, D0 MOVEA.L dq, A0 0xA04E frfree RTS } #pragma parameter __D0 RomDrvStripAddress(__D0) pascal Ptr RomDrvStripAddress(void *addr) = 0xA055; char DiskIsCompressed() { unsigned long signature = *(unsigned long*)kRomDrvLocation; return (signature & 0xFFFFFF00) == 0x46433800; // 'FC8' } char DiskIsWholeCompressed() { unsigned long signature = *(unsigned long*)kRomDrvLocation; return signature == 0x4643385F; // 'FC8_' } char DiskIsBlockCompressed() { unsigned long signature = *(unsigned long*)kRomDrvLocation; return signature == 0x46433862; // 'FC8b' } unsigned long UncompressedDiskSize() { if (DiskIsCompressed()) return *(unsigned long*)(kRomDrvLocation+4); else return kRomDrvSize; } void RomDrvCopy(unsigned char *source, unsigned char *dest, unsigned long count) { signed char mode = true32b; SwapMMUMode(&mode); BlockMoveData(source, dest, count); SwapMMUMode(&mode); } void PStrCpy(unsigned char* str, const unsigned char* str2) { unsigned char len = str2[0]; str[0] = len; for (; len>0; len--) str[len] = str2[len]; } void PStrCat(unsigned char* str, const unsigned char* extra) { unsigned char baseLen = str[0]; unsigned char extraLen = extra[0]; str[0] += extraLen; for (; extraLen>0; extraLen--) str[baseLen+extraLen] = extra[extraLen]; } void PUShortToStr(unsigned char* str, unsigned short num) { unsigned short temp = num; unsigned char power = 1; unsigned char len = 0; while (temp >= 10) { temp /= 10; power *= 10; } while (power > 0) { str[1+len] = '0' + num/power; num -= ((num/power)*power); power /= 10; len++; } str[0] = len; } short RomDrvOpen(IOParamPtr /*p*/, DCtlPtr d) { DrvSts2 *dsptr; DrvQElPtr dq; int i, drvnum = 1; RomDrvContext *ctx; unsigned long driveSize; if (d->dCtlStorage == NULL) { // alloc some memory for driver context d->dCtlStorage = NewHandleSysClear(sizeof(RomDrvContext)); HLock(d->dCtlStorage); ctx = *(RomDrvContext**)d->dCtlStorage; // init the cache records for (i=0; icacheRecords[i].isValid = 0; ctx->cacheRecords[i].pData = NULL; } ctx->marker = 0xBEEFBABE; ctx->usecache = 0; ctx->showedFullError = 0; ctx->numModifiedBlocks = 0; ctx->ioCount = 1; ctx->blocksLoaded = 0; ctx->blocksFlushed = 0; // copy the copy function into RAM, for 32-bit safeness ctx->origcopyfunc = NewPtrSys(64); if (!ctx->origcopyfunc) { SysBeep(8); return openErr; } BlockMove(&RomDrvCopy, ctx->origcopyfunc, 64); ctx->copyfunc = (RomDrvCopyFunc)RomDrvStripAddress(ctx->origcopyfunc); // find an available drive number for (dq = (DrvQElPtr)(GetDrvQHdr())->qHead; dq; dq = (DrvQElPtr)dq->qLink) { if(dq->dQDrive >= drvnum) drvnum = dq->dQDrive+1; } // set drive parameters, and add it to the drive queue ctx->ramdisk = NULL; ctx->disk = (unsigned char *)kRomDrvLocation; dsptr = &ctx->drvsts; dsptr->writeProt = 0xFF; dsptr->diskInPlace = 8; dsptr->dQDrive = drvnum; dsptr->dQRefNum = d->dCtlRefNum; driveSize = UncompressedDiskSize(); dsptr->driveSize = (driveSize/512L) & 0xFFFF; dsptr->driveS1 = ((driveSize/512L) & 0xFFFF0000) >> 16; RomDrvAddDrive(dsptr->dQRefNum, drvnum, (DrvQElPtr)&dsptr->qLink); } return noErr; } char CanAllocAbove8MB(unsigned long bytesNeeded) { // 24-bit can alloc above 8MB? if (GetMMUMode() == false32b && 0x00800000 + bytesNeeded <= *MemTop) return 1; return 0; } char CanAllocWithBufPtr(unsigned long bytesNeeded) { // top of system startup blocks is the lowest point to which BufPtr can safely be lowered // BufPtr = address of the highest byte of allocatable memory // See explanation in Apple's Memory Manager documentation // https://developer.apple.com/legacy/library/documentation/mac/pdf/Memory/Memory_Manager.pdf unsigned long systemStartupBlocksTop = (*MemTop) / 2 + 1024; // 4/24/2016 - The systemStartupBlocksTop formula doesn't seem to work reliably // 1.5MB alloc on a 4MB system passes this test, but then System 7 reports out of memory // same with 3.5MB alloc on an 8MB system // use a more conservative formula instead //if (*BufPtr - bytesNeeded >= systemStartupBlocksTop) if (*BufPtr - (bytesNeeded + 0x80000) >= systemStartupBlocksTop) return 1; return 0; } void EraseBox() { struct QDStorage { QDGlobals qd; long qdGlobalsPtr; } qds; GrafPort gp; GrafPtr oldport; long olda5; Rect r; short cx, cy, extraHeight = 20; const short boxWidth = 300; // setup Quickdraw GetPort(&oldport); olda5 = SetA5((long)&qds.qdGlobalsPtr); InitGraf(&qds.qd.thePort); OpenPort(&gp); cx = gp.portBits.bounds.right / 2; cy = gp.portBits.bounds.bottom / 2; SetRect(&r, cx - boxWidth/2 - 10, cy - 16 - 10, cx + boxWidth/2 + 10, cy + 16 + 40 + extraHeight); FillRect(&r, &qds.qd.gray); ClosePort(&gp); SetA5(olda5); } short DisplayBoxedStrings(char iconType, const unsigned char* str, const unsigned char* str2) { struct QDStorage { QDGlobals qd; long qdGlobalsPtr; } qds; GrafPort gp; GrafPtr oldport; long olda5; Rect r; BitMap sourceBits, destBits; short cx, cy, width, width2 = 0, extraHeight = 20; const short boxWidth = 300; // setup Quickdraw GetPort(&oldport); olda5 = SetA5((long)&qds.qdGlobalsPtr); InitGraf(&qds.qd.thePort); OpenPort(&gp); destBits = gp.portBits; cx = gp.portBits.bounds.right / 2; cy = gp.portBits.bounds.bottom / 2; width = StringWidth(str); if (str2) { width2 = StringWidth(str2); } if (iconType != ICON_NONE) { // draw a centered box, scaled to the text SetRect(&r, cx - boxWidth/2 - 10, cy - 16 - 10, cx + boxWidth/2 + 10, cy + 16 + 40 + extraHeight); EraseRect(&r); FrameRect(&r); if (iconType == ICON_DISK) { SetRect(&r, cx - 16, cy - 16, cx + 16, cy + 16); sourceBits.rowBytes = 4; SetRect(&sourceBits.bounds, 0, 0, 32, 32); sourceBits.baseAddr = (char*)DiskIcon; } else if (iconType == ICON_TITLE) { SetRect(&r, cx - 68, cy - 14, cx + 68, cy + 14); sourceBits.rowBytes = 17; SetRect(&sourceBits.bounds, 0, 0, 136, 28); sourceBits.baseAddr = (char*)bmow_title; } CopyBits(&sourceBits, &destBits, &sourceBits.bounds, &r, srcCopy, NULL); } else { // erase the old text area SetRect(&r, cx - boxWidth/2 - 10, cy + 16 + 30 - 12, cx + boxWidth/2 + 10, cy + 16 + 40 + extraHeight); InsetRect(&r, 1, 1); EraseRect(&r); } MoveTo(cx - width/2, cy + 16 + 30); DrawString(str); if (str2) { MoveTo(cx - width2/2, cy + 16 + 30 + extraHeight); DrawString(str2); } ClosePort(&gp); SetA5(olda5); return boxWidth; } void DisplayErrorString(const unsigned char* str) { DisplayBoxedStrings(ICON_DISK, str, "\pPress RETURN to continue"); // wait for Enter/Return key, keymap bit 36 or 42 (international keyboard) while(1) { if((LLKeyMap[4] & 0x10) || (LLKeyMap[5] & 0x04)) break; } EraseBox(); } void DisplayDiskError(short err) { // draw a centered box, scaled to the prompt text if (err == 1) DisplayErrorString("\pDisk decompression error"); else if (err == 2) DisplayErrorString("\pNot enough RAM"); } asm void MakeSafeRomPC() { // modify the return address on the stack andi.l #0x00FFFFFF, (sp) ori.l #0x40000000, (sp) rts } void CopyDiskDataToIObuf(RomDrvContext *ctx, unsigned char* src, char* dest, unsigned long count) { if (GetMMUMode() == false32b && (!ctx->ramdisk || ctx->ram24at8mb)) { // 24-bit mode with rom disk, or 24-bit mode with 32-bit ram disk // must switch to 32-bit mode and perform the read using a stripped address ctx->copyfunc((unsigned char *)(src), (unsigned char*)RomDrvStripAddress(dest), count); } else { // already in 32-bit mode, or in 24-bit mode with a 24-bit ram disk // ok to just perform the read BlockMoveData(src, dest, count); } } void CopyDiskDataFromIObuf(RomDrvContext *ctx, char* src, unsigned char* dest, unsigned long count) { if (ctx->ram24at8mb) { // 24-bit mode with 32-bit ram disk // must switch to 32-bit mode and perform the write using a stripped address ctx->copyfunc((unsigned char *)RomDrvStripAddress(src), (unsigned char *)(dest), count); } else { // already in 32-bit mode, or in 24-bit mode with a 24-bit ram disk // ok to just perform the write BlockMoveData(src, dest, count); } } unsigned long GetBlockOffset(unsigned char* pCompressedData, unsigned long blockNumber) { const unsigned long kFC8bBlockOffsets = 12; unsigned char* pBlockOffset = pCompressedData + kFC8bBlockOffsets + blockNumber * 4; //signed char addressMode = true32b; unsigned long blockOffset; // ensure the PC's high byte is 0x40 (ROM), so we can safely switch to 32-bit addressing mode //MakeSafeRomPC(); //SwapMMUMode(&addressMode); blockOffset = ((unsigned long)pBlockOffset[0]) << 24 | ((unsigned long)pBlockOffset[1]) << 16 | ((unsigned long)pBlockOffset[2]) << 8 | ((unsigned long)pBlockOffset[3]); // restore the old addressing mode //SwapMMUMode(&addressMode); return blockOffset; } short GetDiskDataFromROMToRamdisk(RomDrvContext *ctx, unsigned char* src, unsigned char* dest, unsigned long count) { short result = 0; // don't need to strip address on dest, because it was already done when dest RAM was allocated if (DiskIsCompressed()) { unsigned short decompressStatus; signed char addressMode = true32b; char isBlockCompressed = DiskIsBlockCompressed(); unsigned char* pCompressedData = (unsigned char*)kRomDrvLocation; // ensure the PC's high byte is 0x40 (ROM), so we can safely switch to 32-bit addressing mode MakeSafeRomPC(); SwapMMUMode(&addressMode); // decompress ROM disk data into the RAM disk. // is this a decompression of the entire disk image, for an image that's block compressed? if (count > CACHE_BLOCK_SIZE && isBlockCompressed) { unsigned long i, numBlocks = count / CACHE_BLOCK_SIZE; for (i=0; icopyfunc(src, dest, count); else BlockMoveData(src, dest, count); } return result; } void FillCacheBlock(RomDrvContext *ctx, unsigned long entry, long offset) { short result = 0; if (!DiskIsBlockCompressed()) { result = GetDiskDataFromROMToRamdisk(ctx, (unsigned char*)kRomDrvLocation + offset, ctx->cacheRecords[entry].pData, CACHE_BLOCK_SIZE); } else { unsigned long blockNumber = offset / CACHE_BLOCK_SIZE, blockOffset; blockOffset = GetBlockOffset((unsigned char*)kRomDrvLocation, blockNumber); if (ctx->cacheRecords[entry].isValid) ctx->blocksFlushed++; result = GetDiskDataFromROMToRamdisk(ctx, (unsigned char*)kRomDrvLocation + blockOffset, ctx->cacheRecords[entry].pData, CACHE_BLOCK_SIZE); ctx->blocksLoaded++; } if (result) DisplayDiskError(result); } char SetupRAMDisk(RomDrvContext *ctx, char useCache) { char result = 0; unsigned long bytesNeeded = useCache ? (CACHE_BLOCK_SIZE * NUM_CACHE_BLOCKS) : UncompressedDiskSize(); ctx->useram = 1; // In 24-bit mode, first try to use normally inaccessable RAM beyond 8MB for the RAM disk if (CanAllocAbove8MB(bytesNeeded)) { ctx->ram24at8mb = 1; ctx->ramdisk = NewPtrSys(1); // just a dummy pointer to make rest of code work ctx->disk = (unsigned char *)(0x00800000); } // Both 24 and 32-bit mode try to allocate RAM by directly lowering BufPtr else if (CanAllocWithBufPtr(bytesNeeded)) { // carve out space for the RAM disk by lowering BufPtr *BufPtr -= bytesNeeded; ctx->ramdisk = (char*)*BufPtr; ctx->disk = (unsigned char *)RomDrvStripAddress((Ptr)ctx->ramdisk); } else { // allocation attempts failed. result = 2; // not enough RAM for decompression ctx->useram = 0; ctx->drvsts.writeProt = 0xFF; } if (ctx->ramdisk) { if (useCache) { // setup pointers to cache block storage in RAM. Data will be loaded on demand int i; for (i=0; icacheRecords[i].pData = ctx->disk + CACHE_BLOCK_SIZE * i; ctx->usecache = 1; } else { // copy/decompress the whole disk image into RAM long startTime, totalTime; if (DiskIsCompressed()) DisplayBoxedStrings(ICON_NONE, "\pDecompressing disk image...", NULL); else DisplayBoxedStrings(ICON_NONE, "\pPreparing disk image...", NULL); startTime = TickCount(); result = GetDiskDataFromROMToRamdisk(ctx, (unsigned char*)kRomDrvLocation, ctx->disk, UncompressedDiskSize()); totalTime = TickCount() - startTime; if (result == 0) { // show the copy/decompression time, then wait for key /*Str255 s; Str32 s2; PStrCpy(s, "\pDecompression time: "); PUShortToStr(s2, (unsigned short)totalTime); PStrCat(s,s2); DisplayErrorString(s); */ } } } return result; } char DrawIntroScreen() { long wait; long diagWait; char diskmode = 0; Str255 s,sd; Str32 s2; unsigned short megs; unsigned char drewPrompt; // find megabytes of installed RAM PStrCpy(s, "\p Detected "); megs = (*MemTop) >> 20; PUShortToStr(s2, megs); PStrCat(s, s2); PStrCat(s, "\p MB RAM, "); // set the diagnostic info if (GetMMUMode() == true32b) PStrCat(s, "\p32-bit mode "); else PStrCat(s, "\p24-bit mode "); if (DiskIsCompressed()) { unsigned long diskBytes = UncompressedDiskSize(); megs = (diskBytes + 512L * 1024) / (1024L * 1024L); PUShortToStr(sd, megs); if (DiskIsBlockCompressed()) PStrCat(sd, "\p MB block-compressed disk image"); else PStrCat(sd, "\p MB whole-compressed disk image"); } else { megs = (kRomDrvSize + 512L * 1024) / (1024L * 1024L); PUShortToStr(sd, megs); if (DiskIsBlockCompressed()) PStrCat(sd, "\p MB uncompressed disk image"); } DisplayBoxedStrings(ICON_TITLE, s, sd); wait = TickCount() + 360; diagWait = TickCount() + 120; drewPrompt = 0; while (TickCount() < wait) { // overwrite diagnotic info after 1 second if (TickCount() > diagWait && drewPrompt == 0) { DisplayBoxedStrings(ICON_DISK, "\pPress R for rom disk, A for ram disk", NULL); drewPrompt = 1; } // check for 'r' key if(LLKeyMap[1] & 0x80) { diskmode = 1; break; } // check for 'a' key else if(LLKeyMap[0] & 0x01) { diskmode = 2; break; } // check for 'x' key else if(LLKeyMap[0] & 0x80) { diskmode = 3; break; } } return diskmode; } unsigned long GetCacheEntryForOffset(RomDrvContext *ctx, long offset) { unsigned long lowestTimestamp = 0xFFFFFFFF; unsigned long entry, replaceableEntry = NUM_CACHE_BLOCKS; unsigned long desiredBlockOffset = offset & (~(CACHE_BLOCK_SIZE-1)); for (entry=0; entrycacheRecords[entry]; if (pCacheRecord->isValid) { // is the desired data in this cache block? if (pCacheRecord->diskOffset == desiredBlockOffset) { break; } // could this entry be used to load a new cache block? if (!pCacheRecord->isModified && lowestTimestamp != 0 && pCacheRecord->timestamp < lowestTimestamp) { // old, unmodified entry can be replaced if necessary replaceableEntry = entry; lowestTimestamp = pCacheRecord->timestamp; } } else if (lowestTimestamp != 0) { // unused/invalid entry can be replaced if necessary replaceableEntry = entry; lowestTimestamp = 0; } } // didn't find the necessary block in the cache? load it into the cache if (entry == NUM_CACHE_BLOCKS) { // is there a replaceable entry? if (replaceableEntry != NUM_CACHE_BLOCKS) { CacheRecord* pCacheRecord = &ctx->cacheRecords[replaceableEntry]; FillCacheBlock(ctx, replaceableEntry, offset); pCacheRecord->isValid = 1; pCacheRecord->isModified = 0; pCacheRecord->hitCount = 0; pCacheRecord->diskOffset = desiredBlockOffset; entry = replaceableEntry; } } return entry; } short HandleDiskRead(RomDrvContext *ctx, IOParamPtr p, DCtlPtr d, long off) { if (!ctx->usecache) { CopyDiskDataToIObuf(ctx, ctx->disk + off, p->ioBuffer, p->ioReqCount); } else { long subOff = off; long subCount = p->ioReqCount; unsigned long entry; // get data from the necessary cache block(s) while (subCount != 0) { entry = GetCacheEntryForOffset(ctx, subOff); // copy the data from the cache block if (entry == NUM_CACHE_BLOCKS) { // cache block isn't loaded, and nothing could be unloaded to make room for it! // TODO: prevent this from happening return offLinErr; } else { CacheRecord* pCacheRecord = &ctx->cacheRecords[entry]; unsigned long copySize = subCount; if (copySize > (pCacheRecord->diskOffset + CACHE_BLOCK_SIZE) - subOff) copySize = (pCacheRecord->diskOffset + CACHE_BLOCK_SIZE) - subOff; CopyDiskDataToIObuf(ctx, pCacheRecord->pData + subOff - pCacheRecord->diskOffset, p->ioBuffer + subOff - off, copySize); subOff += copySize; subCount -= copySize; pCacheRecord->timestamp = ctx->ioCount; pCacheRecord->hitCount++; } } } p->ioActCount = p->ioReqCount; d->dCtlPosition = off + p->ioReqCount; p->ioPosOffset = d->dCtlPosition; return noErr; } short HandleDiskWrite(RomDrvContext *ctx, IOParamPtr p, DCtlPtr d, long off) { if (!ctx->usecache) { CopyDiskDataFromIObuf(ctx, p->ioBuffer, ctx->disk + off, p->ioReqCount); } else { long subOff = off; long subCount = p->ioReqCount; unsigned long entry; // write data to the necessary cache block(s) while (subCount != 0) { entry = GetCacheEntryForOffset(ctx, subOff); // copy the data from the cache block if (entry == NUM_CACHE_BLOCKS) { // cache block isn't loaded, and nothing could be unloaded to make room for it! // this should never happen return verErr; } else { CacheRecord* pCacheRecord = &ctx->cacheRecords[entry]; unsigned long copySize = subCount; // if this block would be newly modified, and would leave fewer than 2 unmodified blocks // remaining, report an error and fail if (!ctx->showedFullError && !pCacheRecord->isModified && ctx->numModifiedBlocks >= NUM_CACHE_BLOCKS - 2) { DisplayErrorString("\pWrite cache is full. Try rom disk X option."); subOff += copySize; subCount -= copySize; pCacheRecord->timestamp = ctx->ioCount; ctx->drvsts.writeProt = 0xFF; ctx->showedFullError = 1; return verErr; } else { if (copySize > (pCacheRecord->diskOffset + CACHE_BLOCK_SIZE) - subOff) copySize = (pCacheRecord->diskOffset + CACHE_BLOCK_SIZE) - subOff; CopyDiskDataFromIObuf(ctx, p->ioBuffer + subOff - off, pCacheRecord->pData + subOff - pCacheRecord->diskOffset, copySize); subOff += copySize; subCount -= copySize; pCacheRecord->timestamp = ctx->ioCount; pCacheRecord->hitCount++; if (!pCacheRecord->isModified) ctx->numModifiedBlocks++; pCacheRecord->isModified = 1; } } } } p->ioActCount = p->ioReqCount; d->dCtlPosition = off + p->ioReqCount; p->ioPosOffset = d->dCtlPosition; return noErr; } short RomDrvPrime(IOParamPtr p, DCtlPtr d) { long off; RomDrvContext *ctx; char startup; char ram; if (!d->dCtlStorage) { p->ioResult = offLinErr; return offLinErr; } ctx = *(RomDrvContext**)d->dCtlStorage; if (!ctx->drvsts.diskInPlace) { return offLinErr; } // on first call to Prime, setup the disk if (!ctx->initialized) { // initialize as a ready-only disk ctx->initialized = 1; // check the startup and ram disk preferences from the control panel // TBD: how do we know something else isn't using this area of PRAM? ReadXPRam(1, 4, &startup); ReadXPRam(1, 5, &ram); if (startup && 0) { if(ram) SetupRAMDisk(ctx, 1); // else continue as a read-only ROM disk } else { char diskmode = DrawIntroScreen(ctx); // confirm the block size if (diskmode > 0 && DiskIsBlockCompressed()) { unsigned long blockSize = ((unsigned long)kRomDrvLocation[8]) << 24 | ((unsigned long)kRomDrvLocation[9]) << 16 | ((unsigned long)kRomDrvLocation[10]) << 8 | ((unsigned long)kRomDrvLocation[11]); if (blockSize != CACHE_BLOCK_SIZE) { Str255 s; Str32 sd; PStrCpy(s, "\pCompressed image block size is not "); PUShortToStr(sd, CACHE_BLOCK_SIZE / 1024); PStrCat(s, sd); PStrCat(s, "\pK"); DisplayErrorString(s); } } // check which mode was selected if (diskmode == 0) { // disable the disk, by flagging it as not in place ctx->drvsts.diskInPlace = 0; EraseBox(); return offLinErr; } else if ((diskmode == 1 && DiskIsBlockCompressed()) || (diskmode == 2 && !DiskIsWholeCompressed())) { // R: create read-only disk directly from ROM, when disk image is compressed // A: create read/write disk with a small RAM cache char result = SetupRAMDisk(ctx, 1); if (result) DisplayDiskError(result); else if (diskmode == 2) ctx->drvsts.writeProt = 0; } else if (DiskIsWholeCompressed() || diskmode == 3) { // X: create read/write disk as a fully-RAM resident disk char result = SetupRAMDisk(ctx, 0); if (result) DisplayDiskError(result); else if (diskmode == 2 || diskmode == 3) ctx->drvsts.writeProt = 0; } EraseBox(); } } // now process the I/O request switch (p->ioPosMode & 0x000F) { case fsAtMark: off = d->dCtlPosition; break; case fsFromStart: off = p->ioPosOffset; break; case fsFromMark: off = d->dCtlPosition + p->ioPosOffset; break; default: break; } ctx->ioCount++; if ((p->ioTrap & 0x00ff) == aRdCmd) { short result = noErr; /* bit 6 indicates this should be a verify operation */ if (!(p->ioPosMode & 0x40)) { result = HandleDiskRead(ctx, p, d, off); } return result; } else if((p->ioTrap & 0x00ff) == aWrCmd && ctx->ramdisk) { return HandleDiskWrite(ctx, p, d, off); } SysBeep(0); return wPrErr; } short RomDrvClose(IOParamPtr /*p*/, DCtlPtr d) { RomDrvContext *ctx; if (!d->dCtlStorage) return noErr; ctx = *(RomDrvContext**)d->dCtlStorage; if (ctx->ramdisk) DisposePtr(ctx->ramdisk); DisposePtr(ctx->origcopyfunc); HUnlock(d->dCtlStorage); DisposeHandle(d->dCtlStorage); d->dCtlStorage = NULL; return noErr; } short main(IOParamPtr p, DCtlPtr d, short cmd) { switch(cmd) { case 0: return RomDrvOpen(p, d); case 1: return RomDrvPrime(p, d); case 2: if (((CntrlParamPtr)p)->csCode == 21) { *(Ptr*)&((CntrlParamPtr)p)->csParam = (Ptr)&DiskIcon; return noErr; } else if (((CntrlParamPtr)p)->csCode == 22) { *(Ptr*)&((CntrlParamPtr)p)->csParam = (Ptr)&DiskIcon; return noErr; } #if NEED_ACCRUN if (((CntrlParamPtr)p)->csCode == accRun) { RomDrvContext *ctx; if (!d->dCtlStorage) return noErr; ctx = *(RomDrvContext**)d->dCtlStorage; // if we want a ram disk, but haven't allocated one yet, do it now if (ctx->useram && !ctx->ramdisk) { // create a buffer for the RAM disk in the system heap // this doesn't seem to work reliabily - OK in System 7.0.1, but hangs at Finder in 7.1 ctx->ramdisk = NewPtrSys(UncompressedDiskSize()); if(ctx->ramdisk) { ctx->disk = (unsigned char *)ctx->ramdisk; FillRAMDisk(ctx); } else { ctx->useram = 0; } } d->dCtlDelay = 0; d->dCtlFlags &= ~dNeedTimeMask; return noErr; } #endif return controlErr; case 3: #if NEED_DRVSTAT if (!d->dCtlStorage) return statusErr; if(((CntrlParamPtr)p)->csCode == drvStsCode) { BlockMove(*d->dCtlStorage, &((CntrlParamPtr)p)->csParam, sizeof(DrvSts2)); return noErr; } #endif return statusErr; case 4: return RomDrvClose(p, d); default: return noErr; } } \ No newline at end of file