/* AUTODISK - program to copy floppy disk to RAM disk upon system boot, and also set the system clock. v 2.1 By Moshe Braner 880116 (can be linked to "mmdummy") FUNCTION This program is to be placed in the \AUTO folder on the boot disk, AFTER the RAMdisk program. (It assumes the RAM disk is already installed.) After asking the user for the current time and date, and setting the ST's two clocks accordingly, this program copies the whole floppy disk data, FATs, directory and all, onto the RAMdisk. (It first finds out which sector is the last one actually holding data, and copies all sectors up to that one.) The RAMdisk ID letter is first assumed to be M, but if no such drive is connected the letter is decremented to the first connected one. HINTS For best results: Freshly format a disk, make an AUTO directory, put in it first RAMDISK.PRG and then AUTODISK.PRG, then put on the disk all other files you want to load to the RAMdisk at boot time, but no others. You can set these files up in folders if you want: first make the folders, then put the files on the disk directly into the folders. For maximum speed do not make any deletions of files, nor copy files from the disk to itself. You may save the desktop (with the RAMdisk icon installed, and perhaps the RAMdisk's window open) on the disk, too. Make sure the RAMdisk is more than big enough to hold all those files. ACKNOWLEDGEMENTS This program made possible in part by Eric Terrell, who posted "eternal.s". The method of setting the ST's clocks is borrowed from "settime", posted by Allan Pratt of Atari. WARNINGS This program is for booting off a floppy disk, not hard disk. This program will not work with "copy protected" disk formats. */ #include #define SECSIZE 512 /* >>>> for now 512-byte sectors only */ #define WORD int /* 16 bits: 'int' in Megamax */ #define OK 0 #define READ 0 #define WRITE 1 #define RREAD 2 #define WWRITE 3 typedef struct bpb { WORD recsiz; WORD clsiz; WORD clsizb; WORD rdlen; WORD fsiz; WORD fatrec; WORD datrec; WORD numcl; WORD bflags; } BPB; #define fixup(s) (s[s[1]+2] = '\0') /* null-terminate a GEMDOS string */ /* * routine to send a one-shot media-definitely-changed * message to GEMDOS (via Rwabs). */ extern dmch(); extern drvnum(); asm{ dmch: MOVEA.W #0x476,A0 /* Rwabs() vector */ LEA oldvec(PC),A1 MOVE.L (A0),(A1) /* save old */ LEA tmpvec(PC),A1 MOVE.L A1,(A0) /* poke new */ RTS tmpvec: MOVE.W drvnum(PC),D0 CMP.W 14(A7),D0 /* target drive? */ BEQ.S now MOVE.L oldvec(PC),A0 /* do normal */ JMP (A0) now: MOVE.L oldvec(PC),0x476 /* restore normal Rwabs */ MOVEQ #-14,D0 /* "media has changed" */ RTS oldvec: DC.L 0 drvnum: DC.W 0 } /* * Print message and quit. */ error(msg) char msg[]; { Cconws(msg); Cconws("\007\r\n\n\tHit any key "); Cnecin(); _exit(0); } /* * Print a long integer as a string. */ prtli(n) register long n; { register char *p; char a[20]; p = &a[19]; *p = 0; do { *(--p) = (n%10) + '0'; n /= 10; } while (n); Cconws(p); } int strlen(s) char *s; { register int i=0; while (s[i++]); return (i-1); } int dotime(s) register char *s; { register int len; register int hour, minute, second; register WORD time; len = strlen(s); if (len < 4 || len == 5 || len > 6) goto badtime; hour = (s[0]-'0') * 10 + (s[1]-'0'); minute = (s[2]-'0') * 10 + (s[3]-'0'); if (len == 6) second = (s[4]-'0') * 10 + (s[5]-'0'); else second = 0; if (hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) goto badtime; time = (WORD)((hour << 11) | (minute << 5) | (second >> 1)); if (Tsettime(time) == 0) return (0); badtime: Cconws("\r\n\tIllegal time (bad format or out of range)\r\n"); return (1); } int dodate(s) register char *s; { register int len; register int month,day,year; register WORD date; len = strlen(s); if (len != 6) goto baddate; year = (s[0]-'0') * 10 + (s[1]-'0') - 80; month = (s[2]-'0') * 10 + (s[3]-'0'); day = (s[4]-'0') * 10 + (s[5]-'0'); if (year < 0 || year > 119 || month < 1 || month > 12 || day < 1 || day > 31) goto baddate; date = (WORD)((year << 9) | (month << 5) | day); if (Tsetdate(date) == 0) return (0); baddate: Cconws("\r\n\tIllegal date (bad format or out of range)\r\n"); return (1); } int ramd; /* RAMdisk ID --- global variable */ findrd() { register int mask; register long *p; p = (long *) 0x4C2; /* _drvbits */ mask = 1; ramd = 'M'-'A'; /* first assume the RAMdisk is M: */ mask <<= ramd; while (ramd>2 && ((*p)&mask)==0) { mask >>= 1; ramd -= 1; } } main() { register int i; register char *buf; int res, sec, secs; int bps, spc, dir, spd, spf, spt, bpc; int dat, drive, sides, chunk; char boot[SECSIZE], str[10]; int minute, hour, day, month, year; WORD date, time; long stack, datime; long memory, bytes, dinfo[4]; BPB *bpb; char *msg1 = "\r\n\tError reading disk!"; char *msg2 = "\r\n\tError writing to RAMdisk!"; Cconws("\033E\r\n\n\tAUTODISK 2.1\tby Moshe Braner\r\n\n"); /* see if IKBD time is valid */ datime = Gettime(); /* get ikbd date & time */ date = (WORD) (datime >> 16); time = (WORD) (datime & 0xffff); minute = ((time >> 5) & 0x3F); hour = ((time >> 11) & 0x1F); day = ((date ) & 0x1F); month = ((date >> 5) & 0x0F); year = ((date >> 9) & 0x3F); if (minute<60 && hour<24 && day<32 && day>0 && month<13 && month>0 && year>7) if (Tsetdate(date)==0 && Tsettime(time)==0) goto timedone; /* we want to prompt the user */ str[0] = 7; /* set up buffer for Cconrs call */ do { Cconws("\r\n\tEnter the time (hhmm[ss]): "); Cconrs(str); fixup(str); } while (dotime(str+2)); do { Cconws("\r\n\tEnter the date (yymmdd): "); Cconrs(str); fixup(str); } while (dodate(str+2)); /* get GEM's time */ datime = ((long)Tgetdate()<<16) + ((long)Tgettime()&0xffffL); Settime(datime); /* update the ikbd's time */ Cconws("\r\n"); timedone: Supexec(&findrd); if (ramd < 2) error("\r\n\tRAMdisk not found!"); i = ramd + 'A'; if (i != 'M') { Cconws("\r\n\tIs the RAMdisk drive "); Bconout(2,i); Cconws(" ? (y/n) "); i = Cnecin(); if (i!='y' && i!='Y') { Cconws("\r\n\tEnter RAMdisk drive letter:"); Cconws(" ('q' to quit) "); i = Cnecin(); if (i>='a' && i<='z') i += ('A' - 'a'); if (i=='Q' || i<'A' || i>'Z') _exit(0); ramd = i - 'A'; } } /* get disk parameters from bios parameter block */ drive = Dgetdrv(); /* use current drive */ bpb = (BPB *) Getbpb(drive); bps = bpb->recsiz; /* bytes per sector */ spc = bpb->clsiz; /* sectors per cluster */ bpc = bpb->clsizb; /* bytes per cluster */ dir = bpb->rdlen; /* length of dir in sectors */ spf = bpb->fsiz; /* sectors per FAT */ dat = bpb->datrec; /* no. of first data sector */ spd = (bpb->numcl) * spc; /* data sectors per disk */ /* adjust RAMdisk BPB */ bpb = (BPB *) Getbpb(ramd); /* RAMdisk BPB area */ if (bpb->recsiz != bps) error("\r\n\tDisk and RAMdisk incompatible!"); if (bpb->bflags & 0x8000) /* our own magic marker */ error("\r\n\tOld RAM disk!"); bpb->bflags |= 0x8000; bpb->clsiz = spc; bpb->clsizb = bpc; bpb->rdlen = dir; bpb->fsiz = spf; bpb->fatrec = spf + 1; bpb->datrec = dat; /* allocate RAM buffer */ memory = Malloc(-1L); if (memory < (spf*bps + 10000) || (buf = (char *)Malloc(memory)) <= 0) error("\r\n\tNot enough memory!"); /* copy the data from floppy to RAM */ Cconws("\r\n\tCopying data...\r\n"); secs = spf; /* read first FAT only */ sec = dat - dir - 2*spf; if (Rwabs (READ, buf, secs, sec, 0) != OK) error(msg1); i = 3*spd; /* >>>> 12-bit FAT entries */ i = 3 + i/spc/2; while (buf[--i] == 0); /* search for last used sector */ i *= spc*2; res = i/3; /* no. of data sectors to read */ if (res > spd) /* safety check */ res = spd; if (spc*bpb->numcl < res) error("\r\n\tNot enough space in RAMdisk!"); /* write FATs to destination */ secs = spf; sec = dat - dir - 2*spf; if (Rwabs (WRITE, buf, secs, sec, ramd) != OK) error(msg2); sec += secs; if (Rwabs (WRITE, buf, secs, sec, ramd) != OK) error(msg2); /* copy rest: root directory and DATA */ chunk = memory/bps; /* how many sectors fit in RAM */ sec = dat - dir; res += dir; while (res > 0) { if (chunk > res) chunk = res; if (Rwabs (RREAD, buf, chunk, sec, drive) != OK) error(msg1); if (Rwabs (WWRITE, buf, chunk, sec, ramd) != OK) error(msg2); sec += chunk; res -= chunk; } *((int *)&drvnum) = ramd; Supexec(&dmch); /* install media-HAS-changed code */ Dfree(dinfo,ramd+1); /* call it through GEMDOS */ Cconws("\r\n\tRAMdisk has "); bytes = dinfo[0] * spc * bps; prtli(bytes); Cconws(" bytes free out of "); bytes = dinfo[1] * spc * bps; prtli(bytes); Cconws("\r\n\n\tAUTODISK finished, no errors\r\n\n"); for (datime=0; datime<50000; datime++); }