TinySafeBoot - kompakter und sicherer Bootloader für AVR-ATtinys und ATmegas




TSB-Firmware für ATtiny & ATmega:


  • Unterstützt viele ATtinys und ATmegas

  • Lesen und Schreiben von Flash und EEPROM

  • Beliebige Ports für serielle Kommunikation verwendbar

  • One-Wire-Betrieb auch mit mehreren AVRs auf einer gemeinsamen Leitung

  • Flexible Baudrate, robustes Protokoll

  • Aktivierung über Hardware-Reset und optionales Passwort

  • Passwort und Timeout nachträglich änderbar

  • Not-Löschung ohne Passwort beseitigt alle Speicherinhalte außer Bootloader.

  • ATtinys: ca. 560 Bytes,
    ATmegas: unter 512 Bytes (!)

  • Selbst-Update des Bootloaders auf ATtinys ohne ISP-Sitzung möglich

  • Sourcecode quelloffen

TSB-Software für den PC:


  • Nutzung der TSB-Funktionen über Kommandozeile oder Dialog

  • Batch-Aufrufe möglich

  • Erzeugung benutzerspezifischer TSB-Bootloader (ohne Assembler)

  • Integrierte Datenbank mit vor-assemblierten TSB-Templates

  • Sourcecode, Compiler und Entwicklungsumgebung quelloffen

tsb logo draft (jt)



Idee

Die meisten AVR-Bootloader sind für ATmegas. Kunststück, hier gibt's besondere Reset-Vektoren für Bootloader, geschützte Speichersegmente, spezielle Fusebits, Hardware-UART und meist recht großzügigen Speicherplatz. Unter solchen Bedingungen kann man es sich dann auch leisten, ein klobiges Protokoll oder sinnfreie Krypto-Spielereien zu implementieren... Dass dies kein 'Naturgesetz' ist, beweist die schlanke ATmega-Implementierung von TSB, siehe weiter unten!

So manches Projekt, für das wir in Zeiten der Verschwendungswirtschaft vorschnell zum ATmega gegriffen hätten, ließe sich bei effizienter Programmierung und pfiffiger Ausnutzung von Portleitungen gewiss auch in einem gut ausgestatteten ATtiny realisieren. Fehlte eigentlich nur noch ein kompakter und sicherer Bootloader für's schnelle Firmware-Update zwischendurch!

Tatsächlich haben die meisten ATtinys das Feature 'Self Programming' und ein wenig SRAM an Bord. Damit sind die wichtigsten Voraussetzungen für einen Bootloader bereits erfüllt. Wir müssen uns nur etwas mehr Gedanken um Speicherverbrauch und sichere Flash-Zugriffe machen.

Die wenigen erstzunehmenden ATtiny-Bootloader sind kleine Meisterwerke an Effizienz und Kompaktheit, zumal in Assembler programmiert. In puncto Installations- und Bedienkomfort, Flexibilität und Sicherheit wirken diese Lösungen jedoch etwas rückständig...

Wer weniger auf Klickibunti steht, sondern für seine AVR-Projekte vor allem einen universellen, kompakten und robusten Bootloader sucht, der sollte einmal TinySafeBoot probieren.

Nach oben | Index



TinySafeBoot


Unterstützte ATtinys:

tn13A tn13 tn1634 tn167 tn2313A tn2313 tn24A tn24 tn25 tn261A tn261 tn4313 tn44A tn44 tn441 tn45 tn461A tn461 tn48 tn84A tn84 tn841 tn85 tn861A tn861 tn87 tn88

Hinweis: Die Liste der ATmegas (rechts) enthält weiterhin so einige "theoretische" Einträge, die ich nicht persönlich testen konnte. Sei Pionier! Berichte mir!
Unterstützte ATmegas:

m162 m164A m164PA m164P m165A m165PA m165P m168A m168 m168PA m168P m169A m169PA m169P m16A m16 m16HVA m16HVB m16M1 m16U2 m16U4 m324A m324PA m324P m3250A m3250 m3250PA m3250P m325A m325 m325PA m325P m328 m328P m3290A m3290 m3290PA m3290P m329A m329 m329PA m329P m32A m32C1 m32 m32HVB m32M1 m32U2 m32U4 m406 m48A m48 m48PA m48P m640 m644A m644 m644PA m644P m6450A m6450 m6450P m645A m645 m645P m6490A m6490 m6490P m649A m649 m649P m64C1 m64M1 m64RFR2 m8515 m8535 m88A m88 m88PA m88P m8A m8 m8HVA m8U2
Speicheraufteilung TSB auf ATtiny2313 Speicheraufteilung TSB auf ATmega8515
Speicheraufteilung:
  • Bootloader liegt im oberen Speicherbereich und belegt dort ca. 560 Bytes.

  • Aufruf: modifizierter Reset-Vektor an $0000.

  • Bootloader übergibt nach Ablauf des Timeouts an Reset-Routine der Applikation (rjmp APPSTART).

  • Applikation muss nicht angepasst werden und muss bei Adresse $0000 beginnen (Sprungbefehl zur Reset-Routine der Applikation).


Speicherzugriffe:
  • Keine Interrupts, Prozessor wird angehalten, solange Flash-Zugriffe laufen.
  • Flash Erase erfolgt  immer von oben nach unten.
    Reset-Vektor bleibt bis zuletzt erhalten.
  • Flash Write erfolgt immer von unten nach oben.
    Reset-Vektor wird mit dem Neuschreiben der 1. Page sofort erneuert.
  • Internes Verifying jeder geschriebenen Speicherseite.
  • Im Fehlerfall wird sicherheitshalber alles wieder gelöscht.
Speicheraufteilung:
  • Bootloader liegt im oberen Speicherbereich
    und belegt Bootloader-Sektion von nur 512 Bytes.

  • Aufruf: Hardware-Reset (Fuse "Boot Reset Vector")

  • Bootloader übergibt nach Nutzung oder Ablauf des Timeouts an die unveränderte Reset-Routine der Applikation durch einen Sprung zu Adresse $0000 (Original-Reset-Vektor).

  • Applikation muss in keiner Weise angepasst werden und steht ohne Änderungen im Flash.


Speicherzugriffe:

  • Keine Interrupt-Spielereien im Bootloader:
    Flash-Zugriffe werden strikt ausgesessen.
  • Flash Erase von oben nach unten.
  • Flash Write von unten nach oben.
Was ist sonst noch besonders 'safe' an TinySafeBoot ?
  • Aktivierung über Kalibrierungszeichen plus Passwort verhindert versehentliches Auslösen.
  • Ernsthafter Schutz mit langem Passwort möglich, da fast eine ganze Page für Benutzerdaten reserviert ist.
  • Passwort und Timeout können nachträglich geändert werden (ohne erneutes Assemblieren und ISP-Zugriff).
  • Effiziente Blockdatenübertragung
  • Internes Verifying jeder geschriebenen Speicherseite
  • Applikations-Sprungbefehl und Benutzerdaten liegen in separatem Bereich ("LASTPAGE").
    Zugriffe auf Benutzerdaten gefährden nicht die Integrität des Bootloaders.
    (ATmega: Kompletter Zugriffsschutz des Bootloaders durch Lockbits möglich.)
  • Kein 'Russisch Roulette' mit Fusebits. (Sicherheitsrelevante Einstellungen müssen über ISP verändert werden.)
  • Konsequent in Assembler programmiert: Kein Schnickschnack, keine Hintertürchen, Quellcode lückenlos nachvollziehbar.
  • Umfangreiche Firmware-Datenbank: Für alle unterstützten ATtinys/ATmegas steht die TSB-Firmware als vor-assemblierter Maschinencode zur Verfügung. Lässt sich mithilfe der TSB-Software an die gewünschten RS232-Portleitungen anpassen
    (KEINE Assembler-Umgebung erforderlich).

Nach oben | Index




Installation

Voraussetzungen für TSB-Software auf dem PC:


Fusebits im Mikrocontroller:

ATtinys:
ATmegas:

Voraussetzungen für die Applikation:


Nach oben |  Index




Protokoll

RS232-TTL, 8-N-1, Halbduplex, bis 115200 Baud ab ca. 12 MHz 

Two-Wire: Die Applikation nutzt ohnehin eine serielle Schnittstelle und die Plattform verfügt über eine hardwaremäßige RS232-Anbindung mit Inverter/Pegelwandler, wie etwa MAX232, FT232xx, LT280x, die 2-Transistor-Schaltung aus Appnote AVR910, oder sogar das hier. Da liegrt es nahe, dass der Bootloader einfach dieselbe Schnittstelle benutzt.
In diesem Fall wird für Bootloader-Sitzungen überhaupt keine zusätzliche Hardware und kein extra Adapter benötigt. Alles läuft über die bereits vorhandenen Komponenten, und der Anwender kann Firmware-Updates ohne Eingriffe in das betreffende Gerät durchführen.
Dabei ist anzumerken, dass TSB nicht zwangsläifig die Leitungen benutzen muss, auf die ein vorhandener UART festgelegt ist, denn TSB verwendet einen sogenannten "Software-UART", der mit jeder Kombination von exisitierenden Ports zusammenspielen kann. Dieses Feature macht den Einsatz von TSB auch auf solchen ATtinys möglich, die tatsächlich gar keinen UART haben.
Der Aufruf des Bootloaders erfolgt grundsätzlich nach jedem Hardware-Reset oder nach dem Einschalten (Power-On-Reset), doch nur wenn innerhalb eines bestimmten Zeitfensters bestimmte Aktivierungszeichen eintreffen, wird der Bootloader auch tatsächlich aktiv. Dann erwartet er eventuell noch ein Passwort, bevor er seine Kennung sendet, und anschließend können Bootloader-Kommandos gesendet werden, um Funktionen des Bootloaders zu nutzen.
Ein versehentliches Auslösen ist also insbesondere in Verbindung mit dem Passwort-Feature ziemlich unwahrscheinlich. Das leicht veränderte Timing im Rahmen eines Hardware-Resets schränkt die Funktionalität der meisten Applikationen in keiner Weise ein.


One-Wire: Wo es auf jede Portleitung ankommt und/oder die Zielplattform keine reguläre RS232-Anbindung vorsieht, können wir mit einem "One-Wire"-Interface (auch "CIV") eine weitere Portleitung einsparen und ggf. ein noch einfacheres Programmierinterface verwenden. Senden und Empfangen geht bei One-Wire natürlich nicht zur gleichen Zeit, sondern immer nur abwechselnd, was aber im Zusammenhang mit dem TSB-Protokoll keinen Unterschied macht, da hier ohnehin ein strikter Halbduplex vorgesehen ist.
Unterstützung durch TSB: Die TSB-Software kann problemlos eine TSB-Variante für One-Wire erzeugen - einfach dieselbe Portleitung für RXD und TXD definieren. Die Firmware steuert diese Leitung dann beim Senden wie einen Open-Collector-Treiber an, sodass es im Zusammenspiel mit einem ordnungsgemäß ausgeführten One-Wire-Interface niemals zu elektrischen "Kollisionen" kommen kann.
Für ausreichenden High-Pegel und hohe Übertragungsgeschwindigkeit ist in der Regel noch ein externer Pullup-Widerstand (1k ... 4k7) nötig, der die Flankensteilheit verbessert. Selbst einfache Interface-Schaltungen, wie etwa diese hier, funktionieren im Zusammenspiel mit TSB recht ordentlich.


One-Wire-Bus: Es ist möglich, mehrere (auch völlig unterschiedliche) AVRs mit TSB auszustatten, für One-Wire zu konfigurieren und diese Bausteine dann alle an eine gemeinsame Programmierleitung zu hängen. Zur "Adressierung" wird jeder TSB mit einem anderen Passwort konfiguriert, und sei es nur eine laufende Nummer oder ein Buchstabe. Dann wird nur derjenige TSB, der mit dem vollständigen richtigen Passwort angesprochen wurde, auf diese Anfrage reagieren. Die anderen Chips verhalten sich auf dem gemeinsamen Datenbus vollkommen passiv und reagieren erst dann wieder auf Kalibrierungszeichen und Passwort, nachdem zum Abschluss der Booloader-Sitzung ein neuer Reset-Zyklus ausgelöst wurde. Weitere Voraussetzungen:
Bei vielen parallel geschalteten AVR-TSBs müsste vielleicht die Belastung des One-Wire-Treibers durch die Eingänge (fan-in) bzw. durch den erforderlichen gemeinsamen Pullup-Widerstand (1k ... 4k7) mitberücksichtigt werden. Die Reset-Leitungen der einzelnen Bausteine müssen zusammengefasst werden oder alles wird durch einen Power-On-Reset resettet und die Bausteine kommen ungefähr zur gleichen Zeit auf die Beine. Ich selbst hatte solche Konfigurationen schon mit bis zu 5 AVRs in Betrieb, und es ist nichts problemlos


Ablauf einer TSB-Sitzung
  1. Herstellen der Verbindung (RS232-Adapter, seriellen Port herausfinden, Konsolenfenster in TSB-Verzeichnis öffnen)
  2. Aufruf des Bootloaders über Hardware-Reset am Controller (Timeout-Zeitfenster)
    Kann auch durch Einschalten der Stromversorgung (Power-On-Reset), oder durch Öffnen der Schnittstelle (bei Nutzung von DTR oder RTS zum Triggern der RESET-Leitung) ausgelöst werden.
  3. Host-Computer sendet Kalibrierungszeichen und Passwort ('Login').
  4. Aus Sicherheitsgründen antwortet der Bootloader erst nach der erfolgreichen Authentifizierung mit seinem Info-Datensatz.
  5. Host sendet Kommando (siehe nachstehende Tabellen).
  6. Wechselseitige Datenübertragung im Binärmodus.
  7. Aktion abgeschlossen; mögliche weitere Kommandos können verarbeitet werden ODER die Applikation wird gestartet.

Noch ein paar Anmerkungen zum Protokoll

Wie die meisten ATtiny-Bootloader, so versucht auch TSB garnicht erst, eines der historischen STK-Protokolle oder gar Z-Modem nachzubilden... Diese sind viel zu klobig für die Implementierung auf einem ATtiny (wenn man außer dem Bootloader noch 'was anderes damit machen will...).
Und dennoch fehlen so elementare und nützliche Dinge, wie eine automatische Erkennung der Baudrate oder ein Passwortschutz!

Bei TSB kommt ein hausgemachtes und gut abgehangenes Minimalprotokoll zum Einsatz. Für Datenübertragungen verwendet er den vollen 8-Bit-Zeichensatz und verzichtet auf jegliche Umcodierung und Prüfsummenzirkus. Das können wir uns erfahrungsgemäß komplett sparen, indem wir auf eine technisch einwandfreie Schnittstellenanbindung bei moderaten Übertragungsgeschwindigkeiten setzen. Schließlich sind hier nur ein paar Meter Kabel zu überbrücken. Witzigerweise ist diese "primitive" Übertragung dann oft sogar schneller, als so manches aufwendige Protokoll, das zwar bei vermeintlich höherer Baudrate arbeitet, sich aber im Endeffekt durch riesige Latenzzeiten, ineffiziente Codierung und ständige Sende-Empfangsrichtungs-Wechsel enorm ausbremst.

Kommandos und Kontrollzeichen sind bei TSB druckbare ASCII-Zeichen. Damit lassen sich Grundfunktionen des Bootloaders besonders einfach und intuitiv über ein beliebiges Terminalprogramm testen.


Aktivierung, Kalibrierung und Kommandozeichen, allgemein:

Aktivierung + Login:

Reset am Controller

Host : "@@@" + "PASSWORT"

BL : Antwortet mit Info-Block

Kommandos verarbeiten:

Host  : sendet Kommando
        (siehe untenstehende Tabellen)

BL    : Bestätigung mit CF oder
        Anforderung weiterer Daten mit RQ

Fertig: BL bereit für weitere Kommandos.
        BL startet Applikation, wenn ungültiges
        Kommandozeichen gesendet.
Kommandos:

"f" = Flash lesen
"F" = Flash schreiben

"e" = EEPROM lesen
"E" = EEPROM schreiben

"c" = Benutzerdaten lesen
"C" = Benutzerdaten schreiben

Handshake/Flusskontrolle:

"?" = chr$(63) = RQ ("Request" = Anforderung/Abbruch)

"!" = chr$(33) = CF ("Confirm" = Bestätigung/Weitermachen)




TSB-Kommandos: Lesen und Schreiben von Flash, EEPROM, Benutzerdaten, sowie Not-Löschung (Emergency Erase):

Flash Read Flash Write

EEPROM Read
EEPROM Write
Immer bis Ende App-Flash Beendigung durch Host
Immer bis Ende EEPROM
Beendigung durch Host
Host
Bootloader

[Login]

"f" + CF

CF

CF

CF



[fertig]
[Reset]

[Info]

[Page1]

[Page2]



[PageN]
+CF


Host Bootloader

[Login]

"F"

CF+[Page1]

CF+[Page2]

...

RQ

[fertig]
[Reset]

[Info]

RQ

RQ





CF



Host
Bootloader

[Login]

"e" + CF

CF

CF

...

CF

[fertig]
[Reset]

[Info]

[Block1]

[Block2]




[BlockN]
+CF

Host Bootloader

[Login]

"E"

CF+[Block1]

CF+[Block2]

...

RQ

[fertig]
[Reset]

[Info]

RQ

RQ





CF


Abbruch durch TSB

(Ende App-Flash oder
Fehler beim Verifying)


Abbruch durch TSB

Host
Bootloader

[Login]

"F"

CF+[Page1]

...

CF+[PageN]





[Abbruch]
[Reset]

[Info]

RQ

RQ



CF
(<> RQ)




Host Bootloader

[Login]

"E"

CF+[Block1]

...

CF+[BlockN]



[fertig]
[Reset]

[Info]

RQ

RQ




CF






User Data Read/Write

Emergency Erase
Benutzerdatensatz (LASTPAGE)
lesen

Not-Löschung auslösen
(1. Flash, 2. EEPROM, 3. Benutzerdaten)
Host
Bootloader        

[Login]

"c"


[fertig]
[Reset]

[Info]

[LASTPAGE-Daten]
+CF


Host
Bootloader

"@@@"

CHR$(0)

CF





[fertig!]

[Reset]

[erwarte Passwort]

RQ [Rückfrage]

[löscht EEPROM]
[löscht Flash]
[löscht LASTPAGE]

CF

Benutzerdatensatz (LASTPAGE)
schreiben


... oder doch lieber nicht !

Host
Bootloader        

[Login]

"C"

CF+
geänderte
Daten für
LASTPAGE


[fertig]
[Reset]

[Info]

RQ




Neuer Info-Block
+CF



Host
Bootloader

"@@@"

CHR$(0)

RQ
(<> CF)


[nix geändert!]
[Reset]

[erwarte Passwort]

RQ [Rückfrage]




[keine Reaktion]



Nach oben |  Index




Firmware

Die Firmware für TinySafeBoot ist in Assembler geschrieben, denn hier geht es um effizienten Code und größtmögliche Transparenz.
Dank "bedingter Assemblierung" enthält der Quelltext alle erforderlichen Anpassungen für sämtliche ATtinys und ATmegas, die die Mindestvoraussetzungen erfüllen, wobei für jedes Modell automatisch eine optimierte Speicheraufteilung erreicht wird. Auf Grundlage dieses Quelltextes erzeuge ich alle TSB-Versionen, die standardmäßig in die aktuelle TSB-Distribution eingepflegt werden. Außer den Chipdefinitionen kommen auch keine weiteren Includes oder gar Libraries dazu. Alles bleibt vollkommen transparent. 
Natürlich steht es jedem offen, den Assemblerquelltext selbst zu modifizieren und eigene Spezialversionen von TSB zu assemblieren.
Der TSB-Bootloader für ATtinys nimmt derzeit maximal 560 Bytes in Anspruch, die ATmega-Version liegt knapp unter 512 Bytes und passt somit noch in die zweitkleinstmögliche Bootloader-Sektion.


TSB für ATtinys:
Neuere Versionen von TSB für ATtinys kommen als "TSB-Installer" heraus. Dabei handelt es sich um eine reguläre "Äpp", die wie jedes andere Programm bei Adresse $0000 beginnt und mit Standardeinstellungen auf den Chip gebracht werden kann - und das nicht nur über ISP, sondern auch über einen bereits vorhandenen Bootloader!
Nach einem weiteren Reset deaktiviert und löscht der TSB-Installer den bisherigen Bootloader, schreibt die mitgebrachte TSB-Firmware in den Ziel-Adressbereich und übergibt die Kontrolle an diesen neuen Bootloader.
Somit ist ein Update von TSB über TSB möglich; wer bisher eine andere Art von Bootloader drauf hatte, kann den nun endlich durch 'was Vernünftiges ersetzen.
Der Installer besteht aus zwei Teilen, der eigentlichen TSB-Firmware und einer Kopierroutine. Letztere wird nur für den Transfer in den Ziel-Adressbereich gebraucht und nach Abschluss der Aktion automatisch gelöscht. Das bedeutet, die eigentliche TSB-Firmware wird durch das Installer-Feature um kein Byte länger! Details zum Installer-Mechanismus weiter unten.


TSB für ATmegas: TSB für ATmegas kann alles, was TSB für ATtinys auch kann. Nach außen hin funktioniert der Zugriff wie bisher, das Protokoll ist zu 100% kompatibel. Unter der Haube gab es für die ATmegas noch die eine oder andere Tuning-Maßnahme. Die neuere TSB-Software kann natürlich für ATtinys und ATmegas gleichermaßen verwendet werden.
Die ATmega-Version passt in eine Bootloader-Sektion von nur 256 Words (512 Bytes). Also endlich mal ein vergleichsweie schlanker Bootloader für ATmegas... und noch mehr Platz für die monströsen Ausgeburten von BASCOM, AVR-GCC und Co... ;-)
Damit der TSB für ATmegas in 512 Bytes reinpasst, musste der Code für ATtinys ein wenig abgespeckt werden. Die Sicherheitsfeatures von TSB, Passwortschutz und Emergency Erase, standen natürlich nicht zur Disposition. Letztlich erzielte ich die erforderliche Einsparung durch ein paar ATmega-spezifische Optimierungen des Maschinencodes und vor allem durch Verzicht auf das interne Verifying. Dieses ist bei ATtinys ein wichtiger Teil des Schutzkonzeptes, weil es gleich nach dem Schreiben einer Seite mögliche Fehler erkennt und im Fehlerfall das Löschen des gesamten Codes veranlasst. Auf diese Weise wird verhindert, dass schadhafter Code im Speicher stehen bleibt und beim nächsten Reset möglicherweise den Bootloader beschädigt oder aussperrt.
Auf einem ATmega muss der Bootloader nicht sofort reagieren. Wenn etwas schiefgeht, ist der Bootloader bei schreibgeschützter Bootloader-Sektion auch nicht in Gefahr. Ein internes Verifying ist somit verzichtbar. Im Zweifelsfall kann man jederzeit ein externes Verifying (also Zurücklesen und Vergleichen der Speicherinhalte) hinterher schieben.
Leider kann ich für ATmegas auch ein ausgeklügeltes Installer-Feature anbieten, denn es würde ja auf einem ATmega ab dem Moment nicht mehr funktionieren, wo wie Lockbits für den Speicherschutz gesetzt sind. Um einen ATmega-TSB zu erneuern ist daher immer eine ISP-Sitzung erforderlich.

Aufruf des Bootloaders

Nach einem Hardware-Reset (per Knopf durch Low-Pegel auf der Leitung RESET sowie Power-Up-, Watchdog-, Brown-Out-Reset) startet ein ATtiny die Programmausführung immer bei Adresse $0000.
Hier steht normalerweise ein Sprungbefehl (RJMP oder JMP), der auf die eigentliche Reset-Routine innerhalb der Applikation weiterleitet; die nachfolgenden Speicherstellen können mit weiteren Interrupt-Vektoren oder Platzhaltern bestückt sein, je nachdem, was die Hardware und das Programm noch so alles können.
Es ist natürlich möglich, den Sprungbefehl an Adresse $0000 zu verbiegen, sodass er auf den Bootloader zeigt. Dann wird durch einen Hardware-Reset immer erst der Bootloader gestartet, und dieser muss an die Applikation weiterleiten. Das ist auch eigentlich kein Problem, denn wenn die Applikation über den Bootloader in den Flash geschrieben wurde, kann sich der Bootloader ja merken, welches Sprungziel der Reset-Vektor dieser Applikation ursprünglich hatte. Nach getaner Arbeit springt ein ATtiny-Bootloader dann an diese Adresse und die Applikation startet mit ihrer Reset-Routine.

Auf einem ATmega läuft es noch etwas eleganter: Wenn auf einem ATmega ein bestimmtes Fusebit gesetzt ist, dann springt der Chip beim Hardware-Reset gar nicht erst nach $0000, sondern gleich zu einer bestimmten Adresse im oberen Flash-Segment, wo sich dann der Bootloader befinden sollte. Die "Bootloader-Sektion" wird per Fusebits definiert und kann über Lockbits auch gleich noch vor versehentlichem Überschreiben geschützt werden. Wenn ein ATmega-Bootloader nach getaner Arbeit an die Applikation übergeben will, muss er einfach nur pauschal den Adresszähler zurücksetzen und an die Adresse $0000 springen. Dort beginnt ja die Applikation regulär mit ihrem regulären Reset-Vektor.

Wenn TSB also bei jedem Einschaltvorgang oder Reset aufgerufen wird, muss er natürlich erst prüfen, ob er tatsächlich gemeint war:

Kalibrierung

Innerhalb des Timeout-Zeitfensters muss der Host-Computer eine Sequenz aus bestimmten seriellen Zeichen senden. Diese enthalten eine bekannte Anzahl von Bitzellen mit 0-Pegel, welche aufaddiert werden und durch Mittelwertbildung einen recht genauen Timing-Faktor liefern. Dieser berücksichtigt sowohl die tatsächliche momentane Taktfrequenz des AVR, als auch die tatsächliche Baudrate der seriellen Host-Schnittstelle inklusive möglicher Abweichungen. Auf dieser Grundlage kann der Bootloader eigene serielle Zeichen in der passenden Baudrate generieren.
Vorteile: Da es sich um eine reine Software-Lösung handelt, wird kein UART benötigt (den viele ATtinys ohnehin nicht haben). Daher ist die Software-Lösung sogar flexibler, da man nicht mehr an die Leitungen gebunden ist, die der Hardware-UART verwenden müsste. Man ist auch nicht auf spezielle "Baudraten-Quarze" angewiesen, da das Verfahren auch mit krummen Teilerverhältnissen funktioniert, solange sich die Rundungsfehler in Grenzen halten. Auch die weniger genauen Keramikresonatoren oder die internen RC-Oszillatoren lassen sich als Taktquelle verwenden. Serielle Kommunikation kann über jede zur Verfügung stehende Portleitung oder sogar "One-wire" abgewickelt werden.
Nachteile: Ist die Baudrate im Verhältnis zur Taktrate des Controllers relativ hoch, dann kommt es zu größeren Timing-Ungenauigkeiten, die dann außerhalb der Toleranzgrenze des Host-UART liegen können, sodass eine stabile Übertragung nicht mehr möglich ist. Das Verfahren funktioniert also nicht unbedingt bis zur höchsten Baudrate, die mit einem Hardware-UART unter der gegebenen Taktfrequenz erzielbar wäre, sondern um einiges niedriger.


Passwortschutz

Nach den Kalibrierungszeichen erwartet der Bootloader ein Passwort, falls eines konfiguriert war. Der Zeichenempfang geschieht ohne irgendeine Rückmeldung. Nur wenn Kalibrierungszeichen und das korrekte Passwort vollständig empfangen wurden, antwortet TSB mit seinem Info-Datensatz. Im Übrigen kann das konsequente Passivschalten wie eine Geräteadresse genutzt werden; damit ist zum Beispiel der Betrieb mehrerer TSB-AVRs an einem gemeinsamen One-Wire-Bus möglich.
Für Passwörter stehen mindestens alle druckbaren ASCII-Zeichen zur Verfügung. Ein TSB-Passwort darf maximal so lang sein, wie die Pagesize in dem jeweiligen ATtiny abzüglich 4 Bytes für den Applikations-Rücksprung, den Timeout-Faktor und ein Terminierungszeichen (siehe weiter unten). Schon auf einem ATtiny25 mit 32 Bytes pro Page ist Platz für ein Passwort von bis zu 28 Zeichen. Das Passwort lässt sich jederzeit ohne Neuinstallation des Bootloaders und ohne erneutes Hochladen der Applikation ändern oder löschen.
(Verbesserung der Password-Prüfroutine im Jahr 2014: Generell darf bei einer Passwortprüfung keine von außen erkennbare Reaktion erfolgen, sobald das erste falsche Zeichen eintrifft. Zu Beginn führte die Passwortprüfung diskret in eine einfache Endlosschleife, die erst per erneutem Hardware-Reset verlassen werden kann. Dann erhielt ich konkrete Hinweise auf einen Angriff auf die damalige Passwortabfrage von TSB mittels "Power-Analysis", der auf Schwankungen des Betriebsstroms beruhte. Nachdem ich das Phänomen messtechnisch nachvollziehen konnte, änderte ich die Passwort-Prüfroutine dahingehend, dass nun praktisch keine auswertbaren Fluktuationen im Power-Profil und auch in den EM-Abstrahlungen auftreten. Der aktualisierte Artikel findet sich in der Linkliste. )


Info-Datensatz

Nach Empfang von Kalibrierungszeichen und korrektem Passwort antwortet der Bootloader automatisch mit seinem Info-Datensatz, der folgendermaßen strukturiert ist:
3 Zeichen-ASCII-Identifikation "tsb" (ATtiny) oder "TSB" (ATmega)
2 Byte Firmware-Versionsnummer (Datumscode)
1 Byte Firmware-Status (noch nicht genauer definiert)
3 Signatur-Bytes, welche nach Atmel-Systematik den Chiptyp kennzeichnen (falls man's doch mal braucht...)
1 Byte Pagesize in Words (bei ATtinys nur 32, 64 oder 128 Byte)
2 Bytes verfügbarer Flash (d. h. freier Speicherplatz für Applikation abzüglich Bootloader)
2 Bytes EEPROM-Größe (in Bytes)
Der Info-Datensatz enthält also bereits alle wichtigen Informationen, die für nachfolgende Aktivitäten benötigt werden. Die PC-Software muss keine Datenbanken durchforsten oder zeitaufwendige Probezugriffe durchführen.
Der Info-Datensatz sind also "Permanentdaten", die sich nach dem Assemblieren des Bootloaders für einen bestimmten ATtiny ohnehin nicht mehr verändern. Daher liegen sie noch innerhalb des Programmcodes, und zwar am Ende der vorletzten von TSB belegten Speicherseite.



Benutzer-Datensatz

Auf Anforderung sendet TSB den Inhalt einer separaten Speicherseite mit benutzerdefinierten Daten:
2 Bytes Applikations-Sprungbefehl
1 Byte Timeout-Faktor
n Bytes Passwort (bis maximal Seitenende-1)
Die ersten zwei Bytes beinhalten den kompletten relativen Sprungbefehl (rjmp) oder die absolute Adresse für den Rücksprung zur Reset-Routine der Applikation (auf ATmegas nicht benötigt). Danach folgt das TIMEOUT-Byte und das Passwort. Diese Daten werden immer in einer separaten Speicherseite untergebracht, bei ATtinys ist dies die physisch letzte adressierbare Page (daher "LASTPAGE"). Sollte es beim schreibenden Flash-Zugriff auf LASTPAGE zu Fehlern kommen, so kann kein wichtiger Programmcode beschädigt werden. (Auf ATmegas befindet sich LASTPAGE in der letzten Speicherseite der Applikations-Sektion.)


Zugriffe auf Flash und EEPROM

Bei allen kritischen Zugriffen hält sich TSB strikt an das, was als 'Best Practice' gilt. Selbstverständlich habe ich vorher jede Menge anderer Ansätze ausprobiert. Jetzt kann ich aus eigener Erfahrung bestätigen: Jawohl, diese Prinzipien sind wirklich das Beste, was man für einen stabilen und sicheren AVR-Bootloader tun kann.



Änderungen an Passwort und Timeout

Passwort, Timeout und Applikations-Sprungbefehl sind in einer separaten Speicherseite (LASTPAGE) untergebracht und lassen sich daher ohne besondere Gefahr für den Bootloader oder die Applikation auch nachträglich über SPM-Zugriffe verändern. Durch einen Verify-Fehler bei Flash-Zugriffen oder durch eine manuell ausgelöste "Not-Löschung" wird LASTPAGE einfach nur gelöscht und nicht wieder neu beschrieben. Dann stehen hier überall $FF-Bytes, was sichere Default-Werte sind, nämlich "kein Sprungbefehl", "kein Passswort" und "langer Timeout". Danach ist der Bootloader in jedem Fall wieder problemlos ansprechbar.

Ein nachträgliches Ändern des Passwortes hat die bekannten Sicherheitsvorteile. Für Debugging-Zwecke kann die Passwortgeschichte natürlich auch komplett abgeschaltet werden. (Dies ist bspw. zur Steuerung über Stapelverarbeitungsdateien erforderlich).

Ein nachträgliches Ändern des Timeouts ist hilfreich, wenn das Reset-Verhalten im Zusammenspiel mit der Applikation erst noch optimiert werden muss. Wenn der AVR in der Zielschaltung automatisch durch Öffnen der RS232-Schnittstelle resettet wird (wie etwa beim XR232USB), dann reicht ein recht kurzer Timeout in der Größenordnung von unter einer zehntel Sekunde schon aus, um den Bootloader sicher anzusprechen. Für andere Anwendungen, bei denen manuell resettet wird oder der Reset-Vorgang schlechter kalkulierbar ist, setzen wir einfach einen deutlich längeren Timeout. Dann lässt sich TSB nämlich auch ganz prima über das Einschalten der Stromversorgung (Power-On-Reset) auslösen.

Da der MCU-Takt beim Assemblieren des Bootloaders nicht berücksichtigt werden kann, ist die Timeout-Skala natürlich nicht "geeicht". Einen GROBEN Überblick zu den zu erwartenden Verzögerungen soll nachstehende Tabelle liefern:


t
TO  = gewünschter Timeout (Sekunden)
fMCU = Controller-Taktfrequenz (MHz)
TO  =  TIMEOUT-Byte (8...255)


        fMCU * 106 * tTO
 TO =  ------------------
             196600    


fMCU / TIMEOUT
4 MHz
8 MHz
16 MHz
 8 80 ms
40 ms
 20 ms
128
6 s
3 s
1,5 s
255
12 s
6 s
3 s



Not-Löschung

Die Funktion Not-Löschung ("Emergency Erase") ist eine Option, wenn man das Passwort tatsächlich nicht mehr weiß und den Chip lieber neu programmieren will, ohne dass ein neuer Bootloader aufgespielt werden muss.
Der Bootloader führt Emergency Erase erst dann aus, wenn bei der Passwortabfrage ein bestimmtes Steuerzeichen mehrfach hintereinander gesendet wurde. Da es sich hierbei um ein nicht-druckbares Zeichen handelt, ist die Gefahr gering, den Emergency Erase versehentlich bei der normalen Passworteingabe auszulösen.
Beim Emergency Erase löscht der Bootloader zuerst den Flash, anschließend den EEPROM und zuletzt die Benutzerdaten. Alle Spuren einer vorherigen Firmware sind damit beseitigt und TSB steht wieder mit Default-Einstellungen zur Verfügung.
Einem "Angreifer" nützt der Emergency Erase ungefähr genauso wenig, wie das Auslösen eines Erase-Zyklus' per ISP.


TSB-Installer für ATtinys

Wer kennt das nicht - gerade hat man eine hübsche ATtiny-Anwendung in Bernstein versiegelt und das Firmware-Update ist wie gewünscht nur noch über TSB möglich - da stellt man fest, dass es seit kurzer Zeit nun gerade für unsere Anwendung eine noch besser geeignete TSB-Version gibt. Statt zu Hammer und Meißel zu greifen, wäre es jetzt echt praktisch, wenn ein TSB-Update über TSB selbst möglich wäre...

Diese Option liefere ich hiermit nach. Der "TSB-Installer" ist als normale AVR-Applikation angelegt, das heißt, sie beginnt regulär bei Adresse $0000 und kann daher über einen beliebigen existierenden Bootloader in den Chip geladen werden.

Nach dem Start löscht der TSB-Installer einen bisherigen Bootloader und schreibt den mitgebrachten TSB-Code in den oberen Speicherbereich. Danach entfernt er sich selbst wieder aus dem Speicher. Das Endergebnis sieht genauso aus, als wäre TSB nach vollständiger Löschung des Flashspeichers über ISP direkt in den Ziel-Adressbereich geschrieben worden.

Klingt alles ganz easy, ist es auch. Solange nichts dazwischenkommt. Laut Murphy müssen wir aber genau damit rechnen: Abstürze, Störimpulse, Stromausfälle, Fehler in der seriellen Übertragung - alles nicht sehr schön, wenn dadurch ein bisher funktionsfähiger Bootloader zerstört wird. Die Aktion MUSS also beim ersten Versuch klappen, besonders dann, wenn "Plan B" (physischer ISP-Zugriff) sich etwas schwieriger gestaltet... Zur Absicherung arbeitet der TSB-Installer nach dem Gesetz der Fünf:

  1. Integritätsprüfung. Das geladene Programm muss sicherstellen, dass es fehlerfrei und vollständig im Speicher steht. (Könnte ja sein, dass die Übertragung am Anfang noch problemlos lief aber aus irgendwelchen Gründen mittendrin abgebrochen wurde, ohne dass der bisherige Bootloader das bemerkt hätte. Da wäre es fatal, den alten intakten Bootloader mit fehlerhaftem Code zu überschreiben. Eine sinnvolle Anwendung für ein wenig Prüfsummenzirkus. Stimmt die berechnete Prüfsumme über den gesamten Code mit dem Wert überein, der gleich am Anfang des Installers steht, dann wurde dieser auch höchstwahrscheinlich korrekt geladen.) Anderenfalls macht das Programm garnichts mehr und der alte Bootloader bleibt im Rennen.

  2. Entfernen des modifizierten Reset-Vektors. Nachdem nun klar ist, dass der Installer vollständig und korrekt im Speicher steht, wird es ernst. Durch Löschung der 1. Page entfernt der Installer den Reset-Vektor, der auf den alten Bootloader zeigt. Wenn danach irgendwas passiert, dann würde durch jeden folgenden Reset der Prozessor immer wieder das Installer-Programm starten. Dessen relevanter Code beginnt nämlich genau in der 2. Page.

  3. Löschung des bisherigen Bootloaders. Alles, was sich hinter dem TSB-Installer im Speicher befindet, wird rigoros gelöscht. Somit bleiben vom alten Bootloader (oder von vorherigen abgebrochenen Schreibversuchen des TSB-Installers) keine Code-Fragmente im Speicher stehen. Der nächste Schritt findet immer einen sauberen Flash vor.

  4. Kopieren der TSB-Firmware in den Ziel-Adressbereich. Jede geschriebene Speicherseite wird verifiziert. Bei einem Fehler geht das Programm in eine Endlosschleife. Über einen Reset wird die Sequenz unter Punkt 2, 3 und 4 immer wieder neu ausgelöst. Auf diese Weise können wir versuchen, durch gezielte Veränderung der Betriebsbedingungen (Spannung, Taktfrequenz, Temperatur) den Flash doch noch zur Zusammenarbeit zu überreden.
    Erst wenn das Kopieren und Verifizieren der gesamten TSB-Firmware erfolgreich war, geht es mit Punkt 5 weiter.

  5. Aufräumen. Hierzu springt das Programm in die Funktion "EraseAppFlash" des neuen TSB, welcher den Applikations-Flash und damit auch den Installer wieder löscht. Damit ist der neue TSB einsatzbereit.


Nach oben | Index


Software

TSB-Software für den Host-PC

Das Kommandozeilenprogramm ermöglicht den Zugriff auf alle Funktionen des TSB-Bootloaders und kann maßgeschneiderte Firmware bzw. Installationsdateien für alle unterstützten AVRs erzeugen. Ausführbare Dateien stehen für Windows und Linux (jeweils 32-Bit-Versionen) zur Verfügung.


Modus 1 - Kommunikation mit TSB

Modus 2 - Erzeugung von TSB-Firmware

Der Aufruf aus Batch-Dateien ist möglich. Die Einbindung in eine Editorumgebung für AVR-Assembler oder in die BASCOM-IDE ziemlich unproblematisch.

Die PC-Software wird unter Geany für FreeBasic entwickelt. Derselbe Programmcode lässt sich ohne besondere Anpassungen unter aktuellen Windows- und Linux-Systemen compilieren.
Natürlich liegen meinem Paket ausführbare Dateien bei (ab WinXP aufwärts sowie aktuelles Debian/Ubuntu).
Dieses Programm ist freie Software. Hinweise zur Verbesserung oder Fehlerbeseitigung nehme ich freudig entgegen!

Die im Paket enthaltenen "changelog"-Dateien geben Auskunft über die aktuellen und bisherigen Änderungen in den jeweiligen Versionen.


Nach oben | Index




Anmerkungen

Ein paar strategische Betrachtungen zur Sicherheit von AVRs mit Bootloadern

Wenn wir auf unserem AVR-ATtiny oder ATmega eine wirklich wichtige Applikation installiert haben und keine weiteren Schutzmaßnahmen treffen, dann könnte jeder, der physischen Zugriff auf das Gerät erlangt, einen Programmieradapter am Chip oder an der nach außen geführten ISP-Schnittstelle anschließen und mal schnell die Firmware des Controllers auslesen oder neu schreiben.

Also zunächst einmal eine ziemlich unsichere Sache. Es sei denn, wir schaffen es, den Programmcode und die Daten, die sich in dem Chip befinden, vor unbefugten Zugriffen zu schützen.
Zum Glück lässt sich das Auslesen von Speicherinhalten bei fast allen AVRs mithilfe der Lockbits relativ wirkungsvoll verhindern. In der höchsten Sicherheitsstufe (MODE 3) ist der Lese- und Schreibzugriff über ISP komplett gesperrt. Das Einzige, was man dann über ISP noch erreichen kann, ist ein Erase-Zyklus. Einmal ausgelöst, löscht der Mikrocontroller dann selbsttätig seinen Flash und EEPROM, und erst zum Schluss werden die Lockbits wieder auf Standardwerte zurückgesetzt. Danach hat man wieder unbeschränkten Zugriff - aber auf einen "fabrikneuen" Mikrocontroller, aus dem sich dann auch mit allergrößter Sicherheit gar keine Daten mehr extrahieren lassen, wovon wir einmal ausgehen wollen.

Zum Schutz von proprietärer Software sind diese Lockbits schon eine feine Sache. So kommt der doofe Chinese auch bestimmt nicht an die ach-so-wertvollen Betriebsgeheimnisse heran. (Betriebsgeheimnis = Es muss geheim bleiben, auf welch stümperhafte Weise die teure Software zusammengepfuscht oder von der Konkurrenz abgekupfert wurde.)

Für richtige Menschen muss Software natürlich quelloffen sein. Aber in manchen Fällen bedeutet die Offenlegung von Sourcecode natürlich auch wieder gewisse Risiken. Ein Angreifer, der die quelloffene Software für Spionage oder Sabotagezwecke verändern will, muss sich nicht einmal die Mühe machen, das Original-Programm vom Chip runterzukratzen und aufwendiges Reverse-Engineering zu betreiben. Stattdessen kann er sich aus den öffentlich verfügbaren Quellen bedienen und eine "Spezialversion" der jeweiligen Anwendung basteln.
Diese könnte zum Beispiel sicherheitsrelevante Passworteingaben über einen Seitenkanal an den Angreifer weiterleiten, oder irgendwelche sonstigen nachteiligen Effekte auslösen. Der Angreifer müsste nur ein einziges Mal physischen Zugriff auf das ISP-Interface des Gerätes bekommen. Dann führt er einen vollständigen Erase durch und ersetzt das Originalprogramm unbesehen durch seine Spezialversion. Wenn das Originalprogramm keinerlei Authentifizierungsmechanismen vorsah, wird die Fälschung möglicherweise nie entdeckt. Sicherheitsproblem!

Aber jetzt kommt der gute Bootloader ins Spiel: Durch Aktivieren der Lockbits auf einem AVR-Mikrocontroller können wir schonmal den gezielten ISP-Zugriff auf Speicherinhalte verhindern. Auf diesem Weg kommt dann (höchstwahrscheinlich) niemand mehr an unsere Daten ran.
Ein auf dem Controller installierter Bootloader kann weiterhin interne Lese- bzw. Schreibzugriffe durchführen und Daten mit der Außenwelt austauschen. Mit einem entscheidenden Vorteil gegenüber ISP: Der vernünftige Bootloader lässt sich mit einem Passwort absichern.  An diesem Passwort gibt es kein Vorbeikommen, sobald die Hardware per Fusebits weitgehend "dichtgemacht" wurde. (Vorausgesetzt natürlich, dass keine praktisch nutzbaren Hintertüren in Hard- oder Software existieren.)

Zwar könnte ein Angreifer weiterhin gefälschte Versionen von Applikation und Bootloader hochladen, die das Verhalten der Original-Installation nachahmen. Dabei steht er aber vor dem grundsätzlichen Problem, dass niemand die Kenntnis eines geheimen Passwortes "vortäuschen" kann, sofern es sich um ein nach außen abgeschottetes System handelt. Das Konzept für einen sicheren (Passwort-)Schutz von Applikation und Bootloader ist daher auf dem Mikrocontroller verblüffend einfach:
Bootloader und Applikation sitzen auf dem Mikrocontroller im selben Boot. Der Leseschutz durch Lockbits betrifft immer den gesamten Speicher. Somit reicht ein Mechanismus zur Authentifizierung beim Bootloader bereits aus, um Bootloader UND Applikation wirkungsvoll gegen unbefugten Zugriff zu schützen.

Das ist ein Zugriffsschutz, der den Inhaber der Hardware nicht bevormundet und entrechtet.


Nach oben | Index



Download


Nach oben | Index



Links



Nach oben | Hauptseite


Erstveröffentlichung: 09/2011 ~ Letzte Änderung: 10/2016