Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

_physmem.c

Go to the documentation of this file.
00001 
00002 #include "rcs_defs.hh"          /* __MSDOS__, _WINDOWS,RCS_FAR */
00003 #include "_physmem.h"
00004 
00005 #ifndef WIN32
00006 #ifdef __MSDOS__
00007 #ifdef _WINDOWS
00008 #include <windows.h>
00009 
00010 #ifndef __BORLANDC__
00011 #ifdef __cplusplus
00012 extern "C" WORD _0000h;
00013 extern "C" WORD _0040h;
00014 extern "C" WORD _A000h;
00015 extern "C" WORD _B000h;
00016 extern "C" WORD _B800h;
00017 extern "C" WORD _C000h;
00018 extern "C" WORD _D000h;
00019 extern "C" WORD _E000h;
00020 extern "C" WORD _F000h;
00021 #else
00022 extern WORD _0000h;
00023 extern WORD _0040h;
00024 extern WORD _A000h;
00025 extern WORD _B000h;
00026 extern WORD _B800h;
00027 extern WORD _C000h;
00028 extern WORD _D000h;
00029 extern WORD _E000h;
00030 extern WORD _F000h;
00031 #endif
00032 #endif
00033 
00034 #else
00035 #include <stdio.h>              // fprintf()
00036 #include <dos.h>                // _REGS, _SREGS
00037 #endif
00038 #endif
00039 #endif
00040 
00041 #include <string.h>             // memcpy()
00042 
00043 int
00044 read_physmem (unsigned long source, void *destination, long bytes)
00045 {
00046 
00047 #ifndef WIN32
00048 #ifdef _WINDOWS
00049 
00050   LPBYTE lpDestination;
00051   LPBYTE lpSource;
00052   WORD wSelector;
00053   int i;
00054 
00055   lpDestination = (LPBYTE) destination;
00056   lpSource = create_ptr_to_physmem (source, bytes, &wSelector);
00057 
00058   if (NULL == lpSource || NULL == lpDestination)
00059     {
00060       return (-1);
00061     }
00062 
00063 
00064   for (i = 0; i < bytes; i++)
00065     {
00066       lpDestination[i] = lpSource[i];
00067     }
00068   if (wSelector)
00069     {
00070       FreeSelector (wSelector);
00071     }
00072   return (i);
00073 #else
00074   char far *ptr_to_destination;
00075   char far *ptr_to_source;
00076   unsigned long physical_source_address;
00077   unsigned long physical_destination_address;
00078   unsigned long temp_segment, temp_offset;
00079   static char two_bytes[2];
00080   char far *ptr_to_two_bytes;
00081   int i;
00082 
00083   if (((unsigned long) destination) < 0x100000UL)
00084     {
00085       ptr_to_source = (char far *)
00086         ((source & 0xf) + ((source & 0xffff0L) << 16));
00087       ptr_to_destination = (char far *) destination;
00088       for (i = 0; i < bytes; i++)
00089         {
00090           ptr_to_destination[i] = ptr_to_source[i];
00091         }
00092       return (i);
00093     }
00094   else
00095     {
00096       physical_source_address = source;
00097       temp_segment = (((unsigned long) destination) & 0xffff0000L) >> 16;
00098       temp_offset = ((unsigned long) destination) & 0x0000ffffL;
00099       physical_destination_address = (temp_segment << 4) + temp_offset;
00100       if (0 == (bytes % 2))
00101         {
00102           return (move_physmem (physical_destination_address,
00103                                 physical_source_address, bytes));
00104         }
00105       else
00106         {
00107           if (bytes > 1)
00108             {
00109               if (-1 == move_physmem (physical_destination_address,
00110                                       physical_source_address, bytes))
00111                 {
00112                   return -1;
00113                 }
00114             }
00115           ptr_to_two_bytes = (char far *) two_bytes;
00116           temp_segment =
00117             (((unsigned long) ptr_to_two_bytes) & 0xffff0000L) >> 16;
00118           temp_offset = ((unsigned long) ptr_to_two_bytes) & 0x0000ffffL;
00119           physical_source_address = source + bytes - 1;
00120           physical_destination_address = (temp_segment << 4) + temp_offset;
00121           if (-1 == move_physmem (physical_destination_address,
00122                                   physical_source_address, 2))
00123             {
00124               return -1;
00125             }
00126           ((char *) destination)[bytes - 1] = (char) two_bytes[0];
00127           return (0);
00128         }
00129     }
00130 #endif
00131 #endif
00132   return (-1);                  /* No Applicable PLATFORM  */
00133 }
00134 
00135 int
00136 write_physmem (unsigned long destination, void *source, long bytes)
00137 {
00138 #ifndef WIN32
00139 #ifdef _WINDOWS
00140 
00141   LPBYTE lpDestination;
00142   LPBYTE lpSource;
00143   WORD wSelector;
00144   DWORD max_size;
00145   int i;
00146 
00147   lpDestination = create_ptr_to_physmem (destination, bytes, &wSelector);
00148   lpSource = (LPBYTE) source;
00149 
00150   if (NULL == lpSource || NULL == lpDestination)
00151     {
00152       return (-1);
00153     }
00154 
00155 
00156   for (i = 0; i < bytes; i++)
00157     {
00158       lpDestination[i] = lpSource[i];
00159     }
00160 
00161   if (wSelector)
00162     {
00163       FreeSelector (wSelector);
00164     }
00165   return (i);
00166 #else
00167   char far *ptr_to_destination;
00168   char far *ptr_to_source;
00169   unsigned long physical_source_address;
00170   unsigned long physical_destination_address;
00171   unsigned long temp_segment, temp_offset;
00172   int i;
00173   static char two_bytes[2];
00174   char far *ptr_to_two_bytes;
00175 
00176   if (destination < 0x100000UL)
00177     {
00178       ptr_to_source = (char far *) source;
00179       ptr_to_destination = (char far *)
00180         ((destination & 0xf) + ((destination & 0xffff0L) << 16));
00181       for (i = 0; i < bytes; i++)
00182         {
00183           ptr_to_destination[i] = ptr_to_source[i];
00184         }
00185       return (i);
00186     }
00187   else
00188     {
00189       temp_segment = (((unsigned long) source) & 0xffff0000L) >> 16;
00190       temp_offset = ((unsigned long) source) & 0x0000ffffL;
00191       physical_source_address = (temp_segment << 4) + temp_offset;
00192       physical_destination_address = destination;
00193       if (0 == (bytes % 2))
00194         {
00195           return (move_physmem (physical_destination_address,
00196                                 physical_source_address, bytes));
00197         }
00198       else
00199         {
00200           if (bytes > 1)
00201             {
00202               if (-1 == move_physmem (physical_destination_address,
00203                                       physical_source_address, bytes))
00204                 {
00205                   return -1;
00206                 }
00207             }
00208           two_bytes[0] = ((char *) source)[bytes - 1];
00209           ptr_to_two_bytes = (char far *) two_bytes;
00210           temp_segment =
00211             (((unsigned long) ptr_to_two_bytes) & 0xffff0000L) >> 16;
00212           temp_offset = ((unsigned long) ptr_to_two_bytes) & 0x0000ffffL;
00213           physical_destination_address = destination + bytes - 1;
00214           physical_source_address = (temp_segment << 4) + temp_offset;
00215           if (-1 == move_physmem (physical_destination_address,
00216                                   physical_source_address, 2))
00217             {
00218               return -1;
00219             }
00220           return (0);
00221         }
00222     }
00223 #endif
00224 #endif
00225   return (-1);                  /* No Applicable PLATFORM  */
00226 }
00227 
00228 #ifdef WIN16
00229 
00230 LPBYTE
00231 create_ptr_to_physmem (unsigned long phys_addr, int bytes,
00232                        WORD FAR * ptr_to_selector)
00233 {
00234   LPBYTE lpPhysAddr;
00235   DWORD dwPhysAddrLinear;
00236   DWORD dwPhysAddrSegment;
00237   DWORD dwPhysAddrOffset;
00238   WORD wPhysAddrSelector;
00239   BOOL boolSynthesizeSelector;
00240   int max_size;
00241 
00242   if (NULL != ptr_to_selector)
00243     {
00244       *ptr_to_selector = 0;
00245     }
00246 
00247 #ifndef __BORLANDC__
00248   if (phys_addr < 0x100000UL)   // Is physical address below 1 MB
00249     {
00250       dwPhysAddrSegment = ((phys_addr & 0xf0000UL) >> 4);
00251       dwPhysAddrOffset = (phys_addr & 0xffff);
00252       boolSynthesizeSelector = FALSE;
00253       max_size = 0x10000UL - dwPhysAddrOffset;
00254       switch (dwPhysAddrSegment)
00255         {
00256         case 0:
00257           if (dwPhysAddrOffset < 0x400)
00258             {
00259               lpPhysAddr = (LPBYTE) MAKELONG (dwPhysAddrOffset, &_0000h);
00260             }
00261           else
00262             {
00263               dwPhysAddrOffset -= 0x400;
00264               max_size += 0x400;
00265               lpPhysAddr = (LPBYTE) MAKELONG (dwPhysAddrOffset, &_0040h);
00266             }
00267           break;
00268 
00269         case 0xA000:
00270           lpPhysAddr = (LPBYTE) MAKELONG (dwPhysAddrOffset, &_A000h);
00271           break;
00272         case 0xB000:
00273           if (dwPhysAddrOffset < 0x8000)
00274             {
00275               lpPhysAddr = (LPBYTE) MAKELONG (dwPhysAddrOffset, &_B000h);
00276             }
00277           else
00278             {
00279               dwPhysAddrOffset -= 0x8000;
00280               max_size += 0x8000;
00281               lpPhysAddr = (LPBYTE) MAKELONG (dwPhysAddrOffset, &_B800h);
00282             }
00283           break;
00284         case 0xC000:
00285           lpPhysAddr = (LPBYTE) MAKELONG (dwPhysAddrOffset, &_C000h);
00286           break;
00287         case 0xD000:
00288           lpPhysAddr = (LPBYTE) MAKELONG (dwPhysAddrOffset, &_D000h);
00289           break;
00290         case 0xE000:
00291           lpPhysAddr = (LPBYTE) MAKELONG (dwPhysAddrOffset, &_E000h);
00292           break;
00293         case 0xF000:
00294           lpPhysAddr = (LPBYTE) MAKELONG (dwPhysAddrOffset, &_F000h);
00295           break;
00296         default:
00297           boolSynthesizeSelector = TRUE;
00298           dwPhysAddrLinear =
00299             ((DWORD) dwPhysAddrSegment << 4L) + dwPhysAddrOffset;
00300           break;
00301         }
00302     }
00303   else
00304 #endif
00305     {
00306       if (0x100000 < bytes)
00307         {
00308           return (NULL);
00309         }
00310       max_size = bytes;
00311       dwPhysAddrLinear = MapPhysicalToLinear (phys_addr, bytes);
00312       boolSynthesizeSelector = TRUE;
00313     }
00314 
00315   if (max_size < bytes)
00316     {
00317       return (NULL);
00318     }
00319 
00320   if (boolSynthesizeSelector)
00321     {
00322       wPhysAddrSelector = SynthSelector (dwPhysAddrLinear, max_size);
00323       if (NULL != ptr_to_selector)
00324         {
00325           *ptr_to_selector = wPhysAddrSelector;
00326         }
00327       lpPhysAddr = GetSelectorPointer (wPhysAddrSelector);
00328     }
00329   return (lpPhysAddr);
00330 }
00331 
00332 /*--------------------------------------------------------------*/
00333 /*  This function is a shell for DPMI Map Physical To Linear.   */
00334 /*  Returns 0 if it failed or the physical address is below     */
00335 /*  1 MB. Returns the linear address if DPMI call succeeded.    */
00336 /*--------------------------------------------------------------*/
00337 DWORD
00338 MapPhysicalToLinear (DWORD dwPhysical, DWORD dwLength)
00339 {
00340   DWORD dwLinear = 0L;          // In case memory below 1 MB, we
00341   // don't want to return garbage.
00342 
00343   if (dwPhysical >= 0x100000L)  // Use only if above 1 MB.
00344     {
00345       _asm
00346       {
00347         push di push si mov bx, WORD PTR[dwPhysical + 2]        /* Load arguments. */
00348         mov cx, WORD PTR[dwPhysical]
00349           mov si, WORD PTR[dwLength + 2]
00350           mov di, WORD PTR[dwLength] mov ax, 800 h int 31 h     /* Issue DPMI call. */
00351         jc short error_return mov dx, bx mov ax, cx jmp short fine_return}
00352       error_return:_asm
00353       {
00354       xor ax, ax mov dx, ax}
00355       fine_return:_asm
00356       {
00357         mov WORD PTR[dwLinear + 2], dx  /* Return value. */
00358         mov WORD PTR[dwLinear], ax pop si pop di}
00359     }
00360   return dwLinear;
00361 }
00362 
00363 /*--------------------------------------------------------------*/
00364 /*   This function will allocate and initialize a selector.     */
00365 /*--------------------------------------------------------------*/
00366 WORD
00367 SynthSelector (DWORD dwLinearAddress, DWORD dwLength)
00368 {
00369   WORD tempSelector, selector = NULL;
00370   WORD data_segment;
00371 
00372   /* Allocate *one* temporary selector by using value of DS  */
00373   /* (DS contains selector of app's or DLL's DGROUP, which   */
00374   /* is less than 64K.) Then set the selector's base        */
00375   /* address and limit to the real values, which may be      */
00376   /* larger than 64K. Because the memory must be accessed by  */
00377   /* 16-bit code, it is necessary to allocate an array of    */
00378   /* tiled selectors. The temporary selector is used to     */
00379   /* force AllocSelector() to allocate an array with the     */
00380   /* proper number of tiled selectors each with the proper   */
00381   /* base and limit. Then, we free the single temporary      */
00382   /* selector.                         */
00383 #ifdef __BORLANDC__
00384   _asm
00385   {
00386   push ds pop ax mov data_segment, ax}
00387   tempSelector = AllocSelector (data_segment);
00388 #else
00389   _asm
00390   {
00391   push ds call AllocSelector mov tempSelector, ax}
00392 #endif
00393   if (tempSelector)             /* AllocSelector returns NULL on error. */
00394     {
00395       SetSelectorBase (tempSelector, dwLinearAddress);
00396       SetSelectorLimit (tempSelector, dwLength);
00397 
00398       selector = AllocSelector (tempSelector);
00399 
00400       SetSelectorLimit (tempSelector, 100L);
00401       FreeSelector (tempSelector);
00402     }
00403   return selector;
00404 }
00405 
00406 /*--------------------------------------------------------------*/
00407 /*   This function builds a pointer to the memory referenced    */
00408 /*   by the selector.                                           */
00409 /*--------------------------------------------------------------*/
00410 LPSTR
00411 GetSelectorPointer (WORD selector)
00412 {
00413   return (LPSTR) MAKELONG (0, selector);
00414 }
00415 
00416 #else
00417 
00418 /*****************************************************************************
00419 **
00420 **      Function:   move_physmem
00421 **
00422 **      Purpose:    The function movphy moves data from/to physical extended
00423 **                  memory.  This is done in word increments up to 64K bytes.
00424 **
00425 **      Args:
00426 **          target      Physical target address.
00427 **          source      Physical source address.
00428 **          wcount      Number of D16 words to transfer.
00429 **
00430 **      Returns:
00431 **          0           If transfer completed normally.
00432 **          nonzero     If BIOS transfer function failed.
00433 **
00434 **      Calls:
00435 **          fprintf, exit, memset, _int86x
00436 **
00437 *****************************************************************************/
00438 int
00439 move_physmem (unsigned long target, unsigned long source, long bcount)
00440 {
00441   static initialized = 0;       /* Has the CPU been checked. */
00442   static unsigned char addrln = 0;      /* Number of addr. lines CPU drives   */
00443   unsigned char gdt[48];        /* Global Descriptor Table,see below  */
00444   unsigned char far *g_p = gdt; /* Pointer to GDT loaded into SI & ES */
00445 
00446 #ifdef __BORLANDC__
00447   union REGS r;                 /* Structure of INTEL registers       */
00448   struct SREGS s;               /* Structure of INTEL segment reg's   */
00449 #endif
00450 #ifdef _MSC_VER
00451   union _REGS r;                /* Structure of INTEL registers       */
00452   struct _SREGS s;              /* Structure of INTEL segment reg's   */
00453 #endif
00454 
00455   /* Movphy can not transfer more than (32K - 1) words */
00456   if (bcount >= 0x7ffffL)
00457     {
00458       fprintf (stderr, "\nTransfer length too large.\n");
00459       return (-1);
00460     }
00461 
00462   /*****************************************************************************
00463    **
00464    **      Identify system processor type and its addressing capability.
00465    **
00466    *****************************************************************************/
00467 
00468   if (!initialized)
00469     {
00470       /*lint -e122 */
00471 #ifdef __BORLANDC__
00472       asm
00473       {
00474 #else
00475       __asm
00476       {
00477 #endif
00478         /* 8086 CPU check */
00479         /* Bits 12-15 are always set on the 8086 processor. */
00480         pushf;                  /* Save EFLAGS.                      */
00481         pop bx;                 /* Store EFLAGS in BX                */
00482         mov ax, 0f ffh;         /*   clear bits 12-15                */
00483         and ax, bx;             /*     in EFLAGS                     */
00484         push ax;                /* Store new EFLAGS value on stack.  */
00485         popf;                   /* Replace current EFLAGS value.     */
00486         pushf;                  /* Set new EFLAGS.                   */
00487         pop ax;                 /* Store new EFLAGS in AX.           */
00488         and ax, 0f 000 h;       /* If bits 12-15 are set, then the   */
00489         cmp ax, 0f 000 h;       /*   CPU is an 8086/8088.            */
00490         mov addrln, 20;         /* Set the number of address lines   */
00491         /*   for a 8086/8088.                */
00492         je nodescriptors;
00493 
00494 
00495         /* 80286 CPU check */
00496         /* Bits 12-15 are always clear on the 80286 processor. */
00497 
00498         or bx, 0f 000 h;        /* Try to set bits 12-15             */
00499         push bx;                /*  */
00500         popf;                   /*  */
00501         pushf;                  /*  */
00502         pop ax;                 /*  */
00503         and ax, 0f 000 h;       /* If bits 12-15 are cleared, then   */
00504         /*   the CPU is an 80286             */
00505         mov addrln, 24;         /* Set the number of address lines   */
00506         /*   for a 80286.                    */
00507         jz descriptors;         /*  */
00508 
00509 
00510         /* Otherwise it is an i386 or later CPU with 32 bit addressing. */
00511         mov addrln, 32;         /* Set the number of address lines   */
00512         /* for either a i386 or later CPU's. */
00513       }
00514       /*lint +e122 */
00515 
00516 
00517     nodescriptors:
00518       if (addrln < 24)
00519         {
00520           fprintf (stderr,
00521                    "\nThis system does not support protected mode.\n");
00522           return (-1);
00523         }
00524 
00525       /* For i286 check against A24 address limit. */
00526     descriptors:
00527       if ((addrln < 32) && (source >= (1UL << 24) || target >= (1UL << 24)))
00528         {
00529           fprintf (stderr, "\nA24 Address out of bounds.\n");
00530           return (-1);
00531         }
00532       initialized = 1;
00533     }
00534 
00535   /*****************************************************************************
00536    **
00537    **      Format of descriptors
00538    **
00539    **    Offset    Size                Description
00540    **
00541    **     00h        2 Bytes        Bits 0-15 of the segment limit.
00542    **
00543    **     02h        3 Bytes        Bits 0-23 of physical address.
00544    **
00545    **     05h        1 Byte         i386 & i486 Access flags:
00546    **                               9Ah = Code segment.
00547    **                               92h = Writable data segment.
00548    **                               90h = Read only data segment.
00549    **
00550    **                               80286 Access flags:
00551    **                               9Bh = Code segment.
00552    **                               93h = Writable data segment.
00553    **                               91h = Read only data segment.
00554    **
00555    **     06h        2 Bytes        Reserved on an 80286, must be zero.
00556    **
00557    **                               A32 Processors Only.
00558    **     06h        1 Byte         Bits 0-3 are the upper 4 bits of the
00559    **                               segment limit.  Bits 4-7 are set to zero.
00560    **                               Please note that this byte is not supported
00561    **                               by Interrupt 0x15 Function 0x87.
00562    **
00563    **                               A32 Processors Only.
00564    **     07h        1 Byte         Bits 24-32 of physical address.
00565    **
00566    *****************************************************************************/
00567 
00568   memset (gdt, '\0', sizeof (gdt));     /* Zero out global descripter table  */
00569 
00570   /* Descripter 2: Source */
00571   gdt[16] = (unsigned char) bcount;
00572   gdt[17] = (unsigned char) (bcount >> 8);
00573   gdt[18] = (unsigned char) source;
00574   gdt[19] = (unsigned char) (source >> 8);
00575   gdt[20] = (unsigned char) (source >> 16);
00576 
00577   if (addrln < 32)
00578     {
00579       gdt[21] = 0x93;           /* A24 Access flag */
00580     }
00581   else
00582     {
00583       gdt[21] = 0x92;           /* A32 Access flag */
00584       gdt[23] = (unsigned char) (source >> 24);
00585     }
00586 
00587   /* Descripter 3: Target */
00588   gdt[24] = (unsigned char) bcount;
00589   gdt[25] = (unsigned char) (bcount >> 8);
00590   gdt[26] = (unsigned char) target;
00591   gdt[27] = (unsigned char) (target >> 8);
00592   gdt[28] = (unsigned char) (target >> 16);
00593 
00594   if (addrln < 32)
00595     {
00596       gdt[29] = 0x93;           /* A24 Access flag */
00597     }
00598   else
00599     {
00600       gdt[29] = 0x92;           /* A32 Access flag */
00601       gdt[31] = (unsigned char) (target >> 24);
00602     }
00603 
00604   r.h.ah = 0x87;
00605   r.x.cx = (int) (bcount / 2);
00606   s.es = (((unsigned long) g_p) & 0xffff0000L) >> 16;
00607   r.x.si = ((unsigned long) g_p) & 0x0000ffffL;
00608 
00609 #ifdef __BORLANDC__
00610   int86x (0x15, &r, &r, &s);
00611 #endif
00612 
00613 #ifdef _MSC_VER
00614   (void) _int86x (0x15, &r, &r, &s);
00615 #endif
00616 
00617   if (r.h.ah)
00618     {
00619       switch (r.h.ah)
00620         {
00621         case 1:
00622           /* RAM parity error occurred */
00623           fprintf (stderr,
00624                    "\nData transfer failed.  A RAM parity error occurred.\n");
00625           break;
00626 
00627         case 2:
00628           /* Exception interrupt error occurred */
00629           fprintf (stderr,
00630                    "\nData transfer failed.  Exception interrupt error occurred.\n");
00631           break;
00632 
00633         case 3:
00634           /* Gating address line 20 failed during switch to protected mode */
00635           fprintf (stderr,
00636                    "\nData transfer failed.  Gate address line 20 failed.\n");
00637           break;
00638 
00639         default:
00640           /* Unknown reason-word count > 32767 */
00641           fprintf (stderr,
00642                    "\nData transfer failed.  Reason unknown, possibly word count > 32767.\n");
00643           break;
00644         }
00645       return (-1);
00646     }
00647 
00648 
00649   return (bcount);
00650 }
00651 
00652 #endif
00653 
00654 
00655 
00656 
00657 // This is the information from Microsoft  that much of the code in this file is
00658 // based on.
00659 #if 0
00660 
00661 From rippey @ cme.nist.gov Wed Jun 5 09:46:29 1996
00662   Date:5 Jun 1996 09:43:35 U
00663   From:"Bill Rippey" < rippey @ cme.nist.gov >
00664   Subject:Net info on physical memory
00665   To:"Will Shackleford" < shackle @ isdmail >
00666   Content - Length:14745
00667   Subject:Time:9:43 AM
00668   OFFICE MEMO Net info on physical memory Date:6 / 5 / 96
00669   Here is the bulletin I grabbed off the network.
00670   -- ---ftp.microsoft.com / developr / win_dk / ddk / 105 / 6 / 43
00671   DOCUMENT:Q105643 05 - JAN - 1995[win16sdk]
00672   TITLE:Accessing Physical Memory in Windows 3.0 and 3.1
00673   PRODUCT:Microsoft Windows Software Development Kit
00674   PROD / VER:3.00 3.10
00675   OPER / SYS:WINDOWS
00676   KEYWORDS:kbprg-- --
00677   ------------------------------------------------------------------The
00678   information in this article applies to:-Microsoft Windows Software
00679   Development
00680 Kit (SDK) for Windows,
00681   versions 3.0 and 3.1-- --
00682   ------------------------------------------------------------------SUMMARY ==
00683   == == =
00684   Some applications need to access memory at a particular physical address
00685   fixed in the address space of the microprocessor.
00686   Such applications typically interact directly with memory -
00687   mapped hardware device interface cards,
00688   or may need to read the computer CMOS settings.
00689   
00690   This article outlines two methods to access physical memory in Windows
00691   protected mode (standard mode or 386 enhanced mode)
00692   .MORE INFORMATION == == == == == == == ==
00693     Method 1:Exported Selectors (Preferred)-- --
00694     ------------------------------------The Windows 3.0 and 3.1 Kernels export
00695     several selectors that should be used by applications that require access
00696     to physical memory located below the 1 megabyte (MB) boundary.
00697     The exported selectors are:__0000h, __0040h, __A000h, __B000h, __B800h,
00698     __C000h, __D000h, __E000h, and __F000h To use one of these selectors,
00699     place it onto a segment register and access the memory or create a long
00700        pointer.Here are examples using the Microsoft Macro Assembler (MASM)
00701      and Microsoft C:In ASM:extern __0040h ... mov ax, __0040h mov es,
00702        ax In C:extern WORD _0040h;
00703      LPSTR lpBIOSDataArea;
00704 ...
00705   /* Note the & and single underscore */
00706   lpBIOSDataArea = (LPSTR) MAKELONG (0, &_0040h);
00707 
00708      In
00709      C++:extern
00710        "C" WORD _0040h;
00711      LPSTR
00712        lpBIOSDataArea;
00713 ...
00714   /* Note the & and single underscore */
00715   lpBIOSDataArea = (LPSTR) MAKELONG (0, &_0040h);
00716 
00717      Each of these data selectors is limited to
00718      accessing 64 kilobytes (K).An attempt to read or write to data beyond the
00719   limit causes a general protection (GP) fault (evidenced by an unrecoverable
00720                                                 application error-- UAE)
00721      in protected
00722        mode.Performing segment arithmetic with
00723        these selectors also causes a GP fault.Finally,
00724      do
00725        not free these
00726          selectors once they are no longer needed.Method 1 is always
00727          recommended and should be used unless the exported selectors
00728        do
00729          not provide access to the necessary area of physical memory.Method
00730            2:Selector Synthesis-- --
00731            ------------------------Selector synthesis should be used when an
00732            application needs to access physical memory that is not addressable
00733            with the selectors exported from the Windows Kernel.
00734            This method involves allocating a new selector and initializing the
00735            associated descriptor with the appropriate values.The functions to
00736          do
00737            this are provided through the Windows Kernel and the MS -
00738              DOS Protected Mode Interface (DPMI) server (which is a part of
00739                                                          Windows).
00740              The required functions include the following:Function
00741              Description-- --
00742              ---------------Map Physical To Linear (DPMI:Interrupt 31 h, AX =
00743                                                     0800 h) Maps a 32 -
00744              bit physical address to a 32 -
00745              bit linear address.In 386 enhanced mode this function is required
00746              because because linear addresses are different from physical
00747              addresses and the selector functions can work only with linear
00748              addresses.In standard mode,
00749              this function is not required because linear addresses are the
00750              same as physical addresses.AllocSelector (WORD
00751                                                        wSelector) (Kernel) Allocates a new selector
00752        or array of tiled selectors and copies the attributes of wSelector to
00753        the new selector (s).
00754        If the limit of wSelector is less than or equal to 64 K,
00755        then only one selector is allocated.
00756        If the limit of wSelector is larger than 64 K,
00757        an array of tiled selectors is allocated such that each selector points
00758        to one 64 K portion of the limit of wSelector.FreeSelector (WORD
00759                                                                    wSelector)
00760        (Kernel) Frees either a single
00761        selector or an array of tiled selectors depending on the limit of
00762        wSelector.
00763        Frees one selector for each 64 K portion of the limit of wSelector.
00764        The selector,
00765        or array of tiled selectors being freed must have been allocated
00766        previously by AllocSelector.Furthermore,
00767        the limit of wSelector must be the same as the selector used as a
00768        parameter to the call to AllocSelector.SetSelectorBase (WORD wSelector,
00769                                                                DWORD dwBase)
00770      (Kernel) Stores the starting
00771        linear
00772        address of the desired region in the
00773        descriptor of wSelector.SetSelectorLimit (WORD wSelector,
00774                                                  DWORD dwLimit) (Kernel) Stores the length of the
00775      desired region in the descriptor of wSelector.GetSelectorLimit (WORD
00776                                                                      wSelector)
00777        (Kernel) Retrieves the length of
00778        the region pointed to by wSelector.
00779        This length comes from wSelector descriptor.Caveats:1. These routines
00780      do
00781        not inform the Windows memory manager that a particular block of memory
00782          is in use.
00783          
00784          It is the responsibility of the caller to ensure that the area of
00785          memory will not be accessed or freed by some other process in the
00786          system.2. Synthesized selectors that alias a memory object allocated
00787          by Windows will not be updated if the memory object is moved.
00788          To make sure that the memory object will not be moved,
00789          call GlobalFix () on it before synthesizing a selector that aliases
00790        it.Note that if the synthesized selector points to memory provided by a
00791        physical device, there is no need to call GlobalFix ()
00792        because the device memory was not allocated by Windows.3. Allocating
00793          large numbers of selectors is discouraged because selectors are a
00794          limited resource.4. Allocating a selector does not actually allocate
00795          any memory:it merely creates a pointer that can be used to access
00796          existing memory (that was previously allocated or is provided by a
00797                           memory -
00798                           mapped hardware device).
00799          Do not confuse allocating a selector with allocating memory.The
00800          following code fragment has been written using the inline assembly
00801          feature of the Microsoft C and C++ compilers.
00802          This code illustrates the technique of selector synthesis.Sample
00803          Code-- -- -------DWORD MapPhysicalToLinear (DWORD, DWORD);
00804      WORD
00805      SynthSelector (DWORD, DWORD);
00806      LPSTR
00807      GetSelectorPointer (WORD);
00808 
00809      /* These prototypes are needed only for the Windows     */
00810      /* Software Development Kit (SDK) version 3.0.          */
00811      /* They are not needed in the Windows 3.1 SDK, because  */
00812      /* they are included in WINDOWS.H.                      */
00813      int FAR PASCAL
00814      SetSelectorBase (WORD, DWORD);
00815      int FAR PASCAL
00816      SetSelectorLimit (WORD, DWORD);
00817      DWORD FAR PASCAL
00818      GetSelectorLimit (WORD);
00819 
00820      LPSTR
00821        lpPhys;                  // Could be declared a huge ptr instead.
00822      DWORD
00823        dwPhysical, dwLinear, dwLength;
00824      WORD
00825        wSelector;
00826      WORD
00827        segment, offset;         // These variables are necessary only
00828      // if the target memory is addressed
00829      // with a "real-mode" style SEG:OFFSET
00830      // pointer.
00831 
00832    /*--------------------------------------------------------------*/
00833      /*        Sample Code to Synthesize a Selector                  */
00834    /*--------------------------------------------------------------*/
00835 
00836      /* Create a linear address.  The method to do this depends upon */
00837      /* where the memory is located.  Both methods are shown below,  */
00838      /* but only *one* must be used.                                 */
00839 
00840      /* If the selector will point to memory below 1 MB, create a  */
00841      /* linear address as follows (yes, this really is a linear   */
00842      /* address):                                                 */
00843 
00844      dwLinear = ((DWORD) segment << 4L) + offset;
00845 
00846      /* Otherwise, if the selector will point to memory above 1 MB, */
00847      /* dwPhysical should contain the 32-bit physical address.    */
00848      /* Call DPMI to convert dwPhysical to a linear address.      */
00849      /* Note that you must pass the physical address and the      */
00850      /* length (limit) to DPMI.                                   */
00851 
00852      dwPhysical = 0xC00000;     // This is physical 12 MB address,
00853      // (for example purposes only).
00854 
00855      dwLinear = MapPhysicalToLinear (dwPhysical, dwLength);
00856      if (!dwLinear)
00857        {
00858          // error...
00859        }
00860 
00861      /* Now that dwLinear contains the linear address, it's time  */
00862      /* to allocate the selector and then the far pointer from    */
00863      /* the selector. For memory regions larger than 64K, a huge  */
00864      /* pointer should be created instead of a far pointer.       */
00865 
00866      wSelector = SynthSelector (dwLinear, dwLength);    // Create selector.
00867      lpPhys = GetSelectorPointer (wSelector);   // Make a pointer.
00868 
00869      /* Use the pointer lpPhys to access memory...                */
00870 
00871      /* Free the selector when finished with it.  Don't need to   */
00872      /* make sure the selector's limit is less than 64K because   */
00873      /* SynthSelector creates an array of tiled selectors and we  */
00874      /* need to free them all.                                    */
00875 
00876      FreeSelector (wSelector);
00877 
00878      /* Rest of program...                                           */
00879 
00880    /*--------------------------------------------------------------*/
00881      /*  This function is a shell for DPMI Map Physical To Linear.   */
00882      /*  Returns 0 if it failed or the physical address is below     */
00883      /*  1 MB. Returns the linear address if DPMI call succeeded.     */
00884    /*--------------------------------------------------------------*/
00885      DWORD MapPhysicalToLinear (DWORD dwPhysical, DWORD dwLength)
00886      {
00887        DWORD dwLinear = 0L;     // In case memory below 1 MB, we
00888        // don't want to return garbage.
00889 
00890        if (dwPhysical >= 0x100000L)     // Use only if above 1 MB.
00891          {
00892            _asm
00893            {
00894              push di push si mov bx, WORD PTR[dwPhysical + 2];
00895              Load arguments.mov cx, WORD PTR[dwPhysical]
00896                mov si, WORD PTR[dwLength + 2]
00897                mov di, WORD PTR[dwLength] mov ax, 800 h int 31 h;
00898              Issue DPMI call.jc short error_return
00899                mov dx, bx
00900                mov ax, cx
00901                jmp short fine_return
00902                error_return:xor ax, ax
00903                mov dx, ax fine_return:mov WORD PTR[dwLinear + 2], dx;
00904            Return value.mov WORD PTR[dwLinear], ax pop si pop di}
00905          }
00906        return dwLinear;
00907      }
00908 
00909    /*--------------------------------------------------------------*/
00910      /*   This function will allocate and initialize a selector.     */
00911    /*--------------------------------------------------------------*/
00912      WORD SynthSelector (DWORD dwLinearAddress, DWORD dwLength)
00913      {
00914        WORD tempSelector, selector = NULL;
00915 
00916        /* Allocate *one* temporary selector by using value of DS  */
00917        /* (DS contains selector of app's or DLL's DGROUP, which   */
00918        /* is less than 64K.) Then set the selector's base        */
00919        /* address and limit to the real values, which may be      */
00920        /* larger than 64K. Because the memory must be accessed by  */
00921        /* 16-bit code, it is necessary to allocate an array of    */
00922        /* tiled selectors. The temporary selector is used to     */
00923        /* force AllocSelector() to allocate an array with the     */
00924        /* proper number of tiled selectors each with the proper   */
00925        /* base and limit. Then, we free the single temporary      */
00926        /* selector.                                               */
00927          _asm
00928        {
00929        push ds call AllocSelector mov tempSelector, ax}
00930 
00931        if (tempSelector)        /* AllocSelector returns NULL on error. */
00932          {
00933            SetSelectorBase (tempSelector, dwLinearAddress);
00934            SetSelectorLimit (tempSelector, dwLength);
00935 
00936            selector = AllocSelector (tempSelector);
00937 
00938            SetSelectorLimit (tempSelector, 100L);
00939            FreeSelector (tempSelector);
00940          }
00941        return selector;
00942      }
00943 
00944    /*--------------------------------------------------------------*/
00945      /*   This function builds a pointer to the memory referenced    */
00946      /*   by the selector.                                           */
00947    /*--------------------------------------------------------------*/
00948      LPSTR GetSelectorPointer (WORD selector)
00949      {
00950        return (LPSTR) MAKELONG (0, selector);
00951      }
00952 
00953      Additional reference words:3.00 3.10 Q80591
00954        KBCategory:kbprg
00955        KBSubcategory:KrMm
00956        == == == == == == == == == == == == == == == == == == == == == == == ==
00957        == == == == == == == == == == == == == == =
00958        THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED
00959        "AS IS" WITHOUT WARRANTY OF ANY KIND.
00960        MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED,
00961        INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00962        PARTICULAR PURPOSE.
00963        IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR
00964        ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL,
00965        CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES,
00966        EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE
00967        POSSIBILITY OF SUCH DAMAGES.
00968        
00969        SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR
00970        CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT
00971        APPLY.Copyright Microsoft Corporation 1995.
00972 #endif

Generated on Sun Dec 2 15:56:47 2001 for rcslib by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001