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.
 
 
 
 

1168 lines
26 KiB

; SCCSID = @(#)sys.asm 1.12 85/10/06
TITLE MS-DOS SYS Program
; SYS - Copies system programs IBMBIO.COM/IO.SYS and IBMDOS.COM/MSDOS.SYS
; 1.6 05/21/82 Added rev number message
; 1.61 06/04/82 Allow SYS to blank disk TimP at SCP
; 1.70 06/30/82 NON contiguous DOS allowed on 2.00 IBM. Allows SYS to
; 1.0 1.1 disks.
; 1.71 07/02/82 Put in CHDIRs to make sure everything done in root dir.
; 1.80 04/26/83 MZ make sys work in small machines; use full 2.0
; system calls
; 1.81 07/22/83 ARR Added check in IBM version for valid FAT ID on
; destination because of IBM problem with SYSing to
; unformatted disks which are really formatted. Prints
; NoDest message for ridic IBM reasons, should have a
; better message.
; 1.82 08/12/83 ARR ZIBOed again. Mark fails to check for errors on
; his file I/O. Results in SYS saying system
; transferred when it hasn't been.
; 1.83 09/08/83 EKE Added code to quit if sys called on a drive across
; a net.
; 1.84 09/09/83 CHRISP grabbed against his will to make this stupid
; program write out a boot sector
; 1.85 10/18/83 NP Printf to print messages and it's now an .EXE file
; 1.86 11/8/83 MZ fix hard file output of boot sector
; 1.87 5/1/84 MZ make sys prompt for system disk in default drive.
; 3.20 11/9/84 RS make sys write out a correct boot sector for the
; version of DOS. It grabs the boot sector off the system
; disk and inserts the correct BPB.
; Uses IOCTL Get Device Parms to get BPB for a Hard drive.
; 3.20 08/5/85 RS Allow FAT ID byte of 0F0H for 'strange' media
; layouts. These come about because of /T /N switches in
; FORMAT.
; 3.20 09/16/85 Incorporate tables of filenames to allow system files
; used by other OEMs to be SYSed onto disks formatted on
; other MSDOS systems. Allows the flexibility to replace
; system files for one OEM by system files for another.
;
;
; 3.30 06/04/86 MT removes initial check for IBMBIO and DOS - not needed
; because of later search of dirs
; 3.30 06/16/86 MT only force part of IBMBIO contig - do this by assuming
; contig part smaller than 1.10 BIOS
; 3.30 06/16/86 MT Check diks space for enough room to install BIO and DOS
.xlist
.xcref
include version.inc
INCLUDE DOSSYM.INC ;also defines version of dos
include ioctl.INC
.cref
.list
;IBMJAPVER EQU FALSE ; this and the following are mutually
;IBMVER EQU TRUE ; exclusive
;IBMCOPYRIGHT EQU FALSE
printf_code segment public
extrn printf:far
printf_code ends
CODE SEGMENT PARA PUBLIC
CODE ENDS
CONST SEGMENT BYTE PUBLIC
EXTRN BIOSNamesTable:byte, DOSNamesTable:byte
EXTRN SourceBIOSFile:byte, SourceDOSFile:byte
CONST ENDS
cstack segment stack
db 278 + 80h dup (?) ; 278 == IBM's ROM requirements
cstack ends
DATA SEGMENT BYTE PUBLIC
DG GROUP CODE,DATA,CONST,cstack
EXTRN BADDRV_ptr:byte, BADPARM_ptr:byte, GETSYS_ptr:byte
EXTRN SYSDRV:byte, NODEST_ptr:byte, BADSIZ_ptr:byte, DONE_ptr:byte
EXTRN BADVER:byte, Crlf_ptr:byte, NoSYS_PTR:byte, GetTarg_ptr:byte
EXTRN TargDrv:byte
EXTRN NotNetM_ptr:byte
DEFALT DB 0
IF IBMCOPYRIGHT
BIOSName DB "A:\IBMBIO.COM",0
DOSName DB "A:\IBMDOS.COM",0
SourceBIOSName DB "A:\IBMBIO.COM",0
SourceDOSName DB "A:\IBMDOS.COM",0
ELSE
BIOSName DB "A:\IO.SYS",0
DOSName DB "A:\MSDOS.SYS",0
SourceBIOSName DB "A:\IO.SYS",0
SourceDOSName DB "A:\MSDOS.SYS",0
ENDIF
IBMBIO_LOW DW 0 ;length of IBMBIO on disk
IBMBIO_HIGH DW 0
IBMDOS_LOW DW 0 ;length of old IBMDOS on disk
IBMDOS_HIGH DW 0
SIZE_OLD_HIGH DW 0
SIZE_OLD_LOW DW 0
NEWBIO_SIZE_LOW DW 0
NEWBIO_SIZE_HIGH DW 0
NEWDOS_SIZE_LOW DW 0
NEWDOS_SIZE_HIGH DW 0
Need_Clusters dw 0
Bytes_Per_Cluster dw 0
Number_Free_Clusters dw 0
;*** WARNING ***
; KEEP THE FOLLOWING ITEMS IN THE EXACT ORDER BELOW!!!
DOSEntFree DB 1
BIOSEntFree DB 1
BIOSInFH DW ? ; file handle of source BIOS
BIOSLenLow DW 2 DUP (?) ; 32-bit length of BIOS
BIOSLenHigh DW 2 DUP (?) ; 32-bit length of BIOS
BIOSTime DW 2 DUP (?) ; place to store time of BIOS write
BIOSOutFH DW ? ; fh of BIOS destination
DOSInFH DW ? ; file handle of source DOS
DOSLenLow DW 2 DUP (?) ; 32-bit length of DOS
DOSLenHigh DW 2 DUP (?) ; 32-bit length of DOS
DOSTime DW 2 DUP (?) ; place to store time of DOS write
DOSOutFH DW ? ; fh of DOS destination
AllName DB "A:\*.*",0
;******************************************
;FCB SNOT
fcb_copy db 32 dup(?)
IF IBMCOPYRIGHT
FCBDOS DB "IBMDOS COM"
FCBBIO DB "IBMBIO COM"
ELSE
FCBDOS DB "MSDOS SYS"
FCBBIO DB "IO SYS"
ENDIF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DOSFile_Offset dw 0 ; Index for system file names in Tables
DirEnt DB 80h DUP (?)
cbBuf DW ? ; number of bytes in buffer
pDOS DW ? ; offset of beginning of DOS in buffer
pDOSEnd DW ? ; offset of end of DOS in buffer
BIOSEG EQU 70H ; STARTING LOCATION OF BIOS
BPBLEN EQU 19
BPB LABEL DWORD ; POINTER TO HARDFILE BPB
DW 0000
DW BIOSEG
public boot
BOOT DB 0,0,0 ; SKIP THE THREE BYTE JUMP
DB "MSDOS3.3"
SECSIZ DW 512 ; SECTOR SIZE
SECALL DB 1 ; SECTOS PER ALLOCATION UNIT
RESNUM DW 1 ; RESERVED SECTORS
FATNUM DB 2 ; NUMBER OF FATS
DIRNUM DW 64 ; NUMBER OF DIRECTORY ENTRIES
SECNUM DW 1*8*40 ; NUMBER OF SECTORS
FATID DB 0FEH
FATSIZE DW 1
SECLIM DW 8
HDLIM DW 1
HIDDEN DW 0
PHYDRV DB 0
DB 510-($-boot) dup (?)
DB 55H,0AAH ; MAGIC WORD
REORG LABEL BYTE
ORG BOOT
INCLUDE ..\BOOT\BOOT.INC
ORG REORG
FATID_TABLE LABEL WORD
DW 0 ; F8 FIXED DISK
DW -2 ; F9
DW -1 ; FA
DW -1 ; FB
DW OFFSET DG:BPB91 ; FC
DW OFFSET DG:BPB92 ; FD
DW OFFSET DG:BPB81 ; FE
DW OFFSET DG:BPB82 ; FF
; BIOS PARAMETER BLOCKS FOR THE VARIOUS MEDIA
BPB81 DB 1
DW 1
DB 2
DW 64
DW 1*8*40
DB 0FEH
DW 1
DW 8
DW 1
DW 0
DB 0
BPB82 DB 2
DW 1
DB 2
DW 112
DW 2*8*40
DB 0FFH
DW 1
DW 8
DW 2
DW 0
DB 0
BPB91 DB 1
DW 1
DB 2
DW 64
DW 1*9*40
DB 0FCH
DW 2
DW 9
DW 1
DW 0
DB 0
BPB92 DB 2
DW 1
DB 2
DW 112
DW 2*9*40
DB 0FDH
DW 2
DW 9
DW 2
DW 0
DB 0
BPB96T DB 1 ; mjb001
DW 1
DB 2
DW 224
DW 2*15*80
DB 0f9H
DW 7
DW 15
DW 2
DW 0
DB 0
BPBSIZ = $-BPB96T
BPB325 DB 2 ; mjb001
DW 1
DB 2
DW 70h
cSec325 DW 2*9*80
DB 0f9H
DW 3
DW 9
DW 2
DW 0
DB 0
;
; Following structure used by Generic IOCTL call Get Device Parameters to get
; the BPB of a hard disk. It 'overflows' into area of BUF.
;
DeviceParameters a_DeviceParameters <0,DEV_HARDDISK>
BUF LABEL BYTE ; beginning of area for file reads
DATA ENDS
CODE SEGMENT PUBLIC PARA
ASSUME CS:DG,DS:NOTHING,ES:NOTHING,SS:CSTACK
start:
JMP SHORT CheckVersion
DW OFFSET DG:BOOT
HEADER DB "SYS 3.30"
CheckVersion:
PUSH AX ; save drive letter validity
MOV AH,GET_VERSION
INT 21H ; get dos version
cmp ax,expected_version
jne gotbaddos
; XCHG AH,AL ; Turn it around to AH.AL
; CMP AX,DOSVER_LOW ; is it too low?
; JNE GOTBADDOS ; yes, error
pop ax
ASSUME DS:NOTHING,ES:NOTHING
push cs
pop es
ASSUME ES:DG
mov si,5ch
mov di,offset dg:fcb_copy
mov cx,32
rep movsb
push cs
pop ds
ASSUME DS:DG
MOV DX,OFFSET DG:DirEnt
MOV AH,SET_DMA
INT 21h
jmp sys
GOTBADDOS:
push cs
pop ds
ASSUME DS:DG
MOV DX,OFFSET DG:BADVER ; message to dump
mov ah,std_con_string_output
int 21h
push es
xor ax,ax
push ax
foo proc far
ret ; Must use this method, version may be < 2.00
foo endp
ERR0:
ASSUME DS:DG,ES:DG
MOV DX,OFFSET DG:BADPARM_ptr ; no drive letter
JMP xerror
ERR1:
ASSUME DS:DG,ES:DG
MOV DX,OFFSET DG:BADDRV_ptr ; drive letter invalid
JMP xerror
;
; We do not have a disk that has an available system in the root. See if the
; media is removable and if so, ask the user for a replacement. If the media
; is not removable, then die gracefully.
;
ERR2:
ASSUME DS:DG,ES:DG
MOV AH,GET_DEFAULT_DRIVE ;Will find out the default drive
INT 21H ;Default now in AL
MOV BL,AL
INC BL ; A = 1
Call IsRemovable
jnc DoPrompt
MOV DX,OFFSET DG:NoSys_PTR
PUSH DX
CALL PRINTF
MOV AX,4C01h
INT 21h
DoPrompt:
MOV AL,DEFALT ; get default drive number
ADD AL,'A'-1 ; turn into letter
MOV SYSDRV,AL
MOV DX,OFFSET DG:GETSYS_ptr
push dx
call printf
CALL GetKeystroke ; wait for him to type simething
XOR AL,AL ; valid drive spec now...
SYS:
ASSUME DS:DG,ES:DG
mov DOSEntFree,1
mov BIOSEntFree,1
CMP BYTE PTR fcb_copy+1," " ; Was file specified?
JNZ ERR0 ; yes, no files are allowed -> error
CMP AL,-1 ; Invalid drive spec?
JZ ERR1 ; yes, must have valid drive -> error
CMP BYTE PTR fcb_copy,0 ; No drive specified?
JZ ERR1 ; yes, cannot sys to default drive error
MOV AH,GET_DEFAULT_DRIVE ; Get default drive
INT 21H
INC AL ; turn from phys drive to logical drive
MOV DEFALT,AL ; save it for possible printing
CMP BYTE PTR fcb_copy,AL ; did he specify the default drive?
JZ ERR1 ; yes, default drive not allowed
;------Code to quit if sys called on a drive across a net-----------------------
CheckNet:
MOV BL,BYTE PTR fcb_copy ; x = IOCTL (getdrive, Drive+1);
MOV AX,(IOCTL SHL 8) + 9
INT 21H
JC NotNet
TEST DX,1200H ; if(x & 0x1000)(redirected or shared)
JZ NotNet
MOV DX,OFFSET DG:NotNetM_ptr ; Fatal ("Can't do over net");
JMP xerror
;-------Load up BIOS and DOS at this point ---------------------------------
NotNet:
MOV AL,DEFALT
ADD AL,'A'-1 ; turn into letter
MOV SourceBIOSName,AL ; twiddle source name
MOV SourceDOSName,AL ; twiddle source name
CLD
MOV DX,OFFSET DG:SourceBIOSName ; source name
MOV CX,7
MOV AH,4Eh
INT 21h
JC ERR2J
MOV AX,WORD PTR DG:DIRENt+26
MOV WORD PTR NEWBIO_SIZE_LOW,AX
MOV AX,WORD PTR DG:DIRENt+28
MOV WORD PTR NEWBIO_SIZE_HIGH,AX
MOV DX,OFFSET DG:SourceBIOSName ; source name
MOV DI,OFFSET DG:BIOSInFH ; pointer to block of data
CALL OpenFile
JNC NotERR2
ERR2J:
JMP Err2 ; not found, go and try again
NotERR2:
MOV DX,OFFSET DG:SourceDOSName ; source name
MOV CX,7
MOV AH,4Eh
INT 21h
JC ERR2J
MOV AX,WORD PTR DG:DIRENt+26
MOV WORD PTR NEWDOS_SIZE_LOW,AX
MOV AX,WORD PTR DG:DIRENt+28
MOV WORD PTR NEWDOS_SIZE_HIGH,AX
MOV DX,OFFSET DG:SourceDOSName ; source of DOS
MOV DI,OFFSET DG:DOSInFH ; pointer to block of data
CALL OpenFile ; Look for DOS
JC ERR2J ; not there, go ask for a system disk
MOV CX,SP ; get lowest available spot
SUB CX,0200h+(OFFSET DG:BUF); leave room for all sorts of things
MOV cbBuf,CX ; store length away
CALL FillMem ; load up memory with files
JC ERR2J ; Some kind of error reading system
CheckDest:
;------------Check for "valid" destination-----------------------------------
MOV AH,0Dh
INT 21h
MOV AL,BYTE PTR fcb_copy
DEC AL
MOV BX,OFFSET DG:buf ; Temp space
MOV DX,1 ; Sector 1 (first sec of FAT)
MOV CX,DX ; One sector
INT 25H ; Read Fat sector
POP AX ; Flags
JC PromptDest ; Issue prompt to insert Destination
; disk
CMP BYTE PTR [BUF],0F8H
JAE OKFAT
;---------Treat 0F0H as a valid 'IBM' FAT ID byte--------------------------------
cmp BYTE PTR [BUF],0F0H
je OKFAT
JMP ERR3
PromptDest:
push ax
mov al,Byte ptr fcb_copy ; Get destination ID
ADD AL,'A'-1 ; turn into letter
MOV TargDrv,AL
MOV DX,OFFSET DG:GetTarg_ptr
push dx
call printf
CALL GetKeystroke ; wait for him to type simething
pop ax
jmp CheckDest
;-------The Fat appears to be OK... See if DOS/Bios there-----------------
OKFAT:
;
;Set up drive letter in destignation filespecs
;
MOV AL,BYTE PTR fcb_copy
ADD AL,'A'-1 ; convert to letter
MOV BIOSName,AL ; point names at destination drive
MOV DOSName,AL
;
; Read in first sector of directory
;
; The reason that we do the direct read of the directory is the find first/next
; or search first/next do an exclusive search for volume labels. By using these
; calls, there is no way to determine if a volume label occupies the first
; location in the directory. Hence we get sleazy and read the directory directly
; (no pun intended) to get this info. While its in there, go ahead and grab the file
; sizes. -MT
;
GetDir:
MOV DL,Byte PTR fcb_copy
MOV AH,Get_DPB
PUSH DS
INT 21h
; DS:BX point to DPB
MOV DX,[BX.dpb_dir_sector]
POP DS
MOV AL,BYTE PTR fcb_copy
DEC AL
MOV BX,OFFSET DG:BUF ; Temp space
MOV CX,1 ; Sector 1 (first sec of FAT)
INT 25H ; Read Fat sector
POP AX ; Flags
JNC Skip
;
;NOTE!!!! This next jump is actually a bug left over from the MS days - if the
;dir is not read successfully then the SYS should be canned at that point -
;however, up thru 3.20 this would just jump to the actual sys. To make things
; a little better I jump to an error - this needs to be DCR'd for a real error
;
JMP Err3
Skip:
;
; Now see if the first two directory entries are available... First check
; for being free:
;
MOV SI,OFFSET DG:BUF
CMP BYTE PTR [SI],0 ; empty dir?
JE Get_Space ; yes, go check for conflicts
CLD
CMP BYTE PTR [SI],0E5h
JE SecondFree
;
; The first entry is not free. See if the BIOS is there
;
MOV DI,OFFSET DG:FCBBIO
MOV CX,11
REP CMPSB
JNE Err3jj ; not BIOS
DEC BIOSEntFree
; added by dcl 8/24/86 - most cases solution
mov ax,0002 ; is ibmbio allocated the 1st cluster?
cmp ax,word ptr DG:BUF+26 ; that being cluster 2???
JNE Err3jj ; not cluster 2 - error; go display
; end added by dcl 8/24/86
;
; IBM change - MT 6/16/86
; Get the size of the file for IBMBIO
;
MOV ax,word ptr DG:BUF+28
MOV word ptr IBMBIO_Low,ax
MOV ax,word ptr DG:BUF+30
MOV word ptr IBMBIO_High,ax
; Check the second entry
;
SecondFree:
MOV SI,OFFSET DG:BUF+32
CMP BYTE PTR [SI],0 ; empty dir?
JE Get_Space ; yes, go check for conflicts
CMP BYTE PTR [SI],0E5h ; how about second?
JE Get_Space
;
; This entry is not free. Check it for IBMDOS
;
MOV DI,OFFSET DG:FCBDOS
MOV CX,11
REP CMPSB
Err3jj: JNZ Err3j1 ; not DOS
DEC DOSEntFree
;
; IBM change - MT 6/16/86
; Get the file size for IBMDOS
;
MOV ax,word ptr DG:BUF+60
MOV word ptr IBMDOS_Low,ax
MOV ax,word ptr DG:BUF+62
MOV word ptr IBMDOS_High,ax
;
; We now have the following:
; Whether or not there is a DOS/BIOS on the disk
; Whether or not the appropriate entry is free
; We are guaranteed that if the entry is free, then it has the correct file in
;
;IBM CHANGE - MT 6/16/86
;
; Here we make some VERY IMPORTANT assumptions.
;
;1) If IBMBIO exists on the disk currently, we assume it is in the correct
; place, i.e. at the front of the data area and contiguous.
;2) The stub loader portion of IBMBIO is less than 2048 bytes long. This
; number comes about by assuming we will never overlay anything smaller
; than 1920 bytes (DOS 1.10 IBMBIO size). This can be expanded to 2048 if
; we also assume the smallest possible cluster length is 512 bytes.
;
; Therefore, if we have an empty disk or IBMBIO exists, then we have enough
; contiguous room to install the portion of IBMBIO that requires itself to
; be contiguous.
;
;IBM CHANGE - MT 6/16/86
;
;See if enough free space for IBMBIO and IBMDOS
;
GET_SPACE:
MOV AH,36H ;Get free space
MOV DL,byte ptr fcb_copy ;Get the drive letter
INT 21h
;16 bit math okay here, no danger of overflow
MUL CX ;Get bytes/cluster
;Result left in AX
PUSH AX ;Save it for later
MOV Bytes_Per_Cluster,AX
MOV Number_Free_Clusters,BX
;Low result in AX, High result in DX
;Get IBMBIO size
MOV AX,IBMBIO_Low
MOV DX,IBMBIO_High
CALL Get_Clusters
ADD Number_Free_Clusters,AX
;Low result in AX, High result in DX
;Get IBMDOS size
MOV AX,IBMDOS_Low
MOV DX,IBMDOS_High
CALL Get_Clusters
ADD Number_Free_Clusters,AX
;Find the total size of new DOS and BIOS
MOV AX,NEWBIO_Size_Low
MOV DX,NEWBIO_Size_High
CALL Get_Clusters
Got_NEW_BIO_Clusters:
MOV Need_Clusters,AX
MOV AX,NEWDOS_Size_Low
MOV DX,NEWDOS_Size_High
CALL Get_Clusters
ADD AX,Need_Clusters
;Now see if there is enough room for all of it on the disk
CMP AX,Number_Free_Clusters
JBE PUT_SYS
ERR3J1:
JMP ERR3
;Go do the sys
PUT_SYS:
CMP BIOSEntFree,0
JNE GetRidDOS
MOV DX,OFFSET DG:BIOSName ; who to change mode
MOV CX,0 ; undo attributes
MOV AX,(ChMod SHL 8) + 1 ; set the attributes
INT 21h
MOV DX,OFFSET DG:BIOSName
MOV AX,(UNLINK SHL 8)
INT 21H ; Delete BIOS file
GetRidDOS:
CMP DOSEntFree,0
JNE CreateBIOS
MOV DX,OFFSET DG:DOSName ; who to change mode
MOV CX,0 ; undo attributes
MOV AX,(ChMod SHL 8) + 1 ; set the attributes
INT 21h
MOV DX,OFFSET DG:DOSName
MOV AX,(UNLINK SHL 8)
INT 21H ; Delete DOS file
CreateBIOS:
MOV DX,OFFSET DG:BIOSName ; destination of BIOS
MOV CX,7 ; fancy attributes
MOV AH,Creat ; make a new one
INT 21h
JC err3j2
MOV BIOSOutFH,AX ; save handle
MOV DX,OFFSET DG:DOSName ; destination of DOS
MOV AH,Creat ; make a new one
INT 21h
JC err3j2
MOV DOSOutFH,AX ; save handle
PUSH DS
MOV AH,GET_DPB
MOV DL,BYTE PTR fcb_copy ; Target drive
INT 21H
MOV [BX.dpb_next_free],0 ; Reset Allocation to start of disk
; so BIOS goes in right place!
POP DS
Copy:
CALL DumpMem ; flush out memory
JC ERR3J2 ; Disk full or some other error
MOV AX,DOSLenHigh ; more DOS?
OR AX,DOSLenLow ; more low dos
OR AX,BIOSLenHigh ; more high BIOS
OR AX,BIOSLenLow ; more low BIOS
JZ AllDone ; nope, all done
CALL FillMem ; reload world
JNC Copy
JMP ERR2 ; Start over again
ERR3J2:
JMP ERR3
ERR4:
MOV DX,OFFSET DG:BADSIZ_ptr
JMP xerror
AllDone:
MOV CX,BIOSTime ; get time and date
MOV DX,BIOSTime+2
MOV BX,BIOSOutFH ; where to stuff the time
MOV AX,(File_Times SHL 8) + 1
INT 21h
MOV AH,Close
INT 21h
MOV CX,DOSTime ; get time and date
MOV DX,DOSTime+2
MOV BX,DOSOutFH ; where to stuff the time
MOV AX,(File_Times SHL 8) + 1
INT 21h
MOV AH,Close
INT 21h
CALL PUTBOOT ; copy the boot sector also
MOV DX,OFFSET DG:DONE_ptr ; all finished message
push dx
call printf
XOR AL,AL ; ok error code
jmp short rexit
xerror:
push dx
call printf
mov dx,offset dg:crlf_ptr
push dx
call printf
mov al,0ffh
rexit:
MOV AH,EXIT ; bye and return error code
INT 21h
POPRET:
POP CX
SETERR:
STC
return
Get_Clusters:
;Round up to the next cluster size
MOV BX,Bytes_Per_Cluster ;Bytes/cluster
DIV BX ;If there is a remainder in DX, then
;we have another cluster to round up
CMP DX,0
JE Got_CLUSTERS
INC AX ;Round up to next cluster
Got_Clusters:
RET
FillMem:
MOV CX,cbBuf ; get length of buffer
MOV BX,BIOSInFH ; get bios source handle
MOV DX,OFFSET DG:BUF+512 ; point to beginning of buffer
; past area to read in boot rec
PUSH CX ; save away total length
CMP BIOSLenHigh,0 ; > 64K to read?
JA UseCX ; use CX
CMP BIOSLenLow,CX ; more left to read?
JA UseCX ; use CX
MOV CX,BIOSLenLow ; move new
UseCX:
MOV AH,Read
INT 21h ; read in what we can
JC POPRET ; Error
CMP AX,CX ; Did we get it all?
JNZ POPRET ; No, error
ADD DX,AX ; update pointer for DOS Read
MOV pDOS,DX ; point to beginning of DOS
SUB BIOSLenLow,AX ; decrement remaining
SBB BIOSLenHigh,0 ; do 32 bit
POP CX ; get original length
SUB CX,AX ; this much is left
MOV BX,DOSInFH ; get bios source handle
CMP DOSLenHigh,0 ; > 64K to read?
JA UseCXDOS ; use CX
CMP DOSLenLow,CX ; more left to read?
JA UseCXDOS ; use CX
MOV CX,DOSLenLow ; move new
UseCXDOS:
MOV AH,Read
INT 21h ; read in what we can
retc ; error
CMP AX,CX
JNZ SETERR ; Didn't read it all
ADD DX,AX ; update pointer for DOS Read
MOV pDOSEnd,DX ; point to End of dos DOS
SUB DOSLenLow,AX ; decrement remaining
SBB DOSLenHigh,0 ; do 32 bit arithmetic
CLC
return
OpenFile:
MOV AX,(OPEN SHL 8) + 0 ; open for reading only
INT 21H ; Look for BIOS
retc ; not found, go and try again
STOSW ; stash away handle
MOV BX,AX ; get ready for seeks
MOV AX,(LSeek SHL 8) + 2 ; seek relative to eof
XOR CX,CX ; zero offset
XOR DX,DX ; zero offset
INT 21h ; get offsets
STOSW ; save low part of size
STOSW ; save low part of size
MOV AX,DX
STOSW ; save high part of size
STOSW ; save high part of size
XOR DX,DX ; zero offset
MOV AX,(LSeek SHL 8) + 0 ; seek relative to beginning
INT 21h
MOV AX,(File_Times SHL 8) + 0
INT 21h ; get last write times
MOV AX,CX
STOSW ; save time
MOV AX,DX
STOSW ; save date
return
ERR3:
MOV DX,OFFSET DG:NODEST_ptr
JMP xerror
DumpMem:
MOV DX,OFFSET DG:BUF+512 ; get offset of bios start
MOV CX,pDOS ; beginning of next guy
SUB CX,DX ; difference is length
JZ DumpDos ; no bios to move
MOV BX,BIOSOutFH ; where to output
MOV AH,Write
INT 21h ; wham
retc ; error
CMP AX,CX ; Did it work?
JNZ WRERR ; No
DumpDos:
MOV DX,pDOS ; beginning of dos
MOV CX,pDOSEnd ; end of dos
SUB CX,DX ; difference is length
retz ; if zero no write
MOV BX,DOSOutFH ; where to output
MOV AH,Write
INT 21h ; wham
retc ; error
CMP AX,CX ; Did it work?
retz ; Yes, carry clear
WRERR:
STC
return
;
; Output a boot sector apporpriate to the supposed version of DOS. We do this
; by reading in the boot sector for the drive and getting the BPB from there.
; This works fine until we get a 1.x diskette, when we have to grab the media
; descriptor byte and select the correct BPB using that.
;
public putboot
PUTBOOT:
mov ax,dg ; initialize DS.
mov ds,ax
mov al,byte ptr fcb_copy ; target drive 1-based
dec al ; convert to 0-based
mov dx,0000H ; get relative sector 0
call Read_Sec
jc Do_Media_Byte
cmp word ptr DG:[Buf+1FEH], 0AA55H ; Is it a 1.x disk?
jnz Do_Media_Byte
PB0:
mov si,(offset DG:Buf)+13 ; Set up SI to point to 'SECALL' in
; the BPB just read in.
jmp PB7
;
; We were unable to use the BPB in the boot sector, so we must now get a
; valid BPB by examining the media descriptor byte.
;
Do_Media_Byte:
MOV AH,GET_DPB
MOV DL,BYTE PTR fcb_copy ; Target drive
INT 21H
MOV AL,[BX.dpb_media] ; Media byte
PUSH CS
POP DS
SUB AL,0F8H
CBW
MOV BX,AX ; BX has offset into bpb table
SHL BX,1 ; Word table, mult by 2
MOV SI,[BX+FATID_TABLE] ; get pointer to bpb
OR SI,SI ; hardfile?
JNZ PB3 ; nope.
;
; We have a hard drive. We can use the IOCTL Get Device Parameters to get the
; BPB for the hard drive.
;
mov bl,byte ptr fcb_copy ; Drive number
mov dx,offset DeviceParameters
mov ah,IOCTL
mov al,GENERIC_IOCTL
mov ch,RAWIO
mov cl,Get_Device_Parameters
int 21H
mov bx,dx ; ds:bx-> DeviceParameters
lea si,byte ptr [bx].DP_BPB ; SI -> BPB returned
inc si
inc si ; si-> secall in BPB
PB3: CMP SI,-1 ; weird internal error?
JZ PB9
CMP SI,-2 ; new multi-value FAT ID?
JNZ PB7 ; nope.
;
; We may have a FAT ID of F9. This may represent TWO different media in two
; incompatible drives. We do a get free space to determine which.
;
MOV AH,Get_Drive_freespace
MOV DL,BYTE PTR FCB_copy
INT 21h
MOV BX,DX
MUL BX ; compute total sectors
CMP AX,cSec325
MOV SI,OFFSET DG:BPB325
JB PB7
MOV SI,OFFSET DG:BPB96T
PB7: PUSH DS ; COPY IN THE NEW STUFF
POP ES
MOV DI,OFFSET DG:SECALL
MOV CX,BPBSIZ
CLD
REP MOVSB
PB8:
cmp dg:FATID,0F8H ; Hard drive?
jnz not_hard
; NOTE:
; The physical hard drive number is placed in the third byte from the end in the
; boot sector in DOS 3.2. This is a change from the previous DOS versions.
;
mov byte ptr dg:[boot+1FDH],80H ; set physical hard drive number
not_hard:
MOV AL,BYTE PTR fcb_copy
DEC AL
MOV BX,OFFSET DG:BOOT ; Boot sector
XOR DX,DX ; Sector 0
MOV CX,DX
INC CX ; One sector
INT 26H ; Write out 8 sector boot sector
jnc pb9
PB9: POP AX ; Flags
RET
;
; Read_Sec reads the sector and track specified in DX from the drive in AL.
; The sector is read into location Buf. Carry set if error.
;
READ_SEC:
push ax ; save registers
mov cx,0001H
mov bx,Offset DG:Buf ; temp. buffer
int 25H
pop ax ; Pop flags pushed by Int 25
Read_Ret:
pop ax
ret
GetKeystroke:
MOV AX,(Std_CON_Input_Flush SHL 8) + Std_CON_Input_No_Echo
INT 21H
MOV AX,(Std_CON_Input_Flush SHL 8) + 0
INT 21H
mov dx,offset dg:crlf_ptr
push dx
call printf
return
;
; Determine if the drive indicated in BX is removable or not.
;
; Inputs: BX has drive (0=default, 1=A)
; Outputs: Carry clear => removable
; Carry set => non-removable
;
; Registers modified: none
;
IsRemovable:
SaveReg <AX>
mov AX,(IOCTL SHL 8) OR 8 ; do a media check
INT 21H
jnc CheckRemove
MOV AX,(IOCTL SHL 8) OR 9 ; Is it a net drive
INT 21H
jc NotRemove ; Yipe! Say non-removable
TEST DX,1000H
jnz NotRemove ; Is NET drive. Say non-removable.
JMP IsRemove
CheckRemove:
TEST ax,1
jnz NotRemove
IsRemove:
CLC
RestoreReg <AX>
return
NotRemove:
STC
RestoreReg <AX>
return
;
; Moves the name at the current locations in the system file name tables into
; the relevant system variables for later use.
; Preserves all registers (except flags).
;
MoveNames:
push bx
push cx
push di
push si
cld
mov bx,word ptr DOSFile_Offset
mov si,offset DG:BIOSNamesTable
add si,bx
mov di,offset DG:BIOSName
add di,3 ; skip over drive,colon,back-slash
mov cx,11
repe movsb
mov si,offset DG:DOSNamesTable
add si,bx
mov di,offset DG:DOSName
add di,3 ; skip over drive,colon,back-slash
mov cx,11
repe movsb
pop si
pop di
pop cx
pop bx
ret
;
; Set up filename in FCB variables for searching directory entries.
;
SetUpFCB:
push si
push di
push bx
mov si,offset DG:BIOSNamesTable
mov bx,word ptr DOSFile_Offset
add si,bx
mov di,offset DG:FCBBIO
call MoveToFCB
mov si,offset DG:DOSNamesTable
mov bx,word ptr DOSFile_Offset
add si,bx
mov di,offset DG:FCBDOS
call MoveToFCB
pop bx
pop di
pop si
ret
;
; Move ASCIZ filename to FCB-type filename from [SI] to [DI].
;
MoveToFCB:
xor cx,cx
NextChar:
lodsb
cmp al,'.'
jz Fill_Blanks
stosb
inc cx
jmp short NextChar
Fill_Blanks:
mov al,' '
cmp cx,8
jge See_Ext
stosb
inc cx
jmp short Fill_Blanks
See_Ext:
mov cx,3
Next_Ext:
lodsb
stosb
dec cx
jnz Next_Ext
RET
;
; Gets source file names from SourceBIOSFile and SourceDOSFile and puts them
; into the ASCIZ strings SourceBIOSName and SourceDOSName.
;
GetSourceNames:
push si
push di
push cx
mov si,offset DG:SourceBIOSFile
mov di,offset DG:SourceBIOSName
add di,3 ; skip over drive,colon,back-slash
mov cx,12
repe movsb
mov si,offset DG:SourceDOSFile
mov di,offset DG:SourceDOSName
add di,3 ; skip over drive,colon,back-slash
mov cx,12
repe movsb
pop cx
pop di
pop si
ret
CODE ENDS
END START