windows-nt/Source/XPSP1/NT/base/mvdm/dpmi/dxdisk.asm

1866 lines
59 KiB
NASM
Raw Normal View History

2020-09-26 03:20:57 -05:00
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