Programowanie sterowników urządzeń w jądrze Linux
Kurs, na praktycznych przykładach, dostarcza wiedzę niezbędną do rozpoczęcia
projektowania i implementacji sterowników urządzeń w jądrze Linux.
Praktyczne ćwiczenia polegają na sukcesywnej implementacji
kolejnych funkcji sterownika obsługującego ekspander I2C. Sterownik alokuje pamięć, wykrywa
i inicjuje urządzenie, komunikuje się z nim, rejestruje przerwanie, udostępnia funkcje urządzenia
w systemie jako urządzenie znakowe, oraz za pośrednictwem frameworków: input
(klawiatura/mysz), gpio, interrupt controller. Definiowane w Device-Tree urządzenie opisuje
zasoby sterownika, określa multipleksację i rezerwację PIN-ów procesora.
- Cas trwania:
- 4 dni (32 godziny)
Cel szkolenia
- poznanie zasad działania jądra Linux
- poznanie algorytmów, mechanizmów i ich warstw: planisty, wywołań
systemowych, zarządzania pamięcią
- poznanie zasad i dobrych praktyk związanych z tworzeniem sterowników w Linuksie
- wykształcenie praktycznych umiejętności pisania sterowników (obsługi
pamięci, przerwań, komunikacji z przestrzenią użytkownika, współbieżności itp.)
- poznanie frameworków dostarczanych przez jądro: model sterowników urządzeń, urdządzenia klas: misc, input, net, framebuffer i inne
- nabycie praktycznych umiejętności programowa w jądrze, debugowania go i rozwiązywania problemów
Program szkolenia
Dzień 1
- Wprowadzenie do programowania w jądrze Linux.
- Budowa systemu przy pomocy narzędzi automatycznych.
- Przygotowanie środowiska pracy, programy pomocnicze i ich wersje.
- Praca z kodem źródłowym jądra i zewnętrznych modułów w środowisku Eclipse.
- Uruchamianie jądra systemu, rola bootloadera. U-BOOT.
- Moduły jądra - zarządzanie modułami, organizacja kodu jądra.
- Komunikacja z przestrzenią użytkownika: wywołania systemowe. Działanie
wywołań systemowych w architekturach x86 i ARM.
Ćwiczenia
- Konfiguracja systemu budowania Yocto. Budowanie systemu (dla zaoszczędzenia czasu dostarczone są: cache i prekompilowane obrazy/toolchain).
- Instalacja SDK zbudowanego przez Yocto.
- Konfiguracja i kompilacja jądra Linux - uruchomienie o na urządzeniu.
- Konfiguracja Eclipse do pracy z kodem żródłowym jądra i modułów.
- (opcjonalnie) Konfiguracja QTCreator-a do pracy z kodem żródłowym jądra i modułów.
- Kompilacja i ładowanie/wyładowanie modułów jądra.
- kompilacja modułów – prosty moduł, moduł z parametrami (chodzi o poznanie specyfiki
pracy z kodem)
- pisanie modułu "wirusa" - ćwiczenie przekrojowe - analizowanie wywołań
systemowych, odnajdywanie implementacji wywołania w jądrze, operacje na listach,
operacje na modułach.
Dzień 2
- Komunikacja ze sprzętem (wejście-wyjście).
- przestrzeń adresowa procesora, adresowanie fizyczne, wirtualna przestrzeń adresowa
- MMU, TLB - mapowanie adresów wirtualnych na fizyczne
- Procesy: pamięć wirtualna, przestrzeń adresowa procesu, cykl życia
procesu, tworzenie procesu, atrybuty procesu, task_struct, implementacja wątków.
- Zarządzanie pamięcią, przestrzeń adresowa, alokacja pamięci, działanie
systemu w środowisku z niewystarczającą ilością pamięci (kmalloc, kzalloc,
vmalloc, get_free_pages, ioremap, SLAB, SLUB, SLOB, oom_killer)
- Komunikacja proces-jądro
- rodzaje urządzeń udostępnianych przez jądro,
- urządzenia znakowe,
- wymiana danych (kopiowanie, mmap())
Ćwiczenia
- Dostęp do fizycznych adresów z poziomu aplikacji i kodu jądra (/dev/mem, ioremap())
- Prosty sterownik portu szeregowego - implementacja odczytów i zapisów do urządzenia znakowego, dostęp do rejestrów procesora.
- Alokacja pamięci - eksperymenty
Dzień 3
- Zunifikowany model urządzeń w Linuksie. W jaki sposób system widzi i organizuje urządzenia? magistrala, sterownik magistrali, sterownik kontrolera, urządzenie, automatyczne kojarzenie sterowników z urządzeniami,
- Magistrala platform. Specyfikowanie urządzeń przy pomocy Device-Tree.
- Magistrala I2C, specyfika urządzeń i sterowników I2C.
- Magistrala SPI, specyfika urządzeń i sterowników SPI.
- (opcjonalnie) Magistrala PCI, specyfika urządzeń i sterowników PCI.
- (opcjonalnie) Magistrala USB, specyfika urządzeń i sterowników USB.
- Urządzenia blokowe – struktura sterownika i wydajność.
- Urządzenia sieciowe – struktura sterownika, kontrola transmisji, interfejs
gniazd, strojenie parametrów,
- Podsystem urządzeń wejściowych interfejsu użytkownika (input).
Ćwiczenia
- Konfiguracja Device-Tree dla kontrolega I2C i urządznia - ekspandera I2C.
- Implementacja sterownika magistrali platform.
- Implementacja obsługi wielu urządzeń w sterowniku.
- Komunikacja z ekspanderem, udostępnianie funkcji ekspandera przy użyciu frameworka misc
- Urządzenia input (polled_input) - sterownik klawiatury.
Dzień 4
- Przerwania: sposób obsługi i rejestracji przerwań w jądrze, dolne połówki
(softirq, tasklet, workqueue), przerwania w wątkach (RT).
- Wejście-wyjście oparte na przerwaniach: synchronizacja proces-jądro,
waitqueue, przykłady rzeczywistych sterowników,
- Planista: O(1), CFQ, cgroup, implementacja planisty, klasy szeregowania
procesów (SCHED_OTHER, SHCED_FIFO, SCHED_RR, SCHED_DEADLINE), priorytety
procesów, afiniczność.
- Wirtualny system plików - budowa i implementacja.
- Zaawansowane operacje na plikach w VFS – komunikacja z przestrzenią
użytkownika - metody synchroniczne i asynchroniczne, ioctl, mmap, AIO.
- Czas w jądrze systemu: pomiar upływu czasu, wstrzymanie uruchomienia -
usypianie na określony czas, oczekiwanie na zdarzenia, timery, timery wysokiej
rozdzielczości.
- Wielowątkowość i synchronizacja zasobów (zmienne atomowe, mutexy,
semafory, spinlock, zmienne warunkowe, algorytmy niewymagające blokowania -
RCU).
- DMA, zasada działania, alokacja pamięci dla DMA, synchronizacja.
- Debugowanie i profilowanie jądra systemu:
- metody i narzędzia debugowania
- printk i funkcje pomocnicze
- debugfs
- oops – analiza zrzutów stosu i rejestrów
- zewnętrzne metody debugowania: KGDB, QEMU, JTAG (dla platform wbudowanych)
- śledzenie wykonania i profilowanie jądra: ftrace, perf, LTTng
- wykrywanie zakleszczeń
- wykrywanie wycieków pamięci - narzędzia, dobre praktyki, praktyczne
przykłady.
Ćwiczenia
- Realizacja sterownika ekspandera z użyciem obsługi przerwań.
- Debugowanie sterownika i obsługi przerwań.
- Eksperymenty z przykładowymi sterownikami i programami.
- Praktyczne profilowanie systemu przy użyciu LTTng.