; 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