linux kernel ii - solutions for tv and iot - adb · komendy insmod bądź modprobe, ... w obrębie...

27
„Hello kernel” - jak napisać pierwszy moduł Linux Kernel II

Upload: doankhanh

Post on 01-Mar-2019

223 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

„Hello kernel” - jak napisaćpierwszy moduł

Linux Kernel II

Page 2: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 2

Przypomnienie (I)

• Moduły uruchamiane są i działają w przestrzeni Kernela (Kernel space),

• Moduły piszemy w języku C,• Moduły działają inaczej niż aplikacje: służą rozszerzaniu

podstawowych funkcjonalności jądra systemu Linux,• Popełnianie błędów programistycznych może owocować

poważniejszymi problemami.

Linux Kernel - Hello World module

Page 3: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 3

Przypomnienie (II)

Przykładowy i uproszczony schemat architektury aplikacji:

Linux Kernel - Hello World module

Hardware Driver Kernel Syscall Library App

Page 4: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 4

Wywołania systemowe (syscalls)

• Podstawowe instrukcje systemu Linux dostępne z poziomu użytkownika,

• Zwykle obudowane bibliotekami systemowymi, nie są wywoływane wprost,

• Każda funkcja standardowych bibliotek języka C może być zastąpiona wywołaniem, bądź serią wywołań systemowych,

• Przykładowo:

int printf(const char *format, ...); [std C lib function]

ssize_t write(int fd, const void *buf, size_t count); [syscall]

Linux Kernel - Hello World module

Page 5: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 5

• Najprostsza odpowiedź: NIE!• Dlaczego?

• Bo... Kernel nie zapewnia wzparcia dla C++,• Bo... nie ma innych sterowników w C++,• Bo… C jest wystarczające, aby napisać każdy sterownik.

• Trudniejsza odpowiedź: TAK! Zawsze możemy przepisać Kernel w języku C++ ;)

• Więcej informacji:• http://www.tux.org/lkml/#s15-3

Czy moduły możemy pisać w C++? (pytanie z poprzedniego wykładu)

Linux Kernel - Hello World module

Page 6: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 6

Cykl życia modułu

Linux Kernel - Hello World module

Wczytaj moduł(Insert)

Wywołaj funkcję inicjującą(Init function)

Czekaj na polecenie(request)

Wywołaj funkcję czyszczącą(Cleanup)

Remove module

komenda insmod

Komenda rmmod

Kolejka poleceń(request queue)

Page 7: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 7

• Czego potrzebujemy?• Kompilatora GCC, który musi być odowiedni dla

posiadanej wersji Linuxa, zwykle jest on dostarczany wraz z “toolchainem”,

• Skompilowanego, bądź odpowiednio przygotowanego kodu źródłowego systemu Linux,

• Konfiguracji Kernela (plik .config),• Listy symboli używanych w Kernelu (plik

Module.symvers).

Pierwszy moduł: przygotowanie (I)

Linux Kernel - Hello World module

Page 8: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 8

• Jeśli posiadamy skompilowane źródła systemu Linux w odpowiedniej wersji, to właśnie zaoszczędziliśmy sobie nieco pracy,

• Jeśli posiadamy prekompilowany system Linux (np. Arch Linux, Ubuntu czy Raspbian), to:

• Używamy przeglądarki Google, aby wyszukać instrukcję “odtworzenia” źródeł systemu Linux,

• Wszystkie instrukcje są do siebie podobne i sprowadzają się do pozyskania plików “.config” oraz “Module.symvers”,

• Większość popularnych systemów posiada łatwo dostępną instrukcję.

Pierwszy moduł: przygotowanie (II)

Linux Kernel - Hello World module

Page 9: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 9

• Przykładowa instrukcja: https://github.com/notro/rpi-source/wiki• Powyższa instrukcja w skrócie:

• Aktualizujemy kompilator GCC, jeśli jest taka potrzeba,• Pobieramy skrypt i uruchamiamy go, a wtedy:

• Skrypt aktualizuje firmware RPI (także Kernel), pobiera źródła systemu Linux w najnowszej wersji do katalogu domowego,

• Odzyskuje konfigurację systemu Linux z /proc/config.gz, bądź generuje domyślną: “make bcmrpi_defconfig”,

• Pobiera plik “Module.symvers” (!),• Wykonuje “make modules_prepare”.

Przykład: przygotowanie systemu Raspbian (III)

Linux Kernel - Hello World module

Page 10: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 10

• W pliku .config przechowywane są informacje o obecnej konfiguracji systemu Linux,

• Aby skonfigurować Kernel użyj:

make <configuration> [ls -l arch/arm/configs]

make mrpropermake menuconfigmake oldconfig

Plik .config

Linux Kernel - Hello World module

Page 11: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 11

• przechowuje dane o eksportowanych przez Kernel symboli,• Symbole to funkcje widoczne dla innych modułów,

Budowa pliku:0x5d9a4bf2 – CRC,ipv6_chk_custom_prefix – nazwa funkcji (symbol)net/ipv6/ipv6 – moduł w którym symbol jest umiejscowiony.

Plik Module.symvers

Linux Kernel - Hello World module

Page 12: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 12

#include <linux/init.h>#include <linux/module.h>#include <linux/sched.h>

MODULE_LICENSE("Dual BSD/GPL");

static int __init hello_init(void) { printk(KERN_ALERT "Hello kernel with process=%s (PID=%i, parent=%s)\n", current->comm, current->pid, current->parent->comm); return 0;}static void __exit hello_exit(void) { printk(KERN_ALERT "Goodbye kernel world.\n");}

module_init(hello_init);module_exit(hello_exit);

Moduł “Hello Kernel”

Linux Kernel - Hello World module

Page 13: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 13

• Linux/module.h• Plik potrzebny wszystkim dynamicznie ładowanym modułom,• Zawiera wiele definicji między innymi makra MODULE_LICENSE,

• Linux/init.h• Plik nagłówkowy zawierający definicje potrzebne to inicjalizacji

modułów, m.in. makra module_init, module_exit, __init, __exit,• Linux/sched.h

• Plik nagłówkowy zawierający m.in. definicje dostarczające dane o obecnym procesie,

• Current→comm, current→parent, current→pid.

Pliki nagłówkowe

Linux Kernel - Hello World module

Page 14: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 14

• Możliwe licencje znaleźć można w pliku nagłówkowym linux/module.h,

• Dostępne licencje: GPL, GPL v2, Dual BSD/GPL, Dual MPL/GPL, Proprietary i inne...,

• Niektórych funkcji można używać jedynie w modułach oznaczonych konkretnymi licencjami,

• Moduły nie zawierające definicji licencji traktowane są jako “proprietary”,

• Kiedy moduł oznaczony jest jako “proprietary”, Kernel staje się “skażony” (ang. “tainted”),

• “Skażone” Kernele nie są wspierane przez brać linuxową...

Makro MODULE_LICENSE

Linux Kernel - Hello World module

Page 15: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 15

static int __init hello_init(void) { printk(KERN_ALERT "Hello kernel with process=%s (PID=%i, parent=%s)\n", current->comm, current->pid, current->parent->comm); return 0;}

• Hello_init: funkcja statyczna, zwracająca wartość decymalną (integer), nie przyjmująca argumentów,

• __init: znacznik mówiący Kernelowi, że funkcja jest używana tylko podczas inicjalizacji modułu (potem jest usuwana z pamięci),

• Printk: funkcja pisząca, podobna do funkcji “printf” w przestrzeni użytkownika (userspace),

• KERN_ALERT: poziom logowania, jest to zwykły string,• “current”: struktura zawierająca informacje o obecnym procesie.

Funkcja init

Linux Kernel - Hello World module

Page 16: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 16

static void __exit hello_exit(void) { printk(KERN_ALERT "Goodbye kernel world.\n");}

• Hello_exit: funkcja statyczna, nie zwracająca oraz nie przyjmująca wartości,

• __exit: znacznik mówiący Kernelowi, że funkcja jest używana jedynie podczas kończenia pracy modułu,

• Jeśli funkcja oznaczona jako __exit zostanie użyta w innym kontakście, zwrócony zostanie błąd.

Funkcja exit

Linux Kernel - Hello World module

Page 17: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 17

module_init(hello_init);module_exit(hello_exit);

• Nazwy funkcji użyte jako argumenty makr module_init i module_exit są uruchamiane odpowiednio:

• W czasie inicjalizacji pracy modułu użyta zostanie funkcja “hello_init”,

• W czasie kończenia pracy modułu użyta zostanie funkcja “hello_exit”,

• Przykładowy wynik końcowy:

Makra module_init i module_exit

Linux Kernel - Hello World module

Page 18: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 18

KERN_VER := $(shell uname -r)PWD := $(shell pwd)

KERNELDIR ?= /lib/modules/$(KERN_VER)/build

obj-m := hello.o

all: clean compile

compile: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean: $(MAKE) -C $(KERNELDIR) M=$(PWD) clean

Kompilacja modułu: plik makefile

Linux Kernel - Hello World module

Page 19: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 19

• Dlaczego pliki makefile modułów Kernela wyglądają inaczej niż tradycyjne?

• Ponieważ plik makefile kompilowanego modułu staje się częścią procesu kompilowania całego Kernela,

• Ta linijka jest odpowiedzialna za dołączenie świeżo napisanego modułu do procesu kompilacji Kernela:

obj-m := hello.o

• Za wywołanie procesu kompilacji odpowiada komenda $(MAKE):

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

Kompilacja modułu: wyjaśnienie

Linux Kernel - Hello World module

Page 20: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 20

• Moduły możemy budować na dwa sposoby:• Jako wbudowane (build-in), ładowane automatycznie podczas startu

systeu Linux,• Jako zewnętrzne (loadable), ładowane przed użytkownika za pomocą

komendy insmod bądź modprobe,• Aby zbudować moduł jako wbudowany należy w pliku “.config”:

• Oznaczyć moduł jako “y”,np. CONFIG_HELLO_WORLD=y

• Aby zbudować moduł jako zewnętrzny należy w pliku “.config”:• Oznaczyć moduł jako “m”,

np. CONFIG_HELLO_WORLD=m• Dlatego też, jeśli w pliku makefile napiszemy:

• Obj-y := hello.o, nasz moduł będzie wbudowany,• Obj-m := hello.o, nasz moduł będzie zewnętrzyny.

Kompilacja modułu: informacje dodatkowe (I)

Linux Kernel - Hello World module

Page 21: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 21

• Budowanie modułu złożonego z plików hello1.c and hello2.c:

obj-m := hello.ohello-objs := hello1.o hello2.o

• Nietypowa komenda “$(MAKE)”:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

Odpowiada ona za wywołanie dodatkowego procesu budowania – dziecka – w obrębie nadrzędnego polecenia “make”.

Kompilacja modułu: informacje dodatkowe (II)

Linux Kernel - Hello World module

Page 22: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 22

• insmod – aby wczytać I uruchomić moduł,• rmmod – aby zakończyć pracę modułu,• lsmod – aby wyświetlić załadowane moduły,• Polecenie: dmesg | tail wyświetli wszystkie polecenia “printk”

użyte w module.

Dynamiczne uruchamianie i kończenie pracy modułów

Linux Kernel - Hello World module

Page 23: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 23

• Kernel Symbol Table to po prostu Tablica Symboli Kernela,• Tablica symboli odnosi się bezpośrednio to wspomnianego wczesniej

pliku Module.symvers,• Co należy zrobić, aby napisaną przez nas funkcję dodać do tablicy

symboli Kernela?Należy wyeksportować ją za pomocą makra: EXPORT_SYMBOL(),

• Po użyciu makra EXPORT_SYMBOL Kernel umieści naszą funkcję w globalnej tablicy symboli i stanie się ona widoczna dla wszystkich modułów w Kernelu.

“Kernel symbol table”

Linux Kernel - Hello World module

Page 24: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 24

• Kiedy zobaczymy taki błąd:Error inserting './hello.ko': -1 “Invalid module format”

• Znaczy to, że coś poszło nie tak... Aby przyjrzeć się bliżej problemowi wpisujemy:

“cat /var/log/messages”, bądź “dmesg” i sprawdzamy ostatnie wpisy,

• Najczęstsze błędy:1. hello: version magic '<this>' should be '<that>'

Zła wersja kernela: należy poszukać DOKŁADNIE takiego samego Kernela, bądź pogrzebać w /linux/module.h (czasem trudne).

Potencjalne problemy i pozbywanie się ich (I)

Linux Kernel - Hello World module

Page 25: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 25

2. hello: no symbol version for module_layoutŹródła systemu Linux nie są kompletne. Brakuje w nich pliku “Module.symvers”: należy pobrać plik od twórcy, bądź skompilować źródła systemu Linux, które posiadamy.

3. W przypadku każdego problemu najprostszym, rozwiązaniem jest przeszukanie internetu. Kernel posiada znakomitą dokumentację! :)

Potencjalne problemy i pozbywanie się ich (II)

Linux Kernel - Hello World module

Page 26: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

page 26

• Aby skompilować swój moduł potrzebujesz odpowiednio przygotowane źródła systemu Linux: konfiguracja oraz stworzenie tablicy symboli są niezbędne!

• Moduły możemy budować jako integralną część Linuxa (build-in) bądź jako zewnętrzne pliki ładowane dynamicznie (loadable),

• Proces budowania modułu jest częścią systemu budowania CAŁEGO systemu Linux,

• Pliki nagłówkowe systemu Linux dostarczają wielu ciekawych informacji,

• Częste sięganie do dokumentacji systemu Linux może zaoszczędzić wielu nerwów,

• Programowanie w systemie Linux wymaga wprawy i szczególnie na początku, może sprawiać problem.

Podsumowanie

Linux Kernel - Hello World module

Page 27: Linux Kernel II - Solutions for TV and IoT - ADB · komendy insmod bądź modprobe, ... w obrębie nadrzędnego polecenia “make”. ... • Programowanie w systemie Linux wymaga

Linux Kernel – Wprowadzenie

Koniec