//RAMBoot.c - boot 9 from RAM. //©5/18/02 - 5/27/02 David "Potatoswatter" Krauss - v1.0.0c1 #include #include #include #include #pragma parameter __D0 VMMap( __A0, __A1 ) OSErr VMMap( UInt32 log, UInt32 phys ) TWOWORDINLINE( 0x7007, 0xfe0a ); #pragma parameter __D0 VMUnmap( __A0, __A1 ) OSErr VMUnmap( UInt32 log, UInt32 valid ) TWOWORDINLINE( 0x7008, 0xfe0a ); Ptr gWindowStor; UInt32 gWindowPage; Ptr gDiskWindowPtr; Ptr gSumWindowPtr, gSum2WindowPtr; struct { UInt8 flags[4]; DrvQEl dqe; } gMyDQE; UInt32 gActualSize = 0; typedef struct PhysRun { UInt32 startPage; UInt32 numBytes; } PhysRun; PhysRun *gRuns; UInt32 gNumRuns; enum { kPageSize = 0x1000, kPageBits = 0xfffff000, kSumBoxVolume = kPageSize, // one page per sum box kSumBoxVolumeLog2 = 12, kSumBoxSide = 8, // box is square array of lattices kSumBoxSideLog2 = 3, kSumBoxDimensions = 4, // plus one more for depth kSumBoxDepth = 1, // bytes, tho the true depth is in bits kSumBytesPerPage = kSumBoxSide * kSumBoxDimensions * kSumBoxDepth, kSumRatio = kSumBoxVolume / kSumBytesPerPage, kMaxDimensions = kSumBoxDimensions }; Ptr gCurSumPtr; UInt32 gCurSumPhys; UInt32 gSumBase; Ptr gCurSum2Ptr; UInt32 gCurSum2Phys; UInt32 gSum2Base; Ptr gCurSum3Ptr; Ptr gSum3Ptr; UInt32 gSum3Size; Ptr gSum3Str; UInt32 gSum3StrSize; const char gTreeChosen[] = "Devices:device-tree:chosen"; const char gPhysRunsProp[] = "ramboot-phys-ranges"; const char gTreeOptions[] = "Devices:device-tree:options"; const char gSumPropertyName[] = "ramboot-checksum"; RegEntryID gOptionsEntry; extern pascal OSErr main(void); extern void DriverHeader(); extern OSErr DriverOpen(); extern OSErr DriverClose(); extern OSErr DriverPrime( IOParamPtr:__a0, DCtlPtr:__a1 ); extern OSErr DriverStatus( CntrlParamPtr:__a0, DCtlPtr:__a1 ); extern OSErr DriverControl( CntrlParamPtr:__a0, DCtlPtr:__a1 ); extern pascal OSErr GestaltProc( UInt32, SInt32 * ); extern void MapDisk( UInt32, Boolean ); extern void UnmapDisk( void ); extern void WriteDiskChecksum( void ); extern void MakeDiskChecksum( Ptr in, Ptr out ); extern void MakeChecksum( Ptr in, Ptr out, UInt32 side, int dimensions ); extern void CorrectDisk( Ptr, Ptr, Ptr, UInt32, int ); extern void PrintHex( UInt32, int ); void PrintHex( UInt32 num, int size ) { char out[8]; int ccnt = size; while ( ccnt-- > 0 ) { int nibble; nibble = ( num >> ( ccnt * 4 ) ) & 0xf; out[7-ccnt] = (nibble<10)? nibble+'0' : nibble-10+'a'; } ISDebugText( (UInt8 *) out + 8 - size, size ); } extern pascal OSErr main() { OSErr err = noErr; SInt16 myRN; Boolean diskInited; SInt32 dl; EnterCodeResource(); InitInterruptSafeDebug(); ISDebugStr( "\pRAMB05" ); if ( GetToolTrapAddress( 0xabe9 ) == GetToolTrapAddress( _Unimplemented ) ) err = paramErr; if ( err == noErr ) { OSErr gerr; gerr = Gestalt( '¨mb0', &dl ); if ( gerr == noErr ) { ISDebugStr( "\pRAMBoot: deferred by Gestalt" ); err = paramErr; } else err = NewGestalt( '¨mb0', &GestaltProc ); } if ( err == noErr ) { RegEntryID chosenRE; RegistryEntryIDInit( &chosenRE ); { err = RegistryCStrEntryLookup( NULL, gTreeChosen, &chosenRE ); } if ( err == noErr ) { err = RegistryPropertyGetSize( &chosenRE, gPhysRunsProp, &gNumRuns ); if ( err ) ISDebugStr( "\pRAMBoot: RAM disk space not reserved. Please reinstall." ); } if ( err == noErr ) { gRuns = (PhysRun *) NewPtrSys( gNumRuns ); err = MemError(); } if ( err == noErr ) { int rcnt; err = RegistryPropertyGet( &chosenRE, gPhysRunsProp, gRuns, &gNumRuns ); gNumRuns /= sizeof( PhysRun ); for ( rcnt = 0; rcnt < gNumRuns; rcnt++ ) { gRuns[rcnt].startPage /= 0x1000; } for ( rcnt = 0; rcnt < gNumRuns; rcnt++ ) { gActualSize += gRuns[rcnt].numBytes; } } RegistryEntryIDDispose( &chosenRE ); } if ( err == noErr ) { gWindowStor = NewPtrSys( kPageSize * 4 - 1 ); // 3 pages + padding err = MemError(); if ( err == noErr ) { gDiskWindowPtr = (Ptr) ( ( (UInt32) gWindowStor + kPageSize-1 ) & kPageBits ); LockMemory( gDiskWindowPtr, kPageSize * 3 ); gWindowPage = (UInt32) gDiskWindowPtr / kPageSize; PrintHex( gWindowPage, 8 ); gSumWindowPtr = gDiskWindowPtr + kPageSize; gSum2WindowPtr = gSumWindowPtr + kPageSize; } if ( err == noErr ) { PhysRun *lastRun = &gRuns[gNumRuns-1]; UInt32 sumSize, sum2Size; #define PaddedSumSize( x ) ( ( ( ( ( x + kPageSize-1 ) / kPageSize ) * kSumBytesPerPage ) + kPageSize-1 ) & kPageBits ) sumSize = PaddedSumSize( gActualSize - ( gActualSize / kSumRatio ) ); sum2Size = PaddedSumSize( sumSize ); gActualSize -= sumSize + sum2Size; lastRun->numBytes -= sumSize + sum2Size; gSumBase = ( lastRun->startPage * kPageSize ) + lastRun->numBytes; gSum2Base = gSumBase + sumSize; gSum3Size = ( sum2Size / kPageSize ) * kSumBytesPerPage;// PaddedSumSize( sum2Size ); gSum3StrSize = gSum3Size * 2; PrintHex( gSum3StrSize, 4 ); #undef PaddedSumSize } if ( err == noErr ) { RegistryEntryIDInit( &gOptionsEntry ); if ( err == noErr ) { err = RegistryCStrEntryLookup( NULL, gTreeOptions, &gOptionsEntry ); } if ( err == noErr ) { gSum3Ptr = NewPtrSysClear( gSum3Size ); err = MemError(); } if ( err == noErr ) { gSum3Str = NewPtrSysClear( gSum3StrSize ); err = MemError(); } if ( err == noErr ) { UInt32 actSize = gSum3StrSize; err = RegistryPropertyGet( &gOptionsEntry, gSumPropertyName, gSum3Str, &actSize ); if ( err==noErr && actSize != gSum3StrSize ) { ISDebugStr( "\pSum3 size changed?!" ); PrintHex( actSize, 4 ); } } if ( err == noErr ) { int bcnt; Ptr pen = gSum3Str; for ( bcnt = 0; bcnt < gSum3Size; bcnt++ ) { int nibble = *pen++; nibble -= nibble>='a'? 'a'-10 : '0'; gSum3Ptr[bcnt] = nibble << 4; nibble = *pen++; nibble -= nibble>='a'? 'a'-10 : '0'; gSum3Ptr[bcnt] |= nibble; } } if ( err == nrNotFoundErr ) { err = noErr; diskInited = false; ISDebugStr( "\pRAMBoot: Master checksum not found. RAM disk data may be damaged." ); } else diskInited = true; } } if ( err == noErr /*&& diskInited*/ ) { UInt32 bcnt; char badSum[ kSumBytesPerPage ]; UnmapDisk(); if ( diskInited ) { ISDebugStr( "\pCorrecting checksum l2" ); for ( bcnt = 0; bcnt < gActualSize; bcnt += kPageSize * kSumRatio * kSumRatio ) { MapDisk( bcnt, true ); MakeDiskChecksum( gSum2WindowPtr, badSum ); PrintHex( *(UInt32*) gCurSum3Ptr, 8 ); PrintHex( *(UInt32*) badSum, 8 ); CorrectDisk( gSum2WindowPtr, gCurSum3Ptr, badSum, kSumBoxSide, kSumBoxDimensions ); UnmapDisk(); } } ISDebugStr( "\pCorrecting checksum l1" ); for ( bcnt = 0; bcnt < gActualSize; bcnt += kPageSize * kSumRatio ) { MapDisk( bcnt, true ); MakeDiskChecksum( gSumWindowPtr, badSum ); CorrectDisk( gSumWindowPtr, gCurSum2Ptr, badSum, kSumBoxSide, kSumBoxDimensions ); UnmapDisk(); } ISDebugStr( "\pCorrecting disk" ); for ( bcnt = 0; bcnt < gActualSize; bcnt += kPageSize ) { MapDisk( bcnt, true ); MakeDiskChecksum( gDiskWindowPtr, badSum ); PrintHex( *(UInt32*) badSum, 8 ); CorrectDisk( gDiskWindowPtr, gCurSumPtr, badSum, kSumBoxSide, kSumBoxDimensions ); UnmapDisk(); } } if ( err == noErr ) { gActualSize /= 512; err = TradInstallDriverFromPtr( (DRVRHeaderPtr) &DriverHeader, 48, 127, &myRN ); } if ( err == noErr ) { ISDebugStr( "\pinstalled drvr" ); err = OpenDriver( "\p.RAMB0", &myRN ); } if ( err == noErr ) { // find the boot drive & link in after it gMyDQE.flags[0] = 0; // unlocked gMyDQE.flags[1] = 8; // nonejectable gMyDQE.flags[2] = 0; // reserved gMyDQE.flags[3] = 0; // n/a gMyDQE.dqe.dQDrive = MoreFindFreeDriveNumber( 8 ); gMyDQE.dqe.dQRefNum = myRN; gMyDQE.dqe.dQFSID = 0; gMyDQE.dqe.qType = 1; gMyDQE.dqe.dQDrvSz = (UInt16) gActualSize; gMyDQE.dqe.dQDrvSz2 = (UInt32) gActualSize >> 16; Enqueue( (QElemPtr) &gMyDQE.dqe, GetDrvQHdr() ); if ( /*!LMGetBootDrive() &&diskInited */true ) { ISDebugStr( "\pSet boot" ); LMSetBootDrive( gMyDQE.dqe.dQDrive ); } ISDebugStr( "\pLoaded drvr" ); } ExitCodeResource(); return noErr; } asm void DriverHeader() { dc.w dNeedLockMask | dStatEnableMask | dCtlEnableMask | dReadEnableMask | dWritEnableMask | dNeedTimeMask dc.w 0 // delay dc.w 0 // evt mask dc.w 0 // menu dc.w 0x1a dc.w 0x1e dc.w 0x28 dc.w 0x32 dc.w 0x3c dc.b "\p.RAMB0" @open: jmp DriverOpen @prime: movem.l a0/a1, -(sp) jsr DriverPrime bra.s @finish @control: movem.l a0/a1, -(sp) jsr DriverControl bra.s @finish @status: movem.l a0/a1, -(sp) jsr DriverStatus bra.s @finish @close: jmp DriverClose @finish: movem.l (sp)+, a0/a1 move.w 6 (a0), d1 // PB.ioTrap btst # noQueueBit, d1 bne.s @rtn move.l 0x8fc, -(sp) // jIODone @rtn: move.w d0, 0x10 (a0) // PB.ioResult rts } extern OSErr DriverOpen() { return noErr; } extern OSErr DriverPrime( IOParamPtr pb:__a0, DCtlPtr dce:__a1 ) { OSErr err = noErr; UInt32 ioPen; int bcnt; EnterCodeResource(); //ISDebugStr( ( pb->ioTrap & 0xff ) == aRdCmd? "\pR" : (/*Debugger(),*/ "\pW") ); pb->ioActCount = 0; while ( pb->ioActCount < pb->ioReqCount ) { UInt32 maxTrans, actTrans; Ptr disk, buff; Boolean read; read = ( pb->ioTrap & 0xff ) == aRdCmd; ioPen = dce->dCtlPosition + pb->ioActCount; MapDisk( ioPen, !read ); maxTrans = kPageSize - ( ioPen & (kPageSize-1) ); actTrans = pb->ioReqCount - pb->ioActCount; actTrans = (maxTransioBuffer + pb->ioActCount; //PrintHex( actTrans, 4 ); //PrintHex( ioPen, 8 ); //PrintHex( gRuns[bcnt].startPage + ( ioPen >> 12 ), 5 ); //ISDebugText( (UInt8*) disk, 200 ); //ISDebugText( (UInt8*) buff, 4 ); if ( read ) { BlockMoveData( disk, buff, actTrans ); } else { BlockMoveData( buff, disk, actTrans ); WriteDiskChecksum(); } UnmapDisk(); pb->ioActCount += actTrans; } //ISDebugStr( "\pDone" ); if ( err ) ISDebugStr( "\p(err)" ); ExitCodeResource(); return err; } extern OSErr DriverControl( CntrlParamPtr pb:__a0, DCtlPtr dce:__a1 ) { OSErr err; EnterCodeResource(); //ISDebugStr( "\pC" ); switch( pb->csCode ) { case kFormat: { { gSum3Ptr = NewPtrSysClear( gSum3Size ); err = MemError(); if ( err == noErr ) { RegistryPropertyDelete( &gOptionsEntry, gSumPropertyName ); err = RegistryPropertyCreate( &gOptionsEntry, gSumPropertyName, gSum3Ptr, gSum3Size ); } } if ( err == noErr ) { UInt32 pcnt, lcnt; for ( pcnt = 0; pcnt < gActualSize * 512; pcnt += kPageSize ) { MapDisk( pcnt, true ); for ( lcnt = 0; lcnt < kPageSize; lcnt += sizeof(long) ) * (UInt32 *) &gDiskWindowPtr[lcnt] = 0; UnmapDisk(); } for ( pcnt = 0; pcnt < gActualSize * 512; pcnt += kPageSize * kSumRatio ) { MapDisk( pcnt, true ); for ( lcnt = 0; lcnt < kPageSize; lcnt += sizeof(long) ) * (UInt32 *) &gSumWindowPtr[lcnt] = 0; UnmapDisk(); } for ( pcnt = 0; pcnt < gActualSize * 512; pcnt += kPageSize * kSumRatio * kSumRatio ) { MapDisk( pcnt, true ); for ( lcnt = 0; lcnt < kPageSize; lcnt += sizeof(long) ) * (UInt32 *) &gSum2WindowPtr[lcnt] = 0; UnmapDisk(); } } break; } case kVerify: err = noErr; break; case accRun: err = PostEvent( diskEvt, gMyDQE.dqe.dQDrive ); dce->dCtlFlags &= ~dNeedTimeMask; break; default: PrintHex( pb->csCode, 4 ); err = controlErr; break; } ExitCodeResource(); return err; } extern OSErr DriverStatus( CntrlParamPtr pb:__a0, DCtlPtr dce:__a1 ) { OSErr err; EnterCodeResource(); //ISDebugStr( "\pS" ); switch( pb->csCode ) { case kReturnFormatList: pb->csParam[0] = 1; (* (UInt32 **) &pb->csParam[1])[0] = gActualSize; (* (UInt32 **) &pb->csParam[1])[1] = 0; err = noErr; break; default: PrintHex( pb->csCode, 4 ); err = statusErr; break; } ExitCodeResource(); return err; } extern OSErr DriverClose() { return noErr; } extern pascal OSErr GestaltProc( UInt32, SInt32 *resp ) { *resp = 0; return noErr; } extern void MapDisk( UInt32 pos, Boolean sumToo ) { { int bcnt; UInt32 pen; for ( bcnt = 0, pen = pos; bcnt < gNumRuns && gRuns[bcnt].numBytes <= pen; bcnt++ ) { pen -= gRuns[bcnt].numBytes; } if ( bcnt == gNumRuns ) { return; } VMMap( gWindowPage, gRuns[bcnt].startPage + ( pen / kPageSize ) ); } if ( sumToo ) { UInt32 sumPos, sum2Pos; { sumPos = ( pos / kPageSize ) * kSumBytesPerPage; gCurSumPhys = gSumBase + sumPos; VMMap( gWindowPage + 1, gCurSumPhys / kPageSize ); gCurSumPtr = gSumWindowPtr + ( gCurSumPhys & (kPageSize-1) ); } { sum2Pos = ( sumPos / kPageSize ) * kSumBytesPerPage; gCurSum2Phys = gSum2Base + sum2Pos; VMMap( gWindowPage + 2, gCurSum2Phys / kPageSize ); gCurSum2Ptr = gSum2WindowPtr + ( gCurSum2Phys & (kPageSize-1) ); } { gCurSum3Ptr = gSum3Ptr + ( sum2Pos / kPageSize ) * kSumBytesPerPage; } } } extern void UnmapDisk( void ) { VMUnmap( gWindowPage, 0 ); VMUnmap( gWindowPage + 1, 0 ); VMUnmap( gWindowPage + 2, 0 ); } extern void WriteDiskChecksum( void ) { OSErr err; MakeDiskChecksum( gDiskWindowPtr, gCurSumPtr ); MakeDiskChecksum( gSumWindowPtr, gCurSum2Ptr ); MakeDiskChecksum( gSum2WindowPtr, gCurSum3Ptr ); { int bcnt; for ( bcnt = 0; bcnt < gSum3Size; bcnt++ ) { int nibble; nibble = ( gSum3Ptr[bcnt] >> 4 ) & 0xf; gSum3Str[bcnt * 2] = nibble>9? 'a'-10 : '0'; gSum3Str[bcnt * 2] += nibble; nibble = gSum3Ptr[bcnt] & 0xf; gSum3Str[bcnt * 2 + 1] = nibble>9? 'a'-10 : '0'; gSum3Str[bcnt * 2 + 1] += nibble; } err = RegistryPropertySet( &gOptionsEntry, gSumPropertyName, gSum3Str, gSum3StrSize ); } if ( err == noErr ) { err = RegistryPropertySetMod( &gOptionsEntry, gSumPropertyName, kRegPropertyValueIsSavedToNVRAM ); } if ( err ) { ISDebugStr( "\pcouldn't write nvsum" ); PrintHex( err, 4 ); } } extern void MakeDiskChecksum( Ptr in, Ptr out ) { MakeChecksum( in, out, kSumBoxSide, kSumBoxDimensions ); } extern void MakeChecksum( Ptr data, Ptr sumPtr, UInt32 side, int dimensions ) { int underBits, overBits, overStart, dcnt, sum; UInt32 underCount, overCount, ucnt, ocnt, lcnt, loff, off; underBits = 0; overBits = kSumBoxVolumeLog2 - kSumBoxSideLog2; for ( dcnt = 0; dcnt < dimensions; dcnt++ ) { underCount = 1 << underBits; overCount = 1 << overBits; overStart = underBits + kSumBoxSideLog2; for ( lcnt = 0; lcnt < kSumBoxSide; lcnt++ ) { sum = 0; loff = lcnt << underBits; for ( ocnt = 0; ocnt < overCount; ocnt++ ) { off = loff + ( ocnt << overStart ); for ( ucnt = 0; ucnt < underCount; ucnt++ ) { sum ^= data[ off + ucnt ]; } } *sumPtr++ = sum; } underBits += kSumBoxSideLog2; overBits -= kSumBoxSideLog2; } } extern void CorrectDisk( Ptr data, Ptr good, Ptr check, UInt32 side, int dimensions ) { int dcnt; UInt32 bcnt; UInt8 bad = 0; for ( bcnt = 0; bcnt < side; bcnt++ ) { if ( good[bcnt] != check[bcnt] ) { // if ( bad & (good[bcnt]^check[bcnt]) ) ISDebugStr( "\pToo many errors" ); bad |= good[bcnt] ^ check[bcnt]; } //PrintHex( good[bcnt], 2 ); //PrintHex( check[bcnt], 2 ); } if(bad)PrintHex( bad, 2 ); while ( bad ) { UInt32 coords[ kMaxDimensions ]; int cubex = bad & -bad; // what's bad & -bad? Bitwise arithmetic! Oh god it's 3:50 am. bad ^= cubex; for ( dcnt = 0; dcnt < dimensions; dcnt++ ) { Ptr gcr = &good[dcnt*side], ccr = &check[dcnt*side]; // good/check coordinate row coords[dcnt] = -1; for ( bcnt = 0; bcnt < side; bcnt++ ) { if ( ( gcr[bcnt] ^ ccr[bcnt] ) & cubex ) { if ( coords[dcnt] != -1 ) { ISDebugStr( "\px" ); coords[dcnt] = -1; break; } coords[dcnt] = bcnt; } } if ( coords[dcnt] == -1 ) { //ISDebugStr( "\p?" ); break; } } if ( dcnt != dimensions ) continue; // from above break; { UInt32 off = 0; UInt32 dcoeff = 1; for ( dcnt = 0; dcnt < dimensions; dcnt++ ) { off += dcoeff * coords[dcnt]; dcoeff *= side; } PrintHex( ( data[off] & cubex ) != 0, 1 ); data[off] ^= cubex; } } }