rmtree() concatenates the directory path and entry name into a
PATH_MAX buffer without checking for truncation, which -Wformat-
truncation flags on the Windows build where PATH_MAX is 260. A
truncated path would also make the cleanup delete the wrong file in
principle.
Check the snprintf() result and skip entries that do not fit; using
the return value also satisfies the warning. A skipped entry means
the parent rmdir() fails with ENOTEMPTY and the workdir lingers, so
report the skip on stderr instead of hiding it - the message names
the entry, making a leftover workdir traceable to its cause.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
The WSL2 section carries a typographic apostrophe and em dashes;
project documentation is plain ASCII (see AGENTS.md). Replace them
with their ASCII equivalents.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Describe the kernel-style stable branches (qdl-X.Y.y) agreed for
shipping urgent fixes independently of master: cut the branch from
the release tag immediately after tagging, backport fixes that landed
on master with cherry-pick -x through stable-targeted pull requests
(CI runs on those unchanged), and cut point releases (vX.Y.Z) from
the branch with the same flow as a normal release.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
The markdown lint wrapper names README.md and docs/ explicitly, so
documents like AGENTS.md, CONTRIBUTING.md and RELEASING.md have never
been linted and accumulated findings silently.
Derive the file list from git ls-files instead, excluding
CHANGELOG.md - generated by the release process, where long
release-note URLs and per-release repeated section headers are part
of the format - and CLAUDE.md, a symlink to the already-linted
AGENTS.md. New documents are picked up automatically.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Preparation for linting every markdown file in the tree: surround the
sign-off example in AGENTS.md with the blank lines the linter wants,
and flatten the RELEASING.md table of contents - its single top-level
entry only repeated the document title, and the nested indentation
tripped the linter's list-indent rule under kramdown.
While at it, replace the literal Signed-off-by example with the
'git commit -s' command that produces it. checkpatch validates
anything shaped like a signature tag on any patch line - added,
removed and context lines alike - so any patch touching these lines
trips 'Unrecognized email address' on the $(git config ...)
placeholders. Documenting the command instead keeps trailer-shaped
text out of the file entirely, with no checkpatch exceptions needed.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
The Windows branch reads path[1] guarded only by short-circuit
evaluation, which is correct at runtime but trips -Warray-bounds when
the function is inlined with a string literal shorter than two bytes,
as the oscompat unit tests do with "". It also passes a plain char
to isalpha(), which is undefined behavior for negative values.
Return early for the empty string, so the path[1] access is provably
in bounds, and feed isalpha() an unsigned char.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
The signed VIP table (DigestsToSign.bin.mbn) and the chained digest
tables are opened in vip_transfer_init() with a plain O_RDONLY. On
Windows/MSYS2 a descriptor opened without O_BINARY defaults to text
mode, which performs CRLF translation and treats a 0x1A (Ctrl-Z) byte
as end-of-file.
These tables are arbitrary binary data (e.g. the 8192-byte signed
table). As soon as read() hits a 0x1A byte or collapses a CRLF pair it
returns fewer bytes than the file size, so vip_transfer_send_raw() fails
its n == sb.st_size length check and aborts with "failed to read
binary". The VIP configure request then fails. On Linux there is no
text/binary distinction (O_BINARY is defined as 0) so the same code
works fine.
Add O_BINARY to both open() calls in vip_transfer_init(), matching what
write_digests_to_table() already does, so the tables are read verbatim
on Windows as well.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
EDL, crash-mode and ramdump devices enumerate with a growing set of
product ids, and every newly discovered variant needed another
allowlist entry - devices with ids not yet on the list were silently
invisible until someone updated it. Both backends now identify the
EDL function by the vendor-specific interface signature instead: the
libusb backend via the config descriptors, the QUD backend via the
Windows compatible ids derived from them.
Trust the vendor id alone in qdl_is_edl_device() and drop the
now-redundant pid gate in the QUD enumeration. The pid parameter
stays in the signature so call sites are unchanged; the interface
gates are what reject non-EDL Qualcomm devices from here on.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
The QUD backend accepts any Qualcomm COM port whose pid is on the
shared EDL allowlist, while the libusb backend identifies the EDL
function by its interface signature - vendor-specific class and
subclass with a known Sahara protocol. Windows exposes exactly that
triple without opening the device: PnP derives compatible ids of the
form "USB\Class_xx&SubClass_xx&Prot_xx" for every USB devnode,
including each interface of a composite device.
Require the same signature set the libusb backend matches (0x10, 0x11
and 0x13 on modern devices, 0xff on older targets), bringing the two
backends' notion of an EDL device in line and filtering Qualcomm COM
ports that expose no vendor-specific function at all.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
The nbdkit plugin is undiscoverable without documentation. Describe how to
build it with meson (including the nbdkit development dependency) and walk
through serving a LUN end to end: starting nbdkit, confirming the export
with nbdinfo, attaching it to /dev/nbdN with nbd-client, and reading it,
plus a warning that writes go straight to the device's flash.
The walkthrough lives in docs/nbd.md to keep the ever growing README lean;
the README gets a short section pointing to it, and the markdown-lint
wrapper now lints everything under docs/ so future documents are covered
automatically.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Inspecting or editing a device's flash previously meant dumping partitions
to files and reflashing them; there was no way to treat the live storage as
a random-access block device. Exposing a LUN over nbdkit lets ordinary host
tools - parted, mount, dd, imaging tools - operate on it directly.
Add an nbdkit plugin that uploads the firehose programmer and serves a
physical partition (LUN) as a read/write block device:
$ modprobe nbd
$ nbdkit -fv ./nbdkit-qdl-plugin.so programmer=prog_firehose_ddr.elf lun=0
meson builds it only when the nbdkit dependency is present (pass
-Dnbdkit=enabled to require it), producing nbdkit-qdl-plugin.so from the
shared qdl sources; the qdl binary is unaffected.
An EDL device can only be programmed once per session - uploading the
programmer is a one-shot transition and a reset reboots it out of firehose
- but nbdkit calls .open/.close several times per client (NBD_OPT_INFO to
probe, then NBD_OPT_GO to transfer). Programming per open and resetting per
close therefore made the first close reboot the board and every later open
time out. To solve this the plugin sets the device up once, on the first
open, keeps it configured across connections, and resets it only when the
plugin unloads.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
decode_sahara_config() was defined in qdl.c - the command-line front-end -
but it is also called from contents.c, which is part of the shared qdl
library. The qdl binary links both, so it built and ran fine; but any
program that links the library without qdl.c ends up with an undefined
reference to decode_sahara_config().
That is exactly what happens to the nbdkit plugin, which is built from
the shared sources plus its own entry point and no qdl.c: loading the
resulting shared object aborts with "undefined symbol:
decode_sahara_config".
Move the function into a dedicated src/sahara_config.c that is part of
the shared source set, so the library is self-contained. It is kept in
its own translation unit rather than folded into contents.c so that the
contents unit tests, which #include contents.c and stub this function,
keep working.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
The firehose layer only drives file-oriented flashing: <program>/<read>
operations described by XML and executed as an op list. Nothing let an
in-process consumer configure the programmer on its own, learn how large a
LUN is, or read and write arbitrary sector ranges to and from memory
buffers.
The upcoming nbdkit plugin needs exactly that - random-access block I/O
against a live device - so add the missing primitives:
- firehose_open() configure the programmer without running any ops
- firehose_getsize() report a LUN's sector size and count, parsed from
the <getstorageinfo> JSON response
- firehose_pread() read a sector range into a buffer, reusing the
chunked read path
- firehose_pwrite() write a buffer to a sector range, streaming it in
max_payload_size chunks
- firehose_reset() made non-static, out-of-tree callers can reuse it
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Kernel-style commit bodies occasionally wrap a sentence or an
example command a few characters past 72, which tripped
commitlint's body-max-line-length even though the messages are
otherwise fine. Raise the body limit from 72 to 75 to match the
wrapping already used in the tree.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Sahara is identified by bInterfaceProtocol 0x10, 0x11, or 0x13 on
modern devices, and 0xff on older targets. Add 0x13 to the accepted
protocols and use hex notation consistently.
Signed-off-by: Yvonne Kaire <ykaire@qti.qualcomm.com>
The usage synopsis documents input XML files and the command verbs
(read/write/erase/sha256/flash/reset) as separate invocation forms,
but the argument loop accepted any mixture of them. Combining a bare
program XML with the reset verb, for example, appended the reset op
during parsing - before qdl_determine_bootable() adds the
setbootablestoragedrive op after the loop - so the device could be
told to reboot before its bootable storage drive was set. The same
mixture on the provisioning path silently performed no reset at all.
Rather than order the two against each other, reject the combination:
track whether a file-type and a verb-type argument have both been
seen and error out when they have. This keeps each documented form
self-consistent and makes the reset verb usable only on its own or
alongside other verbs, where ordering is well defined.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Several long-standing robustness gaps in the Firehose layer:
- firehose_write() keyed its timeout retry on errno, but the qdl_write()
backends report the timeout through the return value and never touch
errno, so the retry could misfire and a stale errno leaked into the
return code. Key both the retry and the error return on the return
value, and free the serialized document on the VIP send-table error
path.
- firehose_configure_response_parser() leaked the response value on the
ACK path when MaxPayloadSizeToTargetInBytesSupported was absent; free
it.
- firehose_program() and firehose_issue_read() divided by a sector size
that could be zero; guard against it and fail cleanly. Route the
VIP send-table failure through the existing cleanup path instead of
returning with the document and buffer still allocated.
- firehose_detect_and_configure() ignored its skip_storage_init argument
and always passed false; honor the caller's request.
- Normalize a few error returns to -1 so callers see a consistent
failure status.
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
firehose_read() read up to sizeof(buf) bytes and then wrote a NUL at
buf[n], overflowing the stack buffer by one byte whenever a read filled
it - routine on stream transports that concatenate responses. Read at
most sizeof(buf) - 1 bytes.
Fixes: da68b4add8 ("qdl: Support for program and patch")
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
firehose_program() logged a failed or NAK'd final programming response
but then returned 0, so firehose_execute_ops() carried on and qdl
exited successfully with the partition left unwritten. Return an error
on a non-ACK final response.
Fixes: a9ec681705 ("program: Refactor the global "programs" list")
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
qdl ramdump passes a NULL images array, but the READ_DATA handlers and
the done-pending quirk indexed it unconditionally and crashed when the
device requested an image. Treat NULL images as "none". Also make the
offset+len range check overflow-safe, use a signed type for write()'s
result, propagate I/O errors from the ramdump helper, bound the region
loop by the bytes actually read, and reject region filenames that
contain a path separator.
Fixes: ff1a3bb1d3 ("ramdump: Make ramdump a qdl subcommand")
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
GPT LBAs are 64-bit but were narrowed to unsigned int, so a partition
beyond 2 TB wrapped and a name-addressed write/erase hit the wrong
sectors. Carry start_sector/num_sectors as uint64_t and range-check
before storing num_sectors. Also reject a bad part_entry_size, fix an
off-by-one in the UTF-16 surrogate handling that read past the name
buffer, and initialise the sim-mode outputs.
Fixes: 60db50966d ("qdl: Extend read/write support to accept GPT partition names")
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>