Skip to content

QFIL: Factory Flashing

TL;DR

QFIL (Qualcomm Flash Image Loader) is the factory-grade tool for writing raw images to UFS/eMMC when normal boot paths are dead or you need a clean slate. It talks to the SoC in EDL (Emergency Download) mode via USB, using the Firehose protocol and a signed programmer (.elf/.mbn) to execute rawprogram*.xml and patch*.xml from your flash package. QFIL bypasses Android, fastboot, and the running OS entirely. It speaks directly to storage. Use it for first flash, unbrick, partition table rebuild, and milestone re-provision. Use fastboot for iterative dev flashes and OTA for field updates.

When fastboot says FAILED (remote: unknown command) and ADB shows no device, QFIL is the tool that still sees the silicon. This page is the factory flash playbook.

QFIL is not “Android flashing.” It’s low-level storage programming:

  1. Host PC sends a Firehose programmer into SoC RAM
  2. Programmer initializes UFS/eMMC controller
  3. Host sends program/patch commands from XML + image files
  4. Programmer writes bytes to specific LUN/sector ranges
  5. Device reboots into whatever boot chain you just wrote
Layer Tool Speaks To
Application OTA agent / lb Update service over gRPC + SOME/IP
OS bootloader fastboot ABL in fastboot mode
Factory/recovery QFIL Firehose programmer in EDL
Dead silicon QFIL + authorized programmer PBL/ROM loader in EDL

QFIL loads images before any OS exists to refuse them.

EDL (Emergency Download Mode) is a USB boot path baked into Qualcomm ROM code. The SoC enumerates as a Qualcomm HS-USB QDLoader device (often PID 9008).

Method When Used Risk
Test point / EDL button Bench boards with exposed pads Low (hardware intent)
ADB: reboot edl Debug builds with allowed command Medium (needs working ADB)
Fastboot: reboot emergency Some platforms Medium
Dead boot / blank flash Automatic; PBL falls to EDL N/A (you’re already there)
Special boot strap pins Production fixtures Low (fixture-controlled)
Common Gotcha

Consumer phone forums love EDL cable tricks (short D+/D−). Automotive bench boards use test points or fixture control. Don’t assume phone hacks work on your cockpit harness. Wrong entry method can leave the board in an undefined state or trip security fuses on production-fused units.

flowchart TD
POWER["Power On / Reset"] --> PBL["PBL (ROM)"]
PBL -->|"Valid XBL on UFS"| XBL["Normal Boot → XBL → ABL → OS"]
PBL -->|"No valid boot chain / forced EDL"| EDL["EDL Mode<br/>USB QDLoader 9008"]
EDL --> QFIL["QFIL sends Firehose programmer"]
QFIL --> FH["Firehose running in RAM"]
FH --> WRITE["Execute rawprogram + patch XML"]
WRITE --> REBOOT["Reboot to new firmware"]

Firehose Protocol: The Language QFIL Speaks

Section titled “Firehose Protocol: The Language QFIL Speaks”

Once in EDL, the host cannot simply “copy a file to disk.” The SoC needs a programmer: a tiny signed binary loaded into RAM that understands Firehose commands.

Firehose Concept Purpose
Programmer (.elf / .mbn / .melf) Chip-specific loader; must match SoC (e.g., SA8155P variant)
Configure Set storage type (UFS), LUN count, sector size
Program Write image data to partition/sector range
Patch Apply small fixups from patch XML
Reset Reboot device after flash complete
Digest / signature Verify programmer authenticity (secure boot enforced on production units)

Typical QFIL log flow:

Connecting to QDLoader 9008...
Sending programmer: prog_firehose_ddr.elf
Target configured: UFS, 2 LUNs, 4096 sector size
Programming xbl.elf → LUN 0, partition xbl ... OK
Programming boot.img → LUN 1, partition boot_a ... OK
Applying patch0.xml ... OK
Resetting device...

Firehose is a high-pressure stream of sector writes. You’re not mounting filesystems; you’re hosing bytes into raw partitions.

Mental Model

Normal boot is a tenant moving into a furnished apartment — ABL opens the door, Android unpacks into RAM. EDL + Firehose is demolition and reconstruction — the building manager (PBL) lets the construction crew (programmer) strip walls to studs and rebuild from blueprints (rawprogram XML). Nothing inside the apartment matters because you’re not going through the front door.

Your BSP/build drop contains:

flash_package/
├── prog_firehose_*.elf # Programmer for your SoC + storage
├── rawprogram0.xml # LUN 0 programs
├── rawprogram1.xml # LUN 1 programs
├── patch0.xml
├── patch1.xml
├── xbl.elf
├── abl.elf
├── boot.img
├── super.img
├── NON-HLOS.bin # modem
├── vbmeta.img
└── ...

Verify: build ID, platform variant, UFS vs eMMC, sparse vs raw image formats.

Use test point, ADB, or fixture. Confirm device in Device Manager / lsusb as Qualcomm QDLoader 9008.

  • Select Flat Build (most automotive packages)
  • Point to prog_firehose programmer
  • Load rawprogram0.xml (+ rawprogram1, etc.)
  • Load matching patch.xml*
  • Ensure image search path includes all referenced filename= entries

QFIL:

  1. Uploads programmer to RAM
  2. Sends configure for UFS
  3. Executes each <program> entry sequentially
  4. Applies patches
  5. Resets device

First boot after full flash may take longer (file system format, slot init). Check:

  • Serial log from XBL/ABL
  • ADB availability
  • Active slot: adb shell bootctl get-current-slot
  • Modem attach if AMSS was flashed
Sparse Images vs Raw Images

Large partitions (system, super) often ship as sparse images, an Android format that encodes “skip these empty blocks.” Firehose understands sparse natively on most programmers. Flashing a sparse image as raw (or vice versa) produces wrong-size writes or corrupt filesystems with no immediate error. Match the format in your XML filename to what the build system generated.

Scenario Tool Why
Brand-new board, empty UFS QFIL No bootloader exists to enter fastboot
Bricked boot / corrupt GPT QFIL Must rewrite LUN 0 and partition table
Full milestone re-provision QFIL Clean, reproducible factory state
Iterative kernel/boot test fastboot Seconds per flash, OS not required
Single partition swap (boot, vendor_boot) fastboot Surgical, preserves userdata
Field fleet update OTA (lb / update_engine) Signed, staged, rollback-aware
Modem-only update (AMSS drop) fastboot or QFIL fastboot if partition exposed; QFIL for full NON-HLOS refresh
Userdata wipe + reflash OS QFIL or fastboot -w QFIL for total rebuild; fastboot for dev wipe
flowchart TD
Q{"What's the device state?"}
Q -->|"No boot at all"| QFIL
Q -->|"Fastboot available"| FB["fastboot flash &lt;partition&gt;"]
Q -->|"OS running, normal ops"| OTA["OTA / lb campaign"]
Q -->|"Need LUN 0 rewrite"| QFIL
FB -->|"Need full factory reset"| QFIL
QFIL is your nuclear option

Reach for QFIL when:

  • The board doesn’t enumerate in fastboot; only QDLoader 9008 appears
  • You need to change partition layout or recover from a wrong XML flash
  • You’re doing first article bring-up with a golden flash package
  • Someone flashed phone firmware onto an automotive board (yes, it happens)

Don’t reach for QFIL when:

  • You’re iterating on boot.img five times an hour: use fastboot
  • You’re pushing a signed build to 100 fleet vehicles: use OTA
  • You only need adb shell debug: QFIL is overkill and wipes state

Bench ritual: Before every QFIL session, screenshot the build ID, programmer filename, and rawprogram variant. After every QFIL session, log active slot and first-boot result. Future-you debugging a bricked board will need all three.

Common Gotcha

Using a programmer or rawprogram from the wrong chip stepping (SA8155P build on SA8295P hardware) often “succeeds” in QFIL then fails silently at first XBL instruction. The flash log shows all green checks. The serial log shows garbage. Programmer + XML + images must be a matched set from one release artifact.

Connect the Dots

Page 8.1 maps partition names to LUNs, the labels in your rawprogram XML. Page 8.3 covers fastboot for day-to-day dev. Page 8.4 explains why unsigned programmers get rejected on production-fused units. Page 8.6 covers OTA for everything QFIL shouldn’t touch in the field.

  1. QFIL programs UFS via EDL + Firehose, below Android and below fastboot.
  2. rawprogram/patch XML + signed programmer + matched images = one atomic flash package.
  3. Factory/unbrick/first flash → QFIL. Dev iteration → fastboot. Fleet delivery → OTA.
  4. QFIL success in the log ≠ boot success. Always verify serial, slot, and modem.

Check Your Understanding

1. What transport mode does QFIL use to communicate with a Qualcomm SoC during factory flashing?

2. When is QFIL the correct tool instead of fastboot?

3. In the Firehose flash flow, what is the role of the programmer (.elf)?