yeet another post
This commit is contained in:
parent
7e0b3a05e1
commit
26d2e57e42
1 changed files with 220 additions and 0 deletions
220
content/posts/pulling-apart-dell-uefi.md
Normal file
220
content/posts/pulling-apart-dell-uefi.md
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
+++
|
||||
date = "2023-10-19"
|
||||
draft = false
|
||||
path = "/blog/pulling-apart-dell-uefi"
|
||||
tags = ["uefi"]
|
||||
title = "Pulling apart Dell UEFI images and messing with ACPI"
|
||||
+++
|
||||
|
||||
This is a quick post to write down the method that worked for me to acquire and
|
||||
pull apart a Dell UEFI image to get the executables out, and how to poke at
|
||||
ACPI.
|
||||
|
||||
The specific issue I was curious about and trying to find more information
|
||||
about is the [`rtsx` card reader NVMe regression][rtsx-explanation] on the Dell
|
||||
XPS 15 9560, which is the laptop I use.
|
||||
|
||||
[rtsx-explanation]: https://lore.kernel.org/regressions/c7bdd821686e496eb31e4298050dfb72@realtek.com/
|
||||
|
||||
The regression was caused by the card reader driver no longer setting a
|
||||
register that forces the PCIe `CLKREQ#` pin to be always pulled low, which was,
|
||||
in effect, making the kernel no longer ask the chipset for PCIe clock all the
|
||||
time.
|
||||
|
||||
However, this is even more confusing, because this is essentially a
|
||||
force-disabling bit for attempting to do PCIe ASPM, which was never enabled in
|
||||
the first place on the machine!
|
||||
|
||||
For *some reason*, the *card reader* ceasing to ask the chipset for clock all
|
||||
the time (which, given that ASPM is purportedly disabled in the ACPI tables,
|
||||
should be a no-op!) caused the *NVMe SSD*, which has nothing to do with the
|
||||
card reader, to lose its PCIe link after the card reader driver loads. Further,
|
||||
this happened to every kind of SSD, so it must be some kind of platform bug.
|
||||
|
||||
If you have any ideas of why this is happening, send me an email at <bug at jade
|
||||
dot fyi>, I am very curious.
|
||||
|
||||
# Extracting the firwmare
|
||||
|
||||
I acquired a copy of the firmware [from fwupd here][fwupd]. This is a
|
||||
Microsoft cabinet file. I then used [BIOSUtilities] and p7zip to extract it:
|
||||
|
||||
[fwupd]: https://fwupd.org/lvfs/devices/com.dell.uefi34578c72.firmware
|
||||
|
||||
```
|
||||
mkdir bios
|
||||
mv ../4d77eabfe13e3d153dfe9f19b570de40cc90260ef7229b2ca070e06b5c840040-Dell_XPS_15_9560_Precision_5520_System_BIOS_Ver.1.24.0.cab bios
|
||||
(cd bios; 7z x *.cab)
|
||||
python Dell_PFS_Extract.py -i bios -o bios_ex
|
||||
```
|
||||
|
||||
This then produces some files:
|
||||
|
||||
```
|
||||
BIOSUtilities » ls bios_ex/firmware.bin_extracted/Firmware/1\ firmware\ --\ *
|
||||
'bios_ex/firmware.bin_extracted/Firmware/1 firmware -- 1 System BIOS with BIOS Guard v1.24.0.bin'
|
||||
'bios_ex/firmware.bin_extracted/Firmware/1 firmware -- 2 Embedded Controller v1.0.29.bin'
|
||||
'bios_ex/firmware.bin_extracted/Firmware/1 firmware -- 3 Intel Management Engine (VPro) Update v11.8.86.3877.bin'
|
||||
'bios_ex/firmware.bin_extracted/Firmware/1 firmware -- 4 Main System TI Port Controller 0 v7.0.0.31.bin'
|
||||
'bios_ex/firmware.bin_extracted/Firmware/1 firmware -- 5 System Board Map v1.0.1.bin'
|
||||
'bios_ex/firmware.bin_extracted/Firmware/1 firmware -- 6 PCR0 XML v0.0.0.1.xml'
|
||||
'bios_ex/firmware.bin_extracted/Firmware/1 firmware -- 7 Model Information v1.0.0.0.txt'
|
||||
```
|
||||
|
||||
[BIOSUtilities]: https://github.com/platomav/BIOSUtilities
|
||||
|
||||
From here, you can use UEFITool on these files:
|
||||
|
||||
```
|
||||
UEFITool firmware.bin_extracted/Firmware/1\ firmware\ --\ 1\ System\ BIOS\ with\ BIOS\ Guard\ v1.24.0.bin
|
||||
```
|
||||
|
||||
From here you can go hunting through the data in there or try `UEFIExtract`.
|
||||
|
||||
You can find a PE32 image called Setup somewhere in the UEFI image, and extract
|
||||
it. With such an image, you can use [`ifrextractor`][ifrextractor] to pull out
|
||||
the BIOS options. Acquire a copy like so:
|
||||
|
||||
[ifrextractor]: https://github.com/LongSoft/IFRExtractor-RS
|
||||
|
||||
`ifrextractor.nix`:
|
||||
|
||||
```nix
|
||||
{ rustPlatform, fetchFromGitHub }:
|
||||
rustPlatform.buildRustPackage {
|
||||
pname = "ifrextractor";
|
||||
version = "0.0.1";
|
||||
src = fetchFromGitHub {
|
||||
owner = "longsoft";
|
||||
repo = "ifrextractor-rs";
|
||||
rev = "f40b9be0da561ede62f3988072100550a73d5386";
|
||||
sha256 = "sha256-No0H91iMcOQlE0Hcc+w02w5CP3M+Ixct+92+XsreIik=";
|
||||
};
|
||||
cargoSha256 = "sha256-smVHEBhjUcy4ApyJzhV31sMTB87Cdq59fxkSJsS1/cw=";
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
nix-build -E 'with import <nixpkgs> {}; callPackage ./ifrextractor.nix'
|
||||
```
|
||||
|
||||
Then extract the setup stuff with the following:
|
||||
|
||||
```
|
||||
ifrextractor firmware.bin_extracted/Section_PE32_image_Setup_body.efi
|
||||
```
|
||||
|
||||
Then read the extremely large file named like:
|
||||
`Section_PE32_image_Setup_body.efi.0.0.en-US.ifr.txt`.
|
||||
|
||||
If you *did* want to tamper with hidden settings, you could potentially have
|
||||
such bad ideas with similar methods to the following (please take a backup of
|
||||
the NVRAM first to not brick your computer!):
|
||||
|
||||
* <https://ristovski.github.io/posts/inside-insydeh2o/#peeking-inside-the-bios-image>
|
||||
* <https://hansdegoede.livejournal.com/25413.html>
|
||||
|
||||
If you want to stick the thing in Ghidra, there does [exist an extension,
|
||||
efiSeek][efiSeek], but I couldn't really tell if it was providing any useful
|
||||
analysis results.
|
||||
|
||||
[efiSeek]: https://github.com/DSecurity/efiSeek
|
||||
|
||||
# ACPI
|
||||
|
||||
In investigating the power management issue I was curious about, I wanted to
|
||||
understand what was in the ACPI tables and what was going on. These tables are
|
||||
probably somewhere in the UEFI image as well, but I am not sure where.
|
||||
|
||||
You can dump the ACPI tables from a running system using `acpidump` from `acpica-tools`:
|
||||
|
||||
```
|
||||
mkdir acpi && cd acpi
|
||||
sudo acpidump -b
|
||||
iasl -d *.dat
|
||||
```
|
||||
|
||||
If you want to get values of ACPI variables, you can use the [ACPI
|
||||
debugger][acpidbg] from the Linux kernel distribution:
|
||||
|
||||
[acpidbg]: https://docs.kernel.org/firmware-guide/acpi/aml-debugger.html
|
||||
|
||||
First, enable the right Kconfig options:
|
||||
|
||||
```nix
|
||||
{ lib, config, ... }: {
|
||||
boot.kernelPackages = pkgs.linuxPackages.extend (self: super: {
|
||||
kernel = super.kernel.override (old: {
|
||||
kernelPatches = old.kernelPatches ++ [
|
||||
{
|
||||
name = "acpi_nonsense";
|
||||
patch = null;
|
||||
extraStructuredConfig = with lib.kernel; {
|
||||
ACPI_DEBUGGER = yes;
|
||||
ACPI_DEBUGGER_USER = module;
|
||||
DEVMEM = yes;
|
||||
STRICT_DEVMEM = no;
|
||||
IO_STRICT_DEVMEM = option no;
|
||||
};
|
||||
}
|
||||
];
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
```
|
||||
cd some-linux-sources
|
||||
make acpi
|
||||
sudo ./power/acpi/acpidbg
|
||||
```
|
||||
|
||||
Inside the debugger you can print out things:
|
||||
|
||||
```
|
||||
- Evaluate UCSI
|
||||
Evaluating \UCSI
|
||||
Evaluation of \UCSI returned object 00000000a57a6a95, external buffer length 18
|
||||
[Integer] = 0000000000000000
|
||||
```
|
||||
|
||||
You can also use `Dump` to get information about a variable, such as its
|
||||
offset, if you need to peek/poke the memory.
|
||||
|
||||
---
|
||||
|
||||
If you want to tamper with the ACPI tables for investigating a potential fix,
|
||||
there are a couple of ways to do it.
|
||||
|
||||
At runtime, you can [load an overlay][overlay]:
|
||||
|
||||
```
|
||||
modprobe acpi_configfs
|
||||
cd /sys/kernel/config/acpi/table/
|
||||
mkdir my-ssdt ; cat ~youruser/somewhere/my-ssdt.aml > my-ssdt/aml
|
||||
|
||||
# unload with:
|
||||
rmdir my-ssdt
|
||||
```
|
||||
|
||||
[overlay]: https://www.kernel.org/doc/html/latest/admin-guide/acpi/ssdt-overlays.html
|
||||
|
||||
It's also possible to replace the ACPI tables [with the initrd][initrd-acpi]:
|
||||
Create a cpio archive with `kernel/firmware/acpi/*.dat`, then prepend it to the
|
||||
actual initrd.
|
||||
|
||||
[initrd-acpi]: https://docs.kernel.org/admin-guide/acpi/initrd_table_override.html
|
||||
|
||||
# Conclusion
|
||||
|
||||
This whole affair did not achieve much, but it was very interesting, and I have
|
||||
more of an idea how firmware works on x86.
|
||||
|
||||
For further information:
|
||||
- [ACPI Spec][https://uefi.org/sites/default/files/resources/ACPI_Spec_6_5_Aug29.pdf]
|
||||
|
||||
There may also exist schematics of the machine online, but I cannot confirm
|
||||
this.
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue