This shows you the differences between two versions of the page.
so2:laboratoare:lab04:exercitii [2017/03/12 17:34] octavian.purdila |
so2:laboratoare:lab04:exercitii [2019/03/12 21:54] (current) constantin.ghioc [1. [2p] Înregistrarea unui dispozitiv de tip caracter] |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Laborator 4: Exerciții ====== | ====== Laborator 4: Exerciții ====== | ||
- | Pentru desfășurarea laboratorului pornim de la [[http://elf.cs.pub.ro/so2/res/laboratoare/lab04-tasks.zip|arhiva de sarcini a laboratorului]]. Descărcăm și decomprimăm arhiva în directorul ''so2/'' din directorul home al utilizatorului ''student'' de pe sistemul de bază (stația ''asgard''):<code bash> | + | ===== Pregătirea laboratorului ===== |
- | student@asgard:~$ cd so2/ | + | |
- | student@asgard:~/so2$ wget http://elf.cs.pub.ro/so2/res/laboratoare/lab04-tasks.zip | + | Pentru rezolvarea laboratorului, vom lucra în același director din care pornim mașina virtuală (''~/so2/linux/tools/labs''). |
- | student@asgard:~/so2$ unzip lab04-tasks.zip | + | |
- | student@asgard:~/so2$ tree lab04-tasks | + | Pașii de rezolvare sunt următorii: |
+ | * pregătirea scheletului de laborator | ||
+ | * compilarea modulelor de Kernel | ||
+ | * copierea modulelor pe mașina virtuală | ||
+ | * pornirea mașinii virtuale și testarea modulelor | ||
+ | |||
+ | ==== Pregătirea scheletului de laborator ==== | ||
+ | |||
+ | Scheletul de laborator este generat din sursele din directorul ''tools/labs/templates''. Putem genera scheletele pentru toate laboratoarele folosind următoarea comanda: | ||
+ | |||
+ | <code bash> | ||
+ | tools/labs $ make skels | ||
</code> | </code> | ||
- | În cadrul directorului ''lab04-tasks/'' se găsesc resursele necesare pentru dezvoltarea exercițiilor de mai jos: fișiere schelet de cod sursă, fișiere Makefile și Kbuild, scripturi și programe de test. | ||
- | Vom dezvolta exercițiile pe sistemul de bază (stația ''asgard'') și apoi le vom testa pe [[:so2:resurse:masini-virtuale|mașina virtuală QEMU]]. După editarea și compilarea unui modul de kernel îl vom copia în directorul dedicat pentru mașina virtuală QEMU folosind o comandă de forma<code bash> | + | Pentru a genera scheletul pentru un singur laborator, vom folosi variabila de mediu ''LABS'': |
- | student@asgard:~/so2$ cp /path/to/module.ko ~/so2/qemu-so2/fsimg/root/modules/ | + | |
- | </code> unde ''/path/to/module.ko'' este calea către fișierul obiect aferent modulului de kernel. Apoi vom porni, din directorul ''~/so2/qemu-so2/'', mașina virtuală QEMU folosind comanda<code bash> | + | <code bash> |
- | student@asgard:~/so2/qemu-so2$ make | + | tools/labs $ make clean |
+ | tools/labs $ LABS=<lab name> make skels | ||
</code> | </code> | ||
- | După pornirea mașinii virtuale QEMU vom putea folosi comenzi în fereastra QEMU pentru a încărca și descărca modulul de kernel:<code> | + | <note important> |
- | # insmod modules/module-name.ko | + | Numele laboratorului curent este ''device_drivers''. |
- | # rmmod module/module-name | + | </note> |
- | </code> unde ''module-name'' este numele modulului de kernel. | + | |
+ | Similar, putem genera și scheletul pentru un singur exercițiu, atribuind valoarea ''<lab_name>/<task_name>'' variabilei ''LABS''. | ||
+ | |||
+ | <note> | ||
+ | Scheletul este generat în directorul ''tools/labs/skels''. | ||
+ | </note> | ||
+ | |||
+ | ==== Compilarea modulelor ==== | ||
+ | |||
+ | Comanda ''make build'' compilează toate modulele din directorul ''skels''. | ||
+ | |||
+ | <code bash> | ||
+ | student@eg106:~/so2/linux/tools/labs$ make build | ||
+ | echo "# autogenerated, do not edit " > skels/Kbuild | ||
+ | echo "ccflags-y += -Wno-unused-function -Wno-unused-label -Wno-unused-variable " >> skels/Kbuild | ||
+ | for i in ./device_drivers/kernel ./device_drivers/extra/char-driver-lin; do echo "obj-m += $i/" >> skels/Kbuild; done | ||
+ | ... | ||
+ | </code> | ||
+ | |||
+ | ==== Copierea modulelor pe mașina virtuală ==== | ||
+ | |||
+ | Putem copia modulele generate pe mașina virtuală folosind target-ul ''copy'' al comenzii make, atunci când mașina virtuală este oprită. | ||
+ | |||
+ | <code bash> | ||
+ | student@eg106:~/so2/linux/tools/labs$ make copy | ||
+ | student@eg106:~/so2/linux/tools/labs$ make boot | ||
+ | </code> | ||
+ | |||
+ | Alternativ, putem copia fișierele prin ''scp'', pentru e evita repornirea mașinii virtuale. Pentru detalii despre folosirea interacțiunea prin rețea cu mașina virtuală citiți [[https://ocw.cs.pub.ro/courses/so2/resurse/masini-virtuale#interactiunea_cu_masina_virtuala|Interacțiunea cu mașina virtuală]]. | ||
+ | |||
+ | ==== Testarea modulelor ==== | ||
+ | |||
+ | Modulele generate sunt copiate pe mașina virtuală în directorul ''/home/root/skels/<lab_name>/<task_name>''. | ||
+ | |||
+ | <code bash> | ||
+ | root@qemux86:~/skels/device_drivers# ls | ||
+ | extra/ kernel/ user/ | ||
+ | root@qemux86:~/skels/device_drivers# ls kernel/ | ||
+ | so2_cdev.ko | ||
+ | </code> | ||
+ | |||
+ | După pornirea mașinii virtuale QEMU vom putea folosi comenzi în fereastra QEMU (sau în ''minicom'') pentru a încărca și descărca modulul de kernel:<code> | ||
+ | root@qemux86:~# insmod skels/<lab_name>/<task_name>/<module_name>.ko | ||
+ | root@qemux86:~# rmmod skels/<lab_name>/<task_name>/<module_name>.ko | ||
+ | </code> | ||
<note> | <note> | ||
Pentru dezvoltarea laboratorului, este recomandat să folosim trei terminale sau, mai bine, trei tab-uri de terminal. Pentru a deschide un nou tab de terminal folosim combinația de taste ''Ctrl+Shift+t''. Cele trei tab-uri de terminal îndeplinesc următoarele roluri: | Pentru dezvoltarea laboratorului, este recomandat să folosim trei terminale sau, mai bine, trei tab-uri de terminal. Pentru a deschide un nou tab de terminal folosim combinația de taste ''Ctrl+Shift+t''. Cele trei tab-uri de terminal îndeplinesc următoarele roluri: | ||
- | - În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtuală QEMU. Lucrăm în directorul aferent rezultat în urma decomprimării arhivei de sarcini a laboratorului. | + | - În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtuală QEMU. Lucrăm în directorul aferent rezultat în urma generării scheletului de laborator, din ''~/so2/linux/tools/labs/skels''. |
- | - În al doilea tab de terminal pornim mașina virtuală QEMU și apoi testăm modulul de kernel: încărcare/descărcare modul, rulare teste. Lucrăm în directorul aferent mașinii virtuale: ''~/so2/qemu-so2/''. | + | - În al doilea tab de terminal pornim mașina virtuală QEMU și apoi testăm modulul de kernel: încărcare/descărcare modul, rulare teste. Lucrăm în directorul aferent mașinii virtuale: ''~/so2/linux/tools/labs''. |
- În al treilea tab de terminal pornim [[:so2:laboratoare:lab02#minicom|minicom]] sau un server UDP care să primească [[:so2:laboratoare:lab02#netconsole|mesajele de netconsole]]. Nu contează în ce director ne aflăm. Folosim comanda<code bash> | - În al treilea tab de terminal pornim [[:so2:laboratoare:lab02#minicom|minicom]] sau un server UDP care să primească [[:so2:laboratoare:lab02#netconsole|mesajele de netconsole]]. Nu contează în ce director ne aflăm. Folosim comanda<code bash> | ||
- | student@asgard:~$ netcat -lup 6666 | + | student@asgard:~$ nc -l -p 6000 -u |
</code> | </code> | ||
</note> | </note> | ||
+ | |||
+ | ===== Exerciții ===== | ||
<note warning> | <note warning> | ||
Line 37: | Line 94: | ||
</note> | </note> | ||
+ | <note important> | ||
+ | Înainte de începerea rezolvării laboratorului, rulați comanda ''%%git pull --rebase%%'' in directorul ''~/so2/linux'', pentru a obține ultima versiune a scheletului de laborator. | ||
+ | </note> | ||
===== [0.5p] Intro ===== | ===== [0.5p] Intro ===== | ||
- | Identificați, folosind cscope sau [[http://lxr.free-electrons.com/source/?v=4.9|LXR]], definițiile următoarelor simboluri: | + | Identificați, folosind cscope, definițiile următoarelor simboluri: |
* structura ''file''; | * structura ''file''; | ||
* structura ''file_operations''; | * structura ''file_operations''; | ||
* constanta ''generic_ro_fops''; | * constanta ''generic_ro_fops''; | ||
- | * funcțiile ''vfs_read'' și ''do_sync_read''; | + | * funcțiile ''vfs_read'', ''new_sync_read'' și ''generic_file_read_iter''; |
- | Urmăriți definiția funcției ''vfs_read''. Observați că pentru un dispozitiv care nu are funcția ''read'', dar care are definită funcția de citire asincronă ''aio_read'', se va apela ''do_sync_read''. Această funcție folosește ''aio_read'', iar apoi așteaptă primirea răspunsului pentru cererea de citire asincronă. | + | Urmăriți definiția funcției ''vfs_read''. Observați că pentru un dispozitiv care nu are funcția ''read'' și nici funcția ''read_iter'' se va apela ''new_sync_read''. Această funcție folosește ''read_iter'' care în mod implicit este definită la ''generic_file_read_iter''. |
<note tip> | <note tip> | ||
- | La căutarea simbolurilor în [[http://lxr.free-electrons.com/source/?v=4.9|LXR]], asiguraţi-vă că selectaţi aceeaşi versiune de kernel ca cea din laborator(4.9). | + | La căutarea simbolurilor în [[https://elixir.bootlin.com/linux/v4.15/source|LXR]], asiguraţi-vă că selectaţi aceeaşi versiune de kernel ca cea din laborator (4.19). |
Pentru cscope, folosiți comanda '':cs f g //nume//'' pentru căutarea definiţiilor şi comanda '':cs f s //nume//'' pentru căutarea simbolurilor. Pentru mai multe informaţii despre comenzile disponibile folosiţi comanda '':help cscope''. | Pentru cscope, folosiți comanda '':cs f g //nume//'' pentru căutarea definiţiilor şi comanda '':cs f s //nume//'' pentru căutarea simbolurilor. Pentru mai multe informaţii despre comenzile disponibile folosiţi comanda '':help cscope''. | ||
Line 55: | Line 115: | ||
===== [10.5p] Character Device Driver ===== | ===== [10.5p] Character Device Driver ===== | ||
- | ==== 1. [1p] Înregistrarea unui dispozitiv de tip caracter ==== | + | ==== 1. [2p] Înregistrarea unui dispozitiv de tip caracter ==== |
Driver-ul va controla un singur dispozitiv cu majorul ''MY_MAJOR'' și minorul ''MY_MINOR ''(macro-urile definite în fișierul ''kernel/so2_cdev.c'') Ca prim pas, va trebui să creați fișierul de tip caracter ''/dev/so2_cdev'' folosind utilitarul ''mknod''. | Driver-ul va controla un singur dispozitiv cu majorul ''MY_MAJOR'' și minorul ''MY_MINOR ''(macro-urile definite în fișierul ''kernel/so2_cdev.c'') Ca prim pas, va trebui să creați fișierul de tip caracter ''/dev/so2_cdev'' folosind utilitarul ''mknod''. | ||
Line 62: | Line 122: | ||
Citiți secțiunea [[:so2:laboratoare:lab04#Identificator major și minor|Identificator major și minor]] din laborator. | Citiți secțiunea [[:so2:laboratoare:lab04#Identificator major și minor|Identificator major și minor]] din laborator. | ||
- | Pentru a evita folosirea ''mknod'' la fiecare boot-are a mașinii, adăugați comanda ''mknod'' cu parametrii relevanți la finalul fișierului ''qemu-vm/fsimg/etc/rcS''. | + | Pentru a evita folosirea ''mknod'' la fiecare boot-are a mașinii, adăugați comanda ''mknod'' cu parametrii relevanți la finalul fișierului ''/etc/rcS'' din mașina virtuală. |
</note> | </note> | ||
Implementați înregistrarea și deînregistrarea dispozitivului cu numele ''so2_cdev'', respectiv în funcția de intrare și cea de ieșire a modulului. Nu uitați că driver-ul controlează un singur dispozitiv. La acest exercițiu nu este nevoie să folosiți apelurile ''cdev_init'' și ''cdev_add''. Le veți folosi la exercițiul 3. | Implementați înregistrarea și deînregistrarea dispozitivului cu numele ''so2_cdev'', respectiv în funcția de intrare și cea de ieșire a modulului. Nu uitați că driver-ul controlează un singur dispozitiv. La acest exercițiu nu este nevoie să folosiți apelurile ''cdev_init'' și ''cdev_add''. Le veți folosi la exercițiul 3. | ||
+ | Urmăriți comentariile marcate cu ''TODO 1''. | ||
<note tip> | <note tip> | ||
Line 71: | Line 132: | ||
</note> | </note> | ||
- | Afișati, folosind macro-ul ''LOG_LEVEL'', un mesaj după operațiile de înregistrare, respectiv deînregistrare, care să confirme realizarea cu succes a acestora. | + | Afișati, folosind ''pr_info'', un mesaj după operațiile de înregistrare, respectiv deînregistrare, care să confirme realizarea cu succes a acestora. |
Încărcați apoi modulul în kernel<code> | Încărcați apoi modulul în kernel<code> | ||
Line 90: | Line 151: | ||
rmmod so2_cdev | rmmod so2_cdev | ||
</code> | </code> | ||
+ | |||
==== 2. [1p] Înregistrarea unui dispozitiv alocat ==== | ==== 2. [1p] Înregistrarea unui dispozitiv alocat ==== | ||
Modificați modulul de kernel pentru a încerca înregistrarea unui dispozitiv deja alocat. | Modificați modulul de kernel pentru a încerca înregistrarea unui dispozitiv deja alocat. | ||
- | Consultați [[http://lxr.free-electrons.com/source/include/uapi/asm-generic/errno-base.h?v=4.9|LXR]] pentru a identifica eroarea întoarsă la înregistrarea modulului. | + | Consultați [[https://elixir.bootlin.com/linux/v4.15/source/include/uapi/asm-generic/errno-base.h|LXR]] pentru a identifica eroarea întoarsă la înregistrarea modulului. |
Reveniți la configurația inițială a modulului. | Reveniți la configurația inițială a modulului. | ||
Line 101: | Line 163: | ||
==== 3. [1p] Implementarea deschiderii și închiderii dispozitivului ==== | ==== 3. [1p] Implementarea deschiderii și închiderii dispozitivului ==== | ||
Rulați comanda ''cat'' peste dispozitivul de tip caracter creat (''/dev/so2_cdev''). Citirea nu funcționează pentru că driver-ul nu are implementate funcțiile de deschidere, citire și închidere fișier. | Rulați comanda ''cat'' peste dispozitivul de tip caracter creat (''/dev/so2_cdev''). Citirea nu funcționează pentru că driver-ul nu are implementate funcțiile de deschidere, citire și închidere fișier. | ||
+ | Urmăriți comentariile marcate cu ''TODO 2'' pentru a realiza următoarele: | ||
- Inițializați dispozitivul | - Inițializați dispozitivul | ||
* Citiți secțiunea [[:so2:laboratoare:lab04#Înregistrarea și deînregistrarea dispozitivelor de tip caracter|Înregistrarea și deînregistrarea dispozitivelor de tip caracter]] din laborator. | * Citiți secțiunea [[:so2:laboratoare:lab04#Înregistrarea și deînregistrarea dispozitivelor de tip caracter|Înregistrarea și deînregistrarea dispozitivelor de tip caracter]] din laborator. | ||
Line 113: | Line 176: | ||
Parcurgeți secțiunea [[:so2:laboratoare:lab04#open și release|open și release]]. | Parcurgeți secțiunea [[:so2:laboratoare:lab04#open și release|open și release]]. | ||
</note> | </note> | ||
+ | |||
==== 4. [1.5p] Restricționare acces ==== | ==== 4. [1.5p] Restricționare acces ==== | ||
- | Restricționați accesul la dispozitiv cu [[:so2:laboratoare:lab03#Variabile atomice|variabile atomice]], astfel încât un singur proces să poată deschide dispozitivul la un moment dat. Restul vor primi eroarea %%"Device busy" (''-EBUSY'')%%. Restricționarea accesului se va face în funcția ''open'' expusă de driver. | + | Restricționați accesul la dispozitiv cu [[:so2:laboratoare:lab03#Variabile atomice|variabile atomice]], astfel încât un singur proces să poată deschide dispozitivul la un moment dat. Restul vor primi eroarea %%"Device busy" (''-EBUSY'')%%. Restricționarea accesului se va face în funcția ''open'' expusă de driver. Urmăriți comentariile marcate cu ''TODO 3''. |
- Adăugați o variabilă de tip ''atomic_t'' în structura dispozitivului. | - Adăugați o variabilă de tip ''atomic_t'' în structura dispozitivului. | ||
- Inițializați variabila la inițializarea dispozitivului. | - Inițializați variabila la inițializarea dispozitivului. | ||
- | - Folosiți variabila în funcția ''open'' pentru a restricționa accesul la dispozitiv. Recomandăm folosirea [[http://lxr.free-electrons.com/source/arch/x86/include/asm/atomic.h?v=4.9#L184|atomic_cmpxchg]] ((''atomic_cmpxchg'' întoarce **vechea** valoare a variabilei atomice)). | + | - Folosiți variabila în funcția ''open'' pentru a restricționa accesul la dispozitiv. Recomandăm folosirea [[https://elixir.bootlin.com/linux/v4.15/source/arch/x86/include/asm/atomic.h#L185|atomic_cmpxchg]] ((''atomic_cmpxchg'' întoarce **vechea** valoare a variabilei atomice)). |
- Resetați variabila în cadrul funcției de tip ''release'', pentru a repermite accesul la dispozitiv. | - Resetați variabila în cadrul funcției de tip ''release'', pentru a repermite accesul la dispozitiv. | ||
- Pentru a testa implementarea va trebui să simulați o utilizare îndelungată a dispozitivului. Apelați scheduler-ul la sfârşitul deschiderii dispozitivului:<code c> | - Pentru a testa implementarea va trebui să simulați o utilizare îndelungată a dispozitivului. Apelați scheduler-ul la sfârşitul deschiderii dispozitivului:<code c> | ||
Line 136: | Line 200: | ||
Mai multe detalii despre parametrii funcției găsiți [[https://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atomic_cmpxchg.html | aici]]. | Mai multe detalii despre parametrii funcției găsiți [[https://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/atomic_cmpxchg.html | aici]]. | ||
- | Un exemplu de folosire găsiți [[http://lxr.free-electrons.com/source/lib/dump_stack.c?v=4.9#L24|aici]]. | + | Un exemplu de folosire găsiți [[https://elixir.bootlin.com/linux/v4.15/source/lib/dump_stack.c#L28|aici]]. |
</note> | </note> | ||
+ | |||
==== 5. [2.5p] Citirea de mesaje ==== | ==== 5. [2.5p] Citirea de mesaje ==== | ||
- | Implementați funcția ''read'' în driver. | + | |
+ | Implementați funcția ''read'' în driver. Urmăriți comentariile marcate cu ''TODO 4''. | ||
- Păstrați în cadrul structurii dispozitivului un buffer pe care să îl inițializați la mesajul dat de macro-ul ''MESSAGE''. Inițializarea acestui buffer se va face odată cu inițializarea dispozitivului. | - Păstrați în cadrul structurii dispozitivului un buffer pe care să îl inițializați la mesajul dat de macro-ul ''MESSAGE''. Inițializarea acestui buffer se va face odată cu inițializarea dispozitivului. | ||
- La un apel ''read'' copiați în bufferul de user space conținutul buffer-ului din kernel space. | - La un apel ''read'' copiați în bufferul de user space conținutul buffer-ului din kernel space. | ||
- | * Folosiți funcția [[http://lxr.free-electrons.com/source/include/asm-generic/uaccess.h?v=4.9#L270|copy_to_user]] pentru a copia informații din kernel space în user space. | + | * Folosiți funcția [[https://elixir.bootlin.com/linux/v4.15/source/include/linux/uaccess.h#L152|copy_to_user]] pentru a copia informații din kernel space în user space. |
* Ignorați pentru moment parametrii ''size'' și ''offset''. Puteți presupune că buffer-ul din user space este suficient de mare. Nu este nevoie să verificați validitatea argumentului ''size'' al funcției ''read''. | * Ignorați pentru moment parametrii ''size'' și ''offset''. Puteți presupune că buffer-ul din user space este suficient de mare. Nu este nevoie să verificați validitatea argumentului ''size'' al funcției ''read''. | ||
* Valoarea întoarsă de apelul ''read'' este numărul de octeți transmiși din buffer-ul din kernel space către buffer-ul din user space. | * Valoarea întoarsă de apelul ''read'' este numărul de octeți transmiși din buffer-ul din kernel space către buffer-ul din user space. | ||
Line 170: | Line 236: | ||
Prin dereferențierea parametrului ''offset'' se permite citirea și deplasarea poziției curente din fișier. Valoarea acesteia trebuie actualizată de fiecare dată când o citire se efectuează cu succes. | Prin dereferențierea parametrului ''offset'' se permite citirea și deplasarea poziției curente din fișier. Valoarea acesteia trebuie actualizată de fiecare dată când o citire se efectuează cu succes. | ||
</note> | </note> | ||
+ | |||
==== 6. [1.5p] Scrierea de mesaje ==== | ==== 6. [1.5p] Scrierea de mesaje ==== | ||
- | Adăugați posibilitatea de a scrie un mesaj care să îl înlocuiască pe cel predefinit. Implementați funcția ''write'' în driver. | + | |
+ | Adăugați posibilitatea de a scrie un mesaj care să îl înlocuiască pe cel predefinit. Implementați funcția ''write'' în driver. Urmăriți comentariile marcate cu ''TODO 5''. | ||
Ignorați pe moment parametrul ''offset''. Puteți presupune că buffer-ul driverului este suficient de mare. Nu este nevoie să verificați validitatea argumentului ''size'' al funcției ''write''. | Ignorați pe moment parametrul ''offset''. Puteți presupune că buffer-ul driverului este suficient de mare. Nu este nevoie să verificați validitatea argumentului ''size'' al funcției ''write''. | ||
Line 186: | Line 254: | ||
</note> | </note> | ||
- | ==== 7. [2p] Operație de tip ''ioctl''. ==== | + | ==== 7. [1p] Operație de tip ''ioctl''. ==== |
- | Pentru acest exercițiu dorim să adăugăm operația ioctl ''MY_IOCTL_PRINT'' care să afișeze mesajul dat de macro-ul ''IOCTL_MESSAGE'' din driver. | + | Pentru acest exercițiu dorim să adăugăm operația ioctl ''MY_IOCTL_PRINT'' care să afișeze mesajul dat de macro-ul ''IOCTL_MESSAGE'' din driver. Urmăriți comentariile marcate cu ''TODO 6''. |
Pentru aceasta: | Pentru aceasta: | ||
- Implementați funcția ''ioctl'' în driver. | - Implementați funcția ''ioctl'' în driver. | ||
- | - Trebuie să scrieți un program în user-space (''user/so2_cdev_test.c'') care să apeleze funcția ''ioctl'' cu parametrii corespunzători. În fișierul de testare trebuie să apelați ''ioctl'' pentru fișierul dispozitivului. | ||
- Folosiți ''printk'' pentru a afișa mesajul din driver. | - Folosiți ''printk'' pentru a afișa mesajul din driver. | ||
+ | - Pentru testare, vom folosi un program în user-space (''user/so2_cdev_test.c'') care să apeleze funcția ''ioctl'' cu parametrii corespunzători. | ||
<note tip> | <note tip> | ||
- | Macrodefiniția ''MY_IOCTL_PRINT'' este definită în fișierul ''include/so2_cdev.h'' din [[http://elf.cs.pub.ro/so2/res/laboratoare/lab04-tasks.zip|arhiva de sarcini]] a laboratorului (folosește ''_IOC'' pentru a defini operația) | + | Macrodefiniția ''MY_IOCTL_PRINT'' este definită în fișierul ''include/so2_cdev.h'' din scheletul laboratorului (folosește ''_IOC'' pentru a defini operația). Acest fișier antet este inclus de ambele fișiere sursă (modulul de kernel și programul de test din user space). |
Citiți secțiunile [[:so2:laboratoare:lab04#ioctl|ioctl]] și [[:so2:laboratoare:lab04#open și release|open și release]] din laborator. | Citiți secțiunile [[:so2:laboratoare:lab04#ioctl|ioctl]] și [[:so2:laboratoare:lab04#open și release|open și release]] din laborator. | ||
Line 202: | Line 270: | ||
<note tip> | <note tip> | ||
- | Pentru a compila codul sursă de user space folosiți compilatorul ''gcc-5''. Pentru aceasta rulați comanda:<code> | + | Codul sursă de user space este compilat automat în momentul în care rulați ''make build''. După ''make copy'', veți găsi executabilul în directorul ''/home/root/skels/device_drivers/user''. |
- | /usr/bin/gcc-5 -m32 -static -Wall -g -o so2_cdev_test so2_cdev_test.c | + | |
- | </code> | + | |
- | + | ||
- | Executabilul rezultat trebuie să îl copiați pe mașina virtuală la fel ca modulul de kernel și să îl rulați pe mașina virtuală pentru a valida implementarea corectă a ''ioctl''. | + | |
</note> | </note> | ||
==== Extra ==== | ==== Extra ==== | ||
+ | |||
+ | <note>Urmăriți comentariile marcate cu ''TODO 7''.</note> | ||
1. (**2 karma**) Ioctl cu transmitere de mesaje | 1. (**2 karma**) Ioctl cu transmitere de mesaje |