How to squeeze 16 GB of memory onto a motherboard that does not support this amount

Original author: Doug Brown
  • Transfer
Some time ago, I installed 16 GB of memory on one of my computers. It has the Foxconn P55MX motherboard with a Core i5 750 on it. It would be possible to replace this old CPU, but it still works fine and does everything that I need.

Here is what is interesting. The motherboard does not officially support 16 GB of RAM. The specifications on the above page indicate that a maximum of 8 GB is supported. There are only two slots on the board, so I had a suspicion that 8GB strips were just a rarity at the time the motherboard came out. I decided to try anyway. In many cases, motherboards support more RAM than the manufacturer officially claims.

I made sure that the latest BIOS version (version 946F1P06) was installed and inserted two of my 8 gigabyte trims. Then I downloaded Ubuntu 16.04, and everything worked perfectly. I decided that my theory that the board supports more memory than stated in the documentation turned out to be correct, and I forgot about it. I liked working with additional RAM and I was happy that the game paid off.

But a few months later I tried to download Windows 10. Basically, the computer runs on Linux. Only sometimes you need to boot Windows to check something. It was then that the fun began.

When GRUB appeared, I selected Windows 10 from the menu and hit Enter. The Windows boot screen appeared briefly, and then I was immediately greeted by the blue screen of death.

Stop code: ACPI_BIOS_ERROR. I googled a lot and found out that the essence is in some kind of problem with ACPI tables in the BIOS. Among other things, ACPI tables tell the operating system how to configure hardware. Trying to boot from the Windows installation USB drive resulted in the same error. So, I think Foxconn didn’t lie. This computer really does not support 16 GB of RAM. Returning to 8 GB resulted in a successful download. The RAM tests were excellent too, so it's not a bad memory bar.

I tried to contact Foxconn support about fixing the BIOS, but did not receive a response. The email address is listed on their website, but it does not work. Perhaps Foxconn is no longer dealing with motherboards. It seems that they also do not provide support.

At this point, an ordinary person would just give up, resigned to 8 GB of memory or buying a new computer. But I didn’t want to give up so easily. I knew that theoretically a computer could use 16 GB because it worked perfectly on Linux. So I started learning ACPI and experimenting with BIOS settings.

I found an interesting BIOS section where you can play with some memory settings. One parameter was the “Memory Remap Feature”. She was included. The BIOS documentation says that the option allows "overlap PCI memory" for mapping above shared physical memory. A search on the Internet indicated that it must be enabled when booting into a 64-bit OS. Just for the sake of experiment, I turned it off, and Windows really booted! However, she said she could use less than 4 GB of RAM. But it was nice: I got a way to get into Windows without having to physically remove the memory bar.

Ubuntu is the same. With the memory remapping feature disabled, it limited me to less than 4 GB of RAM. At the moment, I was sure that there was some kind of memory mapping problem. I decided to study the ACPI_BIOS_ERROR error and its causes in more detail - and came across this excellent document for debugging Microsoft drivers, which explains ACPI_BIOS_ERROR error checking.

According to the document, it was necessary to find four error parameters that were previously displayed on a blue screen in older versions of Windows. Windows 10 hides all information by default, but you can re-enable the display of additional error information by adding an entry to the registry. Here is a great answer on that pointed me in the right direction .

After editing the registry accordingly, I again turned on the memory remapping function in the BIOS and booted Windows. BSOD has now shown four additional codes in the upper left corner:

Great! Thus, parameter 1 is 0x0000000000000002. The Microsoft documentation says that parameter 1, equal to 0x02, means a problem with processing the list of resources for PCI root buses. Since parameters 2, 3, and 4 look like crazy values, these are probably pointers. And if there are only pointers here, Microsoft says the problem is that the PCI decoding area overlaps with the list of memory areas returned by the E820 BIOS.

Okay There is a lot of information, but you can start the research with something. I found information how calling the E820 BIOS provides information about memory areas. Then he returned to Linux and looked at all the kernel start information using the dmesg command, with particular attention to the E820 and ACPI. Here is what was found:

BIOS-e820: [mem 0x0000000000000000-0x000000000009ebff] usable
BIOS-e820: [mem 0x000000000009ec00-0x000000000009ffff] reserved
BIOS-e820: [mem 0x00000000000e0000-0x00000000000fffff] reserved
BIOS-e820: [mem 0x0000000000100000-0x00000000cf77ffff] usable
BIOS-e820: [mem 0x00000000cf780000-0x00000000cf78dfff] ACPI data
BIOS-e820: [mem 0x00000000cf78e000-0x00000000cf7cffff] ACPI NVS
BIOS-e820: [mem 0x00000000cf7d0000-0x00000000cf7dffff] reserved
BIOS-e820: [mem 0x00000000cf7ed000-0x00000000cfffffff] reserved
BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
BIOS-e820: [mem 0x00000000ffb00000-0x00000000ffffffff] reserved
BIOS-e820: [mem 0x0000000100000000-0x000000042fffffff] usable

Later I saw this:

acpi PNP0A08: 00: ignoring host bridge window [mem 0x400000000-0xfffffffff
window] (conflicts with System RAM [mem 0x100000000-0x42fffffff])
PCI host bridge to bus 0000: 00
pci_bus 0000: 00: root bus resource [io 0x0000-0x0cf7 window]
pci_bus 0000: 00: root bus resource [io 0x0d00-0xffff window]
pci_bus 0000: 00: root bus resource [mem 0x000a0000-0x000bffff window]
pci_bus 0000: 00: root bus resource [mem 0x000d0000-0x000dffff window]
pci_bus 0000: 00: root bus resource [mem 0xd0000000-0xdfffffff window]
pci_bus 0000: 00: root bus resource [mem 0xf0000000-0xfed8ffff window]
pci_bus 0000: 00: root bus resource [bus 00-ff]

Yeah! See a conflict warning? I would not have noticed it, but after installing the memory, Linux began to display this message at each boot. I tried to boot into Linux with the memory remapping feature disabled in the BIOS. In this case, the last e820 region disappeared from 0x100000000 to 0x42fffffffff, and thus the conflict message also disappeared, and another “root bus resource” appeared in the list with the main bridge window from 0x400000000 to 0xfffffffff.

So what happens. Linux works with 16 GB because it notices a conflict and ignores the conflicting PCI range that ACPI provides, while Windows raises its hands in disgust and spits out a blue screen: “Your BIOS has a problem!” I can not blame Windows. Indeed, there is overlap, so you can understand that it is confused.

At this point, I was not sure whether to continue. The last 768 MB of memory, from 0x400000000 to 0x42fffffffffff, is mapped to the beginning of the huge area of ​​memory space that the motherboard uses for PCI. Clearly, if the motherboard expects PCI there, something really bad can happen. Thus, the motherboard only supports 15.25 GB of RAM, right?

But ... on Linux, everything works just fine, without the support of this additional PCI mapping area! What if we somehow modify the ACPI tables so that a large PCI range starts from 0x430000000 instead of 0x400000000, that is, immediately after the end of physical RAM. Then the conflict would disappear, and most of the PCI mapping window would still be available.

Challenge accepted.

I started digging into ACPI tables. Fortunately, Linux makes dumping very easy. There are special tools for this, but tables can be easily found in sysfs:

/ sys / firmware / acpi / tables

Here they are. I was also pleased that GRUB has the opportunity to replace your ACPI tables with new versions. Therefore, if you find out which table is involved, you can install a new version of this table using GRUB. Theoretically, Windows will be happy with this.

Among other tools, I used iasl to parse various ACPI tables and find the value 0x400000000 to replace. Most likely, this value is in reverse byte order (little-endian) and 64 bits in size, so I ran binwalk to search all the table files:

binwalk -R '\ x00 \ x00 \ x00 \ x00 \ x04 \ x00 \ x00 \ x00' *

There was one result in the OEMB table. The next 64-bit word after it was 0x1000000000, slightly larger than the end address in the main bridge window conflict message. Very promising clue. The OEMB table is special because it is not a standard table according to ACPI specifications. Linux complains about an invalid checksum, but I don't think that matters. I suppose you guess what I did next. ...

I made a copy of the OEMB table, replacing byte 0x00 immediately before byte 0x04 with 0x30 to change the value to 0x430000000 (remember this is the reverse order). I placed this modified copy in the file /boot/oemb.dat. Then he used GRUB to replace the OEMB table with my copy, temporarily pasting the following command into the list of boot commands (entering the letter 'e' in GRUB after selecting Ubuntu):

acpi --exclude = OEMB /boot/oemb.dat

The idea is that it tells GRUB to load all ACPI tables except the OEMB table, and then load the contents of /boot/oemb.dat and add it as an additional table. This will effectively replace the old OEMB table with the new OEMB table.

Ok, I booted Linux and ...

acpi PNP0A08: 00: ignoring host bridge window [mem 0x400000000-0xfffffffff
window] (conflicts with System RAM [mem 0x100000000-0x42fffffff])

The damned mistake has not gone away. WTF? I assumed that the PCI range was actually determined somewhere else, but I have not seen anywhere that a specific value is determined. I made sure that the revised OEMB table actually loaded, and returned to the study.

This time I decided to use iasl to decompile the DSDT table. Tracking revealed that the DSDT table should contain a method called _CRSthat is responsible for creating this table.

iasl -d DSDT

In the .dsl file, I really found the _CRS method associated with the PCI bus, and it looked pretty complicated. The DSDT table contains the actual code, so looking up the table values ​​is not easy. In my case, the _CRS method turned out to be quite complicated. I interpreted the code as best I could and realized that the _CRS method loads information from another table in memory, starting with 0xCF78E064. I looked again at the Linux boot log in dmesg and found this:

ACPI: Early table checksum verification disabled
ACPI: RSDP 0x00000000000F9820 000014 (v00 ACPIAM)
ACPI: RSDT 0x00000000CF780000 000044 (v01 012110 RSDT0821 20100121 MSFT 00000097)
ACPI: FACP 0x00000000CF780200 000084 (v01 012110 FACP0821 20100121 MSFT 00000097)
ACPI: DSDT 0x00000000CF780460 006FE7 (v01 946F1 946F1P06 00000000 INTL 20051117)
ACPI: FACS 0x00000000CF78E000 000040
ACPI: APIC 0x00000000CF780390 00008C (v01 012110 APIC0821 20100121 MSFT 00000097)
ACPI: MCFG 0x00000000CF780420 00003C (v01 012110 OEMMCFG 20100121 MSFT 00000097)
ACPI: OEMB 0x00000000CF78E040 000082 (v01 012110 OEMB0821 20100121 MSFT 00000097)
ACPI: HPET 0x00000000CF78A460 000038 (v01 012110 OEMHPET 20100121 MSFT 00000097)
ACPI: GSCI 0x00000000CF78E0D0 002024 (v01 012110 GMCHSCI 20100121 MSFT 00000097)
ACPI: DMAR 0x00000000CF790100 000090 (v01 AMI OEMDMAR 00000001 MSFT 00000097)
ACPI: SSDT 0x00000000CF7917C0 000363 (v01 DpgPmm CpuPm 00000012 INTL 20051117)

Yeah! It loads information from the OEMB table. My hunch was right from the start. So why didn't the OEMB table replacement work?

I looked again at the dmesg log after replacing the OEMB table. What I did not understand was that if you are trying to modify tables, GRUB moves most of them, including OEMB, to another memory location. The problem is that the DSDT table is hardcoded to look at the 0xCF78E064 address for the OEMB table. Therefore, the new table is not visible to the system; it still looks at the original table. Wow

The first impulse was to change the DSDT to transfer it to the new location of the OEMB table, but I felt that it was a bad idea in the future because new versions of GRUB could change the location in the memory where the custom OEMB table is stored.

I settled on another idea. The GRUB commands have equivalents write_byte, write_word, write_dwordand read_. What if GRUB modifies the original OEMB table on the fly? Nowadays, BIOSs are compressed. The tables are probably loaded into RAM, so theoretically you can change the values.

So I did. As a temporary test, I added the following command to the GRUB boot sequence:

write_byte 0xCF78E0B5 0x30

It replaces the 0x00 byte immediately before the 0x04 byte with the value 0x30, converting the 64-bit PCI start address of this end range to 0x0000000430000000. I did not update the checksum of the OEMB table because Linux already whined that the checksum was incorrect, so obviously, it doesn’t care.

I rebooted on Linux and anxiously checked the dmesg log for PCI.

PCI host bridge to bus 0000: 00
pci_bus 0000: 00: root bus resource [io 0x0000-0x0cf7 window]
pci_bus 0000: 00: root bus resource [io 0x0d00-0xffff window]
pci_bus 0000: 00: root bus resource [mem 0x000a0000-0x000bffff window]
pci_bus 0000: 00: root bus resource [mem 0x000d0000-0x000dffff window]
pci_bus 0000: 00: root bus resource [mem 0xd0000000-0xdfffffff window]
pci_bus 0000: 00: root bus resource [mem 0xf0000000-0xfed8ffff window]
pci_bus 0000: 00: root bus resource [mem 0x430000000-0xfffffffff window]
pci_bus 0000: 00: root bus resource [bus 00-ff]

Success! Window 0x430000000-0xfffffffffff appeared as a new valid window in the list, and the conflict warning disappeared. After checking that Linux is still working fine, I tried to boot into Windows with the same hack.

It worked! Now I can boot into Windows with 16 GB of RAM if I use GRUB as the bootloader with the above write_byte command. The Windows 10 bootloader will obviously not work. And if I ever reinstall Windows, you probably have to temporarily pull out one RAM bar to load the installer. But it works!

To permanently add the fix to GRUB, I created a /etc/grub.d/00_patchbios file with the following contents:

# This file patches the BIOS in my Foxconn P55MX motherboard to work
# properly when I have 16 GB of RAM installed. It's a nasty hack.
# Basically, the BIOS is hardcoded in the OEMB ACPI table
# to have a PCI address range from 0x400000000 to 0xfffffffff, but
# that overlaps with 16 GB of RAM being installed, because the RAM
# uses up (among other ranges) 0x100000000 to 0x42fffffff.
# This patch changes the table to actually list a PCI range of:
# 0x430000000 to 0xfffffffff
echo "write_byte 0xCF78E0B5 0x30" 

Then he made the script executable and ran it sudo update-grub. Now the patch is automatically applied when GRUB starts.

I honestly don’t know how safe it is. Is the motherboard really hardware-programmed to look at these addresses for PCI or something else. I only know that she passes my RAM tests. Since Linux works fine with 16 gigabytes of RAM, these issues do not bother me much. Perhaps if more PCI / PCIe cards or something else are installed, then there will be problems, but in my case, everything seems to be in order. Obviously, your system may be different, and this hack cannot be directly applied to other motherboards, because the ACPI table for each BIOS is slightly different.

I think it was a fun experience to share with the world! I hope you learned something from this post. Of course, I myself learned a lot in the process.

Also popular now: