You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Installing a bundle over the network makes the transfer nearly free, so
it is fine that a bundle carries every file on the card whether it
changed or not. Over the cable that assumption inverts: the wire is the
expensive part, and most of what crosses it is already on the card, byte
for byte.
Prerequisite for a serial install being pleasant rather than merely
possible (#10), and worth having on its own.
What a real card looks like
The water sensor's bundle, which is the one that motivated this:
entry
size
changes
start.elf
3.02 MB
with a Raspberry Pi firmware release
bootcode.bin
52 KB
with a Raspberry Pi firmware release
fixup.dat
7 KB
with a Raspberry Pi firmware release
kernel7.img
1.69 MB
every build
www/, config.txt
~22 KB
occasionally
bundle
4.79 MB
3.08 MB of that — 64% — is Raspberry Pi's boot firmware, which changes
about once a year. The part that is actually different on a normal
update is the 1.69 MB kernel.
At 1.5 Mbaud, taking #1's figure of ~27 ms per 4 KB chunk, the whole
bundle is ~32 s of wire time and ~20 s of it is spent sending files the
card already holds. If the bytes go per-file through sd-write rather
than into a staged buffer, the ~167 ms per chunk that issue measures its
estimates against makes it minutes instead. Those are arithmetic on a
baud rate, like #1's, not a measurement of this loader.
The device already computes the answer and throws it away
apply's per-entry install asks on_cardbefore writing anything —
length from the directory entry first, then a CRC-32 of the file — and
skips the write when it matches. A bundle full of unchanged firmware
already installs without writing that firmware.
So the card read this needs is not new work; it happens on every update
today. What makes a serial install slow is only that the bytes were
shipped before the question was asked. Ask first, in one short
command, and the transfer disappears at no extra cost to the card.
The command
CMD_SD_CRC32 = 11, PROTOCOL_VERSION 2 → 3. Takes a path the way
the other sd-* commands do; answers u32 length and u32 CRC-32, or
the not-found code that already exists.
CRC-32/ISO-HDLC via bundle::checksum, so host and device produce the
same number by construction rather than by two implementations
agreeing. Same reason the container has one implementation.
No new weakening: a checksum instead of a byte compare is the trade apply already documents and takes, and this asks the identical
question.
rpi-loader sd-crc32 <remote> as a subcommand too. It earns its
place without OTA — confirming a card holds the image you think it does
currently means sd-reading 3 MB back over the wire and comparing on
the host.
A batch form — host sends N × (path, len, crc), device answers a bitmap —
is the obvious next optimization and should wait for a measurement. N is
a few dozen, and the per-entry cost is a card read, so round trips are
unlikely to be the term that hurts.
Trimming the bundle
The host asks about every entry, drops the ones that match, and
re-encodes what is left before sending it.
Only the copy that goes over the cable is trimmed. The .bundle on
disk stays whole; a bundle you can archive and apply to a blank card is
most of the point of having a container.
Safe by construction, because the predicate is "the card's bytes
already are the bundle's bytes". The end state is identical whether the
entry is sent or skipped, which is why this is not a delta format and
needs no reasoning about what a file used to be.
Trap: Bundle::parse enforces the start*.elf/fixup*.dat
pairing, and it enforces it on the device. Trim start.elf on its
own and the whole bundle comes back UnpairedFirmware. So the trim
treats the pair as one unit: both match, both go; either differs, send
both. That costs nothing real — they are released together and change
together — and it respects a check that exists to stop a board being
bricked instead of sneaking past it.
If every entry matches, send nothing and say so.
A format v3 alternative would be an entry carrying a checksum and no
data, meaning "the card should already have this": the device could then
re-verify what was skipped, and the pairing rule would see both halves.
Worth writing down and not worth doing yet — it costs a format version,
and while the loader is the only thing running there is nothing that
could change the card between the question and the install.
The network path wants this too
A 4.79 MB upload over Wi-Fi is not free either, and the same trim would
cut it to the kernel. The query there is application-shaped — an HTTP
endpoint answering the same question — but the predicate is the crate's
in both cases, so this should be built as a crate-level question with two
transports rather than as a serial feature.
Acceptance
On hardware: install a bundle over the cable, rebuild only the kernel,
install again — the second transfer carries ~1.7 MB instead of ~4.8 MB
and the board boots the new kernel. Then touch fixup.dat alone and
confirm both firmware halves are resent and the bundle is accepted.
Installing a bundle over the network makes the transfer nearly free, so
it is fine that a bundle carries every file on the card whether it
changed or not. Over the cable that assumption inverts: the wire is the
expensive part, and most of what crosses it is already on the card, byte
for byte.
Prerequisite for a serial install being pleasant rather than merely
possible (#10), and worth having on its own.
What a real card looks like
The water sensor's bundle, which is the one that motivated this:
start.elfbootcode.binfixup.datkernel7.imgwww/,config.txt3.08 MB of that — 64% — is Raspberry Pi's boot firmware, which changes
about once a year. The part that is actually different on a normal
update is the 1.69 MB kernel.
At 1.5 Mbaud, taking #1's figure of ~27 ms per 4 KB chunk, the whole
bundle is ~32 s of wire time and ~20 s of it is spent sending files the
card already holds. If the bytes go per-file through
sd-writeratherthan into a staged buffer, the ~167 ms per chunk that issue measures its
estimates against makes it minutes instead. Those are arithmetic on a
baud rate, like #1's, not a measurement of this loader.
The device already computes the answer and throws it away
apply's per-entry install askson_cardbefore writing anything —length from the directory entry first, then a CRC-32 of the file — and
skips the write when it matches. A bundle full of unchanged firmware
already installs without writing that firmware.
So the card read this needs is not new work; it happens on every update
today. What makes a serial install slow is only that the bytes were
shipped before the question was asked. Ask first, in one short
command, and the transfer disappears at no extra cost to the card.
The command
CMD_SD_CRC32 = 11,PROTOCOL_VERSION2 → 3. Takes a path the waythe other
sd-*commands do; answersu32length andu32CRC-32, orthe not-found code that already exists.
bundle::checksum, so host and device produce thesame number by construction rather than by two implementations
agreeing. Same reason the container has one implementation.
applyalready documents and takes, and this asks the identicalquestion.
rpi-loader sd-crc32 <remote>as a subcommand too. It earns itsplace without OTA — confirming a card holds the image you think it does
currently means
sd-reading 3 MB back over the wire and comparing onthe host.
rpi-loader-ota", the device sideis
on_cardwith itsdataargument replaced by a(len, crc)pair.Publish that from the crate; do not write the second copy.
A batch form — host sends N × (path, len, crc), device answers a bitmap —
is the obvious next optimization and should wait for a measurement. N is
a few dozen, and the per-entry cost is a card read, so round trips are
unlikely to be the term that hurts.
Trimming the bundle
The host asks about every entry, drops the ones that match, and
re-encodes what is left before sending it.
.bundleondisk stays whole; a bundle you can archive and apply to a blank card is
most of the point of having a container.
already are the bundle's bytes". The end state is identical whether the
entry is sent or skipped, which is why this is not a delta format and
needs no reasoning about what a file used to be.
Bundle::parseenforces thestart*.elf/fixup*.datpairing, and it enforces it on the device. Trim
start.elfon itsown and the whole bundle comes back
UnpairedFirmware. So the trimtreats the pair as one unit: both match, both go; either differs, send
both. That costs nothing real — they are released together and change
together — and it respects a check that exists to stop a board being
bricked instead of sneaking past it.
A format v3 alternative would be an entry carrying a checksum and no
data, meaning "the card should already have this": the device could then
re-verify what was skipped, and the pairing rule would see both halves.
Worth writing down and not worth doing yet — it costs a format version,
and while the loader is the only thing running there is nothing that
could change the card between the question and the install.
The network path wants this too
A 4.79 MB upload over Wi-Fi is not free either, and the same trim would
cut it to the kernel. The query there is application-shaped — an HTTP
endpoint answering the same question — but the predicate is the crate's
in both cases, so this should be built as a crate-level question with two
transports rather than as a serial feature.
Acceptance
On hardware: install a bundle over the cable, rebuild only the kernel,
install again — the second transfer carries ~1.7 MB instead of ~4.8 MB
and the board boots the new kernel. Then touch
fixup.datalone andconfirm both firmware halves are resent and the bundle is accepted.