723 lines
22 KiB
NASM
723 lines
22 KiB
NASM
PAGE ,132
|
|
TITLE DXDMA.ASM -- Dos Extender DMA Services
|
|
|
|
; Copyright (c) Microsoft Corporation 1989-1991. All Rights Reserved.
|
|
|
|
;***********************************************************************
|
|
;
|
|
; DXDMA.ASM -- Dos Extender DMA Services
|
|
;
|
|
;-----------------------------------------------------------------------
|
|
;
|
|
; This module provides the protect mode DMA services for the 286 DOS
|
|
; Extender. It supports a subset of the services documented in
|
|
; "DMA Services for DOS Virtual 8086 and Protected Mode Environments"
|
|
; by Microsoft Corporation.
|
|
;
|
|
;-----------------------------------------------------------------------
|
|
;
|
|
; 12/06/89 jimmat Minor changes to reflect updates in DMA Service Spec.
|
|
; 11/01/89 jimmat Started.
|
|
;
|
|
;***********************************************************************
|
|
|
|
.286p
|
|
|
|
; -------------------------------------------------------
|
|
; INCLUDE FILE DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
.xlist
|
|
.sall
|
|
include segdefs.inc
|
|
include gendefs.inc
|
|
include pmdefs.inc
|
|
include interupt.inc
|
|
if VCPI
|
|
include dxvcpi.inc
|
|
endif
|
|
.list
|
|
|
|
; -------------------------------------------------------
|
|
; GENERAL SYMBOL DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
PhysicalPageSize equ 4096 ;size of 80386 physical page
|
|
PageShift equ 12
|
|
|
|
DMAServiceByte equ 7Bh
|
|
|
|
ChainReserved equ 08h ;set if unsupported services chained
|
|
|
|
DMAServiceID equ 81h ;Int 4Bh/AH=81h are the DMA services
|
|
FirstValidSvc equ 02h ;First valid DMA service #
|
|
LastValidSvc equ 0Ch ;Last valid DMA service #
|
|
|
|
; Get Version information
|
|
|
|
MajorVersion equ 01h ;Major specification version
|
|
MinorVersion equ 00h ;Minor specification version
|
|
|
|
DOSXProductNumber equ 02h ;286 DOS Extender product number
|
|
DOSXProductRevision equ 01h ;286 DOS Extender revision number
|
|
|
|
MemoryContiguous equ 08h ;All memory physically contigious flag
|
|
AutoRemapSupported equ 04h ;Automatic remap supported
|
|
|
|
; DX flags on calls to DMA services
|
|
|
|
AutoBufferCopy equ 02h ;set if data to be copied into DMA buf
|
|
NoAutoBufferAlloc equ 04h ;set if NO automatic buff allocation
|
|
NoAutoRemap equ 08h ;set if NO automatic remap attempted
|
|
Align64k equ 10h ;set if region can't cross 64k boundry
|
|
Align128k equ 20h ;set if region can't cross 128k boundry
|
|
PageTableFmt equ 40h ;set for page table Scatter/Gather lock
|
|
|
|
ValidDXFlags equ 007Eh ;valid DX register flag bits (above)
|
|
|
|
; Error return codes
|
|
|
|
ErrRegionCrossedBoundry equ 02h
|
|
ErrNoBufferAvail equ 04h
|
|
ErrTooManyRegions equ 09h
|
|
ErrInvalidBufferID equ 0Ah
|
|
ErrFuncNotSupported equ 0Fh
|
|
ErrReservedFlagBits equ 10h
|
|
|
|
; DMA Descriptor Structure(s)
|
|
|
|
DDS STRUC ;normal DDS
|
|
DDS_RegionSize dd ?
|
|
DDS_Offset dd ?
|
|
DDS_Selector dw ?
|
|
DDS_BufferID dw ?
|
|
DDS_PhyAddress dd ?
|
|
DDS ENDS
|
|
|
|
SGDDS1 STRUC ;Extended DDS for Scatter/Gather
|
|
dd 3 dup (?) ; Region format
|
|
DDS_NumAvail dw ?
|
|
DDS_NumUsed dw ?
|
|
DDS_Region0Addr dd ?
|
|
DDS_Region0Size dd ?
|
|
SGDDS1 ENDS
|
|
|
|
SGDDS2 STRUC ;Extended DDS for Scatter/Gather
|
|
dd 4 dup (?) ; Page Table format
|
|
DDS_PageTblEnt0 dd ?
|
|
SGDDS2 ENDS
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; EXTERNAL SYMBOL DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
extrn EnterIntHandler:NEAR
|
|
extrn LeaveIntHandler:NEAR
|
|
extrn GetSegmentAddress:NEAR
|
|
extrn PMIntrEntryVector:NEAR
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; DATA SEGMENT DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
DXDATA segment
|
|
ifdef NEC_98
|
|
extrn fPCH98:BYTE
|
|
else ;!NEC_98
|
|
ifdef NOT_NTVDM_NOT
|
|
extrn fMicroChannel:BYTE
|
|
endif
|
|
endif ;!NEC_98
|
|
|
|
if VCPI
|
|
extrn fVCPI:BYTE
|
|
endif
|
|
;
|
|
; Contains a copy of bit 5 of the byte at 40:7b, that indicates
|
|
; whether VDS should be used.
|
|
;
|
|
public bDMAServiceBit
|
|
bDMAServiceBit db 0
|
|
|
|
DXDATA ends
|
|
|
|
; -------------------------------------------------------
|
|
; CODE SEGMENT VARIABLES
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE segment
|
|
|
|
DXCODE ends
|
|
|
|
DXPMCODE segment
|
|
|
|
extrn selDgroupPM:WORD
|
|
|
|
DMASvcTbl label word
|
|
|
|
dw offset DXPMCODE:GetVersion
|
|
dw offset DXPMCODE:LockDMARegion
|
|
dw offset DXPMCODE:DoNothing ;UnlockDMARegion
|
|
dw offset DXPMCODE:ScatterGatherLock
|
|
dw offset DXPMCODE:DoNothing ;ScatterGatherUnlock
|
|
dw offset DXPMCODE:Fail4NoBuffer ;RequestDMABuffer
|
|
dw offset DXPMCODE:DoNothing ;ReleaseDMABuffer
|
|
dw offset DXPMCODE:Fail4BufferID ;CopyIntoDMABuffer
|
|
dw offset DXPMCODE:Fail4BufferID ;CopyOutOfDMABuffer
|
|
dw offset DXPMCODE:DoNothing ;DisableDMATranslation
|
|
dw offset DXPMCODE:DoNothing ;EnableDMATranalation
|
|
|
|
DXPMCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
subttl DMA Service Dispatcher
|
|
page
|
|
; -------------------------------------------------------
|
|
; DMA SERVICE DISPATCHER
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE segment
|
|
assume cs:DXPMCODE
|
|
|
|
; -------------------------------------------------------
|
|
; PMIntr4B -- Entry routine/dispatcher for protected mode DMA
|
|
; services. The DMA services are invoked with an Int 4Bh
|
|
; interrupt. The 286 DOS Extender only supports the DMA
|
|
; services in protected mode. Other systems that use Virtual
|
|
; 8086 mode on 386 processors will most likely need to support
|
|
; the services in virtual mode also.
|
|
;
|
|
; The following services are supported (Int 4Bh/AH = 81h):
|
|
;
|
|
; AL = 00 Reserved
|
|
; 01 Reserved
|
|
; 02 Get Version
|
|
; 03 Lock DMA Region
|
|
; 04 Unlock DMA Region
|
|
; 05 Scatter/Gather Lock Region
|
|
; 06 Scatter/Gather Unlock Region
|
|
; 07 Request DMA Buffer
|
|
; 08 Release DMA Buffer
|
|
; 09 Copy Into DMA Buffer
|
|
; 0A Copy Out Of DMA Buffer
|
|
; 0B Disable DMA Translation
|
|
; 0C Enable DMA Translation
|
|
; 0D Reserved
|
|
; ...
|
|
; FF Reserved
|
|
|
|
public PMIntr4B
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
|
|
PMIntr4B proc near
|
|
|
|
; Is this one of the supported DMA services?
|
|
|
|
cmp ah,DMAServiceID ;is this a DMA service request?
|
|
jz @f
|
|
jmp short i4b_other_service ; no, see if it should be chained
|
|
@@:
|
|
call EnterIntHandler ;saves regs, switches stacks, etc.
|
|
assume ds:DGROUP ;sets DS/ES = DGROUP
|
|
mov es,[bp].pmUserES ; but we want caller's ES
|
|
|
|
cld ;cya...
|
|
|
|
cmp al,FirstValidSvc
|
|
jb i4b_reserved
|
|
|
|
cmp al,LastValidSvc
|
|
ja i4b_reserved
|
|
|
|
test dx,NOT ValidDXFlags ;any reserved flags set?
|
|
jnz i4b_bad_flags
|
|
|
|
; -------------------------------------------------------
|
|
|
|
; Setup local environment and dispatch the service
|
|
|
|
i4b_valid_svc:
|
|
|
|
push offset DXPMCODE:i4b_svc_ret ;save dispatch return address
|
|
|
|
sub al,FirstValidSvc ;get address of service routine
|
|
cbw
|
|
shl ax,1
|
|
add ax,offset DXPMCODE:DMASvcTbl
|
|
|
|
xchg ax,bx
|
|
mov bx,cs:[bx]
|
|
xchg ax,bx
|
|
|
|
push ax ;save routine address on stack
|
|
mov ax,[bp].pmUserAX ;restore entry AX
|
|
|
|
ret ;invoke service routine
|
|
|
|
i4b_svc_ret: ;service routines return here
|
|
|
|
jnc i4b_good_return ;CY set if service failed
|
|
|
|
i4b_error_return:
|
|
|
|
or byte ptr [bp].intUserFL,1 ;set CY in caller's flags
|
|
jmp short i4b_exit
|
|
|
|
i4b_good_return:
|
|
|
|
and byte ptr [bp].intUserFL,not 1 ;clear CY in caller's flags
|
|
|
|
i4b_exit:
|
|
|
|
call LeaveIntHandler ;resotre stack, regs, etc.
|
|
iret
|
|
|
|
; -------------------------------------------------------
|
|
|
|
; Reserved DMA service 00, 01, 0D-FF; return with CY set and
|
|
; AL = ErrFuncNotSupported
|
|
|
|
i4b_reserved:
|
|
|
|
mov byte ptr [bp].intUserAX,ErrFuncNotSupported
|
|
jmp short i4b_error_return
|
|
|
|
; -------------------------------------------------------
|
|
|
|
; User made a DMA service call with a reserved flag bit set. Fail the
|
|
; call with AL = ErrReservedFlagBits
|
|
|
|
i4b_bad_flags:
|
|
|
|
mov byte ptr [bp].intUserAX,ErrReservedFlagBits
|
|
jmp short i4b_error_return
|
|
|
|
; -------------------------------------------------------
|
|
|
|
; This is a non-DMA Int 4B call. On Micro Channel systems, bit 3
|
|
; in location 40:007B indicates if we should chain the call along
|
|
; or not. If the bit is set, we chain. If not Micro Channel, or the
|
|
; bit is not set, we check the real mode Int 4Bh vector to see if someone
|
|
; other than the BIOS has it hooked--if so, we chain anyway. If not,
|
|
; return without changing any regs or flags.
|
|
|
|
i4b_other_service:
|
|
|
|
push ds
|
|
|
|
mov ds,selDgroupPM
|
|
assume ds:DGROUP
|
|
|
|
ifdef NOT_NTVDM_NOT
|
|
ifdef NEC_98
|
|
test fPCH98,0FFh
|
|
else ;!NEC_98
|
|
test fMicroChannel,0FFh ;if micro channel system
|
|
endif ;!NEC_98
|
|
jz i4b_check_vector ; and 40:7B bit 3 set,
|
|
; chain the call to real mode
|
|
push SEL_BIOSDATA or STD_RING
|
|
pop ds
|
|
assume ds:NOTHING
|
|
|
|
test byte ptr ds:DMAServiceByte,ChainReserved
|
|
jnz i4b_chain
|
|
endif
|
|
|
|
i4b_check_vector: ;not micro channel, or bit 3 not set
|
|
|
|
push ax ;check if the real mode Int 4Bh
|
|
mov ax,SEL_RMIVT or STD_RING ; points somewhere and not
|
|
mov ds,ax ; at the BIOS--if so, chain
|
|
mov ax,word ptr ds:[4Bh*4] ; anyway.
|
|
or ax,word ptr ds:[4Bh*4+2]
|
|
pop ax
|
|
jz i4b_dont_chain
|
|
|
|
cmp word ptr ds:[4bh*4+2],0E000h
|
|
jz i4b_dont_chain
|
|
|
|
cmp word ptr ds:[4bh*4+2],0F000h
|
|
jz i4b_dont_chain
|
|
|
|
i4b_chain:
|
|
|
|
pop ds ;chain the request to real mode
|
|
jmp PMIntrEntryVector + 5*4Bh ; (no one can have pMode
|
|
; hooked before us)
|
|
|
|
i4b_dont_chain: ;don't chain the interrupt,
|
|
; just return quietly
|
|
pop ds
|
|
iret
|
|
|
|
PMIntr4B endp
|
|
|
|
; -------------------------------------------------------
|
|
subttl DMA Service Routines
|
|
page
|
|
; -------------------------------------------------------
|
|
; DMA SERVICE ROUTINES
|
|
; -------------------------------------------------------
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; RM4B -- Call the real mode INT 4Bh handler to
|
|
; perform a DMA service, most likely something to
|
|
; do with the VCPI provider's buffer when we are
|
|
; running under VCPI.
|
|
;
|
|
; Input: depends on call
|
|
; Output: Flags, registers from real mode call
|
|
;
|
|
; Notes: This is strictly an internal DOSX call,
|
|
; so if a long pointer is used, then it
|
|
; is assumed to point into DOSX's data
|
|
; segment.
|
|
;
|
|
cProc RM4B,<NEAR,PUBLIC>
|
|
cBegin
|
|
pushf
|
|
push cs
|
|
call near ptr PMIntrEntryVector + 3*4Bh
|
|
cEnd
|
|
|
|
; -------------------------------------------------------
|
|
; DoNothing -- This routine does nothing other than return
|
|
; indicating that the DMA service succeeded.
|
|
;
|
|
; Input: none
|
|
; Output: AL = 0, CY clear
|
|
|
|
assume ds:DGROUP,es:NOTHING,ss:NOTHING
|
|
|
|
DoNothing proc near
|
|
|
|
clc ;indicate success
|
|
ret
|
|
|
|
DoNothing endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; Fail4BufferID -- This routine does nothing other than return
|
|
; indicating that the DMA service failed with 'Invalid Buffer ID'
|
|
;
|
|
; Input: none
|
|
; Output: AL = 0Ah, CY set
|
|
|
|
assume ds:DGROUP,es:NOTHING,ss:NOTHING
|
|
|
|
Fail4BufferID proc near
|
|
|
|
mov byte ptr [bp].intUserAX,ErrInvalidBufferID
|
|
stc
|
|
ret
|
|
|
|
Fail4BufferID endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; Fail4NoBuffer -- This routine does nothing other than return
|
|
; indicating that the DMA service failed with 'No Buffer Available'
|
|
;
|
|
; Input: none
|
|
; Output: AL = 04h, CY set
|
|
|
|
assume ds:DGROUP,es:NOTHING,ss:NOTHING
|
|
|
|
Fail4NoBuffer proc near
|
|
|
|
mov byte ptr [bp].intUserAX,ErrNoBufferAvail
|
|
stc
|
|
ret
|
|
|
|
Fail4NoBuffer endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; GetVersion -- This routine processes the DMA Get Version
|
|
; service (AL = 02).
|
|
;
|
|
; Input: none
|
|
; Output: AH/AL - Major/Minor specification level
|
|
; BX - Product number
|
|
; CX - Product revision number
|
|
; DX - flags
|
|
; SI:DI - 32 bit max buffer size available
|
|
|
|
assume ds:DGROUP,es:NOTHING,ss:NOTHING
|
|
|
|
GetVersion proc near
|
|
|
|
mov [bp].intUserAX,(MajorVersion shl 8) or MinorVersion
|
|
mov [bp].intUserBX,DOSXProductNumber
|
|
mov [bp].intUserCX,DOSXProductRevision
|
|
mov [bp].intUserDX,MemoryContiguous
|
|
|
|
|
|
xor ax,ax ;0 buffer size supported, also clears
|
|
mov [bp].intUserSI,ax ; carry flag
|
|
mov [bp].intUserDI,ax
|
|
|
|
if VCPI
|
|
cmp fVCPI,0
|
|
je gv_x
|
|
mov ax,8102h
|
|
xor dx,dx ;DX = 0
|
|
cmp bDMAServiceBit,0 ;VCPI provider supports VDS?
|
|
je gv_e
|
|
call RM4B
|
|
jc gv_x
|
|
mov [bp].intUserSI,si
|
|
mov [bp].intUserDI,di
|
|
and dx,NOT (AutoRemapSupported or MemoryContiguous)
|
|
gv_e:
|
|
mov [bp].intUserDX,dx
|
|
gv_x:
|
|
endif
|
|
ret
|
|
|
|
GetVersion endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; LockDMARegion -- This routine processes the Lock DMA Region
|
|
; service (AL = 03).
|
|
;
|
|
; Input: DX - flags
|
|
; ES:DI - ptr to DDS
|
|
; Output: if successful, CY clear; else CY set and AL = error code
|
|
; DDS updated
|
|
|
|
assume ds:DGROUP,es:NOTHING,ss:NOTHING
|
|
|
|
LockDMARegion proc near
|
|
|
|
; Since we don't support paging or anything interesting like that, the only
|
|
; thing that can fail us is an alignment problem--check for that.
|
|
|
|
test dl,Align64k or Align128k ;if they don't care,
|
|
jz lock_ok ; we don't care
|
|
|
|
mov si,dx ;save flags in SI
|
|
|
|
call CalcDDSPhyAddress ;see where the region is
|
|
|
|
push dx ;save start address
|
|
push ax
|
|
|
|
mov bx,dx ;bx = hi word start addr
|
|
|
|
add ax,word ptr es:[di].DDS_RegionSize ;see where it ends
|
|
adc dx,word ptr es:[di].DDS_RegionSize+2
|
|
|
|
sub ax,1 ;less 1 to point at
|
|
sbb dx,0 ; last byte, not next
|
|
|
|
mov cx,dx ;cx = hi word end addr
|
|
|
|
test si,Align128k ;64k or 128k alignment wanted?
|
|
jz @f ; already setup for 64k
|
|
and bl,not 1 ;mask to 128k alignment
|
|
and cl,not 1
|
|
@@:
|
|
cmp bx,cx ;within the boundry?
|
|
jz lock_ok_clr_stk ; yes, 'lock' it
|
|
|
|
; The region crosses an alignment boundary, we need to update the allowed
|
|
; region size in the DDS, and fail the call.
|
|
|
|
pop cx
|
|
pop dx ;dx:cx = region start address
|
|
|
|
neg cx ;cx = len to next 64k boundry
|
|
xor bx,bx
|
|
test si,Align128k
|
|
jz @f
|
|
mov bl,dl
|
|
and bl,1
|
|
xor bl,1 ;bx:cx = len to next alignment boundry
|
|
@@:
|
|
mov word ptr es:[di].DDS_RegionSize,cx ;update size in DDS
|
|
mov word ptr es:[di].DDS_RegionSize+2,bx
|
|
|
|
mov byte ptr [bp].intUserAX,ErrRegionCrossedBoundry ;flag failure
|
|
stc
|
|
ret
|
|
|
|
|
|
lock_ok_clr_stk:
|
|
|
|
add sp,4 ;clear start address from stack
|
|
|
|
; No alignment problem, we can 'lock' the region.
|
|
|
|
lock_ok:
|
|
|
|
call CalcDDSPhyAddress ;get physical address of region DX:AX
|
|
mov word ptr es:[di].DDS_PhyAddress,ax
|
|
mov word ptr es:[di].DDS_PhyAddress+2,dx
|
|
|
|
xor ax,ax ;*** also clears CY! ***
|
|
mov es:[di].DDS_BufferID,ax ;no buffer used
|
|
|
|
ret
|
|
|
|
LockDMARegion endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; ScatterGatterLock -- This routine implements the Scatter/Gather
|
|
; Lock Region DMA service (AL = 05h).
|
|
;
|
|
; Input: DX - flags
|
|
; ES:DI - ptr to extended DDS
|
|
; Output: if successful, CY clear; else CY set & AL = error code
|
|
; DDS updated
|
|
|
|
assume ds:DGROUP,es:NOTHING,ss:NOTHING
|
|
|
|
ScatterGatherLock proc near
|
|
|
|
test dl,PageTableFmt ;Scatter/Gather page table form?
|
|
jnz do_page_tbl_lock
|
|
|
|
; This is the region form of Scatter/Gather Lock Region -- for us this
|
|
; is easy, since memory is contiguous -- one region covers the entire area.
|
|
|
|
mov ax,1 ;we need one region entry
|
|
mov es:[di].DDS_NumUsed,ax
|
|
|
|
cmp es:[di].DDS_NumAvail,ax ; is it available?
|
|
jb not_enough_entries
|
|
|
|
call CalcDDSPhyAddress ;get physical address
|
|
|
|
mov word ptr es:[di].DDS_Region0Addr,ax ;store in extended DDS
|
|
mov word ptr es:[di].DDS_Region0Addr+2,dx
|
|
|
|
mov ax,word ptr es:[di].DDS_RegionSize ;copy over the size
|
|
mov word ptr es:[di].DDS_Region0Size,ax
|
|
mov ax,word ptr es:[di].DDS_RegionSize+2
|
|
mov word ptr es:[di].DDS_Region0Size+2,ax
|
|
|
|
clc ;indicate success
|
|
ret
|
|
|
|
; This is the page table form of Scatter/Gather Lock Region -- we need to
|
|
; build a fake page table (even though we may be on an 80286!?) to return
|
|
; in the extended DDS.
|
|
|
|
do_page_tbl_lock:
|
|
|
|
call CalcDDSPhyAddress ;get region start address
|
|
|
|
mov cx,word ptr es:[di].DDS_RegionSize ;calc # pages needed
|
|
mov bx,word ptr es:[di].DDS_RegionSize+2 ; for region of this
|
|
add cx,PhysicalPageSize-1 ; size
|
|
adc bx,0
|
|
shr cx,PageShift
|
|
shl bx,16-PageShift
|
|
or cx,bx ;cx = # pages
|
|
|
|
test ax,PhysicalPageSize-1 ;if region doesn't start on a page
|
|
jz @f ; boundry, add another page to
|
|
inc cx ; the region size
|
|
@@:
|
|
mov es:[di].DDS_NumUsed,cx ;tell caller how many used/needed
|
|
cmp es:[di].DDS_NumAvail,cx ;did caller supply enough page entries?
|
|
jb not_enough_entries ; no!
|
|
|
|
push ax ;save low word of region start address
|
|
|
|
and ax,NOT PhysicalPageSize-1 ;round down to page boundry
|
|
or al,1 ;set page present/locked bit
|
|
mov bx,di ;es:bx -> page table entries
|
|
|
|
jcxz page_ents_done ;better safe than sorry
|
|
@@:
|
|
mov word ptr es:[bx].DDS_PageTblEnt0,ax ;build fake page
|
|
mov word ptr es:[bx].DDS_PageTblEnt0+2,dx ; table entries...
|
|
add ax,PhysicalPageSize
|
|
adc dx,0
|
|
add bx,4
|
|
loop @b
|
|
|
|
page_ents_done:
|
|
|
|
pop ax ;recover low word of start address
|
|
and ax,PhysicalPageSize-1 ; and get offset into first page
|
|
mov [bp].intUserBX,ax ; return to caller in BX
|
|
|
|
clc ;indicate success
|
|
ret
|
|
|
|
; Fail the request for insufficient # of region/page tbl entries
|
|
|
|
not_enough_entries:
|
|
|
|
mov byte ptr [bp].intUserAX,ErrTooManyRegions ;AL = error code
|
|
|
|
mov ax,es:[di].DDS_NumAvail ;store max lockable
|
|
mov dx,ax ; size (bytes) in
|
|
shl ax,PageShift ; DDS region size
|
|
shr dx,16-PageShift
|
|
mov word ptr es:[di].DDS_RegionSize,ax
|
|
mov word ptr es:[di].DDS_RegionSize+2,dx
|
|
|
|
stc ;indicate failure
|
|
ret
|
|
|
|
|
|
ScatterGatherLock endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
subttl DMA Service Utility Routines
|
|
page
|
|
; -------------------------------------------------------
|
|
; DMA SERVICE UTILITY ROUTINES
|
|
; -------------------------------------------------------
|
|
|
|
; -------------------------------------------------------
|
|
; CalcDDSPhyAddress -- This routine calculates the physical
|
|
; address of the region specified in a DDS.
|
|
;
|
|
; Input: ES:DI - ptr to DDS
|
|
; Output: DX:AX - 32 bit physical address
|
|
; Uses: none.
|
|
|
|
assume ds:DGROUP,es:NOTHING,ss:NOTHING
|
|
|
|
CalcDDSPhyAddress proc near
|
|
|
|
push bx
|
|
xor bx,bx
|
|
mov dx,bx
|
|
|
|
mov ax,es:[di.DDS_Selector] ;if a selector is given,
|
|
or ax,ax ; get it's base address
|
|
jz @f
|
|
|
|
call GetSegmentAddress ;bx:dx = segment base
|
|
@@:
|
|
add dx,word ptr es:[di.DDS_Offset] ;add 32 bit offset
|
|
adc bx,word ptr es:[di.DDS_Offset+2]
|
|
|
|
mov ax,dx ;32 bit address to dx:ax
|
|
mov dx,bx
|
|
pop bx
|
|
|
|
ret
|
|
|
|
CalcDDSPhyAddress endp
|
|
|
|
|
|
DXPMCODE ends
|
|
|
|
;****************************************************************
|
|
end
|