Skip to content

Commit 72854cf

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 9b79b34 commit 72854cf

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
@@ -201,6 +201,25 @@ function* firmwareIterator(data: DataView, maxSize: number): Generator<number> {
201201
}
202202
}
203203

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

381-
const firmware = new Uint8Array(firmwareBase.length + checksumExtraLength);
400+
const ev3ExtraLength =
401+
metadata['device-id'] === HubType.EV3
402+
? computeEv3ExtraLength(firmwareBase.length)
403+
: 0;
404+
405+
const firmware = new Uint8Array(
406+
firmwareBase.length + checksumExtraLength + ev3ExtraLength,
407+
);
382408
const firmwareView = new DataView(firmware.buffer);
383409

384410
firmware.set(firmwareBase);

0 commit comments

Comments
 (0)