[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Linear address mapping

(please excuse the fact that I am using MIME/HTML.  It was the only way I could send the VDS info near the bottom of this message...)

Tobias Stumber <tobias.stumber@fr.bosch.de> wrote...
> Jim Ulrich wrote:
> > If you are allocating the buffers on the host PC then try using the
> > DPMI function INT.31 FUNC.0100 to allocate your buffers.
> >
> That works fine. Thank you for this.
> But what if I want to allocate memory above 1M or very large
> memory blocks ( multiple Mb ) ?
> If I allocate linear memory above 1M I could propably get the
> phsyical address through examining the page directory entry and
> the page table entry in the MMU.

No, don't go thru the page tables!  Use some form of DMA Lock such as the Virtual DMA Services I detail down below (I don't know if DOS4GW supports these, but QEMM does and Windows does).

> But this would only lead to the physical address of the first
> 4K page. If I'm right I have to do this with every 4K block of
> my linear memory space because I can't be sure that the whole
> linear address space is mapped into a continous address space
> in the pysical memory.
> That would mean that in worst case a 512K DMA has to be broken
> down to 128 4K DMAs !? There must be a better solution !

You would only need to do this in a environment that uses Virtual Memory.  Dos4GW under realmode MSDOS does not.  It does use the page tables, but only because the 386+ architecture requires paging to be enabled before going into 32bit mode.  TNT should set the page tables up so memory is linear.

But, yes, in fact, if your device is intended to operate in a virtual memory environment (windows, NT, *nix, OS/2), then it will either have to use small static DMA buffers or it will have to support "scatter/gather".  Many modern busmastering devices (such as Adaptec SCSI controllers, I believe) support scatter/gather, where the device is given a whole table of page addresses and automatically transfers in 4k blocks.

> My only idea (at the moment) to avoid this is to disable paging
> mechnism through turning off the MMU. But I didn't find a way to
> do this with watcom c and the dos4gw extender either.

I don't know if Pharlap/TNT supports the 'VDS' Virtual DMA Services specification, but if it does, that is the preferred way of setting up DMA** to arbitrary blocks of address space.  Basically, it has 'dma page lock' calls that can be used to get either the base address of a physically contiguous block or do a 'scatter lock' if the OS uses virtual memory (windows yes, pharlap under dos, no).  This works both in windows enhanced mode and win95 for sure, but I don't know if its supported by Pharlap TNT under straight dos.  It IS supported by QEMM as well as several other dos extenders.

[** by DMA, I am including bus mastering...  Some folks assume this term means ISA style DMA... DMA as a general concept predates the IBM PC by at least 30 years]

This VDS Spec originated with the IBM PS/2 Microchannel systems.

Here's a few exerpts from the VDS 1.0 spec.  I've left out the Scatter-Lock call as I don't think you'll need it if your app is strictly DOS4GW under DOS (and its long...)


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 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.


Most services take a pointer to a DMA descriptor structure (DDS) as a parameter.  The structure is defined as follows:


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.

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




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

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.
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




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

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.
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).
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 .
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).




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

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.


Summary of Error codes:

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




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