mirror of https://github.com/tongzx/nt5src
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.
1865 lines
59 KiB
1865 lines
59 KiB
PAGE ,132
|
|
TITLE DXDISK.ASM -- Dos Extender Low Level Disk Interface
|
|
|
|
; Copyright (c) Microsoft Corporation 1988-1991. All Rights Reserved.
|
|
|
|
;***********************************************************************
|
|
;
|
|
; DXDISK.ASM -- Dos Extender Low Level Disk Interface
|
|
;
|
|
;-----------------------------------------------------------------------
|
|
;
|
|
; This module provides the 286 DOS extender's low level protected-to-
|
|
; real mode disk interface. It supports a subset of the BIOS Int 13h
|
|
; and DOS Int 25h/26h services.
|
|
;
|
|
;-----------------------------------------------------------------------
|
|
;
|
|
; 05/22/89 jimmat Original version
|
|
; 18-Dec-1992 sudeepb Changed cli/sti to faster FCLI/FSTI
|
|
;
|
|
;***********************************************************************
|
|
|
|
.286p
|
|
|
|
; -------------------------------------------------------
|
|
; INCLUDE FILE DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
.xlist
|
|
.sall
|
|
include segdefs.inc
|
|
include gendefs.inc
|
|
include pmdefs.inc
|
|
include interupt.inc
|
|
include intmac.inc
|
|
|
|
.list
|
|
|
|
; -------------------------------------------------------
|
|
; GENERAL SYMBOL DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; EXTERNAL SYMBOL DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
extrn EnterIntHandler:NEAR
|
|
extrn LeaveIntHandler:NEAR
|
|
extrn EnterRealMode:NEAR
|
|
extrn EnterProtectedMode:NEAR
|
|
extrn GetSegmentAddress:NEAR
|
|
extrn SetSegmentAddress:NEAR
|
|
externFP NSetSegmentDscr
|
|
extrn FreeSelector:NEAR
|
|
extrn AllocateSelector:NEAR
|
|
extrn ParaToLDTSelector:NEAR
|
|
|
|
ifdef NEC_98 ;
|
|
extrn IncInBios:NEAR ;
|
|
extrn DecInBios:NEAR ;
|
|
endif ;NEC_98 ;
|
|
|
|
; -------------------------------------------------------
|
|
; DATA SEGMENT DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
DXDATA segment
|
|
|
|
extrn rgbXfrBuf0:BYTE
|
|
extrn rgbXfrBuf1:BYTE
|
|
ifdef NEC_98
|
|
extrn rglpfnRmISR:DWORD
|
|
endif
|
|
|
|
cbSectorSize dw ? ;sector size for target drive
|
|
cSectorsTransfered dw ? ;# sectors transfered so far
|
|
cSectorsToTransfer dw ? ;# sectors to read/write
|
|
cSectorsPerTransfer dw ? ;# sectors to R/W at a time
|
|
cSectorsThisTransfer dw ? ;# sectors to R/W this time
|
|
lpSectorData dd ? ;far pointer to caller's buffer
|
|
|
|
ifdef NEC_98 ;
|
|
public lpRmISR
|
|
endif ;NEC_98 ;
|
|
lpRmISR dd ? ;real mode int service rtn to invoke
|
|
|
|
ifdef NEC_98 ;
|
|
sensedata1 dw ? ;sector length
|
|
sensedata2 dw ? ;cylinder
|
|
sensedata3 dd ? ;head
|
|
sensedata4 dd ? ;sector num
|
|
|
|
extrn fPCH98:BYTE ;for PC_H98
|
|
endif ;NEC_98 ;
|
|
DXDATA ends
|
|
|
|
; -------------------------------------------------------
|
|
; CODE SEGMENT VARIABLES
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE segment
|
|
|
|
DXCODE ends
|
|
|
|
|
|
DXPMCODE segment
|
|
|
|
extrn segDXDataPM:WORD
|
|
|
|
DXPMCODE ends
|
|
|
|
|
|
; -------------------------------------------------------
|
|
subttl INT 13h Mapping Services
|
|
page
|
|
; -------------------------------------------------------
|
|
; INT 13h MAPPING SERVICES
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE segment
|
|
assume cs:DXPMCODE
|
|
|
|
; -------------------------------------------------------
|
|
; PMIntr13 -- Service routine for the Protect Mode INT 13h
|
|
; interface to the real mode BIOS.
|
|
;
|
|
; Input: Various registers
|
|
; Output: Various registers
|
|
; Errors:
|
|
; Uses: All registers preserved, other than return values
|
|
;
|
|
; Currently, the following Int 13h services are supported:
|
|
;
|
|
; ah= 0 - Reset Disk System (no mapping required)
|
|
; 1 - Get Disk System Status (no mapping required)
|
|
; 2 - Read Sector (mapping required)
|
|
; 3 - Write Sector (mapping required)
|
|
; 4 - Verify Sector (mapping required)
|
|
; 5 - Fromat Track (mapping required)
|
|
; 6 - Format Bad Track (no mapping required)
|
|
; 7 - Format Drive (no mapping required)
|
|
; 8 - Get Drive Parameters (mapping required)
|
|
; 9 - Init Fixed Disk Characteristics (no mapping required)
|
|
; C - Seek (no mapping required)
|
|
; D - Reset Disk System (no mapping required)
|
|
; 10 - Get Drive Status (no mapping required)
|
|
; 11 - Recalibrate Drive (no mapping required)
|
|
; 12 - Controller RAM Diagnostic (no mapping required)
|
|
; 13 - Controller Drive Diagnostic (no mapping required)
|
|
; 14 - Controller Internal Diagnostic (no mapping required)
|
|
; 15 - Get Disk Type (no mapping required)
|
|
; 16 - Get Disk Change Status (no mapping required)
|
|
; 17 - Set Disk Type (no mapping required)
|
|
; 18 - Set Media Type for Format (mapping required)
|
|
; 19 - Park Heads (no mapping required)
|
|
;
|
|
; Functions not listed above will most likely not work properly!
|
|
;
|
|
; NOTE: several functions take 2 bits of the cylinder number in CL
|
|
; if the operation is on a fixed disk. The code currently does
|
|
; not account for these bits, and may not work properly if
|
|
; the request must be split into smaller operations for real/
|
|
; extended memory buffering.
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public PMIntr13
|
|
|
|
PMIntr13 proc near
|
|
|
|
ifdef NEC_98 ;
|
|
call IncInBios ;
|
|
endif ;NEC_98 ;
|
|
cld ;cya...
|
|
|
|
call EnterIntHandler ;build an interrupt stack frame
|
|
assume ds:DGROUP,es:DGROUP ; also sets up addressability
|
|
|
|
FSTI ;allow HW interrupts
|
|
|
|
call IntEntry13 ;perform translations/buffering
|
|
|
|
; Execute the real mode BIOS routine
|
|
ifdef NEC_98 ;
|
|
push es
|
|
assume es:nothing
|
|
mov ax,SEL_RMIVT OR STD_RING
|
|
mov es,ax
|
|
mov ax,word ptr es:[4*1bh] ;move real mode Int 13h
|
|
mov word ptr [bp].lParam,ax ; handler address to
|
|
mov ax,word ptr es:[4*1bh+2]; lParam on stack frame
|
|
mov word ptr [bp].lParam+2,ax
|
|
pop es
|
|
assume es:DGROUP
|
|
|
|
mov ah,1bh ;wParam1 = int #, function
|
|
else ;NEC_98 ;
|
|
|
|
push es
|
|
assume es:nothing
|
|
mov ax,SEL_RMIVT OR STD_RING
|
|
mov es,ax
|
|
mov ax,word ptr es:[4*13h] ;move real mode Int 13h
|
|
mov word ptr [bp].lParam,ax ; handler address to
|
|
mov ax,word ptr es:[4*13h+2]; lParam on stack frame
|
|
mov word ptr [bp].lParam+2,ax
|
|
pop es
|
|
assume es:DGROUP
|
|
|
|
mov ah,13h ;wParam1 = int #, function
|
|
endif ;NEC_98 ;
|
|
mov al,byte ptr [bp].intUserAX+1
|
|
mov [bp].wParam1,ax
|
|
|
|
ifdef NEC_98 ;
|
|
and al,0fh
|
|
cmp al,05 ;write data?
|
|
jb i13_not_rw
|
|
cmp al,06 ;read data?
|
|
ja i13_not_rw
|
|
else ;NEC_98 ;
|
|
cmp al,02 ;call special read/write routine
|
|
jb i13_not_rw ; if this is a read/write sectors
|
|
cmp al,03 ; request
|
|
ja i13_not_rw
|
|
endif ;NEC_98 ;
|
|
|
|
call ReadWriteSectors ;common Int 13h/25h/26h read/write code
|
|
jmp short i13_done
|
|
|
|
i13_not_rw:
|
|
SwitchToRealMode ;otherwise, do the service ourself
|
|
pop es
|
|
pop ds
|
|
assume ds:NOTHING,es:NOTHING,ss:DGROUP
|
|
popa
|
|
sub sp,8 ; make room for stack frame
|
|
push bp
|
|
mov bp,sp
|
|
push es
|
|
push ax
|
|
|
|
xor ax,ax
|
|
mov es,ax
|
|
mov [bp + 8],cs
|
|
mov [bp + 6],word ptr (offset i13_10)
|
|
ifdef NEC_98 ;
|
|
mov ax,es:[1Bh*4]
|
|
mov [bp + 2],ax
|
|
mov ax,es:[1Bh*4 + 2]
|
|
else ;NEC_98 ;
|
|
mov ax,es:[13h*4]
|
|
mov [bp + 2],ax
|
|
mov ax,es:[13h*4 + 2]
|
|
endif ;NEC_98 ;
|
|
mov [bp + 4],ax
|
|
pop ax
|
|
pop es
|
|
pop bp
|
|
retf
|
|
|
|
i13_10: pushf
|
|
FCLI
|
|
pusha
|
|
push ds
|
|
push es
|
|
mov bp,sp ;restore stack frame pointer
|
|
SwitchToProtectedMode
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
|
|
FSTI ;allow HW interrupts
|
|
|
|
; Perform fixups on the return register values.
|
|
|
|
i13_done:
|
|
mov ax,[bp].pmUserAX ;get original function code
|
|
call IntExit13
|
|
|
|
FCLI ;LeaveIntHandler requires ints off
|
|
call LeaveIntHandler ;restore caller's registers, stack
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
ifdef NEC_98 ;
|
|
call DecInBios ;
|
|
endif ;NEC_98 ;
|
|
riret
|
|
|
|
PMIntr13 endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; IntEntry13 -- This routine performs translations and
|
|
; buffering of Int 13h requests on entry.
|
|
;
|
|
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public IntEntry13
|
|
|
|
IntEntry13 proc near
|
|
|
|
ifdef NEC_98 ;
|
|
and ah,0fh
|
|
|
|
cmp ah,05 ;Write sectors?
|
|
jb @f
|
|
cmp ah,06 ;Read sectors?
|
|
ja @f
|
|
|
|
;----------- 90/08/13 copy segment address from ds -------
|
|
push ax
|
|
mov ax,segDXDataPM
|
|
mov [bp].intUserES,ax ;segment address
|
|
pop ax
|
|
;------------------------------------------------------------
|
|
mov [bp].intUserBP,offset DGROUP:rgbXfrBuf1 ;use DOSX buffer 90/07/13
|
|
ret
|
|
@@:
|
|
cmp ah,01h ;Verify sectors?
|
|
jnz @f
|
|
|
|
mov [bp].intUserES,0F000h ;older versions of verify need a buff,
|
|
mov [bp].intUserBP,0 ; offset adress 90/07/12 change
|
|
ret
|
|
@@:
|
|
cmp ah,0Dh ;Format track?
|
|
jnz @f
|
|
|
|
;------ 90/11/08 debug -----
|
|
|
|
push ds
|
|
mov si,[bp].pmUserBP ;es:bx -> 512 byte buffer to copy down
|
|
mov ds,[bp].pmUserES
|
|
mov di,offset DGROUP:rgbXfrBuf1
|
|
mov cx,128 ;might be good to check segment limit
|
|
cld ; on callers source!
|
|
rep movsw
|
|
pop ds
|
|
|
|
push ax
|
|
mov ax,segDXDataPM
|
|
mov [bp].intUserES,ax ;segment address
|
|
pop ax
|
|
mov [bp].intUserBP,offset DGROUP:rgbXfrBuf1
|
|
|
|
push es
|
|
pop ds
|
|
|
|
ret
|
|
@@:
|
|
;///// 90/09/04 PC_H98 DISK BIOS command(Read Defect Data) support/////
|
|
test fPCH98,0FFh
|
|
jz @f
|
|
cmp ah,0Ch
|
|
jz ReadDD
|
|
cmp ah,2Ch
|
|
jz ReadDD
|
|
jmp @f
|
|
|
|
ReadDD:
|
|
push ax
|
|
mov ax,segDXDataPM
|
|
mov [bp].intUserES,ax ;segment address
|
|
pop ax
|
|
mov [bp].intUserBP,offset DGROUP:rgbXfrBuf1 ;use DOSX buffer 90/07/13
|
|
;///// 90/09/04 PC_H98 DISK BIOS command(Read Defect Data) support/////
|
|
|
|
@@:
|
|
ret
|
|
|
|
else ;NEC_98 ;
|
|
cmp ah,02 ;Read sectors?
|
|
jb @f
|
|
cmp ah,03 ;Write sectors?
|
|
ja @f
|
|
|
|
mov [bp].intUserBX,offset DGROUP:rgbXfrBuf1 ;use DOSX buffer
|
|
ret
|
|
@@:
|
|
cmp ah,04h ;Verify sectors?
|
|
jnz @f
|
|
|
|
mov [bp].intUserES,0F000h ;older versions of verify need a buff,
|
|
mov [bp].intUserBX,0 ; we just point them at the BIOS!
|
|
ret
|
|
@@:
|
|
cmp ah,05h ;Format track?
|
|
jnz @f
|
|
|
|
mov si,bx ;es:bx -> 512 byte buffer to copy down
|
|
mov di,offset DGROUP:rgbXfrBuf1
|
|
mov [bp].intUserBX,di
|
|
mov ds,[bp].pmUserES
|
|
mov cx,256 ;might be good to check segment limit
|
|
cld ; on callers source!
|
|
rep movsw
|
|
|
|
push es
|
|
pop ds
|
|
|
|
ret
|
|
@@:
|
|
|
|
ret
|
|
endif ;NEC_98 ;
|
|
|
|
IntEntry13 endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; IntExit13 -- This routine performs translations and
|
|
; buffering of Int 13h requests on exit.
|
|
;
|
|
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public IntExit13
|
|
|
|
IntExit13 proc near
|
|
|
|
ifdef NEC_98 ;
|
|
; Functions 06h (Read sectors) and 05h (Write sectors) return a count of
|
|
; sectors transfered in AL. Since we may break the transfer up into a
|
|
; number of transfers, we have to return the total # that we transfered,
|
|
; not the number of the last bios request.
|
|
|
|
;----- 90/11/08 debug -----
|
|
and ah,0fh
|
|
;----- 90/11/08 debug -----
|
|
|
|
;----- 90/07/06 change -----
|
|
cmp ah,05h ;Write data
|
|
jb @f
|
|
cmp ah,06h ;Read data
|
|
ja @f
|
|
|
|
mov al,byte ptr cSectorsTransfered
|
|
mov byte ptr [bp].intUserAX,al
|
|
@@:
|
|
|
|
; Functions 06h (Read sectors), 05h (Write sectors), 01h (Verify sectors),
|
|
; and 0Dh (Format track) need to have the caller's value of bx restored.
|
|
|
|
;----- 90/07/06 change -----
|
|
|
|
cmp ah,01h ;Verify sectors?
|
|
je @f
|
|
cmp ah,05h ;Write sectors?
|
|
je @f
|
|
cmp ah,06h ;Read sectors?
|
|
je @f
|
|
cmp ah,0Dh ;Format track?
|
|
jne other
|
|
|
|
;offset adress 90/07/12 change
|
|
;----------- 90/08/13 copy segment address from ES -------
|
|
mov ax,[bp].pmUserES
|
|
mov [bp].intUserES,ax
|
|
;------------------------------------------------------------
|
|
@@: mov ax,[bp].pmUserBP ;restore caller's BP value
|
|
mov [bp].intUserBP,ax
|
|
other:
|
|
ret
|
|
|
|
else ;NEC_98 ;
|
|
; Functions 02h (Read sectors) and 03h (Write sectors) return a count of
|
|
; sectors transfered in AL. Since we may break the transfer up into a
|
|
; number of transfers, we have to return the total # that we transfered,
|
|
; not the number of the last bios request.
|
|
|
|
cmp ah,02h
|
|
jb @f
|
|
cmp ah,03h
|
|
ja @f
|
|
|
|
mov al,byte ptr cSectorsTransfered
|
|
mov byte ptr [bp].intUserAX,al
|
|
@@:
|
|
|
|
; Functions 02h (Read sectors), 03h (Write sectors), 04h (Verify sectors),
|
|
; and 05h (Format track) need to have the caller's value of bx restored.
|
|
|
|
cmp ah,02h ;Read sectors?
|
|
jb @f
|
|
cmp ah,05 ;Format track?
|
|
ja @f
|
|
|
|
mov ax,[bp].pmUserBX ;restore caller's BX value
|
|
mov [bp].intUserBX,ax
|
|
ret
|
|
@@:
|
|
|
|
; Functions 08h (Get Drive Parameters) and 18h (Set Drive Type for Format)
|
|
; return a pointer in ES:DI. Map the segment in ES to a selector
|
|
|
|
cmp ah,08h ;Get Drive Parameters
|
|
jz i13_map_es
|
|
cmp ah,18h
|
|
jnz @f
|
|
|
|
i13_map_es:
|
|
test byte ptr [bp].intUserFL,1 ;don't bother to map ES if
|
|
jnz @f ; function failed (carry set)
|
|
|
|
i13_do_it:
|
|
mov ax,[bp].intUserES ;returns a pointer in ES:DI, get
|
|
mov bx,STD_DATA ; a selector for it
|
|
call ParaToLDTSelector
|
|
mov [bp].pmUserES,ax
|
|
ret
|
|
@@:
|
|
|
|
ret
|
|
endif ;NEC_98 ;
|
|
|
|
IntExit13 endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
subttl INT 25h/26h Absolute Disk Read/Write
|
|
page
|
|
; -------------------------------------------------------
|
|
; INT 25h/26h ABSOLUTE DISK READ/WRITE
|
|
; -------------------------------------------------------
|
|
; PMIntr25 -- This routine provides the protected-to-real
|
|
; mode mapping for Int 25h (Absolute Disk Read)
|
|
;
|
|
; In: al - drive # (0 = A, 1 = B, ...)
|
|
; cx - # of sectors to read
|
|
; dx - starting sector #
|
|
; ds:bx - selector:offset of buffer
|
|
;
|
|
; -- or --
|
|
;
|
|
; al - drive #
|
|
; cx - -1
|
|
; ds:bx - pointer to 5 word parameter block
|
|
;
|
|
; Out: if successful, carry clear
|
|
; if unsuccessful, carry set and
|
|
; ax - error code
|
|
|
|
assume ds:DGROUP,es:DGROUP
|
|
public PMIntr25
|
|
|
|
PMIntr25 proc near
|
|
|
|
ifdef NEC_98 ;
|
|
call IncInBios ;
|
|
endif ;NEC_98 ;
|
|
cld ;cya...
|
|
|
|
call EnterIntHandler ;build an interrupt stack frame
|
|
assume ds:DGROUP,es:DGROUP ; also sets up addressability
|
|
|
|
FSTI ;allow HW interrupts
|
|
|
|
mov ah,25h
|
|
call IntEntry2X ;perform translations/buffering
|
|
|
|
; Do the read
|
|
|
|
push es
|
|
mov ax,SEL_RMIVT OR STD_RING
|
|
mov es,ax
|
|
assume es:nothing
|
|
mov ax,word ptr es:[4*25h] ;move real mode Int 25h
|
|
mov word ptr [bp].lParam,ax ; handler address to
|
|
mov ax,word ptr es:[4*25h+2]; lParam on stack frame
|
|
mov word ptr [bp].lParam+2,ax
|
|
pop es
|
|
assume es:DGROUP
|
|
|
|
mov ah,25h ;wParam1 = int #
|
|
mov [bp].wParam1,ax
|
|
|
|
call ReadWriteSectors ;common Int 13h/25h/26h read/write code
|
|
|
|
; Perform fixups on the return register values.
|
|
|
|
mov ah,25h
|
|
call IntExit2X ;perform translations/buffering
|
|
|
|
FCLI
|
|
call LeaveIntHandler ;restore caller's registers, stack
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
; Int 25 & 26 leave the caller's flags on the stack, but we want to return
|
|
; with the flags returned by the real mode ISR (which LeaveIntHandler has
|
|
; incorporated into the caller's flags), so make a copy of the flags and
|
|
; pop them into the flags register before returning.
|
|
|
|
push ax
|
|
push bp
|
|
mov bp,sp ;bp -> BP AX IP CS FL
|
|
mov ax,[bp+8]
|
|
xchg ax,[bp+2] ;bp -> BP FL IP CS FL
|
|
pop bp
|
|
ifdef NEC_98 ;
|
|
call DecInBios ;
|
|
endif ;NEC_98 ;
|
|
npopf
|
|
|
|
retf
|
|
|
|
PMIntr25 endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; PMIntr26 -- This routine provides the protected-to-real
|
|
; mode mapping for Int 26h (Absolute Disk Write)
|
|
;
|
|
; In: al - drive # (0 = A, 1 = B, ...)
|
|
; cx - # of sectors to write
|
|
; dx - starting sector #
|
|
; ds:bx - selector:offset of buffer
|
|
;
|
|
; -- or --
|
|
;
|
|
; al - drive #
|
|
; cx - -1
|
|
; ds:bx - pointer to 5 word parameter block
|
|
;
|
|
; Out: if successful, carry clear
|
|
; if unsuccessful, carry set and
|
|
; ax - error code
|
|
|
|
assume ds:DGROUP,es:DGROUP
|
|
public PMIntr26
|
|
|
|
PMIntr26 proc near
|
|
|
|
ifdef NEC_98 ;
|
|
call IncInBios ;
|
|
endif ;NEC_98 ;
|
|
cld ;cya...
|
|
|
|
call EnterIntHandler ;build an interrupt stack frame
|
|
assume ds:DGROUP,es:DGROUP ; also sets up addressability
|
|
|
|
FSTI ;allow HW interrupts
|
|
|
|
mov ah,26h
|
|
call IntEntry2X ;perform translations/buffering
|
|
|
|
; Do the write
|
|
|
|
push es
|
|
mov ax,SEL_RMIVT OR STD_RING
|
|
mov es,ax
|
|
assume es:nothing
|
|
mov ax,word ptr es:[4*26h] ;move real mode Int 25h
|
|
mov word ptr [bp].lParam,ax ; handler address to
|
|
mov ax,word ptr es:[4*26h+2]; lParam on stack frame
|
|
mov word ptr [bp].lParam+2,ax
|
|
pop es
|
|
assume es:DGROUP
|
|
|
|
mov ah,26h ;wParam1 = int #
|
|
mov [bp].wParam1,ax
|
|
|
|
call ReadWriteSectors ;common Int 13h/25h/26h read/write code
|
|
|
|
; Perform fixups on the return register values.
|
|
|
|
mov ah,26h
|
|
call IntExit2X ;perform translations/buffering
|
|
|
|
FCLI
|
|
call LeaveIntHandler ;restore caller's registers, stack
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
; Int 25 & 26 leave the caller's flags on the stack, but we want to return
|
|
; with the flags returned by the real mode ISR (which LeaveIntHandler has
|
|
; incorporated into the caller's flags), so make a copy of the flags and
|
|
; pop them into the flags register before returning.
|
|
|
|
push ax
|
|
push bp
|
|
mov bp,sp ;bp -> BP AX IP CS FL
|
|
mov ax,[bp+8]
|
|
xchg ax,[bp+2] ;bp -> BP FL IP CS FL
|
|
pop bp
|
|
ifdef NEC_98 ;
|
|
call DecInBios ;
|
|
endif ;NEC_98 ;
|
|
npopf
|
|
|
|
retf
|
|
|
|
PMIntr26 endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; IntEntry2X -- This routine performs translations and
|
|
; buffering of Int 25h and 26h requests on entry.
|
|
;
|
|
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public IntEntry2X
|
|
|
|
IntEntry2X proc near
|
|
|
|
cmp [bp].intUserCX,-1 ;DOS 4.0 extended read/write?
|
|
jnz e2x_dsbx ; no, just go map DS:BX
|
|
|
|
mov ds,[bp].pmUserDS ; yes, copy down parameter blk
|
|
assume ds:NOTHING
|
|
mov si,[bp].pmUserBX
|
|
mov di,offset rgbXfrBuf0
|
|
cld
|
|
movsw ;32-bit sector #
|
|
movsw
|
|
movsw ;# sectors to read/write
|
|
|
|
mov ax,offset rgbXfrBuf1 ;replace pointer with addr of
|
|
stosw ; our own low buffer
|
|
mov ax,segDXDataPM ;segment, not selector
|
|
stosw
|
|
|
|
push es
|
|
pop ds
|
|
assume ds:DGROUP
|
|
|
|
mov [bp].intUserBX,offset rgbXfrBuf0
|
|
|
|
ret
|
|
|
|
e2x_dsbx: ;standard read/write, just redirect DS:BX
|
|
|
|
mov [bp].intUserBX,offset rgbXfrBuf1
|
|
|
|
ret
|
|
|
|
IntEntry2X endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; IntExit2X -- This routine performs translations and
|
|
; buffering of Int 25h and 26h requests on exit.
|
|
;
|
|
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public IntExit2X
|
|
|
|
IntExit2X proc near
|
|
|
|
|
|
mov ax,[bp].pmUserBX ;restore caller's BX
|
|
mov [bp].intUserBX,ax
|
|
|
|
ret
|
|
|
|
IntExit2X endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
subttl Disk Utility Routines
|
|
page
|
|
; -------------------------------------------------------
|
|
; DISK UTILITY ROUTINES
|
|
; -------------------------------------------------------
|
|
; ReadWriteSectors -- Common code to read/write disk sectors for
|
|
; Int 13h/25h/26h.
|
|
;
|
|
; In: lParam - seg:off of real mode interrupt handler
|
|
; wParam1 - int #, and possible subfunction
|
|
; regs on stack
|
|
|
|
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public ReadWriteSectors
|
|
|
|
ReadWriteSectors proc near
|
|
|
|
ifdef NEC_98 ;
|
|
pop [bp].wParam2 ;save return addr higher on stack
|
|
|
|
; Setup the global data items for the read/write--pointer to caller's
|
|
; buffer, # sectors to read/write, and sector size.
|
|
|
|
cmp byte ptr [bp].wParam1+1,1Bh ;Int 1Bh?
|
|
jz DISK_BIOS
|
|
jmp DOSReadWriteSectors
|
|
;;;;;;;; jmp rws_dos_size
|
|
|
|
DISK_BIOS:
|
|
;offset adress 90/07/12 change
|
|
mov ax,[bp].pmUserBP ;ES:BP points to caller's buf
|
|
mov word ptr lpSectorData,ax
|
|
mov ax,[bp].pmUserES
|
|
mov word ptr [lpSectorData+2],ax
|
|
|
|
;US:sector num, but :data length 90/07/13
|
|
|
|
;-------------------------- 90/07/23 in ---------------------------
|
|
; to adjust to US, we get a data with sense command on HDD,
|
|
; and set a data with 1MB/640KB on FDD.
|
|
;----------------------------------------------------------------------
|
|
mov al,byte ptr [bp].intUserAX ;
|
|
;
|
|
push ax
|
|
and al,10h ;DA:4th bit on :FDD
|
|
pop ax
|
|
jnz FDBIOS
|
|
|
|
mov ah,84h ;SENSE command
|
|
|
|
push ax
|
|
SwitchToRealMode
|
|
pop ax
|
|
|
|
pushf ;have BIOS get the drive data
|
|
call rglpfnRmISR[1Bh*4] ;90/07/04
|
|
|
|
mov sensedata1,bx ;sector length
|
|
mov sensedata2,cx ;cylinder
|
|
mov byte ptr sensedata3,dh ;DH = head
|
|
mov byte ptr sensedata4,dl ;DL = sector num
|
|
|
|
SwitchToProtectedMode
|
|
jmp SECTOR
|
|
|
|
|
|
FDBIOS:
|
|
|
|
push ax
|
|
mov cx,[bp].intUserCX ;sector size shift factor (0,1,2,3)
|
|
;;;;;;;; mov cl,byte ptr [bp].intUserCX ;sector size shift factor (0,1,2,3)
|
|
mov ax,128
|
|
xchg ch,cl
|
|
shl ax,cl ;ax now = sector size
|
|
mov cx,ax
|
|
mov sensedata1,cx ;sector length
|
|
pop ax
|
|
|
|
cmp al,90h ;1MB floppy disk,1MB/640KBdual modefloppy disk(1MB FD access)
|
|
jb fd640k
|
|
cmp al,93h
|
|
ja fd640k
|
|
|
|
;set the max value to the buffer with 1MBFD
|
|
mov sensedata2,77 ;cylinder
|
|
mov word ptr sensedata3,1 ;head
|
|
mov word ptr sensedata4,26 ;sector num
|
|
jmp SECTOR
|
|
|
|
fd640k:
|
|
cmp al,70h ;640KB floppy disk
|
|
jb @f
|
|
cmp al,73h
|
|
ja @f
|
|
mov sensedata2,79 ;cylinder
|
|
mov word ptr sensedata3,1 ;head
|
|
mov word ptr sensedata4,16 ;sector num
|
|
jmp SECTOR
|
|
@@:
|
|
cmp al,10h ;1MB/640KB dual modefloppy disk(640KB FD access)
|
|
jb @f
|
|
cmp al,13h
|
|
ja @f
|
|
mov sensedata2,79 ;cylinder
|
|
mov word ptr sensedata3,1 ;head
|
|
mov word ptr sensedata4,16 ;sector num
|
|
jmp SECTOR
|
|
@@:
|
|
cmp al,30h ;1.44MBfloppy disk '93 1/5 By S.Kurokawa
|
|
jb fdother
|
|
cmp al,33h
|
|
ja fdother
|
|
mov sensedata2,79 ;cylinder
|
|
mov word ptr sensedata3,1 ;head
|
|
mov word ptr sensedata4,18 ;sector num
|
|
jmp SECTOR
|
|
|
|
|
|
;------------------------ 90/07/23 ------------------------------
|
|
; for the media except for 1MB FD,640KB FD ::�i10MB FD�j
|
|
; we do not know that we can certainly issue a sense command
|
|
;--------------------------------------------------------------------
|
|
fdother:
|
|
mov ah,84h ;SENSE command
|
|
|
|
push ax
|
|
SwitchToRealMode
|
|
pop ax
|
|
|
|
pushf ;have BIOS get the drive data
|
|
call rglpfnRmISR[1Bh*4] ;90/07/04
|
|
|
|
mov sensedata1,bx ;sector length
|
|
mov sensedata2,cx ;cylinder
|
|
mov byte ptr sensedata3,dh ;DH = head
|
|
mov byte ptr sensedata4,dl ;DL = sector num
|
|
|
|
SwitchToProtectedMode
|
|
|
|
|
|
SECTOR:
|
|
push dx
|
|
xor dx,dx
|
|
mov cx,sensedata1 ;sector length
|
|
mov ax,[bp].intUserBX ;# sectors caller wants to
|
|
div cx
|
|
mov cSectorsToTransfer,ax ;bytes�^sector len��sector num
|
|
pop dx
|
|
|
|
;;;; mov cx,1 ;90/07/13
|
|
|
|
FSTI ;don't need them disabled
|
|
|
|
if DEBUG ;------------------------------------------------------------
|
|
|
|
cmp cx,512
|
|
jz @f
|
|
Debug_Out "Odd sector size = #CX"
|
|
@@:
|
|
|
|
endif ;DEBUG --------------------------------------------------------
|
|
|
|
; CX now has the drive's sector size. Determine how many sectors we can
|
|
; transfer at a time
|
|
|
|
rws_have_size:
|
|
|
|
mov cbSectorSize,cx ;save sector size for later
|
|
|
|
xor dx,dx
|
|
mov ax,CB_XFRBUF1 ;buf size / sector size = sectors per
|
|
div cx ; transfer
|
|
|
|
if DEBUG ;------------------------------------------------------------
|
|
or ax,ax
|
|
jnz @f
|
|
Debug_Out "Sectors per transfer = 0!"
|
|
@@:
|
|
endif ;DEBUG --------------------------------------------------------
|
|
|
|
mov cSectorsPerTransfer,ax
|
|
|
|
xor ax,ax
|
|
mov cSectorsTransfered,ax ;sectors transfered so far = 0
|
|
mov cSectorsThisTransfer,ax ;sectors transfered last time = 0
|
|
|
|
; Get/init a selector that we'll use to reference the caller's buffer.
|
|
|
|
mov ax,word ptr [lpSectorData+2] ;get lma of caller's buffer
|
|
call GetSegmentAddress
|
|
add dx,word ptr lpSectorData
|
|
adc bx,0
|
|
|
|
call AllocateSelector ;build a sel/dscr pointing
|
|
mov cx,0FFFFh
|
|
cCall NSetSegmentDscr,<ax,bx,dx,0,cx,STD_DATA>
|
|
xor bx,bx
|
|
mov word ptr lpSectorData,bx ;use that as the buffer ptr
|
|
mov word ptr [lpSectorData+2],ax
|
|
|
|
|
|
; ======================================================================
|
|
; Main sector read/write loop ------------------------------------------
|
|
; ======================================================================
|
|
|
|
rws_do_it_loop:
|
|
|
|
; Calculate how many sectors to transfer this time around, set starting
|
|
; sector number based on how many transfered last time.
|
|
|
|
; int 3 ;------ 90/11/08 debug ------
|
|
|
|
mov ax,cSectorsToTransfer ;total sector
|
|
sub ax,cSectorsTransfered ;total sector - transferred sector = remain
|
|
jnz @f
|
|
jmp rws_done
|
|
@@:
|
|
cmp ax,cSectorsPerTransfer ;buffer size / sector len = sectors in buffer
|
|
jna @f ;sectors in buffer > remain sectors = remain
|
|
mov ax,cSectorsPerTransfer ;sectors in buffer < remain = sectors in buffer
|
|
@@:
|
|
mov bx,cSectorsThisTransfer ;still # R/W from last loop
|
|
|
|
|
|
push [bp].pmUserAX ;the BIOS does not save
|
|
pop [bp].intUserAX ; registers across calls to
|
|
push [bp].pmUserCX ; it so if we're doing
|
|
pop [bp].intUserCX ; multiple calls to buffer
|
|
; push [bp].pmUserDX ; data, restore the initial
|
|
; pop [bp].intUserDX ; register values
|
|
|
|
; Previous two lines include bug. '93 1/15 Debugged by S.Kurokawa.
|
|
|
|
;in data transmits with a byte, so mov AX to BX 90/07/18
|
|
;;;; mov byte ptr [bp].intUserAX,al ;# sectors in AL = sectors
|
|
push ax ;90/11/08
|
|
xor ah,ah ;for calc a data len, ah=0 90/07/25
|
|
mov cx,cbSectorSize
|
|
mul cx ;sector num * sector len 90/07/25
|
|
mov [bp].intUserBX,ax ;# sectors in BX = data len
|
|
pop ax ;90/11/08
|
|
;;;; add byte ptr [bp].intUserCX,bl ;update new start sector in CL
|
|
add byte ptr [bp].intUserDX,bl ;update new start sector in DL = sector num�@90/07/13
|
|
|
|
|
|
rws_size_start_set:
|
|
|
|
; At this point, AX has the number of sectors to transfer. If this is a
|
|
; write, copy a buffer of data from the caller's buffer.
|
|
|
|
mov cSectorsThisTransfer,ax ;in case it's a read
|
|
;cSectorsThisTransfer = sectors in buffer or remained sectors
|
|
|
|
;----------------90/11/08 debug -------------------------------------
|
|
push ax
|
|
mov ax,[bp].wParam1 ;BIOS write?
|
|
and ax,0ff0fh
|
|
cmp ax,1B05h ;BIOS write?
|
|
pop ax
|
|
;----------------90/11/08 debug -------------------------------------
|
|
|
|
jnz rws_not_write
|
|
; call DBIOS_DEVICE
|
|
|
|
rws_buf_write:
|
|
|
|
mul cbSectorSize ;AX now = # bytes to transfer
|
|
mov cx,ax ;can safely assume < 64k
|
|
shr cx,1 ;# words to move
|
|
; lds si,lpSectorData
|
|
; assume ds:NOTHING
|
|
push ds
|
|
mov si,[bp].pmUserBP ;90/11/09
|
|
mov ds,[bp].pmUserES ;90/11/09
|
|
|
|
; mov di,offset rgbXfrBuf1
|
|
mov di,offset DGROUP:rgbXfrBuf1
|
|
cld
|
|
rep movsw
|
|
pop ds
|
|
|
|
push es
|
|
pop ds
|
|
assume ds:DGROUP
|
|
|
|
mov word ptr [bp].pmUserBP,si ;update src ptr for next time
|
|
; mov word ptr lpSectorData,si ;update src ptr for next time
|
|
; call NormalizeBufPtr ; and normalize it
|
|
|
|
|
|
rws_not_write:
|
|
|
|
;------------------------------------------------------------
|
|
push ax ;90/11/09
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
mov ax,segDXDataPM
|
|
; mov ax,[bp].pmUserES ;debug
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
mov [bp].intUserES,ax ;segment address
|
|
pop ax
|
|
mov [bp].intUserBP,offset DGROUP:rgbXfrBuf1
|
|
;------------------------------------------------------------
|
|
|
|
; Switch to real mode, do the transfer.
|
|
|
|
SwitchToRealMode
|
|
assume ds:DGROUP,es:DGROUP
|
|
|
|
push word ptr [bp].lParam
|
|
pop word ptr lpRmISR
|
|
push word ptr [bp].lParam+2
|
|
pop word ptr lpRmISR+2
|
|
|
|
pop es
|
|
pop ds
|
|
assume ds:NOTHING,es:NOTHING,ss:DGROUP
|
|
popa
|
|
call lpRmISR
|
|
pushf
|
|
FCLI
|
|
|
|
rws_save_regs:
|
|
|
|
pusha
|
|
push ds
|
|
push es
|
|
mov bp,sp ;restore stack frame pointer
|
|
|
|
SwitchToProtectedMode
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
|
|
FSTI ;allow HW interrupts
|
|
|
|
|
|
; If the call failed, then cut out now without further processing...
|
|
|
|
test byte ptr [bp].intUserFL,1 ;CY set?
|
|
jnz rws_done
|
|
|
|
; If this was a successful read, copy the data back to the caller.
|
|
|
|
;----------------90/11/08 debug -------------------------------------
|
|
push ax
|
|
mov ax,[bp].wParam1 ;BIOS write?
|
|
and ax,0ff0fh
|
|
cmp ax,1B06h ;BIOS write?
|
|
pop ax
|
|
;----------------90/11/08 debug -------------------------------------
|
|
jnz rws_not_read
|
|
; call DBIOS_DEVICE
|
|
|
|
rws_buf_read:
|
|
mov ax,cSectorsThisTransfer ;calc size of data to move
|
|
mul cbSectorSize
|
|
mov cx,ax
|
|
shr cx,1 ;in words
|
|
;;;;;;;; les di,lpSectorData ;caller's buffer pointer
|
|
;;;;;;;; assume es:NOTHING
|
|
push es
|
|
mov di,[bp].pmUserBP
|
|
mov es,[bp].pmUserES
|
|
mov si,offset DGROUP:rgbXfrBuf1
|
|
cld
|
|
rep movsw
|
|
pop es
|
|
|
|
push ds
|
|
pop es
|
|
assume es:DGROUP
|
|
|
|
mov word ptr [bp].pmUserBP,di ;update dest ptr for next time
|
|
; mov word ptr lpSectorData,di ;update dest ptr for next time
|
|
; call NormalizeBufPtr ; and normailize it
|
|
|
|
rws_not_read:
|
|
|
|
mov ax,cSectorsThisTransfer ;count total sectors transfered
|
|
add cSectorsTransfered,ax ;add sectors transmitted
|
|
;to previous sectors
|
|
;----------- 90/11/09 copy the segment address -------
|
|
push ax
|
|
mov ax,[bp].pmUserES ;90/09/19 BX regster restor
|
|
mov [bp].intUserES,ax
|
|
mov ax,[bp].pmUserBP
|
|
mov [bp].intUserBP,ax
|
|
pop ax
|
|
;------------------------------------------------------------
|
|
|
|
|
|
jmp rws_do_it_loop ;go do another buffer full
|
|
|
|
rws_done:
|
|
|
|
mov ax,word ptr [lpSectorData+2] ;release our temp buffer sel
|
|
call FreeSelector
|
|
|
|
jmp [bp].wParam2
|
|
else ;NEC_98 ;
|
|
pop [bp].wParam2 ;save return addr higher on stack
|
|
|
|
; Setup the global data items for the read/write--pointer to caller's
|
|
; buffer, # sectors to read/write, and sector size.
|
|
|
|
cmp byte ptr [bp].wParam1+1,13h ;Int 13h?
|
|
jnz rws_dos_size
|
|
|
|
mov ax,[bp].pmUserBX ;ES:BX points to caller's buf
|
|
mov word ptr lpSectorData,ax
|
|
mov ax,[bp].pmUserES
|
|
mov word ptr [lpSectorData+2],ax
|
|
|
|
mov al,byte ptr [bp].intUserAX ;# sectors caller wants to
|
|
xor ah,ah ; read or write
|
|
mov cSectorsToTransfer,ax
|
|
|
|
mov ah,08h ;get drive parameters
|
|
mov dx,[bp].intUserDX ; for drive in DL
|
|
|
|
push ax
|
|
SwitchToRealMode
|
|
pop ax
|
|
|
|
pushf ;have BIOS get the drive data
|
|
sub sp,8 ; make room for stack frame
|
|
push bp
|
|
mov bp,sp
|
|
push es
|
|
push ax
|
|
|
|
xor ax,ax
|
|
mov es,ax
|
|
mov [bp + 8],cs
|
|
mov [bp + 6],word ptr (offset rws_10)
|
|
mov ax,es:[13h*4]
|
|
mov [bp + 2],ax
|
|
mov ax,es:[13h*4 + 2]
|
|
mov [bp + 4],ax
|
|
pop ax
|
|
pop es
|
|
pop bp
|
|
retf
|
|
rws_10: jnc @f
|
|
|
|
mov cx,512 ;according to PS/2 tech ref, some
|
|
jmp short rws_to_pm ; old bios versions may fail this,
|
|
@@: ; just use 512 in that case
|
|
|
|
mov cl,es:[di+3] ;sector size shift factor (0,1,2,3)
|
|
mov ax,128
|
|
shl ax,cl ;ax now = sector size
|
|
mov cx,ax
|
|
|
|
rws_to_pm:
|
|
SwitchToProtectedMode
|
|
|
|
FSTI ;don't need them disabled
|
|
|
|
if DEBUG ;------------------------------------------------------------
|
|
|
|
cmp cx,512
|
|
jz @f
|
|
Debug_Out "Odd sector size = #CX"
|
|
@@:
|
|
|
|
endif ;DEBUG --------------------------------------------------------
|
|
|
|
jmp short rws_have_size
|
|
|
|
; Before DOS 4.0, CX was the # sectors to read/write. Starting with 4.0,
|
|
; if CX == -1, DS:BX points to a parameter block which contains the
|
|
; sector size at offset 4.
|
|
|
|
rws_dos_size:
|
|
|
|
mov cx,[bp].intUserCX ;caller's cs == -1?
|
|
inc cx
|
|
jcxz rws_dos_4
|
|
dec cx ; no, then cx has sector count
|
|
|
|
mov ax,[bp].pmUserBX ; and DS:BX points to buffer
|
|
mov word ptr lpSectorData,ax
|
|
mov ax,[bp].pmUserDS
|
|
mov word ptr [lpSectorData+2],ax
|
|
|
|
jmp short rws_dos_num_secs
|
|
|
|
rws_dos_4:
|
|
|
|
mov cx,word ptr rgbXfrBuf0+4 ; yes, get count from low param block
|
|
|
|
push ds ; and DS:BX points to param block
|
|
mov ds,[bp].pmUserDS ; which contains pointer to buffer
|
|
assume ds:NOTHING
|
|
mov bx,[bp].pmUserBX
|
|
mov ax,word ptr ds:[bx+6]
|
|
mov word ptr lpSectorData,ax
|
|
mov ax,word ptr ds:[bx+8]
|
|
mov word ptr [lpSectorData+2],ax
|
|
pop ds
|
|
assume DS:DGROUP
|
|
|
|
rws_dos_num_secs:
|
|
mov cSectorsToTransfer,cx ;number sectors to read/write
|
|
|
|
mov cx,512 ;I've been assured by a WINFILE developer
|
|
; that the Int 25/26 sector size will always
|
|
; be 512 bytes.
|
|
|
|
; CX now has the drive's sector size. Determine how many sectors we can
|
|
; transfer at a time
|
|
|
|
rws_have_size:
|
|
|
|
mov cbSectorSize,cx ;save sector size for later
|
|
|
|
xor dx,dx
|
|
mov ax,CB_XFRBUF1 ;buf size / sector size = sectors per
|
|
div cx ; transfer
|
|
|
|
if DEBUG ;------------------------------------------------------------
|
|
or ax,ax
|
|
jnz @f
|
|
Debug_Out "Sectors per transfer = 0!"
|
|
@@:
|
|
endif ;DEBUG --------------------------------------------------------
|
|
|
|
mov cSectorsPerTransfer,ax
|
|
|
|
xor ax,ax
|
|
mov cSectorsTransfered,ax ;sectors transfered so far = 0
|
|
mov cSectorsThisTransfer,ax ;sectors transfered last time = 0
|
|
|
|
; Get/init a selector that we'll use to reference the caller's buffer.
|
|
|
|
mov ax,word ptr [lpSectorData+2] ;get lma of caller's buffer
|
|
call GetSegmentAddress
|
|
add dx,word ptr lpSectorData
|
|
adc bx,0
|
|
|
|
call AllocateSelector ;build a sel/dscr pointing
|
|
mov cx,0FFFFh
|
|
cCall NSetSegmentDscr,<ax,bx,dx,0,cx,STD_DATA>
|
|
xor bx,bx
|
|
mov word ptr lpSectorData,bx ;use that as the buffer ptr
|
|
mov word ptr [lpSectorData+2],ax
|
|
|
|
|
|
; ======================================================================
|
|
; Main sector read/write loop ------------------------------------------
|
|
; ======================================================================
|
|
|
|
rws_do_it_loop:
|
|
|
|
; Calculate how many sectors to transfer this time around, set starting
|
|
; sector number based on how many transfered last time.
|
|
|
|
mov ax,cSectorsToTransfer
|
|
sub ax,cSectorsTransfered
|
|
jnz @f
|
|
jmp rws_done
|
|
@@:
|
|
cmp ax,cSectorsPerTransfer
|
|
jna @f
|
|
mov ax,cSectorsPerTransfer
|
|
@@:
|
|
mov bx,cSectorsThisTransfer ;STIll # R/W from last loop
|
|
|
|
cmp byte ptr [bp].wParam1+1,13h ;BIOS read/write?
|
|
jnz rws_use_dos_size
|
|
|
|
push [bp].pmUserAX ;the BIOS does not save
|
|
pop [bp].intUserAX ; registers across calls to
|
|
push [bp].pmUserCX ; it so if we're doing
|
|
pop [bp].intUserCX ; multiple calls to buffer
|
|
push [bp].pmUserDX ; data, restore the initial
|
|
pop [bp].intUserDX ; register values
|
|
|
|
mov byte ptr [bp].intUserAX,al ;# sectors in AL
|
|
|
|
add byte ptr [bp].intUserCX,bl ;update new start sector in CL
|
|
|
|
jmp short rws_size_start_set
|
|
|
|
rws_use_dos_size:
|
|
|
|
cmp [bp].intUserCX,0FFFFh ;normal or extended DOS?
|
|
jz rws_dos4_size
|
|
mov [bp].intUserCX,ax ; normal, # sectors in CX
|
|
|
|
add [bp].intUserDX,bx ; new start sector in DX
|
|
|
|
jmp short rws_size_start_set
|
|
|
|
rws_dos4_size:
|
|
|
|
mov word ptr rgbXfrBuf0+4,ax ; extended, # sectors & 32 bit
|
|
add word ptr rgbXfrBuf0,bx ; start sector in parameter
|
|
adc word ptr rgbXfrBuf0+2,0 ; block
|
|
|
|
rws_size_start_set:
|
|
|
|
; At this point, AX has the number of sectors to transfer. If this is a
|
|
; write, copy a buffer of data from the caller's buffer.
|
|
|
|
mov cSectorsThisTransfer,ax ;in case it's a read
|
|
|
|
cmp [bp].wParam1,1303h ;BIOS write?
|
|
jz rws_buf_write
|
|
cmp byte ptr [bp].wParam1+1,26h ;DOS write?
|
|
jnz rws_not_write
|
|
|
|
rws_buf_write:
|
|
|
|
mul cbSectorSize ;AX now = # bytes to transfer
|
|
mov cx,ax ;can safely assume < 64k
|
|
shr cx,1 ;# words to move
|
|
lds si,lpSectorData
|
|
assume ds:NOTHING
|
|
mov di,offset rgbXfrBuf1
|
|
cld
|
|
rep movsw
|
|
|
|
push es
|
|
pop ds
|
|
assume ds:DGROUP
|
|
|
|
mov word ptr lpSectorData,si ;update src ptr for next time
|
|
call NormalizeBufPtr ; and normalize it
|
|
|
|
rws_not_write:
|
|
|
|
|
|
; Switch to real mode, do the transfer.
|
|
|
|
SwitchToRealMode
|
|
assume ds:DGROUP,es:DGROUP
|
|
|
|
push word ptr [bp].lParam
|
|
pop word ptr lpRmISR
|
|
push word ptr [bp].lParam+2
|
|
pop word ptr lpRmISR+2
|
|
|
|
cmp byte ptr [bp].wParam1+1,13h
|
|
jnz rws_call_dos
|
|
|
|
pop es
|
|
pop ds
|
|
assume ds:NOTHING,es:NOTHING,ss:DGROUP
|
|
popa
|
|
call lpRmISR
|
|
pushf
|
|
FCLI
|
|
jmp short rws_save_regs
|
|
|
|
rws_call_dos:
|
|
pop es
|
|
pop ds
|
|
assume ds:NOTHING,es:NOTHING,ss:DGROUP
|
|
popa
|
|
call lpRmISR
|
|
pop word ptr lpRmISR ;int 25/26 leave flags on stack,
|
|
pushf ; pop them to nowhere
|
|
FCLI
|
|
|
|
rws_save_regs:
|
|
pusha
|
|
push ds
|
|
push es
|
|
mov bp,sp ;restore stack frame pointer
|
|
|
|
SwitchToProtectedMode
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
|
|
FSTI ;allow HW interrupts
|
|
|
|
; If the call failed, then cut out now without further processing...
|
|
|
|
test byte ptr [bp].intUserFL,1 ;CY set?
|
|
jnz rws_done
|
|
|
|
; If this was a successful read, copy the data back to the caller.
|
|
|
|
cmp [bp].wParam1,1302h ;BIOS read?
|
|
jz rws_buf_read
|
|
cmp byte ptr [bp].wParam1+1,25h ;DOS read?
|
|
jnz rws_not_read
|
|
|
|
rws_buf_read:
|
|
mov ax,cSectorsThisTransfer ;calc size of data to move
|
|
mul cbSectorSize
|
|
mov cx,ax
|
|
shr cx,1 ;in words
|
|
les di,lpSectorData ;caller's buffer pointer
|
|
assume es:NOTHING
|
|
mov si,offset rgbXfrBuf1
|
|
cld
|
|
rep movsw
|
|
|
|
push ds
|
|
pop es
|
|
assume es:DGROUP
|
|
|
|
mov word ptr lpSectorData,di ;update dest ptr for next time
|
|
call NormalizeBufPtr ; and normailize it
|
|
|
|
rws_not_read:
|
|
|
|
mov ax,cSectorsThisTransfer ;count total sectors transfered
|
|
add cSectorsTransfered,ax
|
|
|
|
jmp rws_do_it_loop ;go do another buffer full
|
|
|
|
rws_done:
|
|
|
|
mov ax,word ptr [lpSectorData+2] ;release our temp buffer sel
|
|
call FreeSelector
|
|
|
|
jmp [bp].wParam2
|
|
endif ;NEC_98 ;
|
|
|
|
ReadWriteSectors endp
|
|
|
|
|
|
ifdef NEC_98 ;
|
|
; -------------------------------------------------------
|
|
subttl Disk Utility Routines
|
|
page
|
|
; -------------------------------------------------------
|
|
; DISK UTILITY ROUTINES
|
|
; -------------------------------------------------------
|
|
; DOSReadWriteSectors -- Common code to read/write disk sectors for
|
|
; Int 13h/25h/26h.
|
|
;
|
|
; In: lParam - seg:off of real mode interrupt handler
|
|
; wParam1 - int #, and possible subfunction
|
|
; regs on stack
|
|
|
|
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public DOSReadWriteSectors
|
|
|
|
DOSReadWriteSectors proc near
|
|
|
|
; int 3 ;------ 90/11/08 debug ------
|
|
|
|
; pop [bp].wParam3 ;save return addr higher on stack
|
|
|
|
; Setup the global data items for the read/write--pointer to caller's
|
|
; buffer, # sectors to read/write, and sector size.
|
|
|
|
|
|
; Before DOS 4.0, CX was the # sectors to read/write. Starting with 4.0,
|
|
; if CX == -1, DS:BX points to a parameter block which contains the
|
|
; sector size at offset 4.
|
|
|
|
rws_dos_size:
|
|
|
|
mov cx,[bp].intUserCX ;caller's cs == -1?
|
|
inc cx
|
|
jcxz rws_dos_4
|
|
dec cx ; no, then cx has sector count
|
|
|
|
mov ax,[bp].pmUserBX ; and DS:BX points to buffer
|
|
mov word ptr lpSectorData,ax
|
|
mov ax,[bp].pmUserDS
|
|
mov word ptr [lpSectorData+2],ax
|
|
|
|
jmp short rws_dos_num_secs
|
|
|
|
rws_dos_4:
|
|
|
|
mov cx,word ptr rgbXfrBuf0+4 ; yes, get count from low param block
|
|
|
|
push ds ; and DS:BX points to param block
|
|
mov ds,[bp].pmUserDS ; which contains pointer to buffer
|
|
assume ds:NOTHING
|
|
mov bx,[bp].pmUserBX
|
|
mov ax,word ptr ds:[bx+6]
|
|
mov word ptr lpSectorData,ax
|
|
mov ax,word ptr ds:[bx+8]
|
|
mov word ptr [lpSectorData+2],ax
|
|
pop ds
|
|
assume DS:DGROUP
|
|
|
|
rws_dos_num_secs:
|
|
mov cSectorsToTransfer,cx ;number sectors to read/write
|
|
|
|
;
|
|
; We will need the sector size if we have to break up the transfer.
|
|
;
|
|
if 0
|
|
push ds
|
|
push bx
|
|
mov dl,byte ptr [bp].pmUserAX
|
|
inc dl
|
|
mov ah,1ch
|
|
assume DS:NOTHING
|
|
int 21h
|
|
pop bx
|
|
pop ds
|
|
assume DS:DGROUP
|
|
cmp al,0ffh
|
|
jne rws_have_size
|
|
;
|
|
; Call to DOS to get drive data failed, probably due to invalid
|
|
; drive number. Assume 512, let INT 25h/26h return the failure.
|
|
;
|
|
rws_use_default:
|
|
�@�@ mov cx,512
|
|
|
|
else
|
|
push bx
|
|
mov bl, byte ptr [bp].pmUserAX
|
|
inc bl
|
|
call GetSectorSize
|
|
pop bx
|
|
endif
|
|
|
|
; CX now has the drive's sector size. Determine how many sectors we can
|
|
; transfer at a time
|
|
|
|
DOS_rws_have_size:
|
|
|
|
mov cbSectorSize,cx ;save sector size for later
|
|
|
|
xor dx,dx
|
|
mov ax,CB_XFRBUF1 ;buf size / sector size = sectors per
|
|
div cx ; transfer
|
|
|
|
if DEBUG ;------------------------------------------------------------
|
|
or ax,ax
|
|
jnz @f
|
|
Debug_Out "Sectors per transfer = 0!"
|
|
@@:
|
|
endif ;DEBUG --------------------------------------------------------
|
|
|
|
mov cSectorsPerTransfer,ax
|
|
|
|
xor ax,ax
|
|
mov cSectorsTransfered,ax ;sectors transfered so far = 0
|
|
mov cSectorsThisTransfer,ax ;sectors transfered last time = 0
|
|
|
|
; Get/init a selector that we'll use to reference the caller's buffer.
|
|
|
|
mov ax,word ptr [lpSectorData+2] ;get lma of caller's buffer
|
|
call GetSegmentAddress
|
|
add dx,word ptr lpSectorData
|
|
adc bx,0
|
|
|
|
call AllocateSelector ;build a sel/dscr pointing
|
|
mov cx,0FFFFh
|
|
cCall NSetSegmentDscr,<ax,bx,dx,0,cx,STD_DATA>
|
|
xor bx,bx
|
|
mov word ptr lpSectorData,bx ;use that as the buffer ptr
|
|
mov word ptr [lpSectorData+2],ax
|
|
|
|
|
|
; ======================================================================
|
|
; Main sector read/write loop ------------------------------------------
|
|
; ======================================================================
|
|
|
|
DOS_rws_do_it_loop:
|
|
|
|
; Calculate how many sectors to transfer this time around, set starting
|
|
; sector number based on how many transfered last time.
|
|
|
|
; int 3 ;------ 90/11/08 debug ------
|
|
|
|
mov ax,cSectorsToTransfer ;totak sectors
|
|
sub ax,cSectorsTransfered ;total sectors - sectors transmitted = remaine sectors
|
|
jnz @f
|
|
jmp DOS_rws_done
|
|
@@:
|
|
cmp ax,cSectorsPerTransfer ;buffer size / sector len = sectors in buffer
|
|
jna @f ;sectors in buffer > remain = remain
|
|
mov ax,cSectorsPerTransfer ;sectors in buf < remain = sectors in buffer
|
|
@@:
|
|
mov bx,cSectorsThisTransfer ;still # R/W from last loop
|
|
|
|
rws_use_dos_size:
|
|
|
|
cmp [bp].intUserCX,0FFFFh ;normal or extended DOS?
|
|
jz rws_dos4_size
|
|
mov [bp].intUserCX,ax ; normal, # sectors in CX
|
|
|
|
add [bp].intUserDX,bx ; new start sector in DX
|
|
|
|
jmp short DOS_rws_size_start_set
|
|
|
|
rws_dos4_size:
|
|
|
|
mov word ptr rgbXfrBuf0+4,ax ; extended, # sectors & 32 bit
|
|
add word ptr rgbXfrBuf0,bx ; start sector in parameter
|
|
adc word ptr rgbXfrBuf0+2,0 ; block
|
|
|
|
DOS_rws_size_start_set:
|
|
|
|
; At this point, AX has the number of sectors to transfer. If this is a
|
|
; write, copy a buffer of data from the caller's buffer.
|
|
|
|
mov cSectorsThisTransfer,ax ;in case it's a read
|
|
;cSectorsThisTransfer = sectors in buffer or remain sectors
|
|
|
|
|
|
;----------------- 90/07/24 -----------------------------------------
|
|
cmp byte ptr [bp].wParam1+1,26h ;DOS write?
|
|
jz DOS_rws_buf_write
|
|
jmp DOS_rws_not_write
|
|
|
|
DOS_rws_buf_write:
|
|
|
|
mul cbSectorSize ;AX now = # bytes to transfer
|
|
mov cx,ax ;can safely assume < 64k
|
|
shr cx,1 ;# words to move
|
|
lds si,lpSectorData
|
|
assume ds:NOTHING
|
|
mov di,offset rgbXfrBuf1
|
|
cld
|
|
rep movsw
|
|
|
|
push es
|
|
pop ds
|
|
assume ds:DGROUP
|
|
|
|
mov word ptr lpSectorData,si ;update src ptr for next time
|
|
call NormalizeBufPtr ; and normalize it
|
|
|
|
DOS_rws_not_write:
|
|
|
|
|
|
; Switch to real mode, do the transfer.
|
|
|
|
SwitchToRealMode
|
|
assume ds:DGROUP,es:DGROUP
|
|
|
|
push word ptr [bp].lParam
|
|
pop word ptr lpRmISR
|
|
push word ptr [bp].lParam+2
|
|
pop word ptr lpRmISR+2
|
|
|
|
rws_call_dos:
|
|
pop es
|
|
pop ds
|
|
assume ds:NOTHING,es:NOTHING,ss:DGROUP
|
|
popa
|
|
pusha ; This trashes all registers
|
|
call lpRmISR
|
|
mov bp,sp
|
|
jnc @F ; If carry, AX = error code
|
|
mov [bp+14],ax
|
|
@@:
|
|
popa
|
|
pop word ptr lpRmISR ; int 25/26 leave flags on stack,
|
|
; pop them to nowhere
|
|
pushf
|
|
FCLI
|
|
|
|
DOS_rws_save_regs:
|
|
|
|
; int 3
|
|
|
|
pusha
|
|
push ds
|
|
push es
|
|
mov bp,sp ;restore stack frame pointer
|
|
|
|
SwitchToProtectedMode
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
|
|
FSTI ;allow HW interrupts
|
|
|
|
; If the call failed, then cut out now without further processing...
|
|
|
|
test byte ptr [bp].intUserFL,1 ;CY set?
|
|
jnz DOS_rws_done
|
|
|
|
; If this was a successful read, copy the data back to the caller.
|
|
|
|
;----------------- 90/07/23 -----------------------------------------
|
|
cmp byte ptr [bp].wParam1+1,25h ;DOS read?
|
|
jz DOS_rws_buf_read
|
|
jmp DOS_rws_not_read
|
|
|
|
DOS_rws_buf_read:
|
|
mov ax,cSectorsThisTransfer ;calc size of data to move
|
|
mul cbSectorSize
|
|
mov cx,ax
|
|
shr cx,1 ;in words
|
|
les di,lpSectorData ;caller's buffer pointer
|
|
assume es:NOTHING
|
|
mov si,offset rgbXfrBuf1
|
|
cld
|
|
rep movsw
|
|
|
|
push ds
|
|
pop es
|
|
assume es:DGROUP
|
|
|
|
mov word ptr lpSectorData,di ;update dest ptr for next time
|
|
call NormalizeBufPtr ; and normailize it
|
|
|
|
DOS_rws_not_read:
|
|
|
|
mov ax,cSectorsThisTransfer ;count total sectors transfered
|
|
add cSectorsTransfered,ax ;add sectors transmitted
|
|
;to previous sectors
|
|
|
|
jmp DOS_rws_do_it_loop ;go do another buffer full
|
|
|
|
DOS_rws_done:
|
|
|
|
mov ax,word ptr [lpSectorData+2] ;release our temp buffer sel
|
|
call FreeSelector
|
|
|
|
jmp [bp].wParam2
|
|
|
|
DOSReadWriteSectors endp
|
|
endif ;NEC_98 ;
|
|
|
|
; -------------------------------------------------------
|
|
|
|
|
|
; This routine 'normalizes' the far pointer in lpSectorData such that
|
|
; the selector/descriptor points to where the selector:offset currently
|
|
; points
|
|
|
|
assume ds:DGROUP,es:NOTHING
|
|
|
|
NormalizeBufPtr proc near
|
|
|
|
mov ax,word ptr [lpSectorData+2] ;get segment base address
|
|
call GetSegmentAddress
|
|
add dx,word ptr lpSectorData ;add in current offset
|
|
adc bx,0
|
|
call SetSegmentAddress ;make that the new seg base
|
|
xor bx,bx
|
|
mov word ptr lpSectorData,bx ; with a zero offset
|
|
|
|
ret
|
|
|
|
NormalizeBufPtr endp
|
|
|
|
ifdef NEC_98 ;
|
|
public GetSectorSize
|
|
GetSectorSize proc near
|
|
|
|
push ax
|
|
push bx
|
|
push dx
|
|
push ds
|
|
sub sp, 40h
|
|
mov dx, sp
|
|
push ss
|
|
pop ds
|
|
mov ax, 440Dh
|
|
mov cx, 0860h
|
|
int 21h
|
|
ifdef NEC_98
|
|
mov cx, 1024 ; if 440D doesn't work, 512 bytes!
|
|
else ;NEC_98
|
|
mov cx, 512 ; if 440D doesn't work, 512 bytes!
|
|
endif ;NEC_98
|
|
jc @F
|
|
mov bx, dx
|
|
mov cx, word ptr ds:[bx+7] ; bytes per sector first field
|
|
@@: add sp, 40h
|
|
pop ds ; in BPB at offset 7.
|
|
pop dx
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
|
|
GetSectorSize endp
|
|
|
|
;-------------------------- DBIOS_DEVICE --------------------------------
|
|
; for difference of cylinders, heads, sectors between all devices
|
|
; if reached at each max value, we change the cylinders, heads
|
|
; to have a READ/WRITE process
|
|
;------------------------------------------------------------------------
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public DBIOS_DEVICE
|
|
|
|
DBIOS_DEVICE proc near
|
|
|
|
mov ax,[bp].intUserDX ;DH = head num�CDL = sector num
|
|
cmp byte ptr sensedata4,al ;maximum sector num ?
|
|
jnz DBIOS_RET ;NO = JMP
|
|
cmp byte ptr sensedata3,ah ;maximum head num ?
|
|
jnz HEADINC ;NO = JMP
|
|
mov [bp].intUserDX,0 ;DH = head num�CDL = sector num 0
|
|
mov ax,[bp].intUserCX ;set the next cylinder
|
|
add al,1 ;
|
|
mov [bp].intUserCX,ax ;
|
|
DBIOS_RET:
|
|
ret ;
|
|
|
|
HEADINC:
|
|
add ah,1 ;increase head num
|
|
mov al,0 ;sector num 0
|
|
mov [bp].intUserDX,ax ;set
|
|
ret
|
|
|
|
DBIOS_DEVICE endp
|
|
endif ;NEC_98 ;
|
|
DXPMCODE ends
|
|
|
|
;****************************************************************
|
|
end
|