Virtual DMA Services (VDS) Version 1.00 Printed July 16, 1990 Table Of Contents Introduction..............................................1 Notes For Writing DMA Device Drivers......................2 Notes For DMA Service Environments........................3 Services..................................................6 Reserved Subfunctions.................................7 Get Version...........................................8 Lock DMA Region.......................................9 Unlock DMA Region....................................11 Scatter/Gather Lock Region...........................12 Scatter/Gather Unlock Region.........................14 Request DMA Buffer...................................15 Release DMA Buffer...................................16 Copy Into DMA Buffer.................................17 Copy Out Of DMA Buffer...............................18 Disable DMA Translation..............................19 Enable DMA Translation...............................20 Summary of Error Codes and Option Flags..................21 .End Table C. INTRODUCTION DOS device drivers which perform DMA, program a controller with an address of a buffer region. All software running in protected mode environments, whether running in virtual 8086 mode or in protected mode under a DOS extender, usually can not determine the physical address of their DMA region. The DMA controller also places further restrictions upon acceptable DMA regions: they must be in contiguous physical memory, on XTs they must be in the first 1Mb of memory and on XTs, ATs and compatibles they must not cross 64Kb or 128Kb alignment boundaries. These services provide the necessary support to allow a device driver or application program to obtain the necessary information to program a DMA transfer using either the on board DMA controller or a busmaster DMA controller. The services are provided through software interrupt 4Bh. Programs must examine bit five (5) of the byte at 0040:007Bh. If the bit is set then they should use the DMA services. Otherwise, the device can assume that all memory is mapped linear = physical (probably running in real mode, this can be a dangerous assumption, if the machine is actually running in virtual mode, because the protected mode software may not support this specification, and there is not a method for checking for physical = linear). An implementation of the DMA services must provide either automatic remapping of pages to force regions of memory to be physically contiguous or support a DMA buffer with a minimum size of 16K, if paging is enabled by the system software. Most 286 software can get by without supporting either option. With the exception of the AX register and unless otherwise specified, all registers and flags are preserved across DMA service calls. The AX register contents are undefined on return unless the carry flag is set in which case AL contains an error code. NOTES FOR WRITING DMA DEVICE DRIVERS DMA devices that use these services must continually monitor bit five (5) of the byte at 0040:007Bh before programming DMA. The services may be initialized or turned off at any time. For example, when a program begins using simulated expanded memory a "LIMulator" will place the machine in Virtual 8086 mode and enable the DMA services. When all LIM memory has been deallocated it will return the machine to real mode and turn off the DMA services. Note also that the type of DMA support provided may change dynamically. For example, the user may run one protected mode environment, exit it, and then run another protected mode environment. In this case the services will be provided by two different implementations. There are various levels of support that device drivers can have for DMA. These options are listed below in order from best to worst: Support scatter/gather on the hardware adaptor Break DMA requests up in software so that a buffer is never required Break up DMA into 16K or smaller pieces so the default buffer can be used Force the user to override the buffer size The last option is really not acceptable. At the very least your software should chop up transfers into 16K pieces. For example, it is acceptable to break hard disk transfers at track boundaries. A normal hard disk track will fit into a 16K buffer. DMA devices that are not as timing sensitive as disk drives should break up transfers. Ideally, all DMA adaptors would support scatter/gather in hardware. In some situations a device driver has a real physical address that it wants to use in a DMA transfer. These physical addresses may be from memory allocated through XMS or INT 15h before DMA services were provided, or may be for memory that exists on an adapter card, etc. In these situations, DMA lock calls should not be called, because the service routines must interpret region addresses as linear addresses. It is necessary, however to call the Disable/Enable Translation services, if the standard DMA controller is used for the transfer. By convention, a buffer ID of zero in the DDS indicates that no buffer has been allocated. Device driver software can check this field to determine if a buffer was allocated. NOTES FOR IMPLEMENTING DMA SERVICES The recommended method of supporting these services is to use a DMA buffer since it has been found to be faster than attempting to remap memory on 386 machines. On 286 machines it is possible to not implement a buffer; on these machines the software calling the services must already know how to split up transfers to deal with crossing alignment boundaries. It is necessary to return the "No buffer available" error (04h) for the Request DMA Buffer service (07h). All implementations of these services should provide mechanisms for overriding the size of the DMA buffer or remap region. Also, all implementations should provide a mechanism for forcing the buffer or remap region to reside in the first megabyte of physical memory. The actual mechanism for doing this will be implementation dependent. For example, some programs may use a configuration file while others could use command line switches. Lock calls for memory which is not "owned" by the provider of these DMA services, memory allocated before the provider started running including low memory, EBIOS data area and extended memory allocated through INT 15h or XMS, must not fail. If auto-remapping is supported, then pages must be remapped to force contiguous regions. If auto-remapping is not supported, then it is necessary for the provider to keep these memory areas contiguous. Additionally, in some environments, device drivers will exist which attempt long term DMA transfers. In these environments it is necessary to allow the user to configure the software so that such transfers can take place. One solution is to force long term DMA device drivers to be loaded after the provider software. The other solution is to keep all "unowned" memory mapped at the original location so linear equals physical; this allows transfers started prior to DMA services being provided to continue as normal. Since other hardware/software services can be provided on the INT 4Bh chain, it is necessary for provider software to determine if they should chain interrupts when AH is not 81h. On Micro Channel machines this can be done by examining bit three (3) in the byte at 0040:007Bh, if the bit is set, then chaining is required, if it is clear, then it is necessary to examine the vector contents. If the vector contents are 0, or point to E000h or F000h ROM, then the interrupt should not be chained, because it may go to a default IRQ handler which may EOI an outstanding hardware interrupt. Summary of bit 3 in 0040:007Bh: Bit 3 Interrupt 4Bh Intercepted Indicator (Micro Channel Only) = 0 Interrupt vector not intercepted. check contents of the interrupt vector. If contents are 0:0 or segment values of E000h or F000h, chaining is not permitted. = 1 Interrupt vector intercepted, chaining required. On other non-Micro Channel architectures examining the vector value may be the only way to determine if interrupts should be chained. If not chaining, then the interrupt should be ignored with an IRET without modifying registers or flags. Determining Which Error Codes to Return The following logic should be used for the Lock DMA Region service (AX=8103h): IF region contiguous THEN IF region does not cross alignment boundary THEN Lock region, set buffer ID to zero, and return with carry clear ELSE DO Buffer/Remap ENDIF ELSE DO Buffer/Remap ENDIF BUFFER/REMAP: IF buffer supported THEN IF buffer disable flag clear THEN DO Buffer ELSE Return with carry flag set and AL=1, 2, or 3 ENDIF ELSE IF remap supported THEN IF remap disable flag clear THEN DO Remap ELSE Return with carry flag set and AL=1, 2, or 3 ENDIF ELSE Return with carry flag set and AL=1, 2, or 3 ENDIF ENDIF BUFFER: IF buffer available THEN IF region size <= buffer size THEN Allocate buffer IF copy flag set THEN Copy data from linear region to buffer ENDIF Set buffer ID (non-zero), set physical address field to buffer physical address, and return with carry clear ELSE Return with carry flag set and AL=05h ENDIF ELSE Return with carry flag set and AL=06h ENDIF REMAP: IF region can be forced contiguous THEN IF region will not cross specified boundary THEN Force region contiguous, set physical address field, set buffer ID to zero, and return with carry clear ELSE Return with carry set and AL=02h ENDIF ELSE Return with carry set and AL=01h ENDIF SERVICES Most services take a pointer to a DMA descriptor structure (DDS) as a parameter. The structure is defined as follows: DESCRIPTION OFFSET Region Size 00h Offset 04h Buffer ID Segment/Selector 08h Physical Address 0Ch Region Size is a dword at offset 0. It specifies the size of the DMA region in bytes. Offset and Segment/Selector are an fword pair at offset 04h. They specify a 48-bit segment:offset pointer for virtual 8086 mode, or a selector:offset pointer for protected mode programs. Note that if the linear address has already been determined then you may set the segment/selector field to 0 and place the linear address in the linear offset field. It is possible to specify 32-bit offsets, even with real mode segment values; this makes it much easier for device drivers to split up DMA transfers, by simply modifying the offset without having to modify the segment/selector. Buffer ID is a word at offset 0Ah. This field is filled in by the Request DMA Buffer service and possibly the Lock DMA Region service. Physical Address is a dword at offset 0Ch. This field is filled in by the Lock DMA Region and Request DMA Buffer services. ============================================================ Reserved Subfunctions Functions 00h, 01h and 0Dh through 0FFh are reserved. If called they will return with the Carry flag set and AL = 0Fh (Function not supported). Programmer's Notes None ============================================================ Get Version This service returns the version of DMA services as well as information about the hardware, size of buffers, and support of automatic memory remapping. To Call AH = 81h AL = 02h DX = Flags All bits reserved and must be zero Returns If function was successful: Carry clear AH = Major specification version # (binary, currently 1) AL = Minor specification version # (binary, currently 0) BX = Product number CX = Product revision number SI:DI = Maximum DMA buffer size in bytes that can be requested. DX = Flags Bit 0 = 1 if PC/XT bus architecture (DMA in first meg only) Bit 1 = 1 if physical buffer/remap region is in first meg Bit 2 = 1 if automatic remap supported Bit 3 = 1 if all memory physically contiguous Other flags reserved and must be zero If function was not successful: Carry flag set AL = Error code 10h = Reserved flag bits set in DX Programmer's Notes o The version numbers returned in AH and AL are used to determine the level of functionality supported by the current implementation. The current driver will return AX=0100h. o Bit 3 of the flag word will only be set in environments that run in protected mode but do not use paging, such as 286 DOS extenders. In these environments, the DMA services are only provided to convert selector:offset linear address pairs into physical addresses. ============================================================ Lock DMA Region This service is used to determine if a target DMA region is in contiguous physical memory. If it is contiguous, then this service returns the physical address of the region so that the software can program for the DMA. A locked DMA region must always be unlocked once the DMA is complete. If the DMA controller has memory placement restrictions (i.e. below 1Mb), then it can compare the returned physical address; if the address is not suitable, then the program must unlock the region and request a DMA buffer. Some implementations of the DMA services will attempt to remap pages to force the region to be contiguous physical memory. The caller can disable this behavior by setting bit 3 in DX. Normally, it is faster for a device to split transfers or use a DMA buffer instead of going through the remap process. It is often convenient to use the automatic buffer allocation option of this service. If the DMA region can not be locked for any reason then the service will attempt to allocate a DMA buffer. If desired, the data in the region will be automatically copied into the buffer. To Call AH = 81h AL = 03h DX = Flags Bit 1 = 1 if data should be copied into buffer (ignored if bit 2 = 1) Bit 2 = 1 if buffer should not be allocated if region is not contiguous or crosses a physical alignment boundary specified by bits 4 and 5 Bit 3 = 1 if automatic remap should not be attempted Bit 4 = 1 if region must not cross a 64K physical alignment boundary Bit 5 = 1 if region must not cross a 128K physical alignment boundary All other bits reserved and must be zero ES:DI = Pointer to DMA Descriptor Structure The caller must fill in the region size, linear offset, and selector/segment fields before calling this service Returns If function was successful: Carry flag clear Memory is locked Physical address field of DDS contains the starting physical address of the region. The buffer ID field will contain the ID of the allocated buffer or 0 if no buffer was allocated. If function was not successful: Carry flag set Memory is not locked Region size field of DDS contains the maximum contiguous length in bytes. AL = Error code 01h = Region specified was not contiguous memory 02h = Region crossed a physical alignment boundary 03h = Unable to lock pages (virtual memory systems only) 05h = Region too large for buffer 06h = Buffer currently in use 07h = Invalid memory region 10h = Reserved flag bits set in DX Programmer's Notes o Memory is locked on a page granular basis. A single page can be locked more than once, thus allowing two DMA regions to overlap on a single page. Page locking is maintained as a count. Some systems need not maintain a count since memory will never be discarded or moved. In these systems, Unlock DMA Region will never fail. o If the automatic buffer allocation option is selected by clearing bit 2 of the flags in DX, then a buffer will be automatically allocated if the region could not be locked. If data should be copied into the buffer for a memory read operation then bit 1 of the flags in DX should be set. If lock is going to fail and bit 2 is clear, but no buffer is supported, then the actual cause of the error is reported as the error message, rather than returning a buffer not available error (4). o You may want to wait in a loop if this function returns a "Buffer in use" error to allow another device time to release the buffer. For more details refer to the documentation for Request DMA Buffer on page 14. o The buffer alignment mask should be used for devices that have physical memory boundary constraints. For example, on an AT architecture, the standard DMA controllers will "wrap" at 64K or 128K physical boundaries. If the DMA controller being programmed has an alignment constraint, then the applicable bit in DX should be set. =========================================================== Unlock DMA Region Service to unlock a previously locked DMA region. To Call AH = 81h AL = 04h DX = Flags Bit 1 = 1 if data should be copied out of buffer All other bits reserved and must be zero ES:DI = Pointer to DMA Descriptor Structure The caller must fill in the region size, physical address, and buffer ID fields before calling this service (Usually the caller simply passes the same structure which was filled in by the call to Lock DMA Region). Returns If function was successful: Carry flag clear Memory is unlocked or no count maintained If function was not successful: Carry flag set All memory remains locked AL = Error code 08h = Memory was not locked 0Ah = Invalid Buffer ID 10h = Reserved flag bits set in DX Programmer's Notes o This service releases a DMA buffer, if one was allocated by the Lock DMA Region call (if Buffer ID is non-zero in the DDS), so any data in it will be lost. If the DMA transfer was a memory write operation, then setting bit 1 in the DX flags parameter will copy the data out of the buffer before it is released. ============================================================ Scatter/Gather Lock Region This service is provided so that hardware devices that support automatic scatter/gather can determine the actual physical regions of and lock an entire linear address range in one call. Device drivers that break up DMA requests may also want to use this service instead of repeatedly calling lock DMA region. To Call AH = 81h AL = 05h DX = Flags Bit 6 = 1 if EDDS should be returned with page table entries Bit 7 = 1 if only present pages should be locked, not present pages will be identified as a page table entry of 0 (bit 7 is ignored, if bit 6 = 0) All other bits reserved and must be zero ES:DI = Pointer to one of the following extended DDS: If option bit 6 = 0 then return Extended DDS (EDDS) with table of physical regions (address and size pairs): DESCRIPTION OFFSET Region Size in Bytes 00h Linear Offset 04h Reserved Segment/Selector 08h # Used # Avail 0Ch Region 0 Physical Address 10h Region 0 Size in Bytes 14h Region 1 Physical Address 18h Region 1 Size in Bytes 1Ch . . . . . . . . . . . . Region n Physical Address 10h+n*8 Region n Size in Bytes 14h+n*8 If option bit 6 = 1 then return Extended DDS with table of page table entries (1 entry per 4Kb page in the same format as 80386 page table entries): DESCRIPTION OFFSET Region Size in Bytes 00h Linear Offset 04h Reserved Segment/Selector 08h # Used # Avail 0Ch Page table entry 0 10h Page table entry 1 14h . . . . . . . . . . . . Page table entry n 10h+n*4 Each page table entry contains the physical page number in the upper 20 bits; the lower 12 bits are flag bits: Bit 0 = 1 if the page is present and locked Bits 1..11 are reserved and will be zero If option bit 7 = 1, then pages in the region which do not have a physical page assigned will have a page table entry of 0, and will not be locked by this call. The caller must fill in the region size, linear segment and offset, and number available field. The # Avail field specifies the number of physical regions/page table entries in the data structure. Returns If function was successful: Carry flag is clear The # used field will contain the number of table entires filled in with physical regions information. If bit 6 of option flags was 1 (page table copy) then low twelve bits of BX = Offset in first page to start of region (high 4 bits will be zero). If function was not successful: Carry flag is set Memory is not locked Region size field of DDS contains the maximum length in bytes that can be locked and described in the DDS table. Table entries are undefined. AL = Error code 03h = Unable to lock pages 07h = Invalid memory region 09h = Number of physical regions/pages was greater than table length (The # used field will contain the number of table entries needed to describe the DMA region.) 10h = Reserved flag bits set in DX Programmer's Notes o The maximum number of physical regions required can be computed as: (Linear Address AND 0FFFh) + Region Size + 0FFFh 1000h ============================================================ Scatter/Gather Unlock Region This service is used to unlock a region that was locked by the Scatter/Gather Lock Region service. To Call AH = 81h AL = 06h DX = Flags Bit 6 = 1 if EDDS contains page table entries Bit 7 = 1 if EDDS may contain not present pages, not present pages are identified as a page table entry of 0 (bit 7 is ignored, if bit 6 = 0) All other bits reserved and must be zero ES:DI = Pointer to the extended DDS that was used when calling the Scatter/Gather Lock Region service. Returns If function was successful: Carry flag is clear Memory is unlocked If function was not successful: Carry flag is set AL = Error code 08h = Memory was not locked 10h = Reserved flag bits set in DX Programmer's Notes o Only the region size, linear offset and segment/selector fields are used. Therefore, the physical address/size or page table entries do not need to be maintained, unless bits 6 and 7 were set in DX in the call to Scatter/Gather Lock Region. If this special form of page table lock was used, then the table is required so that the correct pages can be unlocked. ============================================================ Request DMA Buffer Buffered DMA requires a device driver to request a DMA buffer, copy data into the buffer (if a memory read operation is required), start the DMA transfer with programmed I/O, copy data from the buffer (if a memory write operation is required), and release the DMA buffer. The data must be copied to/from the DMA buffer before release is called and the physical address of the buffer must be considered invalid as soon as release is called. To Call AH = 81h AL = 07h DX = Flags Bit 1 = 1 if data should be copied into buffer All other bits reserved and must be zero ES:DI = Pointer to DMA Descriptor Structure The caller must fill in the region size field. If automatic copy is selected (bit 1 set) then the caller must also fill in the linear region segment and region offset fields. Returns If function was successful: Carry flag clear The physical address field of the DDS contains the starting physical address of the buffer. The region size field specifies the size of the buffer. The buffer ID field contains the ID of the allocated buffer If automatic copy was selected then data was copied into the buffer. If function was not successful: Carry flag set AL = Error code 04h = No buffer available 05h = Region too large for buffer 06h = Buffer currently in use 07h = Invalid memory region 10h = Reserved flag bits set in DX Programmer's Notes o Under Windows/386 devices will often want to enter a Windows/386 critical section to prevent running other VMs while they are using a DMA buffer. o If the buffer is in use you may want to spin in a loop with interrupts enabled and repeatedly attempt to allocate the buffer to allow another device time to complete its DMA. o Your device driver must either spin in a wait loop until the DMA is complete and then release ownership of the buffer or it must release ownership of the buffer from a hardware interrupt. Releasing ownership from hardware interrupts will allow other devices to wait for the buffer to be freed as described above. ============================================================ Release DMA Buffer Releases a DMA buffer that was previously requested. The physical address should be considered invalid following this call. To Call AH = 81h AL = 08h DX = Flags Bit 1 = 1 if data should be copied out of buffer All other bits reserved and must be zero ES:DI = Pointer to DMA Descriptor Structure The caller must fill in the buffer ID field of the DDS before calling this service. Returns If function was successful: Carry flag clear If function was not successful: Carry flag set AL = Error code 0Ah = Invalid buffer ID 10h = Reserved flag bits set in DX Programmer's Notes None ============================================================ Copy Into DMA Buffer Copy data from the user's buffer into the DMA buffer to prepare for a memory read DMA transfer. To Call AH = 81h AL = 09h DX = Flags All bits reserved and must be zero ES:DI = Pointer to DMA Descriptor Structure The caller must fill in the buffer ID field, the fword segment/selector:linear offset fields to specify the source address for the copy, and the region size. BX:CX = Starting offset in DMA buffer to copy The size field of the DDS determines the number of bytes that will be copied Returns If function was successful: Carry flag clear If function was not successful: Carry flag set AL = Error code 0Ah = Invalid buffer ID 0Bh = Copy count+offset is greater than buffer size 10h = Reserved flag bits set in DX ============================================================ Copy Out Of DMA Buffer Copy data from the DMA buffer into the user's buffer after a memory write DMA transfer. To Call AH = 81h AL = 0Ah DX = Flags All bits reserved and must be zero ES:DI = Pointer to DMA Descriptor Structure The caller must fill in the buffer ID field, the fword segment/selector:linear offset fields to specify the destination address for the copy, and the region size. BX:CX = Starting offset in DMA buffer to copy The size field of the DDS determines the number of bytes that will be copied Returns If function was successful: Carry flag clear If function was not successful: Carry flag set AL = Error code 0Ah = Invalid buffer ID 0Bh = Copy count+offset is greater than buffer size 10h = Reserved flag bits set in DX ============================================================ Disable DMA Translation Environments that support the DMA services will trap the standard DMA I/O ports and attempt to remap the client's addresses, which are assumed to be linear addresses, to the appropriate physical address. However, programs which use the DMA services to determine the physical address of their DMA region must disable the automatic remapping of standard DMA by calling this function. A disable count is maintained so you must call Enable DMA Translation for every call to this service before automatic DMA translation will be enabled. To Call AH = 81h AL = 0Bh BX = DMA channel number DX = Flags All bits reserved and must be zero Returns If function was successful: Carry flag clear If function was not successful: Carry flag set AL = Error code 0Ch = Invalid DMA channel number 0Dh = Disable count overflow 10h = Reserved flag bits set in DX Programmer's Notes None ============================================================ Enable DMA Translation This service must be called after calling Disable DMA Translation to re-enable automatic DMA remapping. A disable count is maintained so you must call this service for every call to Disable DMA Translation before automatic DMA translation will be enabled. To Call AH = 81h AL = 0Ch BX = DMA channel number DX = Flags All bits reserved and must be zero Returns If function was successful: Carry flag clear If disable count decremented to 0, then Zero flag set If function was not successful: Carry flag set AL = Error code 0Ch = Invalid DMA channel number 0Eh = Disable count underflow (was not previously disabled). Count not changed. 10h = Reserved flag bits set in DX Programmer's Notes None SUMMARY OF ERROR CODES AND OPTION FLAGS Error codes: 01h = Region not in contiguous memory 02h = Region crossed a physical alignment boundary 03h = Unable to lock pages 04h = No buffer available 05h = Region too large for buffer 06h = Buffer currently in use 07h = Invalid memory region 08h = Region was not locked 09h = Number of physical pages was greater than table length 0Ah = Invalid buffer ID 0Bh = Copy out of buffer range 0Ch = Invalid DMA channel number 0Dh = Disable count overflow 0Eh = Disable count underflow 0Fh = Function not supported 10h = Reserved flag bits set in DX Flags: Bit 1 = Automatically copy to/from buffer Bit 2 = Disable automatic buffer allocation Bit 3 = Disable automatic remap feature Bit 4 = Region must not cross 64K physical alignment boundary Bit 5 = Region must not cross 128K physical alignment boundary Bit 6 = Copy page table for scatter gather remap