📄 wdrminit.asm
字号:
;
; /d:svf
; /d:s /d:v /d:f
;
; These two are the same, both s and v debug options are specified.
; we allow both forms so that users don't get confused and can do multiple
; debug options either way.
;
; This loop exits immeidatly if /d:f is found. Wdctrl will be disabled.
;
movzx cx, BYTE PTR ds:[80h]
jcxz WD_RMI_TSD_No_Debug_Opt
mov si, 81h
cld
WD_RMI_TSD_Cont_Search:
lodsb
WD_RMI_TSD_Cont_Search2:
cmp al,'/'
jne short WD_RMI_TSD_ChkBnd
WD_RMI_TSD_NextSw:
dec cx
jz SHORT WD_RMI_TSD_No_Debug_Opt
lodsb
or al,20h ; force to lower case
cmp al,'d' ; /d ?
jne SHORT WD_RMI_TSD_UnkSwitch ; No, unknown switch
dec cx
jz SHORT WD_RMI_TSD_No_Debug_Opt
lodsb
cmp al,':' ; /d: ?
jne SHORT WD_RMI_TSD_UnkSwitch ; No, unknown switch
dec cx
jz SHORT WD_RMI_TSD_No_Debug_Opt
lodsb
WD_RMI_TSD_ContDebOpt:
cmp al,'A' ; /d: something that is a letter?
jb short WD_RMI_TSD_UnkSwitch ; No, unknown switch
cmp al,'Z'
jbe short WD_RMI_TSD_IsUpDebOpt ; Yes
cmp al,'a'
jb short WD_RMI_TSD_UnkSwitch ; No, unknown switch
cmp al,'z'
ja short WD_RMI_TSD_UnkSwitch ; No, unknown switch
WD_RMI_TSD_IsUpDebOpt:
or al,20h ; force to lower case
cmp al, "f"
je SHORT WD_RMI_TSD_Dont_Load
dec cx
jz SHORT WD_RMI_TSD_No_Debug_Opt
lodsb
cmp al,20h ; End of this debug opt?
je short WD_RMI_TSD_LoopIt ; Yes
cmp al,09h ; End of this debug opt?
je short WD_RMI_TSD_LoopIt ; Yes
cmp al,'/' ; End of this debug opt?
je short WD_RMI_TSD_NextSw ; Yes
jmp short WD_RMI_TSD_ContDebOpt
WD_RMI_TSD_UnkSwitch:
dec cx
jz SHORT WD_RMI_TSD_No_Debug_Opt
WD_RMI_TSD_UnkSwitchCnt:
lodsb
cmp al,20h
je short WD_RMI_TSD_LoopIt
cmp al,09h
je short WD_RMI_TSD_LoopIt
cmp al,'/'
je short WD_RMI_TSD_NextSw
loop WD_RMI_TSD_UnkSwitchCnt
jmp SHORT WD_RMI_TSD_No_Debug_Opt
WD_RMI_TSD_ChkBnd:
cmp al,' '
je short WD_RMI_TSD_LoopIt
cmp al,09h
jne short WD_RMI_TSD_No_Debug_Opt
WD_RMI_TSD_LoopIt:
loop WD_RMI_TSD_Cont_Search
WD_RMI_TSD_No_Debug_Opt:
clc
WD_RMI_TSD_Pop_Exit:
popa
pop ds
ret
WD_RMI_TSD_Dont_Load:
stc
jmp WD_RMI_TSD_Pop_Exit
EndProc Test_Disable_Switch
;******************************************************************************
;
; Print_Hex_Byte
;
; DESCRIPTION:
;
; ENTRY:
; AL = Byte to print
;
; EXIT:
;
; USES:
; Flags
;
;==============================================================================
Hex_Convert_Table db "0123456789ABCDEF"
BeginProc Print_Hex_Byte
pusha
mov bx, ax
mov si, ax
shr bx, 4
and bx, 1111b
and si, 1111b
mov dl, Hex_Convert_Table[bx]
mov ah, 2
int 21h
mov dl, Hex_Convert_Table[si]
int 21h
popa
ret
EndProc Print_Hex_Byte
ENDIF
;******************************************************************************
;
; Clean_Up_Hooks
;
; DESCRIPTION:
;
; ENTRY:
;
; EXIT:
;
; USES:
;
;==============================================================================
BeginProc Clean_Up_Hooks
pusha
xor ecx, ecx
xchg ecx, [DOS_BIOS_Int13_Vec]
jecxz WD_UIC_Int13_Unhooked
mov eax, [ROM_BIOS_Int13_Vec]
mov dx, cx
shr ecx, 16
mov ds, cx
mov bx, ax
shr eax, 16
mov es, ax
mov ah, 13h
int 2Fh
mov ax, cs
mov ds, ax
mov es, ax
;
; Check to see if we have incremented the InDOS flag and broadcasted the
; hardware detection Int 2Fh API. If so, dec the InDOS flag and signal
; then end of hardware detection.
;
WD_UIC_Int13_Unhooked:
xor cx, cx
xchg cl, [Signaled_Detection]
jcxz SHORT WD_UIC_Exit
;
; WARNING: Strange hanging bug with MS-NET server kernel loaded if you
; try to get the InDOS ptr while InDOS is non-zero. Therefore,
; we don't want to call DOS here to get the InDOS flag. That's
; why we saved it away earlier.
;
push es
les bx, [InDOS_Ptr] ; ES:[BX] -> InDOS flag
dec BYTE PTR es:[bx] ; Dec the InDOS flag
pop es
mov ax, (W386_Int_Multiplex SHL 8) + W386_Device_Broadcast
mov bx, BlockDev_Device_ID
mov cx, BlockDev_API_Hw_Detect_End
int 2Fh
WD_UIC_Exit:
popa
ret
EndProc Clean_Up_Hooks
;******************************************************************************
;
; Fatal_Disk_Error
;
; DESCRIPTION:
; This procedure is jumped to by WDCtrl_Validate_Drive if a fatal
; error is detected. It displays a nasty warning message and hangs
; the machine.
;
; ENTRY:
; DS = Our data segment
; BL = Error code
;
; EXIT:
; Never!
;
; USES:
; Who cares!
;
;==============================================================================
BeginProc Fatal_Disk_Error
call Clean_Up_Hooks
IFNDEF SETUP
add bl,'0' ;Convert error code to ASCII 0-9
mov si, OFFSET WD_Fatal_Error_Code
mov ds:[si], bl ;Poke the error number in
mov ah, 9
mov dx, OFFSET WD_Fatal_Error_Msg
int 21h
ELSE
mov ax, DGROUP ;Set up DS, ES to our data segment
mov ds, ax ;before calling error display routine.
mov es, ax
mov ax, ERR_WDCTRL_FATAL
push ax
call _WDCtrlHangError
pop ax
ENDIF
jmp $
EndProc Fatal_Disk_Error
;******************************************************************************
;
; WDCtrl_Validate_Drive
;
; DESCRIPTION:
; The procedure must be called with the following parameters:
; DL = Int 13h drive number to test (80h or 81h)
; [0:DI] -> Fixed disk parameter table for this drive
; DS=ES pointing to a data segment with the following data variables:
;
; Orig_Int13_Vector dd ?
; Int13_Buffer db 512 dup (?)
; My_Read_Buffer db 512 dup (?)
;
; The Orig_Int13_Vector must be filled in by the caller before invoking
; this code. This variable should contain the CS:IP value returned
; by DOS from the Int 2Fh/AH=13h call to obtain the address of the
; original Int 13h handler. The other variables do not need to be
; filled in.
;
; The procedure will do one of three things:
; Return with carry clear to indicate that the drive is WDCtrl compatible
; Return with carry set to indicate that it can't use the drive
; Jump to a label named "FATAL_DISK_ERROR". The main program should
; display an error message and HANG THE MACHINE if this happens.
;
; If the procedure returns with carry set then CX will contain a value
; that defines the phase of initialization that failed.
;
; A flag is returned in BX indicating whether or not the ALTERNATE
; Status register should be used. BX is set to 0FFFFh iff the
; alt status register should be used by WDCtrl for this drive. BX
; will be 0 if the normal status register should be used for this drive.
;
; All segment registers will be preserved by the procedure. All other
; registers and flags will be modified.
;
;==============================================================================
Check_Invalid MACRO JmpIns
LOCAL WD_CI_Invalid, WD_CI_Valid
IFNDEF DEBUG
JmpIns WD_VD_Invalid
inc [bp.Test_Phase]
ELSE
JmpIns SHORT WD_CI_Invalid
inc [bp.Test_Phase]
jmp SHORT WD_CI_Valid
WD_CI_Invalid:
int 3
jmp WD_VD_Invalid
WD_CI_Valid:
ENDIF
ENDM
Check_Fatal_Error MACRO JmpIns,ErrorCode ;;Trashes bl
mov bl, ErrorCode
JmpIns Fatal_Disk_Error
ENDM
BeginProc WDCtrl_Validate_Drive
Test_Stack_Frame STRUC
Test_Sector_Num dw ?
Test_Cyl_Num dw ?
Test_Head_Num dw ?
Test_Phase dw ?
Test_Loop_Phase dw ?
Test_Drive_Number db ?
db ? ; Dword align
Test_Param_Off dw ?
Test_Param_Seg dw ?
Test_Alt_Status_Flag dw ?
Test_Stack_Frame ENDS
push es
push bp
sub sp, SIZE Test_Stack_Frame
mov bp, sp
mov [bp.Test_Drive_Number], dl
xor ax, ax
mov [bp.Test_Phase], ax
mov [bp.Test_Loop_Phase], ax
mov es, ax
les di, es:[di] ; ES:DI -> Drive param table
mov [bp.Test_Param_Seg], es
mov [bp.Test_Param_Off], di
;** Default to the ALT status register. We clear the bit
;** anytime we fail with this register and use the normal one.
mov [bp.Test_Alt_Status_Flag], 0FFFFh
;------------------------------------------------------------------------------
;
; First make sure that the fixed disk parameter table contains the same
; information as Int 13h Get Drive Parameters returns.
;
;------------------------------------------------------------------------------
;** Phase 0
mov ah, 08h
pushf
cli
call [ROM_BIOS_Int13_Vec] ; Q: Did get drive params work?
Check_Invalid jc ; N: Error
; Y: Compare to FDPT
;** Phase 1
inc dh ; One greater returned
cmp dh, es:[di.FDPT_Max_Heads] ; Q: Heads equal?
Check_Invalid jne ; N: No good
;** Phase 2
mov ax, cx
and al, 00111111b
cmp al, es:[di.FDPT_Sec_Per_Track] ; Q: Sector count the same?
Check_Invalid jne ; N: That's strange!
;** Phase 3
shr cl, 6
xchg ch, cl
add cx, 2 ; TWO GREATER RETURNED!
cmp cx, es:[di.FDPT_Max_Cyl] ; Q: Cylinder numbers match?
jne SHORT @F ; N: Try Zenith check
inc [bp.Test_Phase] ; Y: Yes. Bump phase
jmp SHORT WD_VD_CylOK
@@: inc cx ; Check THREE for Zenith
cmp cx, es:[di.FDPT_Max_Cyl]
Check_Invalid jne ; N: Very, very weird
WD_VD_CylOK:
;------------------------------------------------------------------------------
;
; The Test_Loop_Phase variable determines which test to perform. We will
; attempt to read 3 different sectors:
; The 1st sector on the 1st head on the 1st Cyl
; The 503rd sector
; The next-to-last sector on the next-to-last head on the next-to-last cyl
;
;------------------------------------------------------------------------------
WD_VD_Do_Next_Test:
mov ax, [bp.Test_Loop_Phase]
cmp ax, 1
je SHORT WD_VD_Test_503
ja SHORT WD_VD_Test_Last
inc ax
mov [bp.Test_Sector_Num], ax
mov [bp.Test_Head_Num], ax
mov [bp.Test_Cyl_Num], ax
jmp SHORT WD_VD_Do_Read_Now
;------------------------------------------------------------------------------
;
; Now read the next-to-the-last sector on the next-to-the-last head,
; and on the cylinder 7/8 of the way to the end. We don't test the
; last sector because the BIOS might be lying to us about where the
; last sector resides.
;
;------------------------------------------------------------------------------
WD_VD_Test_Last:
movzx ax, es:[di.FDPT_Sec_Per_Track]
dec ax
mov [bp.Test_Sector_Num], ax
movzx ax, es:[di.FDPT_Max_Heads]
dec ax
mov [bp.Test_Head_Num], ax
mov ax, es:[di.FDPT_Max_Cyl]
mov cx, ax ; Get cyl 7/8 of way to end
shr cx, 3
sub ax, cx
mov [bp.Test_Cyl_Num], ax
jmp SHORT WD_VD_Do_Read_Now
;------------------------------------------------------------------------------
;
; Now figure out the head/cyl/sector number for sector 503 on the disk.
; This number was chosen since 503 (decimal) is a prime number. This will
; verify that the BIOS is using standard translation of the BIOS parameter
; table.
;
;------------------------------------------------------------------------------
WD_VD_Test_503:
mov eax, 503 ; EAX = Sector to begin xfer at
xor edx, edx ; Zero high dword for idiv
movzx ecx, es:[di.FDPT_Sec_Per_Track]
idiv ecx ; Remainder+1 = Starting sector
inc dx ; Inc to make 1 based
mov [bp.Test_Sector_Num], dx ; Save it on the stack
xor edx, edx ; Zero high dword for idiv
movzx ecx, es:[di.FDPT_Max_Heads]
idiv ecx ; EAX = Cylinder number
; EDX = Starting head
mov [bp.Test_Cyl_Num], ax ; Save 'em for later
mov [bp.Test_Head_Num], dx
;------------------------------------------------------------------------------
;
; The drive parameters look OK. Now verify read a sector from the drive to
; attempt to force that drive to be selected. To prevent problems with a
; cache we will call the original BIOS handler directly.
;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -