ID Number: Q80591
3.00
WINDOWS
Summary:
Some applications need to use memory that is fixed in the physical
address space of the microprocessor on which the application is run.
Hardware such as network interface cards use on-board buffers that
software must access. This article outlines two methods to access
physical memory in Windows protected mode (standard mode or 386
enhanced mode).
More Information:
Method 1: Exported Selectors (Preferred)
----------------------------------------
The Windows 3.0 Kernel exports several selectors that should be used
by applications that require access to physical memory located below
the 1 megabyte (MB) boundary.
The exported selectors are __0000h, __0040h, __A000h, __B000h,
__B800h, __C000h, __D000h, __E000h, and __F000h.
To use one of these selectors, place it onto a segment register and
access the memory or create a long pointer. Here are examples using
the Microsoft Macro Assembler (MASM) and Microsoft C:
In ASM: externA __0040h
...
mov ax, __0040h
mov es, ax
In C: extern WORD _0040h;
LPSTR lpBIOSDataArea;
...
/* note the & and single underscore */
lpBIOSDataArea = (LPSTR)MAKELONG(0, &_0040h);
Each of these data selectors is limited to accessing 64 kilobytes (K).
An attempt to read or write to data beyond the limit causes a General
Protection fault (evidenced by an unrecoverable application error --
UAE) in protected mode. Performing segment arithmetic with these
selectors will also cause a GP fault.
Method 1 is always recommended and should be used unless the exported
selectors do not provide access to the necessary area of physical
memory.
Method 2: Selector Synthesis
----------------------------
Selector synthesis should be used when an application needs to access
physical memory that is not addressable with the selectors exported
from the Windows Kernel. This method involves allocating a new
selector and initializing the associated descriptor with the
appropriate values. The functions to do this are provided through the
DOS Protected Mode Interface (DPMI), and through Windows Kernel
functions. The required functions include the following:
Function Description
-------- -----------
Map Physical To Linear (DPMI: INT 31h, AX=0800h) Maps a 32-bit
physical address to a 32-bit linear address.
This may be required because the selector
functions can work only with linear
addresses.
AllocSelector(WORD) (Kernel) Allocates a new selector with
default attributes equal to the attributes of
the selector argument to the function.
FreeSelector(WORD) (Kernel) Frees a selector allocated
previously with AllocSelector().
SetSelectorBase(WORD, DWORD)
(Kernel) Stores the linear address of the
start of the desired region in the descriptor
of the first parameter to the function.
SetSelectorLimit(WORD, DWORD)
(Kernel) Stores the length of the desired
region in the descriptor of the first
parameter to the function.
Caveats:
1. These routines do not inform the Windows memory manager that a
particular block of memory is in use. It is the responsibility of
the caller to ensure that the area of memory will not be touched by
some other process in the system.
2. An aliased selector, that is, a synthesized selector pointing to a
memory object allocated by the Kernel, is not updated if the memory
block to which it refers is moved by Windows.
3. Allocating large numbers of selectors is discouraged because
selectors are a limited resource.
4. This method of allocating memory cannot be used in place of
GlobalAlloc(). It should be used only when an application must have
access to a specific range of physical memory.
The following code fragment has been written using the inline assembly
feature of Microsoft C version 6.0. This code illustrates the
technique of selector synthesis.
DWORD MapPhysicalToLinear(DWORD, DWORD);
WORD SynthSelector(DWORD, DWORD);
LPSTR GetSelectorPointer(WORD);
/* The following functions were not prototyped in version */
/* 3.0 of the Windows Software Development Kit (SDK). These */
/* prototypes may not be necessary in future releases. */
int FAR PASCAL SetSelectorBase(WORD, DWORD);
int FAR PASCAL SetSelectorLimit(WORD, DWORD);
DWORD dwPhysical, dwLinear, dwLength;
LPSTR lpPhys;
WORD wSelector;
WORD segment, offset; // These variables are necessary only
// if the target memory is addressed
// with a "real-mode" style SEG:OFFSET
// pointer.
/*--------------------------------------------------------------*/
/* Sample Code to Synthesize a Selector */
/*--------------------------------------------------------------*/
dwPhysical = (segment << 4L) + offset; // Only if "MS-DOS" memory;
// otherwise, dwPhysical
// should contain the
// 32-bit physical address.
// At this point, dwPhysical and dwLength must be set.
dwLinear = MapPhysicalToLinear(dwPhysical, dwLength); // Map addr
if (!dwLinear)
{
// error...
}
wSelector = SynthSelector(dwLinear, dwLength); // Create selector.
lpPhys = GetSelectorPointer(wSelector); // Make a pointer.
// Use the pointer lpPhys to access memory...
FreeSelector(wSelector);
// Rest of program...
/*--------------------------------------------------------------*/
/* This function is a shell for DPMI Map Physical To Linear. */
/*--------------------------------------------------------------*/
DWORD MapPhysicalToLinear(DWORD dwPhysical, DWORD dwLength)
{
DWORD dwLinear;
if (dwPhysical >= 0x100000L) // Use only if above 1 MB.
{
_asm {
push di
push si
mov bx, WORD PTR [dwPhysical+2] ; Load arguments.
mov cx, WORD PTR [dwPhysical]
mov si, WORD PTR [dwLength+2]
mov di, WORD PTR [dwLength]
mov ax, 800h
int 31h ; Issue DPMI call.
jc short error_return
mov dx, bx
mov ax, cx
jmp short fine_return
error_return:
xor ax, ax
mov dx, ax
fine_return:
mov WORD PTR [dwLinear+2], dx ; Return value.
mov WORD PTR [dwLinear], ax
pop si
pop di
}
}
return dwLinear;
}
/*--------------------------------------------------------------*/
/* This function will allocate and initialize a selector. */
/*--------------------------------------------------------------*/
WORD SynthSelector(DWORD dwLinearAddress, DWORD dwLength)
{
WORD selector;
_asm {
push ds
call AllocSelector
mov selector, ax ; Return value from function.
}
if (selector) /* AllocSelector returns NULL on error. */
{
SetSelectorBase(selector, dwLinearAddress);
SetSelectorLimit(selector, dwLength);
}
return selector;
}
/*--------------------------------------------------------------*/
/* This function builds a pointer to the memory referenced */
/* by the selector. */
/*--------------------------------------------------------------*/
LPSTR GetSelectorPointer(WORD selector)
{
return (LPSTR)MAKELONG(0, selector);
}
Additional reference words: 3.00 DPMI Selector