97 Commits
Author SHA1 Message Date
Igor Opaniuk ba46b53f39 Merge pull request #336 from bhavyaVeera/add-qsahara-error-descriptions
sahara: describe status codes in end-of-image and done packets
2026-10-05 21:32:36 +02:00
Veera, Bhavya 737840b1e1 sahara: describe status codes in end-of-image and done packets
Sahara end-of-image and done packets report compact status values from
the target. Including protocol-defined end-of-image descriptions and
the done transfer state alongside the numeric values makes
authentication, hash verification, and transfer-completion results
easier to identify from logs.

Add descriptions for Sahara status codes when logging end-of-image
results, and print done status as pending or complete.

Signed-off-by: Veera, Bhavya <bveera@qti.qualcomm.com>
2026-10-05 23:44:37 +05:30
Igor Opaniuk afddc7d588 Merge pull request #323 from igoropaniuk/refactor/flash-cli
qdl: split the flashing front-end from the CLI plumbing
2026-10-02 21:11:04 +02:00
Igor Opaniuk e7f8f2fc87 Merge pull request #322 from JohnSagaQuic/UFS_Provisioning_EID
firehose: treat -ENODEV on commit=1 as success after UFS provisioning
2026-10-02 19:56:13 +02:00
Zhirong Chen 3797094362 firehose: treat -ENODEV on commit=1 as success after UFS provisioning
Some UFS programmers reset the device right after committing the
configuration descriptor, dropping the USB link before sending the
ACK, so qdl reports a failure although provisioning succeeded.

Map LIBUSB_ERROR_NO_DEVICE to -ENODEV in usb_read() and, when the
device disappears after commit=1, treat it as success and skip the
final reset. Any real descriptor error would already have been
NAKed during the earlier exchange. A disconnect during the commit=0
dry run remains a hard error.

Signed-off-by: Zhirong Chen <zhirongc@qti.qualcomm.com>
2026-10-02 19:47:45 +02:00
Igor Opaniuk ebb28bf027 cli: extract argument parsing into its own module
With qdl_parse_args() self-contained, move it plus print_usage() and
the shared long-option ids into cli.c, out of main()'s compilation
unit, so unit tests can link the option parser directly.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-10-01 10:53:46 +02:00
Igor Opaniuk c0688c775d qdl: split qdl_flash into argument parsing, op-list build and run
qdl_flash() mixed three concerns in 330 lines: option decoding, the
positional-argument walk and the device session. Split them into
qdl_parse_args() (filling struct qdl_opts), qdl_build_op_list() and a
plain session sequence, so each can be reasoned about - and tested -
alone. Options, messages and run order are unchanged; the op-list
builder takes the options mutably because the reset verb overrides
skip-reset.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-10-01 10:53:46 +02:00
Igor Opaniuk a45bf832cd tests: add read and patch XML loader unit tests
patch_load_xml() and read_op_load() turn XML into firehose op lists
and had no direct coverage. Add a cmocka suite (linking util.c for
the real attribute accessors and stubbing the device/ux layers) that
checks a valid entry produces the expected op, that an unrecognized
child tag is skipped, and - locking in the recently fixed error
propagation - that a malformed entry or a missing file makes the
loader return an error instead of reporting success.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-10-01 10:53:46 +02:00
Igor Opaniuk 1c777e2d77 vip: prefix all diagnostics with VIP:
Sahara and Firehose traces carry a "SAHARA: " or "FIREHOSE: " tag, but
most VIP messages have none and the few that do mix "VIP:" with a bare
"VIP TABLE DIGESTS" or a Firehose-tagged packet digest.

Prefix every message from vip.c and the VIP negotiation in firehose.c
with "VIP: ", drop the now redundant "VIP" from message bodies, and
move the packet digest trace under the VIP tag since it belongs to
table generation. The sim's own "sim: VIP ..." messages keep their
prefix.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-10-01 10:30:41 +02:00
Igor Opaniuk 6bd50388af oscompat: drop the unused err/warn shims
All diagnostics go through the ux_warn()/ux_die() helpers now, so the
err(3)-style shims and the <err.h> include are dead code.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-10-01 10:27:58 +02:00
Igor Opaniuk c7a4e6b56d firehose: tag all traces with a FIREHOSE: prefix
Sahara diagnostics are now tagged "SAHARA: ", while the Firehose
traces use a mix of "FIREHOSE READ:", "FIREHOSE WRITE:" and a bare
"LOG:" for device log lines, so the two stages do not line up in a
debug log.

Use "FIREHOSE: <TAG>: " for every Firehose trace, including device
logs and raw binary writes, so all protocol output
follows the same "<STAGE>: " format.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-10-01 10:27:58 +02:00
Igor Opaniuk b6d0f88de7 sahara: prefix all diagnostics with SAHARA:
Firehose traces are tagged FIREHOSE READ/WRITE, but Sahara messages
such as "HELLO version" or "READ image" carry no hint of where they
come from, and only a few had an ad-hoc "Sahara:" prefix. In a
timestamped debug log this makes the two protocol stages hard to tell
apart.

Prefix every message emitted by sahara.c with "SAHARA: ", fold the
existing ad-hoc prefixes into it, and drop the now redundant "Sahara"
from message bodies. The chipinfo report table is command output
rather than a diagnostic and is left unchanged.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-10-01 10:21:20 +02:00
Igor Opaniuk b95f0946d2 firehose: trace XML messages on a single debug line
libxml2 dumps a document with a newline after the declaration and at
the end, and some devices terminate their responses the same way. With
timestamped debug output every FIREHOSE WRITE therefore spans two lines
and is followed by a blank one, which makes the trace hard to scan.

Strip newlines from the XML before printing so each read and write is
one line, matching how devices format their responses.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-10-01 10:21:20 +02:00
Igor Opaniuk ee3d93fc22 ux: route remaining diagnostics through shared logging
USB warnings, Sahara ramdump failures, fatal CLI and archive errors,
and packet hex dumps bypass the ux helpers, so they never get a
--debug timestamp and leave gaps in the protocol timeline.

Route them through shared logging via new warn and die helpers that
keep the program-name prefix, errno text, and exit status. Output
without --debug is unchanged and hex dumps stay visible in both modes.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-10-01 10:21:20 +02:00
Igor Opaniuk 65711e63a1 ux: own the program name used in diagnostics
The error prefix comes from __progname, a BSD-ism that glibc and the
Apple libc export but Windows lacks, so qdl.c and every unit test that
links util.c define their own copy. The nbdkit plugin links neither.

Keep the name in ux.c with a "qdl" default and set it through
ux_set_progname(): from argv[0] in main() and from the plugin's load
hook. Move print_version() into qdl.c, its only caller, so util.c and
the tests no longer need the symbol.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-10-01 10:21:20 +02:00
Igor Opaniuk c6774482b6 ux: timestamp messages in debug mode
Debug logs give no indication of when a message was emitted, which
makes stalls and timeouts hard to pin down and host activity hard to
correlate with device logs.

Prefix every message with the local time at millisecond resolution
when --debug is enabled. Keep multi-line messages aligned and track
partial lines per stream so split messages stay readable. Output
without --debug is unchanged.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-10-01 10:21:19 +02:00
Igor Opaniuk 8b5a89f34c Merge pull request #313 from igoropaniuk/refactor/qdl-extractions
qdl: decouple helper modules from the CLI front-end
2026-09-11 15:39:44 +02:00
Igor Opaniuk 657f12fa64 Merge pull request #314 from igoropaniuk/fix/firehose_ufs_provisioning_timeout 2026-09-01 20:10:20 +02:00
Igor Opaniuk 7def06c38a Merge pull request #306 from franciscojsfc/fix/nand-program-label
firehose: send the partition label in NAND program tags
2026-08-28 21:42:47 +02:00
Igor Opaniuk 14c780eb7b firehose: give the UFS provisioning commit a longer timeout
UFS provisioning drives the programmer with three <ufs> tags: a common
tag, one or more body tags, and an epilogue. The epilogue is sent twice
- first with commit=0 to validate the requested layout, then with
commit=1 to actually write the UFS configuration descriptor to the
device. All of these tags went through firehose_send_single_tag(),
which waited only 5s for the <response value="ACK"/>.

The commit=1 epilogue is the only expensive step: it makes the
programmer write the configuration descriptor to the device, which can
take considerably longer than 5s. When it does, the device emits its
"Calling handler for ufs" log but has not answered with an ACK yet, so
firehose_read() times out, firehose_send_single_tag() reports the tag
as failed, and provisioning is aborted even though the device is still
working. The program/erase write-back paths already use a 120s timeout
for exactly this reason; the UFS commit needs the same treatment.

Thread a timeout into firehose_send_single_tag() and use a short 5s
wait for the cheap common/body/validation tags while giving the commit
epilogue a 120s window. The commit=0 validation pass keeps the short
timeout.

Observed failure before the fix:

  $ qdl --storage ufs prog_firehose_ddr.elf provision_ufs31.xml --debug
  ...
  FIREHOSE WRITE: <?xml version="1.0"?>
  <data><ufs LUNtoGrow="0" commit="1"/></data>
  FIREHOSE READ: <?xml version="1.0" encoding="UTF-8" ?>
  <data>
  <log value="INFO: Calling handler for ufs" /></data>
  LOG: INFO: Calling handler for ufs
  ufs request failed
  failed to apply ufs epilogue
  UFS provisioning failed

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-08-28 16:51:16 +02:00
Igor Opaniuk b59631fa18 qdl: extract input type detection into input_type.c
How a positional argument is classified - verb, rawprogram, patch,
read, ufs or contents document - decides the whole shape of a flashing
run, yet the logic lived as private helpers of the CLI front-end where
no test could reach it, and misclassification bugs (an erase-only
rawprogram failing as "unknown file type") could only be found by
flashing. Give the classification its own module so it can be tested
directly. The contents.xml sniff used by the sahara-archive subcommand
is the same kind of decision and moves along with it.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-08-25 14:34:28 +02:00
Igor Opaniuk 9f465fa274 util: move backend and specifier parsing out of qdl.c
decode_backend() (a --backend value to enum) and qdl_split_specifier()
(splitting "<file>::<selector>") were static string parsers trapped in
qdl.c, which cannot be unit-tested because qdl.c defines main(). Move
them to util.c alongside the other argument parsers (parse_storage_
address, decode_storage_type) and declare them in qdl.h. Pure code
move, no behaviour change.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-08-25 14:34:28 +02:00
Igor Opaniuk 25c484f5f7 tests: add programmer archive decoder unit tests
The archive decoder parses an untrusted blob with hand-rolled bounds
checks, and the audit found real holes there - unvalidated image ids
and entry names among them. Those hardened paths could previously only
be exercised by handing qdl a corrupt archive on the command line.
With the decoder extracted into its own module, craft newc archives in
memory and pin the contract: a valid archive maps its images, and a
truncated header, an out-of-range or zero image id and an unterminated
name are each rejected without touching the image table.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-08-25 14:34:28 +02:00
Igor Opaniuk ec78a4881e qdl: extract programmer archive handling into programmer.c
qdl.c has grown into the tool's junk drawer, and the Sahara programmer
plumbing is its largest self-contained tenant: the specifier-to-image
mapping, the CPIO archive decoder and, since the sahara-archive
subcommand arrived, the matching writer. None of it depends on the CLI
front-end it lives in, but burying it there couples it to main()'s
compilation unit, keeps the decoder and writer of the same format at
opposite ends of a 1500-line file, and puts the logic out of unit
tests' reach. Move the lot into programmer.c, where the format has one
home and the front-end shrinks to argument handling.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-08-25 14:34:28 +02:00
Igor Opaniuk 5e668830d4 tests: add ufs provisioning loader tests
The loader's failure handling is exactly what the context refactor
changed, and nothing exercised it before - the module globals made
the loader untestable, so its error paths could only be reached with
a malformed provisioning XML in a real flashing session. Pin the new
contract while it is fresh: a malformed document must leave the
context empty rather than half-populated, cleanup must be safe to
repeat, and under ASAN the error paths must leak nothing.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-08-25 13:50:06 +02:00