Skip to content

[DNM, WIP] Implement VIP#13

Draft
quic-kdybcio wants to merge 1 commit intoqualcomm:mainfrom
quic-kdybcio:topic/vip
Draft

[DNM, WIP] Implement VIP#13
quic-kdybcio wants to merge 1 commit intoqualcomm:mainfrom
quic-kdybcio:topic/vip

Conversation

@quic-kdybcio
Copy link
Contributor

dumping this here for easy tracking, not mergeable right now

@quic-kdybcio quic-kdybcio marked this pull request as draft July 1, 2025 14:50
@z3ntu
Copy link

z3ntu commented Sep 24, 2025

I was trying this out today, but so far I haven't gotten it to work yet.

First to clarify, I assume the new qdlrs options -M <VIP_MBN_PATH> -T <VIP_AUX_TBL_PATH> are equivalent to fh_loader's --signeddigests=DigestsToSign.bin.mbn --chaineddigests=ChainedTableOfDigests.bin options, with -M being --signeddigests (signme.mbn) and -T being --chaineddigests (tables.bin)?

I've been trying this out with an EDL package which contains rawprogram{0,1,2,3,4,5}.xml and patch{0,1,2,3,4,5}.xml, but for now only with rawprogram2.xml since it looks like qviptblgen can only take in one XML file? Shouldn't it be able to take in all rawprogram*.xml and patch*.xml files?

But anyways, with the following steps, it seems to not do anything. Is the general usage correct with what I have, or am I missing something?

$ qviptblgen rawprogram2.xml
$ sectools.py secimage --chipset bitra --sign_id vip -i out/signme.mbn -s
$ qdl-rs --print-firehose-log -M signme-SIGNED.mbn -l prog_firehose_ddr.elf -s ufs --reset-mode system flasher -p rawprogram2.xml
qdl-rs 0.1.0
Using a default sector size of 4096
Chip serial number: 0xee789c8b
OEM Private Key hash: 0x1c3d8d7ea24e435d7b540e0ffb34aa4bd57421c5f3570eef54f354610953a24c8e1930b57cc9349edaeca2466671c27f
Loader sent. Hack away!
Firehose failed. Resetting the board to edl, try again.

@quic-kdybcio
Copy link
Contributor Author

@z3ntu your decoding of cmdline arguments is correct

Each rawprogramN.xml could be appended into a single file (or not), since every set of commands is largely self-contained, so that's perhaps a UX point to take in mind. VIP simply checks whether the hash of every single command you send matches the (signed) digest table, so it can work both ways

Truth be told, this code dump was compile-tested only, so I'm not surprised it doesn't work for you.. It may be that your programmer outputs some information over UART. Also, perhaps some additional debug logs could come in useful (e.g. before/during/after sending the tables - perhaps I missed something in there)

This isn't particularly high on my to-do list right now, but I hope to come back and finish it up some day

// If we're past Sahara, activate the Firehose reset-on-drop listener
qdl_dev.reset_on_drop = true;

// If VIP is used, the hash table must be sent first, even before <configure>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it may be that this needs to be put below the read a couple lines down

@c60cb859
Copy link

c60cb859 commented Mar 5, 2026

Hi there

I am looking into this at the moment, I have pulled the PR into main and made it build with some changes.
I have a setup with Digests files that was cerated by the PCAT program, and VIP flashing works with PCAT, so currently testint the flashing part..

./qdl-rs \
  --verbose-sahara \
  --verbose-firehose \
  --print-firehose-log \
  -l ./xbl_s_devprg_ns.melf \
  -s ufs \
  -L 0 \
  -M ./DigestsToSign.bin.mbn \
  -T ./ChainedTableOfDigests.bin \
  flasher \
  -p ./rawprogram_unsparse0.xml ./rawprogram1.xml ./rawprogram3.xml ./rawprogram4.xml ./rawprogram5.xml \
  -x ./patch0.xml ./patch1.xml ./patch2.xml ./patch3.xml ./patch4.xml ./patch5.xml

This gives me the following output:

qdl-rs 0.1.0
Using a default sector size of 4096
SaharaPacket { cmd: SaharaHello, len: 48, body: HelloReq(HelloReq { ver: 3, compatible: 1, max_len: 1024, mode: WaitingForImage, unk0: 0, unk1: 0, unk2: 0, unk3: 0, unk4: 0, unk5: 0 }
) }
SaharaPacket { cmd: SaharaCommandReady, len: 8, body: CommandReady(CommandReady) }
SaharaPacket { cmd: SaharaExecuteResp, len: 16, body: ExecResp(ExecResp { command: ReadSerialNum, len: 8 }) }
Chip serial number: 0x________
SaharaPacket { cmd: SaharaHello, len: 48, body: HelloReq(HelloReq { ver: 3, compatible: 1, max_len: 1024, mode: WaitingForImage, unk0: 0, unk1: 0, unk2: 0, unk3: 0, unk4: 0, unk5: 0 }
) }
SaharaPacket { cmd: SaharaCommandReady, len: 8, body: CommandReady(CommandReady) }
SaharaPacket { cmd: SaharaExecuteResp, len: 16, body: ExecResp(ExecResp { command: ReadOemKeyHash, len: 48 }) }
OEM Private Key hash: 0x________________________________________
SaharaPacket { cmd: SaharaHello, len: 48, body: HelloReq(HelloReq { ver: 3, compatible: 1, max_len: 1024, mode: WaitingForImage, unk0: 0, unk1: 0, unk2: 0, unk3: 0, unk4: 0, unk5: 0 }
) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 0, len: 64 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 52, len: 64 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 116, len: 131072 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 131188, len: 640 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 131828, len: 64 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 131880, len: 416 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 340724, len: 11424 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 134900, len: 376 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 137972, len: 167896 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 305868, len: 23764 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 329632, len: 4660 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 352148, len: 64 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 352212, len: 504 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1200020, len: 11232 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 356244, len: 172032 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 528276, len: 172032 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 700308, len: 172032 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 872340, len: 86016 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 958356, len: 65536 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1023892, len: 172032 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1195924, len: 4096 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1211252, len: 64 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1211316, len: 392 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1493876, len: 4088 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1215348, len: 172032 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1387380, len: 38824 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1428340, len: 32768 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1461108, len: 32768 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1497964, len: 64 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1498028, len: 448 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1678188, len: 4136 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1498476, len: 284 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1498760, len: 51204 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1549964, len: 13072 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1563036, len: 55868 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1618904, len: 5800 }) }
SaharaPacket { cmd: SaharaReadData64, len: 32, body: ReadData64Req(ReadData64Req { image: 13, offset: 1624704, len: 51204 }) }
SaharaPacket { cmd: SaharaEndOfImage, len: 16, body: Eoi(Eoi { image: 13, status: 0 }) }
SaharaPacket { cmd: SaharaDoneResp, len: 12, body: DoneResp(DoneResp { status: 1 }) }
Loader sent. Hack away!
LOG: INFO: Binary build date: Feb  4 2026 @ 10:21:44
LOG: INFO: Binary build date: Feb  4 2026 @ 10:21:44

LOG: INFO: Chip serial num (0x0) Chip ID (0x0)
LOG: INFO: Supported Functions (15):
LOG: INFO: program
LOG: INFO: read
LOG: INFO: nop
LOG: INFO: patch
LOG: INFO: configure
LOG: INFO: setbootablestoragedrive
LOG: INFO: erase
LOG: INFO: power
LOG: INFO: firmwarewrite
LOG: INFO: getstorageinfo
LOG: INFO: benchmark
LOG: INFO: emmc
LOG: INFO: ufs
LOG: INFO: fixgpt
LOG: INFO: getsha256digest

It just stops here, nothing seems to happen, but the program doet not stop..

I have time to help out with both test and coding if I can get some pointers where to look

@c60cb859
Copy link

c60cb859 commented Mar 5, 2026

I have some logs from PCAT where it work using VIP downlaod

image

The log from the PCAT
pcat.log
and log output from UART
uart.log

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants