INF: Accessing Physical Memory in Windows 3.0

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