954 lines
29 KiB
NASM
954 lines
29 KiB
NASM
|
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
|
||
|
IFDEF ROM
|
||
|
include dxrom.inc
|
||
|
ENDIF
|
||
|
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
|
||
|
|
||
|
|
||
|
; -------------------------------------------------------
|
||
|
; DATA SEGMENT DEFINITIONS
|
||
|
; -------------------------------------------------------
|
||
|
|
||
|
DXDATA segment
|
||
|
|
||
|
extrn rgbXfrBuf0:BYTE
|
||
|
extrn rgbXfrBuf1:BYTE
|
||
|
extrn rglpfnRmISR:DWORD
|
||
|
|
||
|
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
|
||
|
|
||
|
lpRmISR dd ? ;real mode int service rtn to invoke
|
||
|
|
||
|
DXDATA ends
|
||
|
|
||
|
; -------------------------------------------------------
|
||
|
; CODE SEGMENT VARIABLES
|
||
|
; -------------------------------------------------------
|
||
|
|
||
|
DXCODE segment
|
||
|
|
||
|
DXCODE ends
|
||
|
|
||
|
|
||
|
DXPMCODE segment
|
||
|
|
||
|
IFNDEF ROM
|
||
|
extrn segDXDataPM:WORD
|
||
|
ENDIF
|
||
|
|
||
|
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
|
||
|
|
||
|
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
|
||
|
|
||
|
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
|
||
|
mov al,byte ptr [bp].intUserAX+1
|
||
|
mov [bp].wParam1,ax
|
||
|
|
||
|
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
|
||
|
|
||
|
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)
|
||
|
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
|
||
|
|
||
|
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
|
||
|
|
||
|
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
|
||
|
|
||
|
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
|
||
|
|
||
|
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
|
||
|
|
||
|
; 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
|
||
|
|
||
|
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
|
||
|
|
||
|
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
|
||
|
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
|
||
|
|
||
|
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
|
||
|
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
|
||
|
IFDEF ROM
|
||
|
GetPMDataSeg
|
||
|
ELSE
|
||
|
mov ax,segDXDataPM ;segment, not selector
|
||
|
ENDIF
|
||
|
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
|
||
|
|
||
|
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
|
||
|
|
||
|
ReadWriteSectors endp
|
||
|
|
||
|
|
||
|
; -------------------------------------------------------
|
||
|
|
||
|
|
||
|
; 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
|
||
|
|
||
|
DXPMCODE ends
|
||
|
|
||
|
;****************************************************************
|
||
|
end
|