tsb/tsb.hpp holds the link, the handshake and command bytes, the guard policy and SPM interlock, the boot geometry, act_min/comm_window and a consteval builder for the 16-byte info block, whose BUILDSTATE and ATmega marker bytes are now named rather than commented. Every tier's image is byte-identical to before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
107 lines
3.5 KiB
C++
107 lines
3.5 KiB
C++
// The TinySafeBoot native-UART fixed-baud protocol, as every tier speaks it:
|
|
// the link, the handshake and command bytes, the boot geometry and the
|
|
// device-info block the host reads on activation.
|
|
|
|
#pragma once
|
|
|
|
#include <libavr/libavr.hpp>
|
|
|
|
namespace tsb {
|
|
|
|
using namespace avr::literals;
|
|
namespace spm = avr::spm;
|
|
namespace ee = avr::eeprom;
|
|
|
|
constexpr auto clock = 16_MHz;
|
|
constexpr auto baud_rate = 115200_Bd;
|
|
|
|
// Fixed 8N1; the library solves UBRR + U2X from clock and baud.
|
|
constexpr auto baud = avr::uart::solve_baud(clock, baud_rate, 8, avr::uart::parity::none);
|
|
|
|
// One bit time on the wire: the turn-around a shared-line peer needs to stop
|
|
// driving before this one starts.
|
|
constexpr auto guard_cycles = static_cast<std::uint32_t>(clock.hz / baud.actual);
|
|
|
|
// The loader is purely polled - it never enables interrupts - so every SPM and
|
|
// EEPROM lock folds to nothing under this posture.
|
|
constexpr auto off = avr::irq::guard_policy::unused;
|
|
|
|
// Strict request/response: every SPM operation is waited out before the next
|
|
// byte moves, so no flash operation is ever in flight at an EEPROM access -
|
|
// the write procedure's step 2 has nothing to guard, the omission the
|
|
// datasheet grants (DS40002061B section 8.6.3).
|
|
constexpr auto no_spm = ee::spm_interlock::omitted;
|
|
|
|
constexpr std::uint8_t confirm = '!';
|
|
constexpr std::uint8_t request = '?';
|
|
constexpr std::uint8_t knock = '@';
|
|
constexpr std::uint8_t activation_knocks = 3;
|
|
|
|
namespace command {
|
|
constexpr std::uint8_t read_flash = 'f';
|
|
constexpr std::uint8_t write_flash = 'F';
|
|
constexpr std::uint8_t read_eeprom = 'e';
|
|
constexpr std::uint8_t write_eeprom = 'E';
|
|
constexpr std::uint8_t read_config = 'c';
|
|
constexpr std::uint8_t write_config = 'C';
|
|
} // namespace command
|
|
|
|
// The lockout-proof floor for the receive window: the oracle's F_CPU/1MHz.
|
|
constexpr auto act_min = static_cast<std::uint8_t>(clock.hz / 1'000'000);
|
|
// Post-activation window: the host gets seconds, not milliseconds, mid-session.
|
|
constexpr std::uint8_t comm_window = 200;
|
|
|
|
constexpr std::uint16_t page = spm::page_bytes;
|
|
constexpr std::uint16_t eeprom_end = avr::hw::db.mem.eeprom_size - 1;
|
|
|
|
// The config page (TSB's LASTPAGE), one page below the boot section: the
|
|
// application's jump vector, then these.
|
|
consteval std::uint16_t config_page(std::uint16_t boot_bytes)
|
|
{
|
|
return spm::flash_bytes - boot_bytes - page;
|
|
}
|
|
constexpr std::uint8_t timeout_at = 2;
|
|
constexpr std::uint8_t password_at = 3;
|
|
|
|
// The firmware version stamp, in the encoding the host decodes.
|
|
consteval std::uint16_t date_stamp(std::uint16_t year, std::uint16_t month, std::uint16_t day)
|
|
{
|
|
return year * 512 + month * 32 + day;
|
|
}
|
|
|
|
// BUILDSTATE F3: the native-UART fixed-baud lineage.
|
|
constexpr std::uint8_t build_state = 0xF3;
|
|
constexpr std::uint8_t atmega_marker = 0xAA;
|
|
|
|
consteval auto info_block(std::uint16_t build_date, std::uint16_t app_end)
|
|
{
|
|
const auto low = [](std::uint16_t word) { return static_cast<std::uint8_t>(word); };
|
|
const auto high = [](std::uint16_t word) { return static_cast<std::uint8_t>(word >> 8); };
|
|
const std::uint16_t app_end_words = app_end / 2;
|
|
return std::to_array<std::uint8_t>({
|
|
'T',
|
|
'S',
|
|
'B',
|
|
low(build_date),
|
|
high(build_date),
|
|
build_state,
|
|
avr::hw::db.signature[0],
|
|
avr::hw::db.signature[1],
|
|
avr::hw::db.signature[2],
|
|
page / 2,
|
|
low(app_end_words),
|
|
high(app_end_words),
|
|
low(eeprom_end),
|
|
high(eeprom_end),
|
|
atmega_marker,
|
|
atmega_marker,
|
|
});
|
|
}
|
|
|
|
inline const std::uint8_t *flash_ptr(std::uint16_t addr)
|
|
{
|
|
return reinterpret_cast<const std::uint8_t *>(addr);
|
|
}
|
|
|
|
} // namespace tsb
|