HOWTO: Determine the Amount of Physical Memory Installed

Last reviewed: October 3, 1997
Article ID: Q117889

The information in this article applies to:
  • Microsoft C/C++ for MS-DOS, version 7.0
  • Microsoft Visual C++ for Windows, versions 1.0, 1.5
  • Microsoft Visual C++ 32-bit Edition, versions 1.0, 2.0, 4.0, 5.0
  • Microsoft Macro Assembler (MASM) for MS-DOS, versions 5.1, 6.0
  • Microsoft MASM for MS-DOS and Windows NT, version 6.11

SUMMARY

You may want to programmatically determine the amount of physical memory installed in a computer. When the computer runs under an operating system that has virtual memory or emulates other operating systems, you may not be able to determine the amount of installed memory from the APIs that the particular operating system provides. In the case of 80x86-based machines, you can obtain that information from the CMOS data.

MORE INFORMATION

"Reading" CMOS data isn't as simple as obtaining a pointer to point to a particular memory location. You must output values to an I/O port and then read values from another port. The Run-Time Library functions "inp" and "outp" can be used in straight C/C++ code; or, you can use the in and out assembly instructions with MASM programs (or with inline assembly in version 6.0 and later of the compiler).

The procedure is straightforward: write values to I/O port 0x70 and read them from 0x71. The values 0x15 and 0x16 are used to get the amount of base memory installed, while 0x17 and 0x18 are used to get the amount of expansion memory (up to 15360 kilobytes) installed. Expansion memory is memory above the 1-MB boundary and should not be confused with expanded memory.

Under Win32, the _inp and _outp functions are system-level (priveleged) instructions. Attempting to use Example 1 of the Sample Code below will result either in unresolved externals at link, _inp and _outp, (when using the C functions) or an Application Error at execution (when using the ASM functions). However, one may simply call the Win32 GlobalMemoryStatus API using a pointer to a MEMORYSTATUS structure to determine the amount of physical memory. See Example 2 below.

Sample Code #1

/* Compile options needed: none
*/

   #include <conio.h>
   #include <stdio.h>

   unsigned short GetBaseMemC();
   unsigned short GetExpMemC();
   unsigned short GetBaseMemASM();
   unsigned short GetExpMemASM();

void main( void )
{
   printf( "\nGetBaseMemC() returns %u.\n", (unsigned int) GetBaseMemC() );
   printf( "\nGetExpMemC()  returns %u.\n", (unsigned int) GetExpMemC() );
   printf( "\nGetBaseMemASM() returns %u.\n",
            (unsigned int)GetBaseMemASM() );
   printf( "\nGetExpMemASM()  returns %u.\n",
            (unsigned int) GetExpMemASM() );
}
   unsigned short GetBaseMemC()
   {
       // using run-time library functions
       unsigned short base;
       outp( 0x70, 0x15 );
       base = inp( 0x71 ); // retrieve low byte
       outp( 0x70, 0x16 );
       base += inp(0x71) << 8; // retrieve hi-byte,
                               // shift and add to base
       return base; // return K's of base memory
   }

   unsigned short GetExpMemC()
   {
       // using run-time library functions
       unsigned short extend;
       outp( 0x70, 0x17 );
       extend = inp( 0x71 ); // retrieve low byte
       outp( 0x70, 0x18 );
       extend += inp(0x71) << 8; // retrieve hi-byte,
                                 // shift and add to extend
       return extend; // return K's of expansion memory
   }

   unsigned short GetBaseMemASM()
   {
       // using in-line assembly
       unsigned short base;
       _asm
       {
              mov dx, 71h // port to read from

              mov ax, 15h // lo-byte value
              out 70h, al // write to port
              jmp a       // allow bus to settle down
           a:
              in al, dx   // read from port
              mov byte ptr [base], al // write to lo-byte

              mov ax, 16h // hi-byte value
              out 70h, al // writing
              jmp b       // settling
           b:
              in al, dx   // reading
              mov byte ptr [base+1], al // write to hi-byte
       }

       return base; // return K's of base memory
   }

   unsigned short GetExpMemASM()
   {
       // using in-line assembly
       unsigned short extend;
       _asm
       {
              mov dx, 71h // port to read from

              mov ax, 17h // lo-byte value
              out 70h, al // write to port
              jmp a       // allow bus to settle down
           a:
              in al, dx   // read from port
              mov byte ptr [extend], al // write to lo-byte

              mov ax, 18h // hi-byte value
              out 70h, al // writing
              jmp b       // settling
           b:
              in al, dx   // reading
              mov byte ptr [extend+1], al // write to hi-byte
       }

       return extend; // return K's of expansion memory
   }


Sample Code #2

#include <stdio.h>
#include <windows.h>

DWORD MyGetMem(void) {
   MEMORYSTATUS MemoryStatus;

   memset( &MemoryStatus, sizeof(MEMORYSTATUS), 0 );
   MemoryStatus.dwLength = sizeof(MEMORYSTATUS);

   GlobalMemoryStatus( &MemoryStatus );

   return( MemoryStatus.dwTotalPhys );
}

void main( void )
{
   printf( "Physical memory install = %u bytes.\n", (unsigned int)
MyGetMem() ); }

REFERENCES

The "Programmer's PC Sourcebook," 2nd ed., published by Microsoft Press, contains more information about the layout of the CMOS data area.

The "Win32 Programmer's Reference" contains more information on the GlobalMemoryStatus function as does the Functions Reference of the SDKs : Win32 SDK : Win32 book included in the Visual C++ version 4.0 Books Online.

The "Run-Time Library Reference Manual" contains more information about the inp and outp functions.

Keywords          : CLngIss
Version           : MS- DOS:5.1,6.0,6.11,7.0;WIN3X:1.0,1.5;WINNT:1.0,2.0,4.0,5.0,6.11;
Platform          : MS-DOS NT WINDOWS
Issue type        : kbhowto


================================================================================


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: October 3, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.