Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

2029 lines
51 KiB

;/*
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1991
; * All Rights Reserved.
; */
;===========================================================================
;
; FILE: PHASE1.ASM
;
;===========================================================================
;===========================================================================
;Include file declarations
;===========================================================================
debug equ 0
.xlist
INCLUDE DOSEQUS.INC
INCLUDE DOSMAC.INC
INCLUDE SYSCALL.INC
INCLUDE ERROR.INC
INCLUDE DIRENT.INC
INCLUDE BPB.INC
INCLUDE BOOTSEC.INC
INCLUDE FOREQU.INC
INCLUDE FORMACRO.INC
INCLUDE IOCTL.INC
INCLUDE FORSWTCH.INC
.list
;
;---------------------------------------------------------------------------
;
; M020 : Looked for EXT_BOOT_SIG before assuming that the BPB in the boot
; sector is an extended one. Bug #4946
;
;---------------------------------------------------------------------------
;
;===========================================================================
; Data segment
;===========================================================================
DATA SEGMENT PUBLIC PARA 'DATA'
;===========================================================================
; Declarations for all publics in other modules used by this module
;===========================================================================
;Constants
EXTRN EXIT_NO :ABS
EXTRN EXIT_FATAL :ABS
;Bytes
EXTRN CMCDDFlag :BYTE
EXTRN ValidSavedDeviceParameters:BYTE
EXTRN DriveToFormat :BYTE
EXTRN msgFormatNotSupported :BYTE
EXTRN msgInsertDisk :BYTE
EXTRN msgInvalidDeviceParameters:BYTE
EXTRN ContinueMsg :BYTE
EXTRN msgNotCompatablePart :BYTE
EXTRN msgExistingFormatDiffers :BYTE
EXTRN msgNoQuickFormat :BYTE
EXTRN msgCrLf :BYTE
EXTRN msgCheckExistingDiskFormat:BYTE
EXTRN Extended_Error_Msg :BYTE
EXTRN old_dir :BYTE
EXTRN ExitStatus :BYTE
ifdef NEC_98
EXTRN SizeMap :BYTE
EXTRN msgInsufficientMemory :BYTE
endif
;Words
EXTRN SectorsInRootDirectory :WORD
EXTRN Paras_Per_Fat :WORD
EXTRN SwitchMap :WORD
EXTRN SwitchMap2 :WORD
EXTRN SwitchCopy :WORD
ifdef NEC_98
EXTRN SASI1024Table :WORD
EXTRN SCSI1024Table :WORD
EXTRN Small2048Table :WORD
EXTRN Large512Table :WORD
EXTRN Large256Table :WORD
else
EXTRN DiskTable :WORD
EXTRN DiskTable2 :WORD
endif
EXTRN RWErrorCode :WORD
;Pointers
EXTRN FatSpace :DWORD
;Structures
EXTRN SavedParams :BYTE
EXTRN DeviceParameters :BYTE
EXTRN IsExtRAWIODrv :BYTE
EXTRN SwitchDevParams :BYTE
EXTRN Read_Write_Relative :BYTE
EXTRN SetDPBPacket :BYTE
fBigFat DB FALSE
fBig32Fat DB FALSE
ThisSysInd DB 0 ; indicates size of FAT
StartSector DD ? ; holds first data sector
TotalClusters DD ? ; holds total #clusters on disk
UnformattedHardDrive DB ?
ifdef NEC_98
SAV_INT24_OFF DW 0 ; original int 24 vector address
SAV_INT24_SEG DW 0
endif
MediaSensePacket A_MEDIA_SENSE <> ; structure used in media
; sensing call
; the following table provides templates for
; BPBs used in CP/M disks.
; Order is very important (used by both MSFOR and PHASE1)
CustomCPMBPBs LABEL BYTE
BPB320 a_BPB <512, 2, 1, 2, 112, 2*8*40, 0ffh, 1, 8, 2, 0, 0, 0, 0>
BPB160 a_BPB <512, 1, 1, 2, 64, 1*8*40, 0feh, 1, 8, 1, 0, 0, 0, 0>
BPB360 a_BPB <512, 2, 1, 2, 112, 2*9*40, 0fdh, 2, 9, 2, 0, 0, 0, 0>
BPB180 a_BPB <512, 1, 1, 2, 64, 1*9*40, 0fch, 2, 9, 1, 0, 0, 0, 0>
EndCustomCPMBPBs LABEL BYTE
; This must folow CustomCPMBPBs
BPB12 a_BPB <512, 1, 1, 2, 224, 2*15*80, 0F9h, 7, 15, 2, 0, 0, 0, 0>
BPB720 a_BPB <512, 2, 1, 2, 112, 2* 9*80, 0F9h, 3, 9, 2, 0, 0, 0, 0>
BPB1440 a_BPB <512, 1, 1, 2, 224, 2*18*80, 0F0h, 9, 18, 2, 0, 0, 0, 0>
BPB2880 a_BPB <512, 2, 1, 2, 240, 2*36*80, 0F0h, 9, 36, 2, 0, 0, 0, 0>
ifdef NEC_98
BPB640 a_BPB <512, 2, 1, 2, 112, 2* 8*80, 0FBh, 2, 8, 2, 0, 0, 0, 0>
BPB1250 a_BPB <1024,1, 1, 2, 192, 2* 8*77, 0FEh, 2, 8, 2, 0, 0, 0, 0>
BPB128 a_BPB <512,4,1, 2, 512, 0, 0F0h, 0F3h, 019h, 1, 0,0, 0CBE0h, 03h>
BPB230 a_BPB <512,8,1, 2, 512, 0, 0F0h, 0DAh, 019h, 1, 0,0, 0CF75h, 06h>
BPB650 a_BPB <512,020h,1, 2, 512, 0, 0F0h, 09Fh, 019h, 1, 0,0, 0D040h, 013h>
endif
EndStandardBPBs LABEL BYTE
; the following table indicates the switches
; which must be set for the given CP/M media
CPMSwitchTable LABEL BYTE
dw Switch_4 + Switch_8 ;320K
dw Switch_1 + Switch_4 + Switch_8 ;160K
dw Switch_4 ;360K
dw Switch_1 + Switch_4 ;180K
; ========================================================================
; Tables added for media sense support in 5.00.
; ========================================================================
MediaTable LABEL WORD
ifdef NEC_98
dw 0 ; 0
dw OFFSET BPB12 ; 1 /5
dw OFFSET BPB720 ; 2 /9
dw 0 ; 3
dw OFFSET BPB1250 ; 4 /M
dw 0 ; 5
dw 0 ; 6
dw OFFSET BPB1440 ; 7 /4
dw 0 ; 8
dw OFFSET BPB2880 ; 9 not supported! but rest.
else
dw 0 ; 0
dw 0 ; 1
dw OFFSET BPB720 ; 2
dw 0 ; 3
dw 0 ; 4
dw 0 ; 5
dw 0 ; 6
dw OFFSET BPB1440 ; 7
dw 0 ; 8
dw OFFSET BPB2880 ; 9
endif
EndMediaTable LABEL WORD
DATA ENDS
;===========================================================================
; Executable code segment
;===========================================================================
CODE SEGMENT PUBLIC PARA 'CODE'
ASSUME CS:CODE, DS:DATA, ES:DATA
;===========================================================================
; Declarations for all externs
;===========================================================================
;Functions
EXTRN AccessDisk :NEAR
EXTRN USER_STRING :NEAR
EXTRN CrLf :NEAR
EXTRN CheckSwitches :NEAR
EXTRN Read_Disk :NEAR
EXTRN Yes? :NEAR
ifdef NEC_98
EXTRN GetDeviceParameters :NEAR
EXTRN Alloc_Dir_Buf :NEAR
EXTRN Alloc_Fat_Buf :NEAR
EXTRN Alloc_Fat_Sec_Buf :NEAR
EXTRN Alloc_DirBuf2 :NEAR
EXTRN Alloc_Cluster_Buf :NEAR
ifdef OPKBLD
EXTRN Do_Switch_S :NEAR
endif ;OPKBLD
EXTRN ZeroAllBuffers :NEAR
endif ;NEC_98
;Labels
EXTRN FatalExit :NEAR
EXTRN ExitProgram :NEAR
;===========================================================================
; Declarations for all publics in this module
;===========================================================================
PUBLIC Phase1Initialisation
PUBLIC MediaSense
PUBLIC TargPrm
PUBLIC CopyToSwitchDevParams
PUBLIC CompareDevParams
PUBLIC LoadSwitchDevParams
PUBLIC DetermineExistingFormat
PUBLIC DetermineExistingFormatNomsg
PUBLIC IsValidBpb
PUBLIC ResetDeviceParameters
PUBLIC DetermineCPMFormat
PUBLIC SetCPMParameters
PUBLIC Set_BPB_Info
PUBLIC Scan_Disk_Table
PUBLIC Calc_Big16_Fat
PUBLIC Calc_Big32_Fat
PUBLIC Calc_Small_Fat
PUBLIC SetStartSector
PUBLIC SetfBigFat
PUBLIC GetTotalClusters
PUBLIC fBigFat
PUBLIC fBig32Fat
PUBLIC StartSector
PUBLIC TotalClusters
PUBLIC CustomCPMBPBs
PUBLIC CPMSwitchTable
PUBLIC EndStandardBPBs
PUBLIC BPB720
ifdef NEC_98
PUBLIC BPB640
PUBLIC BPB12
PUBLIC BPB1250
PUBLIC BPB128
PUBLIC BPB230
PUBLIC BPB650
endif
PUBLIC UnformattedHardDrive
; ==========================================================================
; Phase1Initialisation:
; This routine sets up fBigFat
; It also does most of the other initialisation
;
; Algorithm:
; Perform media sensing and if present adjust DeviceParameters
; Check switches against parameters
; Use switches to modify device parameters
; Save a copy of current DeviceParameters in SwitchDevParams
;
; IF (!SWITCH_U)
; {
; IF (!ValidBootRecord || !ValidBPB)
; set SWITCH_U
; ELSE
; {
; get device layout from BPB on disk
; IF (DeviceParameters = SwitchDevParams)
; do safe/quick format
; ELSE
; {
; IF (Switch_N || Switch_T || Switch_F)
; {
; Issue warning
; Format with BPB from SwitchDevParams if user continues
; }
; ELSE
; do safe/quick format
; }
; }
; }
;
; Calculate start sector (first sector not used by DOS)
; fBig32Fat = (((TotalSectors - StartSector)/SectorsPerCluster) >= 65526)
; fBigFat = (((TotalSectors - StartSector)/SectorsPerCluster) >= 4086)
; ==========================================================================
Phase1Initialisation proc near
; use DevParms to check for removable
test DeviceParameters.DP_DeviceAttributes,1
.errnz EDP_DEVICEATTRIBUTES NE DP_DEVICEATTRIBUTES
jnz @F ; Bit 0=1 --> not removable
; New media sensing call added for 5.00 will see if
; see if media sensing is avaliable and if it is will
; reset DeviceParameters to the real parameters for
; the type of disk being formatted.
ifndef NEC_98
call MediaSense
else
cmp DeviceParameters.DP_DeviceType, DEV_HARDDISK ; Hard disk?
.errnz EDP_DEVICETYPE NE DP_DEVICETYPE
jne @F ; No
; We ignore INT24 in order not to be stop formatting
; when "INT21 AH=32" is called.
; Set my INT24
push es
mov ah, 35h
mov al, 24h
int 21h ; get INT24's vector address
mov SAV_INT24_OFF, bx ; save original INT24
mov SAV_INT24_SEG, es ; save original INT24
pop es
push ds
push cs
pop ds
mov ah, 25h
mov al, 24h
mov dx, OFFSET MY_INT24
int 21h ; set my INT24
pop ds
; Update Default BPB
push ds
push bx
mov ah, 32h
mov dl, DriveToFormat
inc dl
int 21h ; Get Drive Parameter Block
pop bx
pop ds
; Set original INT 24
push ds
push dx
mov ah, 25h
mov al, 24h
mov ds, SAV_INT24_SEG
mov dx, SAV_INT24_OFF
int 21h ; set original INT24
pop dx
pop ds
; Get default BPB
lea DX, DeviceParameters
mov DeviceParameters.DP_SpecialFunctions, 0
call GetDeviceParameters
; Allocate memory
call Alloc_Dir_Buf ; Allocate root directory buffer
jc gi_memerr
call Alloc_Fat_Buf ; Allocate FAT buffer
jc gi_memerr
call Alloc_Fat_Sec_Buf ; Allocate fat sector buffer
jc gi_memerr
call Alloc_DirBuf2 ; Allocate 1-sector buffer DirBuf (general-
; purpose use)
jc gi_memerr
call Alloc_Cluster_Buf ; get room for retry buffer
ifdef OPKBLD
call Do_Switch_S ; Load system files if needed
; carry flag determined by Do_Switch_S
else
clc
endif ;OPKBLD
call ZeroAllBuffers ; initialize buffers
jmp short @f
gi_memerr:
Message msgInsufficientMemory
stc
ret
endif
@@:
; Ensure that there is a valid #
; of Sectors in the track table
mov ValidSavedDeviceParameters, 1
cmp IsExtRAWIODrv,0
je OldTabOff2
mov SavedParams.EDP_TrackTableEntries, 0
mov DeviceParameters.EDP_TrackTableEntries,0
jmp short SetBPBnf
OldTabOff2:
mov SavedParams.DP_TrackTableEntries, 0
; Initialise to zero to see if
; CheckSwitches define track layout
mov DeviceParameters.DP_TrackTableEntries,0
SetBPBnf:
call Set_BPB_Info ; Check to see if we are on
; Fat system.If not set BPB to proper
; values for format.
SetMTsupp:
; Check switches against parameters
; and use switches to modify device
; parameters
call CheckSwitches
retc
call CopyToSwitchDevParams ; Save a copy of deviceparameters as
; returned by CheckSwitches
mov ax,SwitchMap ; No need to check existing format
and ax,SWITCH_U+SWITCH_Q
cmp ax,SWITCH_U ; if unconditional format specified
jnz CheckExistingFormat
jmp DevParamsOk
CheckExistingFormat:
; New call added for 5.00 to see if the disk has been
; previously formatted, and if so this will reset
; DeviceParameters to those of the existing format.
call DetermineExistingFormat
jnc ValidExistingFormat ; carry clear if valid existing format
InvalidExistingFormat:
and RWErrorCode,0ffh ; check low byte for 'drive not ready' error
cmp RWErrorCode,ERROR_I24_NOT_READY ;'not ready' error code = 2
jne CheckForQ ; no error reading disk
; 'not ready' error occurred, give msg
mov AX,21 ; load AX with extended error code for not ready
SetFatalErr:
Extended_Message ; deliver message "Not Ready"
mov ExitStatus,EXIT_FATAL ; M006;
stc
jmp EndPhase1
CheckForQ:
test SwitchMap,SWITCH_Q ; Need to give message if /q was specified
jz MakeUnconditional
test SwitchCopy,(SWITCH_T or SWITCH_N or SWITCH_F) ; did user specify size?
jnz TurnOffQ ; do an unconditional format at specified size
ifdef OPKBLD
; Let OEM's quickformat a clean disk
test DeviceParameters.DP_DeviceAttributes,1
jnz DevParamsOk ; Bit 0=1 --> not removable
endif ;OPKBLD
Message msgNoQuickFormat ; Inform user quick format cannot be done
call Yes? ; Continue with unconditional format?
pushf
Message msgCrLf
popf
jnc TurnOffQ
mov ExitStatus,EXIT_NO ; load exit code 5 (response is 'no')
jmp ExitProgram ; User wants to exit
TurnOffQ:
and SwitchMap,NOT SWITCH_Q ; Turn off /Q to continue
MakeUnconditional:
or SwitchMap,SWITCH_U ; Enable /U since invalid existing format
or SwitchMap2, Switch2_C ; Enable /C since invalid existing format
jmp SHORT DevParamsOk ; Device parameters will not have been
; modified since invalid existing format
ValidExistingFormat:
call CompareDevParams ; see if SwitchDevParams = DeviceParameters
jnc DevParamsOk ; they are equal
; Check if user had specified a format
; size, since DeviceParameters on disk
; are different.
test SwitchMap,SWITCH_Q ; special case where size was specified
; together with /Q :- use size specified
; only if invalid existing format
jnz DevParamsOk ; use the parameters found on disk
or SwitchMap,SWITCH_U ; Enable /U since new format specified
or SwitchMap2, Switch2_C ; Enable /C since new format specified
call LoadSwitchDevParams ; Set deviceparameters to SwitchDevParams
; i.e. follow user-specified size
DevParamsOk:
call SetDOS_Dpb ; m035 Setup default DOS DPB for this
; drive (for memory cards).
jc SetFatalErr
; Store sector table info (layout of
; each track)
mov CX, DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerTrack;CX = loop count
.errnz EDP_BPB NE DP_BPB
mov AX, 1 ;AX = sector #
mov BX, DeviceParameters.DP_BPB.oldBPB.BPB_bytesPerSector ;BX = sector size
cmp IsExtRAWIODrv,0
je OldTabOff
cmp DeviceParameters.EDP_TrackTableEntries,0
jne TrackLayoutSet ; There is a good track layout
mov DeviceParameters.EDP_TrackTableEntries,CX
lea DI, DeviceParameters.EDP_SectorTable
jmp short GotTabOff
OldTabOff:
cmp DeviceParameters.DP_TrackTableEntries,0
jne TrackLayoutSet ; There is a good track layout
mov DeviceParameters.DP_TrackTableEntries,CX
lea DI, DeviceParameters.DP_SectorTable
GotTabOff:
cld
LoadSectorTable:
stosw ; Write the sector number
xchg AX, BX ; Get the sector size in bytes
stosw ; Write the sector size
xchg AX, BX
inc AX ; Go to the next sector
loop LoadSectorTable
TrackLayoutSet:
call SetStartSector
call SetfBigFat
call GetTotalClusters
clc
EndPhase1:
return
Phase1Initialisation endp
; =========================================================================
;
; MediaSense
; Checks for media sensing via IOCtl 440d subfuction 0868.
; If sensing is supported the user will be prompted to insert
; the disk if it's not detect and then the device parameters
; will be set according to the type of media being used.
;
; Before we can use the type returned we must be sure it's
; not a larger size disk than is formattable in the drive.
; We can do this by checking the media type byte in the
; saved device parameters.
;
; Input:
; DriveToFormat - Must have already been set
;
; =========================================================================
MediaSense PROC NEAR
mov BL, DriveToFormat
inc BX
mov CX, (RAWIO shl 8) or SENSE_MEDIA_TYPE
cmp IsExtRAWIODrv,0
je DoIOCTL1
mov CX, (EXTRAWIO shl 8) or SENSE_MEDIA_TYPE
DoIOCTL1:
lea DX,MediaSensePacket
; First check if BIOS supports call
mov AX, (IOCTL shl 8) or IOCTL_QUERY_BLOCK
int 21h
jc MediaSenseExit
; Now do actual call
mov AX, (IOCTL shl 8) or GENERIC_IOCTL
int 21h
jnc GotMediaSense
cmp AL,error_not_ready
jne MediaSenseExit ; Machine does not support media sensing
call TargPrm ; Insert disk prompt
jmp SHORT MediaSense ; Retry the operation
; See if the type of media inserted is the same as the
; default for this type of drive and if not check to
; be sure it's
GotMediaSense:
mov AL,MediaSensePacket.MS_DEVICETYPE ; AL == media type
cmp SavedParams.DP_DEVICETYPE,AL ; If the media in the
.errnz EDP_DEVICETYPE NE DP_DEVICETYPE
jl MediaSenseExit ; drv is > default size, use default
; Load BPB for sensed media
xor AH,AH
shl AX,1 ; AX == word offset in media table
mov BX, offset MediaTable ; BX -> Start of media table
add BX, AX ; BX -> Sensed type in media table
cmp BX, offset EndMediaTable ; Make sure we're still in the table
jge MediaSenseExit
mov SI,[BX] ; DS:SI -> Sensed device parameters
or SI,SI
je MediaSenseExit ; Unknown Media?!
lea DI, DeviceParameters.DP_BPB ; ES:DI -> Format parameters
.errnz EDP_BPB NE DP_BPB
mov CX, size A_BPB ; CX = bytes to move
cmp IsExtRAWIODrv,0
je DoIOCTL2
mov CX, size A_BF_BPB ; CX = bytes to move
DoIOCTL2:
cld
rep movsb
;
; Update the D_Cylinders. With 120mb floppies the cylinders field does change
; as opposed 720/1.44 drives
; We just back calculate the cylinders from sec/track, heads & total sectors
;
.386
push edx
push ecx
push eax
movzx eax, DeviceParameters.DP_BPB.A_BPB_Heads
movzx edx, DeviceParameters.DP_BPB.A_BPB_SectorsPerTrack
mul edx
mov ecx, eax ; save sectors per cylinder in ECX
xor eax, eax
mov ax, DeviceParameters.DP_BPB.A_BPB_TotalSectors
or ax, ax
jnz mse_sec_ok
mov eax, dword ptr DeviceParameters.DP_BPB.A_BPB_BigTotalSectors
mse_sec_ok:
div ecx ; EAX = number of cylinders
mov DeviceParameters.DP_Cylinders, ax
pop eax
pop ecx
pop edx
.8086
MediaSenseExit:
ret
MediaSense ENDP
;========================================================================
;
; TargPrm : This procedure prompts the user to insert the target disk
; into the drive.
;
;========================================================================
TargPrm PROC NEAR
mov AL, DriveToFormat
call AccessDisk
Message MsgInsertDisk
Message ContinueMsg
call USER_STRING
call CrLf
ret
TargPrm ENDP
;=========================================================================
;
; CopyToSwitchDevParams : This procedure copies the structure
; DeviceParameters into SwitchDevParams.
; Registers destroyed : CX,DI,SI
; Assumes : DS:DATA, ES:Nothing
;
;=========================================================================
CopyToSwitchDevParams proc NEAR
push DS
pop ES
mov DI,OFFSET SwitchDevParams ; ES:DI --> dest. parms
mov SI,OFFSET DeviceParameters ; DS:SI --> src. parms
mov CX,SIZE EA_DEVICEPARAMETERS ; byte transfer count
cld
rep movsb
ret
CopyToSwitchDevParams endp
;=========================================================================
;
; CompareDevParams : This procedure compares the structure
; DeviceParameters with SwitchDevParams.
; Registers destroyed : CX,DI,SI
; Assumes : DS:DATA, ES:Nothing
;
;=========================================================================
CompareDevParams proc NEAR
push DS
pop ES
mov DI,OFFSET SwitchDevParams ; ES:DI --> dest. parms
mov SI,OFFSET DeviceParameters ; DS:SI --> src. parms
mov CX,SIZE A_DEVICEPARAMETERS ; Set up count in bytes
cmp IsExtRAWIODrv,0
je DoCmp
mov CX,SIZE EA_DEVICEPARAMETERS ; Set up count in bytes
DoCmp:
cld ; Set the direction
repe cmpsb ; Compare the two BPBs
jz EqualParams ; If ZR then BPBs matched
NotEqualParams:
stc ; Signal BPBs don't match
jmp SHORT CompareParamsExit
EqualParams:
clc ; Signal BPB matches
CompareParamsExit:
ret
CompareDevParams endp
;=========================================================================
;
; LoadSwitchDevParams : This procedure copies the structure
; SwitchDevParams into DeviceParameters.
; Registers destroyed : CX,DI,SI
; Assumes : DS:DATA,ES:Nothing
;
;=========================================================================
LoadSwitchDevParams proc NEAR
push DS
pop ES
mov DI,OFFSET DeviceParameters ; ES:DI --> dest. parms
mov SI,OFFSET SwitchDevParams ; DS:SI --> src. parms
mov CX,SIZE EA_DEVICEPARAMETERS ; byte transfer count
cld
rep movsb
ret
LoadSwitchDevParams endp
;=========================================================================
;
; DetermineExistingFormat : This procedure will check if there is a
; valid format existing on the disk, in
; which case DeviceParameters will be reset
; to that format.
;
; It is assumed the destination disk is
; already in the drive.
;
; DetermineExistingFormatNoMsg : alternate entry with no message
;
;
; Calls : IsValidBpb
; ResetDeviceParameters
; DetermineCPMFormat
;
; Called by : Phase1Initialisation
;
;=========================================================================
DetermineExistingFormat proc near
push DS
push ES
Set_Data_Segment ;ensure addressibility
cmp UnformattedHardDrive,TRUE
jne @F
jmp InvalidBootRecord
@@:
Message msgCheckExistingDiskFormat
jmp short DetermineExistCommon
DetermineExistingFormatNoMsg:
push ds
push es
set_data_segment
cmp UnformattedHardDrive,TRUE
je InvalidBootRecord
DetermineExistCommon:
xor DX,DX ; Starting sector to 0
mov AL,DriveToFormat ; Set drive number
mov AH,DH ; Signal this is a read AH=0
lds BX,FatSpace ; Load transfer address
assume DS:NOTHING,ES:DATA
mov CX,2 ; # of sectors to read
; we are accessing < 32mb
mov ES:Read_Write_Relative.Start_Sector_High,0
call Read_Disk ; Disk sector read
jnc BootCheck
mov ES:RWErrorCode,AX ; Save error code (if any)
jmp InvalidbootRecord
BootCheck:
cmp word ptr [bx+3], 'SM'
jne @F
cmp word ptr [bx+5], 'MD'
jne @F
cmp word ptr [bx+7], '3F'
jne @F
mov es:RWErrorCode, 0
stc
jmp short EndDetermine
@@:
cmp BYTE PTR [BX],0e9h ; Check for JMP opcode
je TestBootSignature ; If Ok then check signature
; we can not know #reserved sectors)
cmp BYTE PTR [BX],0ebh ; Else check for SHORT jmp
jne TryCPM ; No match then not valid boot
cmp BYTE PTR [BX+2],90h ; Now check for NOP opcode
jne TryCPM ; No match then not valid boot
TestBootSignature:
ifndef NEC_98
cmp WORD PTR [BX + 510],0aa55h ; Check for 55 AA sequence
jne TryCPM ; Error if not equal
endif
CheckTheBpb:
call IsValidBpb
jc TryCPM ; CY --> Invalid format
call ResetDeviceParameters ; set DeviceParameters to
clc ; existing ones on the disk
jmp SHORT EndDetermine
TryCPM:
ifdef NEC_98
cmp ES:DeviceParameters.DP_DeviceType,DEV_HARDDISK
je InvalidBootRecord
endif
; check in case a CP/M disk is present
test ES:DeviceParameters.DP_DeviceAttributes,1
.errnz EDP_DEVICEATTRIBUTES NE DP_DEVICEATTRIBUTES
jnz InvalidBootRecord ; Bit 0=1 --> not removable
call DetermineCPMFormat
jmp SHORT EndDetermine ; CP/M disk present, DeviceParameters
; will have been modified
; Carry propagated up to
; Note: DS can be anything
InvalidBootRecord:
stc ;flag invalid format
EndDetermine:
pop ES
pop DS
ret
DetermineExistingFormat endp
;=========================================================================
;
; IsValidBpb : This procedure will inspect the BPB loaded into
; memory by the DetermineExistinFormat procedure.
;
; Input : DS:BX Buffer holding boot sector (FatSpace) ; M016
; Output : BPB is valid - NC
; BPB is invalid - CY
;
; Assumes: DS:BX: FatSpace (preserved); M016
;
;=========================================================================
IsValidBpb proc near
assume DS:NOTHING,ES:DATA
push BX ; M016; preserve BX
lea bx,[bx.bsBPB]
ifdef NEC_98
;;; It is possible NEC_98's BPB is not 200h.
cmp [BX.oldBPB.BPB_BytesPerSector],200h ; check BytesPerSector=512
je @F
cmp [BX.oldBPB.BPB_BytesPerSector],400h ; check BytesPerSector=1024
je @F
cmp [BX.oldBPB.BPB_BytesPerSector],800h ; check BytesPerSector=2048
jne NotValidBpb
@@:
else
cmp [BX.oldBPB.BPB_BytesPerSector],200h ; check BytesPerSector=512
jne NotValidBpb
endif
and [BX.oldBPB.BPB_TotalSectors],0ffffh ; check that both TotalSectors
jnz ResetBigTotalSectors ; and BigTotalSectors are not zero
and [BX.oldBPB.BPB_BigTotalSectors],0ffffh ; low word
jnz CheckMore
and [BX.oldBPB.BPB_BigTotalSectorsHigh],0ffffh ; high word
jz NotValidBpb
jmp SHORT CheckMore
ResetBigTotalSectors: ; if TotalSectors<>0 set
and [BX.oldBPB.BPB_BigTotalSectors],0h ; BigTotalSectors to zero
and [BX.oldBPB.BPB_BigTotalSectorsHigh],0h
CheckMore:
and [BX.oldBPB.BPB_SectorsPerFAT],0ffffh ; check SectorsPerFat <> 0
jnz CheckMore2
;
; Is a FAT32 BPB
;
and [BX.BGBPB_BigSectorsPerFat],0ffffh
jnz CheckMore2
and [BX.BGBPB_BigSectorsPerFatHi],0ffffh
jz NotValidBpb
CheckMore2:
cmp [BX.oldBPB.BPB_SectorsPerTrack],1h ; check 0 < SectorsPerTrack < 64
jb NotValidBpb
cmp [BX.oldBPB.BPB_SectorsPerTrack],3fh
ja NotValidBpb
cmp [BX.oldBPB.BPB_Heads],1h ; check 0 < Heads < 256
jb NotValidBpb
cmp [BX.oldBPB.BPB_Heads],0ffh
ja NotValidBpb
BpbIsValid:
clc
jmp SHORT EndIsValidBpb
NotValidBpb:
stc
EndIsValidBpb:
pop BX ; M016; restore BX
ret
IsValidBpb endp
;=========================================================================
;
; ResetDeviceParameters : This procedure will copy the BPB of the
; disk into DeviceParameters. It will also
; set the fields DP_CYLINDERS and DP_MEDIATYPE,
; for removable media.
;
; Inputs : DS:BX Boot sector held in FatSpace ; M016
; Output : Modified DeviceParameters
; Modifies: ES,SI,DI,CX,DX,BX,AX
; Assumes: DS:BX Boot sector, ES:DATA
;
;=========================================================================
ResetDeviceParameters proc near
assume DS:NOTHING,ES:DATA
lea si,[bx.bsBPB] ; Use SI instead of BX for copy
; DS:SI source BPB in buffer
;No need to modify DP_CYLINDERS,DP_MEDIATYPE
;(and DP_DEVICETYPE) for fixed disks.
ifdef NEC_98
cmp ES:DeviceParameters.DP_DeviceType,DEV_HARDDISK
je CopyBpb
endif
;use DevParms to check for removable
test ES:DeviceParameters.DP_DeviceAttributes,1
.errnz EDP_DEVICEATTRIBUTES NE DP_DEVICEATTRIBUTES
jnz CopyBpb ; Bit 0=1 --> not removable
;first compute total cylinders as
;total sectors /(sectors per track)*#heads
.386
movzx EAX,[SI.oldBPB.BPB_TotalSectors] ;get total sectors
.8086
or AX,AX ;do we need to use Big total sectors?
jnz GotTotalSectors ;don't need to if not zero
UseBigTotalSectors:
.386
mov EAX,DWORD PTR [SI.oldBPB.BPB_BigTotalSectors]
GotTotalSectors: ;now EAX has total #sectors
movzx EBX,[SI.oldBPB.BPB_SectorsPerTrack] ;get sectors per track
xor edx,edx
div EBX
.8086
xor DX,DX ;clear the remainder
mov CX,[SI.oldBPB.BPB_Heads] ;get number of heads
div CX
or DX,DX
jz CylindersOk
inc AX
;BUGBUG: Arithmetic may result in CYLINDERS being 1 less than actual value,
; for big disks (hence this calculation is skipped for fixed disks)
; PYS: fixed using same code as MSINIT.ASM
CylindersOk:
mov ES:DeviceParameters.DP_CYLINDERS,AX
.errnz EDP_CYLINDERS NE DP_CYLINDERS
;now determine DP_MEDIATYPE & DP_DEVICETYPE
mov ES:DeviceParameters.DP_MEDIATYPE,0 ; init. to zero
.errnz EDP_MEDIATYPE NE DP_MEDIATYPE
cmp AX,40 ; only 360K or less has 40 cylinders
jne CopyBpb ; MEDIATYPE has been set
cmp ES:DeviceParameters.DP_DEVICETYPE,DEV_5INCH96TPI
.errnz EDP_DEVICETYPE NE DP_DEVICETYPE
jne CopyBpb
Is360K:
mov ES:DeviceParameters.DP_MEDIATYPE,1 ; set to 1 only for 360K in 1.2M
.errnz EDP_MEDIATYPE NE DP_MEDIATYPE
;BUGBUG: Changing the value of DEVICETYPE can result in SwitchDevParams !=
; DeviceParameters, and hence a just-formatted 360K disk may not be
; recognized! -is it really necessary to set DEVICETYPE?
CopyBpb:
mov DI,OFFSET ES:DeviceParameters.DP_BPB
.errnz EDP_BPB NE DP_BPB
;ES:DI destination BPB in DeviceParameters
mov CX,SIZE BIGFATBPB ;byte transfer count
cmp [si.BPB_SectorsPerFAT],0 ;FAT32 BPB?
je @f ;Yes
mov CX,SIZE BPB ;byte transfer count
cmp byte ptr [si.bsBootSignature-bsBPB], 29h ; extended BPB ?
je @f ; Yes
mov cx,((SIZE BPB)-6) ; no, ancient small BPB
@@:
cld ;set the direction
rep movsb ;write the new BPB
ret
ResetDeviceParameters endp
;=========================================================================
;
; DetermineCPMFormat : This procedure will check the media
; descriptor in the FAT of the disk. The
; disk has a valid CP/M format if this is
; in the range FCh - FFh.
;
; Assumes : DS:BX points to boot sectors. ; M016
; Modifies : DS ; M016
; Returns : NC - Valid CP/M format detected
; DeviceParameters modified
; CY - Invalid format
;
;==========================================================================
DetermineCPMFormat proc NEAR
assume DS:NOTHING,ES:DATA
cmp ES:DeviceParameters.DP_BPB.oldBPB.BPB_BytesPerSector,512
.errnz EDP_BPB NE DP_BPB
stc ; Checking default for drive
; (cannot check BPB since disk
; may not have one)
jne ExitDetCPMFormat
add BX,512 ; DS:BX points to first FAT
mov CL,BYTE PTR [BX] ; load media descriptor byte into CL
cmp CL,0fch
jb ExitDetCPMFormat ; below = carry, how practical!
Set_Data_Segment ; For the two following calls
call SetCPMParameters ; modify DeviceParameters accordingly
ExitDetCPMFormat:
ret
DetermineCPMFormat endp
;=========================================================================
;
; SetCPMParameters : This procedure copies the required BPB from the
; CP/M BPB table into DeviceParameters.BPB. Also,
; DeviceParameters.MediaType is set to 1, and
; DeviceParameters.Cylinders is set to 40.
;
; In case the disk has a 160K or 320K format, the /8
; switch is set, so that
; Returns : NC - DeviceParameters updated
; CY - Error (out of table boundaries)
;
; Modifies : AX,BX,CX,DX,SI,DI,ES
; DeviceParameters
;
; Assumes : CL contains media descriptor byte
;
;=========================================================================
SetCPMParameters proc NEAR
xor AX,AX ; find index into CP/M BPB table by
mov AL,0ffh ; subtracting media descriptor from ffh
sub AL,CL
mov BX,SIZE A_BPB ; now find byte offset by multiplying
mul BX ; by entry size
lea SI,CustomCPMBPBs
add SI,AX
cmp SI,OFFSET EndCustomCPMBPBs ; check we are still in table
ja NotInTable
lea DI,DeviceParameters.DP_BPB
.errnz EDP_BPB NE DP_BPB
mov CX,SIZE A_BPB ; set up byte transfer count
push DS ; set ES=DS
pop ES
cld ;set the direction
rep movsb ; load the BPB
mov BYTE PTR DeviceParameters.DP_MediaType,1
.errnz EDP_MEDIATYPE NE DP_MEDIATYPE
mov BYTE PTR DeviceParameters.DP_Cylinders,40
.errnz EDP_CYLINDERS NE DP_CYLINDERS
clc
jmp SHORT ExitSetCPMParm
NotInTable:
stc
ExitSetCPMParm:
ret
SetCPMParameters endp
;=========================================================================
; Set_BPB_Info : When we have a Fat count of 0, we must calculate
; certain parts of the BPB. The following code
; will do just that.
;
; Inputs : DeviceParameters
;
; Outputs : BPB information
;=========================================================================
Procedure Set_BPB_Info ; Calc new BPB
Set_Data_Segment ; Set up addressibility
ifdef NEC_98
cmp DeviceParameters.DP_BPB.BPB_NumberOfFats,00h
je @F ; Yes, 0 FatS specified
cmp DeviceParameters.DP_DeviceType,DEV_HARDDISK
je $$IF101
test DeviceParameters.DP_DeviceAttributes,1
jnz $$IF101 ; Bit 0=1 --> not removable
cmp CMCDDFlag,Yes ; Memory card?
je $$IF101 ; We don't need current BPB
lea DX, DeviceParameters
mov DeviceParameters.DP_SpecialFunctions,INSTALL_FAKE_BPB
call GetDeviceParameters
jmp short $$IF101
@@:
else
; See if we have 0 Fats specified
cmp DeviceParameters.DP_BPB.oldBPB.BPB_NumberOfFats,00h
.errnz EDP_BPB NE DP_BPB
jne $$IF101 ; Yes, 0 FatS specified
endif
call Scan_Disk_Table ; Access disk table
mov BL,BYTE PTR DS:[SI+8] ; Get Fat type
mov CX,WORD PTR DS:[SI+4] ; Get Sectors/cluster
mov DX,WORD PTR DS:[SI+6] ; Number of entries for the root DIR
mov DeviceParameters.DP_BPB.oldBPB.BPB_RootEntries,DX
mov DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerCluster,CH
ifdef NEC_98
;;
mov DeviceParameters.DP_BPB.oldBPB.BPB_MediaDescriptor,Fixed_Disk
;;and ReservedSector not Fixed 1.(Large Partition)
;; reserved sector >= 1024 bytes (NEC)
cmp word ptr DeviceParameters.DP_BPB.oldBPB.BPB_BytesPerSector,0200h
je $$reserved_2
cmp word ptr DeviceParameters.DP_BPB.oldBPB.BPB_BytesPerSector,0100h
;Chicago is not supported 256 secters but for safely.
je $$reserved_4
mov DeviceParameters.DP_BPB.oldBPB.BPB_ReservedSectors,0001h
jmp short @F
$$reserved_2:
mov DeviceParameters.DP_BPB.oldBPB.BPB_ReservedSectors,0002h
jmp short @F
$$reserved_4:
mov DeviceParameters.DP_BPB.oldBPB.BPB_ReservedSectors,0004h
@@:
else
mov DeviceParameters.DP_BPB.oldBPB.BPB_BytesPerSector,0200h
mov DeviceParameters.DP_BPB.oldBPB.BPB_ReservedSectors,0001h
endif
mov DeviceParameters.DP_BPB.oldBPB.BPB_NumberOfFats,02h
.errnz EDP_BPB NE DP_BPB
cmp BL,fBig32 ; 32-bit Fat?
jne $$IF103 ; No
mov DeviceParameters.DP_BPB.oldBPB.BPB_ReservedSectors,0020h
call Calc_Big32_Fat ; Calc Fat info
jmp SHORT $$EN102
$$IF103:
cmp BL,fBig ; 16-bit Fat?
jne $$IF102 ; no
call Calc_Big16_Fat ; Calc Fat info
jmp SHORT $$EN102
$$IF102:
call Calc_Small_Fat ; Calc small Fat info
$$EN102:
$$IF101:
ret
Set_BPB_Info ENDP
;=========================================================================
; Scan_Disk_Table : Scans the table containing information on
; the disk's attributes. When it finds the
; applicable data, it returns a pointer in
; DS:SI for reference by the calling proc.
;
; Inputs : DiskTable - Contains data about disk types
;
; Outputs : DS:SI - Points to applicable disk data
;=========================================================================
Procedure Scan_Disk_Table
cmp DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors,00h ; small disk?
.errnz EDP_BPB NE DP_BPB
je $$IF106 ; Yes
mov DX,00h ; Set high to 0
mov AX,WORD PTR DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors
jmp SHORT $$EN106
$$IF106:
mov DX,WORD PTR DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors[+2]
mov AX,WORD PTR DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors[+0]
$$EN106:
ifdef NEC_98
call SetDiskTableNEC_98
mov DeviceParameters.DP_BPB.oldBPB.BPB_BytesPerSector,BX
cmp dx,0
je @F
mov word ptr DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors,0
mov DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors,AX
mov DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectorsHigh,DX
jmp short set_ok
@@:
mov DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors,AX
mov word ptr DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors,0
mov word ptr DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectorsHigh,0
set_ok:
else
mov SI,offset DiskTable ; Point to disk data
endif
Scan:
cmp DX,WORD PTR DS:[SI] ; Below?
jb Scan_Disk_Table_Exit ; Yes, exit
ja Scan_Next ; No, continue
cmp AX,WORD PTR DS:[SI+2] ; Below or equal?
ifdef NEC_98
jb Scan_Disk_Table_Exit ; Yes, exit
else
jbe Scan_Disk_Table_Exit ; Yes, exit
endif
Scan_Next:
add SI,5*2 ; Adjust pointer
jmp Scan ; Continue scan
Scan_Disk_Table_Exit:
ret
Scan_Disk_Table ENDP
;=========================================================================
; Calc_Big32_Fat : Calculates the Sectors per Fat for a 32 bit Fat.
;
; Inputs : DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors or
; DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors
;
; Outputs : DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerFat
; DeviceParameters.DP_BPB.BGBPB_BigSectorsPerFat
; DeviceParameters.DP_BPB.BGBPB_BigSectorsPerFatHi
; DeviceParameters.DP_BPB.BGBPB_ExtFlags
; DeviceParameters.DP_BPB.BGBPB_FS_Version
; DeviceParameters.DP_BPB.BGBPB_RootDirStrtClus
; DeviceParameters.DP_BPB.BGBPB_RootDirStrtClusHi
;
;=========================================================================
Procedure Calc_Big32_Fat
.386
; Root dir is a cluster chain on FAT32 volumes
movzx edx,DeviceParameters.DP_BPB.oldBPB.BPB_ReservedSectors ; EDX = Reserved
.errnz EDP_BPB NE DP_BPB
; Get total sector count
cmp DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors,00h ; Small disk?
je short $$IF109a ; Yes
movzx EAX,DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors
jmp SHORT $$EN109a
$$IF109a:
mov EAX,DWORD PTR DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors
$$EN109a:
sub EAX,EDX ; EAX = T - R
xor ebx,ebx
mov BL,DeviceParameters.DP_BPB.oldBPB.BPB_NumberOfFATs
mov BH,DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerCluster
shr ebx,1 ; At 4 bytes per clus instead of 2,
; halve divisor
GotDiv1:
add EAX,EBX ; EAX = T-R-D+(256*SPC)+nFAT
dec EAX ; EAX = T-R-D+(256*SPC)+nFAT-1
xor edx,edx
div EBX ; Sec/Fat = CEIL((TOTAL-DIR-RES)/
; (((256*SECPERCLUS)+NUMFATS)/2)
mov DWORD PTR DeviceParameters.DP_BPB.BGBPB_BigSectorsPerFat,EAX
xor ax,ax
mov DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerFat,ax
mov DeviceParameters.DP_BPB.oldBPB.BPB_RootEntries,ax
mov DeviceParameters.DP_BPB.BGBPB_ExtFlags,ax
;
; For the moment we set the root dir start clus to 0. Later on, after
; we determine which clusters are BAD, we will set this to something
; proper.
;
mov DeviceParameters.DP_BPB.BGBPB_RootDirStrtClus,ax
mov DeviceParameters.DP_BPB.BGBPB_RootDirStrtClusHi,ax
mov DeviceParameters.DP_BPB.BGBPB_FS_Version,FAT32_Curr_FS_Version
.8086
ret
Calc_Big32_Fat ENDP
;=========================================================================
; Calc_Big16_Fat : Calculates the Sectors per Fat for a 16 bit Fat.
;
; Inputs : DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors or
; DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors
;
; Outputs : DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerFat
;
;=========================================================================
Procedure Calc_Big16_Fat
; Get root size in sectors and add reserved to it
mov AX,DeviceParameters.DP_BPB.oldBPB.BPB_RootEntries
.errnz EDP_BPB NE DP_BPB
mov bx,size dir_entry
mul bx ; DX:AX = bytes in root dir
mov bx,DeviceParameters.DP_BPB.oldBPB.BPB_bytesPerSector
dec bx ; Round up to sector multiple
add ax,bx
adc dx,0
inc bx ; get back sector size
div bx ; AX is sectors in root dir
mov bx,DeviceParameters.DP_BPB.oldBPB.BPB_ReservedSectors
add ax,bx ; AX = R + D
mov bx,ax ; over to BX
; Get Total sectors
cmp DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors,00h ; Small disk?
je $$IF109 ; Yes
xor DX,DX ; Set high to 0
mov AX,DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors
jmp SHORT $$EN109
$$IF109:
mov DX,DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors[+2]
mov AX,DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors[+0]
$$EN109:
sub AX,BX ; DX:AX = T - R - D
sbb DX,0
mov BL,DeviceParameters.DP_BPB.oldBPB.BPB_NumberOfFATs
mov BH,DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerCluster
add AX,BX ; AX = T-R-D+(256*SPC)+nFAT
adc DX,0
sub AX,1 ; AX = T-R-D+(256*SPC)+nFAT-1
sbb DX,0
div BX ; Sec/Fat = CEIL((TOTAL-DIR-RES)/
; ((256*SECPERCLUS)+NUMFATS)
mov WORD PTR DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerFat,AX
ret
Calc_Big16_Fat ENDP
;=========================================================================
; Calc_Small_Fat: Calculates the Sectors per Fat for a 12 bit Fat.
;
; Inputs : DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors or
; DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors
;
; Outputs : DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerFat
;
;=========================================================================
Procedure Calc_Small_Fat
; Get root size in sectors and add reserved to it
mov AX,DeviceParameters.DP_BPB.oldBPB.BPB_RootEntries
.errnz EDP_BPB NE DP_BPB
mov bx,size dir_entry
mul bx ; DX:AX = bytes in root dir
mov bx,DeviceParameters.DP_BPB.oldBPB.BPB_bytesPerSector
dec bx ; Round up to sector multiple
add ax,bx
adc dx,0
inc bx ; get back sector size
div bx ; AX is sectors in root dir
mov bx,DeviceParameters.DP_BPB.oldBPB.BPB_ReservedSectors
add ax,bx ; AX = R + D
mov bx,ax ; over to BX
; Get total sectors
cmp DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors,00h ;small disk?
je $$IF112 ; Yes
xor DX,DX ; Set high to 0
mov AX,WORD PTR DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors
jmp SHORT $$EN112
$$IF112:
mov DX,WORD PTR DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors[+2]
mov AX,WORD PTR DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors[+0]
$$EN112:
sub AX,BX ; DX:AX = T - R - D
sbb DX,0
xor BX,BX
mov BL,DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerCluster
div BX
; Now multiply by 3/2
mov BX,3
mul BX ; Div by log 2 of Sectors/clus
mov BX,2
div BX
xor DX,DX
; Now divide by 512
mov BX,512
div BX
ifdef NEC_98
or dx,dx ; for remainder
jz @F
inc AX
@@:
test ax,01h ; for even
jz @F
inc ax
@@:
cmp DeviceParameters.DP_BPB.BPB_BytesPerSector,2048
jne @F
test ax,02h ; for 2048 bytes/sector
jz @F
add ax,2
@@:
else
inc AX
; DX:AX contains number of Fat
; sectors necessary
endif
mov DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerFat,AX
ret
Calc_Small_Fat ENDP
; ==========================================================================
; StartSector = number of reserved Sectors
; + number of Fat Sectors ( Number of FatS * Sectors Per Fat )
; + number of directory Sectors ( 32* Root Entries / bytes Per Sector )
; ( above is rounded up )
;
; Calculate the number of directory Sectors
; ==========================================================================
SetStartSector proc near
xor ax,ax
cmp DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerFAT,ax
je NoRootDir
mov AX, DeviceParameters.DP_BPB.oldBPB.BPB_RootEntries
.errnz EDP_BPB NE DP_BPB
mov BX, size dir_entry
mul BX ; DX:AX is bytes in root dir
mov bx, DeviceParameters.DP_BPB.oldBPB.BPB_bytesPerSector
dec bx ; Round up to sector multiple
add ax,bx
adc dx,0
inc bx ; Get sector size back
div bx ; AX = Sectors in root dir
NoRootDir:
mov SectorsInRootDirectory,AX
.386
movzx eax,ax
mov StartSector, EAX ;not done yet!
; Calculate the number of Fat Sectors
movzx EAX, DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerFat
or ax,ax
jnz short NotFat32a
mov EAX, DWORD PTR DeviceParameters.DP_BPB.BGBPB_BigSectorsPerFat
NotFat32a:
movzx ebx,DeviceParameters.DP_BPB.oldBPB.BPB_numberOfFats
mul ebx
; add in the number of boot Sectors
movzx ebx,DeviceParameters.DP_BPB.oldBPB.BPB_ReservedSectors
add EAX,EBX
add StartSector, EAX
.8086
return
SetStartSector endp
; ==========================================================================
;
; fBigFat = ( ( (TotalSectors - StartSector) / SectorsPerCluster) >= 4086 )
;
; ==========================================================================
SetfBigFat proc near
cmp DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerFAT,0
.errnz EDP_BPB NE DP_BPB
jne NotFat32b
mov fBig32Fat, TRUE ; Set flag
mov ThisSysInd,8
jmp SHORT $$EN21
NotFat32b:
cmp DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors+2,0
je $$IF21 ; no, 12-bit Fat
mov fBigFat, TRUE ; Set flag
mov ThisSysInd,6
jmp SHORT $$EN21 ; Nope, < 32,b
$$IF21: ; Assume this used
mov AX,DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors
cmp AX,0 ; Was this field used?
jne $$IF23 ; Yes
; No, use other sector field
mov AX, DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors
$$IF23: ; ** Fix for PTM PCDOS P51
mov ThisSysInd,1 ; Set small Fat for default
sub AX,word ptr StartSector ; Get Sectors in data area
xor DX,DX
xor BX,BX
mov bl,DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerCluster
div BX ; Get total clusters
cmp AX,BIG_Fat_THRESHOLD ; Is clusters >= 4086?
jnae $$IF25
mov fBigFat,TRUE ; 16 bit Fat if >=4096
; ** END fix for PTM PCDOS P51
mov ThisSysInd,4 ; set large Fat
$$IF25:
$$EN21:
return
SetfBigFat endp
;==========================================================================
;
; GetTotalClusters : This procedure initializes the variable TotalClusters.
; This is utilized by Quick Format to check for when all
; the clusters have been processed.
; Destroys : AX,BX,CX,DX
; Strategy : TotalClusters = (TotalSectors-Fats-Root-Reserved)/SectorsPerCluster
;
;==========================================================================
GetTotalClusters proc NEAR
.386
movzx EAX,DeviceParameters.DP_BPB.oldBPB.BPB_TotalSectors
.errnz EDP_BPB NE DP_BPB
or AX,AX ; Check if BigTotalSectors must be used
jnz short GoSubstract ; M015; Substrack Fats, Root and reserved
GetBigSectors:
mov EAX,dword ptr DeviceParameters.DP_BPB.oldBPB.BPB_BigTotalSectors
GoSubstract:
movzx edx,DeviceParameters.DP_BPB.oldBPB.BPB_ReservedSectors
sub EAX,EDX
movzx edx,DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerFat
or dx,dx
jnz short NotFat32c
mov DeviceParameters.DP_BPB.oldBPB.BPB_RootEntries,dx ; No root dir on FAT32
mov edx,dword ptr DeviceParameters.DP_BPB.BGBPB_BigSectorsPerFat
NotFat32c:
movzx cx,DeviceParameters.DP_BPB.oldBPB.BPB_NumberOfFats
jcxz GoDivide ; M017; if non fat, don't even do the root
SubstractAFat:
sub EAX,EDX
loop SubstractAFat
GoSubstractRoot:
; Assumes that BytesPerSectors is a power of 2 and at least 32
; Those are valid assumptions since BIOS requires the same.
mov BX,DeviceParameters.DP_BPB.oldBPB.BPB_BytesPerSector
shr BX,5 ; divide by 32, BX = root entries per sector (a power of 2)
or BX,BX ; Sanity check for infinite looping
jz short SayWhat
mov CX,DeviceParameters.DP_BPB.oldBPB.BPB_RootEntries
SubstractRootLoop:
test BX,1
jnz short SubstractRootReady
shr BX,1
shr CX,1
jmp short SubstractRootLoop
SubstractRootReady:
movzx ecx,cx
sub EAX,ECX
GoDivide:
movzx ebx,DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerCluster
xor edx,edx
div EBX
inc EAX ; Bump by 1 since start with 2
cmp DeviceParameters.DP_BPB.oldBPB.BPB_SectorsPerFat,0
je short NoOvlChk
cmp EAX,0000FFEFh ; Sanity check
ja short SayWhat
NoOvlChk:
mov TotalClusters,EAX
.8086
ret
SayWhat:
Message msgInvalidDeviceParameters
jmp FatalExit
GetTotalClusters endp
; SetDOS_Dpb - Need to set the DPB for a memory card because the
; default will be for the last disk accessed in the
; the drive and may not be correct for the current
; disk.
SetDOS_Dpb PROC
cmp CMCDDFlag, Yes
je @f
clc
ret
@@:
push ds
pop es
mov di, offset SetDPBPacket
mov ax, OFFSET DeviceParameters.DP_BPB ; DS:AX --> BPB for disk
.errnz EDP_BPB NE DP_BPB
mov word ptr [di.SetDPB_Value1],ax
mov word ptr [di.SetDPB_Value1+2],ds
xor ax,ax
mov word ptr [di.SetDPB_Value2],ax
mov word ptr [di.SetDPB_Value2+2],ax
mov word ptr [di.SetDPB_Value3],ax
mov word ptr [di.SetDPB_Value3+2],ax
mov word ptr [di.SetDPB_Value4],ax
mov word ptr [di.SetDPB_Value4+2],ax
.386
mov [di.SetDPB_Function],SetDPB_SetDPBFrmBPB
movzx dx,DriveToFormat
.8086
inc dx ; 1 based drive number
mov ax,(Get_Set_DriveInfo SHL 8) OR Set_DPBForFormat
mov cx,size SDPDFormatStruc
int 21h
;
; NOTE: This call fails in protected mode under Win95. VFAT/VDEF do not
; implement it. This call REALLY isn't necessary anyway. The
; SetDeviceParameters we do as part of the format is supposed to
; trigger the device driver to return "media changed" on the next
; media check call.
;
clc
ret
SetDOS_Dpb ENDP
;==========================================================================
ifdef NEC_98
; IN : DX:AX total_sectors
; : DeviceParameters
; OUT : SI = offset DiskTable
; : BX = BytesPerSector
; : DX:AX = total sectors
;
; USE : AX,BX,DX,SI
;
SetDiskTableNEC_98 proc near
mov bx,DeviceParameters.DP_BPB.BPB_BytesPerSector
cmp bx,200h
je large?_512
cmp bx,100h
je large?_256
cmp bx,400h
jne not_large
large?_1024:
cmp dx,2
jb not_large
je @F
jmp set_large1024 ; 1024 and DX > 2 --> large partition.
; > 129MB
@@:
cmp ax,200h
jb not_large
jmp set_large1024 ; 1024 and DX = 2 and AX >= 512 --> large partition.
; > 128.5MB
large?_512:
cmp dx,4
jb not_large
je @F
jmp set_large512 ; 512 and DX > 4 --> large partition.
; > 129MB
@@:
cmp ax,400h
jb not_large
jmp set_large512 ; 512 and DX = 4 and AX >= 1024 --> large partition.
; > 128.5MB
large?_256:
cmp dx,8
jb not_large
je @F
jmp set_large256 ; 256 and DX > 8 --> large partition.
; > 129MB
@@:
cmp ax,800h
jb not_large
jmp set_large256 ; 256 and DX = 8 and AX >= 2048 --> large partition.
; > 128.5MB
not_large:
cmp bx,800h
jne @F
jmp set_2K
@@:
cmp bx,200h
je sec2K?_512
cmp bx,100h
je sec2K?_256
sec2K?_1024:
cmp dx,1
jb not_2K
je @F
shr dx,1 ;convert 1K->2K
rcr ax,1
jmp set_2K ; 1024 and DX > 1 --> 2KB partition.
; > 65MB
@@:
cmp ax,200h
jb not_2K
shr dx,1 ;convert 1K->2K
rcr ax,1
jmp set_2K ; 1024 and DX = 1 and AX >= 1024 --> 2KB partition.
; > 64.5MB
sec2K?_512:
cmp dx,2
jb not_2K
je @F
shr dx,1 ;convert 512->2K
rcr ax,1
shr dx,1
rcr ax,1
jmp set_2K ; 512 and DX > 2 --> 2KB partition.
; > 65MB
@@:
cmp ax,400h
jb not_2K
shr dx,1 ;convert 512->2K
rcr ax,1
shr dx,1
rcr ax,1
jmp set_2K ; 512 and DX = 2 and AX >= 1024 --> 2KB partition.
; > 64.5MB
sec2K?_256:
cmp dx,4
jb not_2K
je @F
shr dx,1 ;convert 256->2K
rcr ax,1
shr dx,1
rcr ax,1
shr dx,1
rcr ax,1
shr dx,1
rcr ax,1
jmp set_2K ; 256 and DX > 4 --> 2KB partition.
; > 65MB
@@:
cmp ax,800h
jb not_2K
shr dx,1 ;convert 256->2K
rcr ax,1
shr dx,1
rcr ax,1
shr dx,1
rcr ax,1
shr dx,1
rcr ax,1
jmp set_2K ; 256 and DX = 4 and AX >= 1024 --> 2KB partition.
; > 64.5MB
not_2K:
push cx
push dx
push ax
xor dx,dx
mov ax,1024
div bx
mov cx,ax
pop ax ;DX:AX total sectors
pop dx
@@:
shr cx,1
jc @F
shr dx,1
rcr ax,1
jmp short @B
pop cx ;DX:AX convert ->1KB
mov bx,1024
cmp dx,0
je @F
mov ax,0FFFFh
mov dx,0
@@:
;;; follow function is NEC_98 only.
push ax
push ds
push dx
push cx
push cs
pop ds
mov dx,offset LPTABLE
mov cl,13h
int 220 ;GET LPTABLE
add dx,001Ah ;EXLPTABLE start offset
mov al,DriveToFormat
shl al,1 ;Drive * 2
xor ah,ah
add dx,ax
inc dx ;+1 (=DA/UA)
mov bx,dx
mov al,[bx] ;GET DA/UA at al
pop cx
pop dx
pop ds
mov ah,al ;al copy to ah
and al,0F0h
cmp al,80h
je @F
jmp set_SCSItable ;STACK AX ;Not 8xh
@@:
push es
push ax
mov ax,40h
mov es,ax ;es = 0040h
pop ax
mov al,es:[0057h]
pop es
cmp ah,80h
je IDE1_check ;STACK AX
and al,00000111b
cmp al,00000110b
je set_SASItable ;STACK AX 2nd IDE is 40MB
cmp al,00000100b
je set_SASItable ;STACK AX 2nd IDE is 20MB
jmp short set_SCSItable ;STACK AX
IDE1_check:
and al,00111000b
cmp al,00110000b
je set_SASItable ;STACK AX 1st IDE is 40MB
cmp al,00100000b
je set_SASItable ;STACK AX 1st IDE is 20MB
jmp short set_SCSItable ;STACK AX
LPTABLE DB 96 DUP (?)
set_SASItable:
pop ax
mov si, offset SASI1024Table
jmp short exit_disktable
set_large1024:
set_SCSItable:
pop ax
mov si, offset SCSI1024Table
jmp short exit_disktable
set_large256:
mov si, offset Large256Table
jmp short exit_disktable
set_large512:
mov si, offset Large512Table
jmp short exit_disktable
set_2K:
mov bx,2048
cmp dx,0
je @F
mov ax,0FFFFh
mov dx,0
@@:
mov si, offset Small2048Table
exit_disktable:
ret
SetDiskTableNEC_98 endp
MY_INT24 proc far
mov al, 0 ; don't display messages
iret
MY_INT24 endp
endif
CODE ENDS
END