Ephemerboot/Patch Partition/Ephemerboot.c

698 lines
16 KiB
C
Executable File

//RAMBoot.c - boot 9 from RAM.
//©5/18/02 - 5/27/02 David "Potatoswatter" Krauss - v1.0.0c1
#include <InterruptSafeDebug.h>
#include <TradDriverLoaderLib.h>
#include <MoreDisks.h>
#include <A4Stuff.h>
#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 = (maxTrans<actTrans)? maxTrans : actTrans;
disk = gDiskWindowPtr + ( ioPen & 0xfff );
buff = pb->ioBuffer + 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;
}
}
}