home *** CD-ROM | disk | FTP | other *** search
- PROGRAM tst;
- {-read or infer critical disk parameters}
- {-check logical sector number calculations}
- TYPE
- drives = (A, B, C, D, E, F);
- drivedescr = RECORD
- BIOSnum, DOSnum, IDbyte : Byte;
- sectors, tracks, heads, secSize,
- alloUnits, secsPerAllo, bootOffset : Integer;
- END;
- drivearray = ARRAY[drives] OF drivedescr;
- sectorbuffer = ARRAY[1..512] OF Char;
- registers = RECORD
- CASE Integer OF
- 1 : (ax, bx, cx, dx, bp, si, di, ds, es, flags : Integer);
- 2 : (al, ah, bl, bh, cl, ch, dl, dh : Byte);
- END;
- VAR
- DR : drivearray;
- reg : registers;
- lastch, ch : Char;
- sb : sectorbuffer;
- curdrive : drives;
- logsec, curhead, cursector, curtrack, error : Integer;
-
- PROCEDURE BIOSreadSectors(drive : Byte;
- sector, track, head : Integer;
- sects : Integer;
- VAR buffer : sectorbuffer;
- VAR error : Integer);
- {-execute int 13 to read disk via BIOS at low level}
- BEGIN
- reg.ax := $200 OR sects;
- reg.dl := drive;
- reg.dh := head;
- reg.ch := track AND 255;
- reg.cl := (sector AND 63) OR ((track SHR 8) SHL 6);
- reg.es := Seg(buffer);
- reg.bx := Ofs(buffer);
- Intr($13, reg);
- IF Odd(reg.flags AND 1) THEN BEGIN
- error := reg.ax SHR 8;
- WriteLn('disk read error# ', error);
- END ELSE
- error := 0;
- END; {biosreadsectors}
-
- PROCEDURE DOSreadSectors(drive : Byte;
- LSN : Integer;
- sects : Integer;
- VAR buffer : sectorbuffer;
- VAR error : Integer);
- {-execute int 25 to read disk through DOS at low level}
- BEGIN
- INLINE(
- $1E/ {PUSH DS}
- $8A/$46/$10/ {MOV AL,[BP+10]}
- $8B/$56/$0E/ {MOV DX,[BP+0E]}
- $8B/$4E/$0C/ {MOV CX,[BP+0C]}
- $C5/$5E/$08/ {LDS BX,[BP+08]}
- $CD/$25/ {INT 25}
- $72/$02/ {JB 0113}
- $31/$C0/ {XOR AX,AX}
- $9D/ {POPF }
- $1F/ {POP DS}
- $5D/ {POP BP}
- $C4/$7E/$04/ {LES DI,[BP+04]}
- $26/ {ES: }
- $89/$05 {MOV [DI],AX}
- );
- END; {int25}
-
- PROCEDURE DisplaySector(sb : sectorbuffer);
- {-write the read-in sector to screen}
- VAR
- i : Integer;
- ch : Char;
- BEGIN
- FOR i := 1 TO 512 DO BEGIN
- IF sb[i] IN [#10, #13, #32..#127] THEN
- Write(sb[i])
- ELSE
- Write('.');
- END;
- WriteLn;
- Write('press any key...'); Read(Kbd, ch); WriteLn;
- END; {displaysector}
-
- PROCEDURE GetDisk(drive : drives; VAR ddesc : drivedescr);
- {-get the physical parameters of a drive}
-
- FUNCTION isBIOSnum(drive : drives) : Byte;
- {-return the drive number that BIOS uses}
- BEGIN
- CASE Ord(drive) OF
- 0 : isBIOSnum := 0;
- 1 : isBIOSnum := 1;
- 2 : isBIOSnum := $80;
- 3 : isBIOSnum := $81;
- 4 : isBIOSnum := $82;
- 5 : isBIOSnum := $83;
- ELSE
- isBIOSnum := -1;
- END;
- END; {isbiosnum}
-
- FUNCTION isDOSnum(drive : drives) : Byte;
- {-return the drive number that DOS uses}
- BEGIN
- IF Ord(drive) IN [0, 1, 2, 3, 4, 5] THEN
- isDOSnum := Ord(drive)
- ELSE
- isDOSnum := -1;
- END; {isdosnum}
-
- PROCEDURE getFAT(DOSnum : Byte; VAR driveid : Byte;
- VAR secSize, alloUnits, secsPerAllo : Integer);
- {-read the FAT ID info for the specified drive}
- BEGIN
- reg.ah := $1C;
- reg.dl := DOSnum+1;
- MsDos(reg);
- secSize := reg.cx;
- alloUnits := reg.dx;
- secsPerAllo := reg.al;
- driveid := Mem[reg.ds : reg.bx];
- END; {getfat}
-
- PROCEDURE GetDriveParams(BIOSnum : Byte;
- VAR heads, sectors, tracks : Integer);
- {-read the BIOS drive parameters for the specified drive}
- BEGIN
- reg.ah := 8;
- reg.dl := BIOSnum;
- Intr($13, reg);
- IF Odd(reg.flags AND 1) THEN BEGIN
- WriteLn('error getting drive info for drive ', BIOSnum, '....');
- Halt;
- END;
- heads := 1+reg.dh;
- sectors := reg.cx AND 63;
- tracks := 1+(reg.ch OR ((reg.cl SHR 6) SHL 8));
- END; {getdriveparams}
-
- PROCEDURE ReadBootRecord(BIOSnum : Byte; VAR bootOffset : Integer);
- {-determine the offset to use between LSNs and physical sectors}
- TYPE
- partitionrecord = RECORD
- bootind, bhead, bsector, bcyl : Byte;
- systind, ehead, esector, ecyl : Byte;
- relsectl, relsecth : Integer;
- numsectl, numsecth : Integer;
- END;
- bootrecord = ARRAY[1..4] OF partitionrecord;
- VAR
- partition : Byte;
- bootrec : bootrecord;
- BEGIN
- BIOSreadSectors(BIOSnum, 1, 0, 0, 1, sb, error);
- IF error <> 0 THEN BEGIN
- WriteLn('could not read master boot record');
- Halt;
- END;
- {get the bootrecord out of the sector}
- Move(sb[447], bootrec, 66);
- {find the selected partition}
- partition := 0;
- REPEAT
- partition := Succ(partition);
- UNTIL (bootrec[partition].bootind = $80) OR (partition > 4);
- IF partition > 4 THEN BEGIN
- WriteLn('error, did not find a selected partition');
- Halt;
- END;
- {calculate the bootoffset}
- bootOffset := bootrec[partition].relsectl;
- IF bootrec[partition].relsecth <> 0 THEN
- WriteLn('unsupported disk: high word of relative sector offset not zero');
- END; {readbootrecord}
-
- BEGIN {getdisk}
- WITH ddesc DO BEGIN
- BIOSnum := isBIOSnum(drive);
- DOSnum := isDOSnum(drive);
- {read the FAT information}
- getFAT(DOSnum, IDbyte, secSize, alloUnits, secsPerAllo);
-
- IF (BIOSnum IN [0, 1]) THEN BEGIN
- {a floppy, use FAT ID code to set values}
- CASE IDbyte OF
- $FF : BEGIN
- heads := 2; sectors := 8;
- END;
- $FE : BEGIN
- heads := 1; sectors := 8;
- END;
- $FD : BEGIN
- heads := 2; sectors := 9;
- END;
- $FC : BEGIN
- heads := 1; sectors := 9;
- END;
- $F9 : BEGIN
- heads := 2; sectors := 15;
- END;
- $F8 : BEGIN
- WriteLn('hard drive unexpected for A or B....');
- Halt;
- END;
- END;
- tracks := 1+Trunc(Int(secsPerAllo*alloUnits)/Int(sectors*heads));
- bootOffset := 0;
- END ELSE IF (BIOSnum IN [$80, $81, $82, $83]) THEN BEGIN
- {a hard drive, use BIOS function}
- GetDriveParams(BIOSnum, heads, sectors, tracks);
- {also need to get the boot offset between BIOS and DOS sectors}
- ReadBootRecord(BIOSnum, bootOffset);
- END ELSE BEGIN
- {drive not known to BIOS}
- WriteLn('drive unknown to BIOS ');
- Halt;
- END;
- END; {with}
- END; {getdisk}
-
- PROCEDURE ShowDisk(drive : drives);
- {-display the physical parameters of a drive}
- VAR
- bytes : Real;
- ch : Char;
- BEGIN
- WITH DR[drive] DO BEGIN
- WriteLn;
- WriteLn('drive: ', Chr(Ord(DOSnum)+65));
- WriteLn(' BIOSnum = ', BIOSnum);
- WriteLn(' sectors = ', sectors);
- WriteLn(' tracks = ', tracks);
- WriteLn(' heads = ', heads);
- WriteLn(' secsize = ', secSize);
- WriteLn(' alloc units= ', alloUnits);
- WriteLn(' alloc size = ', secsPerAllo);
- WriteLn(' boot offset= ', bootOffset);
- bytes := 1.0*sectors*tracks*heads*secSize;
- WriteLn(' BIOS bytes = ', bytes : 8 : 0);
- bytes := 1.0*alloUnits*secsPerAllo*secSize;
- WriteLn(' DOS bytes = ', bytes : 8 : 0);
- END;
- WriteLn;
- Write('press any key...'); Read(Kbd, ch); WriteLn;
- WriteLn;
- END; {showdisk}
-
- FUNCTION LSN(drive : drives; sector, track, head : Integer) : Integer;
- {-return the logical sector number for a set of physical parameters}
- BEGIN
- WITH DR[drive] DO
- LSN := Pred(sector+sectors*(head+track*heads))-bootOffset;
- END; {lsn}
-
- PROCEDURE PhySect(drive : drives; LSN : Integer;
- VAR sector, track, head : Integer);
- {-return the physical drive parameters for a given lsn}
- VAR
- rem : Integer;
- BEGIN
- WITH DR[drive] DO BEGIN
- {correct for the boot partitioning}
- LSN := LSN+bootOffset;
- track := LSN DIV (sectors*heads);
- rem := LSN-track*sectors*heads;
- head := rem DIV sectors;
- rem := rem-head*sectors;
- sector := Succ(rem);
- END;
- END; {physect}
-
- FUNCTION TotSectors(drive : drives) : Real;
- {-return total number of sectors on drive}
- BEGIN
- WITH DR[drive] DO
- TotSectors := 1.0*heads*tracks*sectors-1.0;
- END; {totsectors}
-
- BEGIN
- ch := 'X';
-
- {loop for testing}
- WHILE True DO BEGIN
- lastch := ch;
- WriteLn;
- Write('Enter drive letter to read (X to quit): ');
- ReadLn(ch);
- IF UpCase(ch) = 'X' THEN Halt;
- curdrive := drives(Ord(UpCase(ch))-65);
-
- {initialize the drive descriptors}
- IF UpCase(ch) <> UpCase(lastch) THEN BEGIN
- GetDisk(curdrive, DR[curdrive]);
- ShowDisk(curdrive);
- END;
-
- {get a logical sector number}
- Write('Enter logical sector number to read: (0..',
- TotSectors(curdrive) : 0 : 0, '): ');
- ReadLn(logsec);
-
- {calculate physical sector parameters}
- PhySect(curdrive, logsec, cursector, curtrack, curhead);
-
- {read directly through BIOS}
- WriteLn('BIOS RESULTS');
- BIOSreadSectors(DR[curdrive].BIOSnum, cursector, curtrack, curhead, 1, sb, error);
- IF error = 0 THEN DisplaySector(sb);
-
- {read through DOS low level facilities}
- WriteLn;
- {check calculation both ways}
- IF logsec <> LSN(curdrive, cursector, curtrack, curhead) THEN
- WriteLn('sector conversion error');
- WriteLn('DOS RESULTS');
- DOSreadSectors(DR[curdrive].DOSnum, logsec, 1, sb, error);
- IF error = 0 THEN DisplaySector(sb);
-
- END;
- END.