eMMC Hardware Partitionierung

Wenn ein Embedded-System für eine lange Lebensdauer vorgesehen ist, ist es nötig, sich mit der Applikation und der darunter liegenden Hardware auseinanderzusetzen - damit beide zusammen eine hohe Langzeitstabilität erreichen.

Damit sind an dieser Stelle keine Software-Aktualisierungen gemeint, die vorhandene Fehler in der Software beheben sollen. Hier geht es darum, das notwendige Speichermedien ihrer Physik entsprechend so genutzt werden, dass eine hohe Zuverlässigkeit und Lebensdauer des Gesamtsystems erreicht werden.

Die Zuverlässigkeit betrifft beispielsweise die dauerhafte Fähigkeit des Systems, bis zu einem bestimmten Applikationszustand starten zu können.

Die Lebensdauer betrifft beispielsweise die Fähigkeit des Systems, das vorhandene Speichermedium nicht zu schnell zu verschleißen.

Beide Anforderungen müssen sich nicht widersprechen. Je nach Applikation tun sie aber genau das in der Realität - sehr oft auch unbemerkt.

eMMC…was?

Zunächst verfügt eine eMMC intern über einen einzigen Speicher-Pool. Im Gegensatz zu ihrer bekannteren Schwester, der SD-Karte, stellt eine eMMC diesen Gesamtspeicher in mehreren sog. Hardware-Partitionen nach außen hin bereit.

Die hier skizzierten Hardware-Partitionen sind in einem laufenden Linux-System als voneinander unabhängige Geräte nutzbar. Den beiden Boot-Hardware-Partitionen kommt eine besondere Bedeutung beim Starten des Systems zu. Auf ihren Inhalt kann von der CPU aus mit einem vereinfachten Protokoll zugegriffen werden. Das beschleunigt das Laden und Starten eines Bootladers. Sie sind bei manchen eMMC-Geräten in der Kapazität konfigurierbar. Die RPMB-Hardware-Partition (RPMB: Replay Protected Memory Block) wiederum dient gänzlich anderen Zwecken und wird wie die Boot-Hardware-Partitionen in diesem Artikel nicht weiter betrachtet. Nur die User Data Area-Hardware-Partition (UDA) wird in den meisten Applikationen zur Laufzeit des System intensiv genutzt. Und genau aus dieser intensiven Nutzung leiten sich Einschränkungen für die eingangs erwähnten Anforderungen an das System ab.

Hinweis: Der Begriff Hardware-Partition hat zunächst nichts mit den ansonsten bekannten Partitionen in einer Partitionstabelle (MBR oder GPT) zu tun, die beispielsweise mit dem Kommando fdisk angelegt und verwaltet werden. Letztere können zusätzlich Anwendung finden.

Ein typisches Szenario

In einer Applikation wird eine eMMC eingesetzt, und die beiden Entwicklungsziele hohe Zuverlässigkeit beim Starten des Systems und eine hohe Lebensdauer beim Speichern von Daten sollen beide gleichermaßen gewährleistet sein.

Im laufenden System sind die von der eMMC bereitgestellten Hardware-Partitionen wie folgt "sichtbar":

/dev/mmcblk0boot0 Boot #0 Hardware Partition
/dev/mmcblk0boot1 Boot #1 Hardware Partition
/dev/mmcblk0 User Data Area Hardware Partition

Wer schon einmal mit eMMC in seinem System gearbeitet hat, wird diese Device-Nodes sicher kennen.

Ein erster Ansatz

Um die Zuverlässigkeit zu gewährleisten, startet das System den Bootlader aus einer der genau für diesen speziellen Zweck vorgesehenen Boot-Hardware-Partitionen. Danach wird ein Linux-basiertes System von der regulären UDA-Hardware-Partition geladen und gestartet und dieses wiederum nutzt einen Teil der UDA-Hardware-Partition als ihr Root-Dateisystem.

Um sicherzustellen, dass das System auch immer starten kann, wird nun die UDA-Hardware-Partition noch weiter unterteilt und das eigentliche Root-Dateisystem ausschließlich lesend verwendet. Ein zweiter Bereich ist während der Laufzeit beschreibbar, so dass beispielsweise Konfigurationen, Log-Dateien und sonstige Daten ständig und dauerhaft gespeichert werden können. Diese Aufteilung erfolgt beispielsweise mit dem Kommando fdisk:

Im laufenden System ist nun die von der eMMC bereitgestellte UDA-Hardware-Partition wie folgt "sichtbar":

/dev/mmcblk0 User Data Area Hardware Partition
/dev/mmcblk0p1 Partition für das RootFS, nur lesend
/dev/mmcblk0p2 Partition zum Schreiben von Daten

Diese Ansatz klingt durchaus plausibel und kann aber während der Lebensdauer des Systems trotzdem dazu führen, dass das Gerät unbrauchbar wird, da es nicht mehr aus dem RootFS starten kann. Die Ursache liegt darin, dass das darunter liegende Speichermedium von dieser Aufteilung in einen Lese-Bereich und einen Schreib-Bereich nichts weiß. Es behandelt die gesamte UDA-Hardware-Partition als einen Bereich. Da wir hier über eine eMMC sprechen und in dieser Flash-Speicher zum Einsatz kommt, kommen Techniken zum Nivellieren des Verschleiß' dieser Art Speichertechnologie zum Einsatz ("wear leveling").

Unter Verschleiß werden viele physikalische Effekte zusammengefasst, die durch wiederholtes Beschreiben der Flash-Blöcke entstehen. Obwohl die genauen Ursachen und Auswirkungen recht komplex sind, reicht uns hier eine starke Vereinfachung: Nach jedem weiteren Schreib-Zyklus verlieren die einzelnen Speicherzellen ihre elektrische Ladung schneller und können irgendwann gar nicht mehr beschrieben werden. Je nach eingesetzter NAND-Technologie werden hunderttausende (SLC) oder nur wenige tausend (TLC/QLC) Zyklen erreicht. Neben dem "wear leveling" werden weitere Techniken eingesetzt, um mit diesen Effekten umzugehen. Dazu gehören: Fehlerkorrektur-Codes (ECC), regelmäßige Korrekturen im Hintergrund ("scrubbing") und ein Vorrat an Reserve-Blöcken.

Für diese Nivellierung wird üblicherweise der gesamte Speicherbereich genutzt, da so insgesamt die höchste Zahl an Schreibzyklen erreicht wird. Der eigentlich als Lese-Bereich gedachte Teil für das Root-Dateisystems wird so mit der Zeit auf bereits stärker genutzte Blöcke verschoben, im folgenden Bild angedeutet über die umlaufenden Pfeile.

Somit können sich Effekte, die durch das Schreiben von Daten auf die schreibbare Partition ausgelöst werden, auch auf die nur-lese-Partition des Root-Dateisystems auswirken. Beispielsweise kann ein System, das vergleichsweise viel geschrieben hat, wenn es für einige Monate ausgeschaltet bleibt, Fehler durch den beschleunigten Ladungsverlust nicht mehr rechtzeitig erkennen und korrigieren. Somit sind weder die gewünschte Lebensdauer noch die Zuverlässigkeit für das Root-Dateisystem gesichert.

Besserer Ansatz mittels eMMC-Partitionierung

eMMCs bieten neben den separaten Boot-Partitionen weitere Hardware-Partitionen an. Diese sind bei Auslieferung der eMMC immer deaktiviert und müssen in einem manuellen Schritt zunächst konfiguriert werden. Zu beachten ist an dieser Stelle, dass sich diese Konfiguration der eMMC nicht mehr rückgängig machen lässt. Es sei also angeraten, diese Art der Konfiguration vorher sorgfältig zu planen. Auch kann sich dabei die Gesamtkapazität der eMMC reduzieren. Dazu später mehr.

Ziel dieser eMMC-Konfigurationsüberlegungen ist es also, der eMMC "mitzuteilen", wie man sie gedenkt zu nutzen.

Um den verfügbaren Speicherbereich aufzuteilen, bietet eine eMMC mehrere Varianten an:

  • Enhanced User Data Area (EUDA)
  • General Purpose Partitions (GPPs)
    • default
    • enhanced
    • extended ("system code" oder "non-persistent")

Dabei ist zu beachten, dass der Standard nicht definiert, was die Attribute genau bedeuten. Für enhanced wird als Beispiel eine bessere Zuverlässigkeit genannt. Darüber hinaus heißt es "The definition of enhanced storage media should be decided upon by each system manufacturer, and is outside the scope of this standard." In der Praxis bedeutet enhanced oft, dass ein SLC-Modus verwendet wird. Letztendlich kommt es jedoch auf den jeweiligen Hersteller der eMMC an, so dass es sich lohnt, die entsprechenden Dokumente zu studieren.

Enhanced User Data Area

Die EUDA führt zu einer internen Änderung des eMMC-Verhaltens im Bereich der UDA. Nach außen hin verhält sich die eMMC weiterhin gleich (bis auf die ggf. reduzierte Kapazität).

Nun sind die beiden Bereiche nicht nur aus applikativer Sicht getrennt, sondern auch die eMMC weiß um diese Trennung und behandelt sie entsprechend unterschiedlich. Zu beachten ist bei dieser Konfiguration, dass nun mittels einer regulären Partitionierung auch aus applikativer Sicht die Partition mit dem schreibbaren Dateisystem hinter der EUDA beginnt. Hier gilt es also bei Anwendung von beispielsweise fdisk die Partitionsgrößen sorgfältig auf die Hardware-Größen einzustellen.

Wie zuvor angedeutet, ändert sich bei dieser Konfiguration nichts an den nach außen sichtbaren Partitionen:

/dev/mmcblk0 User Data Area Hardware Partition
/dev/mmcblk0p1 Partition für das RootFS, nur lesend (auf der EUDA)
/dev/mmcblk0p2 Partition zum Schreiben von Daten

Ob das wear leveling wie im Bild angedeutet tatsächlich UDA und EUDA getrennt verwaltet, lässt sich nur mit der passenden Dokumentation für das eMMC-Modell beantworten.

General Purpose Partitions

Das Konfigurieren einer General Purpose Partition führt im Gegensatz zu einer Enhanced User Data Area zu einer Abtrennung eines Speicherbereichs und deshalb nach außen hin zu einem weiteren Gerät. Beim Anlegen der GPP kann wiederum zwischen den default oder enhanced Speichermodi gewählt werden. Dabei muss die Bedeutung von enhanced für UDA und GPPs nicht identisch sein.

/dev/mmcblk0gpp0 GPP #0 Hardware Partition
/dev/mmcblk0 User Data Area Hardware Partition

An dieser Stelle braucht es Unterstützung auf der Software-Seite, um die separate GPP nutzen zu können. Die Bootlader Barebox und U-Boot sowie der Linux-Kernel verfügen über diese Unterstützung.

Aus Linux-Sicht ist die GPP als /dev/mmcblk0gpp0 nun ein eigenständiges Gerät und auch innerhalb der eMMC unabhängig von der UDA (weiterhin verfügbar als /dev/mmcblk0). In der Nutzung gibt es aber keinen Unterschied. Auch die GPP kann nun partitioniert und formatiert werden. Am Ende entsteht zur Laufzeit dieser Zusammenhang:

/dev/mmcblk0gpp0 GPP #0 Hardware Partition
/dev/mmcblk0gpp0p1 Partition für das Lese-Root-Dateisystem
/dev/mmcblk0 User Data Area Hardware Partition
/dev/mmcblk0p1 Partition für das Schreib-Dateisystem

Neben dem Konfigurieren des Speichers unterstützen eMMCs noch weitere Optionen, um die zukünftige Nutzung jedes Speicherbereichs zu definieren. Damit kann die eMMC die intern verfügbaren Strategien zur Daten- und Speicherbehandlung genauer an die erwartete Nutzung anpassen.

Dazu in einem späteren Artikel mehr.


Weiterführende Links

Statische Dateisysteme

Wann immer es erforderlich ist, ein embedded Gerät einfach so ohne Vorbereitung ausschalten zu können, kommt das Thema Dateisystem-Konsistenz auf. Werden Daten geschrieben und haben vor dem Ausschalten ihren Weg auf das Speichermedium noch nicht vollständig gefunden, droht deren Verlust.


PTXdist: Schon gewusst? Heute: Mal eben neu booten

Wer während der Entwicklung an einem embedded System selbiges immer wieder mal komplett neu starten muss, wird es zu schätzen wissen, wenn so wenig wie möglich getan werden muss, um bei veränderten Daten das System im konsistenten Zustand zu halten.


umpf - Git on a New Level

Moderne Softwareentwicklung ohne begleitende Versionsverwaltung wie Git ist heutzutage unvorstellbar - Änderungen am Quellcode sollen schließlich nachvollziehbar dokumentiert und beliebige Verssionsstände jederzeit einfach reproduziert werden können. Für Arbeiten an komplexeren Projekten wie etwa dem BSP ("Board Support Package") eines eingebetteten Systems mit mehreren Entwicklungssträngen skaliert ein bloßes Aufeinanderstapeln der einzelnen Änderungen jedoch nicht.


Pulse Width Modulation (PWM) is easy, isn't it? - Turning it off and on again

Part of Uwe Kleine-König's work at Pengutronix is to review PWM (Pulse Width Modulation) drivers. In addition, he also sometimes refactors existing drivers and the Linux kernel PWM subsystem in general.


Pengutronix at Embedded World 2022

Welcome to our booth at the Embedded World 2022 in Nürnberg!


Umfassendes RAUC Dokumentations-Update

Wie in vielen Projekten, ist auch bei RAUC an vielen Stellen nach massiver Entwicklung meist nicht mehr ausreichend Zeit geblieben, die Änderungen, neuen Features und grundlegenden Konzepte angemessen aufbereitet in der Dokumentation unterzubringen und zu erklären.