Treiber Flashcards
Treiber Programmierung
Funktion um Speicher für ein CharDev zu reservieren.
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
Bsp:
alloc_chrdev_region(&dev, 0, 1, “hello”)
Treiber Objekt beim Kernel anmelden. Objekt reservieren.
cdev_alloc()
Bsp:
driver_object = cdev_alloc()
Treiber Klasse erstellen.
class_create(owner, name) -> Ist als Makro definiert.
Bsp:
cl = class_create(THIS_MODULE, “hello”);
Instanz des Treibers beim Kernel erstellen.
struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, …)
Bsp:
device_create(cl, NULL, dev, NULL, “hello”)
Treiber beim System abmelden.
void kobject_put(struct kobject *kobj)
Bsp:
kobject_put(&driver_object->kobj);
Nenne Systemfunktionen?
- close()
- read()
- write()
- seek()
- select()
Was passiert bei der Funktion open() ?
- Prüfen ob der Treiber geladen ist
- Zugriffsrechte prüfen
- welcher Zugriff auf das gerät wird verlangt
- Rückgabewert: Filedeskriptor
Treiber dem System hinzufügen (dem Kernel Bescheid geben dass ein neuer Treiber da ist).
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
Bsp:
cdev_add(driver_object, dev, 1)
Reservierten Speicher für den Treiber freigeben. (4 Funktionen)
void cdev_del(struct cdev *p) void device_destroy(struct class *class, dev_t devt) void class_destroy(struct class *cls) static inline void unregister_chrdev(unsigned int major, const char *name) Bsp: cdev_del(driver_object); device_destroy(cl, dev); class_destroy(cl); unregister_chrdev_region(dev, 1);
Treiber write Funktion
static ssize_t driver_write(struct file* instanz, const char* user, size_t conut, loff_t* offset)
Was passiert bei der Funktion read() ?
- Lesen von Daten
- Rückgabewert: Anzahl gelesener Bytes / Fehlercode
Was passiert bei der Funktion write() ?
- Schreiben von Daten
- Rückgabewert: Anzahl an geschreibenen Bytes/Fehlercode
Was passiert bei der Funktion ioctl() ?
- Funktion um mit dem Treiber zu kommunizieren
- Unterstützt frei definierbare Kommandos und Parameter
Was passiert bei der Funktion mmap() ?
- Funktion, um Speicherbereiche eines Geräts in den Adressraum einer Applikation einzublenden.
Was passiert bei der Funktion seek()/poll() ?
- Funktion um zu prüfen ob an einem Gerät Daten zum lesen bereit liegen.
Treiber read Funktion.
static ssize_t driver_read(struct file* instanz, char* user, size_t count, loff_t* offset)
struct file *instanz: Info über die Treiberinstanz
char *user: Speicherbereich im User-Space
size_t count: Größe des Buffers im User-Space
loff_t offs: Offset
Erklären sie das Verhalten wenn ein Treiber im blocking mode ist?
Beim “blocking mode” wird die Application schlafen gelegt sobald keine Daten geschrieben oder gelesen werden können.
Treiber close Funktion
static int driver_close(struct inode * geraetedatei, struct file *instanz)
Treiber writeFunktion
static ssize_t driver_write(struct file* instanz, const char* user, size_t conut, loff_t* offset)
Treiber Funktionen zum FileOperations struct (struct fileoperations) hinzufügen.
static struct file_operations fops = { .owner = THIS_MODULE, .open = driver_open, .release = driver_close, .read = driver_read, .write = driver_write, };
Warum müssen die Treiber Funktionen in das struct fileoperations eingetragen werden?
Der Kernel benötigt die Adressen der Funktionen des Treibers, damit er diese bei einem Systemcall aufrufen kann. Das struct fileoperations stellt die Verbindung für den Kernel zwischen der Treiberfunktion und dem Treiber her.
Nenne die unterschiedlichen Kontexte in denen Treibercode ausgeführt werden kann.
Userkontext
Prozesskontext
Kernelkontext
Interruptkontext
Nenne Funktionen um den Treiber in das Betriebssystem einzubinden.
init_module
cleanup_module
probe
remove
Nenne Funktionen, die durch das Betriebssystem oder die Hardware getriggert werden.
ISR
Soft-IRQ´s
Kernel-Threads
Welche Zugriffsarten gibt es um auf ein Gerät zu zugreifen?
- > blocking mode
- > non blocking mode
Erklären sie das Verhalten wenn ein Treiber im blocking mode ist?
Beim “blocking mode” wird die Application schlafen gelegt sobald keine Daten geschrieben oder gelesen werden können.
Erklären sie das Verhalten wenn ein Treiber im non blocking mode ist?
Beim “non blocking mode” wird der Aufruf direkt zurück kommen mit dem Fehlercode -EAGAIN.
Was gibt der Kontext an in dem Programmcode ausgeführt wird (Prozesskontext, etc.).
Der Kontext (Umgebung) gibt an, auf welche Daten und Dienste ein Codefragment Zugriff hat.
Beschreibe den Interrupt-Kontext.
Limitierte Funktionsauswahl, insbesondere
kein „Schlafen legen“ und kein Zugriff auf
Applikations-Speicherbereiche.
ISRs, Soft-IRQs, Tasklets und Timer.
GFP_ATOMIC
Beschreibe den Kernel-Kontext.
Zugriff auf sämtliche Funktionen des Kernels,
inklusive „Schlafen legen“.
Kernel-Threads, Workqueues, Event-Workqueue
GFP_KERNEL
Was für Aufgaben hat exit_module()?
- Freigeben der allozierten Systemressourcen
- Abmelden des Modules beim System.
Anmelden einer Hardware ISR, inklusiv Beispiel.
Mit request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) wird eine ISR beim System angemeldet.
Bsp:
request_irq(dev->irq, driver_isr, IRQF_DISABLED | IRQF_SHARED, “pci_drv”, dev)
Was sind Soft-IRQ`s?
Werden im Interrupt-Kontext abgearbeitet
Abarbeitungszeitpunkt direkt nach einer ISR
Was gibt die Minornumber an?
Die Minornumber dient zu Unterscheidung der einzelnen logischen Geräte.
Was passiert bei folgendem Befehl “insmod”?
Es wird ein Liste angezeigt mit den geladenen Modulen.
Wie greife ich auf die Major und Minor number zu?
minor = MINOR(dev_t); major= MAJOR(dev_t);
Was für Aufgaben hat exit_module()?
- Freigeben der allozierten Systemressourcen
- Abmelden des Modules beim System.
Was muss in der Treiberfunktion driver_close() beachtet werden?
- zuvor allozierten Ressourcen frei geben.
- Geräte counter zurück setzten
- Rückgabewert: 0
Was passiert bei der Treiberfunktion driver_read?
- Datentransfer zwischen Kernel-User Space.
- Rückgabewert: Anzahl gelesener Bytes / Fehlercode
Funktionen zum Datentransfer zwischen User und Kernel Space.
- copy_to_user( to, from, len )
- copy_from_user( to, from, len )
Bei einem Tasklet kann eine Race-Condition auftreten. Welche?
Wird der Tasklet-Code entladen bevor er aufgerufen wird, würde der Kernel nach einer ISR Code ausführen, der nicht mehr vorhanden ist.
Damit im Betriebssystem die richtige driver_read() Funktion gefunden wird, muss welches Verfahren angewendet werden?
- Der Treiber muss sich beim IO-Subsystem mit einer eindeutigen Kennung anmelden.
alt: Major Minor Nummer
neu: Gerätenummer (32 bit)
Was gibt die Majornumber an?
Die Majornumber dient zur Identifikation des Treibers.
Was gibt die Minornumber an?
Die Minornumber dient zu Unterscheidung der einzelnen logischen Geräte.
Welcher type ist dev_t ?
dev_t ist ein typdef der wiederum aus einem u32 besteht. Dies ist die Gerätenummer.
Wie greife ich auf die Major und Minor number zu?
minor = MINOR(dev_t); major= MAJOR(dev_t);
Was macht int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)?
alloc_chrdev_region registriert eine Reihe von Gerätenummern. Die Majornummer wird dabei dynamisch vom System vergeben.
Was macht int register_chrdev_region(dev_t from, unsigned count, const char *name)?
register_chrdev_region registriert eine Reihe von Gerätenummern angefangen bei dem Parameter “from”. Es muss eine Gerätnummer vergeben worden sein.
Was muss in der Treiberfunktion driver_open() beachtet werden?
- Zugriffsüberwachung (Wie viel mal darf das Gerät geöffnet werden, Wie wird auf das Gerät zugegriffen lesend schreiben)
- Initialisierung
Was ist ein Kernel-Thread
Ein Thread, der im Kernel abläuft und keine Ressourcen im Userland besitzt.
Er besitzt einen eigenen PCB.
Was ist ein Kernel-Thread
Ein Thread, der im Kernel abläuft und keine Ressourcen im Userland besitzt.
Beschreibe kurz eine Race Condition, die bei Kernel Threads auftreten kann.
Ein Thread muss beendet sein, bevor der zugehörige Code entfernt wurde. D.h. auch, dass der Treiber evtl. auf die Beendigung eines Threads warten muss, bevor er entladen wird.
Was passiert bei der Treiberfunktion driver_read?
- Datentransfer zwischen Kernel-User space.
- Rückgabewert: Anzahl gelesener Bytes / Fehlercode
Funktionen zum Datentransfer zwischen User und Kernel Space.
- copy_to_user( to, from, len )
- copy_from_user( to, from, len )
Was sind Workqueues?
Workqueues sind „vorgefertigte“ Kernel-Threads, in deren Kontext Funktionen (einmal) abgearbeitet werden.
Wie kann man einen Kernel-Thread starten, nach dem er erzeugt wurde?
Mit wake_up_process(thread_id) wird eine wartender Thread aktiviert und rechenbereit gemacht.
Welche Möglichkeiten gibt es einen Kernel-Thread zu erzeugen?
- Möglichkeit
kthread_create(thread_code, data, “mykthread”)
Diese Funktion erzeugt einen Thread, der noch nicht aktiv ist und damit vom Scheduler nicht ausgewählt wird. - Möglichkeit
kthread_run(thread_code, data, “mykthread”) wird ein Thread erzeugt und rechenbereit gesetzt.
Erzeugen einer Workqueue.
Mit create:workqueue(name). Damit die workqueue aber arbeitet, muss sie mit queue_work(wq, &work) gestartet werden.
Was passiert bei der Treiberfunktion driver_write?
- Datentransfer zwischen Kernel-User Space.
- Rückgabewert: Anzahl transferierter Bytes / Fehlercode
Erzwingen der Abarbeitung einer workqueue.
flush_workqueue(wq)
Kann es bei einer wait_event_interruptible() zu einer Race-Condition kommen?
Ja kann es, wenn der befehl wake_up() vor der ISR kommt. Durch wake_up() läuft die Anwendung zu ende und entlädt den Treiber.
Welche Arten von “Arbeit” nimmt eine workqueue entgegen?
Eine workqueue nimmt Arbeit von dem Typ struct work entgegen.
Wie wird Arbeit für eine workqueue angelegt?
Statisch mit dem Makro DECLARE_WORK(work, work_func, data)
Auf welche Schutzmechanismen kann innerhalb des Prozesskontext zurückgegriffen werden?
Atomare Operationen
Spinlocks
Mutexte
Semaphore
Auf welche Schutzmechanismen kann innerhalb des Interruptkontextes zurückgegriffen werden?
Atomare Operationen
Spinlocks
Auf welche Schutzmechanismen kann innerhalb des Kernelkontext und Prozesskontext zurückgegriffen werden?
Atomare Operationen
Spinlocks
Mutexte
Semaphore
Funktionen die den Taskzustand beeinflussen.
wait_event_interruptible( wait_queue, Bedingung)
schläft genau so lange, bis entweder die Wartebedingung erfüllt ist oder aber ein Signal den Prozess aufweckt (return -ERESTARTSYS;).
Kann es bei einer wait_event_interruptible() zu einer Race-Condition kommen?
Ja kann es, wenn der befehl wake_up() vor der ISR kommt. Durch wake_up() läuft die Anwendung zu ende und entlädt den Treiber.
Nenne ein Beispiel bei der Verwendung eines Mutex.
mutex_lock(my_mutex)
/kritischer Bereich/
mutex_unlock(my_mutex)
Mutexe können auch unterbrechbar gelockt werden.
if(mutex_lock_killable(my_mutex)) { return -ERESTARTSYS; } /*kritischer Bereich*/ mutex_unlock(my_mutext)
Wie wird ein Mutex definiert?
DEFINE_MUTEX(my_mutex)
Bei der Verwendung sind Mutexe den Semaphoren vorzuziehen. Warum?
Mutexe sind speichereffizienter als Semaphore.
Wann verwendet man spinlock_irqsave()/spin_lock_irqrestore() und spin_lock()/spin_unlock()?
Man verwendet spin_lock() und spin_unlock() wenn die geteilte Ressource nur im Prozesskontext verwendet wird. Wird die Ressource auch im Interruptkontext verwendet, muss im Prozesskontext spin_lock_irqsave() und spin_lock_irgrestore() benutzt werden.
Was machen spin_lock_bh() und spin_unlock_bh().
Die beiden Funktionen schalten Soft-IRQ´s ab lassen aber Hardware-Interrupts zu.