1866 lines
59 KiB
NASM
1866 lines
59 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
|
||
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 ::<3A>i10MB FD<46>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<65>^sector len<65><6E>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<75>@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:
|
||
<EFBFBD>@<EFBFBD>@ 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<75>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<75>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
|