Firmware -flashing- reading on current AMD systems
AMD flashprog BIOS UEFIAfter I got my hands on a second AMD system that is too locked down to
even get read access to the SPI flash controller, I thought it's about
time to summarise my findings. As it turns out, owner control is once
more left behind. This affects not only end users, but also opensource
development, researchers, and not to forget education. But more about
this later.
Prior Open-Source Support
Flashprog has always supported BIOS/firmware flashing from the OS command line on AMD systems. This worked very well so far, also on AMD’s AM4 and AM5 platforms, and respective mobile and server systems. With one wrinkle though: The boot firmware can lock us out. There have been multiple locking mechanisms over the years, most of them somewhat cooperative. That is, they locked the SPI controller to allow only particular commands and to deny access to specific flash regions. This still allowed us to support even odd configurations, e.g. a locked controller with a 32MiB flash chip on platforms that officially support only 16MiB max :D And for the newest platforms, there’s always a patch ready for testing the next, partially locked system.
Alas, this changes now. There’s a new mechanism that completely disables access to the SPI controller. Plus, the interface used by BIOSes to access the flash chip is hidden now.
ROM Armor
A little more than a year ago, a flashprog fellow discovered an oddity on their AMD Rembrandt ThinkPad when trying out flashprog: The configuration of the integrated LPC PCI device wasn’t readable. Traditionally, this configuration space contains the address of the SPI controller’s register space (SPI BAR) among some other BIOS flash related settings.
While it’s not obvious why these settings are hidden, it’s usually attributed to a new protection mechanism AMD dubbed ROM Armor. Beside recent chatter about a vulnerability (CVE-2024-36326) there is little official information to be found in public. AMD’s pro technologies whitepaper only briefly mentions that it “provides protection against unauthorized modifications to the SPI flash”. However, there’s a nice talk and roundup about current AMD protections by IOActive.
What we’ve learned so far:
- With ROM Armor, the x86 opts out from using the SPI controller, and
- the Platform Security Processor (PSP) takes over control instead.
- The PSP configuration contains a policy list that controls which flash regions can be accessed.
- As most x86 firmware needs write access to an NVRAM region in flash, it’s presumable that the System Management Mode (SMM) has an interface to the PSP for this.
Actually, coreboot has a mailbox interface for the opposite case, that ROM Armor is disabled. Here, the x86 firmware controls the SPI flash and accepts requests from the PSP to access it.
Case Studies
First time I could call a ROM-Armored system my own was in February this year, when I bought an AM5 mainboard, the ASRock A620M-HDV/M.2. Knowing that I’ll want to have a look at its firmware sooner or later, I selected this model because it comes a SPI header. Nevertheless, finding out that it has ROM Armor permanently enabled was quite frustrating. Especially because of this: There’s a Software/ BIOS Setup Guide for ASRock’s AM5 boards, that explicitly mentions a toggle for ROM Armor.
I made use of the SPI header right away, trying to remove random UEFI modules that seemed to be related ;) I was unsuccessful, though. After removing one rather promising-sounding module, the system seemed to boot but then reset when it came to loading an OS. Which made me wonder: Does it maybe not know how to write to the flash w/o the PSP doing the deed?
My second system with ROM Armor is a Framework Desktop. In this case, there was no promise about being able to disable it. Still rather annoying, as the BIOS setup explicitly mentions it’s enabled. As if it wanted to tease me (>_<)
With little hope, I got in contact with the support of both vendors. ASRock’s original answer was simply confirming that the BIOS option doesn’t exist. No mention of the deviation from the manual. I thought, maybe they’d fix the manual? Though, half a year later I reminded them, showing some frustration and their answer was, well, that the manual is for all of their AM5 boards and doesn’t fit them all exactly (and pointed out that there is a disclaimer in the manual, of course). So I asked again, which of their AM5 boards has the option? They replied with a surprisingly honest, but disheartening answer:
"the information I have is, none of our AM5 mainboards, because AMD
told us to enable it by default and remove from shown option."
From Framework, I got nothing so far. I already queried their support regarding other firmware questions and was first put off for a while, then eventually was told to refer my questions to their software team. I’ll probably update this post when they reply.
Flashprog Read Support
Without an exploit, writing to the BIOS flash from the OS seems off the menu. Reading its contents, however, should be possible and at least enables some research and allows one to take backups. On x86, the BIOS flash is traditionally memory mapped, meaning software can read from flash ROM just like it would read from RAM. With the PCI configuration hidden, it takes some guesswork however, to make sure we read from the correct address range.
Memory Addresses
Usually, we would follow a chain of addresses, starting with the aforementioned PCI config space of the LPC device:
PCI 00:14.3 (LPC) ==> SPI BAR ==> ROM 3 Range
ROM 3 Range is where we have up to 64MiB of flash memory mapped. Knowing that most firmware configures the SPI BAR and ROM ranges with AMD’s default values, I peeked around a little on the systems at hand.
- SPI BAR:
0xfec10000 - ROM 3:
0xfd00000000
At the usual SPI BAR location, I found nothing. However, at the next
three adjacent 4KiB pages (0xfec11000, 0xfec12000, 0xfec13000)
I discovered similar, but non-functional interfaces. The first even
showing the expected 0xfd00000000 ROM 3 address. That’s at least
something we can use to confirm that we run flashprog in an expected
environment.
Flash-Size Probing
Now, any program that can map the ROM 3 memory range could be used to read the flash contents. It’s convenient though, to use a familiar tool like flashprog. Adding support wasn’t hard, but there was one obstacle: It wants to know the flash size.
The current patch makes use of a peculiarity of SPI flash chips: They ignore address bits that go beyond their capacity. For a 32MiB chip, for instance, this means that it only decodes (considers) 25 address bits, thus the following addresses all look the same to it:
0x00aaaaaa -> 0b0000 0000 1010 1010 1010 1010 1010 10100x02aaaaaa -> 0b0000 0010 1010 1010 1010 1010 1010 10100x04aaaaaa -> 0b0000 0100 1010 1010 1010 1010 1010 10100x06aaaaaa -> 0b0000 0110 1010 1010 1010 1010 1010 1010
When software reads anywhere in the range from 0xfd00000000 to
0xfd03ffffff, the SPI controller removes the 0xfd00000000, and sends
a read command to the SPI flash with the remaining address bits. And to
keep things simple, the controller does not consider the flash chip’s
size. So for a 32MiB chip, we’d get the exact same contents for the
following ranges:
0xfd00000000 .. 0xfd01ffffff0xfd02000000 .. 0xfd03ffffff
Both times, the whole 32MiB flash contents. In other words, within the 64MiB ROM 3 range, a smaller flash chip’s contents always repeat.
With this in mind, and knowing that SPI flashes are always a power-of-2 in size, we can start with a 64MiB guess and then halve this size until we find non-repeating contents:
/*
* We start comparing the two halves of the 64 MiB space. And if
* they match, split the lower half, and so on until we find a
* mismatch (or not, in the unlikely case of empty memory?).
*/
for (flash_size = 64*MiB; flash_size > 0; flash_size /= 2) {
if (compare_sparse(rom3, rom3 + flash_size / 2, flash_size / 2))
break;
}
To speed things up, compare_sparse() only compares data at
pseudo-random addresses. And that’s it, with a pretty high chance, we
know the flash size now. Let’s try this:
Impact of ROM Armor
I understand that AMD most likely pushes ROM Armor forward for security reasons. And I absolutely agree that security by default is most important. Not allowing the hardware owner to opt out from it, seems short-sighted, though. We can opt out from SecureBoot as well. And the AM5 board even allows options to literally burn the CPU, albeit behind a warranty-void screen. But I wouldn’t mind that for a ROM Armor opt-out.
The current situation is somewhat frustrating. Sometimes it looks like open source is gaining, and then suddenly one hits a wall. This is not only about open-source development, though. ROM Armor, enforced like this, also restricts what the hardware owner can do with the systems they paid for. It makes research harder and discourages from experimenting with one’s own systems.
The last part may seem of little importance, but how is it that software developers usually acquire their skills? I believe experimentation plays a significant role there. Many software developers are self-educated, and many companies actually expect them to be, to learn on the job, to keep up with new technologies. Can we have the same for firmware developers? Not if all of the off-the-shelf hardware is locked down.
Companies seem to have trouble hiring PC firmware engineers, maybe AMD among them? Would that be surprising? I think not, and believe this will get worse in the future if we continue to lock everything down. From personal experience: Almost everything I learned about boot firmware, I learned after starting my job. And not for the lack of trying: During my academic education, there was a lot to learn about embedded development. The PC on the other hand, even if prevalent, seemed like a black box to most academics. And this was when PC firmware was rather open compared to today. So if anyone working at AMD reads this: Please try to not enforce black boxes. Your future colleagues might be quite thankful ;)
If you have any feedback, feel free to leave a comment on Mastodon or the flashprog mailing list. I’d be happy to hear if somebody has already more experience with ROM Armor.