What hardware device used to eat up 1.4GB of my 4GB RAM, and now suddenly after no hardware changes eats up 2.2GB?

This is more or less a continuation of

What hardware device eats up 1.4GB of my 4GB RAM?

While I have more or less accepted the solution there that for some mysterious reason, after a BIOS upgrade my graphics adapter suddenly reserved 1.4GB of memory (instead of reserving it dynamically), now (2 weeks after my notebook's warranty expired), after doing nothing special except perhaps trying out a few Linux live CDs (some of them loopback booted from a USB key) and a few times changing the boot options from UEFI to BIOS CSM and back, suddenly 800MB more are reserved.

And just to make it clear, this is not a Windows issue - both memtest and Linux also see that amount of memory. Only Lenovo Diagnostics still sees the full 4GB of memory (and it tested it and found no errors)

Here are screenshots from graphics driver diagnostics tool and from resource monitor:

New situation

(For reference, before 1435MB were reserved for hardware, and max graphics memory was 1138 MB).

Which obviously makes the problem much more urgent, since now half of my memory is "reserved by hardware".

Output of meminfo -r did not change much (the 4th memory range shrunk by almost 800MB):

MemInfo v2.10 - Show PFN database information
Copyright (C) 2007-2009 Alex Ionescu
www.alex-ionescu.com

Physical Memory Range: 0000000000001000 to 000000000009D000 (156 pages, 624 KB)
Physical Memory Range: 0000000000100000 to 0000000020000000 (130816 pages, 523264 KB)
Physical Memory Range: 0000000020200000 to 0000000040004000 (130564 pages, 522256 KB)
Physical Memory Range: 0000000040005000 to 0000000057D32000 (97581 pages, 390324 KB)
Physical Memory Range: 0000000100000000 to 000000011F600000 (128512 pages, 514048 KB)
MmHighestPhysicalPage: 1177088

As I don't trust UEFI any more after the previous stories with Samsung and Lenovo, I went into EFI shell - and dumped a few more info. I don't really know what this is all about, but perhaps this helps somebody:

memmap

Type       Start            End               # Pages          Attributes
BS_code    0000000000000000-0000000000000FFF  0000000000000001 000000000000000F
available  0000000000001000-000000000005AFFF  000000000000005A 000000000000000F
BS_data    000000000005B000-000000000005BFFF  0000000000000001 000000000000000F
BS_code    000000000005C000-0000000000086FFF  000000000000002B 000000000000000F
BS_data    0000000000087000-0000000000087FFF  0000000000000001 000000000000000F
BS_code    0000000000088000-000000000008FFFF  0000000000000008 000000000000000F
reserved   0000000000090000-000000000009FFFF  0000000000000010 000000000000000F
BS_code    0000000000100000-000000000010FFFF  0000000000000010 000000000000000F
available  0000000000110000-000000001FFFFFFF  000000000001FEF0 000000000000000F
reserved   0000000020000000-00000000201FFFFF  0000000000000200 000000000000000F
available  0000000020200000-0000000040003FFF  000000000001FE04 000000000000000F
reserved   0000000040004000-0000000040004FFF  0000000000000001 000000000000000F
available  0000000040005000-0000000057D31FFF  0000000000017D2D 000000000000000F
BS_data    0000000057D32000-0000000057D51FFF  0000000000000020 000000000000000F
available  0000000057D52000-000000005A34AFFF  00000000000025F9 000000000000000F
BS_data    000000005A34B000-000000005A360FFF  0000000000000016 000000000000000F
reserved   000000005A361000-000000005A562FFF  0000000000000202 000000000000000F
BS_data    000000005A563000-000000005AD21FFF  00000000000007BF 000000000000000F
available  000000005AD22000-0000000096B02FFF  000000000003BDE1 000000000000000F
LoaderData 0000000096B03000-0000000096B04FFF  0000000000000002 000000000000000F
available  0000000096B05000-0000000096B06FFF  0000000000000002 000000000000000F
LoaderData 0000000096B07000-0000000096B14FFF  000000000000000E 000000000000000F
LoaderCode 0000000096B15000-0000000096BD1FFF  00000000000000BD 000000000000000F
LoaderData 0000000096BD2000-00000000C9468FFF  0000000000032897 000000000000000F
available  00000000C9469000-00000000C9474FFF  000000000000000C 000000000000000F
LoaderCode 00000000C9475000-00000000C9668FFF  00000000000001F4 000000000000000F
available  00000000C9669000-00000000CA828FFF  00000000000011C0 000000000000000F
BS_data    00000000CA829000-00000000CAE22FFF  00000000000005FA 000000000000000F
available  00000000CAE23000-00000000CAE31FFF  000000000000000F 000000000000000F
BS_data    00000000CAE32000-00000000CD668FFF  0000000000002837 000000000000000F
available  00000000CD669000-00000000CDCD5FFF  000000000000066D 000000000000000F
BS_code    00000000CDCD6000-00000000D6268FFF  0000000000008593 000000000000000F
RT_code    00000000D6269000-00000000D6344FFF  00000000000000DC 800000000000000F
RT_code    00000000D6345000-00000000D6468FFF  0000000000000124 800000000000000F
RT_data    00000000D6469000-00000000D6FEDFFF  0000000000000B85 800000000000000F
RT_data    00000000D6FEE000-00000000D9E9EFFF  0000000000002EB1 800000000000000F
reserved   00000000D9E9F000-00000000DAC13FFF  0000000000000D75 000000000000000F
reserved   00000000DAC14000-00000000DAE9EFFF  000000000000028B 000000000000000F
ACPI_NVS   00000000DAE9F000-00000000DAF04FFF  0000000000000066 000000000000000F
ACPI_NVS   00000000DAF05000-00000000DAF9EFFF  000000000000009A 000000000000000F
ACPI_recl  00000000DAF9F000-00000000DAFD9FFF  000000000000003B 000000000000000F
ACPI_recl  00000000DAFDA000-00000000DAFFEFFF  0000000000000025 000000000000000F
BS_data    00000000DAFFF000-00000000DAFFFFFF  0000000000000001 000000000000000F
available  0000000100000000-000000011F5FFFFF  000000000001F600 000000000000000F
reserved   00000000000A0000-00000000000BFFFF  0000000000000020 0000000000000000
reserved   00000000DB000000-00000000DF9FFFFF  0000000000004A00 0000000000000000
MemMapIO   00000000F80F8000-00000000F80F8FFF  0000000000000001 8000000000000001
MemMapIO   00000000FED1C000-00000000FED1FFFF  0000000000000004 8000000000000001

  reserved  :  24,115 Pages (98,775,040)
  LoaderCode:     689 Pages (2,822,144)
  LoaderData: 207,015 Pages (847,933,440)
  BS_code   :  34,263 Pages (140,341,248)
  BS_data   :  13,865 Pages (56,791,040)
  RT_code   :     512 Pages (2,097,152)
  RT_data   :  14,902 Pages (61,038,592)
  available : 748,703 Pages (3,066,687,488)
  ACPI_recl :      96 Pages (393,216)
  ACPI_NVS  :     256 Pages (1,048,576)
  MemMapIO  :       5 Pages (20,480)
Total Memory: 3,985 MB (4,179,152,896) Bytes

(as a UEFI noob, what does BS_data mean?)

dh -d

http://pastebin.com/KH1rFehj

(dh -v runs into an infinite loop and cannot be dumped...)

dmpstore (I edited out my Windows 8 Product Key):

http://pastebin.com/iYPcbpEY

Any ideas or any other ways to reclaim this memory (does anybody know if there is a working way to reset the UEFI NVRAM completely without making the machine unbootable?) are very much appreciated...

EDIT1

When booting Linux up in UEFI mode, most of the memory is usable.

/proc/meminfo

/proc/iomem

dmesg

But when booting it in Compatibility BIOS mode (via CSM) it is not:

/proc/iomem

dmesg

So probably a bug in the CSM? (But still surprising that it suddenly comes up...)

As my primary OS is Windows (7), I guess I'd have to upgrade to 8(.1) and perform a full reinstall on a GPT partition to make use of UEFI. And considering the problems that UEFI is (still) causing regularly, I'm not sure if I want to go that route...

EDIT2

I also posted a thread on Lenovo Forums about this, but no responses so far: http://forums.lenovo.com/t5/R-and-L-Series-ThinkPad-Laptops/L530-2481-3SG-First-1-4-GB-RAM-of-4-GB-reserved-by-hardware-and/td-p/1539272

I also (just to exclude this cause) removed the CMOS battery, but except some dark fingerprints I found on the "bottom door" (lid behind which the hard disk and RAM is hidden) it did not make me any wiser.

EDIT3

Not much news, some guy from Lenovo followed up to my post on the forum and said some engineer will have a look on it. Let's hope for the best.

EDIT4

Another 21MB have bitten the dust, this time for trying to boot a Linux distro via UEFI Secure Boot... More details in the above mentioned thread in Lenovo forums.

more memory lost


Solved :)

The cause seems to be a strange feature in the UEFI implementation, which can also be seen in the Open Source TianoCore implementation:

https://github.com/tianocore/edk2/blob/master/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsMisc.c#L1425

I ultimately found it after diffing my EFI variable dumps after the last 21MB "loss" and finding interesting variables:

Before losing the last 21MB of memory

Variable NV+RT+BS '4C19049F-4137-4DD3-9C10-8B97A83FFDFA:MemoryTypeInformationBackup' DataSize = 50
00000000: 09 00 00 00 60 00 00 00-0A 00 00 00 00 01 00 00 *....`...........*
00000010: 00 00 00 00 00 10 00 00-06 00 00 00 36 3A 00 00 *............6:..*
00000020: 05 00 00 00 00 02 00 00-03 00 00 00 00 8C 00 00 *................*
00000030: 04 00 00 00 00 40 00 00-01 00 00 00 00 02 00 00 *.....@..........*
00000040: 02 00 00 00 78 F2 03 00-0E 00 00 00 00 00 00 00 *....x...........*
Variable NV+RT+BS '4C19049F-4137-4DD3-9C10-8B97A83FFDFA:MemoryTypeInformation' DataSize = 50
00000000: 09 00 00 00 60 00 00 00-0A 00 00 00 00 01 00 00 *....`...........*
00000010: 00 00 00 00 00 10 00 00-06 00 00 00 36 3A 00 00 *............6:..*
00000020: 05 00 00 00 00 02 00 00-03 00 00 00 00 8C 00 00 *................*
00000030: 04 00 00 00 00 40 00 00-01 00 00 00 00 02 00 00 *.....@..........*
00000040: 02 00 00 00 38 E7 06 00-0E 00 00 00 00 00 00 00 *....8...........*

After losing them

Variable NV+RT+BS '4C19049F-4137-4DD3-9C10-8B97A83FFDFA:MemoryTypeInformationBackup' DataSize = 50
00000000: 09 00 00 00 60 00 00 00-0A 00 00 00 00 01 00 00 *....`...........*
00000010: 00 00 00 00 00 10 00 00-06 00 00 00 36 3A 00 00 *............6:..*
00000020: 05 00 00 00 00 02 00 00-03 00 00 00 00 8C 00 00 *................*
00000030: 04 00 00 00 00 40 00 00-01 00 00 00 00 02 00 00 *.....@..........*
00000040: 02 00 00 00 38 E7 06 00-0E 00 00 00 00 00 00 00 *....8...........*
Variable NV+RT+BS '4C19049F-4137-4DD3-9C10-8B97A83FFDFA:MemoryTypeInformation' DataSize = 50
00000000: 09 00 00 00 60 00 00 00-0A 00 00 00 00 01 00 00 *....`...........*
00000010: 00 00 00 00 00 10 00 00-06 00 00 00 36 3A 00 00 *............6:..*
00000020: 05 00 00 00 00 02 00 00-03 00 00 00 00 8C 00 00 *................*
00000030: 04 00 00 00 82 55 00 00-01 00 00 00 00 02 00 00 *.....U..........*
00000040: 02 00 00 00 38 E7 06 00-0E 00 00 00 00 00 00 00 *....8...........*

Why is this interesting: All the time I tested stuff, upgraded and downgraded the BIOS, changed settings, etc, these variables never changed (and I assumed they store some information about the make/model of my installed RAM or similar).

Now that my memory decreased, the value of MemoryTypeInformation got backed up as MemoryTypeInformationBackup (overwriting the old backup) and exactly one DWORD in the value changes - at offset 0x34: Old value was 0x4000, new value is 0x5582. The difference is 0x1582 or 5506 in decimal, which exactly matches the number of pages (4K blocks) my memory shrunk last time.

Going a step further: the old value of MemoryTypeInformation and MemoryTypeInformationBackup also differs in exactly one value (at a different offset though, 0x44). When comparing their values again, 0x2F4C0 or 193728 in decimal, is exactly again the number of pages my memory shrunk the time before (when the start address changed from 871F2000 to 57D32000).

Comparing this with the aforementioned TianoCore code, this suddenly makes perfect sense:

This code is triggered whenever the system is about to boot a boot option, and it verifies that the different UEFI memory regions have less allocated pages than stored in MemoryTypeInformation. If not, the memory map is incorrect and the variable is updated (with 125% of what is currently allocated) and a reboot is triggered, so that the memory map can be rebuilt from the latest data. Note that the implementation will never decrease any cached size for any memory type, so any change here will be permanent.

The problem here is that if UEFI boot fails, it will put you back into the boot selection menu (or in case it was a device on the default boot order, the next device is tried). As most UEFI boot loaders do not clean up after themselves in case of boot failure, as soon as the next menu is booted, this code will detect that some more memory has been allocated and therefore decides it has to update the memory map so that the following OS will not get into trouble. Unfortunately this repeats for every boot failure so that eventually there is a "hard limit" of how often you can fail booting :-(

The code in TianoCore also has fallback options in case the variable is missing or malformed (which, if I understand the code correctly may cost you up to two extra reboots, though), but considering the fact that Lenovo even included a Backup variable (which does not exist in TianoCore), I decided not to trust this fallback and reverted to the oldest backup I had, minus 800 MB for the LoaderData type, which gives me an effective 667 MB hardware reserved memory (good enough for now). And it works :)

solved memory map

Lessons learned

  • When an UEFI boot fails and you return to the boot menu, never try to boot anything else, better reset the system (I hope that will not trigger the code then; if it does, I'll update the post)

  • EFI Shell has a quite usable hex editor for editing EFI variables and fixing these issues

  • Even if your vendor cannot or does not want to help you - stay stubborn; eventually you will find a solution (even if months later)