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