Linux Kernel III Character devices
Urządzenia systemu Linux (I) Character device Block device Network device Do urządzenia piszemy jak do pliku, Dozwolone działania: open, close, read, write, Np. /dev/tty1. Urządzenie udostępnia system plików, Dozwolone działania: operacje wejścia / wyścia. Obsługuje wszystkie rodzaje interfejsów sieciowych, Nie korzystamy z nich bezpośrednio. Linux Kernel Character devices page 2
Minor and major numbers (I) Każde urządzenie blokowe i znakowe posiada dwa numery, tzw. major i minor number, Numery major i minor umożliwiają jednoznaczną identyfikację urządzenia przez system Linux, Major: rozróżnia klasę urządzenia, którą reprezentuje nasz sterownik, Minor: określa dokładnie które urządzenie reprezentuje nasz sterownik, Ważny dokument dla twórców sterowników: https://www.kernel.org/doc/documentation/devices.txt page 3
Minor and major numbers (II) Żywy Linux: documentation/devices.txt 0 Unnamed devices (e.g. non-device mounts) 0 = reserved as null device 1 char Memory devices 1 = /dev/mem 2 = /dev/kmem 3 = /dev/null 4 = /dev/port 5 = /dev/zero 6 = /dev/core 7 = /dev/full 8 = /dev/random 9 = /dev/urandom 10 = /dev/aio 11 = /dev/kmsg 12 = /dev/oldmem page 4
int alloc_chrdev_region(dev_t *dev, unsigned firstinor, unsigned count, char *name); void unregister_chrdev_region(dev_t first, unsigned count); ------------------------------------------------------------------------ #include <linux/fs.h> #include <linux/kdev_t.h> Rejestracja urządzenia #define DEVNAME My device of doom static dev_t this_dev; char buffer[64]; [...] int rv = alloc_chrdev_region(&this_dev, 0, 1, DEVNAME); printk(kern_alert "Device test module loaded, result: %d (%s)\n", rv, format_dev_t(buffer, this_dev)); [...] page 5
Ważne struktury Kernela Struktura file_operations, Struktura definiuje wszystkie działania, które możemy wykonać z plikiem sterownika, Zawiera się w strukturze file. Struktura file, Reprezentuje każdy plik, Zawiera w sobie strukturę file_operations. Struktura inode, Struktura reprezentuje plik na dysku, Zawiera wielką ilość informacji o pliku, większości z nich nie będziemy potrzebować. page 6
Struktura file_operations Każde urządzenie w systemie Linux jest reprezentowane jako plik, Pliki urządzeń możemy bez trudu znaleźć: ls -l /dev, Podstawowe operacje definiowane dla naszego sterownika przypominają polecenia dla plików: struct file_operations { ssize_t (*read) (struct file *, char user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char user *, size_t, loff_t *); int (*open) (struct inode *, struct file *); int (*release) (struct inode *, struct file *); [...] }; page 7
Przykładowa inicjalizacja file_operations Funkcja: device_read odpowiada za czytanie z urządzenia, device_write odpowiada za pisanie do urządzenia, device_open funkcja otwierająca plik urządzenia, device_release funkcja zwalniająca plik urządzenia. static struct file_operations fopr = {.read = device_read,.write = device_write,.open = device_open,.release = device_release }; page 8
Struktura file Struktura nie ma nic wspólnego ze definicją pliku (FILE) ze standardowej biblioteki C, Reprezentuje otwarty plik (każdy plik, niekoniecznie plik urządzenia), Większość funkcji ze struktury file_operations przyjmuje strukturę file jako jeden z argumentów. struct file { const struct file_operations *f_op; /*struktura file_operations*/ unsigned int f_flags; /* flagi pliku, np. O_RDONLY */ fmode_t f_mode; /* okresla tryb np. FMODE_WRITE, FMODE_READ */ loff_t f_pos; /* wskaźnik do zawartości pliku */ void *private_data; /* do naszego użytku :) */ [...] } page 9
Przykładowe użycie struktury file int mydevice_open(struct inode *inode, struct file *fp) { [...] printk( Device file is opened for: ); if (fp->f_mode == FMODE_READ) { printk( read ); } if (fp->f_mode == FMODE_WRITE) { printk( write ); } printk(.\n ); [...] } static struct file_operations fopr = { [...].open = mydevice_open, [...] }; page 10
Rejestracja urządzenia znakowego Kernel definiuje urządzenie znakowe jako: struct cdev, Definicja urządzenia znakowego znajduje się w: linux/cdev.h struct cdev { struct kobject kobj; struct module *owner; const struct file_operations *ops; struct list_head list; dev_t dev; unsigned int count; }; struct cdev *my_dev = my_dev->ops = &fops; ALBO: struct cdev my_dev; cdev_alloc(); cdev_init(&my_dev,&fops); page 11
Funkcja open int (*open) (struct inode *, struct file *); Funkcja open (ang. otwórz) powinna realizować następujące zadania: Przygotuj urządzenie fizyczne (o ile takie istnieje), Zgłoś ewentualne problemy z urządzeniami fizycznymi, Zainicjuj urządzenie, Wypełnij pole private_data wskaźnika, aby przechować dane pomiędzy wywołaniami systemowymi. Jeśli urządzenia fizyczne nie są podłączone, to funkcja open zadba jedynie o pole private_data oraz, ewentualnie, o ustawienia dostępu do pliku sterownika. page 12
Funkcja release int (*release) (struct inode *, struct file *); Funkcja release (ang. uwolnij) powinna realizować następujące zadania: Dealokować, usuwać i czyścić wszelkie dane zaalokowane w strukturze private_data, Bezpiecznie wyłączać urządzenie fizyczne o ile takie istnieje. Dopóki nie posiadamy urządzeń fizycznych, które chcielibyśmy oprogramować funkcja release będzie zwykle niewielka, W niektórych wersjach systemu Linux funkcja może być nazywana [device]_close zamiast [device]_release. page 13
Funkcja write ssize_t (*write) (struct file *filp, const char user *buff, size_t count, loff_t *offp); Funkcja write (ang. pisz) realizuje wysyłanie danych z kernela do kodu aplikacji, Zazwyczaj używana w połączeniu z funkcjami: unsigned long copy_to_user(void user *to, const void *from, unsigned long count), unsigned long copy_from_user(void *to, const void user *from, unsigned long count). page 14
Funkcja read ssize_t (*read) (struct file *filp, char user *buff, size_t count, loff_t *offp); Funkcja read (ang. czytaj) realizuje odbieranie danych z przestrzeni użytkownika do kodu kernela, Zazwyczaj używana w połączeniu z funkcjami: unsigned long copy_to_user(void user *to, const void *from, unsigned long count), unsigned long copy_from_user(void *to, const void user *from, unsigned long count). page 15
Funkcja copy_to_user unsigned long copy_to_user(void user *to, const void *from, unsigned long count); Funkcja copy_to_user kopiuje zadaną pamięć z Kernela do przestrzeni użytkownika. Argumenty: to wskaźnik na adres docelowy kopiowanej pamięci w przestrzeni użytkownika, from wskaźnik na adres źródłowy kopiowanej pamięci w przestrzeni Kernela, count rozmiar danych do transferu w bajtach. Działa właściwie tak samo jak funkcja memcpy standardowej biblioteki C, Znacznik user oznacza, że wskaźnik jest używany w przestrzeni użytkownika i nie powinien być poddawany dereferencji. page 16
Funkcja copy_from_user unsigned long copy_from_user(void *to, const void user *from, unsigned long count); Funkcja copy_from_user kopiuje zadaną pamięć do przestrzeni użytkownika z Kernela. Argumenty: to wskaźnik na adres docelowy kopiowanej pamięci w przestrzeni Kernela, from wskaźnik na adres źródłowy kopiowanej pamięci w przestrzeni użytkownika, count rozmiar danych do transferu w bajtach. Działa właściwie tak samo jak funkcja memcpy standardowej biblioteki C, Znacznik user oznacza, że wskaźnik jest używany w przestrzeni użytkownika i nie powinien być poddawany dereferencji. page 17
The eudyptula challenge http://eudyptula-challenge.org/ Propozycja dalszego ciągu przygód z Kernelem, Po ostatnich labolatoriach dotyczących Kernela, powstanie odpowiedni temat na https://academy.adbglobal.com/jira W obrębie powstałego tematu spróbujemy (każdy oddzielnie) przebrnąć przez kolejne etapy wyzwania, Wyzwanie może być podjęte przez każdego, w każdym czasie, Chętnych zapraszam do udziału! Linux Kernel - Hello World module page 18
Podsumowanie Minor, major numbers identyfikują każdy sterownik w systemie, Najważniejsze (na początek) struktury Kernela: file_operations, file, inode, Najważniejsze funkcje: open, release, write, read oraz inne zawarte w strukturze file_operations, Funkcje copy_from_user oraz copy_to_user kopiują pamięć między przestrzenią kernela a użytkownika. Linux Kernel - Hello World module page 19
Pytania? Linux Kernel - Hello World module page 20
Linux Kernel Wprowadzenie Koniec