Serie: Embedded Linux - Das Komplizierte

  Götz   Lesezeit: 5 Minuten  🗪 3 Kommentare

Zum Auftakt der Serie geht es um Kernel und Userland.

serie: embedded linux - das komplizierte

Den meisten Nutzern und Nutzerinnen wird einmal von der immerwährenden Voraussage gehört haben, dass dieses Jahr das Jahr des Linux Desktops wird. Dieser – inzwischen ironische, leicht fatalistische Spruch – ist wahr geworden. Wie, werdet ihr euch fragen? Im Kleinen, wo den sonst! Bekannt dürfte das Smartphone sein, dieses arbeitet mit Android und das wiederum hat einen Linux Kernel. Einen sehr stark veränderten Kernel, aber ein Linux Kernel. Auch auf eurem Fernseher läuft ein Linux, auf der Set-Top-Box, dem Router, dem Smart-Home, der intelligenten Soundanlage, … die Liste lässt sich beliebig fortsetzten. Im industriellen Bereich, z. B. der Robotik, hat sich Linux ebenso durchgesetzt.

Aber wie kann ein Betriebssystem so wandelbar sein? Es kann auf einer Set-Top-Box arbeiten, mit einem 500MHz Armv7 Prozessor. Aber auch kann es bei einem Roboter Kamera-, Radar-, LiDAR und Audiodaten verarbeiten.
Dazu muss man die Begrifflichkeiten trennen: Kernel und Userland. Das, was wir als Linux bezeichnen, ist nur die Basis, der Kern des Betriebssystems. Der Kernel steuert den Prozessor an, sein Speicherinterface, seine Beschleuniger für mathematische Operationen und Interfaceschnittstellen, so z. B. CAN, SPI und I2C. Das Userland abstrahiert diese Schnittstellen. Zwischen Userland und Hardware liegt der Kernel. Aber Achtung! Viele erliegen hier der falschen Annahme, dass die ganze „Intelligenz“ der Komponentenansteuerung im Kernel liegt. Bei komplexen Systemen, so der Bildverarbeitung, leistet der Kernel nur die Initialisierung und „Übersetzung“ der Kommunikationsdaten zwischen Hardware und Userland.

Ein gutes Beispiel ist hierfür das Libcamera Projekt. Der Kernel bietet Treibermodule, die die Kommunikation zwischen Software und Grafikkern bereitstellen, die Bibliothek Libcamera hingegen erzeugt die Daten und Befehle für die Verarbeitung. Das Userland (Libcamera) ist nur zu bestimmten Kernelversionen kompatibel, und zwar denen, die das genutzte Interface bereitstellen!

Das wirft eine Frage auf: Kann man Userland und Kernel trennen? Die Antwort ist komplex und endet in einem klaren: Es kommt darauf an. Für die Kapselung spricht, dass jedes Hardwareinterface sich durch ein Softwareinterface abbilden lässt. Ein in Software gekapseltes Hardwareinterface nennt man Treiber. Im Falle Linux beschreibt ein solches Stück Software ein Kernelmodul. Das Softwareinterface kann durch passende Software aus dem Userland angesprochen werden und damit der Hardware Befehle erteilen. Durch einen Paketmanager lässt sich die Software aus dem Userland leicht austauschen.

Der Linux Anwender kennt das, jeder Zugriff über ein open() Systemaufruf spricht durch die verschiedenen Ebenen des Userlands und Kernels einen Datenträger an und lädt eine Datei. Es ist dabei egal, ob diese Datei auf einer CD, Festplatte oder USB-Stick liegt. Dabei ist open() auch eine Form von abstraktem Interface. Indem jede Schnittstelle als Datei angeboten wird, können auch Schnittstellen, wie der I2C, als Datei gelesen und geöffnet werden.

Andererseits gibt es auch komplexere Systeme, am anschaulichsten sind hier Kamerasysteme. Sie kommunizieren über viele Schnittstellen, bekannt dürften dabei USB, CSI (Camera-Serial-Interface) und Ethernet sein. Jede Schnittstelle hat unzählige Formate (= Protokolle) wie Daten übertragen werden können. Bei Ethernet können die Bilder als UDP, TCP oder eine Serie an Ethernet-Frames übertragen werden. Bei CSI können die Bilder schon verarbeitet (RGB-Matrix) oder unverarbeitet (Bayers-Format) eintreffen. Wo ist hier der Unterschied zu einem „normalen“ Systemaufruf? Schliesslich liegt auf meiner Platte auch kein Treiber zum Lesen eines PDFs, warum sollte der Treiber sich um mein Bildformat kümmern? Eingebettete Systeme nutzen im Regelfall bestimmte Rechenwerke, um mathematische Operationen zu beschleunigen. Dies hat zwei Hauptgründe:

  • Kosten: Jede aufwendige Berechnung erfordert einen leistungsstarken Prozessor. Diese sind meist kostspielig, sodass die Entwicklung/Verwendung eines speziellen Rechenwerks billiger ist. Das Rechenwerk kann nur die geforderte Berechnung durchführen, diese aber billig und schnell.

  • Energie: Aufwendige Berechnungen benötigen viel Energie. Durch spezielle Schaltkreise kann der Energiebedarf drastisch gesenkt werden. Matrixoperationen können Element für Element berechnet werden oder durch ein spezielles Rechenwerk als eine, atomare Operation. Dabei benötigt das spezialisierte Rechenwerk viel weniger Energie, da hier insgesamt weniger Schaltungsvorgänge innerhalb des Rechenwerks benötigt werden.

Im Fall der Kamera ist das ein Bildprozessor, der bestimmte Algorithmen ausführt, um aus dem Bild im Bayers-Format eine Punkt-Matrix zu generieren. Aber auch die Generierung eines Videostreams ist möglich. Aus Sicht des Anwenders gibt der Kernel somit ein Bild im Rohformat (Bayers), als Pixelmatrix oder als Frame eines Videosignals aus. Dazu muss das Userland mit den entsprechenden Treibern kommunizieren, Einstellungen vornehmen und Datenendpunkte erzeugen. Der hier beschriebene Anwendungsfall bedeutet für jeden Kamera- und Prozessorhersteller eine einzigartige Lösung. Die Schnittstellen von Bildprozessor und Kamera sind nicht einheitlich. Auch bietet nicht jedes System die gleichen Funktionen an, manche Funktionen sind zusammengefasst, andere separiert. So funktioniert die Software aus dem Userland nur mit bestimmter Hardware und bestimmten Treibern.

Das Problem gibt es bei jeder Form von Betriebssystem. Einheitliche Interfaces bilden sich erst im Laufe der Zeit heraus, wenn Standards geschaffen werden.

Es lässt sich aber auch nicht scharf zwischen dem ersten Anwendungsfall und dem zweiten trennen, es gibt einen fliessenden Übergang. Eingebettete Linuxsysteme zeichnen sich darüber aus, dass man sie eher dem zweiten Fall zuordnen kann. Mehrere spezialisierte Hardwarekomponenten arbeiten zusammen, um eine Aufgabe zu erfüllen. Ein Debian, Ubuntu oder Fedora kann das nicht alles abdecken. Der Aufwand jede Kombination abzubilden, wäre enorm und ist nicht zu leisten.

Im Bereich des Embedded Linux gibt es zwei Lösungen: Buildroot und Yocto. Damit werden für die verwendete Hardware und Anforderung angepasste Kombinationen aus Kernel und Userland erzeugt.

Bildquelle: https://www.raspberrypi.com/news/an-open-source-camera-stack-for-raspberry-pi-using-libcamera/

Tags

Embedded, Kernel, Libcamera, Treiber, Userland, Wettbewerb

Peter
Geschrieben von Peter am 15. Juni 2022 um 13:07

Da gibts noch eine weitere Grenze fuer den Kernel bei SBCs, die interessant sein kann fuer diese Artikelserie. Eine Abgrenzung, an die ich bisher nie dachte:

Core zu Core, sowohl in Kernel wie auch in Userland:

Ein etwas teures Beispiel von heute:

https://www.cnx-software.com/2022/06/15/beaglebone-ai-64-sbc-features-ti-tda4vm-cortex-a72-r5f-soc-with-8-tops-ai-accelerator/

2 Cortex-A Kerne (klar, wohl geeignet fuer einen Linux Kernel).

6 Cortex-R Kerne (nanu?)

Im CNX Artikel steht leider noch nichts zu den folgenden Aspekten diese weiteren "Grenze":

Auf welchen Prozessoren des zB singleboard-Computers laeuft wieviel Linux - und wie offeriert der Kernel Kommunikation und Daten zu den weiteren Prozessoren: Da gibt's Boards mit Coprozessoren. Kennt der Kernel diese? Beispiel Beaglebone und die (zu "einfachen") PRU-Prozessoren.

Beim Beaglebone AI waren es dann schon neben den "richtigen Cortex-A-(Haupt)-Kernen einige Arm Cortex-M Kerne:

Wie bietet der Kernel den Cortex-M an(und vorher die Hardware des Boards): zB via UART, Einblendung von gemeinsamem Speicher? Nun, der M ist zumindest zu klein, um Linux sinnvoll drauf laufen zu lassen, oder ueber ein gemeinsames Scheduling von Prozessen nachzudenken, incl. des vereinfachten Realtime-Befehlssatzes. Also noch relativ naheliegend.

Nun gibt's aber ein noch interessanteres Beispiel von heute:

Beaglebone AI64. Hat natuerlich immer noch PRU Coprozessoren. Nur:

Statt den M-Cores gibt's jetzt Cortex-R cores. Also quasi A-Cores, nur ohne MMU. Und Linux kann (mit Zahnschmerzen) konfiguriert werden, auch ohne MMU zu laufen. Nahezu identischer Befehlssatz auf allen Kernen Cortex A wie R (ok, bei Verzicht auf Befehlssatz-Erweiterungen der neueren A72:)).

Wie bindet nun der SBC / SOM diese Kerne zusammen, und wie und was verteilt der Linux Kernel Prozesse ueber welche CPU-Kerne, wie kommuniziert das Linux von den grossen Cortex A-Kernen mit den "kleinen"?

Alles scheint nicht gaenzlich unmoeglich bei einer solchen Zusammenstellung:

von BIG.little (vielleicht besser: BIG.borked) bis Speichereinblendungen oder auch shared-nothing (zB die R-Kerne mit ihrem eigenen kleinen RTOS nur mit serieller Schnittstelle erreichbar)

Interessante Zeiten, Peter

Goetz
Geschrieben von Goetz am 16. Juni 2022 um 11:58

Ich kenne diese Konzepte. In der Automobilindustrie werden diese verwendet, um wie bei Tesla, alles auf einem Chip arbeiten zu lassen. Bosch bereitet da einige Produkte vor. Ich habe aber den Eindruck, man versucht hier den Teufel mit dem Beelzebub auszutreiben.

Das Ziel ist es Tasks, die so klein sind, dass ein "richtiges" Linux dafür eigentlich nicht gebraucht wird aus Linux heraus zu starten. Der Mikrocontroller wandert in den Prozessor und man spricht ihn nicht über einen Bus, sondern einen Treiber, an. Das klingt am Anfang ganz nett, hat aber massive Probleme:

-> Wie schütze ich die Daten aus meinem Linux? Die MMU kümmert sich ja nicht mehr um den gemappten Speicher, wie verhindere Inkonsistenzen, wie implementiere ich effiziente Locking-Mechanismen? Wie erkläre ich Linux diese Locking-Mechanismen?

-> Wie kompiliere ich Code dafür? Im schlimmsten Fall hat mein Co-Prozessor eine andere Befehlsarchitektur, wie "erkläre" ich das dem Compiler? Mach ich das zur Laufzeit mit einer JIT-compiler und jeder gestartete Task wird durch den JIT geschickt? Wie handhabe ich Befehle die nicht auf dem Co-Prozessor umzusetzen sind? Wie handhabe ich Fehler?

Ich kann die Liste jetzt hier immer weiter fortsetzten. Meiner Meinung nach ist das ein Konzept zum Scheitern verurteilt. In einem Prozessor muss ein Mindestmaß an Homogenität der Kerne vorhanden sein, möchte man nicht ganz andere Architekturen aufmachen (armv10: PatchCores mit "eingebetteten" Befehlsarchitekturen? Grusel) : Das ist zu komplex

UbIx
Geschrieben von UbIx am 27. Juni 2022 um 23:43

Das sehe ich etwas anders. Ich habe komplexe Aufgaben die ich auf Linux löse. Andere z.B. zeitkritische (real time) aufgaben löse ich auf den M oder R cors. Auch wird dort meist. Das (secure) Boot mit eigenem geschützten integrierten (statischen) RAM sowie integrierten (NOR) Flash wird ebenfalls dort gesteuert und ersetzt dann ein BIOS oder ähnliches.