Differences

This shows you the differences between two versions of the page.

Link to this comparison view

so2:laboratoare:lab04:exercitii [2018/03/13 11:18]
ionel.ghita
so2:laboratoare:lab04:exercitii [2019/03/12 21:54] (current)
constantin.ghioc [1. [2p] Înregistrarea unui dispozitiv de tip caracter]
Line 83: Line 83:
 </​code>​ </​code>​
 </​note>​ </​note>​
 +
 +===== Exerciții =====
  
 <note warning> <note warning>
Line 92: 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 =====
Line 103: Line 108:
  
 <note tip> <note tip>
-La căutarea simbolurilor în [[https://​elixir.bootlin.com/​linux/​v4.15.7/​source|LXR]],​ asiguraţi-vă că selectaţi aceeaşi versiune de kernel ca cea din laborator(4.15.7).+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 110: 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 117: 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 126: 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 145: 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 156: 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 168: 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 191: 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 225: 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 241: 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 257: 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
so2/laboratoare/lab04/exercitii.1520932709.txt.gz · Last modified: 2018/03/13 11:18 by ionel.ghita
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0