mirror of https://github.com/AR1972/DOS3.3
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
386 lines
10 KiB
386 lines
10 KiB
; SCCSID = @(#)ibmboot.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 Salmon 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 DCLove 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 IO.SYS. 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.
|
|
;
|
|
;
|
|
; 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
|
|
; (IO.SYS) 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)
|
|
;
|
|
|
|
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
|
|
|
|
;
|
|
; 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
|
|
;
|
|
DB "MSDOS"
|
|
DB "3.3"
|
|
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
|
|
DW 4*17*305-1 ; NUMBER OF SECTORS - NUMBER OF HIDDEN SECTORS
|
|
MEDIA DB 0F8H ; MEDIA BYTE
|
|
cSecFat DW 8 ; NUMBER OF FAT SECTORS
|
|
SECLIM DW 17 ; SECTORS PER TRACK
|
|
HDLIM DW 4 ; NUMBER OF SURFACES
|
|
cSecHid DW 1 ; NUMBER OF HIDDEN SECTORS
|
|
dw 0 ; high order word of Hiden Sectors
|
|
dd 0 ; 32 bit version of NUMBER OF SECTORS
|
|
; (when 16 bit version is zero)
|
|
db 6 dup(?) ; reserved for later expansion
|
|
|
|
|
|
CURHD DB ? ; Unitialized
|
|
|
|
; this is an image of the disk parameter table. Zero entries are copied
|
|
; from the rom table at boot.
|
|
;
|
|
SEC9 DB 0 ; DISK_SPECIFY_1
|
|
DB 0 ; DISK_SPECIFY_2
|
|
DB 0 ; DISK_MOTOR_WAIT
|
|
DB 0 ; DISK_SECTOR_SIZ
|
|
DB 12h ; DISK_EOT
|
|
DB 0 ; DISK_RW_GAP
|
|
DB 0 ; DISK_DTL
|
|
DB 0 ; DISK_FORMT_GAP
|
|
DB 0 ; DISK_FILL
|
|
DB 1 ; DISK_HEAD_STTL
|
|
DB 0 ; DISK_MOTOR_STRT
|
|
|
|
Public UDATA
|
|
UDATA LABEL WORD
|
|
BIOS$ EQU WORD PTR UDATA+1
|
|
CURTRK EQU WORD PTR UDATA+3
|
|
CURSEC EQU BYTE PTR UDATA+5
|
|
COUNT EQU BYTE PTR UDATA+6 ; NUMBER OF BIOS SECTORS
|
|
BIOSAV EQU WORD PTR UDATA+7
|
|
DIR$ EQU WORD PTR UDATA+9
|
|
|
|
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.
|
|
;
|
|
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
|
|
changeloop:
|
|
LODSB
|
|
CMP BYTE PTR ES:[DI],0 ; is the template zero?
|
|
JZ Store ; yes, store what we've got
|
|
MOV AL,ES:[DI]
|
|
Store:
|
|
STOSB
|
|
MOV AL,AH
|
|
LOOP ChangeLoop
|
|
;
|
|
; Place in new disk parameter table.
|
|
;
|
|
PUSH ES
|
|
POP DS
|
|
ASSUME DS:CODE
|
|
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
|
|
;
|
|
; 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.
|
|
;
|
|
MOV AL,cFat ;Determine sector dir starts on
|
|
CBW
|
|
MUL cSecFat
|
|
ADD AX,cSecHid
|
|
ADD AX,cSecRes
|
|
MOV [DIR$],AX ; AX = cFat*cSecFat + cSecRes + cSecHid
|
|
MOV [BIOS$],AX
|
|
;
|
|
; 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$],AX
|
|
;
|
|
; 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 AX,DIR$ ; logical sector of directory
|
|
CALL DODIV ; convert to sector, track, head
|
|
MOV AX,0201H ; disk read 1 sector
|
|
CALL DOCALL ; do the disk read
|
|
JB CKERR ; if errors try to recover
|
|
;
|
|
; Now we scan for the presence of IO.SYS and MSDOS.SYS. Check the
|
|
; first directory entry.
|
|
;
|
|
MOV DI,BX
|
|
MOV CX,11
|
|
MOV SI,OFFSET BIO ; point to "bios 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 "86dos 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
|
|
|
|
RERROR: MOV SI,OFFSET DMSSG ; DISK ERROR MESSAGE
|
|
JMP ErrOut
|
|
;
|
|
; We now begin to load the BIOS in. Compute the number of sectors needed
|
|
;
|
|
DoLoad:
|
|
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
|
|
; BX = First data sector on disk (0-based)
|
|
;
|
|
DISKOK:
|
|
MOV CH,Media
|
|
MOV DL,PhyDrv
|
|
MOV BX,[BIOSAV] ;Get bios sector in bx
|
|
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
|
|
;
|
|
DODIV:
|
|
XOR DX,DX
|
|
DIV SECLIM
|
|
INC DL ; sector numbers are 1-based
|
|
MOV CURSEC,DL
|
|
XOR DX,DX
|
|
DIV HDLIM
|
|
MOV CURHD,DL
|
|
MOV CURTRK,AX
|
|
ENDWR: RET
|
|
;
|
|
; Issue one read request. ES:BX have the transfer address, AL is the number
|
|
; of sectors.
|
|
;
|
|
DOCALL: MOV AH,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 messages.inc
|
|
|
|
BIO DB "IO SYS"
|
|
DOS DB "MSDOS SYS"
|
|
|
|
Free EQU (cbSec - 3) - ($-$start)
|
|
if Free LT 0
|
|
%out FATAL PROBLEM:boot sector is too large
|
|
endif
|
|
|
|
org origin + (cbSec - 3)
|
|
|
|
; FORMAT and SYS count on PHYDRV being right here
|
|
PHYDRV db 0
|
|
; Boot sector signature
|
|
db 55h,0aah
|
|
|
|
CODE ENDS
|
|
END
|