Skip to content

Commit 5ed3861

Browse files
committed
firmware/ev3: pad firmware to avoid bugs
Add a function to pad EV3 firmware size to avoid potentially triggering bugs in the EV3 bootloader. When we do a download command with too small of a payload, the bootloader can send a bad response. We can work around this by ensuring that the firmware size is such that the last chunk is the maximum size. This way we never send a small chunk that could trigger the bug.
1 parent 2b07bf6 commit 5ed3861

File tree

1 file changed

+27
-1
lines changed

1 file changed

+27
-1
lines changed

src/firmware/sagas.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,25 @@ function* firmwareIterator(data: DataView, maxSize: number): Generator<number> {
199199
}
200200
}
201201

202+
function computeEv3ExtraLength(firmwareLength: number): number {
203+
// HACK: If the EV3 firmware size is not a multiple of 2 * 64KiB, then we
204+
// need to add some padding to avoid possibly triggering a bug where small
205+
// download payloads can cause bad replies. This is done by ensuring that
206+
// the last chunk is 1018 bytes.
207+
208+
const maxChunkSize = 1018;
209+
const eraseSize = 2 * 64 * 1024;
210+
const remainder = firmwareLength % eraseSize;
211+
212+
if (remainder === 0) {
213+
// Adding padding would cause an entire extra erase to be needed. Don't
214+
// do that and rely on a a different workaround (always erasing two sectors).
215+
return 0;
216+
}
217+
218+
return maxChunkSize - (remainder % maxChunkSize);
219+
}
220+
202221
/**
203222
* Loads Pybricks firmware from a .zip file.
204223
*
@@ -376,7 +395,14 @@ function* loadFirmware(
376395
throw new Error('unreachable');
377396
}
378397

379-
const firmware = new Uint8Array(firmwareBase.length + checksumExtraLength);
398+
const ev3ExtraLength =
399+
metadata['device-id'] === HubType.EV3
400+
? computeEv3ExtraLength(firmwareBase.length)
401+
: 0;
402+
403+
const firmware = new Uint8Array(
404+
firmwareBase.length + checksumExtraLength + ev3ExtraLength,
405+
);
380406
const firmwareView = new DataView(firmware.buffer);
381407

382408
firmware.set(firmwareBase);

0 commit comments

Comments
 (0)