The PMDD.SYS module provides an IOCtl that takes a physical address and returns a linear address in the address space of the calling process. The presentation display driver calling routine can obtain a linear address from a physical address by calling GetVRAMPointer and is implemented in the S3 driver, which is found in the EDDEFLDB.C file. The following is the source code:
ULONG flVRAMFirst = 0; ULONG pVRAM = 0xffffffff; HFILE hSVGA; ULONG ulAction; CHAR szSQ[32] = "\\DEV\\SINGLEQ$"; /*********************************************************************** * * FUNCTION NAME = GetVRAMPointer * * DESCRIPTION = Uses an IOCtl to get a pointer to VRAM. * * INPUT = * OUTPUT = * * RETURN-NORMAL = * RETURN-ERROR = * /*********************************************************************** ULONG GetVRAMPointer ( ULONG ulAddr , ULONG ulSize , PULONG pulFirst , PULONG ppVRAM ) { SCRNTX scrnTx; SCRNRX scrnRx; BOOL fAttach; USHORT usAction; if (DosOpen( szSQ , &hSVGA , &ulAction , 0, 0, 1, 0x00c0, 0)) { goto getvram_exit; } scrnTx.stx_Address = ulAddr; scrnTx.stx_Size = ulSize; scrnTx.stx_flFlag = 0; if ( !*pulFirst ) { fAttach = 0; usAction = 0x007e; *pulFirst = 1; } else { usAction = 0x007f; scrnTx.stx_Address = *ppVRAM; fAttach = 1; } if ( !DosDevIOCtl( hSVGA, 3, usAction, &scrnTx, sizeof(SCRNTX), 0, &scrnRx, sizeof(SCRNRX), 0) ) { if ( fAttach == 0) { *ppVRAM = scrnRx.srx_ScrnPtr; } } DosClose( hSVGA ); getvram_exit: return( 1L ); }
The preceding code is designed to be called only once upon initialization of the driver and during the once-per-subsequent process that needs the linear address. The linear address returned on the first invocation of the GetVRAMPointer is valid only in the process that called GetVRAMPointer. GRE is multithreaded, so multiple processes use the S3 driver DLL. Each of these processes must have the linear address added to their page tables.
The PMDD.SYS module uses the DevHlp_VMALLOC to obtain the linear address to the physical memory. The pointer returned by the above code is usable anywhere in the driver except in MoveCursor32. (The pointer is unusable in MoveCursor32 because it is called at interrupt time. The pointer returned by the PMDD.SYS module exists only within the context of any process that has attached to it. The ring 0 code that calls MoveCursor32 does not have the pointer in its address space.)
To get a pointer to the aperture or memory-mapped registers that is usable from MoveCursor32, use DevHlp_PhysToGDTSel. (Refer to the XGA ring 0 driver for an example.) The function GetInstanceGDT in the xgaring0.asm file gives an example of using PhysToGDTSel to get a selector:offset pointer to the XGA driver's memory-mapped registers. If you need a flat pointer that can be used by MoveCursor32, implement your own ring 0 physical device driver that uses VMALLOC to create a linear mapping in the global, system linear space. To use it, you would have to guarantee that MoveCursor32 ran at ring 2, because ring 3 processes cannot access memory in the system space. (OS/2 reserves linear addresses above 512MB for use by operating system.)
It is also possible to get a flat pointer to the video aperture by way of an IOCtl to the SCREEN01.SYS file. The source code to the SCREEN01.SYS file is in the IBM Device Driver Source Kit for OS/2. The code to get the flat pointer is GetLinearAccess, in \ DDK\SCR_S3\DEV\SCREENDD\SVGAROUT.ASM. The device name used to access SCREEN01.SYS is "SCREEN$". The IOCtl number is 0xb. The packet used for this IOCtl is the following:
GetLinear_Packet STRUC PacketLength DD 0H ; total size of data packet PhysicalAddress DD 0H ; Physical address of aperture ApertureSize DD 0H ; Size of aperture LinearAddress DD 0H ; Linear address of aperture ( GetLinear_Packet ENDS
The location of the video aperture is the PhysicalAddress. ApertureSize is the size (in bytes) of the video aperture. The LinearAddress field returns the linear address of the device. The address returned will be valid only within the context of the process that called the IOCtl. Also, it is not guaranteed that this IOCtl will return the same linear address for each process. Consequently, if you use this IOCtl, you must keep track of which pointer belongs to which process that is using the driver. (MATROX.C in the S3 driver has an example of how to do this).
The XGA ring 0 driver also has an IOCtl for obtaining a flat pointer to video memory. (In this case, the XGA 1MB aperture.) The function flat_access, can be found in the file \..\..\XGASYS20\XGARING0.ASM. This function calls VMALLOC to obtain a flat pointer to the XGA aperture. The IOCtl function code for flat_access is 0x14. An example of how to call this particular IOCtl can be found in the S3 driver in MATROX.C.
For accessing flat data at ring 3, use selector 53 hex. (Accessing data at ring 3 is always true for code that is not running as part of the system at ring 0.) If a protection fault in the driver appears (Trap d), check the segment register being used to access the data. A segment register other than 0x53 could be part of the cause of the trap.