LFD435 Entwicklung von Gerätetreibern für embedded Linux-Systeme
Classroom Schulung | Deutsch | Anspruch
Schulungsdauer: 4 Tage
Ziele
In diesem Kurs lernen Sie die Entwicklung von Gerätetreibern für Linux-Systeme und erlangen ein Verständnis von Linux-Kernels. Sie erhalten dabei einen Einblick in die unterschiedlichen Typen von Gerätetreibern in Linux sowie in geeignete APIs zur Programmierung von Gerätetreibern.
Zielgruppe
- Programmierer
- Entwickler
Voraussetzungen
- Kenntnisse zu wesentlichen Kernel-Schnittstellen und Techniken
- Anwendungserfahrung mit Synchronisationsfunktionen
- Grundlagenkenntnisse zu Speicherzuweisung und -verwaltung
Agenda
Einführung
Überblick
- Verfahren
- Kernel-Versionen
- Kernel-Quellen und Verwendung von git
- Hardware
Wie man in OSS-Projekten arbeitet
- Überblick darüber, wie man richtig beiträgt
- Bleiben Sie nah an der Hauptstrecke für Sicherheit und Qualität
- Lernen und Verstehen der Projekt-DNA
- Herausfinden, welches Itch Sie Scratchen möchten
- Identifizieren Sie die Maintainer und ihre Arbeitsabläufe und Methoden
- Frühzeitige Eingaben und Arbeit im Freien erhalten
- Inkrementelle Bits beisteuern, keine großen Code-Dumps
- Lassen Sie Ihr Ego an der Tür: Seien Sie nicht Thin-Skinned
- Seien Sie geduldig, entwickeln Sie langfristige Beziehungen, seien Sie hilfsbereit
Entwicklungsübergreifende Toolchain
- Das Compiler-Triplet
- Eingebauter Cross-Compiler für Linux-Distributionen
- Linaro
- CodeSourcery
- crosstool-ng
- Buildroot
- OpenEmbedded
- Yocto-Projekt
QEMU
- Was ist QEMU?
- Emulierte Architekturen
- Bildformate
- Warum QEMU verwenden?
Booten eines Target Development Board von uSD
- Warum verwenden wir uSD-Karten?
- SW auf eine uSD-Karte bringen
- Warum ist die Verwendung von uSD-Karten eine schlechte Idee?
Booten eines Target-Entwicklungsboards über Ethernet
- Verwendung virtueller Hardware
- Ein einfacherer Weg zur Entwicklung
- Ziele des Labs
Konfigurieren, Compilieren und Booten des Kernels
- Konfigurieren des Kernels für den Entwicklungsausschuss
Gerätetreiber
- Arten von Geräten
- Mechanismus vs. Richtlinie
- Binary Blobs vermeiden
- Energieverwaltung
- Wie Anwendungen Gerätetreiber verwenden
- Durch einen Systemanruf gehen und auf ein Gerät zugreifen
- Fehler-Nummern
- printk()
- devres: Verwaltete Geräteressourcen
Module und Gerätetreiber
- Die module_driver()-Makros
- Module und Hot Plug
Speicherverwaltung und -zuweisung
- Virtueller und physischer Speicher
- Memory Zones
- Page Tables
- kmalloc()
- __get_free_pages()
- vmalloc()
- Slabs und Cache-Zuweisungen
Zeichenorientierte Geräte
- Geräte-Nodes
- Haupt- und Nebenzahlen
- Reservieren von Haupt-/Minderwertigen Nummern
- Zugriff auf den Geräte-Nodes
- Registrieren des Geräts
- udev
- dev_printk() und Associates
- file_operationen Struktur
- Driver Entry für Fahrer
- Die Datei- und Inode-Strukturen
- Diverse Zeichen-Treiber
Kernel-Funktionen
- Komponenten des Kernels
- Benutzer-Space vs. Kernel-Space
- Was sind Systemaufrufe?
- Verfügbare Systemanrufe
- Zeitplanungsalgorithmen und Aufgabenstrukturen
- Prozess-Kontext
Übertragung zwischen User- und Kernel-Space
- Übertragen zwischen Spaces
- put(get)_user() und copy_to(from)_user()
- Direkter Transfer: Kernel-I/O und Speicherzuordnung
- Kernel-I/O
- Abbildung von Benutzerseiten
- Memory Mapping
- User-Space Functions für mmap()
- Driver Entry Point für mmap()
- Zugriff auf Dateien vom Kernel aus
Plattform-Treiber
- Übertragen zwischen Spaces
- put(get)_user() und copy_to(from)_user()
- Direkter Transfer: Kernel-I/O und Speicherzuordnung
- Kernel-I/O
- Abbildung von Benutzerseiten
- Memory Mapping
- User-Space Functions für mmap()
- Driver Entry Point für mmap()
- Zugriff auf Dateien vom Kernel aus
Device Trees
- Was sind Device Trees?
- Was Device Trees tun und was sie nicht tun
- Device Trees-Syntax
- Device Trees-Durchgang
- Device Trees-Bindungen
- Unterstützung von Device Trees in Bootloadern
- Verwendung von Device Trees in Treibern
- Koexistenz und Konversion alter Treiber
Interrupts und Exceptions
- Was sind Interrupts und Exceptions?
- Exceptions
- Asynchrone Unterbrechungen
- MSI
- Aktivieren/Deaktivieren von Unterbrechungen
- Was Sie zur Unterbrechungszeit nicht tun können
- IRQ-Datenstrukturen
- Installieren eines Interrupt-Handlers
Zeitmessungen
- Arten von Timing-Messungen
- Jiffies
- Abrufen der aktuellen Zeit
- Takt-Quellen
- Echtzeituhr
- Programmierbarer Intervall-Timer
- Zeitstempel-Zähler
- HPET
- Tickless werden
Kernel-Timer
- Einfügen von Delays
- Was sind Kernel-Timer?
- Low-Resolution Timer-Funktionen
- Low-Resolution Timer-Implementierung
- High-Resolution Timer
- Verwendung High-Resolution Timer
ioctls
- Was sind Ioctls?
- Treiber Einstiegspunkt für Ioctls
- Ioctl definieren
Firmware
- Was ist Firmware?
- Laden von Firmware
Sleeping und Wait Queues
- Was sind Wait Queues?
- Going to Sleep und Waking Up
- Going to Sleep Details
- Exclusives Sleeping
- Waking Up Details
- Umfrage
Unterbrechungsbehandlung: Aufschiebbare Funktionen und Benutzertreiber
- Top und Bottom Halves
- Softirqs
- Aufgaben
- Work Queues
- Neue Work Queue-API
- Kernel-Threads erstellen
- Threaded Interrupt-Handler
- Behandlung von Unterbrechungen im Benutzerbereich
Hardware-I/Os
- Speicher-Barrieren
- Zuweisen und Zuordnen von I/O-Speicher
- Zugriff auf I/O-Speicher
Direkter Speicherzugriff (DMA)
- Was ist DMA?
- DMA direkt zum Benutzer
- DMA und Unterbrechungen
- DMA-Speicher-Einschränkungen
- DMA-Masken
- DMA-API
- DMA-Pools
- Scatter/Gather Mappings
Speichertechnologie-Geräte (Flash Memory Filesystems)
- Was sind MTD-Geräte?
- NAND vs. NOR vs. eMMC
- Treiber- und Anwendermodule
- Flash-Dateisysteme
USB-Treiber
- Was ist USB?
- USB-Topologie
- Terminologie
- Endpunkte
- Deskriptoren
- USB-Geräte-Klassen
- USB-Unterstützung unter Linux
- Registrieren von USB-Gerätetreibern
- Daten verschieben
- Beispiel eines USB-Treibers
Abschluss- und Bewertungsumfrage
- Evaluations-Umfrage
Anhänge
Booten des Target Development
- Board von uSD
- Ziele des Labs
Kernel-Architektur I
- UNIX und Linux
- Monolithische und Mikrokerne
- Objektorientierte Methoden
- Hauptaufgaben im Kernel
- Benutzer-Space und Kernel-Space
Vorschau der Kernel-Programmierung
- Task-Strukturierung
- Speicherzuweisung
- Übertragen von Daten zwischen Benutzer- und Kernel-Bereichen
- Verknüpfte Listen
- Jiffies
Module
- Was sind Module?
- Ein triviales Beispiel
- Module kompilieren
- Module vs. Eingebaut
- Module Dienstprogramme
- Automatisches Laden/Entladen von Modulen
- Anzahl der Modulnutzungen
- Modul-Lizenzierung
- Symbole exportieren
- Symbole auflösen
Kernel-Architektur II
- Prozesse, Threads und Aufgaben
- Kernel-Befreiung
- Echtzeit Preemption Patches
Kernel-Konfiguration und Kompilierung
- Installation und Layout der Kernel-Quelle
- Kernel-Browser
- Kernel-Konfigurationsdateien
- Kernelbau und Makefiles
- initrd und initramfs
Kernel Style und allgemeine Erwägungen
- Kodierungsstil
- Verwendung generischer Kernel-Routinen und -Methoden
- Erstellen eines Kernel-Patches
- sparse
- Verwendung von likely() und unlikely()
- Schreiben von portablem Code, CPU, 32/64-Bit, Endianness
- Schreiben für SMP
- Schreiben für hohe Speichersysteme
- Energieverwaltung
- Sicherheit im Auge behalten
Race Conditions und Synchronisationsmethoden
- Methoden zur Gleichzeitigkeit und Synchronisierung
- Atomare Operationen
- Bit-Operationen
- Spinlocks
- Seqlocks
- Deaktivieren des Vorkaufs
- Mutexe
- Semaphoren
- Funktionen der Vervollständigung
- Lese-Kopier-Update (RCU)
- Referenzzählungen
Speicheradressierung
- Verwaltung des virtuellen Speichers
- Systeme mit und ohne MMU und TLB
- Speicher-Adressen
- Hoher und niedriger Speicher
- Speicher-Zonen
- Spezielle Geräte-Knoten
- NUMA
- Seite
- Seite Tabellen
- Seitenstruktur
Speicherzuweisung
- Anfordern und Freigeben von Seiten
- Buddy-System
- Slabs und Cache-Zuweisungen
- Speicher-Pools
- kmalloc()
- vmalloc()
- Frühe Zuteilungen und bootmem()
- Defragmentierung
Ziele
In diesem Kurs lernen Sie die Entwicklung von Gerätetreibern für Linux-Systeme und erlangen ein Verständnis von Linux-Kernels. Sie erhalten dabei einen Einblick in die unterschiedlichen Typen von Gerätetreibern in Linux sowie in geeignete APIs zur Programmierung von Gerätetreibern.
Zielgruppe
- Programmierer
- Entwickler
Voraussetzungen
- Kenntnisse zu wesentlichen Kernel-Schnittstellen und Techniken
- Anwendungserfahrung mit Synchronisationsfunktionen
- Grundlagenkenntnisse zu Speicherzuweisung und -verwaltung
Agenda
Einführung
Überblick
- Verfahren
- Kernel-Versionen
- Kernel-Quellen und Verwendung von git
- Hardware
Wie man in OSS-Projekten arbeitet
- Überblick darüber, wie man richtig beiträgt
- Bleiben Sie nah an der Hauptstrecke für Sicherheit und Qualität
- Lernen und Verstehen der Projekt-DNA
- Herausfinden, welches Itch Sie Scratchen möchten
- Identifizieren Sie die Maintainer und ihre Arbeitsabläufe und Methoden
- Frühzeitige Eingaben und Arbeit im Freien erhalten
- Inkrementelle Bits beisteuern, keine großen Code-Dumps
- Lassen Sie Ihr Ego an der Tür: Seien Sie nicht Thin-Skinned
- Seien Sie geduldig, entwickeln Sie langfristige Beziehungen, seien Sie hilfsbereit
Entwicklungsübergreifende Toolchain
- Das Compiler-Triplet
- Eingebauter Cross-Compiler für Linux-Distributionen
- Linaro
- CodeSourcery
- crosstool-ng
- Buildroot
- OpenEmbedded
- Yocto-Projekt
QEMU
- Was ist QEMU?
- Emulierte Architekturen
- Bildformate
- Warum QEMU verwenden?
Booten eines Target Development Board von uSD
- Warum verwenden wir uSD-Karten?
- SW auf eine uSD-Karte bringen
- Warum ist die Verwendung von uSD-Karten eine schlechte Idee?
Booten eines Target-Entwicklungsboards über Ethernet
- Verwendung virtueller Hardware
- Ein einfacherer Weg zur Entwicklung
- Ziele des Labs
Konfigurieren, Compilieren und Booten des Kernels
- Konfigurieren des Kernels für den Entwicklungsausschuss
Gerätetreiber
- Arten von Geräten
- Mechanismus vs. Richtlinie
- Binary Blobs vermeiden
- Energieverwaltung
- Wie Anwendungen Gerätetreiber verwenden
- Durch einen Systemanruf gehen und auf ein Gerät zugreifen
- Fehler-Nummern
- printk()
- devres: Verwaltete Geräteressourcen
Module und Gerätetreiber
- Die module_driver()-Makros
- Module und Hot Plug
Speicherverwaltung und -zuweisung
- Virtueller und physischer Speicher
- Memory Zones
- Page Tables
- kmalloc()
- __get_free_pages()
- vmalloc()
- Slabs und Cache-Zuweisungen
Zeichenorientierte Geräte
- Geräte-Nodes
- Haupt- und Nebenzahlen
- Reservieren von Haupt-/Minderwertigen Nummern
- Zugriff auf den Geräte-Nodes
- Registrieren des Geräts
- udev
- dev_printk() und Associates
- file_operationen Struktur
- Driver Entry für Fahrer
- Die Datei- und Inode-Strukturen
- Diverse Zeichen-Treiber
Kernel-Funktionen
- Komponenten des Kernels
- Benutzer-Space vs. Kernel-Space
- Was sind Systemaufrufe?
- Verfügbare Systemanrufe
- Zeitplanungsalgorithmen und Aufgabenstrukturen
- Prozess-Kontext
Übertragung zwischen User- und Kernel-Space
- Übertragen zwischen Spaces
- put(get)_user() und copy_to(from)_user()
- Direkter Transfer: Kernel-I/O und Speicherzuordnung
- Kernel-I/O
- Abbildung von Benutzerseiten
- Memory Mapping
- User-Space Functions für mmap()
- Driver Entry Point für mmap()
- Zugriff auf Dateien vom Kernel aus
Plattform-Treiber
- Übertragen zwischen Spaces
- put(get)_user() und copy_to(from)_user()
- Direkter Transfer: Kernel-I/O und Speicherzuordnung
- Kernel-I/O
- Abbildung von Benutzerseiten
- Memory Mapping
- User-Space Functions für mmap()
- Driver Entry Point für mmap()
- Zugriff auf Dateien vom Kernel aus
Device Trees
- Was sind Device Trees?
- Was Device Trees tun und was sie nicht tun
- Device Trees-Syntax
- Device Trees-Durchgang
- Device Trees-Bindungen
- Unterstützung von Device Trees in Bootloadern
- Verwendung von Device Trees in Treibern
- Koexistenz und Konversion alter Treiber
Interrupts und Exceptions
- Was sind Interrupts und Exceptions?
- Exceptions
- Asynchrone Unterbrechungen
- MSI
- Aktivieren/Deaktivieren von Unterbrechungen
- Was Sie zur Unterbrechungszeit nicht tun können
- IRQ-Datenstrukturen
- Installieren eines Interrupt-Handlers
Zeitmessungen
- Arten von Timing-Messungen
- Jiffies
- Abrufen der aktuellen Zeit
- Takt-Quellen
- Echtzeituhr
- Programmierbarer Intervall-Timer
- Zeitstempel-Zähler
- HPET
- Tickless werden
Kernel-Timer
- Einfügen von Delays
- Was sind Kernel-Timer?
- Low-Resolution Timer-Funktionen
- Low-Resolution Timer-Implementierung
- High-Resolution Timer
- Verwendung High-Resolution Timer
ioctls
- Was sind Ioctls?
- Treiber Einstiegspunkt für Ioctls
- Ioctl definieren
Firmware
- Was ist Firmware?
- Laden von Firmware
Sleeping und Wait Queues
- Was sind Wait Queues?
- Going to Sleep und Waking Up
- Going to Sleep Details
- Exclusives Sleeping
- Waking Up Details
- Umfrage
Unterbrechungsbehandlung: Aufschiebbare Funktionen und Benutzertreiber
- Top und Bottom Halves
- Softirqs
- Aufgaben
- Work Queues
- Neue Work Queue-API
- Kernel-Threads erstellen
- Threaded Interrupt-Handler
- Behandlung von Unterbrechungen im Benutzerbereich
Hardware-I/Os
- Speicher-Barrieren
- Zuweisen und Zuordnen von I/O-Speicher
- Zugriff auf I/O-Speicher
Direkter Speicherzugriff (DMA)
- Was ist DMA?
- DMA direkt zum Benutzer
- DMA und Unterbrechungen
- DMA-Speicher-Einschränkungen
- DMA-Masken
- DMA-API
- DMA-Pools
- Scatter/Gather Mappings
Speichertechnologie-Geräte (Flash Memory Filesystems)
- Was sind MTD-Geräte?
- NAND vs. NOR vs. eMMC
- Treiber- und Anwendermodule
- Flash-Dateisysteme
USB-Treiber
- Was ist USB?
- USB-Topologie
- Terminologie
- Endpunkte
- Deskriptoren
- USB-Geräte-Klassen
- USB-Unterstützung unter Linux
- Registrieren von USB-Gerätetreibern
- Daten verschieben
- Beispiel eines USB-Treibers
Abschluss- und Bewertungsumfrage
- Evaluations-Umfrage
Anhänge
Booten des Target Development
- Board von uSD
- Ziele des Labs
Kernel-Architektur I
- UNIX und Linux
- Monolithische und Mikrokerne
- Objektorientierte Methoden
- Hauptaufgaben im Kernel
- Benutzer-Space und Kernel-Space
Vorschau der Kernel-Programmierung
- Task-Strukturierung
- Speicherzuweisung
- Übertragen von Daten zwischen Benutzer- und Kernel-Bereichen
- Verknüpfte Listen
- Jiffies
Module
- Was sind Module?
- Ein triviales Beispiel
- Module kompilieren
- Module vs. Eingebaut
- Module Dienstprogramme
- Automatisches Laden/Entladen von Modulen
- Anzahl der Modulnutzungen
- Modul-Lizenzierung
- Symbole exportieren
- Symbole auflösen
Kernel-Architektur II
- Prozesse, Threads und Aufgaben
- Kernel-Befreiung
- Echtzeit Preemption Patches
Kernel-Konfiguration und Kompilierung
- Installation und Layout der Kernel-Quelle
- Kernel-Browser
- Kernel-Konfigurationsdateien
- Kernelbau und Makefiles
- initrd und initramfs
Kernel Style und allgemeine Erwägungen
- Kodierungsstil
- Verwendung generischer Kernel-Routinen und -Methoden
- Erstellen eines Kernel-Patches
- sparse
- Verwendung von likely() und unlikely()
- Schreiben von portablem Code, CPU, 32/64-Bit, Endianness
- Schreiben für SMP
- Schreiben für hohe Speichersysteme
- Energieverwaltung
- Sicherheit im Auge behalten
Race Conditions und Synchronisationsmethoden
- Methoden zur Gleichzeitigkeit und Synchronisierung
- Atomare Operationen
- Bit-Operationen
- Spinlocks
- Seqlocks
- Deaktivieren des Vorkaufs
- Mutexe
- Semaphoren
- Funktionen der Vervollständigung
- Lese-Kopier-Update (RCU)
- Referenzzählungen
Speicheradressierung
- Verwaltung des virtuellen Speichers
- Systeme mit und ohne MMU und TLB
- Speicher-Adressen
- Hoher und niedriger Speicher
- Speicher-Zonen
- Spezielle Geräte-Knoten
- NUMA
- Seite
- Seite Tabellen
- Seitenstruktur
Speicherzuweisung
- Anfordern und Freigeben von Seiten
- Buddy-System
- Slabs und Cache-Zuweisungen
- Speicher-Pools
- kmalloc()
- vmalloc()
- Frühe Zuteilungen und bootmem()
- Defragmentierung