/**************************************************************************** ** ** ** Start.c - Rettet CHIP-RAM, lädt und startet Exec, Exit. ** ** ** ***************************************************************************** ** ** ** Modification History ** ** -------------------- ** ** ** ** 19-May-89 CHW Created this file from Auto/Start.S ** ** 04-Jun-89 CHW Testet jetzt ob RAMDisk vorhanden ist ** ** 20-Jun-89 CHW Unterstützt jetzt 1MB CHIP-RAM wenn man's hat ** ** 21-Jun-89 CHW ENV-Variable 'RAMDISKBASE' implementiert ** ** 27-Jun-89 CHW Converted to genim2 ** ** 24-Aug-89 CHW Disk-Version implemented ** ** 27-Nov-89 CHW FastRAM implemented ** ** 15-Dec-89 CHW VBR wird nach 0 gelegt ** ** 30-Jan-90 CHW 1MB ChipRAM wird bei $a0000 statt $90000 getestet ** ** 03-Apr-90 CHW CiaKick eingebaut ** ** 24-Jul-90 CHW NoSave option eingebaut ** ** 03-Sep-90 CHW C-Version, ARP Parser, variable MemSize eingebaut ** ** 01-Oct-90 CHW CHIPSIZE-Option funktioniert jetzt ** ** 17-Oct-90 CHW CHIPSIZE-Option funktioniert wirklich :-) ** ** 23-Feb-91 CHW Läuft jetzt mit dem 2.0 ramdrive.device ** ** 09-May-91 RHS RamDrive Grösse wird jetzt richtig gelesen ** ** 16-Jun-91 CHH TimerB Bug behoben. ** ** 16-Jun-91 CHW/CHH Läuft jetzt unter 2.0 ("chip memory" :-() ** ** 29-Jul-20 CHW Aufgeräumt, VBR und SaveChipMem repariert ** ** ** ****************************************************************************/ #define VERBOSE #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* z.B. für __builtin_memcpy */ #include /* Für getreg und so */ #include extern void exit(long); extern void RawPrintfFunc(char *, ...); extern __regargs void *GetVBR(void); extern __regargs void SetVBR(register void *vbr); extern struct ExecBase *SysBase; extern struct DosLibrary *DOSBase; extern BPTR StdErr; /* Standard Error output stream */ extern BYTE NewOS; extern struct Custom volatile __far custom; extern char ExecModuleStart,ExecModuleEnd; struct GfxBase *GfxBase; struct IntuitionBase *IntuitionBase; char ident[] = "$VER: Start V5.0 (" __DATE__ ") by Christian A. Weber"; char CLI_Template[] = "NS=NOSAVE/S,NF=NOFAST/S,CS=CHIPSIZE/N"; char CLI_Help[] = "Usage: Start [NOSAVE] [NOFAST] [CHIPSIZE size]"; struct { LONG NoSave; LONG NoFast; LONG *ChipSizePtr; } argv; /***************************************************************************/ #define ABORT 0x1FFFFA /* Am Ende des CHIP RAMs */ #define DISKMAGIC 0x43485700 /* Currently 'CHW',0 */ #define INITMAGIC 0x494E4954 /* 'INIT' */ #define FFSMAGIC 0x444f5301 /* 'DOS',1 */ #define local struct RUN /* 2.0 RAD Unit-Struktur */ { struct MinNode Node; void *MemPtr; UWORD MatchWord; }; struct Mem { struct Mem *Next; void *Address; ULONG Size; } *chipmemlist; /* Liste der geretteten CHIP-Blöcke */ UBYTE *radmem; /* Startadresse der RAD-Disk */ ULONG radsize; /* Grösse der RAD-Disk */ ULONG radunit; /* Unit-Nummer der RAD-Disk */ UBYTE *fastbase; /* Startadresse des FAST-RAMs für Exec */ ULONG fastsize; /* Grösse des FAST-RAMs für Exec */ struct Screen *screen; /* Wir öffnen einen Customscreen um Picasso- oder UAE-Screenmodes abzuschalten */ UWORD dmaconsave,intenasave; ULONG attnflags,vblankfreq,sysbplcon0; ULONG oldcacr; void *oldvbr; ULONG oldssp,oldusp; /* Gerettete Supervisor- und User-Stackpointer */ ULONG stacktop; /* Obergrenze des Chip-RAMs für Exec */ #ifdef DEBUG /***************************************************************************/ /* Auf Maustaste warten und dabei Farbe ausgeben */ local void Maus(UWORD col) { LONG i; while((*(volatile UBYTE *)0xbfe001)&0x40) custom.color[0]=col; while(!((*(volatile UBYTE *)0xbfe001)&0x40)) ; for(i=0; i<200000; ++i) custom.color[0]=(UWORD)i; custom.color[0]=0; } #endif /***************************************************************************/ /* Gerettetes CHIP-RAM zurückkopieren */ local void RestoreChipRAM(void) { struct Mem *mc; for(mc=chipmemlist; mc; mc=mc->Next) memcpy(mc->Address,mc+1,mc->Size); } /***************************************************************************/ /* Save-Buffers des CHIP-RAMs freigeben */ local void FreeChipRAMSaveBuffers(void) { struct Mem *mc,*next; LONG size=0; for(mc=chipmemlist; mc; mc=next) { size+=mc->Size; next=mc->Next; FreeMem(mc,mc->Size+sizeof(*mc)); } chipmemlist = NULL; } /***************************************************************************/ /* Alles allozierte CHIP-RAM retten und in eine Liste eintragen */ local BOOL SaveChipRAM(void) { struct MemHeader *mrh; struct MemChunk *mc; struct Mem *dc, *olddc = (struct Mem *)&chipmemlist; UBYTE *chipBlockStart = NULL; /* Retten von Adresse 0 an */ ULONG size; BOOL done = FALSE; if(!(mrh=(struct MemHeader *)FindName(&SysBase->MemList,"Chip Memory"))) { if(!(mrh=(struct MemHeader *)FindName(&SysBase->MemList,"chip memory"))) { Enable(); DisownBlitter(); Puts("Can't find the Chip Memory header"); return FALSE; } } /* Alle nicht freien Memory-Bereiche retten */ for (mc = mrh->mh_First; !done; mc = mc->mc_Next) { /* Am Schluss muss noch der Bereich bis ans Ende des Chip RAMs gerettet werden */ if (mc == NULL) { mc = (struct MemChunk *)SysBase->MaxLocMem; /* auf UAE mit 4MB Chip-RAM ist MaxLocMem dubioserweise $200000 statt $400000, dann sind wir fertig. */ if ((UBYTE *)mc < chipBlockStart) { RawPrintfFunc("All done.\n"); break; } RawPrintfFunc("mc is null, now saving from $%08lx to MaxLocMem ($%08lx)\n", chipBlockStart, SysBase->MaxLocMem); done = TRUE; } /* Wir retten das RAM zwischen den mc-Bereichen und den mc selbst. */ size = (UBYTE *)mc - chipBlockStart + sizeof (*mc); if (dc = AllocMem(size + sizeof(*dc), MEMF_FAST)) { #ifdef VERBOSE RawPrintfFunc("Saving $%06lx-$%06lx (%lu bytes) to $%08lx\n", chipBlockStart, chipBlockStart + size-1, size, dc); #endif dc->Next = NULL; dc->Address = (void *)chipBlockStart; dc->Size = size; CopyMem(chipBlockStart, (void *)(dc+1), size); chipBlockStart = (UBYTE *)mc + mc->mc_Bytes; olddc->Next = dc; olddc = dc; } else { Enable(); //DisownBlitter(); #ifdef VERBOSE RawPrintfFunc("Can't allocate %lu bytes FAST RAM to save $%06lx-$%06lx\n", size, chipBlockStart, chipBlockStart + size-1); #endif printf("Can't allocate %lu bytes FAST RAM to save $%06lx-$%06lx\n", size, chipBlockStart, chipBlockStart + size-1); FreeChipRAMSaveBuffers(); return FALSE; } } return TRUE; } /***************************************************************************/ /* CIA-Resource ankicken */ local void KickResource(char *name) { UBYTE *ciabase=(UBYTE *)FindName(&SysBase->ResourceList,name); ciabase[0x29] = 0x7F; /* Alle Interrupt-Request-Bits setzen */ } /***************************************************************************/ /* Alles freigeben, back to DOS */ __saveds void __asm ExitRoutine(register __d0 ULONG D0, register __d1 ULONG D1, register __a0 void *A0, register __a1 void *A1) { int i; static char text[100]; putreg(REG_A7,oldusp-256); /* Temporärer Stack auf unserem Userstack */ custom.intena = 0x7FFF; /* Alle Interrupts sperren */ custom.dmacon = 0x7FFF; /* DMA abschalten */ custom.color[0] = 0x173; /* Grünlich */ strcpy(text,*(void **)0x110); /* ROMCrack-Text retten */ #if 0 memset(NULL,0xAA,stacktop); /* CHIP-RAM löschen mit $AA */ #endif custom.color[0] = 0x713; /* Rötlich */ RestoreChipRAM(); /* Und CHIP-RAM wieder restoren */ /* AB HIER IST DAS BETRIEBSSYSTEM WIEDER VORHANDEN */ UserState((void *)oldssp); /* Zurück in den Usermode */ custom.cop1lc = (ULONG)GfxBase->copinit; /* Bild wieder einschalten */ custom.dmacon = dmaconsave | DMAF_SETCLR; /* Original dmacon zurückholen */ custom.intena = intenasave | INTF_SETCLR; /* Dito mit intena */ for(i=0; i<8; ++i) custom.spr[i].dataa = custom.spr[i].datab=0; SetVBR(oldvbr); SetCACR(oldcacr); WaitBlit(); //DisownBlitter(); Enable(); RemakeDisplay(); if (screen) { CloseScreen(screen); screen = NULL; } FreeChipRAMSaveBuffers(); if (fastbase) { FreeMem(fastbase,fastsize); fastbase=NULL; } KickResource(CIABNAME); /* CIA-Resources ankicken (alle Interrupts auslösen) */ KickResource(CIAANAME); *(UBYTE *)0xbfed01=0x82; printf("Exec returned: %s\nD0=%08lx D1=%08lx A0=%08lx A1=%08lx\n",text,D0,D1,A0,A1); CloseLibrary((struct Library *)IntuitionBase); CloseLibrary((struct Library *)GfxBase); exit(RETURN_OK); } /***************************************************************************/ int GetDriveVars(char *drive) { struct DeviceNode *ldn; int found=FALSE; Forbid(); for(ldn=BADDR(((struct DosInfo *)BADDR(((struct RootNode *)DOSBase->dl_Root)->rn_Info))->di_DevInfo); ldn; ldn=BADDR(ldn->dn_Next)) { if((ldn->dn_Type==DLT_DEVICE) && (ldn->dn_Startup>0x40)) { struct FileSysStartupMsg *fs = BADDR(ldn->dn_Startup); struct DosEnvec *de = BADDR(fs->fssm_Environ); char *name=(UBYTE *)BADDR(ldn->dn_Name); int i; for(i=0; i< *name; ++i) if((name[i+1]&0xDF) != (drive[i]&0xDF)) goto next; if((drive[i] != ':') && drive[i] != '\0') goto next; radsize = ((de->de_HighCyl) - (de->de_LowCyl) +1 )*de->de_BlocksPerTrack*de->de_Surfaces; radsize <<= 9; /* blocks -> bytes */ radunit = fs->fssm_Unit; found=TRUE; break; } next: ; } while(ldn=BADDR(ldn->dn_Next)) ; Permit(); return found; } /***************************************************************************/ /* Hauptprogramm */ LONG Main(LONG arglen, char *argline) { struct IOStdReq RADIO; ULONG usestacktop; Puts(ident+6); GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0); IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0); if(GetDriveVars("EXEC:")==FALSE) { Puts("Würden Sie bitte gütigerweise das EXEC mounten?!"); return RETURN_ERROR; } if(!OpenDevice("ramdrive.device",radunit,(struct IORequest *)&RADIO,0)) { radok: /* Startadresse rausfinden */ radmem = ((struct RUN *)(RADIO.io_Unit))->MemPtr; if(((struct RUN *)(RADIO.io_Unit))->MatchWord != 0x4AFC) Puts("WARNING: No resident tag!"); CloseDevice((struct IORequest *)&RADIO); if(*(ULONG *)radmem == FFSMAGIC) /* 'DOS1' am Anfang ? */ { ULONG execentry; RawPrintfFunc("RAMDrive: $%08lx (%ldK)\n",radmem,radsize>>10); usestacktop = stacktop = (ULONG)SysBase->MaxLocMem; if(argv.ChipSizePtr) { usestacktop = *argv.ChipSizePtr << 10; if((usestacktop<100000) || (usestacktop>stacktop)) { Puts("Bad CHIP size, please try again!"); return RETURN_ERROR; } } RawPrintfFunc("Chip RAM: $00000000 (%ldK)\n",usestacktop>>10); if (!(screen = OpenScreenTags(NULL, SA_Width,320, SA_Height,200, SA_Depth,1, SA_Type,CUSTOMSCREEN, TAG_DONE))) { Puts("Can't open screen!"); ExitRoutine(); } if(!argv.NoFast) /* Grössten freien FAST-RAM-Block reservieren */ { if(fastsize = AvailMem(MEMF_FAST|MEMF_LARGEST) & ~0xff) { /* Platz lassen für gerettetes Chip-Ram und 10K Reserve */ fastsize -= (stacktop-AvailMem(MEMF_CHIP)+10000); /* Mehr als 2MB Fast-RAM gibt's nicht. Sei sparsam! */ if (fastsize > 2000000) fastsize = 2000000; if((fastsize >= 10000L) && (fastbase = AllocMem(fastsize,MEMF_FAST))) { RawPrintfFunc("Fast RAM: $%08lx (%ldK)\n",fastbase,fastsize>>10); } else { RawPrintfFunc("Not enough FAST RAM available (largest: %ld)", fastsize); fastsize = 0; } } else Puts("No FAST RAM available."); } /* AB HIER DARF IM CHIP-RAM NICHTS MEHR VERÄNDERT WERDEN */ //OwnBlitter(); WaitBlit(); Disable(); /* System-Status für MyExec merken/retten etc. */ dmaconsave = custom.dmaconr&~DMAF_SPRITE; intenasave = custom.intenar&~INTF_INTEN; attnflags = SysBase->AttnFlags; vblankfreq = SysBase->VBlankFrequency; sysbplcon0 = GfxBase->system_bplcon0; oldcacr = GetCACR(); /* Altes CACR retten */ oldvbr = GetVBR(); /* Altes VBR retten */ oldusp = getreg(REG_A7); /* Alten User-Stack retten */ if(!argv.NoSave) /* CHIP-RAM retten */ { if(!SaveChipRAM()) return RETURN_ERROR; } else Puts("CHIP RAM will not be saved."); SetCACR(0L); /* Alle Cache off */ SetVBR(NULL); /* VBR nach 0 legen */ /* AB HIER KEIN BETRIEBSSYSTEM MEHR!! */ oldssp = (ULONG)SuperState(); /* Supervisor-Mode auf Userstack */ putreg(REG_A7,usestacktop-80); /* Neuer Supervisor-Stackpointer */ RawPrintfFunc("Superstate initiated. New SP=$%08lx\n", usestacktop-80); custom.intena = 0x7FFF; /* Interrupts sperren */ custom.dmacon = 0x7FFF; /* Und DMA auch */ custom.color[0] = 0x400; /* Bildschirm dunkelrot */ #if 0 memset(NULL,0,usestacktop); /* CHIP-RAM löschen */ #endif /* GameExec installieren an Adresse 0 */ RawPrintfFunc("Installing GameExec (%ld bytes)... ", &ExecModuleEnd-&ExecModuleStart); memcpy(NULL,&ExecModuleStart,&ExecModuleEnd-&ExecModuleStart); RawPrintfFunc("done.\n"); for(execentry=0; *(ULONG *)execentry!=INITMAGIC; execentry+=2) /* Entry suchen */ ; execentry += 4; if(argv.NoSave) /* Kein Save -> ABORT macht ColdReboot() */ { *(ULONG *)ABORT = 0x4EF80008+execentry; /* JMP<<16+4+4=2.Vektor */ } else { *(UWORD *)ABORT = 0x4EF9; /* Rücksprung-JMP */ *(void **)(ABORT+2) = (void *)ExitRoutine; /* Cleanup-Routine */ } custom.color[0] = 0xF00; /* Bildschirm rot */ { register void (* __asm init)( register __d0 LONG, register __d1 LONG, register __d2 LONG, register __d3 LONG, register __a0 void *,register __a1 void *, register __a2 void *,register __a3 void *); RawPrintfFunc("\n%s: Running Exec at $%08lx ...\r\n", ident+6, execentry); init = (void *)execentry; init( attnflags, /* D0 */ sysbplcon0, /* D1 */ vblankfreq, /* D2 */ (LONG)"MainPrg", /* D3 : MainPrg-Name */ radmem, /* A0 : RAD-Startadresse */ (void *)radsize, /* A1 : RAD-Grösse */ fastbase, /* A2 : FAST-Startadresse */ fastbase+fastsize /* A3 : FAST-Endadresse */ ); ExitRoutine(); /* not reached */ } } else Puts("Du musst eine FFS-RamDisk haben, du Depp!"); } else if(!OpenDevice("ffsdrive.device",radunit,(struct IORequest *)&RADIO,0)) goto radok; else Puts("Can't open ramdrive.device or ffsdrive.device"); return RETURN_OK; }