'===========================================================================
' Subject: READ HD BOOT SECTOR                Date: 01-05-98 (03:03)       
'  Author: Andrew S. Gibson                   Code: QB, PDS                
'  Origin: zapf_dingbat@juno.com            Packet: DISK.ABC
'===========================================================================
' BOOTSEC.BAS   reads the hard drive boot sector into memory.
'
'   Author:     Christy Gemmell
'   Additions:  Martin Overton
'               David Milton (4/7/1995)
'               Andrew Gibson (9/25/1997)
'   Date:       1/9/1998
'
DECLARE FUNCTION FloppyDriveReady% (Drive$, ErrCode%)
DECLARE FUNCTION GetDiskID$ (Drive$)
DECLARE FUNCTION Lo% (IntegerVar%)
DECLARE SUB BootSec (Drive$, ParTable%, Done%)
DECLARE SUB GetDTAAddr ()
DECLARE SUB Help ()

'REGTYPE.BAS - Include file for CALL INTERRUPT & INTERRUPTX
TYPE RegType
  AX    AS INTEGER
  BX    AS INTEGER
  CX    AS INTEGER
  DX    AS INTEGER
  BP    AS INTEGER
  SI    AS INTEGER
  DI    AS INTEGER
  flags AS INTEGER
  DS    AS INTEGER
  ES    AS INTEGER
END TYPE

TYPE ExtendedFCBRecord
	ExtFCB   AS STRING * 1
	Res1     AS STRING * 5
	Attr     AS STRING * 1
	Drive    AS STRING * 1
	Name1    AS STRING * 11
	Unused1  AS STRING * 5
	Name2    AS STRING * 11
	Unused2  AS STRING * 9
END TYPE

CONST FALSE = 0, TRUE = NOT FALSE
DIM SHARED REGISTERS AS RegType, Segment, Offset
DIM SHARED Sector AS STRING * 512
DIM SHARED Part AS STRING * 512

	CLS : Drive$ = COMMAND$   ' Read drive from command line
	IF Drive$ = "" OR Drive$ = "/?" OR Drive$ = "?" OR Drive$ = "HELP" THEN Help: END
	IF Drive$ = "A" OR Drive$ = "B" OR Drive$ = "A:" OR Drive$ = "B:" THEN
	DT = FloppyDriveReady%(Drive$, ErrCode%)
	IF ErrCode% <> TRUE AND DT <> TRUE THEN
	   PRINT "Error occured with Floppy Disk Drive "; CHR$(34); Drive$; CHR$(34); ", ";
	   SELECT CASE ErrCode%
	     CASE &H1
	      PRINT "Bad command."
	     CASE &H2
	      PRINT "Address mark not found."
	     CASE &H3
	      PRINT "Diskette write protected."
	     CASE &H4
	      PRINT "Sector not found."
	     CASE &H6
	      PRINT "Diskette removed."
	     CASE &H8
	      PRINT "DMA Overrun."
	     CASE &H9
	      PRINT "DMA across 64k boundary."
	     CASE &H10
	      PRINT "Bad CRC or ECC."
	     CASE &H20
	      PRINT "CONTROLLER FAILED !!!!"
	     CASE &H40
	      PRINT "Seek Failed."
	     CASE &H80
	      PRINT "Drive timeout."
	     CASE ELSE
	      PRINT "Disk Status Code is "; HEX$(ErrCode%); "h."
	   END SELECT
	   END
	END IF
	END IF

	BootSec Drive$, ParTable%, Done%    ' Read boot sector
	IF Done% THEN                       ' If successful...
	   PRINT "Boot Sector for Drive "; Drive$
	   PRINT "========================"
	   PRINT "Media descriptor         = "; HEX$(ASC(MID$(Sector, 22, 8)))
	   PRINT "OEM Identifier           = "; MID$(Sector, 4, 8)
	   PRINT "Boot Sector Volume Label = "; MID$(Sector, 44, 11); "  Directory Volume Label = "; GetDiskID$(Drive$)
	   PRINT "Serial number            = ";
	   FOR i% = 43 TO 40 STEP -1
			   PRINT RIGHT$("0" + HEX$(ASC(MID$(Sector, i%, 1))), 2);
			   IF i% = 42 THEN PRINT "-";
	   NEXT i%
	   PRINT : PRINT "File system              = "; MID$(Sector, 55, 8)
	   PRINT
	   IF ParTable% THEN
			  PRINT "Partition Table for Drive "; Drive$
			  PRINT "============================"
			  i% = 447: P% = 1
			  DO
					 PRINT "Partition"; P%;
					 IF ASC(MID$(Part, i%, 1)) = 128 THEN
							PRINT TAB(21); "ACTIVE PARTITION";
					 END IF
					 OS% = ASC(MID$(Part, i% + 4, 1))
					 PRINT TAB(41);
					 SELECT CASE OS%
							 CASE 0
									  PRINT "Empty"
							 CASE 1
									  PRINT "DOS 12-bit FAT"
							 CASE 4
									  PRINT "DOS 16-bit FAT (up to 32MB)"
							 CASE 5
									  PRINT "Extended partition"
							 CASE 6
									  PRINT "16-bit FAT (over 32MB)"
							 CASE 7
									  PRINT "OS/2 HPFS or Windows NTFS"
							 CASE ELSE
									  PRINT "Operating System Unknown."
					 END SELECT
					 i% = i% + 16: P% = P% + 1
			  LOOP UNTIL P% > 4
			  PRINT
			  Sig& = ASC(MID$(Part, i%, 1)) + (256& * ASC(MID$(Part, i% + 1, 1)))
			  IF Sig& = 43605 THEN
			       COLOR 15: PRINT "Valid boot block.": COLOR 7
			  ELSE
			       COLOR 28: PRINT "WARNING: INVALID BOOT BLOCK !!!!!!": COLOR 7
			  END IF
	   END IF
	   PRINT "-----------------------------------------------------------"
	ELSE
	PRINT "Boot Sector Interpreter Version 1.51.01": PRINT
	PRINT "You must use a valid drive letter on the command line."
	PRINT CHR$(34); Drive$; CHR$(34); " does not work or is non-existant."
	END IF
END

'   Read the boot sector and partition table of a specified drive.
'
SUB BootSec (Drive$, ParTable%, Done%)
	LSET Sector = STRING$(512, 0)       ' Fill sector buffer with zeroes
	Disk% = ASC(UCASE$(Drive$)) - 65    ' Get drive number
	Head% = 0                           ' Floppies use head zero
	IF Disk% > 1 THEN                   ' Adjust
	   Disk% = (Disk% + 128) - 2        '   for hard
	   Head% = 1                        '     disk
	END IF                              '       drives
	REGISTERS.CX = &H1                       ' Get sector 1 of track zero
	REGISTERS.DX = (Head% * 256) + Disk%     '   of selected drive
	REGISTERS.AX = &H201                     ' Read one full sector
	REGISTERS.BX = VARPTR(Sector)            ' Offset of read buffer
	REGISTERS.ES = VARSEG(Sector)            ' Segment of read buffer
	CALL INTERRUPTX(&H13, REGISTERS, REGISTERS)       ' Read sector into memory
	IF REGISTERS.flags AND 1 THEN            ' Test carry flag for error
	   Done% = FALSE                    ' If set report an error
	ELSE                                ' Otherwise
	   IF Disk% > 1 THEN                ' Hard drive
			  LSET Part = STRING$(512, 0)   ' Fill partition buffer with zeroes
			  Head% = 0                     ' Partition table is under head zero
			  REGISTERS.CX = &H1                 ' Get sector 1 of track zero
			  REGISTERS.DX = (Head% * 256) + Disk% ' of selected drive
			  REGISTERS.AX = &H201               ' Read one full sector
			  REGISTERS.BX = VARPTR(Part)        ' Offset of read buffer
			  REGISTERS.ES = VARSEG(Part)        ' Segment of read buffer
			  CALL INTERRUPTX(&H13, REGISTERS, REGISTERS)    ' Read sector into memory
			  IF REGISTERS.flags AND 1 THEN      ' Test carry flag for error
				 ParTable% = FALSE          ' If set report failure
			  ELSE                          ' Otherwise
				 ParTable% = TRUE           ' Report success
			  END IF
	   END IF
	   Done% = TRUE                     ' report success
	END IF
END SUB

FUNCTION FloppyDriveReady% (Drive$, ErrCode%)
'returns True (-1) if the floppy drive specified in Drive$
'has a disk in it. If the function returns False (0), ErrCode%
'contains the DOS error code.
'by Douglas H. Lusher, April, 1993

Drive% = ASC(UCASE$(Drive$)) - 65

'reset floppy drive
REGISTERS.AX = 0
REGISTERS.DX = Drive%
CALL INTERRUPTX(&H13, REGISTERS, REGISTERS)

REGISTERS.AX = &H401
REGISTERS.CX = &H101
REGISTERS.DX = Drive%
CALL INTERRUPTX(&H13, REGISTERS, REGISTERS)

'call the interrupt twice since if a disk has just been inserted,
'the first time gives a wrong answer
REGISTERS.AX = &H401
REGISTERS.CX = &H101
REGISTERS.DX = Drive%
CALL INTERRUPTX(&H13, REGISTERS, REGISTERS)
FloppyDriveReady% = ((REGISTERS.flags AND 1) = 0)
ErrCode% = ((REGISTERS.AX AND &HFF00) \ &H100) AND &HFF
END FUNCTION

FUNCTION GetDiskID$ (Drive$)
DIM EFCB AS ExtendedFCBRecord
'  Get Address of Data Transfer Area (DTA)
GetDTAAddr
'  Call the Find First FCB function
'  using the Volume attribute
EFCB.ExtFCB = CHR$(&HFF)   'Set EFCB flag
EFCB.Attr = CHR$(&H8)      'Vol label attribute
EFCB.Drive = CHR$(ASC(Drive$) - 64)
EFCB.Name1 = "*.*        "
REGISTERS.AX = &H1100        'Call find first FCB
REGISTERS.DS = VARSEG(EFCB)  'Load DS:DX with
REGISTERS.DX = VARPTR(EFCB)  'address of EFCB
CALL INTERRUPTX(&H21, REGISTERS, REGISTERS)
GetDiskID$ = "NO LABEL EXISTS" ' if it doesn't exist
IF Lo(REGISTERS.AX) = 0 THEN  'Successful
	VOL$ = ""
	DEF SEG = Segment       'Set Segment to DTA
	FOR i = Offset + 8 TO Offset + 18
		VOL$ = VOL$ + CHR$(PEEK(i))
	NEXT i
	DEF SEG
	GetDiskID$ = VOL$
END IF
END FUNCTION

SUB GetDTAAddr
REGISTERS.AX = &H2F00
CALL INTERRUPTX(&H21, REGISTERS, REGISTERS)
Segment = REGISTERS.ES   'Return address of DTA
Offset = REGISTERS.BX    'Segment:Offset format
END SUB

SUB Help
PRINT "Boot Sector Interpreter Version 1.51.01": PRINT
PRINT "The program interprets the contents of Floppy diskette and Hard drive boot"
PRINT "sectors (and active partitions on Hard Disk Drives) and displays the translated"
PRINT "contents. (Does not alter boot sector in ANY WAY !)": PRINT
PRINT SPC(3); "Usage:  BOOTSEC driveletter": PRINT
PRINT "Replace 'driveletter' with the identifier of a known working drive."
PRINT "( I.E. BOOTSEC A: )"
PRINT : PRINT "Original Author: Christy Gemmell"
PRINT "Additions:  Martin Overton, David Milton (4/7/1995), Andrew Gibson (9/25/1997)"
END SUB

FUNCTION Lo% (IntegerVar%)
Lo% = IntegerVar% MOD 256
END FUNCTION
