48 - Is your BIOS lying to you about it's RAM memory size?

Unique hits godaddy counter


Q: (OS) How much RAM can I use?
A: (BIOS) That depends on how you ask me!

Note: Latest version of GETMEM is now v1.5 (Aug 16 2011) - now shows whole memory map (including unusable RAM and Extended Attributes)

Many BIOSes today are unreliable when you try to run DOS on them, especially when using ram drives or DPMI extended memory handlers (cwsdpmi, EMM386, etc.). 
In my experience, many of these problems are caused by the BIOS not reporting the amount of free memory (RAM) correctly.

An Operating System can determine how much free memory there is by using an IBM compatible BIOS  Interrupt 15h routine.
DOS uses Int 15h AX=E801h - this returns the amount of contiguous free memory available up to 4GB - the specification is described here.
XP and later Operating Systems use the more recently defined BIOS call of Int 15h AX=E820h - this reports back a memory map to the Operating System. The map details the location, size and status of the memory areas within the CPU addressable memory map. For instance, if a system had free memory from 0 to 2GB and then from 4 to 6GB, a 64-bit operating system could use both areas of memory.

As nearly all systems and BIOSes are tested very thoroughly on Windows (7) before they are released, the Int 15h E820h memory map tends to be accurate. However, the value returned by the Int 15h E801h call is not always correct. This is a shame as most DOS utilities rely on this!

I have written the DOS utility GETMEM.EXE to check what different system BIOSes report back via these two BIOS Int 15h interfaces (E801 and E820).
If you run the DOS utility GETMEM (available in the Beta Downloads page), you will see that it displays the value returned by both calls and checks the values to see if it makes sense.
Note that you must boot to MS-DOS or FreeDOS (or IBM DOS,etc.) without any extended memory handlers loaded as some of these are naughty and patch the Int 15h interrupt hook! See Tutorial 37 for an example of how to make a bootable FreeDos USB drive.

You can also use the grub4dos displaymem command to list the Int 15h E820 memory map.

Note: the GETMEM Base and Length translations in the 3rd and 4th columns are rounded down to the nearest 1MiB, but the hex values in the first two columns are reported accurately.

Some GETMEM outputs from different systems are shown below, the first two systems are OK, but the Acer Aspire 7741G notebook appears to have some problems!



Below is an example from an Asus EeePC 1000H:


REM GET AND CHECK MEMORY MAP (INT 15h E820 and E801)  v1.1 2011-08-08 [SSi]
REM =======================================================================
REM BIOS call to Interrupt 15h AX=E801 returns amount of memory (max 4GB).
REM Interrupt 15h AX=E820 returns a map (base address and length of blocks)
REM DOS needs a contiguous block, it cannot cope with 'holes' in the memory
REM DOS uses AX=E801, Windows uses AX=E820
REM So the amount of contiguous memory reported by E801 should match or be
REM less than that reported by E820 - if not then DOS programs which use
REM extended memory may crash.
REM ERRORLEVEL=number of errors - 0 is OK, if not then check output.
REM =======================================================================
REM E801 AX=Extended1 - contiguous KB between 1-16MB, max. 15 MB
SET E801_AX=15360
REM E801 BX=Extended2 - contiguous 64KB between 16MB-4GB
SET E801_BX=15994
REM E801 CX=Configured1 - contiguous KB between 1-16MB, max. 15 MB
SET E801_CX=15360
REM E801 DX=Configured2 - contiguous 64KB between 16MB-4GB
SET E801_DX=15994
REM =======================================================================
REM   BASE ADDRESS (H)   LENGTH (BYTES)   Base Add(MB) Length(MB)
REM   ================   ================ ============ ============
REM B=0000000000000000 L=000000000009FC00 B=       0MB L=       0MB
REM B=0000000000100000 L=000000003F6A0000 B=       1MB L=    1014MB

SET E801=1015
SET E820_TOTAL=1015
SET E820_CONTIG=1015
REM INT 15h E801 ideally should be same as INT 15h E820 = OK
SET RMEMTEST_PARAM=1 1014
SET E801_64K_COUNT=16250
SET E820_64K_COUNT=16250
SET ERRORLEVEL=0


You can see that no problem was found. Both E801 and E820 report the same amount of memory is free for use by DOS (1015MiB). The memory map shows no 'holes' either.


Here is a DELL Inspiron 530:

REM GET AND CHECK MEMORY MAP (INT 15h E820 and E801)  v1.1 2011-08-08 [SSi]
REM =======================================================================
REM BIOS call to Interrupt 15h AX=E801 returns amount of memory (max 4GB).
REM Interrupt 15h AX=E820 returns a map (base address and length of blocks)
REM DOS needs a contiguous block, it cannot cope with 'holes' in the memory
REM DOS uses AX=E801, Windows uses AX=E820
REM So the amount of contiguous memory reported by E801 should match or be
REM less than that reported by E820 - if not then DOS programs which use
REM extended memory may crash.
REM ERRORLEVEL=number of errors - 0 is OK, if not then check output.
REM =======================================================================
REM E801 AX=Extended1 - contiguous KB between 1-16MB, max. 15 MB
SET E801_AX=15360
REM E801 BX=Extended2 - contiguous 64KB between 16MB-4GB
SET E801_BX=48873
REM E801 CX=Configured1 - contiguous KB between 1-16MB, max. 15 MB
SET E801_CX=15360
REM E801 DX=Configured2 - contiguous 64KB between 16MB-4GB
SET E801_DX=48873
REM =======================================================================
REM   BASE ADDRESS (H)   LENGTH (BYTES)   Base Add(MB) Length(MB)
REM   ================   ================ ============ ============
REM B=0000000000000000 L=000000000009E800 B=       0MB L=       0MB
REM B=0000000000100000 L=00000000BFD90000 B=       1MB L=    3069MB

SET E801=3070
SET E820_TOTAL=3070
SET E820_CONTIG=3070
REM INT 15h E801 ideally should be same as INT 15h E820 = OK
SET RMEMTEST_PARAM=1 3069
SET E801_64K_COUNT=49129
SET E820_64K_COUNT=49129
SET ERRORLEVEL=0

Again quite clean and the values match.


However, now look at the results when run GETMEM on an Acer Aspire 7741G notebook:


REM GET AND CHECK MEMORY MAP (INT 15h E820 and E801)  v1.4 2011-08-10 [SSi]
REM ========================================================================
REM BIOS call to Interrupt 15h AX=E801 returns amount of memory (max 4GB).
REM Interrupt 15h AX=E820 returns a map (base address and length of blocks)
REM DOS needs a contiguous block, it cannot cope with 'holes' in the memory
REM DOS typically uses AX=E801, Windows uses AX=E820
REM So the amount of contiguous memory reported by E801 should match or be
REM less than that reported by E820 - if not then DOS programs which use
REM extended memory may crash.
REM Notes: Columns 3 & 4 are rounded down to nearest 1MB only.
REM Ext Attrib=Extended Attributes (bit 0 set if valid value present)
REM T=Type   1=Free 2=Resvd 3=ACPI 4=NVS 5=Unusable 6=Hole else 'Other'
REM ERRORLEVEL=number of errors - 0 is OK, if not 0 then check output.
REM ========================================================================
REM E801 AX=Extended1 - contiguous KB between 1-16MB, max. 15 MB
SET E801_AX=15360
REM E801 BX=Extended2 - contiguous 64KB between 16MB-4GB
SET E801_BX=47720
REM E801 CX=Configured1 - contiguous KB between 1-16MB, max. 15 MB
SET E801_CX=15360
REM E801 DX=Configured2 - contiguous 64KB between 16MB-4GB
SET E801_DX=47720
REM ========================================================================
REM BASE ADDRESS (H)     LENGTH (BYTES)   BaseAd(MB) Length(MB) Ext Attrib T
REM ==================   ================ ========== ========== ========== =
REM B=0000000000000000 L=000000000009C400        0MB        0MB E=00000000 1
REM B=000000000009C400 L=0000000000003C00        0MB        0MB E=00000000 2
REM B=00000000000DC000 L=0000000000004000        0MB        0MB E=00000000 2
REM B=00000000000E4000 L=000000000001C000        0MB        0MB E=00000000 2
REM B=0000000000100000 L=00000000BB17C000        1MB     2993MB E=00000000 1
REM B=00000000BB27C000 L=0000000000006000     2994MB        0MB E=00000000 2
REM B=00000000BB282000 L=0000000000162000     2994MB        1MB E=00000000 1
REM B=00000000BB3E4000 L=000000000002B000     2995MB        0MB E=00000000 2
REM B=00000000BB40F000 L=0000000000060000     2996MB        0MB E=00000000 1
REM B=00000000BB46F000 L=0000000000001000     2996MB        0MB E=00000000 2
REM B=00000000BB470000 L=0000000000081000     2996MB        0MB E=00000000 4
REM B=00000000BB4F1000 L=000000000021E000     2996MB        2MB E=00000000 2
REM B=00000000BB70F000 L=0000000000008000     2999MB        0MB E=00000000 1
REM B=00000000BB717000 L=0000000000008000     2999MB        0MB E=00000000 2
REM B=00000000BB71F000 L=000000000005E000     2999MB        0MB E=00000000 1
REM B=00000000BB77D000 L=0000000000022000     2999MB        0MB E=00000000 4
REM B=00000000BB79F000 L=0000000000041000     2999MB        0MB E=00000000 1
REM B=00000000BB7E0000 L=000000000001F000     2999MB        0MB E=00000000 3
REM B=00000000BB7FF000 L=0000000000001000     2999MB        0MB E=00000000 1
REM B=00000000BB800000 L=0000000000800000     3000MB        8MB E=00000000 2
REM B=00000000E0000000 L=0000000010000000     3584MB      256MB E=00000000 2
REM B=00000000F060A000 L=0000000000001000     3846MB        0MB E=00000000 2
REM B=00000000FEAFF000 L=0000000000001000     4074MB        0MB E=00000000 2
REM B=00000000FEC00000 L=0000000000010000     4076MB        0MB E=00000000 2
REM B=00000000FED00000 L=0000000000000400     4077MB        0MB E=00000000 2
REM B=00000000FED1C000 L=0000000000004000     4077MB        0MB E=00000000 2
REM B=00000000FED20000 L=0000000000070000     4077MB        0MB E=00000000 2
REM B=00000000FEE00000 L=0000000000001000     4078MB        0MB E=00000000 2
REM B=00000000FF000000 L=0000000001000000     4080MB       16MB E=00000000 2

SET E801=2998
SET E820_TOTAL=2996
SET E820_CONTIG=2994
REM INT 15h E801 ideally should be same as INT 15h E820 =  ** POSSIBLE FAIL **
SET RMEMTEST_PARAM=1 2997
REM ERROR - E801 memory cannot be more than E820 total contiguous memory!
SET E801_64K_COUNT=47976
SET E820_64K_COUNT=47911
REM ERROR - E801 returned more 64K blocks available than E820!
SET ERRORLEVEL=3

You can see that E801 reports 2998MiB of RAM free, but the E820 map shows that only 2994 is actually contiguous (ignoring the lower 1MB area which we are not concerned with when using Himem or EMM386 or DPMI memory handlers under DOS). Something is clearly wrong, If DOS tries to use extended memory in this area, we may be accessing RAM which is actually used by the BIOS and so that area may become corrupted by the BIOS whilst DOS is using the same area for say a RAM Drive or extended memory buffer areas (e.g. cwsdpmi.exe).

Also the 64K available block count does not match, E801 reports 47976 blocks available (assumes all bottom 1MB is available), where as E820 reports only 47911 blocks are available - so which is correct? My guess is that the E820 map is correct because Windows XP+ uses this map, which means that the E801 result is incorrect!

One way to test if this area (in our case 2994 to 2998MiB) is really free to use, is to run a memory test which will test this area. One test I have used for many years and which I have found to be extremely good at finding memory issues under DOS  (up to 3.5GiB) is Gregoriev's AleGr MEMTEST.EXE. For this Acer notebook, we need to run the command line:

MEMTEST 2997 1 /fastdetect

This will test memory from the 1MiB start position for a length of 2997MiB - if the value returned by Int 15h E801h of this BIOS is correct, then this test should pass (64 passes are needed for a thorough test, but usually 1 pass will be sufficient if an area of memory is actually missing or being corrupted by the BIOS).

OR to just quickly test the top area that is under suspicion, we can use:

MEMTEST 2994 4 /fastdetect

to test base address areas of 2994MB, 2995MB, 2996MB and 2997MB.


Here is an example from an H61 based mainboard (using v1.3 of GETMEM):


REM GET AND CHECK MEMORY MAP (INT 15h E820 and E801)  v1.3 2011-08-10 [SSi]
REM =======================================================================
REM BIOS call to Interrupt 15h AX=E801 returns amount of memory (max 4GB).
REM Interrupt 15h AX=E820 returns a map (base address and length of blocks)
REM DOS needs a contiguous block, it cannot cope with 'holes' in the memory
REM DOS uses AX=E801, Windows uses AX=E820
REM So the amount of contiguous memory reported by E801 should match or be
REM less than that reported by E820 - if not then DOS programs which use
REM extended memory may crash.
REM ERRORLEVEL=number of errors - 0 is OK, if not then check output.
REM =======================================================================
REM E801 AX=Extended1 - contiguous KB between 1-16MB, max. 15 MB
SET E801_AX=15360
REM E801 BX=Extended2 - contiguous 64KB between 16MB-4GB
SET E801_BX=7936
REM E801 CX=Configured1 - contiguous KB between 1-16MB, max. 15 MB
SET E801_CX=15360
REM E801 DX=Configured2 - contiguous 64KB between 16MB-4GB
SET E801_DX=7936
REM =======================================================================
REM   BASE ADDRESS (H)   LENGTH (BYTES)   Base Add(MB) Length(MB)   Extnd Atts
REM   ================   ================ ============ ============ ==========
REM B=0000000000000000 L=000000000009EC00 B=       0MB L=       0MB E=00000001
REM B=0000000000100000 L=000000001FF00000 B=       1MB L=     511MB E=00000001
REM B=0000000020200000 L=000000001FE00000 B=     514MB L=     510MB E=00000001
REM B=0000000040200000 L=000000003A063000 B=    1026MB L=     928MB E=00000001
REM B=000000007A5C7000 L=0000000000002000 B=    1957MB L=       0MB E=00000001
REM B=000000007A685000 L=000000000017B000 B=    1958MB L=       1MB E=00000001
REM B=0000000100000000 L=0000000000600000 B=       0MB L=       6MB E=00000001

SET E801=512
SET E820_TOTAL=1957
SET E820_CONTIG=512
REM INT 15h E801 ideally should be same as INT 15h E820 = OK
SET RMEMTEST_PARAM=1 511
SET E801_64K_COUNT=8192
SET E820_64K_COUNT=8192
SET ERRORLEVEL=0


You can see that there is a hole at 512MB, so the E801 value correctly reports 512MB, but actually there is 2GB of RAM fitted.
This BIOS returns valid values (except that it did not like ECX=24h when calling Int 15h E820h and I had to change this to 18h to make it work!) - Series 6 chipset boards seem to have a 'hole' at 512MB.
The area around 512MB, 1024MB and 1948MB is most likely used by the on-board memory mapped USB EHCI, Network and Audio adapters which can be mapped in this Series 6 chipset to anywhere within the first 4GB of address space.



Example from DQ67OW Intel Series 6 chipset mainboard (using GETMEM v 1.4)

REM GET AND CHECK MEMORY MAP (INT 15h E820 and E801)  v1.4 2011-08-10 [SSi]
REM ========================================================================
REM BIOS call to Interrupt 15h AX=E801 returns amount of memory (max 4GB).
REM Interrupt 15h AX=E820 returns a map (base address and length of blocks)
REM DOS needs a contiguous block, it cannot cope with 'holes' in the memory
REM DOS typically uses AX=E801, Windows uses AX=E820
REM So the amount of contiguous memory reported by E801 should match or be
REM less than that reported by E820 - if not then DOS programs which use
REM extended memory may crash.
REM Notes: Columns 3 & 4 are rounded down to nearest 1MB only.
REM Ext Attrib=Extended Attributes (bit 0 set if valid value present)
REM T=Type   1=Free 2=Resvd 3=ACPI 4=NVS 5=Unusable 6=Hole else 'Other'
REM ERRORLEVEL=number of errors - 0 is OK, if not 0 then check output.
REM ========================================================================
REM E801 AX=Extended1 - contiguous KB between 1-16MB, max. 15 MB
SET E801_AX=15360
REM E801 BX=Extended2 - contiguous 64KB between 16MB-4GB
SET E801_BX=7936
REM E801 CX=Configured1 - contiguous KB between 1-16MB, max. 15 MB
SET E801_CX=15360
REM E801 DX=Configured2 - contiguous 64KB between 16MB-4GB
SET E801_DX=7936
REM ========================================================================
REM BASE ADDRESS (H)     LENGTH (BYTES)   BaseAd(MB) Length(MB) Ext Attrib T
REM ==================   ================ ========== ========== ========== =
REM B=0000000000000000 L=000000000009C000        0MB        0MB E=00000001 1
REM B=000000000009C000 L=0000000000004000        0MB        0MB E=00000001 2
REM B=00000000000E0000 L=0000000000020000        0MB        0MB E=00000001 2
REM B=0000000000100000 L=000000001FF00000        1MB      511MB E=00000001 1
REM B=0000000020000000 L=0000000000200000      512MB        2MB E=00000001 2
REM B=0000000020200000 L=000000001FE00000      514MB      510MB E=00000001 1
REM B=0000000040000000 L=0000000000200000     1024MB        2MB E=00000001 2
REM B=0000000040200000 L=000000003A776000     1026MB      935MB E=00000001 1
REM B=000000007A976000 L=000000000004B000     1961MB        0MB E=00000001 4
REM B=000000007A9C1000 L=0000000000009000     1961MB        0MB E=00000001 3
REM B=000000007A9CA000 L=00000000001FB000     1961MB        1MB E=00000001 2
REM B=000000007ABC5000 L=0000000000001000     1963MB        0MB E=00000001 1
REM B=000000007ABC6000 L=0000000000010000     1963MB        0MB E=00000001 2
REM B=000000007ABD6000 L=000000000001F000     1963MB        0MB E=00000001 4
REM B=000000007ABF5000 L=0000000000024000     1963MB        0MB E=00000001 2
REM B=000000007AC19000 L=0000000000043000     1964MB        0MB E=00000001 4
REM B=000000007AC5C000 L=0000000000220000     1964MB        2MB E=00000001 2
REM B=000000007AE7C000 L=0000000000184000     1966MB        1MB E=00000001 1
REM B=0000000100000000 L=0000000000600000        0MB        6MB E=00000001 1
REM B=000000007B800000 L=0000000002200000     1976MB       34MB E=00000001 2
REM B=00000000FED1C000 L=0000000000024000     4077MB        0MB E=00000001 2
REM B=00000000FF000000 L=0000000001000000     4080MB       16MB E=00000001 2

SET E801=512
SET E820_TOTAL=1964
SET E820_CONTIG=512
REM INT 15h E801 ideally should be same as INT 15h E820 = OK
SET RMEMTEST_PARAM=1 511
SET E801_64K_COUNT=8192
SET E820_64K_COUNT=8192
SET ERRORLEVEL=0

This is similar to the H61 result - again memory 'holes' are apparent, but DOS should not complain.


BIOSes can use areas of memory as 'scratchpad' areas, or keep important tables or even code there or map memory-based registers there. For instance, an area of RAM might be used to keep track of the battery status during charging/discharging. In this case, some bytes may be updated only every minute or so, and thus may be hard to detect even when running a memory test as the test fills and reads back each pattern quite quickly. Other uses can be for USB buffers, CPU registers, hard disk and network buffers, PXE code/buffers/scratchpad area, and so on.

Why not put GETMEM and MEMTEST on a DOS bootable USB stick and try them out on different systems (do not load any drivers - i.e. no CONFIG.SYS or TSR's loaded). 

See if your BIOS lies to you!

P.S. If you want to test memory above 3.5GB, I recommend the memory test that is part of the Windows 7 Recovery partition (64-bit) or Install DVD. This does test areas above 4GB (unlike some tests such as memtest86+ which look like they do, but actually don't!).