Programowanie Systemów Wbudowanych
Transkrypt
Programowanie Systemów Wbudowanych
Programowanie Systemów Wbudowanych Jadro ˛ systemu Linux Iwona Kochańska Katedra Systemów Elektroniki Morskiej WETI PG March 30, 2016 Elementy wbudowanego OS Linux Toolchain kompilator i inne narzdzia do tworzenia kodu dla urzadze ˛ ń Bootloader inicjalizuje platform sprz˛etowa˛ oraz ładuje jadro ˛ systemu Kernel serce systemu, zarzadza ˛ zasobami i komunikuje sie˛ ze sprz˛etem Root filesystem GUT – Intel 2015/16 biblioteki i programy uruchamiane w systemie 2/47 Jadro ˛ systemu Linux Jadro ˛ (Kernel) - cz˛eść systemu operacyjnego odpowiedzialna za zarzadzanie ˛ zasobami i komunikacje˛ ze sprzetem ˛ I zwykle dopasowane do konkretnej konfiguracji sprz˛etu I drzewa urzadze ˛ ń umożliwiaja˛ tworzenie generycznego jadra, ˛ dopasowanego do platformy sprz˛etowej poprzez dtb 1991 - Linus Torvalds rozpoczał˛ prace nad systemem operacyjnym Linux dla komputerów Intel 386 i 486 I Inspiracja - Minix OS napisany przez Andrew S. Tanenbaum (1987) I Różnica miedzy ˛ Linux a Minix: I I 32-bitowe jadro ˛ wykorzystujace ˛ pamieć ˛ wirtualna˛ kod otwarty (open source, później - licencja GPL 2) GUT – Intel 2015/16 3/47 Co robi jadro? ˛ I I Linus Torvalds napisał jadro ˛ systemu operacyjnego, wykorzystujac ˛ komponenty projektu GNU (toolchain, biblioteka C, podstawowe narz˛edzia linii poleceń) Jadro ˛ może pracować wraz: I I I I przestrzenia˛ użytkownika GNU (GNU user space) -> GNU/Linux dla komputerów CP i serwerów przestrzenia˛ użytkownika Android -> OS dla urzadze ˛ ń mobilnych mała˛ przestrzenia˛ użytkownika Busybox -> kompaktowy system wbudowany Główne zadania jadra: ˛ I I I zarzadzanie ˛ zasobami, interfejs ze sprz˛etem, dostarczanie API z użytecznym poziomem abstrakcji dla programów w przestrzeni użytkownika GUT – Intel 2015/16 4/47 Co robi jadro? ˛ I Aplikacje uruchamiane sa˛ w przestrzeni użytkownika z niskim poziomem praw do CPU. Moga˛ wywoływać funkcje biblioteczne. I Biblioteka C - interfejs miedzy ˛ przestrzenia˛ użytkownika (user space) a przestrzenia˛ jadra ˛ (kernel space). Tłumaczy funkcje poziomu użytkownika (user level functions) w wywołania systemowe (kernel system calls). I Interfejs wywołań systemowych używa pułapki (trap) lub przerwań programowych (software interrupt) do przełaczania ˛ CPU miedzy ˛ przestrzenia˛ użytkownika a przestrzenia˛ jadra ˛ I Przestrzeń jadra ˛ - wysoki poziom praw dostepu ˛ do całej przestrzeni adresowej i rejestrów CPU GUT – Intel 2015/16 5/47 Co robi jadro? ˛ I System call handler przekazuje wywołania do podsystemów jadra: ˛ I I scheduling calls -> scheduler, filesystem calls -> filesystem code, I Niektóre wywołania wymagaja˛ pobrania danych z urzadze ˛ ń dołaczonych ˛ do systemu - sa˛ przekazywane do sterownika urzadzenia ˛ I Urzadzenie ˛ może samo wywołać funkcje˛ jadra ˛ generujac ˛ przerwanie I Przerwanie może być obsłużone tylko przez sterownik (nigdy przez aplikacje˛ w przestrzeni użytkownika!) Wszystko co robi aplikacja jest robione przez jadro ˛ systemu. GUT – Intel 2015/16 6/47 Wersje jadra ˛ I Nowa wersja jadra ˛ - raz na 8-12 tygodni I Numerowanie wersji: I I I przed lipcem 2011: 3 liczby,2 np.: 2.6.39. Środkowa liczba wskazuje, czy jest to wersja rozwojowa (l. nieparzysta) czy stabilna (l. parzysta) lipiec 2011: zmiana numeru z 2.6.39 na 3.0. Rezygnacja ze środkowej liczby. kwiecień 2015: wersja 4 GUT – Intel 2015/16 7/47 Wersje jadra ˛ I Drzewo rozwoju kodu jadra: ˛ $ g i t c l o n e g i t : / / g i t . k e r n e l . org / pub / scm / linux / kernel / g i t / torvalds / linux . g i t I Cykl rozwoju kodu: I I I I I 2 tygodnie akceptacji łatek do nowej wersji faza stabilizacji - publikacja wersji-kandydatów (numerowanych jako -rc1, -rc2, itd.) użytkownicy testuja˛ wersje-kandydatów i zgłaszaja˛ raporty błedów ˛ i poprawek po naprawieniu wszystkich błedów ˛ nowa wersja jadra ˛ jest publikowana Przeglad ˛ wszystkich wersji: http://kernelnewbies.org/LinuxVersions. GUT – Intel 2015/16 8/47 Wersja stabilna jadra ˛ I O wersje stabline jadra ˛ dba Greg Kroah-Hartman. I wersje “naprawcze” (bug fix releases) jadra ˛ stabilnego numerowane sa˛ trzecia˛ liczba:3.18.1, ˛ 3.18.2, itd. Przed wersja˛ 3 były to numery 4-liczbowe (2.6.29.1, 2.6.39.2) I Niektóre jadra ˛ sa˛ oznaczone jako long term (utrzymywane przez 2 lata lub dłużej) I Każdego roku publikowane jest przynajmniej jedno jadro ˛ “długoterminowe”(4.1, 3.18, 3.14, 3.12, 3.10, 3.4, 3.2, 2.6.32). I jadro ˛ 2.6.32 jest utrzymywane od 5 lat (aktulanie wersja 2.6.32.68). GUT – Intel 2015/16 9/47 Wsparcie sprzedawców sprz˛etu Sam Linux obsługuje waski ˛ zbiór platform sprz˛etowych I wsparcie niezależnych projektów open source: Linaro, Yocto Project I wsparcie firm dostarczajacych ˛ rozwiaza ˛ ń z wbudowanym OS Linux I wsparcie dostawców SoC (jadro ˛ działajace ˛ na SoC) GUT – Intel 2015/16 10/47 Licencje I Kod źródłowy Linux: licencja GPL v2 (GNU General Public License) I Założenia GPL: I I I I wolność uruchamiania programu w dowolnym celu wolność analizowania, jak program działa i dostosowywania go do swoich potrzeb wolność rozpowszechniania niezmodyfikowanej kopii programu wolność udoskonalania programu i publicznego rozpowszechniania własnych ulepszeń, dzieki ˛ czemu może z nich skorzystać cała społeczność GUT – Intel 2015/16 11/47 Licencje I Tekst licencji - w pliku COPYING. I Rozpoczyna sie˛ adnotacja, ˛ że uruchamianie wywołań jadra ˛ z przestrzeni użytkownika przez interfej wywołań systemowych nie jest pochodna˛ pracy jadra, ˛ wiec ˛ nie podlega licencji. I Licencja GPL gwarantuje, że programista systemu wbudowanego zawsze ma dostep ˛ do kodu źródłowego jadra ˛ GUT – Intel 2015/16 12/47 Licencje I I Problem z licencja: ˛ moduły jadra ˛ Moduł jadra ˛ (kernel module) - fragment kodu dynamicznie linkowany z jadrem ˛ podczas jego pracy (linked at runtime), rozszerzajacy ˛ funkcjonalność jadra ˛ I I I licencja GPL nie rozróżnia linkowania statycznego i dynamicznego akceptowalna praktyka: GPL nie musi obejmować modułow jadra ˛ (zapis w makro MODULE_LICENSE) dyskusja o GPL vs moduły jadra: ˛ http://yarchive.net/comp/linux/gpl_modules.html. GUT – Intel 2015/16 13/47 Budowa jadra ˛ - źródła I Pobranie źródeł jadra: ˛ git lub tarball. I Przykład: $ g i t c l o n e g i t : / / g i t . k e r n e l . org / pub / scm / l i n u x / k e r n e l / g i t / s t a b l e / l i n u x −s t a b l e . g i t l i n u x $ cd l i n u x $ g i t checkout v4 . 1 . 1 0 GUT – Intel 2015/16 14/47 Budowa jadra ˛ - źródła Źródła zorganizowane sa˛ w katalogi: I arch: pliki specyficzne dla architektur procesora I Documentation I drivers: sterowniki I fs: kod systemu plików I include: pliki nagłówkowe jadra ˛ I init: kod rozruchowy jadra ˛ I kernel: podstawowe funkcje: scheduling, liczniki, zarzadzanie ˛ moca, ˛ debugger I mm: zarzadzanie ˛ pamieci ˛ a˛ I net: protokoły sieciowe I scripts: skrypty, np. kompilator drzewa urzadze ˛ ń (dtc) I tools: narz˛edzia, np. do pomiaru wydajności, perf GUT – Intel 2015/16 15/47 Konfiguracja jadra ˛ I Jadro ˛ może być różnie skonfigurowane: od małego, dedykowanego (np. do obsługi termostatu) po duże i złożone (np. do obsługi telefonu komórkowego) I W każdej wersji jadra ˛ - wiele opcji konfiguracji I Kconfig - narz˛edzie konfiguracyjne I Kbuild - narz˛edzie do kompilacji i budowy jadra ˛ I Dokumentacja narz˛edzi: Documentation/kbuild/. I Kconfig/Kbuild sa˛ używane również w innych projektach: crosstool-NG, U-Boot, Barebox, BusyBox. GUT – Intel 2015/16 16/47 Konfiguracja jadra ˛ I Opcje konfiguracji zorganizowane sa˛ w sposób hierarchiczny jako pliki Kconfig I Dokumentacja: Documentation/kbuild/kconfig-language.txt. I Przykład głównego menu: Ostatnia linia: odwołanie do innego pliku Kconfig, zależnego od architektury sprz˛etu GUT – Intel 2015/16 17/47 Konfiguracja jadra ˛ I Wybór architektury: ARCH=[architecture], w przeciwnym wypadku wybrana zostanie architektura maszyny lokalnej I Wartość ARCH - jeden z podkatalogów katalogu arch (wyjatek: ˛ ARCH=i386 i ARCH=x86_64 maja˛ te same źródła arch/x86/Kconfig). Wyglad ˛ menu głównego może być różny w zależności od ARCH I GUT – Intel 2015/16 18/47 Konfiguracja jadra ˛ Plik Kconfig składa sie˛ z: I wielu menu, oznaczonych słowami kluczowymi: menu, menu title, endmenu I pozycji menu (config) GUT – Intel 2015/16 19/47 Konfiguracja jadra ˛ I Informacje o konfiguracji przechowywane sa˛ w pliku .config (plik ukryty, widoczny dla komendy ls -a) I nazwy zmiennych w pliku .config rozpoczynaja˛ sie˛ od przedrostka CONFIG_ DEVMEM is enabled -> CONFIG_DEVMEM=y GUT – Intel 2015/16 20/47 Konfiguracja jadra ˛ Typy danych: I bool: y lub not defined. I tristate: opcja może być zrealizowana jako moduł jadra ˛ (m) , wbudowana w jadro ˛ (y) lub not defined I int: liczba calkowita w systemie dziesietnym ˛ I hex: liczba całkowita bez znaku w systemie szestastkowym I string: łańcuch znaków. GUT – Intel 2015/16 21/47 Konfiguracja jadra ˛ I Zależności (dependencies) miedzy ˛ pozycjami menu sa˛ wyrażone poprzez depends on: Jeśli CONFIG_MTD nie zostało ustawione jako ’enabled’, bieżaca ˛ opcja nie zostanie wyświetlona w menu. GUT – Intel 2015/16 22/47 Konfiguracja jadra ˛ I Odrócona zależność: słowo select ustawia inne opcje, jeśli bieżaca ˛ jest ’enabled’ (przydatne podczas definiowania opcji zależnych od architektury) GUT – Intel 2015/16 23/47 Konfiguracja jadra ˛ Narz˛edzia do czytania plików Kconfig i generowania pliku .config: I Menuconfig I xconfig gconfig. Każde z nich uruchamia sie˛ poleceniem make, podajac ˛ informacje˛ o architekturze platformy: I $ make ARCH=arm menuconfig GUT – Intel 2015/16 24/47 Kernel configuration Ekran menuconfig z zaznaczona˛ opcja˛ DEVMEM: Klawisz ’/’ - szukanie opcji 25/47 GUT – Intel 2015/16 Kernel configuration I Zbiór działajacych ˛ plików konfiguracyjnych: arch/$ARCH/configs, I Podczas budowy jadra ˛ generowany jest plik nagłówkowy include/generated/autoconf.h, który zawiera sekcje #define dla każdej wartości opcji konfiguracyjnej GUT – Intel 2015/16 26/47 Identyfikacja jadra ˛ I Zapytanie o ostatnio zbudowana˛ wersje˛ jadra: ˛ $ make k e r n e l v e r s i o n 4.1.10 Ta˛ sama˛ informacje˛ można otrzymać podczas działania jadra ˛ za pomoca˛ komendy uname I Po zmianie domyślnej konfiguracji jadra ˛ należy ja˛ nazwać poprzez ustawienie zmiennej CONFIG_LOCALVERSION (w General setup configuration menu). I Zapytanie o wersje˛ konfiguracji: $ make k e r n e l r e l e a s e Ta sama informacja umieszczona jest na poczatku ˛ log-a jadra ˛ GUT – Intel 2015/16 27/47 Moduły jadra ˛ (kernel modules) I OS Linux dla Desktop: I I I moduły jadra ˛ umożliwiaja˛ dynamiczne linkowanie sterowników w zależności od dołaczonego ˛ sprz˛etu bez modułów jadra ˛ każdy sterownik musiałby być statycznie linkowany z kodem jadra ˛ -> znaczny wzrost rozmiaru jadra ˛ OS Linux dla systemów wbudowanych: I I I konfiguracja sprz˛etu i jadra ˛ jest zwykle ustalona i znana moduły jadra ˛ generuja˛ zależności miedzy ˛ wersjami jadra ˛ i systemu plików -> potencjalne źródło problemów (np. podczas aktualizacji jednego z elementów) zwykle jadra ˛ systemów wbudowanych nie korzystaja˛ z żadnych dodatkowych modułów GUT – Intel 2015/16 28/47 Moduły jadra ˛ Kiedy stosowanie modułów jadra ˛ w systemie wbudowanym jest korzystne? I kiedy rozruch musi być szybki - można odłożyć na poźniej ładowanie niektórych sterowników I kiedy system jest rozbudowany - zbyt dużo sterowników, by linkować je z jadrem ˛ statycznie (np. interfejs USB obsługujacy ˛ szerokie spektrum urzadze ˛ ń) GUT – Intel 2015/16 29/47 Kompilacja jadra ˛ Kbuild - narz˛edzie do budowy jadra. ˛ Jest to zbiór skryptów make, które: I odczytuja˛ informacje˛ o konfiguracji z pliku .config, I rozwiazuj ˛ a˛ zależności I kompiluja˛ wszystkie niezbedne ˛ elementy do kompilacji samego jadra ˛ (dtb, moduły jadra) ˛ GUT – Intel 2015/16 30/47 Kompilacja jadra ˛ Zależności (dependencies) zapisane sa˛ w plikach makefiles w ścieżce bieżacej ˛ każdego budowanego elementu. I Przykład: obj-y - element kompilowany bezwarunkowo obj-$(CONFIG_PARAM) - element kompilowany zależnie od parametru (y, m lub not defined). GUT – Intel 2015/16 31/47 Kompilacja obrazu jadra ˛ Czego oczekuje program rozruchowy? I U-Boot: plik uImage, nowsze wersje moga˛ używać zImage za pomoca˛ komendy bootz I platformy x86: plik bzImage I wiekszość ˛ pozostałych programów rozruchowych: plik zImage Przykład budowy pliku zImage: Opcja -j 4: 4 zadania moga˛ być wykonywane jednocześnie GUT – Intel 2015/16 32/47 Kompilacja obrazu jadra ˛ Platformy ARM: I Linux 3.7 - to samo jadro ˛ może działać dla róznych platform ARM I Jadro ˛ wybiera właściwa˛ platforme˛ sprz˛etowa˛ np. odczytujac ˛ informacje˛ z drzewa urzadze ˛ ń I Lokalizacja pamieci ˛ fizycznej może być różna w zależności od platformy (a wiec ˛ i adres jadra) ˛ I LOADADDR = adres odczytany z pliku mach-[your SoC]/Makefile.boot (wartość zreladdr-y). I Kompilacja jadra: ˛ GUT – Intel 2015/16 33/47 Kompilacja obrazu jadra ˛ I W wyniku kompilacji jadra ˛ powstaja˛ dwa pliki: I I I vmlinux - jadro ˛ jako plik ELF. Jeśli jadro ˛ było kompilowane z właczon ˛ a˛ opcja˛ debugowania (CONFIG_DEBUG_INFO=y), plik ten zawiera symbole pomocne dla debuggerów (np. kgdb) System.map - tablica symboli Wiekszość ˛ programów rozruchowych nie obsługuje kodu ELF. Obraz przetwarzany jest dalej w surowy plik binarny. GUT – Intel 2015/16 34/47 Kompilacja drzewa urzadze ˛ ń I dtbs - narz˛edzie do kompilacji i budowy drzewa urzadze ˛ ń. I Uruchomienie: target dla polecenia make I Przepis dla dtbs: I I plik arch/$ARCH/boot/dts/Makefile plik z kodem źródłowym Pliki .dtb generowane sa˛ w tej samej ścieżce co źródła GUT – Intel 2015/16 35/47 Kompilacja modułów jadra ˛ I Moduły moga˛ być kompilowane niezależnie od jadra. ˛ I Target modules dla make: I Skompilowane moduły maja˛ rozszerzenie .ko i znajduja˛ sie˛ w tej samej ścieżce co źródła I Target modules_install dla make - instalacja modułów jadra ˛ I Domyślna lokalizacja modułów ( /lib/modules) może być zmieniona za pomoca˛ opcji INSTALL_MOD_PATH. GUT – Intel 2015/16 36/47 Czyszczenie źródeł jadra ˛ Opcje dla polecenia make: I clean: usuwa pliki objektów i wiekszość ˛ plików pośrednich I mrproper: usuwa wszystkie pliki pośrednie, włacznie ˛ z plikiem .config file I distclean: jak mrproper oraz usuwa pliki zapasowe narz˛edzi kompilacji GUT – Intel 2015/16 37/47 Uruchomienie jadra ˛ I Proces uruchamiania jadra ˛ jest zależny od platformy sprz˛etowej I Przykład - uruchomienie jadra ˛ Linuxa na platformie BeagleBone Black z poziomu U-Boot: GUT – Intel 2015/16 38/47 Uruchomienie jadra ˛ - “kernel panic” Kernel panic - pojawienie sie˛ nierozwiazywalnego ˛ błedu ˛ I wypisanie na konsoli informacji o błedzie ˛ i zawieszenie działania systemu I Przykład: brak poprawnego systemu plików: [ VFS : [ VFS : 1.886379] Unable t o 1.895105] Unable t o Kernel panic − not syncing : mount r o o t f s on unknown−b l o c k ( 0 , 0 ) −−−[ end K e r n e l p a n i c − n o t s y n c i n g : mount r o o t f s on unknown−b l o c k ( 0 , 0 ) Taki bład ˛ może być naprawiony przez użytkownika - system plików może być dostarczony np. na karcie SD GUT – Intel 2015/16 39/47 Uruchomienie jadra ˛ - wczesna przestrzeń użytkownika (early user space) źródło: http://www.slideshare.net/shimosawa/linux-initialization-process-2 GUT – Intel 2015/16 40/47 Uruchomienie jadra ˛ - wczesna przestrzeń użytkownika I Proces PID 1 uruchamia kod init/main.c, kernel_init(). I Jeśli jest dostepny ramdisk, PID 1 spróbuje uruchomić program /init (uruchomienie przestrzeni użytkownika) I Jeśli nie uda sie˛ znaleźć i uruchomić /init, jadro ˛ spróbuje uruchomić prepare_namespace() w init/do_mounts.c. I I wymaga opcji root= w celu zdefiniowania urzadzenia ˛ blokowego (block device), z którego ma zostać zamontowany system plików root=/dev/<disk name><partition number> root=/dev/<disk name>p<partition number> Przykład: system plików z karty SD. Kolejność poleceń-prób zamontowania systemu plików root=/dev/mmcblk0p1/sbin/init GUT – Intel 2015/16 41/47 /etc/init bin/sh Komunikaty jadra ˛ I Wartość 0 - komunikat najważniejszy. I Komunikaty można obejrzeć po wywołaniu plecenia dmesg GUT – Intel 2015/16 42/47 Komunikaty jadra ˛ GUT – Intel 2015/16 43/47 Komunikaty jadra ˛ I Komunikaty sa˛ zapisywane w buforze __log_buf o rozmiarze 2^CONFIG_LOG_BUF_SHIFT I Polecenie dmesg wypisuje na ekranie zawartość bufora I Komunikat jest wyświetlany, jeśli ich poziom jest mniejszy od poziomu logowania w konsoli (wartość 7) I Oznacza to, że komunikaty KERN_DEBUG nie sa˛ zapisywane. I Zmiana poziomu logowania konsoli: loglevel=<level> lub dmesg -n <level>. GUT – Intel 2015/16 44/47 Linia poleceń jadra ˛ Kernel command line - łańcuchy znaków przekazywane do jadra: ˛ I przez bootloader (np. zmienna bootargs U-Boot) I zdefiniowane w drzewie urzadze ˛ ń I jako cz˛eść konfiguracji jadra ˛ w CONFIG_CMDLINE. Komunikaty: I debug ustawienie poziomu logowania konsoli na najwyższy poziom (8) I init= program init uruchamiany z zamontowanego systemu plików (domyślnie /sbin/init) I lpj= ustawia loops_per_jiffy I panic= jak sie˛ zachowa jadro ˛ w przypadku “kernel panic” I I I jeśli >0 - liczba sekund przed ponownym uruchomieniem jeśli = 0 - system czeka w nieskończoność (domyślnie) jeśli <0 - system uruchamia sie˛ ponownie bez żadnego opóźnienia GUT – Intel 2015/16 45/47 Linia poleceń jadra ˛ Komunikaty: I quite ustawia poziom logowania konsoli na 1 I rdinit= init program z ramdisk (domyślnie /init) I ro montuje urzadzenie ˛ root-a jako read-only (bez wpływu na ramdisk) I root= urzadzenie ˛ reprezentujace ˛ system plików root-a I rootdelay= liczba sekund przed próba˛ zamontowania urzadzenia ˛ roota (domyślnie 0) I rootfstype= rodzaj systemu plików urzadzenia ˛ roota (wymagane dla jffs2) I rootwait czeka na wykrycie urzadzenia ˛ roota (np. karty SD) I rw montuje urzadzenie ˛ root-a jako read-write (domyślnie) GUT – Intel 2015/16 46/47 Warto przeczytać C. Simmonds. Mastering Embedded Linux Programming. PACKT, 2015. A. S. Tanenbaum, H. Bos. Systemy operacyjne. Wydanie IV. Helion, 2015. GUT – Intel 2015/16 47/47