This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
linux-kernel-dev:capitole:capitol-03 [2015/09/08 10:52] razvan |
linux-kernel-dev:capitole:capitol-03 [2016/08/31 07:50] (current) razvan [Resurse utile] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== 3. Drivere de dispozitiv ====== | + | ====== 3. Kernel API ====== |
===== Subiecte abordate ===== | ===== Subiecte abordate ===== | ||
Line 5: | Line 5: | ||
* API-ul expus de kernel pentru module de kernel: printing, lucrul cu memoria, liste | * API-ul expus de kernel pentru module de kernel: printing, lucrul cu memoria, liste | ||
* Erori în kernel, depanarea erorilor | * Erori în kernel, depanarea erorilor | ||
- | * Dispozitive văzute în user space | + | |
- | * Dispozitive virtuale | + | |
- | * Operații pe dispozitive | + | |
===== Resurse utile ===== | ===== Resurse utile ===== | ||
- | * TODO | + | * [[https://www.kernel.org/doc/htmldocs/kernel-api/|The Linux Kernel API]] |
+ | * [[http://ocw.cs.pub.ro/courses/so2/laboratoare/lab03|SO2: Kernel API]] | ||
===== Exerciții ===== | ===== Exerciții ===== | ||
Line 34: | Line 34: | ||
</note> | </note> | ||
- | ==== Eliberarea memorie alocate dinamic == | + | ==== Eliberarea memoriei alocate dinamic == |
Pentru anularea încărcării memoriei, trebuie să eliberăm memoria alocată dinamică. | Pentru anularea încărcării memoriei, trebuie să eliberăm memoria alocată dinamică. | ||
Pentru aceasta definiți un vector în care rețineți pointerii către zonele de memorie alocate. Apoi, în funcția de ''exit'' a modulului, folosiți funcția ''kfree()'' pentru a elibera memoria astfel alocată. | Pentru aceasta definiți un vector în care rețineți pointerii către zonele de memorie alocate. Apoi, în funcția de ''exit'' a modulului, folosiți funcția ''kfree()'' pentru a elibera memoria astfel alocată. | ||
+ | |||
+ | <note tip> | ||
+ | Vectorul trebuie definit ca variabilă globală ca să fie accesibil atât în funcția de inițializare cât și în funcția de ''exit''. | ||
+ | </note> | ||
==== Afișarea listei de procese a sistemului ==== | ==== Afișarea listei de procese a sistemului ==== | ||
Line 57: | Line 61: | ||
Santinela listei dublu înlănțuite este dată de câmpul ''children'' al structurii ''task_struct''. | Santinela listei dublu înlănțuite este dată de câmpul ''children'' al structurii ''task_struct''. | ||
- | Folosiți macro-ul ''list_for_each'' pentru a parcurge procesele copil și apoi macro-ul ''list_entry'' pentru a obține structura ''task_struct'' pentru fiecare proces din listă. | + | Folosiți macro-ul ''list_for_each'' pentru a parcurge procesele copil și apoi macro-ul ''list_entry'' pentru a obține structura ''task_struct'' pentru fiecare proces din listă. Câmpul din cadrul structurii ''task_struct'' care definește structura de tip listă care leagă toate procesele copil este ''sibling''. |
</note> | </note> | ||
Line 72: | Line 76: | ||
==== Depanarea unui oops ==== | ==== Depanarea unui oops ==== | ||
- | Atunci când nucleul întâlnește o eroare afișează un mesaj de eroare similar //Segmentation fault// numit //oops//. Este o indicație că ceva nepotrivit a avut loc; sistemul de operare continuă execuția, dar este posibil ca eroare să se propage. | + | Atunci când nucleul întâlnește o eroare afișează un mesaj de eroare similar //Segmentation fault// numit //oops//. Este o indicație că ceva nepotrivit a avut loc; sistemul de operare continuă execuția, dar este posibil ca eroarea să se propage. |
Erorile grave se prezintă în formă de //kernel panic// și conduc la înghețarea sistemului. | Erorile grave se prezintă în formă de //kernel panic// și conduc la înghețarea sistemului. | ||
Line 103: | Line 107: | ||
</note> | </note> | ||
- | ==== ioctl în dispozitiv de tip caracter ==== | ||
- | |||
- | Comunicarea și interacțiunea dintre user space și kernel space se poate face prind dispozitive (//devices//). Acestea sunt vizibile utilizatorului ca intrări în sistemul de fișier (de obicei în ''/dev'') pe care acesta le poate opera. | ||
- | |||
- | În directorul ''ioctl-print/'' avem un modul de kernel care expunde dispozitivul ''/dev/print'' și care, la operații de tip ioctl (''Input/Output Control'') afișează un mesaj. Este un modul didactic, vrem să urmărim comportamentul ioctl. | ||
- | |||
- | Pentru a putea observa apelul ''ioctl()'' folosim și un modul de test rulabil din user space, care este compilat static în executabilul ''print_test''. | ||
- | |||
- | <note> | ||
- | Modulul de kernel se găsește în subdirectorul ''kernel/'' în vreme ce testul de user space se găsește în subdirectorul ''user/''. | ||
- | </note> | ||
- | |||
- | Atât fișierul de test cât și fișierul modul se copiază pe mașina virtuală pentru a putea testa funcționalitatea respectivă: afișarea unui mesaj la apelul ''ioctl()''. | ||
- | |||
- | După ce modulul este inserat, trebuie creat dispozitivul ''/dev/print'' cu ajutorul comenzii<code> | ||
- | mknod /dev/print c 42 0 | ||
- | </code> | ||
- | |||
- | Apoi se poate rula executabilul de test cu opțiunea aferentă pentru a invoca funcționalitatea de tip ioctl:<code> | ||
- | ./print_test p | ||
- | </code> | ||
- | |||
- | ==== Alocare și dezalocare la ioctl ==== | ||
- | |||
- | Adăugați două noi operații la ''ioctl'', astfel încât la una dintre ele să aloce o zonă de memorie de 10KB și să rețină pointer-ul rezultat într-o variabilă globală, iar la cealaltă să-l elibereze. | ||
- | |||
- | Nu va aloca dacă a fost deja alocată zona de memorie, nu o va elibera dacă a fost deja eliberată. | ||
- | |||
- | ==== Citire din dispozitiv ==== | ||
- | |||
- | Operațiile de tipul ''ioctl'' sunt operații de comandă/control. Pentru transfer de informație cel mai adesea follosim operații de tipul ''read'' și ''write''. Pentru început să folosim operația ''read''. | ||
- | |||
- | În directorul ''read-string/'' din arhiva de suport a capitolului se găsește o implementare de modul care întoarce un șir predefinit (//anaaremere//) la orice operație de citire. Practic, oricând folosim comanda ''cat'' pe dispozitivul afernet (''/dev/string'') ne va afișa șirul predefinit. | ||
- | |||
- | Compilați modululul și apoi copiați-l pe mașina virtuală QEMU și testați această funcționalitate. | ||
- | |||
- | ==== Generator de caractere de 1 ==== | ||
- | |||
- | Creați un modul de kernel care expune un dispozitiv ''/dev/one'' care la citire generează o infinnitate de caractere de ''1''. Se oprește doar când cere spațiul utilizator să se oprească. Este similar cu ''/dev/zero''. | ||
- | |||
- | ==== Reply device ==== | ||
- | |||
- | Adăugați funcționalitatea de ''write'' modulului din directorul ''read-string/'' astfel încât sa și permită scrierea de mesaje în dispozitiv. După ce un mesaj este scris, același mesaj este citit de operațiile de citire. | ||
- | |||
- | <note tip> | ||
- | Pentru a scrie un mesaj într-un fișier, folosiți comanda:<code> | ||
- | echo "mesaj" > <fisier> | ||
- | </code> | ||
- | unde ''<fisier>'' este numele intrării în care vreți să scrieți, de exemplu ''/dev/string''. | ||
- | </note> | ||
- | |||
- | ==== Length device ==== | ||
- | |||
- | Actualizați modulul de mai sus astfel încât la citire să nu mai întoarcă șirul scris, ci un șir de cifre care să însemne lungimea șirului scris anterior. | ||