Category : Assembly Language Source Code
Archive   : BOOTSECT.ZIP
Filename : BOOTSECT.TXT

 
Output of file : BOOTSECT.TXT contained in archive : BOOTSECT.ZIP

; PC-DOS Bootstrap Loader
;
; This code is found in sector 0 of every PC-DOS diskette. It loads
; the file IBMBIO.COM into memory and transfers control to it (on a
; bootable diskette) or displays relevant error messages (on a non-
; bootable diskette)
;
; Although this code (in object form) appears in sector 0 of every
; diskette formatted by DOS, copyrights are no doubt in effect, by
; Microsoft, or IBM, or Both.
; It has been hand dis-assembled from object code, and appropriately
; commented. Beware the computer police!
;
;
; Notes - This code taken from a high-density (1.2Meg) diskette
; - Boot code is loaded into memory, at absolute addr 0000:7C00
; - Several locations within the code are used for data after
; they are no longer useful. These locations have been combined
; into a structure, the elements of which are names xNN, where
; NN is a two digit number corresponding to sequence. They are
; accessed via equates, of the form aXXXXXX, where XXXXXX is
; a symbolic name ("a" stands for "alias")
;
;*****************************************************************************


LoadAdr equ 7C00h ; Load address of this code
Vec_1E equ 0078h ; Address of Interrupt 1E Vector
FNSize equ 11 ; Size of a Filename + Extension

DirLoad equ 0500h ; Where the directory block is loaded
BIOLoad equ 0700h ; Where IBMBI.COM is loaded

ConOut equ 10h ; BIOS Interrupt: Console Output
DiskInt equ 13h ; BIOS Interrupt: Diskette Control
KbdInt equ 16h ; BIOS Interrupt: Keyboard Input
Reboot equ 19h ; BIOS Interrupt: Reboot This Machine



; The following structure a directory entry.
; It's here to make the code look better.

DirNtry struc
Filename db 8 dup(?)
Extension db 3 dup(?)
Attrib db ?
Reserved db 10 dup(?)
FileTime dw ?
FileDate dw ?
FirstClstr dw ?
FileSize dd ?
DirNtry ends


page

; The following structure corresponds to the section of code space
; which is reused. All aliases are defined as byte offsets.
; In addition, the diskette-description header symbols are defined
; here, as absolute addresses, because that is how they are
; accessed within the program (Offsets from DS, which is 0000)

ReUsed struc
db LoadAdr dup(?) ; The beginning of memory
db 3 dup(?) ; The jump to executable code
OEM_ID db 8 dup(?) ; OEM Identification
Byt_Sec dw ? ; Bytes per Sector (512)
Sct_AlU db ? ; Sectors per Allocation Unit
RsvdSct dw ? ; Reserved Sectors (strt at 0)
NumFATs db ? ; Number of FAT's
RootSiz dw ? ; # of Root Dir Entries (112)
TotSect dw ? ; Total Sectors in Device (720)
MedDesc db ? ; Media Descriptor Byte (DS/9s)
FATSect dw ? ; # Sectors used by each FAT
Sct_Trk dw ? ; Sectors per Track
NumHead dw ? ; Number of Heads
NumHSct dw ? ; Nubmer of Hidden Sectors
aDrivNm db ? ; Drive Number (always 0, = A:)
aHeadNm db ? ; Head Number
db 0Bh dup(?) ; Disk Parameters Table
db ? ; - Not Resused -- It's START:
a1stDat dw ? ; First sector above directory
aTrakNm dw ? ; Track Number
aSectNm db ? ; Sector Number (1..n)
aFilSize db ? ; Sectors in current boot file
aCurSect dw ? ; Secotr to read from
aDirLoc dw ? ; First sector in directory
ReUsed ends


page
org 0000


Entry: 0000 JMP Start ; Skip identification code
0002 NOP


0003 db 'IBM 3.1' ; OEM Identification
000B dw 0200h ; Bytes per Sector (512)
000D db 2 ; Sectors per Allocation Unit
000E dw 1 ; Reserved Sectors (strt at 0)
0010 db 2 ; Number of FAT's
0011 dw 70h ; # of Root Dir Entries (112)
0013 dw 02D0h ; Total Sectors in Device (720)
0015 db 0FDh ; Media Descriptor Byte (DS/9s)
0016 dw 2 ; # Sectors used by each FAT
0018 dw 9 ; Sectors per Track
001A dw 2 ; Number of Heads
001C dw 0 ; Nubmer of Hidden Sectors

dw 0 ; - gets filled in...


DskParm db 00, 00, 00, 00 ; Disk parameter block - gets
db 0Fh, 00, 00, 00 ; contents of *IntVect_1E
db 00, 01h, 00 ; (except those already set)


Start: 002B CLI ; The stack will be placed just
002C XOR AX,AX ; below executable code
002E MOV SS,AX
0030 MOV SP, LoadAdr
0033 PUSH SS ; ES will do 0-page addressing
0034 POP ES

0035 MOV BX, Vec_1E ; Diskette parms at *IntVect_1E
0038 LDS SI, SS:[BX] ; DS:SI => Diskette Params
003B PUSH DS ; - These addresses are being
003C PUSH SI ; saved so that the locations
003D PUSH SS ; may be restored if a boot
003E PUSH BX ; error occurs
003F MOV DI, DskParm ; Params will go into our CS
0042 MOV CX, 000Bh ; Note - If any of the bytes
0045 CLD ; are already set in our
DParmLp:0046 LODSB ; table, our values are
0047 CMP Byte Ptr ES:[DI], 00 ; retained. This allows
004B JZ SetParm ; simple changes to the
004D MOV AL, ES:[DI] ; loaded code for any
SetParm:0050 STOSB ; diskette in use.
0051 MOV AL, AH
0053 LOOP DParmLp

ReParm: 0055 PUSH ES ; Re-point the Diskette params
0056 POP DS ; into the block just built
0057 MOV [BX+02],AX
005A MOV Word Ptr [BX],7C20
005E STI

005F INT DiskInt ; Reset the disk subsystem
0061 JB DskErr2 ; (fatal error abort)
0063 MOV AL, [NumFATs] ; Find the starting sector for
0066 CBW ; the Root Directory
0067 MUL Word Ptr [FATSect]
006B ADD AX, [NumHSct]
006F ADD AX, [RsvdSct]
0073 MOV [aDirLoc], AX
0076 MOV [a1stDat], AX
0079 MOV AX, TYPE DirNtry
007C MUL Word Ptr [RootSiz] ; How big is the directory?
0080 MOV BX, [Byt_Sec]
0084 ADD AX, BX ; (this will round up)
0086 DEC AX
0087 DIV BX
0089 ADD [a1stDat], AX ; Store upper bounds of Root
008D MOV BX, DirLoad
0090 MOV AX, [aDirLoc] ; And point to the first block
0093 CALL CvtSct
0096 MOV AX, 0201h
0099 CALL ReadSct ; Read it In!
009C JB DskErr1 ; (Can't do it! Abort!)
009E MOV DI, BX ; Index into the directory blk
00A0 MOV CX, FNSize
00A3 MOV SI, BIO_Nam ; Looking for "IBMBIO.COM"
00A6 REPZ
00A7 CMPSB
00A8 JNZ DskErr1 ; It wasn't the first file!

00AA LEA DI, [BX+20] ; Looking for "IBMDOS.COM"
00AD MOV SI, DOS_Nam
00B0 MOV CX, FNSize
00B3 REPZ
00B4 CMPSB
00B5 JZ BootIt ; Hey! It's Bootable!

DskErr1:00B7 MOV SI, OFFSET DskMsg ; Yell at the user
DE_Sub: 00BA CALL DspErr
00BD XOR AH, AH ; And wait for a keystroke
00BF INT KbdInt
00C1 POP SI ; Pop the Int_1E Vector Addr
00C2 POP DS
00C3 POP [SI] ; Diskette Params pointer goes
00C5 POP [SI+02] ; back into this vector
00C8 INT Reboot ; And we do it all again.

DskErr2:00CA MOV SI, OFFSET BootMsg ; An indeterminate, real bad
00CD JMP DE_Sub ; error has happened.


BootIt: 00CF MOV AX, [DirLoad.FileSize] ; Get the IBMBIO.COM's size
00D2 XOR DX, DX ; We hope it's under 64k!
00D4 DIV Word Ptr [Byt_Sec]
00D8 INC AL
00DA MOV [aFilSize], AL ; Store it away
00DD MOV AX, [a1stDat] ; It must start right after
00E0 MOV [aCurSect], AX ; the root directory ends
00E3 MOV BX, BIOLoad
RdLoop: 00E6 MOV AX, [a1stDat] ; So set up the location
00E9 CALL CvtSct
00EC MOV AX, [Sct_Trk] ; And read that track, from
00EF SUB AL, [aSectNm] ; that sector to the end
00F3 INC AX
00F4 PUSH AX
00F5 CALL ReadSct
00F8 POP AX
00F9 JB DskErr2
00FB SUB [aFilSiz], AL ; Is there any more?
00FF JBE CallBIO
0101 ADD [a1stDat], AX ; Yes, position the buffer ptr
0105 MUL Word Ptr [Byt_Sec] ; after what we've read in,
0109 ADD BX, AX ; and read the next track
010B JMP RdLoop
CallBIO:010D MOV CH, [MedDesc] ; Ready to call IBMBIO.COM
0111 MOV DL, [aDrivNm]
0115 MOV BX, [aCurSct]
0119 JMP 0070:0000


;****************************************************************
;
; DspErr
;
; Display error message on console
;
; Input:
; DS:SI = Pointer to NUL-terminated string
;

DspErr: 011E LODSB
011F OR AL, AL ; Check for End-Of-String
0121 JZ Return ; Save a byte!
0123 MOV AH, 0E ; Using TTYOUT mode
0125 MOV BX, 0007
0128 INT Video
012A JMP DspErr


;****************************************************************
;
; CvtSct
;
; Convert logical sector number to absolute Head / Track / Sector
; position.
;
; Input:
; AX = Logical Sector Number
;
; Output:
; -- = Absolute position is stored in aliased variables
; AX = Track Number
; DL = Head Number

CvtSct: 012C XOR DX,DX
012E DIV Word Ptr [SctTrk] ; Sectors go from 1 .. N
0132 INC DL
0134 MOV [aSectNm], DL
0138 XOR DX, DX
013A DIV Word Ptr [NumHead]
013E MOV [aHeadNm], DL
0142 MOV [aTrakNm], AX
Return: 0145 RET


;****************************************************************
;
; ReadSct
;
; Reads a sector into memory
; position.
;
; Input:
; AL = Number of sectors to read
; BX = Buffer Address
;
; Output:
; -- = Output is identical to BIOS Interrupt 13 (AH=2)

ReadSct:0146 MOV AH, 02 ; We will be doing a Read
0148 MOV DX, [aTrakNm] ; Track and sector get mixed -
014C MOV CL, 06 ; high 2 bits of track number
014E SHL DH, CL ; are combined with sector #
0150 OR DH, [aSectNm] ; (allows 1024 tracks/cyl)
0154 MOV CX, DX
0156 XCHG CH, CL
0158 MOV DX, [aDrivNum] ; Drive and Head are here
015C INT DiskInt ; Perform the operation
015E RET



;******************************************************************************
;
; Messages, And Whatever else is Needed
;
;******************************************************************************


DskMsg 015F db 13, 10, 'Non-System disk or disk error'
db 13, 10, 'Replace and strike any key when ready'
db 13, 10, 0
BootMsg 01A8 db 13, 10, 'Disk Boot failure'
db 13, 10, 0

BIO_Nam 01BE db 'IBMBIO COM'
DOS_Nam 01CA db 'IBMDOS COM'

Resrvd db 42 dup( 0 )
Boot_ID db 55h, 0AAh