pureboot: PI lint, tightened gates, and the self-update test suite
check_pi.py asserts the two link-time facts position independence rests on (no absolute jmp/call; the info block within the image's first 256 bytes); the size gates drop to 510 on the tinies for the trampoline word. New per-chip tests beside the reworked protocol test: the planner units (programming orders and their recovery properties, the surgery, staging composition, boot-fuse decode, and the update preflight's error/warning matrix over synthetic fuse bytes), the relocated-copy sweep (the identical image installed one slot lower serves the full command set — the PI acceptance test, and the one that caught the temporary-buffer trap), and the self-update end-to-end: --update-loader to a re-timed build (pureboot9, byte-different by PUREBOOT_TIMEOUT alone), then every power-fail phase killed mid-write, restarted from the runner's flash dump, and completed by a re-run with the application intact throughout. The mega rounds run the BOOTRST-unprogrammed profile: the fixture application's 'L' jump is the application-owned loader entry that profile relies on. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
// Test-fixture application for the pureboot protocol test: prints "APP" on
|
||||
// the chip's serial link (the same link the loader uses) and idles — the
|
||||
// proof that the loader's hand-over, and on the tinies the host's
|
||||
// reset-vector surgery, actually launched it. Linked normally (crt, vectors
|
||||
// at 0); on the tinies its reset vector is the rjmp the host re-homes.
|
||||
// Test-fixture application for the pureboot protocol tests: prints "APP" on
|
||||
// the chip's serial link (the same link the loader uses) — the proof that
|
||||
// the loader's hand-over, and on the tinies the host's reset-vector
|
||||
// surgery, actually launched it. Linked normally (crt, vectors at 0); on
|
||||
// the tinies its reset vector is the rjmp the host re-homes.
|
||||
//
|
||||
// On the mega it then listens, and an 'L' makes it jump into the resident
|
||||
// loader — the application-owned loader entry a BOOTRST-unprogrammed mega
|
||||
// relies on (reset always boots the application there), exercised by the
|
||||
// self-update tests. The tinies idle: reset reaches their loader through
|
||||
// the patched vector, so the application owes it nothing.
|
||||
#include <libavr/libavr.hpp>
|
||||
|
||||
using namespace avr::literals;
|
||||
@@ -27,6 +33,12 @@ struct link {
|
||||
{
|
||||
tx_t::write(static_cast<std::uint8_t>(c));
|
||||
}
|
||||
[[noreturn]] static void idle()
|
||||
{
|
||||
for (;;)
|
||||
if (tx_t::read_blocking() == 'L')
|
||||
reinterpret_cast<void (*)()>((avr::hw::db.mem.flash_size - 512) / 2)();
|
||||
}
|
||||
};
|
||||
|
||||
template <avr::hertz_t C>
|
||||
@@ -36,6 +48,11 @@ struct link<C, false> {
|
||||
{
|
||||
tx_t::write(static_cast<std::uint8_t>(c));
|
||||
}
|
||||
[[noreturn]] static void idle()
|
||||
{
|
||||
while (true) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -46,6 +63,5 @@ int main()
|
||||
link<dev::clock>::tx('A');
|
||||
link<dev::clock>::tx('P');
|
||||
link<dev::clock>::tx('P');
|
||||
while (true) {
|
||||
}
|
||||
link<dev::clock>::idle();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user