Without any verification on the host side, a dry-run with pre-built VIP
tables (-n -D <path>) would silently succeed even when the digest tables
did not match the data being flashed. The only way to catch a mismatch
was to attempt a real flash and wait for the device to reject it, which
wastes time and risks leaving a device in a broken state.
Add hash validation to the simulator so mismatches are caught at dry-run
time, before any hardware is involved.
The signed initial table (DigestsToSign.bin.mbn) and all chained tables
(ChainedTableOfDigests<n>.bin) are parsed as they arrive. Chain hashes
linking each table to the next are verified to ensure table integrity.
Per-chunk SHA256 hashes are checked in order against every XML command
write and raw payload write; any mismatch is reported via ux_err()
without aborting so all mismatches remain visible at the end of a run.
Validation is active in exactly the intended modes:
-n plain dry-run, no tables sent -- no-op
-n -D <path> dry-run with VIP tables -- full hash validation
-n -t <dir> digest generation -- validation disabled
MAX_DIGESTS_PER_SIGNED_FILE and MAX_DIGESTS_PER_CHAINED_FILE are moved
from vip.c to vip.h so sim.c can reference them. sha2.c is added to
RAMDUMP_SRCS because qdl-ramdump links sim.o which now calls SHA256.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Replace the stub sim_read()/sim_write() with a simulator that
parses incoming XML commands and enqueues matching XML responses,
mirroring the real Firehose device protocol. This decreases divergence
in behavior between the real HW and the dry-run mode, giving better
validation of the flashing process in dry-run mode.
sim_write() now dispatches based on the command tag:
- configure: enqueue log + ACK echoing the same max payload size so
firehose_try_configure() does not trigger a redundant exchange
- program/read: enqueue log + rawmode=true ACK and transition to
SIM_STATE_RAW_IN/RAW_OUT to track the raw binary transfer
- erase/patch/setbootablestoragedrive/ufs: enqueue log + ACK
- power: enqueue log + ACK and mark the simulator as closed
sim_read() first drains the XML response queue (ensuring protocol
responses are delivered before any raw data), then serves zero-filled
sector data in SIM_STATE_RAW_OUT, and returns -EIO once closed so
the trailing drain in firehose_reset() completes immediately.
Since the simulator now produces correct protocol responses, remove the
QDL_DEVICE_SIM early-return guards in firehose_read() and
firehose_try_configure() that previously bypassed response parsing.
Pre-initialize qdl->sector_size = 4096 in sim_init() and only probe
sector size in firehose_try_configure() if unset. Previously, the
probe <read> commands were executed during --createdigest dry-runs and
included in the VIP digest table, but not issued during real VIP
flashing (where probing is gated on VIP_DISABLED). This caused all
subsequent digest entries to shift, resulting in hash mismatches on
the device.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Usage of __unused macro before the variable name leads
to triggering checkpatch sanity check:
CHECK: spaces preferred around that '*' (ctx:WxV)
Fix this by moving the macro to the end of a function param
declaration, like it's done in the Linux kernel code.
Fixes: a79a572f18 ("Address unused parameter warnings")
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Use __unused attribute to suppress compile warnings for callback
implementations, where some parameters aren't used. For example:
warning: unused parameter ‘qdl’ [-Wunused-parameter]
./firehose.c:257:80: warning: unused parameter ‘rawmode’ [-Wunused-parameter]
257 | static int firehose_configure_response_parser(xmlNode *node...
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
During QRB2210 provisioning, a USB write failure has been
observed early in the Firehose phase (first block write).
This issue has been traced to a timeout during the USB
bulk transfer of the Zero-Length Packet (ZLP).
In some conditions, the ZLP transfer may take longer than
the current timeout, up to approximately 1.7 seconds.
The issue specifically occurs after a prior large eMMC write
operation (e.g., during a previous QDL session). It could then
be related to internal eMMC I/O operations or timing delays
affecting the USB ack.
To resolve this issue, we introduce a timeout parameter to the
qdl_write function, consistent with the existing qdl_read, and
we increase the timeout to 10 seconds for Firehose raw binary
write operations to avoid 'false-positive' timeout.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Address these issues reported by checkpatch.pl script:
WARNING: void function return statements are not generally useful
+ return;
+}
WARNING: void function return statements are not generally useful
+ return;
+}
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
This extends the Firehose protocol implementation to support the VIP
extension. It implements a state machine that counts the number of
packets sent, then injects the VIP table as the next RAW packet when
the Firehose programmer runs out of provided digests and needs a new table
of digests to validate the next packets. For example:
Packet 0: DigestsTableToSign.bin.mbn (53 digest + 1 digest of next table)
Packet 1: <configure>
Packet 2: <program>
Packet 3: ...
...
Packet 54: ChainedTableOfDigests0.bin (255 digests + digest of next table)
Packet 55: <program>
...
Packet 309: ChainedTableOfDigests1.bin
To enable VIP extension provide a path where previously generated VIP
tables are stored using "--vip-table-path" param:
$ qdl --vip-table-path "<vip-table-path>" prog_firehose_ddr.elf \
rawprogram*.xml patch*.xml
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Address all obvious coding style issues caught by checkpatch.pl tool.
sha2.c and sha2.h were kept as there are.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Add SPDX-License-Identifier line to each source file that
contains license text. More details about SPDX license identifiers
can be found at [1].
The scancode-toolkit [2] was used to match license text to the correct
SPDX-License-Identifier:
$ scancode --license --copyright --html scancode_result.html ./
[1] https://spdx.org/licenses/
[2] https://github.com/nexB/scancode-toolkit
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Add support for Digests Table generation for Validated Image
Programming (VIP), which is activated when Secure Boot is enabled
on the target. VIP controls which packets are allowed to be issued to
the target. Controlling the packets that can be sent to the target is
done through hashing. The target applies a hashing function to all
received data, comparing the resulting hash digest against an existing
digest table in memory. If the calculated hash digest matches the next
entry in the table, the packet (data or command) is accepted; otherwise,
the packet is rejected, and the target halts.
This change introduces logic for VIP table generation.
In the current VIP design the first signed hash table can be a
maximum of 8 KB. Considering that it must be in MBN format, and in
addition to the raw hash table, it also includes an MBN header,
a signature, and certificates, the number of hash digests it can
contain is limited to 54 hashes (a 40-byte MBN header +
a 1696-byte hash table + a 256-byte signature + 6144 bytes of certificates).
All hashes left are stored in the additional ChainedTableOfDigests<n>.bin
files.
To generate table of digests run QDL with --create-digests param,
providing a path to store VIP tables.
As a result 3 types of files are generated:
- DIGEST_TABLE.bin - contains the SHA256 table of digests for all firehose
packets to be sent to the target. It is an intermediary table and is
used only for the subsequent generation of "DigestsToSign.bin" and
"ChainedTableOfDigests.bin" files. It is not used by QDL for VIP
programming.
- DigestsToSign.bin - first 53 digests + digest of ChainedTableOfDigests.bin.
This file has to be converted to MBN format and then signed with sectools:
$ sectools mbn-tool generate --data DigestsToSign.bin --mbn-version 6
--outfile DigestsToSign.bin.mbn
$ sectools secure-image --sign DigestsToSign.bin.mbn --image-id=VIP
Please check the security profile for your SoC to determine which version of
the MBN format should be used.
- ChainedTableOfDigests<n>.bin - contains left digests, split on
multiple files with 255 digests + appended hash of next table.
For example, for 400 packets supposed to be sent to the target, these files
will be generated (all digests are 32 bytes in size):
DIGEST_TABLE.bin
_____________
| Digest 0 |
| Digest 1 |
| etc. |
| |
| Digest 399 |
|_____________|
DigestsTableToSign.bin ChainedTableOfDigests0.bin ChainedTableOfDigests1.bin
___________________ ___________________ ____________
| Digest 0 | | Digest 53 | | Digest 308 |
| Digest 1 | | Digest 54 | | Digest 309 |
| etc. | | etc. | | etc. |
| Digest 52 | | Digest 307 | | Digest 399 |
| Next table digest | | Next table digest | |____________|
|___________________| |___________________|
When QDL is executed with --debug parameter, it will also report
Firehose packet SHA-256 hashes, for example:
FIREHOSE WRITE: <?xml version="1.0"?>
<data><patch SECTOR_SIZE_IN_BYTES="4096" byte_offset="72" filename="DISK"
physical_partition_number="5" size_in_bytes="8"
start_sector="NUM_DISK_SECTORS-1" value="NUM_DISK_SECTORS-5."/></data>
FIREHOSE PACKET SHA256: a27b1459042ea36f654c5eed795730bf73ce37ce5e92e204fe06833e5e5e1749
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
This mode assists in validating the `rawprogram_.xml` and `patch_.xml`
files, as well as the Firehose commands that are expected to be sent
to the Firehose programmer.
Dry run implementation is also expected to be extended for
the Digests Table generation required for Firehose Validated Image
Programming (VIP).
Example of usage:
$ qdl --dry-run --serial=0AA94EFD --debug prog_firehose_ddr.elf rawprogram*.xml patch*.xml
qdl version v2.1-24-g30ac3a8-dirty
This is a dry-run execution of QDL. No actual flashing has been performed
waiting for programmer...
FIREHOSE WRITE: <?xml version="1.0"?>
<data><configure MemoryName="ufs" MaxPayloadSizeToTargetInBytes="1048576"
verbose="0" ZLPAwareHost="1" SkipStorageInit="0"/></data>
FIREHOSE WRITE: <?xml version="1.0"?>
<data><configure MemoryName="ufs" MaxPayloadSizeToTargetInBytes="0"
verbose="0" ZLPAwareHost="1" SkipStorageInit="0"/></data>
accepted max payload size: 0
FIREHOSE WRITE: <?xml version="1.0"?>
<data><program SECTOR_SIZE_IN_BYTES="4096" num_partition_sectors="131072"
physical_partition_number="0" start_sector="6" filename="efi.bin"/></data>
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>