Differences

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

Link to this comparison view

so2:laboratoare:lab11:exercitii [2017/05/07 19:38]
octavian.purdila [3. [2p] Operații de read/write în memoria mapată]
so2:laboratoare:lab11:exercitii [2019/05/08 09:53] (current)
constantin.ghioc [2. [3p] Mapare de memorie virtual contiguă în user space]
Line 1: Line 1:
 ====== Laborator 11: Exerciții ====== ====== Laborator 11: Exerciții ======
  
-Pentru desfășurarea ​laboratorului pornim ​de la [[http://​elf.cs.pub.ro/so2/res/laboratoare/lab11-tasks.zip|arhiva ​de sarcini a laboratorului]]. Descărcăși decomprimăm arhiva în directorul ​''​so2/'' ​din directorul home al utilizatorului ​''​student''​ de pe sistemul de bază (stația ​''​mjolnir''​):<code bash> + 
-student@mjolnir:​~$ cd so2/ +===== Pregătirea laboratorului ​===== 
-student@mjolnir:​~/​so2$ wget http://​elf.cs.pub.ro/​so2/​res/​laboratoare/​lab11-tasks.zip + 
-student@mjolnir:​~/​so2$ unzip lab11-tasks.zip +Pentru rezolvarea laboratorului,​ vom lucra în același director din care pornim ​mașina virtuală (''​~/so2/linux/tools/labs''​). 
-student@mjolnir:​~/​so2tree lab11-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 ==== 
 + 
 +Pentru rezolvarea laboratorului trebuie sa activam suportul de netfilter din kernel. In meniul deschis cu ''​make menuconfig''​ 
 +activati optiunea ​''​Networking support/​Networking options/​Network packet filtering framework (Netfilter)''​
 + 
 +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 ''​lab11-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 ​''​mjolnir''​) ș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@mjolnir:​~/so2cp /​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@mjolnir:​~/​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 ''​memory_mapping''​
-# rmmod module/module-name +</note> 
-</codeunde ''​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>​ <​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+Alt+t''​. ​Cele trei tab-uri de terminal îndeplinesc următoarele roluri: +Scheletul ​este generat în directorul ​''​tools/​labs/​skels''​. 
-  - În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtaulă QEMU. Lucrăm în directorul aferent rezultat în urma decomprimării arhivei de sarcini a laboratorului. +</​note>​ 
-  - Î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 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> +==== Compilarea modulelor ==== 
-student@mjolnir:~$ netcat ​-lup 6666+ 
 +Comanda ''​make build''​ compilează toate modulele din directorul ''​skels''​. 
 + 
 +<code bash> 
 +student@eg106:~/​so2/​linux/​tools/​labsmake 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 ./​memory_mapping/​vmmap ./​memory_mapping/​kmmap;​ do echo "obj-m += $i/" >> skels/​Kbuild;​ done 
 +...
 </​code>​ </​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>''​.
 +
 +<code bash>
 +root@qemux86:​~/​skels/​memory_mapping#​ ls
 +kmmap  test   vmmap
 +root@qemux86:​~/​skels/​memory_mapping#​ ls vmmap/
 +vmmap.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>​
 +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 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 accesăm directorul ''​~/​so2/​linux/''​ cu sursele nucleului unde putem folosi [[:​so2:​laboratoare:​lab01#​cscope|Vim și cscope]] pentru parcurgerea codului sursă.<​code>​
 +student@eg106-pc:​~$ netcat -lup 6666
 +</​code>​
 +
 +</​note>​
 +
 +===== Exerciții =====
 +
 +<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>​ </​note>​
  
 ==== 1. [3p] Mapare de memorie fizic contiguă în user space ==== ==== 1. [3p] Mapare de memorie fizic contiguă în user space ====
-    * Utilizați scheletul de modul de kernel din directorul ''​lin/kmmap/''​ pentru a crea o mapare a memoriei driver-ului în user-space.+    * Utilizați scheletul de modul de kernel din directorul ''​kmmap/''​ pentru a crea o mapare a memoriei driver-ului în user-space.
       * Memoria driver-ului este alocată folosind ''​kmalloc''​.       * Memoria driver-ului este alocată folosind ''​kmalloc''​.
       * Completați zonele marcate cu ''​TODO 1''​.       * Completați zonele marcate cu ''​TODO 1''​.
       * Parcurgeți secțiunea [[:​so2:​laboratoare:​lab11#​Kernel-space|Maparea memoriei. Kernel-space]].       * Parcurgeți secțiunea [[:​so2:​laboratoare:​lab11#​Kernel-space|Maparea memoriei. Kernel-space]].
-    * Alocați, în funcția de inițializare a modulului, o zonă de memorie de ''​NPAGES+1''​ pagini folosind ''​kmalloc''​.+    * Alocați, în funcția de inițializare a modulului, o zonă de memorie de ''​NPAGES+2''​ pagini folosind ''​kmalloc''​.
       * O pagină în kernel are dimensiunea [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​arch/​x86/​include/​asm/​page_types.h#​L9|PAGE_SIZE]].       * O pagină în kernel are dimensiunea [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​arch/​x86/​include/​asm/​page_types.h#​L9|PAGE_SIZE]].
        * Zona alocată din spațiul kernel este indicată de ''​kmalloc_area''​.        * Zona alocată din spațiul kernel este indicată de ''​kmalloc_area''​.
-       * Dimensiunea ''​NPAGES+1''​ este necesară pentru aliniere.+       * Dimensiunea ''​NPAGES+2''​ este necesară pentru aliniere.
     * Adresa ​ ''​kmalloc_ptr''​ (variabilă globală) obținută în urma apelului ''​kmalloc''​ trebuie aliniată la adresa unei pagini.     * Adresa ​ ''​kmalloc_ptr''​ (variabilă globală) obținută în urma apelului ''​kmalloc''​ trebuie aliniată la adresa unei pagini.
       * Pentru aceasta, va trebui să alocați o pagină în plus față de numărul de pagini necesare și să folosiți formula:<​code>​       * Pentru aceasta, va trebui să alocați o pagină în plus față de numărul de pagini necesare și să folosiți formula:<​code>​
Line 51: Line 117:
       * Shiftați rezultatul cu [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​arch/​x86/​include/​asm/​page_types.h#​L8|PAGE_SHIFT]] biți pentru a obține ''​pfn''​.       * Shiftați rezultatul cu [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​arch/​x86/​include/​asm/​page_types.h#​L8|PAGE_SHIFT]] biți pentru a obține ''​pfn''​.
     * Încărcați modulul în kernel.     * Încărcați modulul în kernel.
-    * Pentru testare utilizați testul din directorul ''​lin/test''​. +    * Pentru testare utilizați testul din directorul ''​test/''​.
-      * Compilați testul folosind comanda ''​make''​.+
       * Rulați testul folosind comanda ''​./​mmap-test''​.       * Rulați testul folosind comanda ''​./​mmap-test''​.
       * Dacă totul merge bine testul va afișa mesaje ''​matched''​.       * Dacă totul merge bine testul va afișa mesaje ''​matched''​.
     * Descărcați modulul din kernel.     * Descărcați modulul din kernel.
  
-==== 2. [3p] Mapare de memorie ​virtual contiguă în user space ==== +==== 2. [3p] Mapare de memorie ​fizic discontiguă în user space ==== 
-    * Utilizați scheletul de modul de kernel din directorul ''​lin/vmmap/''​ pentru a crea o mapare a memoriei driver-ului în user-space.+    * Utilizați scheletul de modul de kernel din directorul ''​vmmap/''​ pentru a crea o mapare a memoriei driver-ului în user-space.
       * Memoria driver-ului este alocată folosind ''​vmalloc''​.       * Memoria driver-ului este alocată folosind ''​vmalloc''​.
-      * Completați zonele marcate cu ''​TODO ​2''​.+      * Completați zonele marcate cu ''​TODO ​1''​.
       * Parcurgeți secțiunea [[:​so2:​laboratoare:​lab11#​Kernel-space|Maparea memoriei. Kernel-space]] din laborator.       * Parcurgeți secțiunea [[:​so2:​laboratoare:​lab11#​Kernel-space|Maparea memoriei. Kernel-space]] din laborator.
     * Alocați ​ o zonă de memorie de ''​NPAGES''​ pagini în funcția de inițializare a modulului folosind ''​vmalloc''​.     * Alocați ​ o zonă de memorie de ''​NPAGES''​ pagini în funcția de inițializare a modulului folosind ''​vmalloc''​.
Line 80: Line 145:
       * Al treilea argument pentru [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​mm/​memory.c#​L1760|remap_pfn_range]] este pfn-ul paginii virtuale din kernel-space care se dorește remapată.       * Al treilea argument pentru [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​mm/​memory.c#​L1760|remap_pfn_range]] este pfn-ul paginii virtuale din kernel-space care se dorește remapată.
     * Încărcați modulul în kernel.     * Încărcați modulul în kernel.
-    * Pentru testare utilizați testul din directorul ''​lin/test''​. +    * Pentru testare utilizați testul din directorul ''​test/''​.
-      * Compilați testul folosind comanda ''​make''​.+
       * Rulați testul folosind comanda ''​./​mmap-test''​.       * Rulați testul folosind comanda ''​./​mmap-test''​.
       * Dacă totul merge bine testul va afișa mesaje ''​matched''​.       * Dacă totul merge bine testul va afișa mesaje ''​matched''​.
Line 91: Line 155:
       * E vorba de un exercițiu didactic ca să vedem că același spațiu poate fi folosit și cu apel-ul ''​mmap''​ și cu apeluri de tipul ''​read''​ și ''​write''​.       * E vorba de un exercițiu didactic ca să vedem că același spațiu poate fi folosit și cu apel-ul ''​mmap''​ și cu apeluri de tipul ''​read''​ și ''​write''​.
       * Operațiile de citire și scriere vor acționa chiar asupra zonei de memorie alocate.       * Operațiile de citire și scriere vor acționa chiar asupra zonei de memorie alocate.
-      * Completați zonele marcate cu ''​TODO ​3''​.+      * Completați zonele marcate cu ''​TODO ​2''​.
       * Revedeți [[so2:​laboratoare:​lab04 | Laboratorul 4]]       * Revedeți [[so2:​laboratoare:​lab04 | Laboratorul 4]]
     * **Ignorați** parametrul ''​offset''​ trimis operației de read/write.     * **Ignorați** parametrul ''​offset''​ trimis operației de read/write.
-    * Pentru testare utilizați testul din directorul ''​lin/test''​. +    * Pentru testare utilizați testul din directorul ''​test/''​. 
-      * Definiți macroul ​''​TASK_3''​ în ''​mmap_test.c''​ +      * Rulați testul folosind comanda ​''​./mmap-test 3''​. 
-== 4. [3p] Afișare memorie mapată în ''​procfs''​ ==+ 
 + 
 +==== 4. [3p] Afișare memorie mapată în ''​procfs'' ​====
     * Folosind **unul dintre** modulele anterioare, creați un fișier ''​procfs''​ în care să afișați totalul memoriei mapate de procesul apelant.     * Folosind **unul dintre** modulele anterioare, creați un fișier ''​procfs''​ în care să afișați totalul memoriei mapate de procesul apelant.
-      * Completați zonele marcate cu ''​TODO ​4''​.+      * Completați zonele marcate cu ''​TODO ​3''​.
     * Creați o intrare nouă în ''​procfs''​ (''​PROC_ENTRY_NAME'',​ definit în ''​mmap-test.h''​) care va afișa totalul memoriei mapate de procesul care a apelat read-ul pe acel fișier. Folosiți apelul [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​proc_fs.h#​L30|proc_create]].     * Creați o intrare nouă în ''​procfs''​ (''​PROC_ENTRY_NAME'',​ definit în ''​mmap-test.h''​) care va afișa totalul memoriei mapate de procesul care a apelat read-ul pe acel fișier. Folosiți apelul [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​proc_fs.h#​L30|proc_create]].
         * Pentru parametrul ''​mode''​ folosiți ''​0'',​ iar pentru parametrul ''​parent''​ folosiți ''​NULL''​.         * Pentru parametrul ''​mode''​ folosiți ''​0'',​ iar pentru parametrul ''​parent''​ folosiți ''​NULL''​.
Line 120: Line 186:
     * În funcția ''​my_seq_open''​ înregistrați funcția de afișare (''​my_seq_show''​) folosind apelul [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​fs/​seq_file.c#​L566|single_open]].     * În funcția ''​my_seq_open''​ înregistrați funcția de afișare (''​my_seq_show''​) folosind apelul [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​fs/​seq_file.c#​L566|single_open]].
       * Ca al treilea argument pentru ''​single_open''​ puteți folosi ''​NULL''​.       * Ca al treilea argument pentru ''​single_open''​ puteți folosi ''​NULL''​.
-    * Pentru testare utilizați testul din directorul ''​lin/test''​. +    * Pentru testare utilizați testul din directorul ''​test/''​. 
-      * Definiți ''​TASK_4''​ în ''​mmap_test.c''​+      * Rulați testul folosind comanda ​''​./mmap-test 4''​.
-      * Rulați testul.+
         * Testul așteaptă un timp (are o instrucțiune ''​sleep''​ internă).         * Testul așteaptă un timp (are o instrucțiune ''​sleep''​ internă).
         * Cât timp testul așteaptă, folosiți în altă consolă comanda ''​pmap''​ pentru a vedea mapările testului și a le compara cu cele obținute.         * Cât timp testul așteaptă, folosiți în altă consolă comanda ''​pmap''​ pentru a vedea mapările testului și a le compara cu cele obținute.
           * Puteți folosi comanda în forma<​code>​           * Puteți folosi comanda în forma<​code>​
-pmap $(pidof mmap-test)+cat /proc/$(pidof mmap-test)/maps
 </​code>​ </​code>​
 <​note>​ <​note>​
-          * Pentru a accesa altă consolă ​în mașina virtuală folosiți combinația de taste ''​Alt+F2''​.+          * Pentru a accesa altă consolă ​porniți ​mașina virtuală ​în mod grafic și folosiți combinația de taste ''​Alt+F2''​.
           * Pentru a reveni înapoi în prima consolă folosiți combinația de taste ''​Alt+F1''​.           * Pentru a reveni înapoi în prima consolă folosiți combinația de taste ''​Alt+F1''​.
 </​note>​ </​note>​
so2/laboratoare/lab11/exercitii.txt · Last modified: 2019/05/08 09:53 by constantin.ghioc
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