diff --git a/tsb/tsb_pure.cpp b/tsb/tsb_pure.cpp index c93b8fe..bc8004d 100644 --- a/tsb/tsb_pure.cpp +++ b/tsb/tsb_pure.cpp @@ -4,9 +4,9 @@ // reimplementing the TinySafeBoot wire protocol (native-UART fixed-baud // lineage) on libavr. This variant is written for clarity: well-factored // functions, no compiler-specific size hacks, no inline assembly. The only -// attributes are the ones the task inherently needs — [[gnu::progmem]] for the -// flash-resident info block and the naked reset entry that stands in for the -// absent C runtime. +// attribute is the one the task inherently needs — the naked reset entry that +// stands in for the absent C runtime; the flash-resident info block is a libavr +// flash_table. // // The structure follows the hand-written reference: one SRAM page buffer that // every page transfer shares, separate flash/EEPROM leaf routines (so nothing @@ -48,10 +48,11 @@ constexpr std::uint16_t eeprom_end = avr::hw::db.mem.eeprom_size - 1; // Firmware version stamp: YY*512 + MM*32 + DD, the encoding the host decodes. constexpr std::uint16_t build_date = 26 * 512 + 7 * 32 + 19; -// The 16-byte device-info block the host reads on activation. Flash-resident so -// it needs no .data (there is no crt to copy it). +// The 16-byte device-info block the host reads on activation. A flash_table +// keeps it in progmem with no .data image (there is no crt to copy one) and +// reads it back through LPM. // clang-format off -[[gnu::progmem]] constexpr std::uint8_t info[16] = { +inline constexpr std::array info_data = { 'T', 'S', 'B', build_date & 0xFF, build_date >> 8, 0xF3, // status byte (native-UART fixed-baud lineage) @@ -62,6 +63,7 @@ constexpr std::uint16_t build_date = 26 * 512 + 7 * 32 + 19; 0xAA, 0xAA, // ATmega processor-type marker (bytes 14 == 15) }; // clang-format on +using info = avr::flash_table; // One page staged in SRAM. Scratch that is always filled before it is read, so // it lives in .noinit — no startup clear (there is no crt to run one) and no @@ -116,8 +118,7 @@ bool request_confirm() // high, as the SPM word buffer wants). void write_flash_page(std::uint16_t addr) { - for (std::uint16_t i = 0; i < page; i += 2) - spm::fill(addr + i, static_cast(buffer[i] | (buffer[i + 1] << 8))); + spm::fill(addr, std::span{buffer, page}); spm::write_page(addr); spm::wait(); } @@ -200,7 +201,7 @@ void write_config() { // A bootloader may be entered by a watchdog reset; the reference loader // hands straight back to the application in that case rather than run. - if (avr::hw::reg<"MCUSR">::read() & avr::hw::field<"MCUSR", "WDRF">{}(1).value) + if (avr::hw::field<"MCUSR", "WDRF">::test()) appjump(); avr::init(); @@ -225,7 +226,7 @@ void write_config() for (;;) { } - send_flash(reinterpret_cast(&info[0]), sizeof(info)); + send_flash(reinterpret_cast(info::storage.data()), info::size()); for (;;) { tx(confirm); // Mainloop ready