Q: How can I access memory-mapped peripheral devices (or any other
absolute address) above 1 MByte mark?
A: You should use DPMI functions to allocate an LDT descriptor, and map it to an absolute physical address. This maps the physical address of the memory on the device to a linear address, and returns that linear address to you. You then create a selector to access the span of linear addresses on the device.
Here are the DPMI calls that you will have to use:
All of these DPMI calls have
__dpmi_XXX wrappers in the DJGPP
library. Here's a somewhat schematic example:
#include <dpmi.h> . . __dpmi_meminfo mi; int selector; . . /* Map the physical device address to linear memory. */ mi.address = physical_address; mi.size = physical_address_size; __dpmi_physical_address_mapping (&mi); /* Now mi.address holds the linear address. */ . . /* Allocate an LDT descriptor and set it up to span the entire device on-board memory. */ selector = __dpmi_allocate_ldt_descriptor (1); __dpmi_set_segment_base_address (selector, mi.address); __dpmi_set_segment_limit (selector, mi.size - 1);
Note that the segment limit should be one less than the size. Also, segments over 1MB in length must be a multiple of 4KB, otherwise the DPMI server might fail the call, or silently change the limit.
You can then use the functions from the
sys/farptr.h header file
to access that device. See accessing memory-mapped devices, for more
details about accessing memory-mapped devices given their linear
The DPMI function that is issued by
__dpmi_physical_address_mapping only works reliably for addresses
above 1MB mark. If you call it with a physical address in the first
Megabyte, it might fail, depending on the DPMI server (e.g., CWSDPMI
fails such calls). (The DPMI spec explicitly says that programs should
not call this function to access memory below the 1MB boundary.)
This failure usually means that the offending address is already mapped
into the page tables, so you shouldn't worry about it; and most DPMI
servers map the first Megabyte 1:1 anyway.