lbmk/util/e6400-flash-unlock
Nicholas Chin 724cb39f86
util/e6400-flash-unlock: Update to upstream version
This updates lbmk's copy of e6400-flash-unlock to commit c5567fece479
(README.md: Update with info about broader device support) in my
upstream repo.

Changes:
- Theoretical support for any Dell system that implements that flash
  descriptor override command. This is done by reading base address
  registers at runtime instead of hard coding them for specific devices.
  Tested on the Latitude E6400 and Latitude E6430.
- Support for OpenBSD. It compiles, runs, and behaves as expected,
  though I have not actually tested internally flashing with flashrom
  yet. It should work though, as the program checks if the descriptor
  override is set and the BIOS Write Enable is able to be set to 1, which
  is all that is needed to internal flash.
- Integrated changes made in the lbmk copy
- Moved operating system accessor implementations to their own file

It should be fully functional, though minor formatting and cleanup
changes are still planned.

Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com>
2023-10-09 23:16:18 -06:00
..
COPYING Add E6400 flash unlock utility 2023-04-19 00:31:33 -06:00
Makefile util/e6400-flash-unlock: Update to upstream version 2023-10-09 23:16:18 -06:00
README.md util/e6400-flash-unlock: Update to upstream version 2023-10-09 23:16:18 -06:00
accessors.c util/e6400-flash-unlock: Update to upstream version 2023-10-09 23:16:18 -06:00
accessors.h util/e6400-flash-unlock: Update to upstream version 2023-10-09 23:16:18 -06:00
e6400_flash_unlock.c util/e6400-flash-unlock: Update to upstream version 2023-10-09 23:16:18 -06:00

README.md

Dell Laptop Internal Flashing

This utility allows you to use flashrom's internal programmer to program the entire BIOS flash chip from software while still running the original Dell BIOS, which normally restricts software writes to the flash chip. It seems like this works on any Dell laptop that has an EC similar to the SMSC MEC5035 on the E6400, which mainly seem to be the Latitude and Precision lines starting from around 2008 (E6400 era).

TL;DR

Run make to compile the utility, and then run sudo ./e6400_flash_unlock and follow the directions it outputs.

Confirmed supported devices

  • Latitude E6400
  • Latitude E6410
  • Latitude E4310
  • Latitude E6430
  • Precision M6800

It is likely that any other Latitude/Precision laptops from the same era as devices specifically mentioned in the above list will work as Dell seems to use the same ECs in one generation.

Detailed device specific behavior

  • On GM45 era laptops, the expected behavior is that you will run the utility for the first time, which will tell the EC to set the descriptor override on the next boot. Then you will need to shut down the system, after which the system will automatically boot up. You should then re-run the utility to disable SMM, after which you can run flashrom. Finally, you should run the utility a third time to reenable SMM so that shutdown works properly afterwards.
  • On 1st Generation Intel Core systems such as the E6410 and newer, run the utility and shutdown in the same way as the E6400. However, it seems like the EC no longer automatically boots the system. In this case you should manually power it on. It also seems that the firmware does not set the BIOS Lock bit when the descriptor override is set, making the 2nd run after the reboot technically unnecessary. There is no harm in rerunning it though, as the utility can detect when the flash is unlocked and perform the correct steps as necessary.

How it works

There are several ways the firmware can protect itself from being overwritten. One way is the Intel Flash Descriptor (IFD) permissions. On Intel systems, the flash image is divided into several regions such as the IFD itself, Gigabit Ethernet (GBE) non-volative memory, Management Engine (ME) firmware, Platform Data (PD), and the BIOS. The IFD contains a section which specifies the read/write permissions for each SPI controller (such as the host system) and each region of the flash, which are enforced by the chipset.

On the Latitude E6400, the host has read-only access to the IFD, no access to the ME region, and read-write access to the PD, GBE, and BIOS regions. In order for flashrom to write to the entire flash internally, the host needs full permissions to all of these regions. Since the IFD is read only, we cannot change these permissions unless we directly access the chip using an external programmer, which defeats the purpose of internal flashing.

However, Intel chipsets have a pin strap that allows the flash descriptor permissions to be overridden depending on the value of the pin at power on, granting RW permissions to all regions. On the ICH9M chipset on the E6400, this pin is HDA_DOCK_EN/GPIO33, which will enable the override if it is sampled low. This pin happens to be connected to a GPIO controlled by the Embedded Controller (EC), a small microcontroller on the board which handles things like the keyboard, touchpad, LEDs, and other system level tasks. Software can send a certain command to the EC, which tells it to pull GPIO33 low on the next boot.

Although we now have full access according to the IFD permissions, we still cannot flash the whole chip, due to another protection the firmware uses. Before software can update the BIOS, it must change the BIOS Write Enable (BIOSWE) bit in the chipset from 0 to 1. However, if the BIOS Lock Enable (BLE) bit is also set to 1, then changing the BIOSWE bit triggers a System Management Interrupt (SMI). This causes the processor to enter System Management Mode (SMM), a highly privileged x86 execution state which operates transparently to the operating system. The code that SMM runs is provided by the BIOS, which checks the BIOSWE bit and sets it back to 0 before returning control to the OS. This feature is intended to only allow SMM code to update the system firmware. As the switch to SMM suspends the execution of the OS, it appears to the OS that the BIOSWE bit was never set to 1. Unfortunately, the BLE bit cannot be set back to 0 once it is set to 1, so this functionality cannot be disabled after it is first enabled by the BIOS.

Older versions of the E6400 BIOS did not set the BLE bit, allowing flashrom to flash the entire flash chip internally after only setting the descriptor override. However, more recent versions do set it, so we may have hit a dead end unless we force downgrade to an older version (though there is a more convenient method, as we are about to see).

What if there was a way to sidestep the BIOS Lock entirely? As it turns out, there is, and it's called the Global SMI Enable (GBL_SMI_EN) bit. If it's set to 1, then the chipset will generate SMIs, such as when we change BIOSWE with BLE set. If it's 0, then no SMI will be generated, even with the BLE bit set. On the E6400, GBL_SMI_EN is set to 1, and it can be changed back to 0, unlike the BLE bit. But there still might be one bit in the way, the SMI_LOCK bit, which prevents modifications to GBL_SMI_EN when SMI_LOCK is 1. Like the BLE bit, it cannot be changed back to 0 once it set to 1. But we are in luck, as the vendor E6400 BIOS leaves SMI_LOCK unset at 0, allowing us to clear GBL_SMI_EN and disable SMIs, bypassing the BIOS Lock protections.

There are other possible protection mechanisms that the firmware can utilize, such as Protected Range Register settings, which apply access permissions to address ranges of the flash, similar to the IFD. However, the E6400 vendor firmware does not utilize these, so they will not be discussed.