MCUBoot Bootloader auf einem STM32

Bootloader

Bootloader sorgen für eine gewisse Sicherheit vor fehlerhaften Applikationen und ermöglichen nachträgliche Firmware-Updates. Im Folgenden wird ein gewisses Grundwissen zu den Themen Bootloader und Mikrocontrollern vorausgesetzt. Wem zum Beispiel die Begriffe Linker-Skript, Vektortabelle, Flash-Speicher oder Binärdatei nichts sagen, dem kann ich das Buch STM32: Das umfassende Praxisbuch oder eines der vielen Online-Tutorials empfehlen.

MCUBoot erster Eindruck - aller Anfang ist schwer

Kennt ihr das? Ihr klappt ein Schweizer Taschenmesser auf und habt keine Ahnung, wofür manche Werkzeuge gedacht sind und wie man sie verwenden kann?

So ging es mir anfangs bei MCUBoot. Es gibt viele Konfigurationsmöglichkeiten, sodass man zunächst schnell den Überblick verlieren kann. Ich hatte arge Schwierigkeiten, mich in die MCUBoot-Dokumentation einzuarbeiten. Viele Erkenntnisse sind erst durch Trial & Error und Recherche nach Code-Beispielen gekommen. Dennoch lohnt sich der Aufwand, denn MCUBoot ist vielfältig einsetzbar und mit vielen Sicherheitsfeatures bestückt. Ist einmal alles richtig konfiguriert, läuft das System auch stabil und man kann sich zurücklehnen und der Bootloader-Magie zuschauen.

Speicherbereiche und Update-Mechanismen

Ist das MCUBoot-Projekt für einen bestimmten Mikrocontroller portiert, müssen in der Linker-Datei die jeweiligen Speicherbereiche für Applikation und Bootloader festgelegt werden.

Üblicherweise wird der Bootloader an die Startadresse des ROM gelegt. Darauf folgen die Applikation und der Bereich für die Update-Applikation. Die in der Linker-Datei festgelegten Speicherbereiche werden für die Flash-Operationen von MCUBoot benötigt, womit ein mikrocontrollerspezifisches Interface angelegt werden muss, damit MCUBoot mit dem Flash umgehen kann (z.B. Lesen, Schreiben, Löschen).

Ist ein Bootloader sowie eine gültige Applikation vorhanden und der Mikrocontroller wird gestartet, springt man grundsätzlich erstmal direkt in die Applikation. Möchte man ein Update durchführen, muss das mithilfe des Update-Pending-Flags boot_set_pending während der Applikationslaufzeit angekündigt werden. Dabei wird die Update-Applikation markiert und löst die Update-Prozedur beim Bootloader nach einem Neustart (z.B. mit Software-Reset) aus.

Bei der Funktion boot_set_pending gibt es außerdem mittels Parameter noch die Wahl zwischen einem dauerhaften oder einmaligen Betrieb der Update-Applikation. Der Einmal-Betrieb ist für einen Testlauf eines Updates gedacht, kann aber auch mittels boot_set_confirmed als dauerhaft markiert werden.

Update-Image Erzeugung und Validierung

Empfehlenswert ist die Verwendung des Python-Tools ImgTool von MCUBoot, das Aufgaben wie das Security Key-Management und die Image-Signierung für die Update-Binärdatei-Erzeugung übernimmt. Das Tool bietet zudem einige Konfigurationsmöglichkeiten, zum Beispiel für Versionierung, Image-Speicheradressierung, Verschlüsselung und Metadaten für den Image-Header. MCUBoot überprüft dann ein neues Update-Image je nach Konfiguration beispielsweise auf korrekte Checksumme, höhere Versionsnummer und valide Image-Größe. Nach der Validierung folgt die optionale Entschlüsselung des Images.

Image Swap

Ist ein neues Firmwareimage valide, gibt es zwei Verfahren zum Tausch (Swap) der Applikationen im Flash-Bereich. Dafür wird ein bestimmter freier Speicherbereich benötigt, um das Verschieben der Applikationsdaten zu ermöglichen.

Swap-Scratch-Algorithmus - Austausch mit Scratch-Bereich

Die untenstehende Grafik (Abb. 1) zeigt die vier Speicherbereiche, mit denen MCUBoot den Tausch realisiert. Anfangs befindet sich die alte Applikation im Primary Slot (Slot 0) und die neue Applikation wartet im Secondary Slot (Slot 1) auf den Start des Tauschvorgangs. Dabei wird je nach Speicherarchitektur ein Speicherblock (Segment) bestimmter Größe vom Ende des Secondary Slots (Slot 1) in den Scratch-Bereich zwischengeparkt. Ein Block gleicher Größe wird vom Ende des Primary Slots (Slot 0) in das frei gewordene letzte Segment des Slot 1 geschoben. Das im Scratch befindliche Slot-1-Segment kann nun an seinen neuen Bestimmungsort im Primary Slot verschoben werden. Als Nächstes folgt der Tausch der vorletzten Segmente wie eben beschrieben. Am Ende befindet sich die neue Applikation im Primary Slot und die alte Applikation im Secondary Slot.

Abb. 1: Swap-Scratch-Algorithmus
Abb. 1: Swap-Scratch-Algorithmus

Swap-Move-Algorithmus - Austausch ohne Scratch-Bereich

Mithilfe eines Padding-Bereichs am Ende des Slot 0 wird zunächst eine Verschiebung der alten Applikation, beginnend mit dem letzten Segment, ermöglicht. Das frei gewordene Segment im Slot 0 wird nun mit dem ersten Segment des Slot 1 gefüllt. Im ersten Segment des Slot 1 kann daraufhin das erste Segment der alten Applikation platziert werden. Ab jetzt werden die Segmente weiter getauscht, bis die neue Applikation vollständig im Primary Slot und die alte Version im Secondary Slot steht. In Abb. 2: Swap-Move-Algorithmus wird der Vorgang dargestellt.

Abb. 2: Swap-Move-Algorithmus
Abb. 2: Swap-Move-Algorithmus

Abwägung Scratch/Padding-Größe

Beachten sollte man bei beiden Verfahren, dass je kleiner der verfügbare Scratch-/Padding-Bereich festgelegt wird, desto mehr werden die zugehörigen Speicherbereiche mit Schreibzugriffen für den Applikationstausch „belastet“. Zu viele Schreibzyklen führen auf Dauer zu permanentem Speicherverlust. Zu viel Platz für Scratch/Padding schränkt wiederum die maximal mögliche Firmwaregröße ein. Hier muss man abwägen, wie oft ein Firmware-Update durchgeführt werden soll und wie groß die Applikation werden darf.

Fallbacks

MCUBoot sorgt mit entsprechender Konfiguration für eine hohe Sicherheit bei Firmwareupdates. Sollte doch mal etwas nicht so laufen wie es sollte, gibt es beim Bootloader folgende Fallback-Mechanismen:

  • Validierungsfehler: Wenn die Validierung des Updates fehlschlägt, werden die Applikationen nicht getauscht. Der Update-Speicherbereich wird gelöscht und die alte Applikation wird wieder ausgeführt.
  • Stromverlust: Der aktuelle Stand des Image-Swaps wird als Metadaten zwischengespeichert. Sobald die Stromversorgung wiederhergestellt ist, wird der Tausch fortgesetzt.
  • Instabile Applikation: Mithilfe der Option eines vorläufigen Updates und boot_set_confirmed an einer geeigneten Position in der neuen Applikation kann bis zu einem bestimmten Grad vor Laufzeitproblemen geschützt werden. Steckt die Applikation beispielsweise in der Initialisierungsphase in einer ungewollten Endlosschleife und boot_set_confirmed ist noch nicht erreicht worden, folgt bei einem Neustart der Rücktausch und die alte Applikation läuft wieder.

Fazit

MCUBoot bietet dem Nutzer unter anderem konfigurierbare Optionen rund um Updateprozesse auf STM32-Boards. Diese Optionen greifen typische Probleme in der Übertragung und Validierung auf und bieten vorgefertigte Lösungsblocke, die bedarfsgerecht angepasst werden können. Für Anwender ist der Einsatz allerdings mit einer Lernkurve verbunden. Unsere Erfahrungswerte beim Einsatz von MCUBoot können in anderen Projekten die teure und schmerzhafte Lernkurve vermeiden und einen Vorteil bieten, der sich letztlich auch wirtschaftlich durch deutlich kürzere Entwicklungszeiten bemerkbar macht.