DOS 3.30 source code leak
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.
 
 
 
 

767 lines
25 KiB

title Non-Contiguous BIOS Loader (MSLOAD)
IF1
%OUT ASSEMBLING: Non-Contiguous BIOS Loader (MSLOAD)
%OUT
ENDIF
bootseg segment at 0h
org 7C00h
Boot_Sector label byte
org 7D00h
Relocate_Start label byte
bootseg ends
dosseg segment at 70h
org 00h
BIOS_Address label byte
dosseg ends
cseg segment public para 'code'
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
include msload.inc
org 0h
start:
subttl Setup Stack
page
;***********************************************************************
; Setup_Stack
;***********************************************************************
;
; Input: none
;
; Output:
;
; SS:SP = 0:7C00h
; AX destroyed
;-----------------------------------------------------------------------
; First thing is to reset the stack to a better and more known place.
;
; Move the stack to just under the boot record and relocation area (0:7C00h)
;
; Preserve all other registers
;----------------------------------------------------------------------
CLI ;Stop interrupts till stack ok
XOR AX,AX
MOV SS,AX ;Work in stack just below this routine
MOV SP,7C00h - 30 ;Leave room for stack frame
MOV BP,7C00h - 30 ;Point BP as stack index pointer
STI
subttl Save Input Values
page
;***********************************************************************
; Save_Input_Values
;***********************************************************************
;
; Input: none
;
; DL = INT 13 drive number we booted from
; CH = media byte
; BX = First data sector on disk (0-based)
;
; Output:
;
; BX = first data sector on disk
; CL = number of floppies including fake one
; CH = media byte
;
; [bp].Media_Byte = input CH
; [bp].Drive_Number = input DL
; [bp].First_Sector = input BX
; [bp].Drive_Boot = output AX
; [bp].Number_Floppy = output CL
; [bp].Number_Sectors = Sectors/track
; [bp].Number_Heads = heads/cylinder
;
; DS = 0
; AX,DX,SI destroyed
;
; Calls: none
;-----------------------------------------------------------------------
; Save input information
;
; Get Equipment Flag
;
; Find how many drives on system
;
; Figure out boot drive
;
;----------------------------------------------------------------------
Save_Input_Values:
mov [bp].First_Sector,bx
mov [bp].media_Byte,ch
mov [bp].Drive_Number,dl
; INT 11h ;GET EQUIPMENT STATUS
; ROL AL,1 ;Put bits 6 & 7 into bits 0 & 1
; ROL AL,1
; AND AX,3 ;Only look at bits 0 & 1
; JNZ NOTsingle ;Zero means single drive system
; INC AX ;Pretend it's a two drive system
NOTSingle:
; INC AX ;AX has number of drives, 2-4
;Is also 0 indexed boot drive if we
; booted off hard file
; MOV CL,AL ;CH is FAT ID, CL # floppies
; TEST DL,80H ;BOOT FROM FLOPPY ?
; JNZ GOTHRD ;NO.
; XOR AX,AX ;INDICATE BOOT FROM DRIVE A
GotHrd:
xor ax,ax ;Segment 0
mov ds,ax
assume ds:Bootseg
mov ax,Boot_Sector.SECLIM ;Get Sectors per track
mov [bp].Sectors_Per_Track,ax
mov ax,Boot_Sector.HDLIM ;Get BPB heads per cylinder
mov [bp].Number_Of_Heads,ax
mov ax,Boot_Sector.cSecFat ;Get sectors per FAT
mov [bp].Number_Of_FAT_Sectors,ax
mov ax,Boot_Sector.cSecHid ;Get hidden sectors
mov [bp].Hidden_Sectors,ax
mov ax,Boot_Sector.cSecRes ;Get Reserved Sectors
mov [bp].Reserved_Sectors,ax
subttl Find_Cluster_Size
page
;***********************************************************************
; Find_Cluster_Size
;***********************************************************************
;
; Input: BPB information in loaded boot record at 0:7C00h
;
; Output:
;
; DS = 0
; AX = Bytes/Cluster
; BX = Sectors/Cluster
; SI destroyed
; Calls: none
;-----------------------------------------------------------------------
;
; Get Bytes/sector from BPB
;
; Get sectors/cluster from BPB
;
; Bytes/cluster = Bytes/sector * sector/cluster
;----------------------------------------------------------------------
Find_Cluster_Size:
;For the time being just assume the boot record is valid and the BPB
;is there.
xor ax,ax ;Segment 0
mov ds,ax
assume ds:bootseg
mov ax,Boot_Sector.ByteSec ;Get BPB bytes/sector
xor bx,bx
mov bl,Boot_Sector.cAlloc ;Get sectors/cluster
mul bx ;Bytes/cluster
mov [bp].Size_Cluster,ax ;Save it
subttl Determine FAT size
page
;***********************************************************************
; Determine_FAT_Size
;***********************************************************************
;
; Notes:
;
; Determine if FAT is 12 or 16 bit FAT. 12 bit FAT if floppy, read MBR
; to find out what system id byte is.
;
; Input: [bp].Media_Byte = FAT ID Byte
;
; Output:
;
; [BP].Fat_Size = FAT12_bit or FAT16_bit
; ES = 0
; All other registers destroyed
;
; Calls: READ_DISK
;-----------------------------------------------------------------------
;IF (not FAT ID of F8)
; {12 bit FAT}
;ELSE
; {
; Read in master boot record at 0:7C00h
;
; Scan system id bytes for 1 or 4
;
; IF (Sys id = 4)
; {16 bit FAT}
; ELSE
; {IF (Sys id = 1)
; {12 bit FAT}
; ELSE
; {Error}
; ENDIF
; ENDIF
; ENDIF
;
;----------------------------------------------------------------------
Determine_FAT_Size:
mov [bp].FAT_Size,FAT12_bit ;Assume 12 bit fat
cmp [bp].Media_Byte,0F8h ;Is it floppy
jne FAT_Size_Found ;Yep, all set
mov [bp].Logical_Sector,0 ;Got hardfile, go get MBR
xor ax,ax
mov es,ax
mov di,offset Relocate_Start
mov [bp].Sector_Count,1
call Disk_Read
mov si,offset Relocate_Start+1C2h
mov cx,4
xor ax,ax
mov ds,ax
Find_Sys_Id:
mov [bp].FAT_Size,FAT12_bit ;Assume 12 bit fat
cmp byte ptr [si],1
je FAT_Size_Found
mov [bp].FAT_Size,FAT16_bit ;Assume 12 bit fat
cmp byte ptr [si],4
je Fat_Size_Found
add si,16
loop Find_Sys_Id
;xxxxxxxxxxxxxxxxxxxxxxxxxx error
FAT_Size_Found:
subttl Determine First Cluster
page
;***********************************************************************
; Determine_First_Cluster
;***********************************************************************
;
; Notes: Find the last cluster that was loaded
;
;
; Input:
;
; [BP].Size_Cluster
; Total_Length is offset of end of MSLOAD
;
; Output:
;
; [BP].Last_Found_Cluster = the last cluster loaded containing MSLOAD
; code. This is also the number of clusters
; with MSLOAD code +2
;
; Calls: none
;-----------------------------------------------------------------------
;
;Get length of loader portion of bios
;
;Divide by bytes/cluster
;
;If (Remainder = 0)
; {Last_Used_Cluster = quotient+2}
;Else
; {Last_Used_Cluster = quotient+3}
;----------------------------------------------------------------------
Determine_First_Cluster:
mov [bp].Last_Found_Cluster,1 ;2 is the first cluster-1
mov ax,offset Total_Length ;Get whole length
xor dx,dx
div [bp].Size_Cluster ;Div by bytes/sector
add [bp].Last_Found_Cluster,ax ;Save the result
cmp dx,0 ;Was there remainder?
je First_Cluster_Found ;No
inc [bp].Last_Found_Cluster ;Yes, round up
First_Cluster_Found:
subttl Relocate
page
;
;***********************************************************************
; RELOCATE
;***********************************************************************
;
; Notes:
;
; Relocate the loader code to 0:7C00 - this will allow bios to be loaded
; underneath at 70:0
;
; Input: none
;
; Output: es is set to 0
; ds is set to cs (70h)
; ax,cx,si,di destroyed
;
; Calls: none
;-----------------------------------------------------------------------
; Copy code from Relocate_Code to Relocate_Start (7C00h)
;
; The length to copy is Relocate_Length
;
; Jump to relocated code
;-----------------------------------------------------------------------
;
Relocate:
push cs ;Set up ds segreg
pop ds
xor ax,ax ;Set up ES segreg
mov es,ax
assume es:bootseg,ds:cseg
mov si,offset Relocate_Code ;Source
mov di,offset Relocate_Start ;Target
mov cx,Relocate_Length ;Length
rep movsb ;Go do it
jmp far ptr Relocate_Start
;
;*************************************************************************
;* RELOCATED CODE ********************************************************
;*************************************************************************
;
Relocate_Code label byte
subttl Read In FAT
page
;***********************************************************************
; Read_In_FAT
;***********************************************************************
;
; Notes:
;
; Reads in the entire FAT at 0:8000. This gives the relocated portion
; of this loader a maximum size of 1024 bytes (8000 - 7C00). The max
; size of the FAT is 64 sectors (32k) so everything will fit under the
; 64k DMA boundary, so no problems with loading.
;
; Input: none
;
; Output:
;
; ES = 0
; All sectors destroyed
;
; Calls: READ DISK
;-----------------------------------------------------------------------
; Get number of sectors in FAT
;
; Set ES:DI to 0:8000h
;
; Read in the sectors
;
;----------------------------------------------------------------------
Read_In_FAT:
xor ax,ax
mov ds,ax
assume ds:bootseg
mov ax,[bp].Number_Of_FAT_Sectors ;Get sectors/FAT
mov [bp].Sector_Count,ax ;Number of sectors to read
mov ax,[bp].Hidden_Sectors ;Hidden+Reserved = Fat
add ax,[bp].Reserved_Sectors
mov [bp].Logical_Sector,ax ;Save it, setup for read
xor ax,ax
mov es,ax
mov di,8000h ;Point to buffer
call Disk_Read
subttl Keep Loaded BIO
page
;***********************************************************************
; KEEP LOADED BIO
;***********************************************************************
;
; Notes:
;
; Determine how much of bios was loaded in when the loader was loaded
; by the boot record (only the portion that is guaranteed to be
; contiguous
;
; Input:
;
; [BP].Last_Found_Cluster = number of clusters used for loader+2
;
; Output:
; ES = DS = 70h
; DI = Next offset to load bios code
; AX,BX,CX,DX,SI destroyed
;
; [bp].Next_BIO_Location = DI on output
; [bp].Last_Cluster = last cluster loaded
;
; Calls: none
;-----------------------------------------------------------------------
;Number of clusters loaded+2 is in [BP].Last_Found_Cluster
;
;Multiply cluster * cluster size in bytes to get total loaded for MSLOAD
;
;Subtract TOTAL_LOADED - LOADBIO_SIZE to get loaded bios in last cluster
;
;Relocate this piece of bios down to 70:0
;
;----------------------------------------------------------------------
Keep_Loaded_BIO:
push ds
mov ax,[bp].Last_Found_Cluster ;Point to last cluster loaded
sub ax,1 ;Get number of clusters loaded
mul [bp].Size_Cluster ;Get total bytes loaded by
;This is always < 64k, so
;lower 16 bits ok
sub ax,LoadBio_Size ;Get portion of bios loaded
mov cx,ax ;Save length to move
mov ax,70h ;Segment at 70h
mov ds,ax
mov es,ax
mov si,offset cs:Total_Length ;Point at bios
mov di,0 ;Point at 70:0
rep movsb ;Relocate this code
mov [bp].Next_Bio_Location,di ;Save where to load next
pop ds
subttl Get Contiguous Clusters
page
;***********************************************************************
; Get_Contiguous_Clusters
;***********************************************************************
;
; Notes: Go find clusters as long as they are contiguous
;
;
; Input:
;
; [BP].Next_BIO_Location
; [BP].
;
;
; Output:
;
;
; Calls: Get_Next_FAT_Entry
;-----------------------------------------------------------------------
;
;Set [BP].Sector_Count to Sectors per cluster
;
;Call Get_Next_FAT_Entry to get next cluster in file
;
;Call Check_for_EOF
;
;IF (NC returned)
;
; {Call Get_Next_FAT_Entry
;
; IF (New cluster is contig to old cluster)
; {Add sectors per cluster to [BP].Sector_Count
;
; Call Check_For_EOF
;
; IF (NC returned)
;
;
;----------------------------------------------------------------------
Get_Contiguous_Cluster:
xor ah,ah
mov al,Boot_Sector.cAlloc ;Assume we will get one cluster
mov [bp].Sector_Count,ax
call Get_Next_Fat_Entry ;Go get it
mov [bp].Last_Found_Cluster,ax ;Update the last one found
cmp [bp].EOF,End_Of_File
je GOTO_bios
Got_Contig_Clusters:
sub ax,2 ;Zero base the cluster
xor ch,ch
mov cl,Boot_Sector.cAlloc ;Get sectors per cluster
mul cx ;Get how many
add ax,[bp].First_Sector ;See where the data sector starts
mov [bp].Logical_Sector,ax ;Save it
mov di,[bp].Next_Bio_Location ;Get where to put code
push [bp].Sector_Count ;Save how many sectors
mov ax,dosseg ;Get area to load code
mov es,ax
call Disk_Read
pop ax ;Get back total sectors read in
; jc ##########
mul Boot_Sector.ByteSec ;Get number of bytes we loaded
add [bp].Next_Bio_Location,ax ;Point to where to load next
jmp short Get_Contiguous_Cluster
subttl GOTO bios
page
;***********************************************************************
; GOTO_bios
;***********************************************************************
;
; Notes:
;
; Set up required registers for bios, then jump to it (70:0)
;
; Input: none
;
; [bp].Media_Byte = media byte
; [bp].Drive_Number = INT 13 drive number we booted from
; [bp].First_Sector = First data sector on disk (0-based)
;
; Output:
;
; Required by MSINIT
; DL = INT 13 drive number we booted from
; CH = media byte
; BX = First data sector on disk (0-based)
;
; Calls: none
;-----------------------------------------------------------------------
;
; Set up registers for MSINIT then do Far Jmp
;
;----------------------------------------------------------------------
GOTO_bios:
mov ch,[bp].Media_Byte ;Restore regs required for MSINT
mov dl,[bp].Drive_Number
mov bx,[bp].First_Sector
jmp far ptr bios_Address
subttl Disk Read
page
;***********************************************************************
; Disk_Read
;***********************************************************************
;
; Notes:
;
; Read in the [BP].Sector_Count number of sectors at ES:DI
;
;
; Input: none
;
; DI = Offset of start of read
; ES = Segment of read
; [bp].Sector_Count = number of sectors to read
; [bp].Logical_sector = starting sector
; Following is BPB info that must be setup prior to call
; [bp].Number_Of_Heads
; [bp].Number_Of_Sectors
; [bp].Drive_Number
; [bp].Sectors_Per_Track
;
; Output:
;
; ES = 0
; AX,BX,CX,DX,SI,DI destroyed
;
;
; Calls: none
;-----------------------------------------------------------------------
; Divide start sector by sectors per track
; The remainder is the actual sector number, 0 based
;
; Increment actual sector number to get 1 based
;
; The quotient is the number of tracks - divide by heads to get the cyl
;
; The remainder is actual head, the quotient is cylinder
;
; Figure the number of sectors in that track, set AL to this
;
; Do the read
;
; If Error, Do RESET, then redo the INT 13h
;
; If successful read, Subtract # sectors read from Sector_Count, Add to
; Logical Sector, add #sectors read * Sector_Size to BX;
;
; If Sector_Count <> 0 Do next read
;----------------------------------------------------------------------
Disk_Read:
;
; convert a logical sector into Track/sector/head. AX has the logical
; sector number
;
DODIV:
MOV cx,5 ;5 retries
Try_Read:
PUSH cx ;Save it
MOV AX,[bp].Logical_Sector ;Get starting sector
XOR DX,DX
DIV word ptr [bp].Sectors_Per_Track
MOV bx,[bp].Sectors_Per_Track ;Get number of sectors we can
sub bx,dx ;read in this track
mov si,bx
cmp [bp].Sector_Count,si ;Is possible sectors in track more
jae Got_Length ;than what we need to read?
mov si,[bp].Sector_Count ;Yes, only read what we need to
Got_Length:
INC DL ; sector numbers are 1-based
MOV bl,dl ;Start sector in DL
XOR DX,DX
DIV word ptr [bp].Number_Of_Heads ;Start cyl in ax,head in DL
MOV DH,DL
;
; Issue one read request. ES:BX have the transfer address, AL is the number
; of sectors.
;
;
; Now convert to standard ROM call
;
mov cl,bl ;Get starting sector
ror ah,1 ;Set up high 2 bits
ror ah,1 ;Set up high 2 bits
or cl,ah ;Combine cyl/start sector
mov ch,al ;Set low order of cyl
mov bx,di ;Set offset
mov dl,[bp].Drive_Number ;Set drive
mov ax,si ;Set count
mov ah,02 ;Read Command
push ax ;Save regs
push di ; *
int 13h ;Call ROM-Bios
pop di ;Restore Regs
pop ax ; *
pop cx ;Get retry count back
jnc Read_OK
push cx
mov bx,di ;
push di ;Save Reg
mov dl,[bp].Drive_Number ;Set drive
mov ah,0 ;RESET Disk Command
int 13h ;Call ROM-Bios
pop di ;Restore Reg
pop cx
loop Try_Read
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx error
Read_OK:
xor ah,ah ;Mask out command, just get # read
sub [bp].Sector_Count,ax ;Bump number down
jz Read_Finished
add [bp].Logical_Sector,ax ;Where to start next time
xor bx,bx ;Get number sectors read
mov bl,al
mov ax,Boot_Sector.ByteSec ;Bytes per sector
mul bx ;Get total bytes read
add di,ax ;Add it to offset
jmp short DODIV
Read_Finished:
RET
subttl GET NEXT FAT ENTRY
page
;***********************************************************************
; GET_NEXT_FAT_ENTRY
;***********************************************************************
;
; Notes:
;
; Given the last cluster found, this will return the next cluster of
; bios. If the last cluster is (F)FF8 - (F)FFF, then the final cluster
; of bios has been loaded, and control is passed to GOTO_bios
;
; Input:
;
; [bp].Last_Found_Cluster
; [bp].Fat_Size
;
; Output:
;
; [bp].Last_Found_Cluster (updated)
;
; Calls: none
;-----------------------------------------------------------------------
; Get Last_Found_Cluster
;
; IF (16 bit FAT)
; {IF (Last_Found_Cluster = FFF8 - FFFF)
; {JMP GOTO_bios}
; ELSE
; {Get offset by multiply cluster by 2}
;
; ELSE
; {IF (Last_Found_Cluster = FF8 - FFF)
; {JMP GOTO_bios}
; ELSE
; {Get offset by - multiply cluster by 3
;
; Rotate right to divide by 2
;
; IF (CY set - means odd number)
; {SHR 4 times to keep high twelve bits}
;
; ELSE
; {AND with 0FFFh to keep low 12 bits}
; }
; }
;
; Add in 8000h to get offset of next cluster in FAT buffer
;
;----------------------------------------------------------------------
Get_Next_FAT_Entry:
mov [bp].EOF,End_Of_File ;Assume last cluster
mov ax,[bp].Last_Found_Cluster ;Get last cluster
cmp [bp].Fat_Size,FAT12_bit
jne Got_16_Bit
xor bx,bx
mov bl,3 ;Mult by 3
mul bx
shr ax,1 ;Div by 2 to get 1.5
mov si,ax ;Get the final buffer offset
mov ax,[si]+8000h ;Get new cluster
test [bp].Last_Found_Cluster,1 ;Was last cluster odd?
jnz Odd_Result ;If Carry set it was odd
and ax,0FFFh ;Keep low 12 bits
jmp short Test_EOF
Odd_Result:
mov cl,4 ;Keep high 12 bits for odd
shr ax,cl
Test_EOF:
cmp ax,0FF8h ;Is it last cluster?
jae Got_Cluster_Done ;Yep, all done here
jmp short Not_Last_CLuster
Got_16_Bit:
shl ax,1 ;Multiply cluster by 2
mov si,ax ;Get the final buffer offset
mov ax,[si]+8000h ;Get new cluster
cmp ax,0FFF8h
jae Got_Cluster_Done
Not_Last_Cluster:
mov [bp].EOF,not End_Of_File ;Assume last cluster
Got_Cluster_Done:
ret
Relocate_Length equ $ - Read_In_FAT
Total_Length label byte
LoadBIO_Size equ $ - Start
cseg ends
end start