Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

722 lines
22 KiB

  1. PAGE ,132
  2. TITLE DXDMA.ASM -- Dos Extender DMA Services
  3. ; Copyright (c) Microsoft Corporation 1989-1991. All Rights Reserved.
  4. ;***********************************************************************
  5. ;
  6. ; DXDMA.ASM -- Dos Extender DMA Services
  7. ;
  8. ;-----------------------------------------------------------------------
  9. ;
  10. ; This module provides the protect mode DMA services for the 286 DOS
  11. ; Extender. It supports a subset of the services documented in
  12. ; "DMA Services for DOS Virtual 8086 and Protected Mode Environments"
  13. ; by Microsoft Corporation.
  14. ;
  15. ;-----------------------------------------------------------------------
  16. ;
  17. ; 12/06/89 jimmat Minor changes to reflect updates in DMA Service Spec.
  18. ; 11/01/89 jimmat Started.
  19. ;
  20. ;***********************************************************************
  21. .286p
  22. ; -------------------------------------------------------
  23. ; INCLUDE FILE DEFINITIONS
  24. ; -------------------------------------------------------
  25. .xlist
  26. .sall
  27. include segdefs.inc
  28. include gendefs.inc
  29. include pmdefs.inc
  30. include interupt.inc
  31. if VCPI
  32. include dxvcpi.inc
  33. endif
  34. .list
  35. ; -------------------------------------------------------
  36. ; GENERAL SYMBOL DEFINITIONS
  37. ; -------------------------------------------------------
  38. PhysicalPageSize equ 4096 ;size of 80386 physical page
  39. PageShift equ 12
  40. DMAServiceByte equ 7Bh
  41. ChainReserved equ 08h ;set if unsupported services chained
  42. DMAServiceID equ 81h ;Int 4Bh/AH=81h are the DMA services
  43. FirstValidSvc equ 02h ;First valid DMA service #
  44. LastValidSvc equ 0Ch ;Last valid DMA service #
  45. ; Get Version information
  46. MajorVersion equ 01h ;Major specification version
  47. MinorVersion equ 00h ;Minor specification version
  48. DOSXProductNumber equ 02h ;286 DOS Extender product number
  49. DOSXProductRevision equ 01h ;286 DOS Extender revision number
  50. MemoryContiguous equ 08h ;All memory physically contigious flag
  51. AutoRemapSupported equ 04h ;Automatic remap supported
  52. ; DX flags on calls to DMA services
  53. AutoBufferCopy equ 02h ;set if data to be copied into DMA buf
  54. NoAutoBufferAlloc equ 04h ;set if NO automatic buff allocation
  55. NoAutoRemap equ 08h ;set if NO automatic remap attempted
  56. Align64k equ 10h ;set if region can't cross 64k boundry
  57. Align128k equ 20h ;set if region can't cross 128k boundry
  58. PageTableFmt equ 40h ;set for page table Scatter/Gather lock
  59. ValidDXFlags equ 007Eh ;valid DX register flag bits (above)
  60. ; Error return codes
  61. ErrRegionCrossedBoundry equ 02h
  62. ErrNoBufferAvail equ 04h
  63. ErrTooManyRegions equ 09h
  64. ErrInvalidBufferID equ 0Ah
  65. ErrFuncNotSupported equ 0Fh
  66. ErrReservedFlagBits equ 10h
  67. ; DMA Descriptor Structure(s)
  68. DDS STRUC ;normal DDS
  69. DDS_RegionSize dd ?
  70. DDS_Offset dd ?
  71. DDS_Selector dw ?
  72. DDS_BufferID dw ?
  73. DDS_PhyAddress dd ?
  74. DDS ENDS
  75. SGDDS1 STRUC ;Extended DDS for Scatter/Gather
  76. dd 3 dup (?) ; Region format
  77. DDS_NumAvail dw ?
  78. DDS_NumUsed dw ?
  79. DDS_Region0Addr dd ?
  80. DDS_Region0Size dd ?
  81. SGDDS1 ENDS
  82. SGDDS2 STRUC ;Extended DDS for Scatter/Gather
  83. dd 4 dup (?) ; Page Table format
  84. DDS_PageTblEnt0 dd ?
  85. SGDDS2 ENDS
  86. ; -------------------------------------------------------
  87. ; EXTERNAL SYMBOL DEFINITIONS
  88. ; -------------------------------------------------------
  89. extrn EnterIntHandler:NEAR
  90. extrn LeaveIntHandler:NEAR
  91. extrn GetSegmentAddress:NEAR
  92. extrn PMIntrEntryVector:NEAR
  93. ; -------------------------------------------------------
  94. ; DATA SEGMENT DEFINITIONS
  95. ; -------------------------------------------------------
  96. DXDATA segment
  97. ifdef NEC_98
  98. extrn fPCH98:BYTE
  99. else ;!NEC_98
  100. ifdef NOT_NTVDM_NOT
  101. extrn fMicroChannel:BYTE
  102. endif
  103. endif ;!NEC_98
  104. if VCPI
  105. extrn fVCPI:BYTE
  106. endif
  107. ;
  108. ; Contains a copy of bit 5 of the byte at 40:7b, that indicates
  109. ; whether VDS should be used.
  110. ;
  111. public bDMAServiceBit
  112. bDMAServiceBit db 0
  113. DXDATA ends
  114. ; -------------------------------------------------------
  115. ; CODE SEGMENT VARIABLES
  116. ; -------------------------------------------------------
  117. DXCODE segment
  118. DXCODE ends
  119. DXPMCODE segment
  120. extrn selDgroupPM:WORD
  121. DMASvcTbl label word
  122. dw offset DXPMCODE:GetVersion
  123. dw offset DXPMCODE:LockDMARegion
  124. dw offset DXPMCODE:DoNothing ;UnlockDMARegion
  125. dw offset DXPMCODE:ScatterGatherLock
  126. dw offset DXPMCODE:DoNothing ;ScatterGatherUnlock
  127. dw offset DXPMCODE:Fail4NoBuffer ;RequestDMABuffer
  128. dw offset DXPMCODE:DoNothing ;ReleaseDMABuffer
  129. dw offset DXPMCODE:Fail4BufferID ;CopyIntoDMABuffer
  130. dw offset DXPMCODE:Fail4BufferID ;CopyOutOfDMABuffer
  131. dw offset DXPMCODE:DoNothing ;DisableDMATranslation
  132. dw offset DXPMCODE:DoNothing ;EnableDMATranalation
  133. DXPMCODE ends
  134. ; -------------------------------------------------------
  135. subttl DMA Service Dispatcher
  136. page
  137. ; -------------------------------------------------------
  138. ; DMA SERVICE DISPATCHER
  139. ; -------------------------------------------------------
  140. DXPMCODE segment
  141. assume cs:DXPMCODE
  142. ; -------------------------------------------------------
  143. ; PMIntr4B -- Entry routine/dispatcher for protected mode DMA
  144. ; services. The DMA services are invoked with an Int 4Bh
  145. ; interrupt. The 286 DOS Extender only supports the DMA
  146. ; services in protected mode. Other systems that use Virtual
  147. ; 8086 mode on 386 processors will most likely need to support
  148. ; the services in virtual mode also.
  149. ;
  150. ; The following services are supported (Int 4Bh/AH = 81h):
  151. ;
  152. ; AL = 00 Reserved
  153. ; 01 Reserved
  154. ; 02 Get Version
  155. ; 03 Lock DMA Region
  156. ; 04 Unlock DMA Region
  157. ; 05 Scatter/Gather Lock Region
  158. ; 06 Scatter/Gather Unlock Region
  159. ; 07 Request DMA Buffer
  160. ; 08 Release DMA Buffer
  161. ; 09 Copy Into DMA Buffer
  162. ; 0A Copy Out Of DMA Buffer
  163. ; 0B Disable DMA Translation
  164. ; 0C Enable DMA Translation
  165. ; 0D Reserved
  166. ; ...
  167. ; FF Reserved
  168. public PMIntr4B
  169. assume ds:NOTHING,es:NOTHING,ss:NOTHING
  170. PMIntr4B proc near
  171. ; Is this one of the supported DMA services?
  172. cmp ah,DMAServiceID ;is this a DMA service request?
  173. jz @f
  174. jmp short i4b_other_service ; no, see if it should be chained
  175. @@:
  176. call EnterIntHandler ;saves regs, switches stacks, etc.
  177. assume ds:DGROUP ;sets DS/ES = DGROUP
  178. mov es,[bp].pmUserES ; but we want caller's ES
  179. cld ;cya...
  180. cmp al,FirstValidSvc
  181. jb i4b_reserved
  182. cmp al,LastValidSvc
  183. ja i4b_reserved
  184. test dx,NOT ValidDXFlags ;any reserved flags set?
  185. jnz i4b_bad_flags
  186. ; -------------------------------------------------------
  187. ; Setup local environment and dispatch the service
  188. i4b_valid_svc:
  189. push offset DXPMCODE:i4b_svc_ret ;save dispatch return address
  190. sub al,FirstValidSvc ;get address of service routine
  191. cbw
  192. shl ax,1
  193. add ax,offset DXPMCODE:DMASvcTbl
  194. xchg ax,bx
  195. mov bx,cs:[bx]
  196. xchg ax,bx
  197. push ax ;save routine address on stack
  198. mov ax,[bp].pmUserAX ;restore entry AX
  199. ret ;invoke service routine
  200. i4b_svc_ret: ;service routines return here
  201. jnc i4b_good_return ;CY set if service failed
  202. i4b_error_return:
  203. or byte ptr [bp].intUserFL,1 ;set CY in caller's flags
  204. jmp short i4b_exit
  205. i4b_good_return:
  206. and byte ptr [bp].intUserFL,not 1 ;clear CY in caller's flags
  207. i4b_exit:
  208. call LeaveIntHandler ;resotre stack, regs, etc.
  209. iret
  210. ; -------------------------------------------------------
  211. ; Reserved DMA service 00, 01, 0D-FF; return with CY set and
  212. ; AL = ErrFuncNotSupported
  213. i4b_reserved:
  214. mov byte ptr [bp].intUserAX,ErrFuncNotSupported
  215. jmp short i4b_error_return
  216. ; -------------------------------------------------------
  217. ; User made a DMA service call with a reserved flag bit set. Fail the
  218. ; call with AL = ErrReservedFlagBits
  219. i4b_bad_flags:
  220. mov byte ptr [bp].intUserAX,ErrReservedFlagBits
  221. jmp short i4b_error_return
  222. ; -------------------------------------------------------
  223. ; This is a non-DMA Int 4B call. On Micro Channel systems, bit 3
  224. ; in location 40:007B indicates if we should chain the call along
  225. ; or not. If the bit is set, we chain. If not Micro Channel, or the
  226. ; bit is not set, we check the real mode Int 4Bh vector to see if someone
  227. ; other than the BIOS has it hooked--if so, we chain anyway. If not,
  228. ; return without changing any regs or flags.
  229. i4b_other_service:
  230. push ds
  231. mov ds,selDgroupPM
  232. assume ds:DGROUP
  233. ifdef NOT_NTVDM_NOT
  234. ifdef NEC_98
  235. test fPCH98,0FFh
  236. else ;!NEC_98
  237. test fMicroChannel,0FFh ;if micro channel system
  238. endif ;!NEC_98
  239. jz i4b_check_vector ; and 40:7B bit 3 set,
  240. ; chain the call to real mode
  241. push SEL_BIOSDATA or STD_RING
  242. pop ds
  243. assume ds:NOTHING
  244. test byte ptr ds:DMAServiceByte,ChainReserved
  245. jnz i4b_chain
  246. endif
  247. i4b_check_vector: ;not micro channel, or bit 3 not set
  248. push ax ;check if the real mode Int 4Bh
  249. mov ax,SEL_RMIVT or STD_RING ; points somewhere and not
  250. mov ds,ax ; at the BIOS--if so, chain
  251. mov ax,word ptr ds:[4Bh*4] ; anyway.
  252. or ax,word ptr ds:[4Bh*4+2]
  253. pop ax
  254. jz i4b_dont_chain
  255. cmp word ptr ds:[4bh*4+2],0E000h
  256. jz i4b_dont_chain
  257. cmp word ptr ds:[4bh*4+2],0F000h
  258. jz i4b_dont_chain
  259. i4b_chain:
  260. pop ds ;chain the request to real mode
  261. jmp PMIntrEntryVector + 5*4Bh ; (no one can have pMode
  262. ; hooked before us)
  263. i4b_dont_chain: ;don't chain the interrupt,
  264. ; just return quietly
  265. pop ds
  266. iret
  267. PMIntr4B endp
  268. ; -------------------------------------------------------
  269. subttl DMA Service Routines
  270. page
  271. ; -------------------------------------------------------
  272. ; DMA SERVICE ROUTINES
  273. ; -------------------------------------------------------
  274. ; -------------------------------------------------------
  275. ; RM4B -- Call the real mode INT 4Bh handler to
  276. ; perform a DMA service, most likely something to
  277. ; do with the VCPI provider's buffer when we are
  278. ; running under VCPI.
  279. ;
  280. ; Input: depends on call
  281. ; Output: Flags, registers from real mode call
  282. ;
  283. ; Notes: This is strictly an internal DOSX call,
  284. ; so if a long pointer is used, then it
  285. ; is assumed to point into DOSX's data
  286. ; segment.
  287. ;
  288. cProc RM4B,<NEAR,PUBLIC>
  289. cBegin
  290. pushf
  291. push cs
  292. call near ptr PMIntrEntryVector + 3*4Bh
  293. cEnd
  294. ; -------------------------------------------------------
  295. ; DoNothing -- This routine does nothing other than return
  296. ; indicating that the DMA service succeeded.
  297. ;
  298. ; Input: none
  299. ; Output: AL = 0, CY clear
  300. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  301. DoNothing proc near
  302. clc ;indicate success
  303. ret
  304. DoNothing endp
  305. ; -------------------------------------------------------
  306. ; Fail4BufferID -- This routine does nothing other than return
  307. ; indicating that the DMA service failed with 'Invalid Buffer ID'
  308. ;
  309. ; Input: none
  310. ; Output: AL = 0Ah, CY set
  311. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  312. Fail4BufferID proc near
  313. mov byte ptr [bp].intUserAX,ErrInvalidBufferID
  314. stc
  315. ret
  316. Fail4BufferID endp
  317. ; -------------------------------------------------------
  318. ; Fail4NoBuffer -- This routine does nothing other than return
  319. ; indicating that the DMA service failed with 'No Buffer Available'
  320. ;
  321. ; Input: none
  322. ; Output: AL = 04h, CY set
  323. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  324. Fail4NoBuffer proc near
  325. mov byte ptr [bp].intUserAX,ErrNoBufferAvail
  326. stc
  327. ret
  328. Fail4NoBuffer endp
  329. ; -------------------------------------------------------
  330. ; GetVersion -- This routine processes the DMA Get Version
  331. ; service (AL = 02).
  332. ;
  333. ; Input: none
  334. ; Output: AH/AL - Major/Minor specification level
  335. ; BX - Product number
  336. ; CX - Product revision number
  337. ; DX - flags
  338. ; SI:DI - 32 bit max buffer size available
  339. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  340. GetVersion proc near
  341. mov [bp].intUserAX,(MajorVersion shl 8) or MinorVersion
  342. mov [bp].intUserBX,DOSXProductNumber
  343. mov [bp].intUserCX,DOSXProductRevision
  344. mov [bp].intUserDX,MemoryContiguous
  345. xor ax,ax ;0 buffer size supported, also clears
  346. mov [bp].intUserSI,ax ; carry flag
  347. mov [bp].intUserDI,ax
  348. if VCPI
  349. cmp fVCPI,0
  350. je gv_x
  351. mov ax,8102h
  352. xor dx,dx ;DX = 0
  353. cmp bDMAServiceBit,0 ;VCPI provider supports VDS?
  354. je gv_e
  355. call RM4B
  356. jc gv_x
  357. mov [bp].intUserSI,si
  358. mov [bp].intUserDI,di
  359. and dx,NOT (AutoRemapSupported or MemoryContiguous)
  360. gv_e:
  361. mov [bp].intUserDX,dx
  362. gv_x:
  363. endif
  364. ret
  365. GetVersion endp
  366. ; -------------------------------------------------------
  367. ; LockDMARegion -- This routine processes the Lock DMA Region
  368. ; service (AL = 03).
  369. ;
  370. ; Input: DX - flags
  371. ; ES:DI - ptr to DDS
  372. ; Output: if successful, CY clear; else CY set and AL = error code
  373. ; DDS updated
  374. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  375. LockDMARegion proc near
  376. ; Since we don't support paging or anything interesting like that, the only
  377. ; thing that can fail us is an alignment problem--check for that.
  378. test dl,Align64k or Align128k ;if they don't care,
  379. jz lock_ok ; we don't care
  380. mov si,dx ;save flags in SI
  381. call CalcDDSPhyAddress ;see where the region is
  382. push dx ;save start address
  383. push ax
  384. mov bx,dx ;bx = hi word start addr
  385. add ax,word ptr es:[di].DDS_RegionSize ;see where it ends
  386. adc dx,word ptr es:[di].DDS_RegionSize+2
  387. sub ax,1 ;less 1 to point at
  388. sbb dx,0 ; last byte, not next
  389. mov cx,dx ;cx = hi word end addr
  390. test si,Align128k ;64k or 128k alignment wanted?
  391. jz @f ; already setup for 64k
  392. and bl,not 1 ;mask to 128k alignment
  393. and cl,not 1
  394. @@:
  395. cmp bx,cx ;within the boundry?
  396. jz lock_ok_clr_stk ; yes, 'lock' it
  397. ; The region crosses an alignment boundary, we need to update the allowed
  398. ; region size in the DDS, and fail the call.
  399. pop cx
  400. pop dx ;dx:cx = region start address
  401. neg cx ;cx = len to next 64k boundry
  402. xor bx,bx
  403. test si,Align128k
  404. jz @f
  405. mov bl,dl
  406. and bl,1
  407. xor bl,1 ;bx:cx = len to next alignment boundry
  408. @@:
  409. mov word ptr es:[di].DDS_RegionSize,cx ;update size in DDS
  410. mov word ptr es:[di].DDS_RegionSize+2,bx
  411. mov byte ptr [bp].intUserAX,ErrRegionCrossedBoundry ;flag failure
  412. stc
  413. ret
  414. lock_ok_clr_stk:
  415. add sp,4 ;clear start address from stack
  416. ; No alignment problem, we can 'lock' the region.
  417. lock_ok:
  418. call CalcDDSPhyAddress ;get physical address of region DX:AX
  419. mov word ptr es:[di].DDS_PhyAddress,ax
  420. mov word ptr es:[di].DDS_PhyAddress+2,dx
  421. xor ax,ax ;*** also clears CY! ***
  422. mov es:[di].DDS_BufferID,ax ;no buffer used
  423. ret
  424. LockDMARegion endp
  425. ; -------------------------------------------------------
  426. ; ScatterGatterLock -- This routine implements the Scatter/Gather
  427. ; Lock Region DMA service (AL = 05h).
  428. ;
  429. ; Input: DX - flags
  430. ; ES:DI - ptr to extended DDS
  431. ; Output: if successful, CY clear; else CY set & AL = error code
  432. ; DDS updated
  433. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  434. ScatterGatherLock proc near
  435. test dl,PageTableFmt ;Scatter/Gather page table form?
  436. jnz do_page_tbl_lock
  437. ; This is the region form of Scatter/Gather Lock Region -- for us this
  438. ; is easy, since memory is contiguous -- one region covers the entire area.
  439. mov ax,1 ;we need one region entry
  440. mov es:[di].DDS_NumUsed,ax
  441. cmp es:[di].DDS_NumAvail,ax ; is it available?
  442. jb not_enough_entries
  443. call CalcDDSPhyAddress ;get physical address
  444. mov word ptr es:[di].DDS_Region0Addr,ax ;store in extended DDS
  445. mov word ptr es:[di].DDS_Region0Addr+2,dx
  446. mov ax,word ptr es:[di].DDS_RegionSize ;copy over the size
  447. mov word ptr es:[di].DDS_Region0Size,ax
  448. mov ax,word ptr es:[di].DDS_RegionSize+2
  449. mov word ptr es:[di].DDS_Region0Size+2,ax
  450. clc ;indicate success
  451. ret
  452. ; This is the page table form of Scatter/Gather Lock Region -- we need to
  453. ; build a fake page table (even though we may be on an 80286!?) to return
  454. ; in the extended DDS.
  455. do_page_tbl_lock:
  456. call CalcDDSPhyAddress ;get region start address
  457. mov cx,word ptr es:[di].DDS_RegionSize ;calc # pages needed
  458. mov bx,word ptr es:[di].DDS_RegionSize+2 ; for region of this
  459. add cx,PhysicalPageSize-1 ; size
  460. adc bx,0
  461. shr cx,PageShift
  462. shl bx,16-PageShift
  463. or cx,bx ;cx = # pages
  464. test ax,PhysicalPageSize-1 ;if region doesn't start on a page
  465. jz @f ; boundry, add another page to
  466. inc cx ; the region size
  467. @@:
  468. mov es:[di].DDS_NumUsed,cx ;tell caller how many used/needed
  469. cmp es:[di].DDS_NumAvail,cx ;did caller supply enough page entries?
  470. jb not_enough_entries ; no!
  471. push ax ;save low word of region start address
  472. and ax,NOT PhysicalPageSize-1 ;round down to page boundry
  473. or al,1 ;set page present/locked bit
  474. mov bx,di ;es:bx -> page table entries
  475. jcxz page_ents_done ;better safe than sorry
  476. @@:
  477. mov word ptr es:[bx].DDS_PageTblEnt0,ax ;build fake page
  478. mov word ptr es:[bx].DDS_PageTblEnt0+2,dx ; table entries...
  479. add ax,PhysicalPageSize
  480. adc dx,0
  481. add bx,4
  482. loop @b
  483. page_ents_done:
  484. pop ax ;recover low word of start address
  485. and ax,PhysicalPageSize-1 ; and get offset into first page
  486. mov [bp].intUserBX,ax ; return to caller in BX
  487. clc ;indicate success
  488. ret
  489. ; Fail the request for insufficient # of region/page tbl entries
  490. not_enough_entries:
  491. mov byte ptr [bp].intUserAX,ErrTooManyRegions ;AL = error code
  492. mov ax,es:[di].DDS_NumAvail ;store max lockable
  493. mov dx,ax ; size (bytes) in
  494. shl ax,PageShift ; DDS region size
  495. shr dx,16-PageShift
  496. mov word ptr es:[di].DDS_RegionSize,ax
  497. mov word ptr es:[di].DDS_RegionSize+2,dx
  498. stc ;indicate failure
  499. ret
  500. ScatterGatherLock endp
  501. ; -------------------------------------------------------
  502. subttl DMA Service Utility Routines
  503. page
  504. ; -------------------------------------------------------
  505. ; DMA SERVICE UTILITY ROUTINES
  506. ; -------------------------------------------------------
  507. ; -------------------------------------------------------
  508. ; CalcDDSPhyAddress -- This routine calculates the physical
  509. ; address of the region specified in a DDS.
  510. ;
  511. ; Input: ES:DI - ptr to DDS
  512. ; Output: DX:AX - 32 bit physical address
  513. ; Uses: none.
  514. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  515. CalcDDSPhyAddress proc near
  516. push bx
  517. xor bx,bx
  518. mov dx,bx
  519. mov ax,es:[di.DDS_Selector] ;if a selector is given,
  520. or ax,ax ; get it's base address
  521. jz @f
  522. call GetSegmentAddress ;bx:dx = segment base
  523. @@:
  524. add dx,word ptr es:[di.DDS_Offset] ;add 32 bit offset
  525. adc bx,word ptr es:[di.DDS_Offset+2]
  526. mov ax,dx ;32 bit address to dx:ax
  527. mov dx,bx
  528. pop bx
  529. ret
  530. CalcDDSPhyAddress endp
  531. DXPMCODE ends
  532. ;****************************************************************
  533. end