Page 60,132 ; SCCSID = @(#)msboot.asm 1.1 85/05/13 TITLE BOOT SECTOR 1 OF TRACK 0 - BOOT LOADER ; Rev 1.0 ChrisP, AaronR and others. 2.0 format boot ; ; Rev 3.0 MarkZ PC/AT enhancements ; 2.50 in label ; Rev 3.1 MarkZ 3.1 in label due to vagaries of SYSing to IBM drive D's ; This resulted in the BPB being off by 1. So we now trust ; 2.0 and 3.1 boot sectors and disbelieve 3.0. ; ; Rev 3.2 LeeAc Modify layout of extended BPB for >32M support ; Move PHYDRV to 3rd byte from end of sector ; so that it won't have to be moved again ; FORMAT and SYS count on PHYDRV being in a known location ; ; Rev. 3.3 D.C. L. Changed Sec 9 EOT field from 15 to 18. May 29, 1986. ; ; Rev 3.31 MarkT The COUNT value has a bogus check (JBE????) to determine ; if we've loaded in all the sectors of IBMBIO. This will ; cause too big of a load if the sectors per track is high ; enough, causing either a stack overflow or the boot code ; to be overwritten. ; ; Rev 4.00 J. K. For DOS 4.00 Modified to handle the extended BPB, and ; 32 bit sector number calculation to enable the primary ; partition be started beyond 32 MB boundary. ; ; ; The ROM in the IBM PC starts the boot process by performing a hardware ; initialization and a verification of all external devices. If all goes ; well, it will then load from the boot drive the sector from track 0, head 0, ; sector 1. This sector is placed at physical address 07C00h. The initial ; registers are set up as follows: CS=DS=ES=SS=0. IP=7C00h, SP=0400H. ; ; The code in this sector is responsible for locating the MSDOS device drivers ; (IBMBIO) and for placing the directory sector with this information at ; physical address 00500h. After loading in this sector, it reads in the ; entirety of the BIOS at BIOSEG:0 and does a long jump to that point. ; ; If no BIOS/DOS pair is found an error message is displayed and the user is ; prompted to reinsert another disk. If there is a disk error during the ; process, a message is displayed and things are halted. ; ; At the beginning of the boot sector, there is a table which describes the ; MSDOS structure of the media. This is equivalent to the BPB with some ; additional information describing the physical layout of the driver (heads, ; tracks, sectors) ; ;============================================================================== ;REVISION HISTORY: ;AN000 - New for DOS Version 4.00 - J.K. ;AC000 - Changed for DOS Version 4.00 - J.K. ;AN00x - PTM number for DOS Version 4.00 - J.K. ;============================================================================== ;AN001; d52 Make the fixed positioned variable "CURHD" to be local. 7/6/87 J.K. ;AN002; d48 Change head settle at boot time. 7/7/87 J.K. ;AN003; P1820 New message SKL file 10/20/87 J.K. ;AN004; D304 New structrue of Boot record for OS2. 11/09/87 J.K. ;============================================================================== ORIGIN EQU 7C00H ; Origin of bootstrap LOADER BIOSEG EQU 70H ; destingation segment of BIOS BioOff EQU 700H ; offset of bios cbSec EQU 512 cbDirEnt EQU 32 DirOff EQU 500h IBMLOADSIZE equ 3 ;J.K. Size of IBMLOAD module in sectors ROM_DISKRD equ 2 include version.inc ; ; Define the destination segment of the BIOS, including the initialization ; label ; SEGBIOS SEGMENT AT BIOSEG BIOS LABEL BYTE SEGBIOS ENDS CODE SEGMENT ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING ; ORG DirOff + 1Ch ;BiosFS LABEL WORD ORG ORIGIN DSKADR = 1EH*4 ;POINTER TO DRIVE PARAMETERS Public $START $START: JMP START ;---------------------------------------------------------- ; ; THE FOLLOWING DATA CONFIGURES THE BOOT PROGRAM ; FOR ANY TYPE OF DRIVE OR HARDFILE ; ;J.K. Extened_BPB if ibmcopyright DB "IBM " else DB "MSDOS" endif DB "4.0" ;AN005; ByteSec DW cbSec ; SIZE OF A PHYSICAL SECTOR DB 8 ; SECTORS PER ALLOCATION UNIT cSecRes DW 1 ; NUMBER OF RESERVED SECTORS cFat DB 2 ; NUMBER OF FATS DirNum DW 512 ; NUMBER OF DIREC ENTRIES cTotSec DW 4*17*305-1 ; NUMBER OF SECTORS - NUMBER OF HIDDEN SECTORS ; (0 when 32 bit sector number) MEDIA DB 0F8H ; MEDIA BYTE cSecFat DW 8 ; NUMBER OF FAT SECTORS SECLIM DW 17 ; SECTORS PER TRACK HDLIM DW 4 ; NUMBER OF SURFACES Ext_cSecHid label dword cSecHid_L DW 1 ;AN000; NUMBER OF HIDDEN SECTORS cSecHid_H dw 0 ;AN000; high order word of Hiden Sectors Ext_cTotSec label dword ctotsec_L dw 0 ;AN000; 32 bit version of NUMBER OF SECTORS ctotsec_H dw 0 ;AN000; (when 16 bit version is zero) ; Phydrv db 80h ;AN004; Curhd db 0h ;AN004; Current Head Ext_Boot_Sig db 41 ;AN000; Boot_Serial dd 0 ;AN000; Boot_Vol_Label db 'NO NAME ' ;AN000; Boot_System_id db 'FAT12 ' ;AN000; ;J.K. Danger!!! If not 32 bit sector number calculation, FORMAT should ;set the value of cSecHid_h and Ext_cTotSec to 0 !!! ; ; Public UDATA UDATA LABEL byte Sec9 equ byte ptr UDATA+0 ;11 byte diskette parm. table BIOS$_L EQU WORD PTR UDATA+11 BIOS$_H equ word ptr UDATA+13 ;AN000; CURTRK EQU WORD PTR UDATA+15 CURSEC EQU BYTE PTR UDATA+17 DIR$_L EQU WORD PTR UDATA+18 Dir$_H equ word ptr UDATA+20 ;AN000; START: ; ; First thing is to reset the stack to a better and more known place. The ROM ; may change, but we'd like to get the stack in the correct place. ; CLI ;Stop interrupts till stack ok XOR AX,AX MOV SS,AX ;Work in stack just below this routine ASSUME SS:CODE MOV SP,ORIGIN PUSH SS POP ES ASSUME ES:CODE ; ; We copy the disk parameter table into a local area. We scan the table above ; for non-zero parameters. Any we see get changed to their non-zero values. ; ;J.K. We copy the disk parameter table into a local area (overlayed into the ;code), and set the head settle time to 1, and End of Track to SECLIM given ;by FORMAT. MOV BX,DSKADR LDS SI,DWORD PTR SS:[BX] ; get address of disk table PUSH DS ; save original vector for possible PUSH SI ; restore PUSH SS PUSH BX MOV DI,offset Sec9 MOV CX,11 CLD if $ le BIOS$_L %OUT Don't destroy unexcuted code yet!!! endif repz movsb ;AN000; push es ;AN000; pop ds ;AN000; DS = ES = code = 0. assume ds:code ;AN000; ; mov byte ptr [di-2], 1 ;AN000; Head settle time ;J.K. Change the head settle to 15 ms will slow the boot time quite a bit!!! mov byte ptr [di-2], 0fh ;AN002; Head settle time mov cx, SECLIM ;AN004; mov byte ptr [di-7], cl ;AN000; End of Track ; ; Place in new disk parameter table vector. ; MOV [BX+2],AX MOV [BX],offset SEC9 ; ; We may now turn interrupts back on. Before this, there is a small window ; when a reboot command may come in when the disk parameter table is garbage ; STI ;Interrupts OK now ; ; Reset the disk system just in case any thing funny has happened. ; INT 13H ;Reset the system ; JC RERROR jc CKErr ;AN000; ; ; The system is now prepared for us to begin reading. First, determine ; logical sector numbers of the start of the directory and the start of the ; data area. xor ax,ax ;AN000; cmp cTotSec,ax ;AN000; 32 bit calculation? je Dir_Cont ;AN000; mov cx,cTotSec ;AN000; mov cTotSec_L,cx ;AN000; cTotSec_L,cTotSec_H will be used for calculation Dir_Cont: ;AN000; MOV AL,cFat ;Determine sector dir starts on MUL cSecFat ;DX;AX ADD AX,cSecHid_L adc DX,cSecHid_H ;AN000; ADD AX,cSecRes ADC DX,0 MOV [DIR$_L],AX ; DX;AX = cFat*cSecFat + cSecRes + cSecHid mov [DIR$_H],DX ;AN000; MOV [BIOS$_L],AX mov [BIOS$_H],DX ;AN000; ; ; Take into account size of directory (only know number of directory entries) ; MOV AX,cbDirEnt ; bytes per directory entry MUL DirNum ; convert to bytes in directory MOV BX,ByteSec ; add in sector size ADD AX,BX DEC AX ; decrement so that we round up DIV BX ; convert to sector number ADD [BIOS$_L],AX ; Start sector # of Data area adc [BIOS$_H],0 ;AN000; ; ; We load in the first directory sector and examine it to make sure the the ; BIOS and DOS are the first two directory entries. If they are not found, ; the user is prompted to insert a new disk. The directory sector is loaded ; into 00500h ; MOV BX,DirOff ; sector to go in at 00500h mov dx,[DIR$_H] ;AN000; MOV AX,[DIR$_L] ; logical sector of directory CALL DODIV ; convert to sector, track, head jc CKErr ;AN000; Overflow? BPB must be wrong!! ; MOV AX,0201H ; disk read 1 sector mov al, 1 ;AN000; disk read 1 sector CALL DOCALL ; do the disk read JB CKERR ; if errors try to recover ; ; Now we scan for the presence of IBMBIO COM and IBMDOS COM. Check the ; first directory entry. ; MOV DI,BX MOV CX,11 MOV SI,OFFSET BIO ; point to "ibmbio com" REPZ CMPSB ; see if the same JNZ CKERR ; if not there advise the user ; ; Found the BIOS. Check the second directory entry. ; LEA DI,[BX+20h] MOV SI,OFFSET DOS ; point to "ibmdos com" MOV CX,11 REPZ CMPSB JZ DoLoad ; ; There has been some recoverable error. Display a message and wait for a ; keystroke. ; CKERR: MOV SI,OFFSET SYSMSG ; point to no system message ErrOut: CALL WRITE ; and write on the screen XOR AH,AH ; wait for response INT 16H ; get character from keyboard POP SI ; reset disk parameter table back to POP DS ; rom POP [SI] POP [SI+2] INT 19h ; Continue in loop till good disk Load_Failure: pop ax ;adjust the stack pop ax pop ax jmp short Ckerr ;display message and reboot. ;J.K. We don't have the following error message any more!!! ;J.K. Sysmsg is fine. This will save space by eliminating DMSSG message. ;RERROR: MOV SI,OFFSET DMSSG ; DISK ERROR MESSAGE ; JMP ErrOut ; ; We now begin to load the BIOS in. Compute the number of sectors needed. ; J.K. All we have to do is just read in sectors contiguously IBMLOADSIZE ; J.K. times. We here assume that IBMLOAD module is contiguous. Currently ; J.K. we estimate that IBMLOAD module will not be more than 3 sectors. DoLoad: mov BX,BioOff ;offset of ibmbio(IBMLOAD) to be loaded. mov CX,IBMLOADSIZE ;# of sectors to read. mov AX, [BIOS$_L] ;Sector number to read. mov DX, [BIOS$_H] ;AN000; Do_While: ;AN000; push AX ;AN000; push DX ;AN000; push CX ;AN000; call DODIV ;AN000; DX;AX = sector number. jc Load_Failure ;AN000; Adjust stack. Show error message mov al, 1 ;AN000; Read 1 sector at a time. ;This is to handle a case of media ;when the first sector of IBMLOAD is the ;the last sector in a track. call DOCALL ;AN000; Read the sector. pop CX ;AN000; pop DX ;AN000; pop AX ;AN000; jc CkErr ;AN000; Read error? add AX,1 ;AN000; Next sector number. adc DX,0 ;AN000; add BX,ByteSec ;AN000; adjust buffer address. loop Do_While ;AN000; ; MOV AX,BiosFS ; get file size ; XOR DX,DX ; presume < 64K ; DIV ByteSec ; convert to sectors ; INC AL ; reading in one more can't hurt ; MOV COUNT,AL ; Store running count ; MOV AX,BIOS$ ; get logical sector of beginning of BIOS ; MOV BIOSAV,AX ; store away for real bios later ; MOV BX,BioOff ; Load address from BIOSSEG ; ; Main read-in loop. ; ES:BX points to area to read. ; Count is the number of sectors remaining. ; BIOS$ is the next logical sector number to read ; ;LOOPRD: ; MOV AX,BIOS$ ; Starting sector ; CALL DODIV ; ; CurHD is the head for this next disk request ; CurTrk is the track for this next request ; CurSec is the beginning sector number for this request ; ; Compute the number of sectors that we may be able to read in a single ROM ; request. ; ; MOV AX,SECLIM ; SUB AL,CURSEC ; INC AX ; ; AX is the number of sectors that we may read. ; ; ;New code for Rev 3.31 ;***************************************************************************** ; CMP COUNT,AL ;Is sectors we can read more than we need? ; JAE GOT_SECTORS ;No, it is okay ; MOV AL,COUNT ;Yes, only read in what is left ;GOT_SECTORS: ;***************************************************************************** ;End of change ; ; PUSH AX ; CALL DOCALL ; POP AX ; JB RERROR ; If errors report and go to ROM BASIC ; SUB COUNT,AL ; Are we finished? ; ;Old code replaced by Rev 3.3 ;******************************************************************** ; JBE DISKOK ; Yes -- transfer control to the DOS ;******************************************************************** ;New code for Rev 3.3 ; ; JZ DISKOK ; Yes -- transfer control to the DOS ;******************************************************************** ;End of change ; ; ADD BIOS$,AX ; increment logical sector position ; MUL ByteSec ; determine next offset for read ; ADD BX,AX ; (BX)=(BX)+(SI)*(Bytes per sector) ; JMP LOOPRD ; Get next track ; ; IBMINIT requires the following input conditions: ; ; DL = INT 13 drive number we booted from ; CH = media byte ;J.K.I1. BX was the First data sector on disk (0-based) ;J.K.I1. IBMBIO init routine should check if the boot record is the ;J.K.I1. extended one by looking at the extended_boot_signature. ;J.K.I1. If it is, then should us AX;BX for the starting data sector number. DISKOK: MOV CH,Media MOV DL,PhyDrv MOV bx,[BIOS$_L] ;AN000; J.K.I1.Get bios sector in bx mov ax,[BIOS$_H] ;AN000; J.K.I1. JMP FAR PTR BIOS ;CRANK UP THE DOS WRITE: LODSB ;GET NEXT CHARACTER OR AL,AL ;clear the high bit JZ ENDWR ;ERROR MESSAGE UP, JUMP TO BASIC MOV AH,14 ;WILL WRITE CHARACTER & ATTRIBUTE MOV BX,7 ;ATTRIBUTE INT 10H ;PRINT THE CHARACTER JMP WRITE ; convert a logical sector into Track/sector/head. AX has the logical ; sector number ; J.K. DX;AX has the sector number. Because of not enough space, we are ; going to use Simple 32 bit division here. ; Carry set if DX;AX is too big to handle. ; DODIV: cmp dx,Seclim ;AN000; To prevent overflow!!! jae DivOverFlow ;AN000; Compare high word with the divisor. DIV SECLIM ;AX = Total tracks, DX = sector number INC DL ;Since we assume SecLim < 255 (a byte), DH =0. ;Cursec is 1-based. MOV CURSEC, DL ;save it XOR DX,DX DIV HDLIM MOV CURHD,DL ;Also, Hdlim < 255. MOV CURTRK,AX clc ;AN000; ret ;AN000; DivOverFlow: ;AN000; stc ;AN000; EndWR: ret ; ;J.K.We don't have space for the following full 32 bit division. ; convert a logical sector into Track/sector/head. AX has the logical ; sector number ; J.K. DX;AX has the sector number. ;DODIV: ; push ax ; mov ax,dx ; xor dx,dx ; div SecLim ; mov Temp_H,ax ; pop ax ; div SecLim ;J.K.Temp_H;AX = total tracks, DX=sector ; INC DL ;Since we assume SecLim < 255 (a byte), DH =0. ; ;Cursec is 1-based. ; MOV CURSEC, DL ;save it ; push ax ; mov ax,Temp_H ; XOR DX,DX ; DIV HDLIM ; mov Temp_H,ax ; pop ax ; div HdLim ;J.K.Temp_H;AX=total cyliners,DX=head ; MOV CURHD,DL ;Also, Hdlim < 255. ; cmp Temp_H,0 ; ja TooBigToHandle ; cmp ax, 1024 ; ja TooBigToHandle ; MOV CURTRK,AX ;ENDWR: RET ;TooBigToHandle: ; stc ; ret ; ; Issue one read request. ES:BX have the transfer address, AL is the number ; of sectors. ; DOCALL: MOV AH,ROM_DISKRD ;AC000;=2 MOV DX,CURTRK MOV CL,6 SHL DH,CL OR DH,CURSEC MOV CX,DX XCHG CH,CL MOV DL, PHYDRV mov dh, curhd INT 13H RET ; include ibmbtmes.inc include boot.cl1 ;AN003; IF IBMCOPYRIGHT BIO DB "IBMBIO COM" DOS DB "IBMDOS COM" ELSE BIO DB "IO SYS" DOS DB "MSDOS SYS" ENDIF Free EQU (cbSec - 4) - ($-$start) ;AC000; ;Free EQU (cbSec - 5) - ($-$start) if Free LT 0 %out FATAL PROBLEM:boot sector is too large endif org origin + (cbSec - 2) ;AN004; ; org origin + (cbSec - 5) ;Warning!! Do not change the position of following unless ;Warning!! you change BOOTFORM.INC (in COMMON subdirectory) file. ;Format should set this EOT value for IBMBOOT. ;FEOT db 12h ;AN000; set by FORMAT. AN004;Use SecLim in BPB instead. ; FORMAT and SYS count on CURHD,PHYDRV being right here ;J.K. CURHD has been deleted since it is not being used by anybody. ;CURHD DB ? ;AN001;Unitialized (J.K. Maybe don't need this). ;PHYDRV db 0 ;AN000;moved into the header part. ; Boot sector signature db 55h,0aah CODE ENDS END